Merge branch 'master' of github.com:imduffy15/ec2stack into run-instance
diff --git a/ec2stack/controllers/default.py b/ec2stack/controllers/default.py
index c9acfe0..1f77393 100644
--- a/ec2stack/controllers/default.py
+++ b/ec2stack/controllers/default.py
@@ -51,6 +51,7 @@
         security_groups.revoke_security_group_egress,
         'RevokeSecurityGroupIngress':
         security_groups.revoke_security_group_ingress,
+        'RunInstances': instances.run_instance,
         'StartInstances': instances.start_instance,
         'TerminateInstances': instances.terminate_instance,
     }
diff --git a/ec2stack/errors.py b/ec2stack/errors.py
index 606641a..979cfab 100644
--- a/ec2stack/errors.py
+++ b/ec2stack/errors.py
@@ -51,6 +51,12 @@
         'The specified Disk offering does not exist.'
     )
 
+def invalid_service_offering_name():
+    raise Ec2stackError(
+        '400',
+        'InvalidServiceOffering.NotFound',
+        'The specified Service offering does not exist.'
+    )
 
 def invalid_keypair_name():
     raise Ec2stackError(
diff --git a/ec2stack/helpers.py b/ec2stack/helpers.py
index 08a80d2..34c90b2 100644
--- a/ec2stack/helpers.py
+++ b/ec2stack/helpers.py
@@ -128,7 +128,9 @@
 
 def _valid_signature():
     signature = get('Signature')
+    print('Signature = ' + str(signature))
     generated_signature = generate_signature()
+    print('Generated signature = ' + str(generated_signature))
 
     if signature != generated_signature:
         raise Ec2stackError(
@@ -138,6 +140,7 @@
         )
 
 
+
 def generate_signature(data=None, method=None, host=None):
     if data is None:
         data = request.form
diff --git a/ec2stack/providers/cloudstack/instances.py b/ec2stack/providers/cloudstack/instances.py
index 15a7890..c33cfcd 100644
--- a/ec2stack/providers/cloudstack/instances.py
+++ b/ec2stack/providers/cloudstack/instances.py
@@ -2,7 +2,7 @@
 # encoding: utf-8
 
 from ec2stack.providers import cloudstack
-from ec2stack.providers.cloudstack import requester
+from ec2stack.providers.cloudstack import requester, service_offerings, zones
 
 from ec2stack import helpers, errors
 
@@ -62,6 +62,49 @@
 
 
 @helpers.authentication_required
+def run_instance():
+    helpers.require_parameters(['ImageId', 
+                                'Placement.AvailabilityZone', 
+                                'InstanceType'])
+    response = _run_instance_request()
+    return _run_instance_response(response)
+
+
+def _run_instance_request():
+    args = {}
+
+    availibity_zone_name = helpers.get('Placement.AvailabilityZone')
+    service_offering_name = helpers.get('InstanceType')
+
+    args['zoneid'] = zones.get_zone(availibity_zone_name)['id']
+
+
+    #args['serviceofferingid'] = \
+    #        service_offerings.get_service_offering(service_offering_name)['id']
+
+    args['serviceofferingid'] = \
+            service_offerings.get_service_offering('Small Instance')['id']
+    args['templateid'] = helpers.get('ImageId')
+    args['command'] = 'deployVirtualMachine'
+
+    response = requester.make_request_async(args)
+
+    response = response['virtualmachine']
+
+    return response
+
+
+def _run_instance_response(response):
+    response = {
+        'template_name_or_list': 'run_instance.xml',
+        'response_type': 'RunInstancesResponse',
+        'response': response
+    }
+
+    return response
+
+
+@helpers.authentication_required
 def start_instance():
     helpers.require_parameters(['InstanceId.1'])
     instance_id = helpers.get('InstanceId.1')
diff --git a/ec2stack/providers/cloudstack/service_offerings.py b/ec2stack/providers/cloudstack/service_offerings.py
new file mode 100644
index 0000000..1a1fc9d
--- /dev/null
+++ b/ec2stack/providers/cloudstack/service_offerings.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+from ec2stack import errors
+from ec2stack.providers import cloudstack
+
+
+def get_service_offering(offering_name):
+    args = {'name': offering_name, 'command': 'listServiceOfferings'}
+    response = cloudstack.describe_item_request(
+        args, 'serviceoffering', errors.invalid_service_offering_name
+    )
+
+    return response
\ No newline at end of file
diff --git a/ec2stack/templates/run_instance.xml b/ec2stack/templates/run_instance.xml
new file mode 100644
index 0000000..19da2ed
--- /dev/null
+++ b/ec2stack/templates/run_instance.xml
@@ -0,0 +1,49 @@
+{% extends "response.xml" %}
+{% block response_content %}
+    <instancesSet>
+        <item>
+            <instanceId>{{ response.id }}</instanceId>
+            <imageId>{{ response.templateid }}</imageId>
+            <name>{{ response.name }}</name>
+            <instanceState>
+                {% if response.state == 'Starting' %}
+                <code>0</code>
+                <name>pending</name>
+                {% elif response.state == 'Running' %}
+                <code>16</code>
+                <name>running</name>
+                {% elif new_state.state == 'Destroyed' %}
+                <code>32</code>
+                <name>shutting-down</name>
+                {% elif response.state == 'Stopping' %}
+                <code>64</code>
+                <name>stopping</name>
+                {% elif response.state == 'Expunging' %}
+                <code>48</code>
+                <name>terminated</name>
+                {% elif response.state == 'Stopped' %}
+                <code>80</code>
+                <name>stopped</name>
+                {% endif %}
+            </instanceState>
+            <keyName>{{ response.keypair }}</keyName>
+            <instanceType>{{ response.serviceofferingname }}</instanceType>
+            <launchTime>{{ response.created }}</launchTime>
+            <placement>
+                <availabilityZone>{{ response.zonename }}</availabilityZone>
+            </placement>
+            {% if 'nic' in response %}
+            <ipAddress>{{ response.nic.0.ipaddress }}</ipAddress>
+            {% endif %}
+            <hypervisor>{{ response.hypervisor }}</hypervisor>
+            <groupSet>
+                {% for securitygroup in response.securitygroup %}
+                <item>
+                    <groupId>{{ securitygroup.id }}</groupId>
+                    <groupName>{{ securitygroup.name }}</groupName>
+                </item>
+                {% endfor %}
+            </groupSet>
+        </item>
+    </instancesSet>
+{% endblock %}
\ No newline at end of file
diff --git a/tests/instances_tests.py b/tests/instances_tests.py
index 3837550..7b9749a 100644
--- a/tests/instances_tests.py
+++ b/tests/instances_tests.py
@@ -137,4 +137,26 @@
         self.assert_bad_request(response)
         assert 'InvalidParameterValue' in response.data
 
+    def test_describe_instance_attribute(self):
+        data = self.get_example_data()
+        data['Action'] = 'DescribeInstanceAttribute'
+        data['InstanceId'] = '43791f77-26f8-48ca-b557-3a9392f735ae'
+        data['Attribute'] = 'name'
+        data['Signature'] = generate_signature(data, 'POST', 'localhost')
+
+        get = mock.Mock()
+        get.return_value.text = read_file(
+            'tests/data/valid_describe_instance.json'
+        )
+        get.return_value.status_code = 200
+
+        with mock.patch('requests.get', get):
+            response = self.post(
+                '/',
+                data=data
+            )
+
+        self.assert_ok(response)
+        assert 'DescribeInstanceAttributeResponse' in response.data
+