X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=snaps%2Fopenstack%2Fcreate_project.py;h=ed7e9cd3259d0d7cb0f5aecaa5b7504d0cc8cd6d;hb=e0c640946294e6fc190f03f341e873e6db483291;hp=60f9ed072ac12d54c34f227f0254d44d280c694c;hpb=1a0967b4e23c2d985b8c02dc9f23bd6c3afa86a3;p=snaps.git diff --git a/snaps/openstack/create_project.py b/snaps/openstack/create_project.py index 60f9ed0..ed7e9cd 100644 --- a/snaps/openstack/create_project.py +++ b/snaps/openstack/create_project.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Cable Television Laboratories, Inc. ("CableLabs") +# Copyright (c) 2017 Cable Television Laboratories, Inc. ("CableLabs") # and others. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,18 +14,20 @@ # limitations under the License. import logging -from keystoneclient.exceptions import NotFound +from keystoneclient.exceptions import NotFound, Conflict -from snaps.openstack.utils import keystone_utils +from snaps.config.project import ProjectConfig +from snaps.openstack.openstack_creator import OpenStackIdentityObject +from snaps.openstack.utils import keystone_utils, neutron_utils, nova_utils __author__ = 'spisarski' logger = logging.getLogger('create_image') -class OpenStackProject: +class OpenStackProject(OpenStackIdentityObject): """ - Class responsible for creating a project/project in OpenStack + Class responsible for managing a project/project in OpenStack """ def __init__(self, os_creds, project_settings): @@ -35,31 +37,65 @@ class OpenStackProject: :param project_settings: The project's settings :return: """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.project_settings = project_settings self.__project = None self.__role = None - self.__keystone = keystone_utils.keystone_client(self.__os_creds) + self.__role_name = self.project_settings.name + '-role' - def create(self, cleanup=False): + def initialize(self): """ - Creates the image in OpenStack if it does not already exist - :param cleanup: Denotes whether or not this is being called for cleanup or not - :return: The OpenStack Image object + Loads the existing Project object if it exists + :return: The Project domain object """ - try: - self.__project = keystone_utils.get_project(keystone=self.__keystone, - project_name=self.project_settings.name) - if self.__project: - logger.info('Found project with name - ' + self.project_settings.name) - elif not cleanup: - self.__project = keystone_utils.create_project(self.__keystone, self.project_settings) - else: - logger.info('Did not create image due to cleanup mode') - except Exception as e: - logger.error('Unexpected error. Rolling back') - self.clean() - raise Exception(e.message) + super(self.__class__, self).initialize() + + self.__project = keystone_utils.get_project( + keystone=self._keystone, project_settings=self.project_settings) + return self.__project + + def create(self): + """ + Creates a Project/Tenant in OpenStack if it does not already exist + :return: The Project domain object + """ + self.initialize() + + if not self.__project: + self.__project = keystone_utils.create_project( + self._keystone, self.project_settings) + for username in self.project_settings.users: + user = keystone_utils.get_user(self._keystone, username) + if user: + try: + self.assoc_user(user) + except Conflict as e: + logger.warn('Unable to associate user %s due to %s', + user.name, e) + + if self.project_settings.quotas: + quota_dict = self.project_settings.quotas + nova = nova_utils.nova_client(self._os_creds, self._os_session) + quotas = nova_utils.get_compute_quotas(nova, self.__project.id) + if quotas: + if 'cores' in quota_dict: + quotas.cores = quota_dict['cores'] + if 'instances' in quota_dict: + quotas.instances = quota_dict['instances'] + if 'injected_files' in quota_dict: + quotas.injected_files = quota_dict['injected_files'] + if 'injected_file_content_bytes' in quota_dict: + quotas.injected_file_content_bytes = \ + quota_dict['injected_file_content_bytes'] + if 'ram' in quota_dict: + quotas.ram = quota_dict['ram'] + if 'fixed_ips' in quota_dict: + quotas.fixed_ips = quota_dict['fixed_ips'] + if 'key_pairs' in quota_dict: + quotas.key_pairs = quota_dict['key_pairs'] + + nova_utils.update_quotas(nova, self.__project.id, quotas) return self.__project @@ -69,19 +105,44 @@ class OpenStackProject: :return: void """ if self.__project: + # Delete security group 'default' if exists + neutron = neutron_utils.neutron_client( + self._os_creds, self._os_session) + try: + default_sec_grp = neutron_utils.get_security_group( + neutron, self._keystone, sec_grp_name='default', + project_name=self.__project.name) + if default_sec_grp: + try: + neutron_utils.delete_security_group( + neutron, default_sec_grp) + except: + pass + finally: + neutron.httpclient.session.session.close() + + # Delete Project try: - keystone_utils.delete_project(self.__keystone, self.__project) + keystone_utils.delete_project(self._keystone, self.__project) except NotFound: pass self.__project = None if self.__role: try: - keystone_utils.delete_role(self.__keystone, self.__role) + keystone_utils.delete_role(self._keystone, self.__role) except NotFound: pass self.__project = None + # Final role check in case init was done from an existing instance + role = keystone_utils.get_role_by_name( + self._keystone, self.__role_name) + if role: + keystone_utils.delete_role(self._keystone, role) + + super(self.__class__, self).clean() + def get_project(self): """ Returns the OpenStack project object populated on create() @@ -92,48 +153,77 @@ class OpenStackProject: def assoc_user(self, user): """ The user object to associate with the project - :param user: the OpenStack user object to associate with project + :param user: the OpenStack User domain object to associate with project :return: """ if not self.__role: - self.__role = keystone_utils.create_role(self.__keystone, self.project_settings.name + '-role') + self.__role = keystone_utils.get_role_by_name( + self._keystone, self.__role_name) + if not self.__role: + self.__role = keystone_utils.create_role( + self._keystone, self.__role_name) - keystone_utils.assoc_user_to_project(self.__keystone, self.__role, user, self.__project) + keystone_utils.grant_user_role_to_project(self._keystone, self.__role, + user, self.__project) + + def get_compute_quotas(self): + """ + Returns the compute quotas as an instance of the ComputeQuotas class + :return: + """ + nova = nova_utils.nova_client(self._os_creds, self._os_session) + try: + return nova_utils.get_compute_quotas(nova, self.__project.id) + finally: + nova.client.session.session.close() -class ProjectSettings: + def get_network_quotas(self): + """ + Returns the network quotas as an instance of the NetworkQuotas class + :return: + """ + neutron = neutron_utils.neutron_client( + self._os_creds, self._os_session) + try: + return neutron_utils.get_network_quotas(neutron, self.__project.id) + finally: + neutron.httpclient.session.session.close() + + def update_compute_quotas(self, compute_quotas): + """ + Updates the compute quotas for this project + :param compute_quotas: a ComputeQuotas object. + """ + nova = nova_utils.nova_client(self._os_creds, self._os_session) + try: + nova_utils.update_quotas(nova, self.__project.id, compute_quotas) + finally: + nova.client.session.session.close() + + def update_network_quotas(self, network_quotas): + """ + Updates the network quotas for this project + :param network_quotas: a NetworkQuotas object. + """ + neutron = neutron_utils.neutron_client( + self._os_creds, self._os_session) + try: + neutron_utils.update_quotas( + neutron, self.__project.id, network_quotas) + finally: + neutron.httpclient.session.session.close() + + +class ProjectSettings(ProjectConfig): """ - Class to hold the configuration settings required for creating OpenStack project objects + Class to hold the configuration settings required for creating OpenStack + project objects + deprecated """ - def __init__(self, config=None, name=None, domain='default', description=None, enabled=True): - """ - Constructor - :param config: dict() object containing the configuration settings using the attribute names below as each - member's the key and overrides any of the other parameters. - :param name: the project's name (required) - :param domain: the project's domain name (default 'default'). Field is used for v3 clients - :param description: the description (optional) - :param enabled: denotes whether or not the user is enabled (default True) - """ - - if config: - self.name = config.get('name') - if config.get('domain'): - self.domain = config['domain'] - else: - self.domain = domain - - self.description = config.get('description') - if config.get('enabled') is not None: - self.enabled = config['enabled'] - else: - self.enabled = enabled - else: - self.name = name - self.domain = domain - self.description = description - self.enabled = enabled - - if not self.name: - raise Exception("The attribute name is required for ProjectSettings") + def __init__(self, **kwargs): + from warnings import warn + warn('Use snaps.config.project.ProjectConfig instead', + DeprecationWarning) + super(self.__class__, self).__init__(**kwargs)