From 2f5dcb896b2e3a7f3670409660c4305577edeae5 Mon Sep 17 00:00:00 2001
From: Russell Haering <russell.haering@rackspace.com>
Date: Wed, 18 Dec 2013 15:47:48 -0800
Subject: [PATCH] begin on command execution

---
 teeth_agent/agent.py | 22 +++++++++++++--------
 teeth_agent/api.py   | 47 +++++++++++++++++++++++++++++++++++++-------
 2 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/teeth_agent/agent.py b/teeth_agent/agent.py
index 4211b5001..3cc24dc64 100644
--- a/teeth_agent/agent.py
+++ b/teeth_agent/agent.py
@@ -17,11 +17,11 @@ 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
+import pkg_resources
+from teeth_rest import encoding
+from werkzeug import serving
 
-from teeth_agent.api import TeethAgentAPIServer
+from teeth_agent import api
 
 
 class TeethAgentOperationModes(object):
@@ -34,7 +34,7 @@ class TeethAgentOperationModes(object):
             raise RuntimeError('Invalid mode: {}'.format(mode))
 
 
-class TeethAgentStatus(Serializable):
+class TeethAgentStatus(encoding.Serializable):
     def __init__(self, mode, started_at, version):
         self.mode = mode
         self.started_at = started_at
@@ -58,7 +58,7 @@ class TeethAgent(object):
         self.listen_port = listen_port
         self.started_at = None
         self.mode = mode
-        self.api = TeethAgentAPIServer(self)
+        self.api = api.TeethAgentAPIServer(self)
 
     def get_status(self):
         """
@@ -67,9 +67,15 @@ class TeethAgent(object):
         return TeethAgentStatus(
             mode=self.mode,
             started_at=self.started_at,
-            version=get_distribution('teeth-agent').version
+            version=pkg_resources.get_distribution('teeth-agent').version
         )
 
+    def execute_command(self, command):
+        """
+        Execute an agent command.
+        """
+        pass
+
     def run(self):
         """
         Run the Teeth Agent.
@@ -78,4 +84,4 @@ class TeethAgent(object):
             raise RuntimeError('Agent was already started')
 
         self.started_at = time.time()
-        run_simple(self.listen_host, self.listen_port, self.api)
+        serving.run_simple(self.listen_host, self.listen_port, self.api)
diff --git a/teeth_agent/api.py b/teeth_agent/api.py
index 740ad58b3..29b58b197 100644
--- a/teeth_agent/api.py
+++ b/teeth_agent/api.py
@@ -14,13 +14,36 @@ 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
-)
+from collections import OrderedDict
+
+from teeth_rest import component, encoding, errors, responses
 
 
-class TeethAgentAPI(APIComponent):
+class AgentCommand(encoding.Serializable):
+    def __init__(self, name, params):
+        self.name = name
+        self.params = params
+
+    @classmethod
+    def deserialize(cls, obj):
+        if 'name' not in obj:
+            raise errors.InvalidContentError('Missing command \'name\' field.')
+        if 'params' not in obj:
+            raise errors.InvalidContentError('Missing command \'params\' field.')
+
+        return cls(obj['name'], obj['params'])
+
+    def serialize(self, view):
+        """
+        Turn a command into a dictionary.
+        """
+        return OrderedDict([
+            ('name', self.name),
+            ('params', self.params),
+        ])
+
+
+class TeethAgentAPI(component.APIComponent):
     """
     The primary Teeth Agent API.
     """
@@ -34,15 +57,25 @@ class TeethAgentAPI(APIComponent):
         Called during initialization. Override to map relative routes to methods.
         """
         self.route('GET', '/status', self.get_agent_status)
+        self.route('POST', '/command', self.execute_agent_command)
 
     def get_agent_status(self, request):
         """
         Get the status of the agent.
         """
-        return ItemResponse(self.agent.get_status())
+        return responses.ItemResponse(self.agent.get_status())
+
+    def execute_agent_command(self, request):
+        """
+        Execute a command on the agent.
+        """
+        command = AgentCommand.deserialize(self.parse_content(request))
+        self.agent.execute_command(command)
+        # TODO(russellhaering): implement actual responses
+        return responses.ItemResponse({'result': 'success'})
 
 
-class TeethAgentAPIServer(APIServer):
+class TeethAgentAPIServer(component.APIServer):
     """
     Server for the teeth agent API.
     """