dfilppi | 9981f55 | 2017-08-07 20:10:53 +0000 | [diff] [blame^] | 1 | ######### |
| 2 | # Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # * See the License for the specific language governing permissions and |
| 14 | # * limitations under the License. |
| 15 | |
| 16 | import time |
| 17 | |
| 18 | from cloudify import ctx |
| 19 | from cloudify.decorators import operation |
| 20 | from cloudify import exceptions as cfy_exc |
| 21 | |
| 22 | from openstack_plugin_common import (delete_resource_and_runtime_properties, |
| 23 | with_cinder_client, |
| 24 | get_resource_id, |
| 25 | transform_resource_name, |
| 26 | use_external_resource, |
| 27 | validate_resource, |
| 28 | COMMON_RUNTIME_PROPERTIES_KEYS, |
| 29 | OPENSTACK_AZ_PROPERTY, |
| 30 | OPENSTACK_ID_PROPERTY, |
| 31 | OPENSTACK_TYPE_PROPERTY, |
| 32 | OPENSTACK_NAME_PROPERTY) |
| 33 | from glance_plugin.image import handle_image_from_relationship |
| 34 | |
| 35 | VOLUME_STATUS_CREATING = 'creating' |
| 36 | VOLUME_STATUS_DELETING = 'deleting' |
| 37 | VOLUME_STATUS_AVAILABLE = 'available' |
| 38 | VOLUME_STATUS_IN_USE = 'in-use' |
| 39 | VOLUME_STATUS_ERROR = 'error' |
| 40 | VOLUME_STATUS_ERROR_DELETING = 'error_deleting' |
| 41 | VOLUME_ERROR_STATUSES = (VOLUME_STATUS_ERROR, VOLUME_STATUS_ERROR_DELETING) |
| 42 | |
| 43 | # Note: The 'device_name' property should actually be a property of the |
| 44 | # relationship between a server and a volume; It'll move to that |
| 45 | # relationship type once relationship properties are better supported. |
| 46 | DEVICE_NAME_PROPERTY = 'device_name' |
| 47 | |
| 48 | VOLUME_OPENSTACK_TYPE = 'volume' |
| 49 | |
| 50 | RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS |
| 51 | |
| 52 | |
| 53 | @operation |
| 54 | @with_cinder_client |
| 55 | def create(cinder_client, status_attempts, status_timeout, args, **kwargs): |
| 56 | |
| 57 | if use_external_resource(ctx, cinder_client, VOLUME_OPENSTACK_TYPE, |
| 58 | 'name'): |
| 59 | return |
| 60 | |
| 61 | name = get_resource_id(ctx, VOLUME_OPENSTACK_TYPE) |
| 62 | volume_dict = {'name': name} |
| 63 | volume_dict.update(ctx.node.properties['volume'], **args) |
| 64 | handle_image_from_relationship(volume_dict, 'imageRef', ctx) |
| 65 | volume_dict['name'] = transform_resource_name( |
| 66 | ctx, volume_dict['name']) |
| 67 | |
| 68 | v = cinder_client.volumes.create(**volume_dict) |
| 69 | |
| 70 | ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = v.id |
| 71 | ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ |
| 72 | VOLUME_OPENSTACK_TYPE |
| 73 | ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = \ |
| 74 | volume_dict['name'] |
| 75 | wait_until_status(cinder_client=cinder_client, |
| 76 | volume_id=v.id, |
| 77 | status=VOLUME_STATUS_AVAILABLE, |
| 78 | num_tries=status_attempts, |
| 79 | timeout=status_timeout, |
| 80 | ) |
| 81 | ctx.instance.runtime_properties[OPENSTACK_AZ_PROPERTY] = \ |
| 82 | v.availability_zone |
| 83 | |
| 84 | |
| 85 | @operation |
| 86 | @with_cinder_client |
| 87 | def delete(cinder_client, **kwargs): |
| 88 | delete_resource_and_runtime_properties(ctx, cinder_client, |
| 89 | RUNTIME_PROPERTIES_KEYS) |
| 90 | |
| 91 | |
| 92 | @with_cinder_client |
| 93 | def wait_until_status(cinder_client, volume_id, status, num_tries, |
| 94 | timeout): |
| 95 | for _ in range(num_tries): |
| 96 | volume = cinder_client.volumes.get(volume_id) |
| 97 | |
| 98 | if volume.status in VOLUME_ERROR_STATUSES: |
| 99 | raise cfy_exc.NonRecoverableError( |
| 100 | "Volume {0} is in error state".format(volume_id)) |
| 101 | |
| 102 | if volume.status == status: |
| 103 | return volume, True |
| 104 | time.sleep(timeout) |
| 105 | |
| 106 | ctx.logger.warning("Volume {0} current state: '{1}', " |
| 107 | "expected state: '{2}'".format(volume_id, |
| 108 | volume.status, |
| 109 | status)) |
| 110 | return volume, False |
| 111 | |
| 112 | |
| 113 | @with_cinder_client |
| 114 | def get_attachment(cinder_client, volume_id, server_id): |
| 115 | volume = cinder_client.volumes.get(volume_id) |
| 116 | for attachment in volume.attachments: |
| 117 | if attachment['server_id'] == server_id: |
| 118 | return attachment |
| 119 | |
| 120 | |
| 121 | @operation |
| 122 | @with_cinder_client |
| 123 | def creation_validation(cinder_client, **kwargs): |
| 124 | validate_resource(ctx, cinder_client, VOLUME_OPENSTACK_TYPE, |
| 125 | 'name') |