From 9981f55920a6f1c1f20396d42e35b075b22f6a8f Mon Sep 17 00:00:00 2001 From: dfilppi Date: Mon, 7 Aug 2017 20:10:53 +0000 Subject: ARIA multivim plugin initial checkin Change-Id: I3a24ab6fc5ba54466bfecaf596a13b8907248ae8 Issue-id: SO-77 Signed-off-by: DeWayne Filppi --- aria/multivim-plugin/nova_plugin/keypair.py | 202 ++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 aria/multivim-plugin/nova_plugin/keypair.py (limited to 'aria/multivim-plugin/nova_plugin/keypair.py') diff --git a/aria/multivim-plugin/nova_plugin/keypair.py b/aria/multivim-plugin/nova_plugin/keypair.py new file mode 100644 index 0000000000..92281ab9e5 --- /dev/null +++ b/aria/multivim-plugin/nova_plugin/keypair.py @@ -0,0 +1,202 @@ +######### +# 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) -- cgit 1.2.3-korg