'SnapshotId': {'Type': 'String'},
'Tags': {'Type': 'List'}}
+ _restore_property = 'SnapshotId'
+
+ def _display_name(self):
+ return self.physical_resource_name()
+
+ def _display_description(self):
+ return self.physical_resource_name()
+
+ def _create_arguments(self):
+ return {'size': self.properties['Size'],
+ 'availability_zone': self.properties['AvailabilityZone']}
+
def handle_create(self):
- backup_id = self.properties.get('SnapshotId')
+ backup_id = self.properties.get(self._restore_property)
cinder = self.cinder()
if backup_id is not None:
if volume_backups is None:
- raise exception.Error('SnapshotId not supported')
+ raise exception.Error(
+ '%s not supported' % self._restore_property)
vol_id = cinder.restores.restore(backup_id)['volume_id']
vol = cinder.volumes.get(vol_id)
vol.update(
- display_name=self.physical_resource_name(),
- display_description=self.physical_resource_name())
+ display_name=self._display_name(),
+ display_description=self._display_description())
else:
vol = cinder.volumes.create(
- self.properties['Size'],
- display_name=self.physical_resource_name(),
- display_description=self.physical_resource_name())
+ display_name=self._display_name(),
+ display_description=self._display_description(),
+ **self._create_arguments())
while vol.status == 'creating':
eventlet.sleep(1)
self.stack.clients.detach_volume_from_instance(server_id, volume_id)
+class CinderVolume(Volume):
+
+ properties_schema = {'availability_zone': {'Type': 'String',
+ 'Required': True},
+ 'size': {'Type': 'Number'},
+ 'snapshot_id': {'Type': 'String'},
+ 'backup_id': {'Type': 'String'},
+ 'name': {'Type': 'String'},
+ 'description': {'Type': 'String'},
+ 'volume_type': {'Type': 'String'},
+ 'metadata': {'Type': 'Map'},
+ 'imageRef': {'Type': 'String'},
+ 'source_volid': {'Type': 'String'}}
+
+ _restore_property = 'backup_id'
+
+ def _display_name(self):
+ name = self.properties['name']
+ if name:
+ return name
+ return super(CinderVolume, self)._display_name()
+
+ def _display_description(self):
+ return self.properties['description']
+
+ def _create_arguments(self):
+ arguments = {
+ 'size': self.properties['size'],
+ 'availability_zone': self.properties['availability_zone']
+ }
+ optionals = ['snapshot_id', 'volume_type', 'imageRef', 'source_volid',
+ 'metadata']
+ arguments.update((prop, self.properties[prop]) for prop in optionals
+ if self.properties[prop])
+ return arguments
+
+
def resource_mapping():
return {
'AWS::EC2::Volume': Volume,
'AWS::EC2::VolumeAttachment': VolumeAttachment,
+ 'OS::Cinder::Volume': CinderVolume,
}
setup_dummy_db()
def create_volume(self, t, stack, resource_name):
- resource = vol.Volume(resource_name,
- t['Resources'][resource_name],
- stack)
+ data = t['Resources'][resource_name]
+ data['Properties']['AvailabilityZone'] = 'nova'
+ resource = vol.Volume(resource_name, data, stack)
self.assertEqual(resource.validate(), None)
scheduler.TaskRunner(resource.create)()
self.assertEqual(resource.state, vol.Volume.CREATE_COMPLETE)
clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
# delete script
# create script
clients.OpenStackClients.cinder().AndReturn(self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
eventlet.sleep(1).AndReturn(None)
self.m.ReplayAll()
t = template_format.parse(volume_template)
+ t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
stack = parse_stack(t, stack_name=stack_name)
resource = vol.Volume('DataVolume',
clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
# create script
self.m.ReplayAll()
t = template_format.parse(volume_template)
+ t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
stack = parse_stack(t, stack_name=stack_name)
scheduler.TaskRunner(stack['DataVolume'].create)()
clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
# create script
self.m.ReplayAll()
t = template_format.parse(volume_template)
+ t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
stack = parse_stack(t, stack_name=stack_name)
scheduler.TaskRunner(stack['DataVolume'].create)()
clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
eventlet.sleep(1).AndReturn(None)
clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
eventlet.sleep(1).AndReturn(None)
clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
self.cinder_fc)
self.cinder_fc.volumes.create(
- u'1', display_description='%s.DataVolume' % stack_name,
+ size=u'1', availability_zone='nova',
+ display_description='%s.DataVolume' % stack_name,
display_name='%s.DataVolume' % stack_name).AndReturn(fv)
eventlet.sleep(1).AndReturn(None)
t = template_format.parse(volume_template)
t['Resources']['DataVolume']['DeletionPolicy'] = 'Snapshot'
+ t['Resources']['DataVolume']['Properties']['AvailabilityZone'] = 'nova'
stack = parse_stack(t, stack_name=stack_name)
resource = vol.Volume('DataVolume',
t['Resources']['DataVolume'],
self.m.VerifyAll()
+ def test_cinder_create(self):
+ fv = FakeVolume('creating', 'available')
+ stack_name = 'test_volume_stack'
+
+ clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
+ self.cinder_fc)
+ self.cinder_fc.volumes.create(
+ size=u'1', availability_zone='nova',
+ display_description='CustomDescription',
+ display_name='CustomName',
+ imageRef='Image1',
+ snapshot_id='snap-123',
+ metadata={'key': 'value'},
+ source_volid='vol-012',
+ volume_type='lvm').AndReturn(fv)
+
+ eventlet.sleep(1).AndReturn(None)
+
+ self.m.ReplayAll()
+
+ t = template_format.parse(volume_template)
+ t['Resources']['DataVolume']['Properties'] = {
+ 'size': '1',
+ 'availability_zone': 'nova',
+ 'name': 'CustomName',
+ 'description': 'CustomDescription',
+ 'volume_type': 'lvm',
+ 'metadata': {'key': 'value'},
+ # Note that specifying all these arguments doesn't work in
+ # practice, as they are conflicting, but we just want to check they
+ # are sent to the backend.
+ 'imageRef': 'Image1',
+ 'snapshot_id': 'snap-123',
+ 'source_volid': 'vol-012',
+ }
+ stack = parse_stack(t, stack_name=stack_name)
+
+ resource = vol.CinderVolume('DataVolume',
+ t['Resources']['DataVolume'],
+ stack)
+ self.assertEqual(resource.validate(), None)
+ scheduler.TaskRunner(resource.create)()
+ self.assertEqual(resource.state, vol.Volume.CREATE_COMPLETE)
+ self.assertEqual(fv.status, 'available')
+
+ self.m.VerifyAll()
+
+ def test_cinder_default(self):
+ fv = FakeVolume('creating', 'available')
+ stack_name = 'test_volume_stack'
+
+ clients.OpenStackClients.cinder().MultipleTimes().AndReturn(
+ self.cinder_fc)
+ self.cinder_fc.volumes.create(
+ size=u'1', availability_zone='nova',
+ display_description=None,
+ display_name='%s.DataVolume' % stack_name).AndReturn(fv)
+
+ eventlet.sleep(1).AndReturn(None)
+
+ self.m.ReplayAll()
+
+ t = template_format.parse(volume_template)
+ t['Resources']['DataVolume']['Properties'] = {
+ 'size': '1',
+ 'availability_zone': 'nova',
+ }
+ stack = parse_stack(t, stack_name=stack_name)
+
+ resource = vol.CinderVolume('DataVolume',
+ t['Resources']['DataVolume'],
+ stack)
+ self.assertEqual(resource.validate(), None)
+ scheduler.TaskRunner(resource.create)()
+ self.assertEqual(resource.state, vol.Volume.CREATE_COMPLETE)
+ self.assertEqual(fv.status, 'available')
+
+ self.m.VerifyAll()
+
class FakeVolume:
status = 'attaching'