From 56e8d806303a8d2437940a432750b8a649e79ae0 Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Mon, 9 Apr 2012 22:23:42 +1000 Subject: [PATCH] Get the volumes working properly. Tested with: heat create wp_ebs -t ./templates/WordPress_Single_Instance_With_EBS_Volume.template --parameters="InstanceType=m1.xlarge;KeyName=my_key" Signed-off-by: Angus Salkeld --- heat/engine/parser.py | 5 +++ heat/engine/resources.py | 94 +++++++++++++++++++++++++++++----------- tools/openstack | 6 +-- 3 files changed, 77 insertions(+), 28 deletions(-) diff --git a/heat/engine/parser.py b/heat/engine/parser.py index 69326585..e2823273 100644 --- a/heat/engine/parser.py +++ b/heat/engine/parser.py @@ -109,6 +109,11 @@ class Stack: self.resources[r].start() def stop(self): + # stop VolumeAttachment's first + for r in self.t['Resources']: + if self.t['Resources'][r]['Type'] == 'AWS::EC2::VolumeAttachment': + self.resources[r].stop() + for r in self.t['Resources']: self.resources[r].stop() diff --git a/heat/engine/resources.py b/heat/engine/resources.py index 770778af..6c79934a 100644 --- a/heat/engine/resources.py +++ b/heat/engine/resources.py @@ -13,11 +13,12 @@ # License for the specific language governing permissions and limitations # under the License. +import base64 +import eventlet import logging import os -import time -import base64 import string + from novaclient.v1_1 import client from heat.db import api as db_api @@ -39,12 +40,11 @@ class Resource(object): self.t = json_snippet self.depends_on = [] self.references = [] - self.references_resolved = False self.state = None self.stack = stack self.name = name self.instance_id = None - self._nova = None + self._nova = {} if not self.t.has_key('Properties'): # make a dummy entry to prevent having to check all over the # place for it. @@ -53,18 +53,23 @@ class Resource(object): stack.resolve_static_refs(self.t) stack.resolve_find_in_map(self.t) - def nova(self): - if self._nova: - return self._nova + def nova(self, service_type='compute'): + if self._nova.has_key(service_type): + return self._nova[service_type] username = self.stack.creds['username'] password = self.stack.creds['password'] tenant = self.stack.creds['tenant'] auth_url = self.stack.creds['auth_url'] + if service_type == 'compute': + service_name = 'nova' + else: + service_name = None + - self._nova = client.Client(username, password, tenant, auth_url, - service_type='compute', service_name='nova') - return self._nova + self._nova[service_type] = client.Client(username, password, tenant, auth_url, + service_type=service_type, service_name=service_name) + return self._nova[service_type] def start(self): for c in self.depends_on: @@ -93,7 +98,7 @@ class Resource(object): self.state = new_state def stop(self): - pass + print 'stopping %s id:%s' % (self.name, self.instance_id) def reload(self): pass @@ -194,19 +199,34 @@ class Volume(Resource): self.state_set(self.CREATE_IN_PROGRESS) super(Volume, self).start() - vol = self.nova().volumes.create(self.t['Properties']['Size'], - display_name=self.name, - display_description=self.name) - self.instance_id = vol.id + vol = self.nova('volume').volumes.create(self.t['Properties']['Size'], + display_name=self.name, + display_description=self.name) + + while vol.status == 'creating': + eventlet.sleep(1) + vol.get() + if vol.status == 'available': + self.state_set(self.CREATE_COMPLETE) + self.instance_id = vol.id + else: + self.state_set(self.CREATE_FAILED) def stop(self): if self.state == self.DELETE_IN_PROGRESS or self.state == self.DELETE_COMPLETE: return + + if self.instance_id != None: + vol = self.nova('volume').volumes.get(self.instance_id) + if vol.status == 'in-use': + print 'cant delete volume when in-use' + return + self.state_set(self.DELETE_IN_PROGRESS) Resource.stop(self) if self.instance_id != None: - self.nova().volumes.delete(self.instance_id) + self.nova('volume').volumes.delete(self.instance_id) self.state_set(self.DELETE_COMPLETE) class VolumeAttachment(Resource): @@ -220,11 +240,22 @@ class VolumeAttachment(Resource): self.state_set(self.CREATE_IN_PROGRESS) super(VolumeAttachment, self).start() - att = self.nova().volumes.create_server_volume(self.t['Properties']['InstanceId'], - self.t['Properties']['VolumeId'], - self.t['Properties']['Device']) - self.instance_id = att.id - self.state_set(self.CREATE_COMPLETE) + print 'InstanceId %s' % self.t['Properties']['InstanceId'] + print 'VolumeId %s' % self.t['Properties']['VolumeId'] + print 'Device %s' % self.t['Properties']['Device'] + va = self.nova().volumes.create_server_volume(server_id=self.t['Properties']['InstanceId'], + volume_id=self.t['Properties']['VolumeId'], + device=self.t['Properties']['Device']) + + vol = self.nova('volume').volumes.get(va.id) + while vol.status == 'available' or vol.status == 'attaching': + eventlet.sleep(1) + vol.get() + if vol.status == 'in-use': + self.state_set(self.CREATE_COMPLETE) + self.instance_id = va.id + else: + self.state_set(self.CREATE_FAILED) def stop(self): if self.state == self.DELETE_IN_PROGRESS or self.state == self.DELETE_COMPLETE: @@ -232,9 +263,17 @@ class VolumeAttachment(Resource): self.state_set(self.DELETE_IN_PROGRESS) Resource.stop(self) - if self.instance_id == None: - self.nova().volumes.delete_server_volume(self.t['Properties']['InstanceId'], - self.instance_id) + print 'VolumeAttachment un-attaching %s %s' % (self.instance_id, self.t['Properties']['VolumeId']) + + self.nova().volumes.delete_server_volume(self.t['Properties']['InstanceId'], + self.t['Properties']['VolumeId']) + + vol = self.nova('volume').volumes.get(self.t['Properties']['VolumeId']) + while vol.status == 'in-use': + print 'trying to un-attach %s, but still in-use' % self.instance_id + eventlet.sleep(1) + vol.get() + self.state_set(self.DELETE_COMPLETE) class Instance(Resource): @@ -324,11 +363,16 @@ class Instance(Resource): key_name = self.t['Properties']['KeyName'] image_name = self.t['Properties']['ImageId'] + image_id = None image_list = self.nova().images.list() for o in image_list: if o.name == image_name: image_id = o.id + # TODO(asalkeld) we need to test earlier whether the image_id exists. + if image_id is None: + raise + flavor_list = self.nova().flavors.list() for o in flavor_list: if o.name == flavor: @@ -339,7 +383,7 @@ class Instance(Resource): userdata=self.FnBase64(userdata)) while server.status == 'BUILD': server.get() - time.sleep(0.1) + eventlet.sleep(1) if server.status == 'ACTIVE': self.state_set(self.CREATE_COMPLETE) self.instance_id = server.id diff --git a/tools/openstack b/tools/openstack index 430af6ac..b03f1af6 100755 --- a/tools/openstack +++ b/tools/openstack @@ -25,7 +25,7 @@ function os_start() { action=start sudo systemctl $action qpidd.service mysqld.service sleep 1 - sudo systemctl $action openstack-keystone.service + sudo systemctl $action openstack-keystone.service tgtd.service sleep 1 for svc in api registry do @@ -40,7 +40,7 @@ function os_start() { function os_stop() { action=stop - sudo systemctl $action openstack-keystone.service + sudo systemctl $action openstack-keystone.service tgtd.service for svc in api objectstore compute network volume scheduler cert do sudo systemctl $action openstack-nova-$svc.service @@ -85,7 +85,7 @@ EOF function os_install() { - sudo yum install -y openstack-nova openstack-glance openstack-keystone openstack-dashboard + sudo yum install -y openstack-nova openstack-glance openstack-keystone openstack-dashboard scsi-target-utils sudo dd if=/dev/zero of=/var/lib/nova/nova-volumes.img bs=1M seek=20k count=0 sudo systemctl start mysqld.service sleep 1 -- 2.45.2