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
+