diff options
Diffstat (limited to 'aria')
34 files changed, 0 insertions, 4940 deletions
diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/__init__.py deleted file mode 100644 index a9dfcc4473..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/tests/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/tests/__init__.py deleted file mode 100644 index a9dfcc4473..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/tests/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/tests/test_volume.py b/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/tests/test_volume.py deleted file mode 100644 index 0ee85bc334..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/tests/test_volume.py +++ /dev/null @@ -1,342 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import mock -import unittest - -from cloudify import mocks as cfy_mocks -from cloudify import exceptions as cfy_exc -from cloudify.state import current_ctx -from cinder_plugin import volume -from nova_plugin import server -from openstack_plugin_common import (OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY) - - -class TestCinderVolume(unittest.TestCase): - - def _mock(self, **kwargs): - ctx = cfy_mocks.MockCloudifyContext(**kwargs) - current_ctx.set(ctx) - return ctx - - def tearDown(self): - current_ctx.clear() - - def test_create_new(self): - volume_name = 'fake volume name' - volume_description = 'fake volume' - volume_id = '00000000-0000-0000-0000-000000000000' - volume_size = 10 - - volume_properties = { - 'volume': { - 'size': volume_size, - 'description': volume_description - }, - 'use_external_resource': False, - 'device_name': '/dev/fake', - 'resource_id': volume_name, - } - - creating_volume_m = mock.Mock() - creating_volume_m.id = volume_id - creating_volume_m.status = volume.VOLUME_STATUS_CREATING - available_volume_m = mock.Mock() - available_volume_m.id = volume_id - available_volume_m.status = volume.VOLUME_STATUS_AVAILABLE - cinder_client_m = mock.Mock() - cinder_client_m.volumes = mock.Mock() - cinder_client_m.volumes.create = mock.Mock( - return_value=creating_volume_m) - cinder_client_m.volumes.get = mock.Mock( - return_value=available_volume_m) - ctx_m = self._mock(node_id='a', properties=volume_properties) - - volume.create(cinder_client=cinder_client_m, args={}, ctx=ctx_m, - status_attempts=10, status_timeout=2) - - cinder_client_m.volumes.create.assert_called_once_with( - size=volume_size, - name=volume_name, - description=volume_description) - cinder_client_m.volumes.get.assert_called_once_with(volume_id) - self.assertEqual( - volume_id, - ctx_m.instance.runtime_properties[OPENSTACK_ID_PROPERTY]) - self.assertEqual( - volume.VOLUME_OPENSTACK_TYPE, - ctx_m.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY]) - - def test_create_use_existing(self): - volume_id = '00000000-0000-0000-0000-000000000000' - - volume_properties = { - 'use_external_resource': True, - 'device_name': '/dev/fake', - 'resource_id': volume_id, - } - existing_volume_m = mock.Mock() - existing_volume_m.id = volume_id - existing_volume_m.status = volume.VOLUME_STATUS_AVAILABLE - cinder_client_m = mock.Mock() - cinder_client_m.volumes = mock.Mock() - cinder_client_m.volumes.create = mock.Mock() - cinder_client_m.cosmo_get_if_exists = mock.Mock( - return_value=existing_volume_m) - cinder_client_m.get_id_from_resource = mock.Mock( - return_value=volume_id) - ctx_m = self._mock(node_id='a', properties=volume_properties) - - volume.create(cinder_client=cinder_client_m, args={}, ctx=ctx_m, - status_attempts=10, status_timeout=2) - - self.assertFalse(cinder_client_m.volumes.create.called) - self.assertEqual( - volume_id, - ctx_m.instance.runtime_properties[OPENSTACK_ID_PROPERTY]) - self.assertEqual( - volume.VOLUME_OPENSTACK_TYPE, - ctx_m.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY]) - - def test_delete(self): - volume_id = '00000000-0000-0000-0000-000000000000' - volume_name = 'test-volume' - - volume_properties = { - 'use_external_resource': False, - } - - cinder_client_m = mock.Mock() - cinder_client_m.cosmo_delete_resource = mock.Mock() - - ctx_m = self._mock(node_id='a', properties=volume_properties) - ctx_m.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = volume_id - ctx_m.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ - volume.VOLUME_OPENSTACK_TYPE - ctx_m.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = \ - volume_name - - volume.delete(cinder_client=cinder_client_m, ctx=ctx_m) - - cinder_client_m.cosmo_delete_resource.assert_called_once_with( - volume.VOLUME_OPENSTACK_TYPE, volume_id) - self.assertTrue( - OPENSTACK_ID_PROPERTY not in ctx_m.instance.runtime_properties) - self.assertTrue(OPENSTACK_TYPE_PROPERTY - not in ctx_m.instance.runtime_properties) - self.assertTrue(OPENSTACK_NAME_PROPERTY - not in ctx_m.instance.runtime_properties) - - @mock.patch('openstack_plugin_common.NovaClientWithSugar') - @mock.patch('openstack_plugin_common.CinderClientWithSugar') - @mock.patch.object(volume, 'wait_until_status', return_value=(None, True)) - def test_attach(self, wait_until_status_m, cinder_m, nova_m): - volume_id = '00000000-0000-0000-0000-000000000000' - server_id = '11111111-1111-1111-1111-111111111111' - device_name = '/dev/fake' - - volume_ctx = cfy_mocks.MockContext({ - 'node': cfy_mocks.MockContext({ - 'properties': {volume.DEVICE_NAME_PROPERTY: device_name} - }), - 'instance': cfy_mocks.MockContext({ - 'runtime_properties': { - OPENSTACK_ID_PROPERTY: volume_id, - } - }) - }) - server_ctx = cfy_mocks.MockContext({ - 'node': cfy_mocks.MockContext({ - 'properties': {} - }), - 'instance': cfy_mocks.MockContext({ - 'runtime_properties': { - server.OPENSTACK_ID_PROPERTY: server_id - } - }) - }) - - ctx_m = self._mock(node_id='a', - target=server_ctx, - source=volume_ctx) - - nova_instance = nova_m.return_value - cinder_instance = cinder_m.return_value - - server.attach_volume(ctx=ctx_m, status_attempts=10, - status_timeout=2) - - nova_instance.volumes.create_server_volume.assert_called_once_with( - server_id, volume_id, device_name) - wait_until_status_m.assert_called_once_with( - cinder_client=cinder_instance, - volume_id=volume_id, - status=volume.VOLUME_STATUS_IN_USE, - num_tries=10, - timeout=2, - ) - - @mock.patch('openstack_plugin_common.NovaClientWithSugar') - @mock.patch('openstack_plugin_common.CinderClientWithSugar') - def _test_cleanup__after_attach_fails( - self, expected_err_cls, expect_cleanup, - wait_until_status_m, cinder_m, nova_m): - volume_id = '00000000-0000-0000-0000-000000000000' - server_id = '11111111-1111-1111-1111-111111111111' - attachment_id = '22222222-2222-2222-2222-222222222222' - device_name = '/dev/fake' - - attachment = {'id': attachment_id, - 'server_id': server_id, - 'volume_id': volume_id} - - volume_ctx = cfy_mocks.MockContext({ - 'node': cfy_mocks.MockContext({ - 'properties': {volume.DEVICE_NAME_PROPERTY: device_name} - }), - 'instance': cfy_mocks.MockContext({ - 'runtime_properties': { - OPENSTACK_ID_PROPERTY: volume_id, - } - }) - }) - server_ctx = cfy_mocks.MockContext({ - 'node': cfy_mocks.MockContext({ - 'properties': {} - }), - 'instance': cfy_mocks.MockContext({ - 'runtime_properties': { - server.OPENSTACK_ID_PROPERTY: server_id - } - }) - }) - - ctx_m = self._mock(node_id='a', - target=server_ctx, - source=volume_ctx) - - attached_volume = mock.Mock(id=volume_id, - status=volume.VOLUME_STATUS_IN_USE, - attachments=[attachment]) - nova_instance = nova_m.return_value - cinder_instance = cinder_m.return_value - cinder_instance.volumes.get.return_value = attached_volume - - with self.assertRaises(expected_err_cls): - server.attach_volume(ctx=ctx_m, status_attempts=10, - status_timeout=2) - - nova_instance.volumes.create_server_volume.assert_called_once_with( - server_id, volume_id, device_name) - volume.wait_until_status.assert_any_call( - cinder_client=cinder_instance, - volume_id=volume_id, - status=volume.VOLUME_STATUS_IN_USE, - num_tries=10, - timeout=2, - ) - if expect_cleanup: - nova_instance.volumes.delete_server_volume.assert_called_once_with( - server_id, attachment_id) - self.assertEqual(2, volume.wait_until_status.call_count) - volume.wait_until_status.assert_called_with( - cinder_client=cinder_instance, - volume_id=volume_id, - status=volume.VOLUME_STATUS_AVAILABLE, - num_tries=10, - timeout=2) - - def test_cleanup_after_waituntilstatus_throws_recoverable_error(self): - err = cfy_exc.RecoverableError('Some recoverable error') - with mock.patch.object(volume, 'wait_until_status', - side_effect=[err, (None, True)]) as wait_mock: - self._test_cleanup__after_attach_fails(type(err), True, wait_mock) - - def test_cleanup_after_waituntilstatus_throws_any_not_nonrecov_error(self): - class ArbitraryNonRecoverableException(Exception): - pass - err = ArbitraryNonRecoverableException('An exception') - with mock.patch.object(volume, 'wait_until_status', - side_effect=[err, (None, True)]) as wait_mock: - self._test_cleanup__after_attach_fails(type(err), True, wait_mock) - - def test_cleanup_after_waituntilstatus_lets_nonrecov_errors_pass(self): - err = cfy_exc.NonRecoverableError('Some non recoverable error') - with mock.patch.object(volume, 'wait_until_status', - side_effect=[err, (None, True)]) as wait_mock: - self._test_cleanup__after_attach_fails(type(err), False, wait_mock) - - @mock.patch.object(volume, 'wait_until_status', return_value=(None, False)) - def test_cleanup_after_waituntilstatus_times_out(self, wait_mock): - self._test_cleanup__after_attach_fails(cfy_exc.RecoverableError, True, - wait_mock) - - @mock.patch('openstack_plugin_common.NovaClientWithSugar') - @mock.patch('openstack_plugin_common.CinderClientWithSugar') - @mock.patch.object(volume, 'wait_until_status', return_value=(None, True)) - def test_detach(self, wait_until_status_m, cinder_m, nova_m): - volume_id = '00000000-0000-0000-0000-000000000000' - server_id = '11111111-1111-1111-1111-111111111111' - attachment_id = '22222222-2222-2222-2222-222222222222' - - attachment = {'id': attachment_id, - 'server_id': server_id, - 'volume_id': volume_id} - - volume_ctx = cfy_mocks.MockContext({ - 'node': cfy_mocks.MockContext({ - 'properties': {} - }), - 'instance': cfy_mocks.MockContext({ - 'runtime_properties': { - OPENSTACK_ID_PROPERTY: volume_id, - } - }) - }) - server_ctx = cfy_mocks.MockContext({ - 'node': cfy_mocks.MockContext({ - 'properties': {} - }), - 'instance': cfy_mocks.MockContext({ - 'runtime_properties': { - server.OPENSTACK_ID_PROPERTY: server_id - } - }) - }) - - ctx_m = self._mock(node_id='a', - target=server_ctx, - source=volume_ctx) - - attached_volume = mock.Mock(id=volume_id, - status=volume.VOLUME_STATUS_IN_USE, - attachments=[attachment]) - nova_instance = nova_m.return_value - cinder_instance = cinder_m.return_value - cinder_instance.volumes.get.return_value = attached_volume - - server.detach_volume(ctx=ctx_m, status_attempts=10, status_timeout=2) - - nova_instance.volumes.delete_server_volume.assert_called_once_with( - server_id, attachment_id) - volume.wait_until_status.assert_called_once_with( - cinder_client=cinder_instance, - volume_id=volume_id, - status=volume.VOLUME_STATUS_AVAILABLE, - num_tries=10, - timeout=2, - ) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/volume.py b/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/volume.py deleted file mode 100644 index 168681b943..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/cinder_plugin/volume.py +++ /dev/null @@ -1,125 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import time - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify import exceptions as cfy_exc - -from openstack_plugin_common import (delete_resource_and_runtime_properties, - with_cinder_client, - get_resource_id, - transform_resource_name, - use_external_resource, - validate_resource, - COMMON_RUNTIME_PROPERTIES_KEYS, - OPENSTACK_AZ_PROPERTY, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY) -from glance_plugin.image import handle_image_from_relationship - -VOLUME_STATUS_CREATING = 'creating' -VOLUME_STATUS_DELETING = 'deleting' -VOLUME_STATUS_AVAILABLE = 'available' -VOLUME_STATUS_IN_USE = 'in-use' -VOLUME_STATUS_ERROR = 'error' -VOLUME_STATUS_ERROR_DELETING = 'error_deleting' -VOLUME_ERROR_STATUSES = (VOLUME_STATUS_ERROR, VOLUME_STATUS_ERROR_DELETING) - -# Note: The 'device_name' property should actually be a property of the -# relationship between a server and a volume; It'll move to that -# relationship type once relationship properties are better supported. -DEVICE_NAME_PROPERTY = 'device_name' - -VOLUME_OPENSTACK_TYPE = 'volume' - -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS - - -@operation -@with_cinder_client -def create(cinder_client, status_attempts, status_timeout, args, **kwargs): - - if use_external_resource(ctx, cinder_client, VOLUME_OPENSTACK_TYPE, - 'name'): - return - - name = get_resource_id(ctx, VOLUME_OPENSTACK_TYPE) - volume_dict = {'name': name} - volume_dict.update(ctx.node.properties['volume'], **args) - handle_image_from_relationship(volume_dict, 'imageRef', ctx) - volume_dict['name'] = transform_resource_name( - ctx, volume_dict['name']) - - v = cinder_client.volumes.create(**volume_dict) - - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = v.id - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ - VOLUME_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = \ - volume_dict['name'] - wait_until_status(cinder_client=cinder_client, - volume_id=v.id, - status=VOLUME_STATUS_AVAILABLE, - num_tries=status_attempts, - timeout=status_timeout, - ) - ctx.instance.runtime_properties[OPENSTACK_AZ_PROPERTY] = \ - v.availability_zone - - -@operation -@with_cinder_client -def delete(cinder_client, **kwargs): - delete_resource_and_runtime_properties(ctx, cinder_client, - RUNTIME_PROPERTIES_KEYS) - - -@with_cinder_client -def wait_until_status(cinder_client, volume_id, status, num_tries, - timeout): - for _ in range(num_tries): - volume = cinder_client.volumes.get(volume_id) - - if volume.status in VOLUME_ERROR_STATUSES: - raise cfy_exc.NonRecoverableError( - "Volume {0} is in error state".format(volume_id)) - - if volume.status == status: - return volume, True - time.sleep(timeout) - - ctx.logger.warning("Volume {0} current state: '{1}', " - "expected state: '{2}'".format(volume_id, - volume.status, - status)) - return volume, False - - -@with_cinder_client -def get_attachment(cinder_client, volume_id, server_id): - volume = cinder_client.volumes.get(volume_id) - for attachment in volume.attachments: - if attachment['server_id'] == server_id: - return attachment - - -@operation -@with_cinder_client -def creation_validation(cinder_client, **kwargs): - validate_resource(ctx, cinder_client, VOLUME_OPENSTACK_TYPE, - 'name') diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/__init__.py deleted file mode 100644 index 809f033a55..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -######### -# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/image.py b/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/image.py deleted file mode 100644 index a8d5b203f4..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/image.py +++ /dev/null @@ -1,177 +0,0 @@ -######### -# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. -import httplib -from urlparse import urlparse - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError - -from openstack_plugin_common import ( - with_glance_client, - get_resource_id, - use_external_resource, - get_openstack_ids_of_connected_nodes_by_openstack_type, - delete_resource_and_runtime_properties, - validate_resource, - COMMON_RUNTIME_PROPERTIES_KEYS, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY) - - -IMAGE_OPENSTACK_TYPE = 'image' -IMAGE_STATUS_ACTIVE = 'active' - -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS -REQUIRED_PROPERTIES = ['container_format', 'disk_format'] - - -@operation -@with_glance_client -def create(glance_client, **kwargs): - if use_external_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE): - return - - img_dict = { - 'name': get_resource_id(ctx, IMAGE_OPENSTACK_TYPE) - } - _validate_image_dictionary() - img_properties = ctx.node.properties['image'] - img_dict.update({key: value for key, value in img_properties.iteritems() - if key != 'data'}) - img = glance_client.images.create(**img_dict) - img_path = img_properties.get('data', '') - img_url = ctx.node.properties.get('image_url') - try: - _validate_image() - if img_path: - with open(img_path, 'rb') as image_file: - glance_client.images.upload( - image_id=img.id, - image_data=image_file) - elif img_url: - img = glance_client.images.add_location(img.id, img_url, {}) - - except: - _remove_protected(glance_client) - glance_client.images.delete(image_id=img.id) - raise - - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = img.id - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ - IMAGE_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = img.name - - -def _get_image_by_ctx(glance_client, ctx): - return glance_client.images.get( - image_id=ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY]) - - -@operation -@with_glance_client -def start(glance_client, start_retry_interval, **kwargs): - img = _get_image_by_ctx(glance_client, ctx) - if img.status != IMAGE_STATUS_ACTIVE: - return ctx.operation.retry( - message='Waiting for image to get uploaded', - retry_after=start_retry_interval) - - -@operation -@with_glance_client -def delete(glance_client, **kwargs): - _remove_protected(glance_client) - delete_resource_and_runtime_properties(ctx, glance_client, - RUNTIME_PROPERTIES_KEYS) - - -@operation -@with_glance_client -def creation_validation(glance_client, **kwargs): - validate_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE) - _validate_image_dictionary() - _validate_image() - - -def _validate_image_dictionary(): - img = ctx.node.properties['image'] - missing = '' - try: - for prop in REQUIRED_PROPERTIES: - if prop not in img: - missing += '{0} '.format(prop) - except TypeError: - missing = ' '.join(REQUIRED_PROPERTIES) - if missing: - raise NonRecoverableError('Required properties are missing: {' - '0}. Please update your image ' - 'dictionary.'.format(missing)) - - -def _validate_image(): - img = ctx.node.properties['image'] - img_path = img.get('data') - img_url = ctx.node.properties.get('image_url') - if not img_url and not img_path: - raise NonRecoverableError('Neither image url nor image path was ' - 'provided') - if img_url and img_path: - raise NonRecoverableError('Multiple image sources provided') - if img_url: - _check_url(img_url) - if img_path: - _check_path() - - -def _check_url(url): - p = urlparse(url) - conn = httplib.HTTPConnection(p.netloc) - conn.request('HEAD', p.path) - resp = conn.getresponse() - if resp.status >= 400: - raise NonRecoverableError('Invalid image URL') - - -def _check_path(): - img = ctx.node.properties['image'] - img_path = img.get('data') - try: - with open(img_path, 'rb'): - pass - except TypeError: - if not img.get('url'): - raise NonRecoverableError('No path or url provided') - except IOError: - raise NonRecoverableError( - 'Unable to open image file with path: "{}"'.format(img_path)) - - -def _remove_protected(glance_client): - if use_external_resource(ctx, glance_client, IMAGE_OPENSTACK_TYPE): - return - - is_protected = ctx.node.properties['image'].get('protected', False) - if is_protected: - img_id = ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - glance_client.images.update(img_id, protected=False) - - -def handle_image_from_relationship(obj_dict, property_name_to_put, ctx): - images = get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, IMAGE_OPENSTACK_TYPE) - if images: - obj_dict.update({property_name_to_put: images[0]}) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/tests/resources/test-image-start.yaml b/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/tests/resources/test-image-start.yaml deleted file mode 100644 index 12c9aa79b7..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/tests/resources/test-image-start.yaml +++ /dev/null @@ -1,30 +0,0 @@ - -tosca_definitions_version: cloudify_dsl_1_3 - -imports: - - https://raw.githubusercontent.com/cloudify-cosmo/cloudify-manager/4.1/resources/rest-service/cloudify/types/types.yaml - - plugin.yaml - -inputs: - use_password: - type: boolean - default: false - -node_templates: - image: - type: cloudify.openstack.nodes.Image - properties: - image: - disk_format: test_format - container_format: test_format - data: test_path - openstack_config: - username: aaa - password: aaa - tenant_name: aaa - auth_url: aaa - interfaces: - cloudify.interfaces.lifecycle: - start: - inputs: - start_retry_interval: 1 diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/tests/test.py b/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/tests/test.py deleted file mode 100644 index 4a88cba4e7..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/glance_plugin/tests/test.py +++ /dev/null @@ -1,148 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import mock -import os -import tempfile -import unittest - -import glance_plugin -from glance_plugin import image - -from cloudify.mocks import MockCloudifyContext -from cloudify.test_utils import workflow_test -from cloudify.exceptions import NonRecoverableError - - -def ctx_mock(image_dict): - return MockCloudifyContext( - node_id='d', - properties=image_dict) - - -class TestCheckImage(unittest.TestCase): - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image': {}})) - def test_check_image_no_file_no_url(self): - # Test if it throws exception no file & no url - self.assertRaises(NonRecoverableError, - image._validate_image) - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image_url': 'test-url', 'image': {'data': '.'}})) - def test_check_image_and_url(self): - # Test if it throws exception file & url - self.assertRaises(NonRecoverableError, - image._validate_image) - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image_url': 'test-url', 'image': {}})) - def test_check_image_url(self): - # test if it passes no file & url - http_connection_mock = mock.MagicMock() - http_connection_mock.return_value.getresponse.return_value.status = 200 - with mock.patch('httplib.HTTPConnection', http_connection_mock): - glance_plugin.image._validate_image() - - def test_check_image_file(self): - # test if it passes file & no url - image_file_path = tempfile.mkstemp()[1] - with mock.patch('glance_plugin.image.ctx', - ctx_mock({'image': {'data': image_file_path}})): - glance_plugin.image._validate_image() - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image': {'data': '/test/path'}})) - # test when open file throws IO error - def test_check_image_bad_file(self): - open_name = '%s.open' % __name__ - with mock.patch(open_name, create=True) as mock_open: - mock_open.side_effect = [mock_open(read_data='Data').return_value] - self.assertRaises(NonRecoverableError, - glance_plugin.image._validate_image) - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image_url': '?', 'image': {}})) - # test when bad url - def test_check_image_bad_url(self): - http_connection_mock = mock.MagicMock() - http_connection_mock.return_value.getresponse.return_value.status = 400 - with mock.patch('httplib.HTTPConnection', http_connection_mock): - self.assertRaises(NonRecoverableError, - glance_plugin.image._validate_image) - - -class TestValidateProperties(unittest.TestCase): - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image': {'container_format': 'bare'}})) - def test_check_image_container_format_no_disk_format(self): - # Test if it throws exception no file & no url - self.assertRaises(NonRecoverableError, - image._validate_image_dictionary) - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image': {'disk_format': 'qcow2'}})) - def test_check_image_no_container_format_disk_format(self): - # Test if it throws exception no container_format & disk_format - self.assertRaises(NonRecoverableError, - image._validate_image_dictionary) - - @mock.patch('glance_plugin.image.ctx', - ctx_mock({'image': {}})) - def test_check_image_no_container_format_no_disk_format(self): - # Test if it throws exception no container_format & no disk_format - self.assertRaises(NonRecoverableError, - image._validate_image_dictionary) - - @mock.patch('glance_plugin.image.ctx', - ctx_mock( - {'image': - {'container_format': 'bare', - 'disk_format': 'qcow2'}})) - def test_check_image_container_format_disk_format(self): - # Test if it do not throw exception container_format & disk_format - image._validate_image_dictionary() - - -class TestStartImage(unittest.TestCase): - blueprint_path = os.path.join('resources', - 'test-image-start.yaml') - - @mock.patch('glance_plugin.image.create') - @workflow_test(blueprint_path, copy_plugin_yaml=True) - def test_image_lifecycle_start(self, cfy_local, *_): - test_vars = { - 'counter': 0, - 'image': mock.MagicMock() - } - - def _mock_get_image_by_ctx(*_): - i = test_vars['image'] - if test_vars['counter'] == 0: - i.status = 'different image status' - else: - i.status = glance_plugin.image.IMAGE_STATUS_ACTIVE - test_vars['counter'] += 1 - return i - - with mock.patch('openstack_plugin_common.GlanceClient'): - with mock.patch('glance_plugin.image._get_image_by_ctx', - side_effect=_mock_get_image_by_ctx): - cfy_local.execute('install', task_retries=3) - - self.assertEqual(2, test_vars['counter']) - self.assertEqual(0, test_vars['image'].start.call_count) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/__init__.py deleted file mode 100644 index 04cb21f745..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'idanmo' diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/floatingip.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/floatingip.py deleted file mode 100644 index 1a9d0449ca..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/floatingip.py +++ /dev/null @@ -1,104 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError -from openstack_plugin_common import ( - with_neutron_client, - provider, - is_external_relationship, - is_external_relationship_not_conditionally_created, - OPENSTACK_ID_PROPERTY -) -from openstack_plugin_common.floatingip import ( - use_external_floatingip, - set_floatingip_runtime_properties, - delete_floatingip, - floatingip_creation_validation -) - - -@operation -@with_neutron_client -def create(neutron_client, args, **kwargs): - - if use_external_floatingip(neutron_client, 'floating_ip_address', - lambda ext_fip: ext_fip['floating_ip_address']): - return - - floatingip = { - # No defaults - } - floatingip.update(ctx.node.properties['floatingip'], **args) - - # Sugar: floating_network_name -> (resolve) -> floating_network_id - if 'floating_network_name' in floatingip: - floatingip['floating_network_id'] = neutron_client.cosmo_get_named( - 'network', floatingip['floating_network_name'])['id'] - del floatingip['floating_network_name'] - elif 'floating_network_id' not in floatingip: - provider_context = provider(ctx) - ext_network = provider_context.ext_network - if ext_network: - floatingip['floating_network_id'] = ext_network['id'] - else: - raise NonRecoverableError( - 'Missing floating network id, name or external network') - - fip = neutron_client.create_floatingip( - {'floatingip': floatingip})['floatingip'] - set_floatingip_runtime_properties(fip['id'], fip['floating_ip_address']) - - ctx.logger.info('Floating IP creation response: {0}'.format(fip)) - - -@operation -@with_neutron_client -def delete(neutron_client, **kwargs): - delete_floatingip(neutron_client) - - -@operation -@with_neutron_client -def creation_validation(neutron_client, **kwargs): - floatingip_creation_validation(neutron_client, 'floating_ip_address') - - -@operation -@with_neutron_client -def connect_port(neutron_client, **kwargs): - if is_external_relationship_not_conditionally_created(ctx): - return - - port_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - floating_ip_id = ctx.target.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - fip = {'port_id': port_id} - neutron_client.update_floatingip(floating_ip_id, {'floatingip': fip}) - - -@operation -@with_neutron_client -def disconnect_port(neutron_client, **kwargs): - if is_external_relationship(ctx): - ctx.logger.info('Not disassociating floatingip and port since ' - 'external floatingip and port are being used') - return - - floating_ip_id = ctx.target.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - fip = {'port_id': None} - neutron_client.update_floatingip(floating_ip_id, {'floatingip': fip}) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/network.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/network.py deleted file mode 100644 index eadcc3b4e8..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/network.py +++ /dev/null @@ -1,109 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError -from openstack_plugin_common import ( - transform_resource_name, - with_neutron_client, - get_resource_id, - is_external_resource, - is_external_resource_not_conditionally_created, - delete_resource_and_runtime_properties, - use_external_resource, - validate_resource, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY, - COMMON_RUNTIME_PROPERTIES_KEYS -) - -NETWORK_OPENSTACK_TYPE = 'network' - -# Runtime properties -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS - - -@operation -@with_neutron_client -def create(neutron_client, args, **kwargs): - - if use_external_resource(ctx, neutron_client, NETWORK_OPENSTACK_TYPE): - return - - network = { - 'admin_state_up': True, - 'name': get_resource_id(ctx, NETWORK_OPENSTACK_TYPE), - } - network.update(ctx.node.properties['network'], **args) - transform_resource_name(ctx, network) - - net = neutron_client.create_network({'network': network})['network'] - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = net['id'] - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] =\ - NETWORK_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = net['name'] - - -@operation -@with_neutron_client -def start(neutron_client, **kwargs): - network_id = ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - if is_external_resource_not_conditionally_created(ctx): - ctx.logger.info('Validating external network is started') - if not neutron_client.show_network( - network_id)['network']['admin_state_up']: - raise NonRecoverableError( - 'Expected external resource network {0} to be in ' - '"admin_state_up"=True'.format(network_id)) - return - - neutron_client.update_network( - network_id, { - 'network': { - 'admin_state_up': True - } - }) - - -@operation -@with_neutron_client -def stop(neutron_client, **kwargs): - if is_external_resource(ctx): - ctx.logger.info('Not stopping network since an external network is ' - 'being used') - return - - neutron_client.update_network( - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY], { - 'network': { - 'admin_state_up': False - } - }) - - -@operation -@with_neutron_client -def delete(neutron_client, **kwargs): - delete_resource_and_runtime_properties(ctx, neutron_client, - RUNTIME_PROPERTIES_KEYS) - - -@operation -@with_neutron_client -def creation_validation(neutron_client, **kwargs): - validate_resource(ctx, neutron_client, NETWORK_OPENSTACK_TYPE) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/port.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/port.py deleted file mode 100644 index 4db4c442c5..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/port.py +++ /dev/null @@ -1,222 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError - -import neutronclient.common.exceptions as neutron_exceptions - -from openstack_plugin_common import ( - transform_resource_name, - with_neutron_client, - with_nova_client, - get_resource_id, - get_openstack_id_of_single_connected_node_by_openstack_type, - delete_resource_and_runtime_properties, - delete_runtime_properties, - use_external_resource, - is_external_relationship, - validate_resource, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY, - COMMON_RUNTIME_PROPERTIES_KEYS, - is_external_relationship_not_conditionally_created) - -from neutron_plugin.network import NETWORK_OPENSTACK_TYPE -from neutron_plugin.subnet import SUBNET_OPENSTACK_TYPE -from openstack_plugin_common.floatingip import get_server_floating_ip - -PORT_OPENSTACK_TYPE = 'port' - -# Runtime properties -FIXED_IP_ADDRESS_PROPERTY = 'fixed_ip_address' # the fixed ip address -MAC_ADDRESS_PROPERTY = 'mac_address' # the mac address -RUNTIME_PROPERTIES_KEYS = \ - COMMON_RUNTIME_PROPERTIES_KEYS + [FIXED_IP_ADDRESS_PROPERTY, - MAC_ADDRESS_PROPERTY] - -NO_SG_PORT_CONNECTION_RETRY_INTERVAL = 3 - - -@operation -@with_neutron_client -def create(neutron_client, args, **kwargs): - - ext_port = use_external_resource(ctx, neutron_client, PORT_OPENSTACK_TYPE) - if ext_port: - try: - net_id = \ - get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE, True) - - if net_id: - port_id = ctx.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - - if neutron_client.show_port( - port_id)['port']['network_id'] != net_id: - raise NonRecoverableError( - 'Expected external resources port {0} and network {1} ' - 'to be connected'.format(port_id, net_id)) - - ctx.instance.runtime_properties[FIXED_IP_ADDRESS_PROPERTY] = \ - _get_fixed_ip(ext_port) - ctx.instance.runtime_properties[MAC_ADDRESS_PROPERTY] = \ - ext_port['mac_address'] - return - except Exception: - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - raise - - net_id = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - - port = { - 'name': get_resource_id(ctx, PORT_OPENSTACK_TYPE), - 'network_id': net_id, - 'security_groups': [], - } - - _handle_fixed_ips(port) - port.update(ctx.node.properties['port'], **args) - transform_resource_name(ctx, port) - - p = neutron_client.create_port({'port': port})['port'] - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = p['id'] - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] =\ - PORT_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = p['name'] - ctx.instance.runtime_properties[FIXED_IP_ADDRESS_PROPERTY] = \ - _get_fixed_ip(p) - ctx.instance.runtime_properties[MAC_ADDRESS_PROPERTY] = p['mac_address'] - - -@operation -@with_neutron_client -def delete(neutron_client, **kwargs): - try: - delete_resource_and_runtime_properties(ctx, neutron_client, - RUNTIME_PROPERTIES_KEYS) - except neutron_exceptions.NeutronClientException, e: - if e.status_code == 404: - # port was probably deleted when an attached device was deleted - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - else: - raise - - -@operation -@with_nova_client -@with_neutron_client -def detach(nova_client, neutron_client, **kwargs): - - if is_external_relationship(ctx): - ctx.logger.info('Not detaching port from server since ' - 'external port and server are being used') - return - - port_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - server_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - server_floating_ip = get_server_floating_ip(neutron_client, server_id) - if server_floating_ip: - ctx.logger.info('We have floating ip {0} attached to server' - .format(server_floating_ip['floating_ip_address'])) - server = nova_client.servers.get(server_id) - server.remove_floating_ip(server_floating_ip['floating_ip_address']) - return ctx.operation.retry( - message='Waiting for the floating ip {0} to ' - 'detach from server {1}..' - .format(server_floating_ip['floating_ip_address'], - server_id), - retry_after=10) - change = { - 'port': { - 'device_id': '', - 'device_owner': '' - } - } - ctx.logger.info('Detaching port {0}...'.format(port_id)) - neutron_client.update_port(port_id, change) - ctx.logger.info('Successfully detached port {0}'.format(port_id)) - - -@operation -@with_neutron_client -def connect_security_group(neutron_client, **kwargs): - port_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - security_group_id = ctx.target.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - - if is_external_relationship_not_conditionally_created(ctx): - ctx.logger.info('Validating external port and security-group are ' - 'connected') - if any(sg for sg in neutron_client.show_port(port_id)['port'].get( - 'security_groups', []) if sg == security_group_id): - return - raise NonRecoverableError( - 'Expected external resources port {0} and security-group {1} to ' - 'be connected'.format(port_id, security_group_id)) - - # WARNING: non-atomic operation - port = neutron_client.cosmo_get('port', id=port_id) - ctx.logger.info( - "connect_security_group(): source_id={0} target={1}".format( - port_id, ctx.target.instance.runtime_properties)) - sgs = port['security_groups'] + [security_group_id] - neutron_client.update_port(port_id, {'port': {'security_groups': sgs}}) - - # Double check if SG has been actually updated (a race-condition - # in OpenStack): - port_info = neutron_client.show_port(port_id)['port'] - port_security_groups = port_info.get('security_groups', []) - if security_group_id not in port_security_groups: - return ctx.operation.retry( - message='Security group connection (`{0}\' -> `{1}\')' - ' has not been established!'.format(port_id, - security_group_id), - retry_after=NO_SG_PORT_CONNECTION_RETRY_INTERVAL - ) - - -@operation -@with_neutron_client -def creation_validation(neutron_client, **kwargs): - validate_resource(ctx, neutron_client, PORT_OPENSTACK_TYPE) - - -def _get_fixed_ip(port): - # a port may have no fixed IP if it's set on a network without subnets - return port['fixed_ips'][0]['ip_address'] if port['fixed_ips'] else None - - -def _handle_fixed_ips(port): - fixed_ips_element = {} - - # checking for fixed ip property - if ctx.node.properties['fixed_ip']: - fixed_ips_element['ip_address'] = ctx.node.properties['fixed_ip'] - - # checking for a connected subnet - subnet_id = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, SUBNET_OPENSTACK_TYPE, if_exists=True) - if subnet_id: - fixed_ips_element['subnet_id'] = subnet_id - - # applying fixed ip parameter, if available - if fixed_ips_element: - port['fixed_ips'] = [fixed_ips_element] diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/router.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/router.py deleted file mode 100644 index 1a2851e4bc..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/router.py +++ /dev/null @@ -1,215 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import warnings - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError - -from openstack_plugin_common import ( - provider, - transform_resource_name, - get_resource_id, - with_neutron_client, - use_external_resource, - is_external_relationship, - is_external_relationship_not_conditionally_created, - delete_runtime_properties, - get_openstack_ids_of_connected_nodes_by_openstack_type, - delete_resource_and_runtime_properties, - get_resource_by_name_or_id, - validate_resource, - COMMON_RUNTIME_PROPERTIES_KEYS, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY -) - -from neutron_plugin.network import NETWORK_OPENSTACK_TYPE - - -ROUTER_OPENSTACK_TYPE = 'router' - -# Runtime properties -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS - - -@operation -@with_neutron_client -def create(neutron_client, args, **kwargs): - - if use_external_resource(ctx, neutron_client, ROUTER_OPENSTACK_TYPE): - try: - ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client) - - if ext_net_id_by_rel: - router_id = \ - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - router = neutron_client.show_router(router_id)['router'] - if not (router['external_gateway_info'] and 'network_id' in - router['external_gateway_info'] and - router['external_gateway_info']['network_id'] == - ext_net_id_by_rel): - raise NonRecoverableError( - 'Expected external resources router {0} and ' - 'external network {1} to be connected'.format( - router_id, ext_net_id_by_rel)) - return - except Exception: - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - raise - - router = { - 'name': get_resource_id(ctx, ROUTER_OPENSTACK_TYPE), - } - router.update(ctx.node.properties['router'], **args) - transform_resource_name(ctx, router) - - _handle_external_network_config(router, neutron_client) - - r = neutron_client.create_router({'router': router})['router'] - - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = r['id'] - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] =\ - ROUTER_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = r['name'] - - -@operation -@with_neutron_client -def connect_subnet(neutron_client, **kwargs): - router_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - subnet_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - if is_external_relationship_not_conditionally_created(ctx): - ctx.logger.info('Validating external subnet and router ' - 'are associated') - for port in neutron_client.list_ports(device_id=router_id)['ports']: - for fixed_ip in port.get('fixed_ips', []): - if fixed_ip.get('subnet_id') == subnet_id: - return - raise NonRecoverableError( - 'Expected external resources router {0} and subnet {1} to be ' - 'connected'.format(router_id, subnet_id)) - - neutron_client.add_interface_router(router_id, {'subnet_id': subnet_id}) - - -@operation -@with_neutron_client -def disconnect_subnet(neutron_client, **kwargs): - if is_external_relationship(ctx): - ctx.logger.info('Not connecting subnet and router since external ' - 'subnet and router are being used') - return - - neutron_client.remove_interface_router( - ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY], { - 'subnet_id': ctx.source.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - } - ) - - -@operation -@with_neutron_client -def delete(neutron_client, **kwargs): - delete_resource_and_runtime_properties(ctx, neutron_client, - RUNTIME_PROPERTIES_KEYS) - - -@operation -@with_neutron_client -def creation_validation(neutron_client, **kwargs): - validate_resource(ctx, neutron_client, ROUTER_OPENSTACK_TYPE) - - -def _insert_ext_net_id_to_router_config(ext_net_id, router): - router['external_gateway_info'] = router.get( - 'external_gateway_info', {}) - router['external_gateway_info']['network_id'] = ext_net_id - - -def _handle_external_network_config(router, neutron_client): - # attempting to find an external network for the router to connect to - - # first by either a network name or id passed in explicitly; then by a - # network connected by a relationship; with a final optional fallback to an - # external network set in the Provider-context. Otherwise the router will - # simply not get connected to an external network - - provider_context = provider(ctx) - - ext_net_id_by_rel = _get_connected_ext_net_id(neutron_client) - ext_net_by_property = ctx.node.properties['external_network'] - - # the following is meant for backwards compatibility with the - # 'network_name' sugaring - if 'external_gateway_info' in router and 'network_name' in \ - router['external_gateway_info']: - warnings.warn( - 'Passing external "network_name" inside the ' - 'external_gateway_info key of the "router" property is now ' - 'deprecated; Use the "external_network" property instead', - DeprecationWarning) - - ext_net_by_property = router['external_gateway_info']['network_name'] - del (router['external_gateway_info']['network_name']) - - # need to check if the user explicitly passed network_id in the external - # gateway configuration as it affects external network behavior by - # relationship and/or provider context - if 'external_gateway_info' in router and 'network_id' in \ - router['external_gateway_info']: - ext_net_by_property = router['external_gateway_info']['network_name'] - - if ext_net_by_property and ext_net_id_by_rel: - raise RuntimeError( - "Router can't have an external network connected by both a " - 'relationship and by a network name/id') - - if ext_net_by_property: - ext_net_id = get_resource_by_name_or_id( - ext_net_by_property, NETWORK_OPENSTACK_TYPE, neutron_client)['id'] - _insert_ext_net_id_to_router_config(ext_net_id, router) - elif ext_net_id_by_rel: - _insert_ext_net_id_to_router_config(ext_net_id_by_rel, router) - elif ctx.node.properties['default_to_managers_external_network'] and \ - provider_context.ext_network: - _insert_ext_net_id_to_router_config(provider_context.ext_network['id'], - router) - - -def _check_if_network_is_external(neutron_client, network_id): - return neutron_client.show_network( - network_id)['network']['router:external'] - - -def _get_connected_ext_net_id(neutron_client): - ext_net_ids = \ - [net_id - for net_id in - get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) if - _check_if_network_is_external(neutron_client, net_id)] - - if len(ext_net_ids) > 1: - raise NonRecoverableError( - 'More than one external network is connected to router {0}' - ' by a relationship; External network IDs: {0}'.format( - ext_net_ids)) - - return ext_net_ids[0] if ext_net_ids else None diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/security_group.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/security_group.py deleted file mode 100644 index 5f335f482b..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/security_group.py +++ /dev/null @@ -1,130 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from time import sleep - -from requests.exceptions import RequestException - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError -from openstack_plugin_common import ( - transform_resource_name, - with_neutron_client, - delete_resource_and_runtime_properties, -) -from openstack_plugin_common.security_group import ( - build_sg_data, - process_rules, - use_external_sg, - set_sg_runtime_properties, - delete_sg, - sg_creation_validation, - RUNTIME_PROPERTIES_KEYS -) - -DEFAULT_RULE_VALUES = { - 'direction': 'ingress', - 'ethertype': 'IPv4', - 'port_range_min': 1, - 'port_range_max': 65535, - 'protocol': 'tcp', - 'remote_group_id': None, - 'remote_ip_prefix': '0.0.0.0/0', -} - - -@operation -@with_neutron_client -def create( - neutron_client, args, - status_attempts=10, status_timeout=2, **kwargs -): - - security_group = build_sg_data(args) - if not security_group['description']: - security_group['description'] = ctx.node.properties['description'] - - sg_rules = process_rules(neutron_client, DEFAULT_RULE_VALUES, - 'remote_ip_prefix', 'remote_group_id', - 'port_range_min', 'port_range_max') - - disable_default_egress_rules = ctx.node.properties.get( - 'disable_default_egress_rules') - - if use_external_sg(neutron_client): - return - - transform_resource_name(ctx, security_group) - - sg = neutron_client.create_security_group( - {'security_group': security_group})['security_group'] - - for attempt in range(max(status_attempts, 1)): - sleep(status_timeout) - try: - neutron_client.show_security_group(sg['id']) - except RequestException as e: - ctx.logger.debug("Waiting for SG to be visible. Attempt {}".format( - attempt)) - else: - break - else: - raise NonRecoverableError( - "Timed out waiting for security_group to exist", e) - - set_sg_runtime_properties(sg, neutron_client) - - try: - if disable_default_egress_rules: - for er in _egress_rules(_rules_for_sg_id(neutron_client, - sg['id'])): - neutron_client.delete_security_group_rule(er['id']) - - for sgr in sg_rules: - sgr['security_group_id'] = sg['id'] - neutron_client.create_security_group_rule( - {'security_group_rule': sgr}) - except Exception: - try: - delete_resource_and_runtime_properties( - ctx, neutron_client, - RUNTIME_PROPERTIES_KEYS) - except Exception as e: - raise NonRecoverableError( - 'Exception while tearing down for retry', e) - raise - - -@operation -@with_neutron_client -def delete(neutron_client, **kwargs): - delete_sg(neutron_client) - - -@operation -@with_neutron_client -def creation_validation(neutron_client, **kwargs): - sg_creation_validation(neutron_client, 'remote_ip_prefix') - - -def _egress_rules(rules): - return [rule for rule in rules if rule.get('direction') == 'egress'] - - -def _rules_for_sg_id(neutron_client, id): - rules = neutron_client.list_security_group_rules()['security_group_rules'] - rules = [rule for rule in rules if rule['security_group_id'] == id] - return rules diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/subnet.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/subnet.py deleted file mode 100644 index 6e97c96755..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/subnet.py +++ /dev/null @@ -1,101 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError -from openstack_plugin_common import ( - with_neutron_client, - transform_resource_name, - get_resource_id, - get_openstack_id_of_single_connected_node_by_openstack_type, - delete_resource_and_runtime_properties, - delete_runtime_properties, - use_external_resource, - validate_resource, - validate_ip_or_range_syntax, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY, - COMMON_RUNTIME_PROPERTIES_KEYS -) - -from neutron_plugin.network import NETWORK_OPENSTACK_TYPE - -SUBNET_OPENSTACK_TYPE = 'subnet' - -# Runtime properties -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS - - -@operation -@with_neutron_client -def create(neutron_client, args, **kwargs): - - if use_external_resource(ctx, neutron_client, SUBNET_OPENSTACK_TYPE): - try: - net_id = \ - get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE, True) - - if net_id: - subnet_id = \ - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - if neutron_client.show_subnet( - subnet_id)['subnet']['network_id'] != net_id: - raise NonRecoverableError( - 'Expected external resources subnet {0} and network' - ' {1} to be connected'.format(subnet_id, net_id)) - return - except Exception: - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - raise - - net_id = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - subnet = { - 'name': get_resource_id(ctx, SUBNET_OPENSTACK_TYPE), - 'network_id': net_id, - } - subnet.update(ctx.node.properties['subnet'], **args) - transform_resource_name(ctx, subnet) - - s = neutron_client.create_subnet({'subnet': subnet})['subnet'] - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s['id'] - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ - SUBNET_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = subnet['name'] - - -@operation -@with_neutron_client -def delete(neutron_client, **kwargs): - delete_resource_and_runtime_properties(ctx, neutron_client, - RUNTIME_PROPERTIES_KEYS) - - -@operation -@with_neutron_client -def creation_validation(neutron_client, args, **kwargs): - validate_resource(ctx, neutron_client, SUBNET_OPENSTACK_TYPE) - subnet = dict(ctx.node.properties['subnet'], **args) - - if 'cidr' not in subnet: - err = '"cidr" property must appear under the "subnet" property of a ' \ - 'subnet node' - ctx.logger.error('VALIDATION ERROR: ' + err) - raise NonRecoverableError(err) - validate_ip_or_range_syntax(ctx, subnet['cidr']) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/__init__.py deleted file mode 100644 index 04cb21f745..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__author__ = 'idanmo' diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test.py deleted file mode 100644 index 459c23a6cd..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test.py +++ /dev/null @@ -1,220 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import mock -import random -import string -import unittest - -from cloudify.exceptions import NonRecoverableError -from cloudify.context import BootstrapContext - -from cloudify.mocks import MockCloudifyContext - -import openstack_plugin_common as common -import openstack_plugin_common.tests.test as common_test - -import neutron_plugin -import neutron_plugin.network -import neutron_plugin.port -import neutron_plugin.router -import neutron_plugin.security_group - - -class ResourcesRenamingTest(unittest.TestCase): - def setUp(self): - neutron_plugin.port._find_network_in_related_nodes = mock.Mock() - # *** Configs from files ******************** - common.Config.get = mock.Mock() - common.Config.get.return_value = {} - # *** Neutron ******************** - self.neutron_mock = mock.Mock() - - def neutron_mock_connect(unused_self, unused_cfg): - return self.neutron_mock - common.NeutronClient.connect = neutron_mock_connect - - self.neutron_mock.cosmo_list = mock.Mock() - self.neutron_mock.cosmo_list.return_value = [] - - def _setup_ctx(self, obj_type): - ctx = common_test.create_mock_ctx_with_provider_info( - node_id='__cloudify_id_something_001', - properties={ - obj_type: { - 'name': obj_type + '_name', - }, - 'rules': [] # For security_group - } - ) - return ctx - - def _test(self, obj_type): - ctx = self._setup_ctx(obj_type) - attr = getattr(self.neutron_mock, 'create_' + obj_type) - attr.return_value = { - obj_type: { - 'id': obj_type + '_id', - } - } - getattr(neutron_plugin, obj_type).create(ctx) - calls = attr.mock_calls - self.assertEquals(len(calls), 1) # Exactly one object created - # Indexes into call[]: - # 0 - the only call - # 1 - regular arguments - # 0 - first argument - arg = calls[0][1][0] - self.assertEquals(arg[obj_type]['name'], 'p2_' + obj_type + '_name') - - def test_network(self): - self._test('network') - - def test_port(self): - self._test('port') - - def test_router(self): - self._test('router') - - def test_security_group(self): - self._test('security_group') - - # Network chosen arbitrary for this test. - # Just testing something without prefix. - def test_network_no_prefix(self): - ctx = self._setup_ctx('network') - for pctx in common_test.BOOTSTRAP_CONTEXTS_WITHOUT_PREFIX: - ctx._bootstrap_context = BootstrapContext(pctx) - self.neutron_mock.create_network.reset_mock() - self.neutron_mock.create_network.return_value = { - 'network': { - 'id': 'network_id', - } - } - neutron_plugin.network.create(ctx) - calls = self.neutron_mock.create_network.mock_calls - self.assertEquals(len(calls), 1) # Exactly one network created - # Indexes into call[]: - # 0 - the only call - # 1 - regular arguments - # 0 - first argument - arg = calls[0][1][0] - self.assertEquals(arg['network']['name'], 'network_name', - "Failed with context: " + str(pctx)) - - -def _rand_str(n): - chars = string.ascii_uppercase + string.digits - return ''.join(random.choice(chars) for _ in range(n)) - - -class SecurityGroupTest(unittest.TestCase): - def setUp(self): - # *** Configs from files ******************** - common.Config.get = mock.Mock() - common.Config.get.return_value = {} - # *** Neutron ******************** - self.neutron_mock = mock.Mock() - - def neutron_mock_connect(unused_self, unused_cfg): - return self.neutron_mock - common.NeutronClient.connect = neutron_mock_connect - neutron_plugin.security_group._rules_for_sg_id = mock.Mock() - neutron_plugin.security_group._rules_for_sg_id.return_value = [] - - def _setup_ctx(self): - sg_name = _rand_str(6) + '_new' - ctx = MockCloudifyContext(properties={ - 'security_group': { - 'name': sg_name, - 'description': 'blah' - }, - 'rules': [{'port': 80}], - 'disable_default_egress_rules': True, - }) - return ctx - - def test_sg_new(self): - ctx = self._setup_ctx() - self.neutron_mock.cosmo_list = mock.Mock() - self.neutron_mock.cosmo_list.return_value = [] - self.neutron_mock.create_security_group = mock.Mock() - self.neutron_mock.create_security_group.return_value = { - 'security_group': { - 'description': 'blah', - 'id': ctx['security_group']['name'] + '_id', - } - } - neutron_plugin.security_group.create(ctx) - self.assertTrue(self.neutron_mock.create_security_group.mock_calls) - - def test_sg_use_existing(self): - ctx = self._setup_ctx() - self.neutron_mock.cosmo_list = mock.Mock() - self.neutron_mock.cosmo_list.return_value = [{ - 'id': ctx['security_group']['name'] + '_existing_id', - 'description': 'blah', - 'security_group_rules': [{ - 'remote_group_id': None, - 'direction': 'ingress', - 'protocol': 'tcp', - 'ethertype': 'IPv4', - 'port_range_max': 80, - 'port_range_min': 80, - 'remote_ip_prefix': '0.0.0.0/0', - }] - }] - self.neutron_mock.create_security_group = mock.Mock() - self.neutron_mock.create_security_group.return_value = { - 'security_group': { - 'description': 'blah', - 'id': ctx['security_group']['name'] + '_id', - } - } - neutron_plugin.security_group.create(ctx) - self.assertFalse(self.neutron_mock.create_security_group.mock_calls) - - def test_sg_use_existing_with_other_rules(self): - ctx = self._setup_ctx() - self.neutron_mock.cosmo_list = mock.Mock() - self.neutron_mock.cosmo_list.return_value = [{ - 'id': ctx['security_group']['name'] + '_existing_id', - 'description': 'blah', - 'security_group_rules': [{ - 'remote_group_id': None, - 'direction': 'ingress', - 'protocol': 'tcp', - 'ethertype': 'IPv4', - 'port_range_max': 81, # Note the different port! - 'port_range_min': 81, # Note the different port! - 'remote_ip_prefix': '0.0.0.0/0', - }] - }] - self.neutron_mock.create_security_group = mock.Mock() - self.neutron_mock.create_security_group.return_value = { - 'security_group': { - 'description': 'blah', - 'id': ctx['security_group']['name'] + '_id', - } - } - self.assertRaises( - NonRecoverableError, - neutron_plugin.security_group.create, - ctx - ) - - -if __name__ == '__main__': - unittest.main() diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test_port.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test_port.py deleted file mode 100644 index 1acee3d05d..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test_port.py +++ /dev/null @@ -1,156 +0,0 @@ -######## -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import unittest - -import mock - -import neutron_plugin.port -from cloudify.mocks import (MockCloudifyContext, - MockNodeInstanceContext, - MockRelationshipSubjectContext) -from openstack_plugin_common import (NeutronClientWithSugar, - OPENSTACK_ID_PROPERTY) -from cloudify.exceptions import OperationRetry - - -class TestPort(unittest.TestCase): - - def test_fixed_ips_no_fixed_ips(self): - node_props = {'fixed_ip': ''} - - with mock.patch( - 'neutron_plugin.port.' - 'get_openstack_id_of_single_connected_node_by_openstack_type', - self._get_connected_subnet_mock(return_empty=True)): - with mock.patch( - 'neutron_plugin.port.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - - port = {} - neutron_plugin.port._handle_fixed_ips(port) - - self.assertNotIn('fixed_ips', port) - - def test_fixed_ips_subnet_only(self): - node_props = {'fixed_ip': ''} - - with mock.patch( - 'neutron_plugin.port.' - 'get_openstack_id_of_single_connected_node_by_openstack_type', - self._get_connected_subnet_mock(return_empty=False)): - with mock.patch( - 'neutron_plugin.port.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - - port = {} - neutron_plugin.port._handle_fixed_ips(port) - - self.assertEquals([{'subnet_id': 'some-subnet-id'}], - port.get('fixed_ips')) - - def test_fixed_ips_ip_address_only(self): - node_props = {'fixed_ip': '1.2.3.4'} - - with mock.patch( - 'neutron_plugin.port.' - 'get_openstack_id_of_single_connected_node_by_openstack_type', - self._get_connected_subnet_mock(return_empty=True)): - with mock.patch( - 'neutron_plugin.port.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - - port = {} - neutron_plugin.port._handle_fixed_ips(port) - - self.assertEquals([{'ip_address': '1.2.3.4'}], - port.get('fixed_ips')) - - def test_fixed_ips_subnet_and_ip_address(self): - node_props = {'fixed_ip': '1.2.3.4'} - - with mock.patch( - 'neutron_plugin.port.' - 'get_openstack_id_of_single_connected_node_by_openstack_type', - self._get_connected_subnet_mock(return_empty=False)): - with mock.patch( - 'neutron_plugin.port.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - - port = {} - neutron_plugin.port._handle_fixed_ips(port) - - self.assertEquals([{'ip_address': '1.2.3.4', - 'subnet_id': 'some-subnet-id'}], - port.get('fixed_ips')) - - @staticmethod - def _get_connected_subnet_mock(return_empty=True): - return lambda *args, **kw: None if return_empty else 'some-subnet-id' - - @staticmethod - def _get_mock_ctx_with_node_properties(properties): - return MockCloudifyContext(node_id='test_node_id', - properties=properties) - - -class MockNeutronClient(NeutronClientWithSugar): - """A fake neutron client with hard-coded test data.""" - def __init__(self, update): - self.update = update - self.body = {'port': {'id': 'test-id', 'security_groups': []}} - - def show_port(self, *_): - return self.body - - def update_port(self, _, b, **__): - if self.update: - self.body.update(b) - return - - def cosmo_get(self, *_, **__): - return self.body['port'] - - -class TestPortSG(unittest.TestCase): - @mock.patch('openstack_plugin_common._put_client_in_kw') - def test_connect_sg_to_port(self, *_): - mock_neutron = MockNeutronClient(update=True) - ctx = MockCloudifyContext( - source=MockRelationshipSubjectContext(node=mock.MagicMock(), - instance=mock.MagicMock()), - target=MockRelationshipSubjectContext(node=mock.MagicMock(), - instance=mock.MagicMock())) - - with mock.patch('neutron_plugin.port.ctx', ctx): - neutron_plugin.port.connect_security_group(mock_neutron) - self.assertIsNone(ctx.operation._operation_retry) - - @mock.patch('openstack_plugin_common._put_client_in_kw') - def test_connect_sg_to_port_race_condition(self, *_): - mock_neutron = MockNeutronClient(update=False) - - ctx = MockCloudifyContext( - source=MockRelationshipSubjectContext(node=mock.MagicMock(), - instance=mock.MagicMock()), - target=MockRelationshipSubjectContext( - node=mock.MagicMock(), - instance=MockNodeInstanceContext( - runtime_properties={ - OPENSTACK_ID_PROPERTY: 'test-sg-id'}))) - with mock.patch('neutron_plugin.port.ctx', ctx): - neutron_plugin.port.connect_security_group(mock_neutron, ctx=ctx) - self.assertIsInstance(ctx.operation._operation_retry, - OperationRetry) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test_security_group.py b/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test_security_group.py deleted file mode 100644 index e958cddb33..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/neutron_plugin/tests/test_security_group.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -######### -# Copyright (c) 2016 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import unittest - -from mock import Mock, patch -from requests.exceptions import RequestException - -from neutron_plugin import security_group - -from cloudify.exceptions import NonRecoverableError -from cloudify.state import current_ctx - -from cloudify.mocks import MockCloudifyContext - - -class FakeException(Exception): - pass - - -@patch('openstack_plugin_common.OpenStackClient._validate_auth_params') -@patch('openstack_plugin_common.NeutronClientWithSugar') -class TestSecurityGroup(unittest.TestCase): - - def setUp(self): - super(TestSecurityGroup, self).setUp() - self.nova_client = Mock() - - self.ctx = MockCloudifyContext( - node_id='test', - deployment_id='test', - properties={ - 'description': 'The best Security Group. Great', - 'rules': [], - 'resource_id': 'mock_sg', - 'security_group': { - }, - 'server': {}, - 'openstack_config': { - 'auth_url': 'things/v3', - }, - }, - operation={'retry_number': 0}, - provider_context={'resources': {}} - ) - current_ctx.set(self.ctx) - self.addCleanup(current_ctx.clear) - - findctx = patch( - 'openstack_plugin_common._find_context_in_kw', - return_value=self.ctx, - ) - findctx.start() - self.addCleanup(findctx.stop) - - def test_set_sg_runtime_properties(self, mock_nc, *_): - security_group.create( - nova_client=self.nova_client, - ctx=self.ctx, - args={}, - ) - - self.assertEqual( - { - 'external_type': 'security_group', - 'external_id': mock_nc().get_id_from_resource(), - 'external_name': mock_nc().get_name_from_resource(), - }, - self.ctx.instance.runtime_properties - ) - - def test_create_sg_wait_timeout(self, mock_nc, *_): - mock_nc().show_security_group.side_effect = RequestException - - with self.assertRaises(NonRecoverableError): - security_group.create( - nova_client=self.nova_client, - ctx=self.ctx, - args={}, - status_attempts=3, - status_timeout=0.001, - ) - - @patch( - 'neutron_plugin.security_group.delete_resource_and_runtime_properties') - def test_dont_duplicate_if_failed_rule(self, mock_del_res, mock_nc, *_): - self.ctx.node.properties['rules'] = [ - { - 'port': '🍷', - }, - ] - mock_nc().create_security_group_rule.side_effect = FakeException - mock_del_res.side_effect = FakeException('the 2nd') - - with self.assertRaises(NonRecoverableError) as e: - security_group.create( - nova_client=self.nova_client, - ctx=self.ctx, - args={}, - ) - - self.assertIn('the 2nd', str(e.exception)) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/__init__.py deleted file mode 100644 index bb533273be..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -__author__ = 'idanmo' diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/floatingip.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/floatingip.py deleted file mode 100644 index e770c540a8..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/floatingip.py +++ /dev/null @@ -1,60 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from cloudify import ctx -from cloudify.decorators import operation -from openstack_plugin_common import with_nova_client -from openstack_plugin_common.floatingip import ( - use_external_floatingip, - set_floatingip_runtime_properties, - delete_floatingip, - floatingip_creation_validation -) - - -# random note regarding nova floating-ips: floating ips on nova-net have -# pre-assigned ids, and thus a call "nova.floating_ips.get(<fip_id>)" will -# return a value even if the floating-ip isn't even allocated. -# currently all lookups in the code, including by id, use search (i.e. -# nova.<type>.findall) and lists, which won't return such unallocated -# resources. - -@operation -@with_nova_client -def create(nova_client, args, **kwargs): - - if use_external_floatingip(nova_client, 'ip', - lambda ext_fip: ext_fip.ip): - return - - floatingip = { - 'pool': None - } - floatingip.update(ctx.node.properties['floatingip'], **args) - - fip = nova_client.floating_ips.create(floatingip['pool']) - set_floatingip_runtime_properties(fip.id, fip.ip) - - -@operation -@with_nova_client -def delete(nova_client, **kwargs): - delete_floatingip(nova_client) - - -@operation -@with_nova_client -def creation_validation(nova_client, **kwargs): - floatingip_creation_validation(nova_client, 'ip') diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/keypair.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/keypair.py deleted file mode 100644 index 92281ab9e5..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/keypair.py +++ /dev/null @@ -1,202 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import os -import errno -from getpass import getuser - -from cloudify import ctx -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError -from openstack_plugin_common import ( - with_nova_client, - validate_resource, - use_external_resource, - transform_resource_name, - is_external_resource, - is_external_resource_not_conditionally_created, - delete_runtime_properties, - get_resource_id, - delete_resource_and_runtime_properties, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY, - COMMON_RUNTIME_PROPERTIES_KEYS -) - -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS -KEYPAIR_OPENSTACK_TYPE = 'keypair' - -PRIVATE_KEY_PATH_PROP = 'private_key_path' - - -@operation -@with_nova_client -def create(nova_client, args, **kwargs): - - private_key_path = _get_private_key_path() - pk_exists = _check_private_key_exists(private_key_path) - - if use_external_resource(ctx, nova_client, KEYPAIR_OPENSTACK_TYPE): - if not pk_exists: - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - raise NonRecoverableError( - 'Failed to use external keypair (node {0}): the public key {1}' - ' is available on Openstack, but the private key could not be ' - 'found at {2}'.format(ctx.node.id, - ctx.node.properties['resource_id'], - private_key_path)) - return - - if pk_exists: - raise NonRecoverableError( - "Can't create keypair - private key path already exists: {0}" - .format(private_key_path)) - - keypair = { - 'name': get_resource_id(ctx, KEYPAIR_OPENSTACK_TYPE), - } - keypair.update(ctx.node.properties['keypair'], **args) - transform_resource_name(ctx, keypair) - - keypair = nova_client.keypairs.create(keypair['name'], - keypair.get('public_key')) - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = keypair.id - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ - KEYPAIR_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = keypair.name - - try: - # write private key file - _mkdir_p(os.path.dirname(private_key_path)) - with open(private_key_path, 'w') as f: - f.write(keypair.private_key) - os.chmod(private_key_path, 0600) - except Exception: - _delete_private_key_file() - delete_resource_and_runtime_properties(ctx, nova_client, - RUNTIME_PROPERTIES_KEYS) - raise - - -@operation -@with_nova_client -def delete(nova_client, **kwargs): - if not is_external_resource(ctx): - ctx.logger.info('deleting keypair') - - _delete_private_key_file() - - nova_client.keypairs.delete( - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY]) - else: - ctx.logger.info('not deleting keypair since an external keypair is ' - 'being used') - - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - - -@operation -@with_nova_client -def creation_validation(nova_client, **kwargs): - - def validate_private_key_permissions(private_key_path): - ctx.logger.debug('checking whether private key file {0} has the ' - 'correct permissions'.format(private_key_path)) - if not os.access(private_key_path, os.R_OK): - err = 'private key file {0} is not readable'\ - .format(private_key_path) - ctx.logger.error('VALIDATION ERROR: ' + err) - raise NonRecoverableError(err) - ctx.logger.debug('OK: private key file {0} has the correct ' - 'permissions'.format(private_key_path)) - - def validate_path_owner(path): - ctx.logger.debug('checking whether directory {0} is owned by the ' - 'current user'.format(path)) - from pwd import getpwnam, getpwuid - - user = getuser() - owner = getpwuid(os.stat(path).st_uid).pw_name - current_user_id = str(getpwnam(user).pw_uid) - owner_id = str(os.stat(path).st_uid) - - if not current_user_id == owner_id: - err = '{0} is not owned by the current user (it is owned by {1})'\ - .format(path, owner) - ctx.logger.warning('VALIDATION WARNING: {0}'.format(err)) - return - ctx.logger.debug('OK: {0} is owned by the current user'.format(path)) - - validate_resource(ctx, nova_client, KEYPAIR_OPENSTACK_TYPE) - - private_key_path = _get_private_key_path() - pk_exists = _check_private_key_exists(private_key_path) - - if is_external_resource_not_conditionally_created(ctx): - if pk_exists: - if os.name == 'posix': - validate_private_key_permissions(private_key_path) - validate_path_owner(private_key_path) - else: - err = "can't use external keypair: the public key {0} is " \ - "available on Openstack, but the private key could not be " \ - "found at {1}".format(ctx.node.properties['resource_id'], - private_key_path) - ctx.logger.error('VALIDATION ERROR: {0}'.format(err)) - raise NonRecoverableError(err) - else: - if pk_exists: - err = 'private key path already exists: {0}'.format( - private_key_path) - ctx.logger.error('VALIDATION ERROR: {0}'.format(err)) - raise NonRecoverableError(err) - else: - err = 'private key directory {0} is not writable' - while private_key_path: - if os.path.isdir(private_key_path): - if not os.access(private_key_path, os.W_OK | os.X_OK): - raise NonRecoverableError(err.format(private_key_path)) - else: - break - private_key_path, _ = os.path.split(private_key_path) - - ctx.logger.debug('OK: keypair configuration is valid') - - -def _get_private_key_path(): - return os.path.expanduser(ctx.node.properties[PRIVATE_KEY_PATH_PROP]) - - -def _delete_private_key_file(): - private_key_path = _get_private_key_path() - ctx.logger.debug('deleting private key file at {0}'.format( - private_key_path)) - try: - os.remove(private_key_path) - except OSError as e: - if e.errno == errno.ENOENT: - # file was already deleted somehow - pass - raise - - -def _check_private_key_exists(private_key_path): - return os.path.isfile(private_key_path) - - -def _mkdir_p(path): - if path and not os.path.isdir(path): - os.makedirs(path) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/security_group.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/security_group.py deleted file mode 100644 index 283eae85cf..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/security_group.py +++ /dev/null @@ -1,81 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from cloudify import ctx -from cloudify.decorators import operation -from openstack_plugin_common import ( - transform_resource_name, - with_nova_client, - delete_resource_and_runtime_properties -) -from openstack_plugin_common.security_group import ( - build_sg_data, - process_rules, - use_external_sg, - set_sg_runtime_properties, - delete_sg, - sg_creation_validation, - RUNTIME_PROPERTIES_KEYS -) - - -@operation -@with_nova_client -def create(nova_client, args, **kwargs): - - security_group = build_sg_data(args) - security_group['description'] = ctx.node.properties['description'] - - sgr_default_values = { - 'ip_protocol': 'tcp', - 'from_port': 1, - 'to_port': 65535, - 'cidr': '0.0.0.0/0', - # 'group_id': None, - # 'parent_group_id': None, - } - sg_rules = process_rules(nova_client, sgr_default_values, - 'cidr', 'group_id', 'from_port', 'to_port') - - if use_external_sg(nova_client): - return - - transform_resource_name(ctx, security_group) - - sg = nova_client.security_groups.create( - security_group['name'], security_group['description']) - - set_sg_runtime_properties(sg, nova_client) - - try: - for sgr in sg_rules: - sgr['parent_group_id'] = sg.id - nova_client.security_group_rules.create(**sgr) - except Exception: - delete_resource_and_runtime_properties(ctx, nova_client, - RUNTIME_PROPERTIES_KEYS) - raise - - -@operation -@with_nova_client -def delete(nova_client, **kwargs): - delete_sg(nova_client) - - -@operation -@with_nova_client -def creation_validation(nova_client, **kwargs): - sg_creation_validation(nova_client, 'cidr') diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/server.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/server.py deleted file mode 100644 index 6726f24804..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/server.py +++ /dev/null @@ -1,944 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - - -import os -import time -import copy -import operator - -from novaclient import exceptions as nova_exceptions - -from cloudify import ctx -from cloudify.manager import get_rest_client -from cloudify.decorators import operation -from cloudify.exceptions import NonRecoverableError, RecoverableError -from cinder_plugin import volume -from openstack_plugin_common import ( - provider, - transform_resource_name, - get_resource_id, - get_openstack_ids_of_connected_nodes_by_openstack_type, - with_nova_client, - with_cinder_client, - assign_payload_as_runtime_properties, - get_openstack_id_of_single_connected_node_by_openstack_type, - get_openstack_names_of_connected_nodes_by_openstack_type, - get_single_connected_node_by_openstack_type, - is_external_resource, - is_external_resource_by_properties, - is_external_resource_not_conditionally_created, - is_external_relationship_not_conditionally_created, - use_external_resource, - delete_runtime_properties, - is_external_relationship, - validate_resource, - USE_EXTERNAL_RESOURCE_PROPERTY, - OPENSTACK_AZ_PROPERTY, - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - OPENSTACK_NAME_PROPERTY, - COMMON_RUNTIME_PROPERTIES_KEYS, - with_neutron_client) -from nova_plugin.keypair import KEYPAIR_OPENSTACK_TYPE -from nova_plugin import userdata -from openstack_plugin_common.floatingip import (IP_ADDRESS_PROPERTY, - get_server_floating_ip) -from neutron_plugin.network import NETWORK_OPENSTACK_TYPE -from neutron_plugin.port import PORT_OPENSTACK_TYPE -from cinder_plugin.volume import VOLUME_OPENSTACK_TYPE -from openstack_plugin_common.security_group import \ - SECURITY_GROUP_OPENSTACK_TYPE -from glance_plugin.image import handle_image_from_relationship - -SERVER_OPENSTACK_TYPE = 'server' - -# server status constants. Full lists here: http://docs.openstack.org/api/openstack-compute/2/content/List_Servers-d1e2078.html # NOQA -SERVER_STATUS_ACTIVE = 'ACTIVE' -SERVER_STATUS_BUILD = 'BUILD' -SERVER_STATUS_SHUTOFF = 'SHUTOFF' - -OS_EXT_STS_TASK_STATE = 'OS-EXT-STS:task_state' -SERVER_TASK_STATE_POWERING_ON = 'powering-on' - -MUST_SPECIFY_NETWORK_EXCEPTION_TEXT = 'More than one possible network found.' -SERVER_DELETE_CHECK_SLEEP = 2 - -# Runtime properties -NETWORKS_PROPERTY = 'networks' # all of the server's ips -IP_PROPERTY = 'ip' # the server's private ip -ADMIN_PASSWORD_PROPERTY = 'password' # the server's password -RUNTIME_PROPERTIES_KEYS = COMMON_RUNTIME_PROPERTIES_KEYS + \ - [NETWORKS_PROPERTY, IP_PROPERTY, ADMIN_PASSWORD_PROPERTY] - - -def _get_management_network_id_and_name(neutron_client, ctx): - """Examine the context to find the management network id and name.""" - management_network_id = None - management_network_name = None - provider_context = provider(ctx) - - if ('management_network_name' in ctx.node.properties) and \ - ctx.node.properties['management_network_name']: - management_network_name = \ - ctx.node.properties['management_network_name'] - management_network_name = transform_resource_name( - ctx, management_network_name) - management_network_id = neutron_client.cosmo_get_named( - 'network', management_network_name) - management_network_id = management_network_id['id'] - else: - int_network = provider_context.int_network - if int_network: - management_network_id = int_network['id'] - management_network_name = int_network['name'] # Already transform. - - return management_network_id, management_network_name - - -def _merge_nics(management_network_id, *nics_sources): - """Merge nics_sources into a single nics list, insert mgmt network if - needed. - nics_sources are lists of networks received from several sources - (server properties, relationships to networks, relationships to ports). - Merge them into a single list, and if the management network isn't present - there, prepend it as the first network. - """ - merged = [] - for nics in nics_sources: - merged.extend(nics) - if management_network_id is not None and \ - not any(nic['net-id'] == management_network_id for nic in merged): - merged.insert(0, {'net-id': management_network_id}) - return merged - - -def _normalize_nics(nics): - """Transform the NICs passed to the form expected by openstack. - - If both net-id and port-id are provided, remove net-id: it is ignored - by openstack anyway. - """ - def _normalize(nic): - if 'port-id' in nic and 'net-id' in nic: - nic = nic.copy() - del nic['net-id'] - return nic - return [_normalize(nic) for nic in nics] - - -def _prepare_server_nics(neutron_client, ctx, server): - """Update server['nics'] based on declared relationships. - - server['nics'] should contain the pre-declared nics, then the networks - that the server has a declared relationship to, then the networks - of the ports the server has a relationship to. - - If that doesn't include the management network, it should be prepended - as the first network. - - The management network id and name are stored in the server meta properties - """ - network_ids = get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, PORT_OPENSTACK_TYPE) - management_network_id, management_network_name = \ - _get_management_network_id_and_name(neutron_client, ctx) - if management_network_id is None and (network_ids or port_ids): - # Known limitation - raise NonRecoverableError( - "Nova server with NICs requires " - "'management_network_name' in properties or id " - "from provider context, which was not supplied") - - nics = _merge_nics( - management_network_id, - server.get('nics', []), - [{'net-id': net_id} for net_id in network_ids], - get_port_networks(neutron_client, port_ids)) - - nics = _normalize_nics(nics) - - server['nics'] = nics - if management_network_id is not None: - server['meta']['cloudify_management_network_id'] = \ - management_network_id - if management_network_name is not None: - server['meta']['cloudify_management_network_name'] = \ - management_network_name - - -def _get_boot_volume_relationships(type_name, ctx): - ctx.logger.debug('Instance relationship target instances: {0}'.format(str([ - rel.target.instance.runtime_properties - for rel in ctx.instance.relationships]))) - targets = [ - rel.target.instance - for rel in ctx.instance.relationships - if rel.target.instance.runtime_properties.get( - OPENSTACK_TYPE_PROPERTY) == type_name and - rel.target.node.properties.get('boot', False)] - - if not targets: - return None - elif len(targets) > 1: - raise NonRecoverableError("2 boot volumes not supported") - return targets[0] - - -def _handle_boot_volume(server, ctx): - boot_volume = _get_boot_volume_relationships(VOLUME_OPENSTACK_TYPE, ctx) - if boot_volume: - boot_volume_id = boot_volume.runtime_properties[OPENSTACK_ID_PROPERTY] - ctx.logger.info('boot_volume_id: {0}'.format(boot_volume_id)) - az = boot_volume.runtime_properties[OPENSTACK_AZ_PROPERTY] - # If a block device mapping already exists we shouldn't overwrite it - # completely - bdm = server.setdefault('block_device_mapping', {}) - bdm['vda'] = '{0}:::0'.format(boot_volume_id) - # Some nova configurations allow cross-az server-volume connections, so - # we can't treat that as an error. - if not server.get('availability_zone'): - server['availability_zone'] = az - - -@operation -@with_nova_client -@with_neutron_client -def create(nova_client, neutron_client, args, **kwargs): - """ - Creates a server. Exposes the parameters mentioned in - http://docs.openstack.org/developer/python-novaclient/api/novaclient.v1_1 - .servers.html#novaclient.v1_1.servers.ServerManager.create - """ - - external_server = use_external_resource(ctx, nova_client, - SERVER_OPENSTACK_TYPE) - - if external_server: - _set_network_and_ip_runtime_properties(external_server) - if ctx._local: - return - else: - network_ids = \ - get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - port_ids = get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, PORT_OPENSTACK_TYPE) - try: - _validate_external_server_nics( - neutron_client, - network_ids, - port_ids - ) - _validate_external_server_keypair(nova_client) - return - except Exception: - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - raise - - provider_context = provider(ctx) - - def rename(name): - return transform_resource_name(ctx, name) - - server = { - 'name': get_resource_id(ctx, SERVER_OPENSTACK_TYPE), - } - server.update(copy.deepcopy(ctx.node.properties['server'])) - server.update(copy.deepcopy(args)) - - _handle_boot_volume(server, ctx) - handle_image_from_relationship(server, 'image', ctx) - - if 'meta' not in server: - server['meta'] = dict() - - transform_resource_name(ctx, server) - - ctx.logger.debug( - "server.create() server before transformations: {0}".format(server)) - - for key in 'block_device_mapping', 'block_device_mapping_v2': - if key in server: - # if there is a connected boot volume, don't require the `image` - # property. - # However, python-novaclient requires an `image` input anyway, and - # checks it for truthiness when deciding whether to pass it along - # to the API - if 'image' not in server: - server['image'] = ctx.node.properties.get('image') - break - else: - _handle_image_or_flavor(server, nova_client, 'image') - _handle_image_or_flavor(server, nova_client, 'flavor') - - if provider_context.agents_security_group: - security_groups = server.get('security_groups', []) - asg = provider_context.agents_security_group['name'] - if asg not in security_groups: - security_groups.append(asg) - server['security_groups'] = security_groups - elif not server.get('security_groups', []): - # Make sure that if the server is connected to a security group - # from CREATE time so that there the user can control - # that there is never a time that a running server is not protected. - security_group_names = \ - get_openstack_names_of_connected_nodes_by_openstack_type( - ctx, - SECURITY_GROUP_OPENSTACK_TYPE) - server['security_groups'] = security_group_names - - # server keypair handling - keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, KEYPAIR_OPENSTACK_TYPE, True) - - if 'key_name' in server: - if keypair_id: - raise NonRecoverableError("server can't both have the " - '"key_name" nested property and be ' - 'connected to a keypair via a ' - 'relationship at the same time') - server['key_name'] = rename(server['key_name']) - elif keypair_id: - server['key_name'] = _get_keypair_name_by_id(nova_client, keypair_id) - elif provider_context.agents_keypair: - server['key_name'] = provider_context.agents_keypair['name'] - else: - server['key_name'] = None - ctx.logger.info( - 'server must have a keypair, yet no keypair was connected to the ' - 'server node, the "key_name" nested property ' - "wasn't used, and there is no agent keypair in the provider " - "context. Agent installation can have issues.") - - _fail_on_missing_required_parameters( - server, - ('name', 'flavor'), - 'server') - - _prepare_server_nics(neutron_client, ctx, server) - - ctx.logger.debug( - "server.create() server after transformations: {0}".format(server)) - - userdata.handle_userdata(server) - - ctx.logger.info("Creating VM with parameters: {0}".format(str(server))) - # Store the server dictionary contents in runtime properties - assign_payload_as_runtime_properties(ctx, SERVER_OPENSTACK_TYPE, server) - ctx.logger.debug( - "Asking Nova to create server. All possible parameters are: {0})" - .format(','.join(server.keys()))) - - try: - s = nova_client.servers.create(**server) - except nova_exceptions.BadRequest as e: - if 'Block Device Mapping is Invalid' in str(e): - return ctx.operation.retry( - message='Block Device Mapping is not created yet', - retry_after=30) - if str(e).startswith(MUST_SPECIFY_NETWORK_EXCEPTION_TEXT): - raise NonRecoverableError( - "Can not provision server: management_network_name or id" - " is not specified but there are several networks that the " - "server can be connected to.") - raise - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] = s.id - ctx.instance.runtime_properties[OPENSTACK_TYPE_PROPERTY] = \ - SERVER_OPENSTACK_TYPE - ctx.instance.runtime_properties[OPENSTACK_NAME_PROPERTY] = server['name'] - - -def get_port_networks(neutron_client, port_ids): - - def get_network(port_id): - port = neutron_client.show_port(port_id) - return { - 'net-id': port['port']['network_id'], - 'port-id': port['port']['id'] - } - - return map(get_network, port_ids) - - -@operation -@with_nova_client -def start(nova_client, start_retry_interval, private_key_path, **kwargs): - server = get_server_by_context(nova_client) - - if is_external_resource_not_conditionally_created(ctx): - ctx.logger.info('Validating external server is started') - if server.status != SERVER_STATUS_ACTIVE: - raise NonRecoverableError( - 'Expected external resource server {0} to be in ' - '"{1}" status'.format(server.id, SERVER_STATUS_ACTIVE)) - return - - if server.status == SERVER_STATUS_ACTIVE: - ctx.logger.info('Server is {0}'.format(server.status)) - - if ctx.node.properties['use_password']: - private_key = _get_private_key(private_key_path) - ctx.logger.debug('retrieving password for server') - password = server.get_password(private_key) - - if not password: - return ctx.operation.retry( - message='Waiting for server to post generated password', - retry_after=start_retry_interval) - - ctx.instance.runtime_properties[ADMIN_PASSWORD_PROPERTY] = password - ctx.logger.info('Server has been set with a password') - - _set_network_and_ip_runtime_properties(server) - return - - server_task_state = getattr(server, OS_EXT_STS_TASK_STATE) - - if server.status == SERVER_STATUS_SHUTOFF and \ - server_task_state != SERVER_TASK_STATE_POWERING_ON: - ctx.logger.info('Server is in {0} status - starting server...'.format( - SERVER_STATUS_SHUTOFF)) - server.start() - server_task_state = SERVER_TASK_STATE_POWERING_ON - - if server.status == SERVER_STATUS_BUILD or \ - server_task_state == SERVER_TASK_STATE_POWERING_ON: - return ctx.operation.retry( - message='Waiting for server to be in {0} state but is in {1}:{2} ' - 'state. Retrying...'.format(SERVER_STATUS_ACTIVE, - server.status, - server_task_state), - retry_after=start_retry_interval) - - raise NonRecoverableError( - 'Unexpected server state {0}:{1}'.format(server.status, - server_task_state)) - - -@operation -@with_nova_client -def stop(nova_client, **kwargs): - """ - Stop server. - - Depends on OpenStack implementation, server.stop() might not be supported. - """ - if is_external_resource(ctx): - ctx.logger.info('Not stopping server since an external server is ' - 'being used') - return - - server = get_server_by_context(nova_client) - - if server.status != SERVER_STATUS_SHUTOFF: - nova_client.servers.stop(server) - else: - ctx.logger.info('Server is already stopped') - - -@operation -@with_nova_client -def delete(nova_client, **kwargs): - if not is_external_resource(ctx): - ctx.logger.info('deleting server') - server = get_server_by_context(nova_client) - nova_client.servers.delete(server) - _wait_for_server_to_be_deleted(nova_client, server) - else: - ctx.logger.info('not deleting server since an external server is ' - 'being used') - - delete_runtime_properties(ctx, RUNTIME_PROPERTIES_KEYS) - - -def _wait_for_server_to_be_deleted(nova_client, - server, - timeout=120, - sleep_interval=5): - timeout = time.time() + timeout - while time.time() < timeout: - try: - server = nova_client.servers.get(server) - ctx.logger.debug('Waiting for server "{}" to be deleted. current' - ' status: {}'.format(server.id, server.status)) - time.sleep(sleep_interval) - except nova_exceptions.NotFound: - return - # recoverable error - raise RuntimeError('Server {} has not been deleted. waited for {} seconds' - .format(server.id, timeout)) - - -def get_server_by_context(nova_client): - return nova_client.servers.get( - ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY]) - - -def _set_network_and_ip_runtime_properties(server): - - ips = {} - - if not server.networks: - raise NonRecoverableError( - 'The server was created but not attached to a network. ' - 'Cloudify requires that a server is connected to ' - 'at least one port.' - ) - - manager_network_ip = None - management_network_name = server.metadata.get( - 'cloudify_management_network_name') - - for network, network_ips in server.networks.items(): - if (management_network_name and - network == management_network_name) or not \ - manager_network_ip: - manager_network_ip = next(iter(network_ips or []), None) - ips[network] = network_ips - ctx.instance.runtime_properties[NETWORKS_PROPERTY] = ips - # The ip of this instance in the management network - ctx.instance.runtime_properties[IP_PROPERTY] = manager_network_ip - - -@operation -@with_nova_client -def connect_floatingip(nova_client, fixed_ip, **kwargs): - server_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - floating_ip_id = ctx.target.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - - if is_external_relationship_not_conditionally_created(ctx): - ctx.logger.info('Validating external floatingip and server ' - 'are associated') - if nova_client.floating_ips.get(floating_ip_id).instance_id ==\ - server_id: - return - raise NonRecoverableError( - 'Expected external resources server {0} and floating-ip {1} to be ' - 'connected'.format(server_id, floating_ip_id)) - - floating_ip_address = ctx.target.instance.runtime_properties[ - IP_ADDRESS_PROPERTY] - server = nova_client.servers.get(server_id) - server.add_floating_ip(floating_ip_address, fixed_ip or None) - - server = nova_client.servers.get(server_id) - all_server_ips = reduce(operator.add, server.networks.values()) - if floating_ip_address not in all_server_ips: - return ctx.operation.retry(message='Failed to assign floating ip {0}' - ' to machine {1}.' - .format(floating_ip_address, server_id)) - - -@operation -@with_nova_client -@with_neutron_client -def disconnect_floatingip(nova_client, neutron_client, **kwargs): - if is_external_relationship(ctx): - ctx.logger.info('Not disassociating floatingip and server since ' - 'external floatingip and server are being used') - return - - server_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - ctx.logger.info("Remove floating ip {0}".format( - ctx.target.instance.runtime_properties[IP_ADDRESS_PROPERTY])) - server_floating_ip = get_server_floating_ip(neutron_client, server_id) - if server_floating_ip: - server = nova_client.servers.get(server_id) - server.remove_floating_ip(server_floating_ip['floating_ip_address']) - ctx.logger.info("Floating ip {0} detached from server" - .format(server_floating_ip['floating_ip_address'])) - - -@operation -@with_nova_client -def connect_security_group(nova_client, **kwargs): - server_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - security_group_id = ctx.target.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - security_group_name = ctx.target.instance.runtime_properties[ - OPENSTACK_NAME_PROPERTY] - - if is_external_relationship_not_conditionally_created(ctx): - ctx.logger.info('Validating external security group and server ' - 'are associated') - server = nova_client.servers.get(server_id) - if [sg for sg in server.list_security_group() if sg.id == - security_group_id]: - return - raise NonRecoverableError( - 'Expected external resources server {0} and security-group {1} to ' - 'be connected'.format(server_id, security_group_id)) - - server = nova_client.servers.get(server_id) - for security_group in server.list_security_group(): - # Since some security groups are already attached in - # create this will ensure that they are not attached twice. - if security_group_id != security_group.id and \ - security_group_name != security_group.name: - # to support nova security groups as well, - # we connect the security group by name - # (as connecting by id - # doesn't seem to work well for nova SGs) - server.add_security_group(security_group_name) - - _validate_security_group_and_server_connection_status(nova_client, - server_id, - security_group_id, - security_group_name, - is_connected=True) - - -@operation -@with_nova_client -def disconnect_security_group(nova_client, **kwargs): - if is_external_relationship(ctx): - ctx.logger.info('Not disconnecting security group and server since ' - 'external security group and server are being used') - return - - server_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - security_group_id = ctx.target.instance.runtime_properties[ - OPENSTACK_ID_PROPERTY] - security_group_name = ctx.target.instance.runtime_properties[ - OPENSTACK_NAME_PROPERTY] - server = nova_client.servers.get(server_id) - # to support nova security groups as well, we disconnect the security group - # by name (as disconnecting by id doesn't seem to work well for nova SGs) - server.remove_security_group(security_group_name) - - _validate_security_group_and_server_connection_status(nova_client, - server_id, - security_group_id, - security_group_name, - is_connected=False) - - -@operation -@with_nova_client -@with_cinder_client -def attach_volume(nova_client, cinder_client, status_attempts, - status_timeout, **kwargs): - server_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - volume_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - if is_external_relationship_not_conditionally_created(ctx): - ctx.logger.info('Validating external volume and server ' - 'are connected') - attachment = volume.get_attachment(cinder_client=cinder_client, - volume_id=volume_id, - server_id=server_id) - if attachment: - return - else: - raise NonRecoverableError( - 'Expected external resources server {0} and volume {1} to be ' - 'connected'.format(server_id, volume_id)) - - # Note: The 'device_name' property should actually be a property of the - # relationship between a server and a volume; It'll move to that - # relationship type once relationship properties are better supported. - device = ctx.source.node.properties[volume.DEVICE_NAME_PROPERTY] - nova_client.volumes.create_server_volume( - server_id, - volume_id, - device if device != 'auto' else None) - try: - vol, wait_succeeded = volume.wait_until_status( - cinder_client=cinder_client, - volume_id=volume_id, - status=volume.VOLUME_STATUS_IN_USE, - num_tries=status_attempts, - timeout=status_timeout - ) - if not wait_succeeded: - raise RecoverableError( - 'Waiting for volume status {0} failed - detaching volume and ' - 'retrying..'.format(volume.VOLUME_STATUS_IN_USE)) - if device == 'auto': - # The device name was assigned automatically so we - # query the actual device name - attachment = volume.get_attachment( - cinder_client=cinder_client, - volume_id=volume_id, - server_id=server_id - ) - device_name = attachment['device'] - ctx.logger.info('Detected device name for attachment of volume ' - '{0} to server {1}: {2}' - .format(volume_id, server_id, device_name)) - ctx.source.instance.runtime_properties[ - volume.DEVICE_NAME_PROPERTY] = device_name - except Exception, e: - if not isinstance(e, NonRecoverableError): - _prepare_attach_volume_to_be_repeated( - nova_client, cinder_client, server_id, volume_id, - status_attempts, status_timeout) - raise - - -def _prepare_attach_volume_to_be_repeated( - nova_client, cinder_client, server_id, volume_id, - status_attempts, status_timeout): - - ctx.logger.info('Cleaning after a failed attach_volume() call') - try: - _detach_volume(nova_client, cinder_client, server_id, volume_id, - status_attempts, status_timeout) - except Exception, e: - ctx.logger.error('Cleaning after a failed attach_volume() call failed ' - 'raising a \'{0}\' exception.'.format(e)) - raise NonRecoverableError(e) - - -def _detach_volume(nova_client, cinder_client, server_id, volume_id, - status_attempts, status_timeout): - attachment = volume.get_attachment(cinder_client=cinder_client, - volume_id=volume_id, - server_id=server_id) - if attachment: - nova_client.volumes.delete_server_volume(server_id, attachment['id']) - volume.wait_until_status(cinder_client=cinder_client, - volume_id=volume_id, - status=volume.VOLUME_STATUS_AVAILABLE, - num_tries=status_attempts, - timeout=status_timeout) - - -@operation -@with_nova_client -@with_cinder_client -def detach_volume(nova_client, cinder_client, status_attempts, - status_timeout, **kwargs): - if is_external_relationship(ctx): - ctx.logger.info('Not detaching volume from server since ' - 'external volume and server are being used') - return - - server_id = ctx.target.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - volume_id = ctx.source.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - - _detach_volume(nova_client, cinder_client, server_id, volume_id, - status_attempts, status_timeout) - - -def _fail_on_missing_required_parameters(obj, required_parameters, hint_where): - for k in required_parameters: - if k not in obj: - raise NonRecoverableError( - "Required parameter '{0}' is missing (under host's " - "properties.{1}). Required parameters are: {2}" - .format(k, hint_where, required_parameters)) - - -def _validate_external_server_keypair(nova_client): - keypair_id = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, KEYPAIR_OPENSTACK_TYPE, True) - if not keypair_id: - return - - keypair_instance_id = \ - [node_instance_id for node_instance_id, runtime_props in - ctx.capabilities.get_all().iteritems() if - runtime_props.get(OPENSTACK_ID_PROPERTY) == keypair_id][0] - keypair_node_properties = _get_properties_by_node_instance_id( - keypair_instance_id) - if not is_external_resource_by_properties(keypair_node_properties): - raise NonRecoverableError( - "Can't connect a new keypair node to a server node " - "with '{0}'=True".format(USE_EXTERNAL_RESOURCE_PROPERTY)) - - server = get_server_by_context(nova_client) - if keypair_id == _get_keypair_name_by_id(nova_client, server.key_name): - return - raise NonRecoverableError( - "Expected external resources server {0} and keypair {1} to be " - "connected".format(server.id, keypair_id)) - - -def _get_keypair_name_by_id(nova_client, key_name): - keypair = nova_client.cosmo_get_named(KEYPAIR_OPENSTACK_TYPE, key_name) - return keypair.id - - -def _validate_external_server_nics(neutron_client, network_ids, port_ids): - # validate no new nics are being assigned to an existing server (which - # isn't possible on Openstack) - new_nic_nodes = \ - [node_instance_id for node_instance_id, runtime_props in - ctx.capabilities.get_all().iteritems() if runtime_props.get( - OPENSTACK_TYPE_PROPERTY) in (PORT_OPENSTACK_TYPE, - NETWORK_OPENSTACK_TYPE) and - not is_external_resource_by_properties( - _get_properties_by_node_instance_id(node_instance_id))] - if new_nic_nodes: - raise NonRecoverableError( - "Can't connect new port and/or network nodes to a server node " - "with '{0}'=True".format(USE_EXTERNAL_RESOURCE_PROPERTY)) - - # validate all expected connected networks and ports are indeed already - # connected to the server. note that additional networks (e.g. the - # management network) may be connected as well with no error raised - if not network_ids and not port_ids: - return - - server_id = ctx.instance.runtime_properties[OPENSTACK_ID_PROPERTY] - connected_ports = neutron_client.list_ports(device_id=server_id)['ports'] - - # not counting networks connected by a connected port since allegedly - # the connection should be on a separate port - connected_ports_networks = {port['network_id'] for port in - connected_ports if port['id'] not in port_ids} - connected_ports_ids = {port['id'] for port in - connected_ports} - disconnected_networks = [network_id for network_id in network_ids if - network_id not in connected_ports_networks] - disconnected_ports = [port_id for port_id in port_ids if port_id not - in connected_ports_ids] - if disconnected_networks or disconnected_ports: - raise NonRecoverableError( - 'Expected external resources to be connected to external server {' - '0}: Networks - {1}; Ports - {2}'.format(server_id, - disconnected_networks, - disconnected_ports)) - - -def _get_properties_by_node_instance_id(node_instance_id): - client = get_rest_client() - node_instance = client.node_instances.get(node_instance_id) - node = client.nodes.get(ctx.deployment.id, node_instance.node_id) - return node.properties - - -@operation -@with_nova_client -def creation_validation(nova_client, args, **kwargs): - - def validate_server_property_value_exists(server_props, property_name): - ctx.logger.debug( - 'checking whether {0} exists...'.format(property_name)) - - serv_props_copy = server_props.copy() - try: - handle_image_from_relationship(serv_props_copy, 'image', ctx) - _handle_image_or_flavor(serv_props_copy, nova_client, - property_name) - except (NonRecoverableError, nova_exceptions.NotFound) as e: - # temporary error - once image/flavor_name get removed, these - # errors won't be relevant anymore - err = str(e) - ctx.logger.error('VALIDATION ERROR: ' + err) - raise NonRecoverableError(err) - - prop_value_id = str(serv_props_copy[property_name]) - prop_values = list(nova_client.cosmo_list(property_name)) - for f in prop_values: - if prop_value_id == f.id: - ctx.logger.debug('OK: {0} exists'.format(property_name)) - return - err = '{0} {1} does not exist'.format(property_name, prop_value_id) - ctx.logger.error('VALIDATION ERROR: ' + err) - if prop_values: - ctx.logger.info('list of available {0}s:'.format(property_name)) - for f in prop_values: - ctx.logger.info(' {0:>10} - {1}'.format(f.id, f.name)) - else: - ctx.logger.info('there are no available {0}s'.format( - property_name)) - raise NonRecoverableError(err) - - validate_resource(ctx, nova_client, SERVER_OPENSTACK_TYPE) - - server_props = dict(ctx.node.properties['server'], **args) - validate_server_property_value_exists(server_props, 'flavor') - - -def _get_private_key(private_key_path): - pk_node_by_rel = \ - get_single_connected_node_by_openstack_type( - ctx, KEYPAIR_OPENSTACK_TYPE, True) - - if private_key_path: - if pk_node_by_rel: - raise NonRecoverableError("server can't both have a " - '"private_key_path" input and be ' - 'connected to a keypair via a ' - 'relationship at the same time') - key_path = private_key_path - else: - if pk_node_by_rel and pk_node_by_rel.properties['private_key_path']: - key_path = pk_node_by_rel.properties['private_key_path'] - else: - key_path = ctx.bootstrap_context.cloudify_agent.agent_key_path - - if key_path: - key_path = os.path.expanduser(key_path) - if os.path.isfile(key_path): - return key_path - - err_message = 'Cannot find private key file' - if key_path: - err_message += '; expected file path was {0}'.format(key_path) - raise NonRecoverableError(err_message) - - -def _validate_security_group_and_server_connection_status( - nova_client, server_id, sg_id, sg_name, is_connected): - - # verifying the security group got connected or disconnected - # successfully - this is due to Openstack concurrency issues that may - # take place when attempting to connect/disconnect multiple SGs to the - # same server at the same time - server = nova_client.servers.get(server_id) - - if is_connected ^ any(sg for sg in server.list_security_group() if - sg.id == sg_id): - raise RecoverableError( - message='Security group {0} did not get {2} server {1} ' - 'properly' - .format( - sg_name, - server.name, - 'connected to' if is_connected else 'disconnected from')) - - -def _handle_image_or_flavor(server, nova_client, prop_name): - if prop_name not in server and '{0}_name'.format(prop_name) not in server: - # setting image or flavor - looking it up by name; if not found, then - # the value is assumed to be the id - server[prop_name] = ctx.node.properties[prop_name] - - # temporary error message: once the 'image' and 'flavor' properties - # become mandatory, this will become less relevant - if not server[prop_name]: - raise NonRecoverableError( - 'must set {0} by either setting a "{0}" property or by setting' - ' a "{0}" or "{0}_name" (deprecated) field under the "server" ' - 'property'.format(prop_name)) - - image_or_flavor = \ - nova_client.cosmo_get_if_exists(prop_name, name=server[prop_name]) - if image_or_flavor: - server[prop_name] = image_or_flavor.id - else: # Deprecated sugar - if '{0}_name'.format(prop_name) in server: - prop_name_plural = nova_client.cosmo_plural(prop_name) - server[prop_name] = \ - getattr(nova_client, prop_name_plural).find( - name=server['{0}_name'.format(prop_name)]).id - del server['{0}_name'.format(prop_name)] diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/__init__.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/__init__.py +++ /dev/null diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-keypair-validation-blueprint.yaml b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-keypair-validation-blueprint.yaml deleted file mode 100644 index 22b7fb5362..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-keypair-validation-blueprint.yaml +++ /dev/null @@ -1,23 +0,0 @@ -tosca_definitions_version: cloudify_dsl_1_3 - -imports: - - https://raw.githubusercontent.com/cloudify-cosmo/cloudify-manager/4.1/resources/rest-service/cloudify/types/types.yaml - - plugin.yaml - -inputs: - private_key: {} - is_keypair_external: {} - - -node_templates: - - keypair: - type: cloudify.openstack.nodes.KeyPair - properties: - private_key_path: { get_input: private_key } - use_external_resource: { get_input: is_keypair_external } - openstack_config: - username: aaa - password: aaa - tenant_name: aaa - auth_url: aaa diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-server-create-secgroup.yaml b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-server-create-secgroup.yaml deleted file mode 100644 index 70b75f6bf5..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-server-create-secgroup.yaml +++ /dev/null @@ -1,31 +0,0 @@ -tosca_definitions_version: cloudify_dsl_1_3 - -imports: - - https://raw.githubusercontent.com/cloudify-cosmo/cloudify-manager/4.1/resources/rest-service/cloudify/types/types.yaml - - plugin.yaml - -inputs: - use_password: - type: boolean - default: false - -node_templates: - - security_group: - type: cloudify.openstack.nodes.SecurityGroup - - server: - type: cloudify.openstack.nodes.Server - properties: - install_agent: false - use_password: { get_input: use_password } - openstack_config: - username: aaa - password: aaa - tenant_name: aaa - auth_url: aaa - server: - key_name: 'aa' - relationships: - - type: cloudify.openstack.server_connected_to_security_group - target: security_group diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-start-operation-retry-blueprint.yaml b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-start-operation-retry-blueprint.yaml deleted file mode 100644 index 275806cf5a..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/resources/test-start-operation-retry-blueprint.yaml +++ /dev/null @@ -1,31 +0,0 @@ -tosca_definitions_version: cloudify_dsl_1_3 - -imports: - - https://raw.githubusercontent.com/cloudify-cosmo/cloudify-manager/4.1/resources/rest-service/cloudify/types/types.yaml - - plugin.yaml - -inputs: - use_password: - type: boolean - default: false - -node_templates: - server: - type: cloudify.openstack.nodes.Server - properties: - install_agent: false - use_password: { get_input: use_password } - server: - key_name: key - scheduler_hints: - group: affinity-group-id - openstack_config: - username: aaa - password: aaa - tenant_name: aaa - auth_url: aaa - interfaces: - cloudify.interfaces.lifecycle: - start: - inputs: - start_retry_interval: 1 diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_relationships.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_relationships.py deleted file mode 100644 index 2814057fb7..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_relationships.py +++ /dev/null @@ -1,228 +0,0 @@ -######### -# Copyright (c) 2016 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -"""Test the functions related to retrieving relationship information. - -Functions under test are mostly inside openstack_plugin_common: -get_relationships_by_openstack_type -get_connected_nodes_by_openstack_type -get_openstack_ids_of_connected_nodes_by_openstack_type -get_single_connected_node_by_openstack_type -""" - -import uuid -from unittest import TestCase - -from neutron_plugin.network import NETWORK_OPENSTACK_TYPE - -from cloudify.exceptions import NonRecoverableError - -from cloudify.mocks import ( - MockCloudifyContext, - MockNodeContext, - MockNodeInstanceContext, - MockRelationshipContext, - MockRelationshipSubjectContext, -) -from openstack_plugin_common import ( - OPENSTACK_ID_PROPERTY, - OPENSTACK_TYPE_PROPERTY, - get_openstack_id_of_single_connected_node_by_openstack_type, - get_openstack_ids_of_connected_nodes_by_openstack_type, - get_relationships_by_openstack_type, - get_single_connected_node_by_openstack_type, -) - - -class RelationshipsTestBase(TestCase): - def _make_vm_ctx_with_relationships(self, rel_specs, properties=None): - """Prepare a mock CloudifyContext from the given relationship spec. - - rel_specs is an ordered collection of relationship specs - dicts - with the keys "node" and "instance" used to construct the - MockNodeContext and the MockNodeInstanceContext, and optionally a - "type" key. - Examples: [ - {}, - {"node": {"id": 5}}, - { - "type": "some_type", - "instance": { - "id": 3, - "runtime_properties":{} - } - } - ] - """ - if properties is None: - properties = {} - relationships = [] - for rel_spec in rel_specs: - node = rel_spec.get('node', {}) - node_id = node.pop('id', uuid.uuid4().hex) - - instance = rel_spec.get('instance', {}) - instance_id = instance.pop('id', '{0}_{1}'.format( - node_id, uuid.uuid4().hex)) - if 'properties' not in node: - node['properties'] = {} - node_ctx = MockNodeContext(id=node_id, **node) - instance_ctx = MockNodeInstanceContext(id=instance_id, **instance) - - rel_subject_ctx = MockRelationshipSubjectContext( - node=node_ctx, instance=instance_ctx) - rel_type = rel_spec.get('type') - rel_ctx = MockRelationshipContext(target=rel_subject_ctx, - type=rel_type) - relationships.append(rel_ctx) - return MockCloudifyContext(node_id='vm', properties=properties, - relationships=relationships) - - -class TestGettingRelatedResources(RelationshipsTestBase): - - def test_get_relationships_finds_all_by_type(self): - """get_relationships_by_openstack_type returns all rels that match.""" - rel_specs = [{ - 'instance': { - 'id': instance_id, - 'runtime_properties': { - OPENSTACK_TYPE_PROPERTY: NETWORK_OPENSTACK_TYPE - } - } - } for instance_id in range(3)] - - rel_specs.append({ - 'instance': { - 'runtime_properties': { - OPENSTACK_TYPE_PROPERTY: 'something else' - } - } - }) - - ctx = self._make_vm_ctx_with_relationships(rel_specs) - filtered = get_relationships_by_openstack_type(ctx, - NETWORK_OPENSTACK_TYPE) - self.assertEqual(3, len(filtered)) - - def test_get_ids_of_nodes_by_type(self): - - rel_spec = { - 'instance': { - 'runtime_properties': { - OPENSTACK_TYPE_PROPERTY: NETWORK_OPENSTACK_TYPE, - OPENSTACK_ID_PROPERTY: 'the node id' - } - } - } - ctx = self._make_vm_ctx_with_relationships([rel_spec]) - ids = get_openstack_ids_of_connected_nodes_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - self.assertEqual(['the node id'], ids) - - -class TestGetSingleByID(RelationshipsTestBase): - def _make_instances(self, ids): - """Mock a context with relationships to instances with given ids.""" - rel_specs = [{ - 'node': { - 'id': node_id - }, - 'instance': { - 'runtime_properties': { - OPENSTACK_TYPE_PROPERTY: NETWORK_OPENSTACK_TYPE, - OPENSTACK_ID_PROPERTY: node_id - } - } - } for node_id in ids] - return self._make_vm_ctx_with_relationships(rel_specs) - - def test_get_single_id(self): - ctx = self._make_instances(['the node id']) - found_id = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - self.assertEqual('the node id', found_id) - - def test_get_single_id_two_found(self): - ctx = self._make_instances([0, 1]) - self.assertRaises( - NonRecoverableError, - get_openstack_id_of_single_connected_node_by_openstack_type, ctx, - NETWORK_OPENSTACK_TYPE) - - def test_get_single_id_two_found_if_exists_true(self): - ctx = self._make_instances([0, 1]) - - try: - get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE, if_exists=True) - except NonRecoverableError as e: - self.assertIn(NETWORK_OPENSTACK_TYPE, e.message) - else: - self.fail() - - def test_get_single_id_if_exists_none_found(self): - ctx = self._make_instances([]) - found = get_openstack_id_of_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE, if_exists=True) - self.assertIsNone(found) - - def test_get_single_id_none_found(self): - rel_spec = [] - ctx = self._make_vm_ctx_with_relationships(rel_spec) - self.assertRaises( - NonRecoverableError, - get_openstack_id_of_single_connected_node_by_openstack_type, - ctx, - NETWORK_OPENSTACK_TYPE) - - def test_get_single_node(self): - ctx = self._make_instances(['the node id']) - found_node = get_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE) - self.assertEqual('the node id', found_node.id) - - def test_get_single_node_two_found(self): - ctx = self._make_instances([0, 1]) - self.assertRaises( - NonRecoverableError, - get_single_connected_node_by_openstack_type, - ctx, NETWORK_OPENSTACK_TYPE) - - def test_get_single_node_two_found_if_exists(self): - ctx = self._make_instances([0, 1]) - - self.assertRaises( - NonRecoverableError, - get_single_connected_node_by_openstack_type, - ctx, - NETWORK_OPENSTACK_TYPE, - if_exists=True) - - def test_get_single_node_if_exists_none_found(self): - ctx = self._make_instances([]) - - found = get_single_connected_node_by_openstack_type( - ctx, NETWORK_OPENSTACK_TYPE, if_exists=True) - self.assertIsNone(found) - - def test_get_single_node_none_found(self): - ctx = self._make_instances([]) - - self.assertRaises( - NonRecoverableError, - get_single_connected_node_by_openstack_type, - ctx, - NETWORK_OPENSTACK_TYPE) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_server.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_server.py deleted file mode 100644 index a50930555c..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_server.py +++ /dev/null @@ -1,551 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -from os import path -import tempfile - -import unittest -import mock - -import nova_plugin -from cloudify.test_utils import workflow_test - -from openstack_plugin_common import NeutronClientWithSugar, \ - OPENSTACK_TYPE_PROPERTY, OPENSTACK_ID_PROPERTY -from neutron_plugin.network import NETWORK_OPENSTACK_TYPE -from neutron_plugin.port import PORT_OPENSTACK_TYPE -from nova_plugin.tests.test_relationships import RelationshipsTestBase -from nova_plugin.server import _prepare_server_nics -from cinder_plugin.volume import VOLUME_OPENSTACK_TYPE -from cloudify.exceptions import NonRecoverableError -from cloudify.state import current_ctx - -from cloudify.utils import setup_logger - -from cloudify.mocks import ( - MockNodeContext, - MockCloudifyContext, - MockNodeInstanceContext, - MockRelationshipContext, - MockRelationshipSubjectContext -) - - -class TestServer(unittest.TestCase): - - blueprint_path = path.join('resources', - 'test-start-operation-retry-blueprint.yaml') - - @mock.patch('nova_plugin.server.create') - @mock.patch('nova_plugin.server._set_network_and_ip_runtime_properties') - @workflow_test(blueprint_path, copy_plugin_yaml=True) - def test_nova_server_lifecycle_start(self, cfy_local, *_): - - test_vars = { - 'counter': 0, - 'server': mock.MagicMock() - } - - def mock_get_server_by_context(*_): - s = test_vars['server'] - if test_vars['counter'] == 0: - s.status = nova_plugin.server.SERVER_STATUS_BUILD - else: - s.status = nova_plugin.server.SERVER_STATUS_ACTIVE - test_vars['counter'] += 1 - return s - - with mock.patch('nova_plugin.server.get_server_by_context', - new=mock_get_server_by_context): - cfy_local.execute('install', task_retries=3) - - self.assertEqual(2, test_vars['counter']) - self.assertEqual(0, test_vars['server'].start.call_count) - - @workflow_test(blueprint_path, copy_plugin_yaml=True) - @mock.patch('nova_plugin.server.create') - @mock.patch('nova_plugin.server._set_network_and_ip_runtime_properties') - def test_nova_server_lifecycle_start_after_stop(self, cfy_local, *_): - - test_vars = { - 'counter': 0, - 'server': mock.MagicMock() - } - - def mock_get_server_by_context(_): - s = test_vars['server'] - if test_vars['counter'] == 0: - s.status = nova_plugin.server.SERVER_STATUS_SHUTOFF - elif test_vars['counter'] == 1: - setattr(s, - nova_plugin.server.OS_EXT_STS_TASK_STATE, - nova_plugin.server.SERVER_TASK_STATE_POWERING_ON) - else: - s.status = nova_plugin.server.SERVER_STATUS_ACTIVE - test_vars['counter'] += 1 - test_vars['server'] = s - return s - - with mock.patch('nova_plugin.server.get_server_by_context', - new=mock_get_server_by_context): - cfy_local.execute('install', task_retries=3) - - self.assertEqual(1, test_vars['server'].start.call_count) - self.assertEqual(3, test_vars['counter']) - - @workflow_test(blueprint_path, copy_plugin_yaml=True) - @mock.patch('nova_plugin.server.create') - @mock.patch('nova_plugin.server._set_network_and_ip_runtime_properties') - def test_nova_server_lifecycle_start_unknown_status(self, cfy_local, *_): - test_vars = { - 'counter': 0, - 'server': mock.MagicMock() - } - - def mock_get_server_by_context(_): - s = test_vars['server'] - if test_vars['counter'] == 0: - s.status = '### unknown-status ###' - test_vars['counter'] += 1 - test_vars['server'] = s - return s - - with mock.patch('nova_plugin.server.get_server_by_context', - new=mock_get_server_by_context): - self.assertRaisesRegexp(RuntimeError, - 'Unexpected server state', - cfy_local.execute, - 'install') - - self.assertEqual(0, test_vars['server'].start.call_count) - self.assertEqual(1, test_vars['counter']) - - @workflow_test(blueprint_path, copy_plugin_yaml=True) - @mock.patch('nova_plugin.server.start') - @mock.patch('nova_plugin.server._handle_image_or_flavor') - @mock.patch('nova_plugin.server._fail_on_missing_required_parameters') - @mock.patch('openstack_plugin_common.nova_client') - def test_nova_server_creation_param_integrity( - self, cfy_local, mock_nova, *args): - cfy_local.execute('install', task_retries=0) - calls = mock_nova.Client.return_value.servers.method_calls - self.assertEqual(1, len(calls)) - kws = calls[0][2] - self.assertIn('scheduler_hints', kws) - self.assertEqual(kws['scheduler_hints'], - {'group': 'affinity-group-id'}, - 'expecting \'scheduler_hints\' value to exist') - - @workflow_test(blueprint_path, copy_plugin_yaml=True, - inputs={'use_password': True}) - @mock.patch('nova_plugin.server.create') - @mock.patch('nova_plugin.server._set_network_and_ip_runtime_properties') - @mock.patch( - 'nova_plugin.server.get_single_connected_node_by_openstack_type', - autospec=True, return_value=None) - def test_nova_server_with_use_password(self, cfy_local, *_): - - test_vars = { - 'counter': 0, - 'server': mock.MagicMock() - } - - tmp_path = tempfile.NamedTemporaryFile(prefix='key_name') - key_path = tmp_path.name - - def mock_get_server_by_context(_): - s = test_vars['server'] - if test_vars['counter'] == 0: - s.status = nova_plugin.server.SERVER_STATUS_BUILD - else: - s.status = nova_plugin.server.SERVER_STATUS_ACTIVE - test_vars['counter'] += 1 - - def check_agent_key_path(private_key): - self.assertEqual(private_key, key_path) - return private_key - - s.get_password = check_agent_key_path - return s - - with mock.patch('nova_plugin.server.get_server_by_context', - mock_get_server_by_context): - with mock.patch( - 'cloudify.context.BootstrapContext.' - 'CloudifyAgent.agent_key_path', - new_callable=mock.PropertyMock, return_value=key_path): - cfy_local.execute('install', task_retries=5) - - -class TestMergeNICs(unittest.TestCase): - def test_merge_prepends_management_network(self): - """When the mgmt network isnt in a relationship, its the 1st nic.""" - mgmt_network_id = 'management network' - nics = [{'net-id': 'other network'}] - - merged = nova_plugin.server._merge_nics(mgmt_network_id, nics) - - self.assertEqual(len(merged), 2) - self.assertEqual(merged[0]['net-id'], 'management network') - - def test_management_network_in_relationships(self): - """When the mgmt network was in a relationship, it's not prepended.""" - mgmt_network_id = 'management network' - nics = [{'net-id': 'other network'}, {'net-id': 'management network'}] - - merged = nova_plugin.server._merge_nics(mgmt_network_id, nics) - - self.assertEqual(nics, merged) - - -class TestNormalizeNICs(unittest.TestCase): - def test_normalize_port_priority(self): - """Whe there's both net-id and port-id, port-id is used.""" - nics = [{'net-id': '1'}, {'port-id': '2'}, {'net-id': 3, 'port-id': 4}] - normalized = nova_plugin.server._normalize_nics(nics) - expected = [{'net-id': '1'}, {'port-id': '2'}, {'port-id': 4}] - self.assertEqual(expected, normalized) - - -class MockNeutronClient(NeutronClientWithSugar): - """A fake neutron client with hard-coded test data.""" - - @mock.patch('openstack_plugin_common.OpenStackClient.__init__', - new=mock.Mock()) - def __init__(self): - super(MockNeutronClient, self).__init__() - - @staticmethod - def _search_filter(objs, search_params): - """Mock neutron's filtering by attributes in list_* methods. - - list_* methods (list_networks, list_ports) - """ - def _matches(obj, search_params): - return all(obj[k] == v for k, v in search_params.items()) - return [obj for obj in objs if _matches(obj, search_params)] - - def list_networks(self, **search_params): - networks = [ - {'name': 'network1', 'id': '1'}, - {'name': 'network2', 'id': '2'}, - {'name': 'network3', 'id': '3'}, - {'name': 'network4', 'id': '4'}, - {'name': 'network5', 'id': '5'}, - {'name': 'network6', 'id': '6'}, - {'name': 'other', 'id': 'other'} - ] - return {'networks': self._search_filter(networks, search_params)} - - def list_ports(self, **search_params): - ports = [ - {'name': 'port1', 'id': '1', 'network_id': '1'}, - {'name': 'port2', 'id': '2', 'network_id': '1'}, - {'name': 'port3', 'id': '3', 'network_id': '2'}, - {'name': 'port4', 'id': '4', 'network_id': '2'}, - ] - return {'ports': self._search_filter(ports, search_params)} - - def show_port(self, port_id): - ports = self.list_ports(id=port_id) - return {'port': ports['ports'][0]} - - -class NICTestBase(RelationshipsTestBase): - """Base test class for the NICs tests. - - It comes with helper methods to create a mock cloudify context, with - the specified relationships. - """ - mock_neutron = MockNeutronClient() - - def _relationship_spec(self, obj, objtype): - return {'node': {'properties': obj}, - 'instance': { - 'runtime_properties': {OPENSTACK_TYPE_PROPERTY: objtype, - OPENSTACK_ID_PROPERTY: obj['id']}}} - - def _make_vm_ctx_with_ports(self, management_network_name, ports): - port_specs = [self._relationship_spec(obj, PORT_OPENSTACK_TYPE) - for obj in ports] - vm_properties = {'management_network_name': management_network_name} - return self._make_vm_ctx_with_relationships(port_specs, - vm_properties) - - def _make_vm_ctx_with_networks(self, management_network_name, networks): - network_specs = [self._relationship_spec(obj, NETWORK_OPENSTACK_TYPE) - for obj in networks] - vm_properties = {'management_network_name': management_network_name} - return self._make_vm_ctx_with_relationships(network_specs, - vm_properties) - - -class TestServerNICs(NICTestBase): - """Test preparing the NICs list from server<->network relationships. - - Each test creates a cloudify context that represents a openstack VM - with relationships to networks. Then, examine the NICs list produced from - the relationships. - """ - def test_nova_server_creation_nics_ordering(self): - """NIC list keeps the order of the relationships. - - The nics= list passed to nova.server.create should be ordered - depending on the relationships to the networks (as defined in the - blueprint). - """ - ctx = self._make_vm_ctx_with_networks( - management_network_name='network1', - networks=[ - {'id': '1'}, - {'id': '2'}, - {'id': '3'}, - {'id': '4'}, - {'id': '5'}, - {'id': '6'}, - ]) - server = {'meta': {}} - - _prepare_server_nics( - self.mock_neutron, ctx, server) - - self.assertEqual( - ['1', '2', '3', '4', '5', '6'], - [n['net-id'] for n in server['nics']]) - - def test_server_creation_prepends_mgmt_network(self): - """If the management network isn't in a relation, it's the first NIC. - - Creating the server examines the relationships, and if it doesn't find - a relationship to the management network, it adds the management - network to the NICs list, as the first element. - """ - ctx = self._make_vm_ctx_with_networks( - management_network_name='other', - networks=[ - {'id': '1'}, - {'id': '2'}, - {'id': '3'}, - {'id': '4'}, - {'id': '5'}, - {'id': '6'}, - ]) - server = {'meta': {}} - - _prepare_server_nics( - self.mock_neutron, ctx, server) - - first_nic = server['nics'][0] - self.assertEqual('other', first_nic['net-id']) - self.assertEqual(7, len(server['nics'])) - - def test_server_creation_uses_relation_mgmt_nic(self): - """If the management network is in a relation, it isn't prepended. - - If the server has a relationship to the management network, - a new NIC isn't prepended to the list. - """ - ctx = self._make_vm_ctx_with_networks( - management_network_name='network1', - networks=[ - {'id': '1'}, - {'id': '2'}, - {'id': '3'}, - {'id': '4'}, - {'id': '5'}, - {'id': '6'}, - ]) - server = {'meta': {}} - - _prepare_server_nics( - self.mock_neutron, ctx, server) - self.assertEqual(6, len(server['nics'])) - - -class TestServerPortNICs(NICTestBase): - """Test preparing the NICs list from server<->port relationships. - - Create a cloudify ctx representing a vm with relationships to - openstack ports. Then examine the resulting NICs list: check that it - contains the networks that the ports were connected to, and that each - connection uses the port that was provided. - """ - - def test_network_with_port(self): - """Port on the management network is used to connect to it. - - The NICs list entry for the management network contains the - port-id of the port from the relationship, but doesn't contain net-id. - """ - ports = [{'id': '1'}] - ctx = self._make_vm_ctx_with_ports('network1', ports) - server = {'meta': {}} - - _prepare_server_nics( - self.mock_neutron, ctx, server) - - self.assertEqual([{'port-id': '1'}], server['nics']) - - def test_port_not_to_mgmt_network(self): - """A NICs list entry is added with the network and the port. - - A relationship to a port must not only add a NIC, but the NIC must - also make sure to use that port. - """ - ports = [{'id': '1'}] - ctx = self._make_vm_ctx_with_ports('other', ports) - server = {'meta': {}} - - _prepare_server_nics( - self.mock_neutron, ctx, server) - expected = [ - {'net-id': 'other'}, - {'port-id': '1'} - ] - self.assertEqual(expected, server['nics']) - - -class TestBootFromVolume(unittest.TestCase): - - @mock.patch('nova_plugin.server._get_boot_volume_relationships', - autospec=True) - def test_handle_boot_volume(self, mock_get_rels): - mock_get_rels.return_value.runtime_properties = { - 'external_id': 'test-id', - 'availability_zone': 'test-az', - } - server = {} - ctx = mock.MagicMock() - nova_plugin.server._handle_boot_volume(server, ctx) - self.assertEqual({'vda': 'test-id:::0'}, - server['block_device_mapping']) - self.assertEqual('test-az', - server['availability_zone']) - - @mock.patch('nova_plugin.server._get_boot_volume_relationships', - autospec=True, return_value=[]) - def test_handle_boot_volume_no_boot_volume(self, *_): - server = {} - ctx = mock.MagicMock() - nova_plugin.server._handle_boot_volume(server, ctx) - self.assertNotIn('block_device_mapping', server) - - -class TestImageFromRelationships(unittest.TestCase): - - @mock.patch('glance_plugin.image.' - 'get_openstack_ids_of_connected_nodes_by_openstack_type', - autospec=True, return_value=['test-id']) - def test_handle_boot_image(self, *_): - server = {} - ctx = mock.MagicMock() - nova_plugin.server.handle_image_from_relationship(server, 'image', ctx) - self.assertEqual({'image': 'test-id'}, server) - - @mock.patch('glance_plugin.image.' - 'get_openstack_ids_of_connected_nodes_by_openstack_type', - autospec=True, return_value=[]) - def test_handle_boot_image_no_image(self, *_): - server = {} - ctx = mock.MagicMock() - nova_plugin.server.handle_image_from_relationship(server, 'image', ctx) - self.assertNotIn('image', server) - - -class TestServerRelationships(unittest.TestCase): - - def _get_ctx_mock(self, instance_id, boot): - rel_specs = [MockRelationshipContext( - target=MockRelationshipSubjectContext(node=MockNodeContext( - properties={'boot': boot}), instance=MockNodeInstanceContext( - runtime_properties={ - OPENSTACK_TYPE_PROPERTY: VOLUME_OPENSTACK_TYPE, - OPENSTACK_ID_PROPERTY: instance_id - })))] - ctx = mock.MagicMock() - ctx.instance = MockNodeInstanceContext(relationships=rel_specs) - ctx.logger = setup_logger('mock-logger') - return ctx - - def test_boot_volume_relationship(self): - instance_id = 'test-id' - ctx = self._get_ctx_mock(instance_id, True) - result = nova_plugin.server._get_boot_volume_relationships( - VOLUME_OPENSTACK_TYPE, ctx) - self.assertEqual( - instance_id, - result.runtime_properties['external_id']) - - def test_no_boot_volume_relationship(self): - instance_id = 'test-id' - ctx = self._get_ctx_mock(instance_id, False) - result = nova_plugin.server._get_boot_volume_relationships( - VOLUME_OPENSTACK_TYPE, ctx) - self.assertFalse(result) - - -class TestServerNetworkRuntimeProperties(unittest.TestCase): - - @property - def mock_ctx(self): - return MockCloudifyContext( - node_id='test', - deployment_id='test', - properties={}, - operation={'retry_number': 0}, - provider_context={'resources': {}} - ) - - def test_server_networks_runtime_properties_empty_server(self): - ctx = self.mock_ctx - current_ctx.set(ctx=ctx) - server = mock.MagicMock() - setattr(server, 'networks', {}) - with self.assertRaisesRegexp( - NonRecoverableError, - 'The server was created but not attached to a network.'): - nova_plugin.server._set_network_and_ip_runtime_properties(server) - - def test_server_networks_runtime_properties_valid_networks(self): - ctx = self.mock_ctx - current_ctx.set(ctx=ctx) - server = mock.MagicMock() - network_id = 'management_network' - network_ips = ['good', 'bad1', 'bad2'] - setattr(server, - 'networks', - {network_id: network_ips}) - nova_plugin.server._set_network_and_ip_runtime_properties(server) - self.assertIn('networks', ctx.instance.runtime_properties.keys()) - self.assertIn('ip', ctx.instance.runtime_properties.keys()) - self.assertEquals(ctx.instance.runtime_properties['ip'], 'good') - self.assertEquals(ctx.instance.runtime_properties['networks'], - {network_id: network_ips}) - - def test_server_networks_runtime_properties_empty_networks(self): - ctx = self.mock_ctx - current_ctx.set(ctx=ctx) - server = mock.MagicMock() - network_id = 'management_network' - network_ips = [] - setattr(server, - 'networks', - {network_id: network_ips}) - nova_plugin.server._set_network_and_ip_runtime_properties(server) - self.assertIn('networks', ctx.instance.runtime_properties.keys()) - self.assertIn('ip', ctx.instance.runtime_properties.keys()) - self.assertEquals(ctx.instance.runtime_properties['ip'], None) - self.assertEquals(ctx.instance.runtime_properties['networks'], - {network_id: network_ips}) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_server_image_and_flavor.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_server_image_and_flavor.py deleted file mode 100644 index 2ae475843c..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_server_image_and_flavor.py +++ /dev/null @@ -1,228 +0,0 @@ -######### -# Copyright (c) 2014 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - - -import unittest - -import mock -from novaclient import exceptions as nova_exceptions - -import nova_plugin.server as server -from cloudify.exceptions import NonRecoverableError -from cloudify.mocks import MockCloudifyContext - - -class TestServerImageAndFlavor(unittest.TestCase): - - def test_no_image_and_no_flavor(self): - node_props = { - 'image': '', - 'flavor': '' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - self.assertRaises(NonRecoverableError, - server._handle_image_or_flavor, - serv, nova_client, 'image') - self.assertRaises(NonRecoverableError, - server._handle_image_or_flavor, - serv, nova_client, 'flavor') - - def test_image_and_flavor_properties_as_names(self): - node_props = { - 'image': 'some-image-name', - 'flavor': 'some-flavor-name' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertEquals('some-flavor-id', serv.get('flavor')) - - def test_image_and_flavor_properties_as_ids(self): - node_props = { - 'image': 'some-image-id', - 'flavor': 'some-flavor-id' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertEquals('some-flavor-id', serv.get('flavor')) - - def test_image_id_and_flavor_id(self): - node_props = { - 'image': '', - 'flavor': '' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - serv['image'] = 'some-image-id' - serv['flavor'] = 'some-flavor-id' - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertEquals('some-flavor-id', serv.get('flavor')) - - def test_image_name_and_flavor_name(self): - node_props = { - 'image': '', - 'flavor': '' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - serv['image_name'] = 'some-image-name' - serv['flavor_name'] = 'some-flavor-name' - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertNotIn('image_name', serv) - self.assertEquals('some-flavor-id', serv.get('flavor')) - self.assertNotIn('flavor_name', serv) - - def test_unknown_image_name_and_flavor_name(self): - node_props = { - 'image': '', - 'flavor': '' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - serv['image_name'] = 'some-unknown-image-name' - serv['flavor_name'] = 'some-unknown-flavor-name' - - self.assertRaises(nova_exceptions.NotFound, - server._handle_image_or_flavor, - serv, nova_client, 'image') - self.assertRaises(nova_exceptions.NotFound, - server._handle_image_or_flavor, - serv, nova_client, 'flavor') - - def test_image_id_and_flavor_id_override_on_properties(self): - node_props = { - 'image': 'properties-image-id', - 'flavor': 'properties-flavor-id' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - serv['image'] = 'some-image-id' - serv['flavor'] = 'some-flavor-id' - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertEquals('some-flavor-id', serv.get('flavor')) - - def test_image_name_and_flavor_name_override_on_properties(self): - node_props = { - 'image': 'properties-image-id', - 'flavor': 'properties-flavor-id' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - serv['image_name'] = 'some-image-name' - serv['flavor_name'] = 'some-flavor-name' - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertNotIn('image_name', serv) - self.assertEquals('some-flavor-id', serv.get('flavor')) - self.assertNotIn('flavor_name', serv) - - def test_image_name_and_flavor_name_override_on_image_and_flavor_ids(self): - node_props = { - 'image': '', - 'flavor': '' - } - with mock.patch('nova_plugin.server.ctx', - self._get_mock_ctx_with_node_properties(node_props)): - nova_client = self._get_mocked_nova_client() - - serv = {} - serv['image'] = 'some-bad-image-id' - serv['image_name'] = 'some-image-name' - serv['flavor'] = 'some-bad-flavor-id' - serv['flavor_name'] = 'some-flavor-name' - server._handle_image_or_flavor(serv, nova_client, 'image') - server._handle_image_or_flavor(serv, nova_client, 'flavor') - - self.assertEquals('some-image-id', serv.get('image')) - self.assertNotIn('image_name', serv) - self.assertEquals('some-flavor-id', serv.get('flavor')) - self.assertNotIn('flavor_name', serv) - - @staticmethod - def _get_mocked_nova_client(): - nova_client = mock.MagicMock() - - def mock_get_if_exists(prop_name, **kwargs): - is_image = prop_name == 'image' - searched_name = kwargs.get('name') - if (is_image and searched_name == 'some-image-name') or \ - (not is_image and searched_name == 'some-flavor-name'): - result = mock.MagicMock() - result.id = 'some-image-id' if \ - is_image else 'some-flavor-id' - return result - return [] - - def mock_find_generator(prop_name): - def mock_find(**kwargs): - result = mock_get_if_exists(prop_name, **kwargs) - if not result: - raise nova_exceptions.NotFound(404) - return result - return mock_find - - nova_client.cosmo_plural = lambda x: '{0}s'.format(x) - nova_client.cosmo_get_if_exists = mock_get_if_exists - nova_client.images.find = mock_find_generator('image') - nova_client.flavors.find = mock_find_generator('flavor') - return nova_client - - @staticmethod - def _get_mock_ctx_with_node_properties(properties): - return MockCloudifyContext(node_id='test_node_id', - properties=properties) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_userdata.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_userdata.py deleted file mode 100644 index d7f056d72c..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_userdata.py +++ /dev/null @@ -1,63 +0,0 @@ -######### -# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import unittest - -import mock - -from cloudify.mocks import MockCloudifyContext - -from nova_plugin import userdata - - -def ctx_mock(): - result = MockCloudifyContext( - node_id='d', - properties={}) - result.node.type_hierarchy = ['cloudify.nodes.Compute'] - return result - - -class TestServerUserdataHandling(unittest.TestCase): - - @mock.patch('nova_plugin.userdata.ctx', ctx_mock()) - def test_no_userdata(self): - server_conf = {} - userdata.handle_userdata(server_conf) - self.assertEqual(server_conf, {}) - - def test_agent_installation_userdata(self): - ctx = ctx_mock() - ctx.agent.init_script = lambda: 'SCRIPT' - with mock.patch('nova_plugin.userdata.ctx', ctx): - server_conf = {} - userdata.handle_userdata(server_conf) - self.assertEqual(server_conf, {'userdata': 'SCRIPT'}) - - @mock.patch('nova_plugin.userdata.ctx', ctx_mock()) - def test_existing_userdata(self): - server_conf = {'userdata': 'EXISTING'} - server_conf_copy = server_conf.copy() - userdata.handle_userdata(server_conf) - self.assertEqual(server_conf, server_conf_copy) - - def test_existing_and_agent_installation_userdata(self): - ctx = ctx_mock() - ctx.agent.init_script = lambda: '#! SCRIPT' - with mock.patch('nova_plugin.userdata.ctx', ctx): - server_conf = {'userdata': '#! EXISTING'} - userdata.handle_userdata(server_conf) - self.assertTrue(server_conf['userdata'].startswith( - 'Content-Type: multi')) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_validation.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_validation.py deleted file mode 100644 index aa1dfdd814..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/tests/test_validation.py +++ /dev/null @@ -1,194 +0,0 @@ -######### -# Copyright (c) 2016 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import os -from os import path -import tempfile -import shutil - -import unittest -import mock - -from cloudify.test_utils import workflow_test -from nova_plugin.keypair import creation_validation -from cloudify.exceptions import NonRecoverableError - -PRIVATE_KEY_NAME = 'private_key' - - -class TestValidation(unittest.TestCase): - - blueprint_path = path.join('resources', - 'test-keypair-validation-blueprint.yaml') - - def setUp(self): - _, fp = tempfile.mkstemp() - self.private_key = fp - _, fp = tempfile.mkstemp() - self.not_readable_private_key = fp - os.chmod(self.not_readable_private_key, 0o200) - self.temp_dir = tempfile.mkdtemp() - self.not_writable_temp_dir_r = tempfile.mkdtemp() - os.chmod(self.not_writable_temp_dir_r, 0o400) - self.not_writable_temp_dir_rx = tempfile.mkdtemp() - os.chmod(self.not_writable_temp_dir_rx, 0o500) - self.not_writable_temp_dir_rw = tempfile.mkdtemp() - os.chmod(self.not_writable_temp_dir_rw, 0o600) - - def tearDown(self): - if self.private_key: - os.remove(self.private_key) - - if self.not_readable_private_key: - os.remove(self.not_readable_private_key) - - shutil.rmtree(self.not_writable_temp_dir_r, ignore_errors=True) - shutil.rmtree(self.not_writable_temp_dir_rx, ignore_errors=True) - shutil.rmtree(self.not_writable_temp_dir_rw, ignore_errors=True) - shutil.rmtree(self.temp_dir, ignore_errors=True) - - def new_keypair_create(self, *args, **kwargs): - creation_validation(*args, **kwargs) - - def new_keypair_create_with_exception(self, *args, **kwargs): - self.assertRaises(NonRecoverableError, creation_validation, - *args, **kwargs) - - def get_keypair_inputs_private_key(self, is_external, **kwargs): - return { - 'private_key': self.private_key, - 'is_keypair_external': is_external - } - - def get_keypair_inputs_not_readable_private_key(self, - is_external, **kwargs): - return { - 'private_key': self.not_readable_private_key, - 'is_keypair_external': is_external - } - - def get_keypair_inputs_not_writable_dir_r(self, is_external, **kwargs): - return { - 'private_key': path.join(self.not_writable_temp_dir_r, - PRIVATE_KEY_NAME), - 'is_keypair_external': is_external - } - - def get_keypair_inputs_not_writable_dir_rx(self, is_external, **kwargs): - return { - 'private_key': path.join(self.not_writable_temp_dir_rx, - PRIVATE_KEY_NAME), - 'is_keypair_external': is_external - } - - def get_keypair_inputs_not_writable_dir_rw(self, is_external, **kwargs): - return { - 'private_key': path.join(self.not_writable_temp_dir_rw, - PRIVATE_KEY_NAME), - 'is_keypair_external': is_external - } - - def get_keypair_inputs_temp_dir(self, is_external, **kwargs): - return { - 'private_key': path.join(self.temp_dir, PRIVATE_KEY_NAME), - 'is_keypair_external': is_external - } - - @workflow_test(blueprint_path, inputs={ - 'private_key': '', - 'is_keypair_external': False - }) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_valid_config(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, inputs='get_keypair_inputs_private_key', - input_func_kwargs={'is_external': True}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_valid_config_external(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, inputs='get_keypair_inputs_temp_dir', - input_func_kwargs={'is_external': True}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_no_private_key(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create_with_exception): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, inputs='get_keypair_inputs_private_key', - input_func_kwargs={'is_external': False}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_local_and_exists(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create_with_exception): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, inputs='get_keypair_inputs_temp_dir', - input_func_kwargs={'is_external': False}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_local_temp_dir(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, - inputs='get_keypair_inputs_not_writable_dir_r', - input_func_kwargs={'is_external': False}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_local_non_writable_dir_r(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create_with_exception): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, - inputs='get_keypair_inputs_not_writable_dir_rx', - input_func_kwargs={'is_external': False}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_local_non_writable_dir_rx(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create_with_exception): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, - inputs='get_keypair_inputs_not_writable_dir_rw', - input_func_kwargs={'is_external': False}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_local_non_writable_dir_rw(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create_with_exception): - cfy_local.execute('install', task_retries=0) - - @workflow_test(blueprint_path, - inputs='get_keypair_inputs_not_readable_private_key', - input_func_kwargs={'is_external': True}) - @mock.patch('nova_plugin.keypair.validate_resource') - def test_keypair_not_readable_private_key(self, cfy_local, *args): - - with mock.patch('nova_plugin.keypair.create', - new=self.new_keypair_create_with_exception): - cfy_local.execute('install', task_retries=0) diff --git a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/userdata.py b/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/userdata.py deleted file mode 100644 index ba63bb5328..0000000000 --- a/aria/multivim-plugin/src/main/python/multivim-plugin/nova_plugin/userdata.py +++ /dev/null @@ -1,50 +0,0 @@ -######### -# Copyright (c) 2015 GigaSpaces Technologies Ltd. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# * See the License for the specific language governing permissions and -# * limitations under the License. - -import requests - -from cloudify import compute -from cloudify import exceptions -from cloudify import ctx - - -def handle_userdata(server): - - existing_userdata = server.get('userdata') - install_agent_userdata = ctx.agent.init_script() - - if not (existing_userdata or install_agent_userdata): - return - - if isinstance(existing_userdata, dict): - ud_type = existing_userdata['type'] - if ud_type not in userdata_handlers: - raise exceptions.NonRecoverableError( - "Invalid type '{0}' for server userdata)".format(ud_type)) - existing_userdata = userdata_handlers[ud_type](existing_userdata) - - if not existing_userdata: - final_userdata = install_agent_userdata - elif not install_agent_userdata: - final_userdata = existing_userdata - else: - final_userdata = compute.create_multi_mimetype_userdata( - [existing_userdata, install_agent_userdata]) - server['userdata'] = final_userdata - - -userdata_handlers = { - 'http': lambda params: requests.get(params['url']).text -} |