X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=snaps%2Fopenstack%2Fcreate_network.py;h=3d50eb500a606029f748b35c7a2e7f154bd928d5;hb=c711acf8ae3e4ad6f746500747857bcc9fd6f7be;hp=83573139a4e142d8d1befc4b013552ea0ff84643;hpb=49402e392615f0326b37c772ed91671bd880f92d;p=snaps.git diff --git a/snaps/openstack/create_network.py b/snaps/openstack/create_network.py index 8357313..3d50eb5 100644 --- a/snaps/openstack/create_network.py +++ b/snaps/openstack/create_network.py @@ -14,17 +14,21 @@ # limitations under the License. import logging -from neutronclient.common.exceptions import NotFound -from snaps.openstack.utils import keystone_utils, neutron_utils +import enum +from neutronclient.common.exceptions import NetworkNotFoundClient, Unauthorized + +from snaps.config.network import NetworkConfig, SubnetConfig, PortConfig +from snaps.openstack.openstack_creator import OpenStackNetworkObject +from snaps.openstack.utils import neutron_utils, keystone_utils __author__ = 'spisarski' logger = logging.getLogger('OpenStackNetwork') -class OpenStackNetwork: +class OpenStackNetwork(OpenStackNetworkObject): """ - Class responsible for creating a network in OpenStack + Class responsible for managing a network in OpenStack """ def __init__(self, os_creds, network_settings): @@ -33,59 +37,45 @@ class OpenStackNetwork: :param os_creds: The credentials to connect with OpenStack :param network_settings: The settings used to create a network """ - self.__os_creds = os_creds + super(self.__class__, self).__init__(os_creds) + self.network_settings = network_settings - self.__neutron = None # Attributes instantiated on create() self.__network = None - self.__subnets = list() - def create(self, cleanup=False): + def initialize(self): + """ + Loads the existing OpenStack network/subnet + :return: The Network domain object or None + """ + super(self.__class__, self).initialize() + + try: + keystone = keystone_utils.keystone_client(self._os_creds) + self.__network = neutron_utils.get_network( + self._neutron, keystone, + network_settings=self.network_settings, + project_name=self._os_creds.project_name) + except Unauthorized as e: + logger.warn('Unable to lookup network with name %s - %s', + self.network_settings.name, e) + + return self.__network + + def create(self): """ Responsible for creating not only the network but then a private subnet, router, and an interface to the router. - :param cleanup: When true, only perform lookups for OpenStack objects. - :return: the created network object or None + :return: the Network domain object """ - self.__neutron = neutron_utils.neutron_client(self.__os_creds) + self.initialize() - logger.info( - 'Creating neutron network %s...' % self.network_settings.name) - net_inst = neutron_utils.get_network( - self.__neutron, self.network_settings.name, - self.network_settings.get_project_id(self.__os_creds)) - if net_inst: - self.__network = net_inst - else: - if not cleanup: - self.__network = neutron_utils.create_network( - self.__neutron, self.__os_creds, self.network_settings) - else: - logger.info( - 'Network does not exist and will not create as in cleanup' - ' mode') - return - logger.debug( - "Network '%s' created successfully" % self.__network['network'][ - 'id']) - - logger.debug('Creating Subnets....') - for subnet_setting in self.network_settings.subnet_settings: - sub_inst = neutron_utils.get_subnet_by_name(self.__neutron, - subnet_setting.name) - if sub_inst: - self.__subnets.append(sub_inst) - logger.debug( - "Subnet '%s' created successfully" % sub_inst['subnet'][ - 'id']) - else: - if not cleanup: - self.__subnets.append( - neutron_utils.create_subnet(self.__neutron, - subnet_setting, - self.__os_creds, - self.__network)) + if not self.__network: + self.__network = neutron_utils.create_network( + self._neutron, self._os_creds, self.network_settings) + logger.debug( + 'Network [%s] created successfully' % self.__network.id) return self.__network @@ -93,23 +83,11 @@ class OpenStackNetwork: """ Removes and deletes all items created in reverse order. """ - for subnet in self.__subnets: - try: - logger.info( - 'Deleting subnet with name ' + subnet['subnet']['name']) - neutron_utils.delete_subnet(self.__neutron, subnet) - except NotFound as e: - logger.warning( - 'Error deleting subnet with message - ' + str(e)) - pass - self.__subnets = list() - if self.__network: try: - neutron_utils.delete_network(self.__neutron, self.__network) - except NotFound: + neutron_utils.delete_network(self._neutron, self.__network) + except NetworkNotFoundClient: pass - self.__network = None def get_network(self): @@ -119,405 +97,54 @@ class OpenStackNetwork: """ return self.__network - def get_subnets(self): - """ - Returns the OpenStack subnet objects - :return: - """ - return self.__subnets - -class NetworkSettings: +class NetworkSettings(NetworkConfig): """ - Class representing a network configuration + Class to hold the configuration settings required for creating OpenStack + Network objects + deprecated """ def __init__(self, **kwargs): - """ - Constructor - all parameters are optional - :param name: The network name. - :param admin_state_up: The administrative status of the network. - True = up / False = down (default True) - :param shared: Boolean value indicating whether this network is shared - across all projects/tenants. By default, only - administrative users can change this value. - :param project_name: Admin-only. The name of the project that will own - the network. This project can be different from - the project that makes the create network request. - However, only administrative users can specify a - project ID other than their own. You cannot change - this value through authorization policies. - :param external: when true, will setup an external network - (default False). - :param network_type: the type of network (i.e. vlan|flat). - :param physical_network: the name of the physical network - (this is required when network_type is 'flat') - :param subnets or subnet_settings: List of SubnetSettings objects. - :return: - """ - - self.project_id = None - - self.name = kwargs.get('name') - if kwargs.get('admin_state_up') is not None: - self.admin_state_up = bool(kwargs['admin_state_up']) - else: - self.admin_state_up = True - - if kwargs.get('shared') is not None: - self.shared = bool(kwargs['shared']) - else: - self.shared = None - - self.project_name = kwargs.get('project_name') - - if kwargs.get('external') is not None: - self.external = bool(kwargs.get('external')) - else: - self.external = False - - self.network_type = kwargs.get('network_type') - self.physical_network = kwargs.get('physical_network') - - self.subnet_settings = list() - subnet_settings = kwargs.get('subnets') - if not subnet_settings: - subnet_settings = kwargs.get('subnet_settings') - if subnet_settings: - for subnet_config in subnet_settings: - if isinstance(subnet_config, SubnetSettings): - self.subnet_settings.append(subnet_config) - else: - self.subnet_settings.append( - SubnetSettings(**subnet_config['subnet'])) - - if not self.name or len(self.name) < 1: - raise Exception('Name required for networks') - - def get_project_id(self, os_creds): - """ - Returns the project ID for a given project_name or None - :param os_creds: the credentials required for keystone client retrieval - :return: the ID or None - """ - if self.project_id: - return self.project_id - else: - if self.project_name: - keystone = keystone_utils.keystone_client(os_creds) - project = keystone_utils.get_project(keystone, - self.project_name) - if project: - return project.id - - return None - - def dict_for_neutron(self, os_creds): - """ - Returns a dictionary object representing this object. - This is meant to be converted into JSON designed for use by the Neutron - API - TODO - expand automated testing to exercise all parameters + from warnings import warn + warn('Use snaps.config.network.NetworkConfig instead', + DeprecationWarning) + super(self.__class__, self).__init__(**kwargs) - :param os_creds: the OpenStack credentials - :return: the dictionary object - """ - out = dict() - if self.name: - out['name'] = self.name - if self.admin_state_up is not None: - out['admin_state_up'] = self.admin_state_up - if self.shared: - out['shared'] = self.shared - if self.project_name: - project_id = self.get_project_id(os_creds) - if project_id: - out['project_id'] = project_id - else: - raise Exception( - 'Could not find project ID for project named - ' + - self.project_name) - if self.network_type: - out['provider:network_type'] = self.network_type - if self.physical_network: - out['provider:physical_network'] = self.physical_network - if self.external: - out['router:external'] = self.external - return {'network': out} +class IPv6Mode(enum.Enum): + """ + A rule's direction + deprecated - use snaps.config.network.IPv6Mode + """ + slaac = 'slaac' + stateful = 'dhcpv6-stateful' + stateless = 'dhcpv6-stateless' -class SubnetSettings: +class SubnetSettings(SubnetConfig): """ - Class representing a subnet configuration + Class to hold the configuration settings required for creating OpenStack + Subnet objects + deprecated """ def __init__(self, **kwargs): - """ - Constructor - all parameters are optional except cidr (subnet mask) - :param cidr: The CIDR. REQUIRED if config parameter is None - :param ip_version: The IP version, which is 4 or 6. - :param name: The subnet name. - :param project_name: The name of the project who owns the network. - Only administrative users can specify a project ID - other than their own. You cannot change this value - through authorization policies. - :param start: The start address for the allocation pools. - :param end: The end address for the allocation pools. - :param gateway_ip: The gateway IP address. - :param enable_dhcp: Set to true if DHCP is enabled and false if DHCP is - disabled. - :param dns_nameservers: A list of DNS name servers for the subnet. - Specify each name server as an IP address - and separate multiple entries with a space. - For example [8.8.8.7 8.8.8.8]. - :param host_routes: A list of host route dictionaries for the subnet. - For example: - "host_routes":[ - { - "destination":"0.0.0.0/0", - "nexthop":"123.456.78.9" - }, - { - "destination":"192.168.0.0/24", - "nexthop":"192.168.0.1" - } - ] - :param destination: The destination for static route - :param nexthop: The next hop for the destination. - :param ipv6_ra_mode: A valid value is dhcpv6-stateful, - dhcpv6-stateless, or slaac. - :param ipv6_address_mode: A valid value is dhcpv6-stateful, - dhcpv6-stateless, or slaac. - :raise: Exception when config does not have or cidr values are None - """ - self.cidr = kwargs['cidr'] - if kwargs.get('ip_version'): - self.ip_version = kwargs['ip_version'] - else: - self.ip_version = 4 - - # Optional attributes that can be set after instantiation - self.name = kwargs.get('name') - self.project_name = kwargs.get('project_name') - self.start = kwargs.get('start') - self.end = kwargs.get('end') - self.gateway_ip = kwargs.get('gateway_ip') - self.enable_dhcp = kwargs.get('enable_dhcp') - - if kwargs.get('dns_nameservers'): - self.dns_nameservers = kwargs.get('dns_nameservers') - else: - self.dns_nameservers = ['8.8.8.8'] - - self.host_routes = kwargs.get('host_routes') - self.destination = kwargs.get('destination') - self.nexthop = kwargs.get('nexthop') - self.ipv6_ra_mode = kwargs.get('ipv6_ra_mode') - self.ipv6_address_mode = kwargs.get('ipv6_address_mode') + from warnings import warn + warn('Use snaps.config.network.SubnetConfig instead', + DeprecationWarning) + super(self.__class__, self).__init__(**kwargs) - if not self.name or not self.cidr: - raise Exception('Name and cidr required for subnets') - def dict_for_neutron(self, os_creds, network=None): - """ - Returns a dictionary object representing this object. - This is meant to be converted into JSON designed for use by the Neutron - API - :param os_creds: the OpenStack credentials - :param network: The network object on which the subnet will be created - (optional) - :return: the dictionary object - """ - out = { - 'cidr': self.cidr, - 'ip_version': self.ip_version, - } - - if network: - out['network_id'] = network['network']['id'] - if self.name: - out['name'] = self.name - if self.project_name: - keystone = keystone_utils.keystone_client(os_creds) - project = keystone_utils.get_project(keystone, self.project_name) - project_id = None - if project: - project_id = project.id - if project_id: - out['project_id'] = project_id - else: - raise Exception( - 'Could not find project ID for project named - ' + - self.project_name) - if self.start and self.end: - out['allocation_pools'] = [{'start': self.start, 'end': self.end}] - if self.gateway_ip: - out['gateway_ip'] = self.gateway_ip - if self.enable_dhcp is not None: - out['enable_dhcp'] = self.enable_dhcp - if self.dns_nameservers and len(self.dns_nameservers) > 0: - out['dns_nameservers'] = self.dns_nameservers - if self.host_routes and len(self.host_routes) > 0: - out['host_routes'] = self.host_routes - if self.destination: - out['destination'] = self.destination - if self.nexthop: - out['nexthop'] = self.nexthop - if self.ipv6_ra_mode: - out['ipv6_ra_mode'] = self.ipv6_ra_mode - if self.ipv6_address_mode: - out['ipv6_address_mode'] = self.ipv6_address_mode - return out - - -class PortSettings: +class PortSettings(PortConfig): """ - Class representing a port configuration + Class to hold the configuration settings required for creating OpenStack + Subnet objects + deprecated """ def __init__(self, **kwargs): - """ - Constructor - all parameters are optional - :param name: A symbolic name for the port. - :param network_name: The name of the network on which to create the - port. - :param admin_state_up: A boolean value denoting the administrative - status of the port. True = up / False = down - :param project_name: The name of the project who owns the network. - Only administrative users can specify a project ID - other than their own. You cannot change this value - through authorization policies. - :param mac_address: The MAC address. If you specify an address that is - not valid, a Bad Request (400) status code is - returned. If you do not specify a MAC address, - OpenStack Networking tries to allocate one. If a - failure occurs, a Service Unavailable (503) status - code is returned. - :param ip_addrs: A list of dict objects where each contains two keys - 'subnet_name' and 'ip' values which will get mapped to - self.fixed_ips. These values will be directly - translated into the fixed_ips dict - :param fixed_ips: A dict where the key is the subnet IDs and value is - the IP address to assign to the port - :param security_groups: One or more security group IDs. - :param allowed_address_pairs: A dictionary containing a set of zero or - more allowed address pairs. An address - pair contains an IP address and MAC - address. - :param opt_value: The extra DHCP option value. - :param opt_name: The extra DHCP option name. - :param device_owner: The ID of the entity that uses this port. - For example, a DHCP agent. - :param device_id: The ID of the device that uses this port. - For example, a virtual server. - :return: - """ - self.network = None - - self.name = kwargs.get('name') - self.network_name = kwargs.get('network_name') - - if kwargs.get('admin_state_up') is not None: - self.admin_state_up = bool(kwargs['admin_state_up']) - else: - self.admin_state_up = True - - self.project_name = kwargs.get('project_name') - self.mac_address = kwargs.get('mac_address') - self.ip_addrs = kwargs.get('ip_addrs') - self.fixed_ips = kwargs.get('fixed_ips') - self.security_groups = kwargs.get('security_groups') - self.allowed_address_pairs = kwargs.get('allowed_address_pairs') - self.opt_value = kwargs.get('opt_value') - self.opt_name = kwargs.get('opt_name') - self.device_owner = kwargs.get('device_owner') - self.device_id = kwargs.get('device_id') - - if not self.name or not self.network_name: - raise Exception( - 'The attributes neutron, name, and network_name are required ' - 'for PortSettings') - - def __set_fixed_ips(self, neutron): - """ - Sets the self.fixed_ips value - :param neutron: the Neutron client - :return: None - """ - if not self.fixed_ips and self.ip_addrs: - self.fixed_ips = list() - - for ip_addr_dict in self.ip_addrs: - subnet = neutron_utils.get_subnet_by_name(neutron, - ip_addr_dict[ - 'subnet_name']) - if subnet: - self.fixed_ips.append({'ip_address': ip_addr_dict['ip'], - 'subnet_id': subnet['subnet'][ - 'id']}) - else: - raise Exception( - 'Invalid port configuration, subnet does not exist ' - 'with name - ' + ip_addr_dict['subnet_name']) - - def dict_for_neutron(self, neutron, os_creds): - """ - Returns a dictionary object representing this object. - This is meant to be converted into JSON designed for use by the Neutron - API - - TODO - expand automated testing to exercise all parameters - :param neutron: the Neutron client - :param os_creds: the OpenStack credentials - :return: the dictionary object - """ - self.__set_fixed_ips(neutron) - - out = dict() - - project_id = None - if self.project_name: - keystone = keystone_utils.keystone_client(os_creds) - project = keystone_utils.get_project(keystone, self.project_name) - if project: - project_id = project.id - - if not self.network: - self.network = neutron_utils.get_network(neutron, - self.network_name, - project_id) - if not self.network: - raise Exception( - 'Cannot locate network with name - ' + self.network_name) - - out['network_id'] = self.network['network']['id'] - - if self.admin_state_up is not None: - out['admin_state_up'] = self.admin_state_up - if self.name: - out['name'] = self.name - if self.project_name: - if project_id: - out['project_id'] = project_id - else: - raise Exception( - 'Could not find project ID for project named - ' + - self.project_name) - if self.mac_address: - out['mac_address'] = self.mac_address - if self.fixed_ips and len(self.fixed_ips) > 0: - out['fixed_ips'] = self.fixed_ips - if self.security_groups: - out['security_groups'] = self.security_groups - if self.allowed_address_pairs and len(self.allowed_address_pairs) > 0: - out['allowed_address_pairs'] = self.allowed_address_pairs - if self.opt_value: - out['opt_value'] = self.opt_value - if self.opt_name: - out['opt_name'] = self.opt_name - if self.device_owner: - out['device_owner'] = self.device_owner - if self.device_id: - out['device_id'] = self.device_id - return {'port': out} + from warnings import warn + warn('Use snaps.config.network.PortConfig instead', + DeprecationWarning) + super(self.__class__, self).__init__(**kwargs)