From a58e837e59835a062b1519bab74e1e6543f1361a Mon Sep 17 00:00:00 2001
From: Russell Haering <russell.haering@rackspace.com>
Date: Tue, 17 Dec 2013 15:13:30 -0800
Subject: [PATCH] begin adding agent API

---
 teeth_agent/agent.py     | 81 ++++++++++++++++++++++++++++++++++++++++
 teeth_agent/api.py       | 52 ++++++++++++++++++++++++++
 teeth_agent/cmd/agent.py |  5 ++-
 3 files changed, 137 insertions(+), 1 deletion(-)
 create mode 100644 teeth_agent/agent.py
 create mode 100644 teeth_agent/api.py

diff --git a/teeth_agent/agent.py b/teeth_agent/agent.py
new file mode 100644
index 000000000..4211b5001
--- /dev/null
+++ b/teeth_agent/agent.py
@@ -0,0 +1,81 @@
+"""
+Copyright 2013 Rackspace, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+from collections import OrderedDict
+import time
+
+from pkg_resources import get_distribution
+from teeth_rest.encoding import Serializable
+from werkzeug.serving import run_simple
+
+from teeth_agent.api import TeethAgentAPIServer
+
+
+class TeethAgentOperationModes(object):
+    DECOM = 'DECOM'
+    STANDBY = 'STANDBY'
+
+    @classmethod
+    def validate_mode(cls, mode):
+        if not hasattr(cls, mode) or getattr(cls, mode) != mode:
+            raise RuntimeError('Invalid mode: {}'.format(mode))
+
+
+class TeethAgentStatus(Serializable):
+    def __init__(self, mode, started_at, version):
+        self.mode = mode
+        self.started_at = started_at
+        self.version = version
+
+    def serialize(self, view):
+        """
+        Turn the status into a dict.
+        """
+        return OrderedDict([
+            ('mode', self.mode),
+            ('started_at', self.started_at),
+            ('version', self.version),
+        ])
+
+
+class TeethAgent(object):
+    def __init__(self, listen_host, listen_port, mode):
+        TeethAgentOperationModes.validate_mode(mode)
+        self.listen_host = listen_host
+        self.listen_port = listen_port
+        self.started_at = None
+        self.mode = mode
+        self.api = TeethAgentAPIServer(self)
+
+    def get_status(self):
+        """
+        Retrieve a serializable status.
+        """
+        return TeethAgentStatus(
+            mode=self.mode,
+            started_at=self.started_at,
+            version=get_distribution('teeth-agent').version
+        )
+
+    def run(self):
+        """
+        Run the Teeth Agent.
+        """
+        if self.started_at:
+            raise RuntimeError('Agent was already started')
+
+        self.started_at = time.time()
+        run_simple(self.listen_host, self.listen_port, self.api)
diff --git a/teeth_agent/api.py b/teeth_agent/api.py
new file mode 100644
index 000000000..740ad58b3
--- /dev/null
+++ b/teeth_agent/api.py
@@ -0,0 +1,52 @@
+"""
+Copyright 2013 Rackspace, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+from teeth_rest.component import APIComponent, APIServer
+from teeth_rest.responses import (
+    ItemResponse
+)
+
+
+class TeethAgentAPI(APIComponent):
+    """
+    The primary Teeth Agent API.
+    """
+
+    def __init__(self, agent):
+        super(TeethAgentAPI, self).__init__()
+        self.agent = agent
+
+    def add_routes(self):
+        """
+        Called during initialization. Override to map relative routes to methods.
+        """
+        self.route('GET', '/status', self.get_agent_status)
+
+    def get_agent_status(self, request):
+        """
+        Get the status of the agent.
+        """
+        return ItemResponse(self.agent.get_status())
+
+
+class TeethAgentAPIServer(APIServer):
+    """
+    Server for the teeth agent API.
+    """
+
+    def __init__(self, agent):
+        super(TeethAgentAPIServer, self).__init__()
+        self.add_component('/v1.0', TeethAgentAPI(agent))
diff --git a/teeth_agent/cmd/agent.py b/teeth_agent/cmd/agent.py
index 431293b09..359323391 100644
--- a/teeth_agent/cmd/agent.py
+++ b/teeth_agent/cmd/agent.py
@@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
 limitations under the License.
 """
 
+from teeth_agent.agent import TeethAgent
+
 
 def run():
-    pass
+    agent = TeethAgent('0.0.0.0', 9999, 'STANDBY')
+    agent.run()