From b14d5b5b31ef2f58c3b0700e7166af9bb552db76 Mon Sep 17 00:00:00 2001 From: Leonardo Maycotte Date: Wed, 3 Aug 2016 14:10:08 -0500 Subject: [PATCH] Creating Custom Composites for networking and compute - Adding the CustomComposite class - Adding the compute_endpoint_config param to the _ComputeAuthComposite so it can be set like the endpoint_config and user_config - Updating the _NetworkingAuthComposite params with: networking_endpoint_config, user_auth_config and user_config - Adding to the NetworkingComposite the auth_composite param - Adding the auth_composite param to the networking extension composites: ip_addresses_api, limits_api and security_groups_api - Updating the CREATE_IP_ADDRESS constant to 201 Change-Id: I357724d8f3e1c9a6f85422fdc2c8f1c6be51acd9 --- cloudcafe/compute/composites.py | 6 +- .../networking/networks/common/composites.py | 358 ++++++++++++++++++ cloudcafe/networking/networks/composites.py | 15 +- .../extensions/ip_addresses_api/composites.py | 4 +- .../extensions/ip_addresses_api/constants.py | 2 +- .../extensions/limits_api/composites.py | 4 +- .../security_groups_api/composites.py | 4 +- 7 files changed, 378 insertions(+), 15 deletions(-) create mode 100644 cloudcafe/networking/networks/common/composites.py diff --git a/cloudcafe/compute/composites.py b/cloudcafe/compute/composites.py index 49b02eda..f57b9c03 100644 --- a/cloudcafe/compute/composites.py +++ b/cloudcafe/compute/composites.py @@ -52,8 +52,10 @@ class _ComputeAuthComposite(MemoizedAuthServiceComposite): _auth_endpoint_config = UserAuthConfig _auth_user_config = UserConfig - def __init__(self, endpoint_config=None, user_config=None): - self.compute_endpoint_config = self._compute_endpoint_config() + def __init__(self, endpoint_config=None, user_config=None, + compute_endpoint_config=None): + self.compute_endpoint_config = compute_endpoint_config or \ + self._compute_endpoint_config() self.marshalling_config = MarshallingConfig() self._auth_endpoint_config = \ endpoint_config or self._auth_endpoint_config() diff --git a/cloudcafe/networking/networks/common/composites.py b/cloudcafe/networking/networks/common/composites.py new file mode 100644 index 00000000..f1fdaf80 --- /dev/null +++ b/cloudcafe/networking/networks/common/composites.py @@ -0,0 +1,358 @@ +""" +Copyright 2016 Rackspace + +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 cloudcafe.compute.composites import _ComputeAuthComposite, \ + ComputeComposite +from cloudcafe.compute.config import ComputeEndpointConfig +from cloudcafe.compute.extensions.ip_associations_api.composites \ + import IPAssociationsComposite +from cloudcafe.networking.networks.composites import _NetworkingAuthComposite,\ + NetworkingComposite +from cloudcafe.networking.networks.config import NetworkingEndpointConfig, \ + UserAuthConfig, UserConfig +from cloudcafe.networking.networks.extensions.ip_addresses_api.composites \ + import IPAddressesComposite +from cloudcafe.networking.networks.extensions.limits_api.composites \ + import LimitsComposite +from cloudcafe.networking.networks.extensions.security_groups_api.composites \ + import SecurityGroupsComposite + + +class CustomComposite(object): + """ + @summary: Creates customized composites for networking specifying a + config file and/or overwriting the config section parameters from + networking_endpoint, user, and user_auth_config. + """ + CAFE_CONFIG_FILE_PATH = 'CAFE_CONFIG_FILE_PATH' + + def __init__(self, region=None, networking_endpoint_name=None, + networking_endpoint_url=None, compute_endpoint_name=None, + compute_endpoint_url=None, auth_endpoint=None, + strategy=None, username=None, api_key=None, tenant_id=None, + user_id=None, project_id=None, passcode=None, password=None, + tenant_name=None, config_file_path=None): + """ + @param region: environment region, for ex. QE-ORD, DFW, IAD, etc. + (networking_endpoint and compute_endpoint config file param) + @type region: str + @param networking_endpoint_name: service catalog name to get the + publicURL, for ex. cloudNetworks (networking_endpoint config file + section param) + @type networking_endpoint_name: str + @param networking_endpoint_url: to override publicURL from the catalog + (networking_endpoint config file section param) + @type networking_endpoint_url: str + + @param compute_endpoint_name: service catalog name to get the + publicURL, for ex. cloudServersOpenStack (compute_endpoint config file + section param) + @type compute_endpoint_name: str + @param compute_endpoint_url: to override publicURL from the catalog + (compute_endpoint config file section param) + @type compute_endpoint_url: str + @param auth_endpoint: authentication endpoint for user credentials + @type auth_endpoint: str + @param strategy: type of authentication exposed by the auth_endpoint. + Currently supported values: keystone, rax_auth, rax_auth_mfa, and + saio_tempauth + @type strategy: str + @param username: name of the user + @type username: str + @param api_key: user api key + @type api_key: str + @param tenant_id: user tenant ID + @type tenant_id: str + @param user_id: user ID + @type user_id: str + @param project_id: user project ID (usually same as tenant ID) + @type project_id: str + @param passcode: auth MFA secondary password (passcode) + @type passcode: str + @param password: user password + @type password: str + @param tenant_name: user tenant name + @type tenant_name: str + @param config_file_path: to override the CAFE_CONFIG_FILE_PATH file + @type config_file_path: str + + """ + # networking_endpoint section params (region is also used by compute) + self.region = region + self.networking_endpoint_name = networking_endpoint_name + self.networking_endpoint_url = networking_endpoint_url + + # compute_endpoint section params + self.compute_endpoint_name = compute_endpoint_name + self.compute_endpoint_url = compute_endpoint_url + + # user_auth_config section params + self.auth_endpoint = auth_endpoint + self.strategy = strategy + + # user section params + self.username = username + self.api_key = api_key + self.tenant_id = tenant_id + self.user_id = user_id + self.project_id = project_id + self.passcode = passcode + self.password = password + self.tenant_name = tenant_name + + # To track all config file paths used + self.config_file_path_records = [] + + # Overwriting config file path if given + self.config_file_path = config_file_path + self.set_cafe_config_file_path() + + # Setting the new config objects + self.set_cafe_configs() + + # Networking composites and sub-composites + self.net = None + self.networks = None + self.subnets = None + self.ports = None + + # Extension composites: security groups (sec), IP addresses (ipaddr), + # limits, and IP associations (ipassoc). + self.sec = None + self.ipaddr = None + self.ipassoc = None + + # Compute composites and sub-composites + self.compute = None + self.flavors = None + self.images = None + self.servers = None + self.keypairs = None + + # Initially setting the networking composite only + self.set_cafe_composites(composites=['networking']) + + def set_cafe_configs(self, configs=None): + """Setting attributes for new config objects""" + if not configs: + configs = ['user', 'user_auth', 'compute_endpoint', + 'networking_endpoint'] + + if 'user' in configs: + self.set_user_config() + if 'user_auth' in configs: + self.set_user_auth_config() + if 'compute_endpoint' in configs: + self.set_compute_endpoint_config() + if 'networking_endpoint' in configs: + self.set_networking_endpoint_config() + + def set_cafe_config_file_path(self): + """Updating the cafe config file path value""" + self.config_file_path_records.append(os.environ.get( + self.CAFE_CONFIG_FILE_PATH)) + if self.config_file_path: + os.environ.update({self.CAFE_CONFIG_FILE_PATH: + self.config_file_path}) + + def reset_cafe_config_file_path(self): + """Resetting to the previous cafe config file path value""" + if self.config_file_path_records: + previous_config_file = self.config_file_path_records.pop() + os.environ.update({self.CAFE_CONFIG_FILE_PATH: + previous_config_file}) + + def reset_attr_values(self, attrs=None): + """ + @summary: Setting to None the class config values + """ + if not attrs: + attrs = ['region', 'networking_endpoint_name', + 'networking_endpoint_url', 'compute_endpoint_name', + 'compute_endpoint_url', 'auth_endpoint', 'strategy', + 'username', 'api_key', 'tenant_id', 'user_id', + 'project_id', 'passcode', 'password', 'tenant_name'] + + for val in attrs: + setattr(self, val, None) + + def set_cafe_composites(self, composites=None): + """ + @summary: Setting customized composites + @param composites: composites to set, for ex. ['networking'] + @type composites: list + """ + + # setting all if not given + if not composites: + composites = ['networking', 'compute', 'ip_associations', + 'security_groups', 'ip_addresses', 'limits'] + + # Compute needs to go first since used by networking + if 'compute' in composites: + self.compute = ComputeComposite( + auth_composite=self.compute_auth_composite) + self.flavors = self.compute.flavors + self.images = self.compute.images + self.servers = self.compute.servers + self.keypairs = self.compute.keypairs + if 'networking' in composites: + self.net = NetworkingComposite( + auth_composite=self.networking_auth_composite) + self.networks = self.net.networks + self.subnets = self.net.subnets + self.ports = self.net.ports + + # need to overwrite the compute composite at networking + self.net.behaviors.compute = self.compute + + if 'ip_associations' in composites: + self.ipassoc = IPAssociationsComposite( + auth_composite=self.compute_auth_composite) + if 'security_groups' in composites: + self.sec = SecurityGroupsComposite( + auth_composite=self.networking_auth_composite) + if 'ip_addresses' in composites: + self.ipaddr = IPAddressesComposite( + auth_composite=self.networking_auth_composite) + if 'limits' in composites: + self.limits = LimitsComposite( + auth_composite=self.networking_auth_composite) + + @property + def networking_auth_composite(self): + """Getting customized networking auth composite""" + + return _NetworkingAuthComposite( + networking_endpoint_config=self.networking_endpoint_config, + user_auth_config=self.user_auth_config, + user_config=self.user_config) + + @property + def compute_auth_composite(self): + """Getting customized compute auth composite""" + + return _ComputeAuthComposite( + compute_endpoint_config=self.compute_endpoint_config, + endpoint_config=self.user_auth_config, + user_config=self.user_config) + + def set_networking_endpoint_config(self): + """Setting the updated self._new_networking_endpoint_config attr""" + endpoint_config = NetworkingEndpointConfig() + + new_config_kwargs = dict( + region=self.region, + networking_endpoint_name=self.networking_endpoint_name, + networking_endpoint_url=self.networking_endpoint_url) + + self._new_networking_endpoint_config = \ + Clone(obj_to_clone=endpoint_config, new_kwargs=new_config_kwargs) + + @property + def networking_endpoint_config(self): + """Returning the networking_endpoint config""" + return self._new_networking_endpoint_config + + def set_compute_endpoint_config(self): + """Setting the updated self._new_compute_endpoint_config attribute""" + endpoint_config = ComputeEndpointConfig() + + new_config_kwargs = dict( + region=self.region, + compute_endpoint_name=self.compute_endpoint_name, + compute_endpoint_url=self.compute_endpoint_url) + + self._new_compute_endpoint_config = Clone(obj_to_clone=endpoint_config, + new_kwargs=new_config_kwargs) + + @property + def compute_endpoint_config(self): + """Returning the compute_endpoint config""" + return self._new_compute_endpoint_config + + def set_user_auth_config(self): + """Setting the updated self._new_user_auth_config attribute""" + user_auth_config = UserAuthConfig() + + # in the config file auth_endpoint is just endpoint + new_config_kwargs = dict(auth_endpoint=self.auth_endpoint, + strategy=self.strategy) + + self._new_user_auth_config = Clone(obj_to_clone=user_auth_config, + new_kwargs=new_config_kwargs) + + @property + def user_auth_config(self): + """Returning the user_auth_config""" + return self._new_user_auth_config + + def set_user_config(self): + """Setting the updated self._new_user_config attribute""" + user_config = UserConfig() + new_config_kwargs = dict( + username=self.username, api_key=self.api_key, + tenant_id=self.tenant_id, user_id=self.user_id, + project_id=self.project_id, passcode=self.passcode, + password=self.password, tenant_name=self.tenant_name) + + self._new_user_config = Clone(obj_to_clone=user_config, + new_kwargs=new_config_kwargs) + + @property + def user_config(self): + """Returning the user config""" + return self._new_user_config + + def __repr__(self): + """Representing custom config data""" + data = self.__dict__ + msg = ['Custom config data:'] + for key, value in data.items(): + if type(value) is str: + s = '{0}: {1}'.format(key, value) + msg.append(s) + s = '\n{0} records: {1}'.format(self.CAFE_CONFIG_FILE_PATH, + self.config_file_path_records) + msg.append(s) + res = '\n'.join(msg) + return res + + +class Clone(object): + """Class to create custom objects""" + def __init__(self, obj_to_clone, new_kwargs=None): + """ + @param obj_to_clone: instance of object to copy for ex. UserConfig() + @type obj_to_clone: instance + @param new_kwargs: attributes to set in new copy (clone) + @type new_kwargs: dict + """ + original_attrs = dir(obj_to_clone) + + # Copying the object data to the clone + for attr in original_attrs: + if not attr.startswith('_'): + val = getattr(obj_to_clone, attr, None) + setattr(self, attr, val) + + # Setting new data into the clone + for key, val in new_kwargs.items(): + if val: + setattr(self, key, val) diff --git a/cloudcafe/networking/networks/composites.py b/cloudcafe/networking/networks/composites.py index cb4625c4..0334891c 100644 --- a/cloudcafe/networking/networks/composites.py +++ b/cloudcafe/networking/networks/composites.py @@ -42,11 +42,14 @@ class _NetworkingAuthComposite(MemoizedAuthServiceComposite): _auth_endpoint_config = UserAuthConfig _auth_user_config = UserConfig - def __init__(self): - self.networking_endpoint_config = self._networking_endpoint_config() + def __init__(self, networking_endpoint_config=None, user_auth_config=None, + user_config=None): + self.networking_endpoint_config = (networking_endpoint_config or + self._networking_endpoint_config()) self.marshalling_config = MarshallingConfig() - self._auth_endpoint_config = self._auth_endpoint_config() - self._auth_user_config = self._auth_user_config() + self._auth_endpoint_config = (user_auth_config or + self._auth_endpoint_config()) + self._auth_user_config = (user_config or self._auth_user_config()) super(_NetworkingAuthComposite, self).__init__( service_name=self.networking_endpoint_config.networking_endpoint_name, @@ -85,8 +88,8 @@ class NetworkingComposite(object): networking_auth_composite = _NetworkingAuthComposite behavior_class = NetworkingBehaviors - def __init__(self): - auth_composite = self.networking_auth_composite() + def __init__(self, auth_composite=None): + auth_composite = auth_composite or self.networking_auth_composite() self.url = auth_composite.networking_url self.user = auth_composite._auth_user_config self.config = NetworkingBaseConfig() diff --git a/cloudcafe/networking/networks/extensions/ip_addresses_api/composites.py b/cloudcafe/networking/networks/extensions/ip_addresses_api/composites.py index 2f3fd72b..02032c8c 100644 --- a/cloudcafe/networking/networks/extensions/ip_addresses_api/composites.py +++ b/cloudcafe/networking/networks/extensions/ip_addresses_api/composites.py @@ -26,8 +26,8 @@ from cloudcafe.networking.networks.extensions.ip_addresses_api.config \ class IPAddressesComposite(object): networking_auth_composite = _NetworkingAuthComposite - def __init__(self): - auth_composite = self.networking_auth_composite() + def __init__(self, auth_composite=None): + auth_composite = auth_composite or self.networking_auth_composite() self.url = auth_composite.networking_url self.user = auth_composite._auth_user_config self.config = IPAddressesConfig() diff --git a/cloudcafe/networking/networks/extensions/ip_addresses_api/constants.py b/cloudcafe/networking/networks/extensions/ip_addresses_api/constants.py index 045863b9..5dc65e62 100644 --- a/cloudcafe/networking/networks/extensions/ip_addresses_api/constants.py +++ b/cloudcafe/networking/networks/extensions/ip_addresses_api/constants.py @@ -35,7 +35,7 @@ class IPAddressesResponseCodes(NeutronResponseCodes): GET_IP_ADDRESS = 200 # Using HTTP 200 instead of 201 till NCP-1577 is fixed - CREATE_IP_ADDRESS = 200 + CREATE_IP_ADDRESS = 201 UPDATE_IP_ADDRESS = 200 DELETE_IP_ADDRESS = 204 diff --git a/cloudcafe/networking/networks/extensions/limits_api/composites.py b/cloudcafe/networking/networks/extensions/limits_api/composites.py index a16f1599..4341dc6e 100644 --- a/cloudcafe/networking/networks/extensions/limits_api/composites.py +++ b/cloudcafe/networking/networks/extensions/limits_api/composites.py @@ -26,8 +26,8 @@ from cloudcafe.networking.networks.extensions.limits_api.config \ class LimitsComposite(object): networking_auth_composite = _NetworkingAuthComposite - def __init__(self): - auth_composite = self.networking_auth_composite() + def __init__(self, auth_composite=None): + auth_composite = auth_composite or self.networking_auth_composite() self.url = auth_composite.networking_url self.user = auth_composite._auth_user_config self.config = LimitsConfig() diff --git a/cloudcafe/networking/networks/extensions/security_groups_api/composites.py b/cloudcafe/networking/networks/extensions/security_groups_api/composites.py index e4e33a07..1a40179a 100644 --- a/cloudcafe/networking/networks/extensions/security_groups_api/composites.py +++ b/cloudcafe/networking/networks/extensions/security_groups_api/composites.py @@ -26,8 +26,8 @@ from cloudcafe.networking.networks.extensions.security_groups_api.config \ class SecurityGroupsComposite(object): networking_auth_composite = _NetworkingAuthComposite - def __init__(self): - auth_composite = self.networking_auth_composite() + def __init__(self, auth_composite=None): + auth_composite = auth_composite or self.networking_auth_composite() self.url = auth_composite.networking_url self.user = auth_composite._auth_user_config self.config = SecurityGroupsConfig()