def _validate_device_list(data, valid_values=None): """Validate the list of service definitions.""" if not data: # Devices must be provided msg = _("Cannot create a gateway with an empty device list") return msg try: for device in data: key_specs = {DEVICE_ID_ATTR: {'type:regex': attributes.UUID_PATTERN, 'required': True}, IFACE_NAME_ATTR: {'type:string': None, 'required': False}} err_msg = attributes._validate_dict( device, key_specs=key_specs) if err_msg: return err_msg unexpected_keys = [key for key in device if key not in key_specs] if unexpected_keys: err_msg = (_("Unexpected keys found in device description:%s") % ",".join(unexpected_keys)) return err_msg except TypeError: return (_("%s: provided data are not iterable") % _validate_device_list.__name__)
def _check_lb_service_on_router(self, resource, event, trigger, payload=None): """Prevent removing a router GW or deleting a router used by LB""" router_id = payload.resource_id context = payload.context nsx_router_id = nsx_db.get_nsx_router_id(context.session, router_id) if not nsx_router_id: # Skip non-v3 routers (could be a V router in case of TVD plugin) return nsxlib = self.loadbalancer.core_plugin.nsxlib service_client = nsxlib.load_balancer.service # Check if there is any lb service on nsx router lb_service = service_client.get_router_lb_service(nsx_router_id) if lb_service: msg = _('Cannot delete a %s as it still has lb service ' 'attachment') % resource raise n_exc.BadRequest(resource='lbaas-lb', msg=msg) # Also check if there are any loadbalancers attached to this router # subnets router_subnets = self.loadbalancer.core_plugin._find_router_subnets( context.elevated(), router_id) subnet_ids = [subnet['id'] for subnet in router_subnets] if subnet_ids and self._get_lb_ports(context.elevated(), subnet_ids): msg = (_('Cannot delete a %s as it used by a loadbalancer') % resource) raise n_exc.BadRequest(resource='lbaas-lb', msg=msg)
def _create_ssl_cert(self, edge_id=None): # Create a self signed certificate in the backend if both Cert details # and private key are not supplied in nsx.ini if (not cfg.CONF.nsxv.metadata_nova_client_cert and not cfg.CONF.nsxv.metadata_nova_client_priv_key): h = self.nsxv_plugin.nsx_v.vcns.create_csr(edge_id)[0] # Extract the CSR ID from header csr_id = lbaas_common.extract_resource_id(h['location']) # Create a self signed certificate cert = self.nsxv_plugin.nsx_v.vcns.create_csr_cert(csr_id)[1] cert_id = cert['objectId'] else: # Raise an error if either the Cert path or the private key is not # configured error = None if not cfg.CONF.nsxv.metadata_nova_client_cert: error = _('Metadata certificate path not configured') elif not cfg.CONF.nsxv.metadata_nova_client_priv_key: error = _('Metadata client private key not configured') if error: raise nsxv_exc.NsxPluginException(err_msg=error) pem_encoding = utils.read_file( cfg.CONF.nsxv.metadata_nova_client_cert) priv_key = utils.read_file( cfg.CONF.nsxv.metadata_nova_client_priv_key) request = { 'pemEncoding': pem_encoding, 'privateKey': priv_key} cert = self.nsxv_plugin.nsx_v.vcns.upload_edge_certificate( edge_id, request)[1] cert_id = cert.get('certificates')[0]['objectId'] return cert_id
def validate_session_persistence(pool, listener, completor, old_pool=None): sp = pool.get('session_persistence') if not listener or not sp: # safety first! return # L4 listeners only allow source IP persistence if (listener['protocol'] == lb_const.LB_PROTOCOL_TCP and sp['type'] != lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP): completor(success=False) msg = (_("Invalid session persistence type %(sp_type)s for " "pool on listener %(lst_id)s with %(proto)s protocol") % {'sp_type': sp['type'], 'lst_id': listener['id'], 'proto': listener['protocol']}) raise n_exc.BadRequest(resource='lbaas-pool', msg=msg) # Cannot switch (yet) on update from source IP to cookie based, and # vice versa cookie_pers_types = (lb_const.LB_SESSION_PERSISTENCE_HTTP_COOKIE, lb_const.LB_SESSION_PERSISTENCE_APP_COOKIE) if old_pool: oldsp = old_pool.get('session_persistence') if not oldsp: return if ((sp['type'] == lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP and oldsp['type'] in cookie_pers_types) or (sp['type'] in cookie_pers_types and oldsp['type'] == lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP)): completor(success=False) msg = (_("Cannot update session persistence type to " "%(sp_type)s for pool on listener %(lst_id)s " "from %(old_sp_type)s") % {'sp_type': sp['type'], 'lst_id': listener['id'], 'old_sp_type': oldsp['type']}) raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
def update_backend_pool(self, nsx_pool_id, subnet_request): update_args = { 'cidr': self._get_cidr_from_request(subnet_request), 'allocation_ranges': self._get_ranges_from_request(subnet_request), 'gateway_ip': subnet_request.gateway_ip} try: self.nsxlib_ipam.update( nsx_pool_id, **update_args) except nsx_lib_exc.ManagerError as e: LOG.error("NSX IPAM failed to update pool %(id)s: " " %(e)s; code %(code)s", {'e': e, 'id': nsx_pool_id, 'code': e.error_code}) if (e.error_code == error.ERR_CODE_IPAM_RANGE_MODIFY or e.error_code == error.ERR_CODE_IPAM_RANGE_DELETE or e.error_code == error.ERR_CODE_IPAM_RANGE_SHRUNK): # The change is not allowed: already allocated IPs out of # the new range raise ipam_exc.InvalidSubnetRequest( reason=_("Already allocated IPs outside of the updated " "pools")) except Exception as e: # unexpected error msg = _('Failed to update subnet IPAM: %s') % e raise ipam_exc.IpamValueInvalid(message=msg)
def _validate_device_list(self, devices, check_backend=True): # In NSXv3, one L2 gateway is mapped to one bridge endpoint profle. # So we expect only one device to be configured as part of # a L2 gateway resource. The name of the device must be the bridge # endpoint profile UUID. if len(devices) != 1: msg = _("Only a single device is supported by the NSX L2" "gateway driver") raise n_exc.InvalidInput(error_message=msg) dev_name = devices[0]['device_name'] if not uuidutils.is_uuid_like(dev_name): msg = _("Device name must be configured with a UUID") raise n_exc.InvalidInput(error_message=msg) # Ensure the L2GW device is a valid bridge endpoint profile in NSX if check_backend: try: self._core_plugin.nsxlib.bridge_endpoint_profile.get( dev_name) except nsxlib_exc.ResourceNotFound: msg = _("Could not find Bridge Endpoint Profile for L2 " "gateway device %s on NSX backend") % dev_name LOG.error(msg) raise n_exc.InvalidInput(error_message=msg) # One L2 gateway must have only one interface defined. interfaces = devices[0].get(l2gw_const.IFACE_NAME_ATTR) if len(interfaces) > 1: msg = _("Maximum of one interface is supported by the NSX L2 " "gateway driver") raise n_exc.InvalidInput(error_message=msg)
def _validate_network(self, context, net_data): network_type = net_data.get(pnet.NETWORK_TYPE) segmentation_id = net_data.get(pnet.SEGMENTATION_ID) segmentation_id_set = attr.is_attr_set(segmentation_id) if not context.is_admin: err_msg = _("Only and admin can create a DVS provider " "network") raise n_exc.InvalidInput(error_message=err_msg) err_msg = None if network_type == c_utils.NetworkTypes.FLAT: if segmentation_id_set: err_msg = _("Segmentation ID cannot be specified with " "flat network type") elif network_type == c_utils.NetworkTypes.VLAN: if not segmentation_id_set: err_msg = _("Segmentation ID must be specified with " "vlan network type") elif (segmentation_id_set and not utils.is_valid_vlan_tag(segmentation_id)): err_msg = (_("%(segmentation_id)s out of range " "(%(min_id)s through %(max_id)s)") % {'segmentation_id': segmentation_id, 'min_id': constants.MIN_VLAN_TAG, 'max_id': constants.MAX_VLAN_TAG}) else: err_msg = (_("%(net_type_param)s %(net_type_value)s not " "supported") % {'net_type_param': pnet.NETWORK_TYPE, 'net_type_value': network_type}) if err_msg: raise n_exc.InvalidInput(error_message=err_msg)
def _validate_network_mapping_info(self, network_mapping_info): self._set_mapping_info_defaults(network_mapping_info) network_id = network_mapping_info.get(NETWORK_ID) if not network_id: raise exceptions.InvalidInput( error_message=_("A network identifier must be specified " "when connecting a network to a network " "gateway. Unable to complete operation")) connection_attrs = set(network_mapping_info.keys()) if not connection_attrs.issubset(ALLOWED_CONNECTION_ATTRIBUTES): raise exceptions.InvalidInput( error_message=(_("Invalid keys found among the ones provided " "in request body: %(connection_attrs)s."), connection_attrs)) seg_type = network_mapping_info.get(SEGMENTATION_TYPE) seg_id = network_mapping_info.get(SEGMENTATION_ID) # It is important to validate that the segmentation ID is actually an # integer value try: seg_id = int(seg_id) except ValueError: msg = _("An invalid segmentation ID was specified. The " "segmentation ID must be a positive integer number") raise exceptions.InvalidInput(error_message=msg) # The NSX plugin accepts 0 as a valid vlan tag seg_id_valid = seg_id == 0 or utils.is_valid_vlan_tag(seg_id) if seg_type.lower() == 'flat' and seg_id: msg = _("Cannot specify a segmentation id when " "the segmentation type is flat") raise exceptions.InvalidInput(error_message=msg) elif (seg_type.lower() == 'vlan' and not seg_id_valid): msg = _("Invalid segmentation id (%s) for " "vlan segmentation type") % seg_id raise exceptions.InvalidInput(error_message=msg) return network_id
def __init__(self, az_conf, az_class, default_availability_zones=None): self.availability_zones = {} # Add the configured availability zones for az in az_conf: obj = az_class(az) self.availability_zones[obj.name] = obj # add a default entry obj = az_class(None, default_name=self.default_name) self.availability_zones[obj.name] = obj # validate the default az: if default_availability_zones: # we support only 1 default az if len(default_availability_zones) > 1: raise nsx_exc.NsxInvalidConfiguration( opt_name="default_availability_zones", opt_value=default_availability_zones, reason=_("The NSX plugin supports only 1 default AZ")) default_az_name = default_availability_zones[0] if (default_az_name not in self.availability_zones): raise nsx_exc.NsxInvalidConfiguration( opt_name="default_availability_zones", opt_value=default_availability_zones, reason=_("The default AZ is not defined in the NSX " "plugin")) else: self._default_az = self.availability_zones[default_az_name] else: self._default_az = self.availability_zones[self.default_name]
def add_nsx_extensions_to_parser(parser, client_manager, is_create=True): allowed_extensions = utils.get_extensions(client_manager) # Provider security group (only for create action) if (is_create and 'provider-security-group' in allowed_extensions): parser.add_argument( '--provider-security-group', metavar='<provider-security-group>', action='append', dest='provider_security_groups', help=_("Provider Security group to associate with this port " "(name or ID) " "(repeat option to set multiple security groups)") ) if 'vnic-index' in allowed_extensions: # vnic index parser.add_argument( '--vnic-index', type=int, metavar='<vnic-index>', help=_("Vnic index") ) if 'mac-learning' in allowed_extensions: # mac-learning-enabled mac_learning_group = parser.add_mutually_exclusive_group() mac_learning_group.add_argument( '--enable-mac-learning', action='store_true', help=_("Enable MAC learning") ) mac_learning_group.add_argument( '--disable-mac-learning', action='store_true', help=_("Disable MAC learning (Default") )
def create_ipsec_site_connection(self, context, ipsec_site_connection): LOG.debug('Creating ipsec site connection %(conn_info)s.', {"conn_info": ipsec_site_connection}) new_ipsec = self._convert_ipsec_conn(context, ipsec_site_connection) vpnservice_id = ipsec_site_connection['vpnservice_id'] edge_id = self._get_router_edge_id(context, vpnservice_id)[1] with locking.LockManager.get_lock(edge_id): vse_sites = self._generate_new_sites(edge_id, new_ipsec) ipsec_id = ipsec_site_connection["id"] try: LOG.debug('Updating ipsec vpn configuration %(vse_sites)s.', {'vse_sites': vse_sites}) self._update_ipsec_config(edge_id, vse_sites, enabled=True) except vcns_exc.VcnsApiException: self._update_status(context, vpnservice_id, ipsec_id, "ERROR") msg = (_("Failed to create ipsec site connection " "configuration with %(edge_id)s.") % {'edge_id': edge_id}) raise nsxv_exc.NsxPluginException(err_msg=msg) LOG.debug('Updating ipsec vpn firewall') try: self._update_firewall_rules(context, vpnservice_id) except vcns_exc.VcnsApiException: self._update_status(context, vpnservice_id, ipsec_id, "ERROR") msg = (_("Failed to update firewall rule for ipsec vpn " "with %(edge_id)s.") % {'edge_id': edge_id}) raise nsxv_exc.NsxPluginException(err_msg=msg) self._update_status(context, vpnservice_id, ipsec_id, "ACTIVE")
def update_lrouter_port_ips(cluster, lrouter_id, lport_id, ips_to_add, ips_to_remove): uri = nsxlib._build_uri_path(LROUTERPORT_RESOURCE, lport_id, lrouter_id) try: port = nsxlib.do_request(HTTP_GET, uri, cluster=cluster) # TODO(salvatore-orlando): Enforce ips_to_add intersection with # ips_to_remove is empty ip_address_set = set(port['ip_addresses']) ip_address_set = ip_address_set - set(ips_to_remove) ip_address_set = ip_address_set | set(ips_to_add) # Set is not JSON serializable - convert to list port['ip_addresses'] = list(ip_address_set) nsxlib.do_request(HTTP_PUT, uri, jsonutils.dumps(port), cluster=cluster) except exception.NotFound: # FIXME(salv-orlando):avoid raising different exception data = {'lport_id': lport_id, 'lrouter_id': lrouter_id} msg = (_("Router Port %(lport_id)s not found on router " "%(lrouter_id)s") % data) LOG.exception(msg) raise nsx_exc.NsxPluginException(err_msg=msg) except api_exc.NsxApiException as e: msg = _("An exception occurred while updating IP addresses on a " "router logical port:%s") % e LOG.exception(msg) raise nsx_exc.NsxPluginException(err_msg=msg)
def get_details(self): """Return subnet data as a SpecificSubnetRequest""" # get the pool from the backend try: pool_details = self.nsxlib_ipam.get(self._nsx_pool_id) except Exception as e: msg = _('Failed to get details for nsx pool: %(id)s: ' '%(e)s') % {'id': self._nsx_pool_id, 'e': e} raise ipam_exc.IpamValueInvalid(message=msg) first_range = pool_details.get('subnets', [None])[0] if not first_range: msg = _('Failed to get details for nsx pool: %(id)s') % { 'id': self._nsx_pool_id} raise ipam_exc.IpamValueInvalid(message=msg) cidr = first_range.get('cidr') gateway_ip = first_range.get('gateway_ip') pools = [] for subnet in pool_details.get('subnets', []): for ip_range in subnet.get('allocation_ranges', []): pools.append(netaddr.IPRange(ip_range.get('start'), ip_range.get('end'))) return ipam_req.SpecificSubnetRequest( self._tenant_id, self._subnet_id, cidr, gateway_ip=gateway_ip, allocation_pools=pools)
def create_flow_classifier_precommit(self, context): """Validate the flow classifier data before committing the transaction The NSX-v redirect rules does not support: - logical ports - l7 parameters - source ports range / destination port range with more than 15 ports """ flow_classifier = context.current # Logical source port logical_source_port = flow_classifier['logical_source_port'] if logical_source_port is not None: msg = _('The NSXv driver does not support setting ' 'logical source port in FlowClassifier') raise exc.FlowClassifierBadRequest(message=msg) # Logical destination port logical_destination_port = flow_classifier['logical_destination_port'] if logical_destination_port is not None: msg = _('The NSXv driver does not support setting ' 'logical destination port in FlowClassifier') raise exc.FlowClassifierBadRequest(message=msg) # L7 parameters l7_params = flow_classifier['l7_parameters'] if l7_params is not None and len(l7_params.keys()) > 0: msg = _('The NSXv driver does not support setting ' 'L7 parameters in FlowClassifier') raise exc.FlowClassifierBadRequest(message=msg)
def _extract_external_gw(self, context, router, is_extract=True): r = router['router'] gw_info = constants.ATTR_NOT_SPECIFIED # First extract the gateway info in case of updating # gateway before edge is deployed. if 'external_gateway_info' in r: gw_info = r.get('external_gateway_info', {}) if is_extract: del r['external_gateway_info'] network_id = (gw_info.get('network_id') if gw_info else None) if network_id: ext_net = self._get_network(context, network_id) if not ext_net.external: msg = (_("Network '%s' is not a valid external network") % network_id) raise n_exc.BadRequest(resource='router', msg=msg) subnets = self._get_subnets_by_network(context.elevated(), network_id) if not subnets: msg = _("Cannot update gateway on Network '%s' " "with no subnet") % network_id raise n_exc.BadRequest(resource='router', msg=msg) return gw_info
def validate_tier0(self, tier0_groups_dict, tier0_uuid): err_msg = None try: lrouter = self._router_client.get(tier0_uuid) except nsx_exc.ResourceNotFound: err_msg = (_("Tier0 router %s not found at the backend. Either a " "valid UUID must be specified or a default tier0 " "router UUID must be configured in nsx.ini") % tier0_uuid) else: edge_cluster_uuid = lrouter.get('edge_cluster_id') if not edge_cluster_uuid: err_msg = _("Failed to get edge cluster uuid from tier0 " "router %s at the backend") % lrouter else: edge_cluster = nsxlib.get_edge_cluster(edge_cluster_uuid) member_index_list = [member['member_index'] for member in edge_cluster['members']] if len(member_index_list) < MIN_EDGE_NODE_NUM: err_msg = _("%(act_num)s edge members found in " "edge_cluster %(cluster_id)s, however we " "require at least %(exp_num)s edge nodes " "in edge cluster for use.") % { 'act_num': len(member_index_list), 'exp_num': MIN_EDGE_NODE_NUM, 'cluster_id': edge_cluster_uuid} if err_msg: raise n_exc.InvalidInput(error_message=err_msg) else: tier0_groups_dict[tier0_uuid] = { 'edge_cluster_uuid': edge_cluster_uuid, 'member_index_list': member_index_list}
def _validate_dns_format(data): if not data: return try: # Allow values ending in period '.' trimmed = data if not data.endswith('.') else data[:-1] names = trimmed.split('.') for name in names: if not name: raise TypeError(_("Encountered an empty component")) if name.endswith('-') or name[0] == '-': raise TypeError( _("Name '%s' must not start or end with a hyphen") % name) if not re.match(DNS_LABEL_REGEX, name): raise TypeError( _("Name '%s' must be 1-63 characters long, each of " "which can only be alphanumeric or a hyphen") % name) # RFC 1123 hints that a TLD can't be all numeric. last is a TLD if # it's an FQDN. if len(names) > 1 and re.match("^[0-9]+$", names[-1]): raise TypeError(_("TLD '%s' must not be all numeric") % names[-1]) except TypeError as e: msg = _("'%(data)s' not a valid DNS search domain. Reason: " "%(reason)s") % {'data': data, 'reason': str(e)} return msg
def validate(self, context, network_id): """Validate and return subnet's dhcp info for migration.""" network = self.plugin.get_network(context, network_id) if self.manager.lsn_exists(context, network_id): reason = _("LSN already exist") raise p_exc.LsnMigrationConflict(net_id=network_id, reason=reason) if network[external_net.EXTERNAL]: reason = _("Cannot migrate an external network") raise n_exc.BadRequest(resource='network', msg=reason) filters = {'network_id': [network_id]} subnets = self.plugin.get_subnets(context, filters=filters) count = len(subnets) if count == 0: return None elif count == 1 and subnets[0]['cidr'] == rpc.METADATA_SUBNET_CIDR: reason = _("Cannot migrate a 'metadata' network") raise n_exc.BadRequest(resource='network', msg=reason) elif count > 1: reason = _("Unable to support multiple subnets per network") raise p_exc.LsnMigrationConflict(net_id=network_id, reason=reason) else: return subnets[0]
def delete_ipsec_site_connection(self, context, ipsec_site_conn): LOG.debug('Deleting ipsec site connection %(site)s.', {"site": ipsec_site_conn}) ipsec_id = ipsec_site_conn['id'] edge_id = self._get_router_edge_id(context, ipsec_site_conn['vpnservice_id'])[1] with locking.LockManager.get_lock(edge_id): del_site, vse_sites = self._find_vse_site(context, edge_id, ipsec_site_conn) if not del_site: LOG.error("Failed to find ipsec_site_connection " "%(ipsec_site_conn)s with %(edge_id)s.", {'ipsec_site_conn': ipsec_site_conn, 'edge_id': edge_id}) raise nsxv_exc.NsxIPsecVpnMappingNotFound(conn=ipsec_id) vse_sites.remove(del_site) enabled = True if vse_sites else False try: self._update_ipsec_config(edge_id, vse_sites, enabled) except vcns_exc.VcnsApiException: msg = (_("Failed to delete ipsec site connection " "configuration with edge_id: %(edge_id)s.") % {'egde_id': edge_id}) raise nsxv_exc.NsxPluginException(err_msg=msg) try: self._update_firewall_rules(context, ipsec_site_conn['vpnservice_id']) except vcns_exc.VcnsApiException: msg = _("Failed to update firewall rule for ipsec vpn with " "%(edge_id)s.") % {'edge_id': edge_id} raise nsxv_exc.NsxPluginException(err_msg=msg)
def create_l2_gateway_connection_precommit(self, context, gw_connection): """Validate the L2 gateway connection Do not allow another connection with the same bride cluster and seg_id """ admin_ctx = context.elevated() nsxlib = self._core_plugin.nsxlib l2gw_id = gw_connection.get(l2gw_const.L2GATEWAY_ID) devices = self._get_l2_gateway_devices(context, l2gw_id) bep_id = devices[0].get('device_name') # Check for bridge endpoint profile existence # if bridge endpoint profile is not found, this is likely an old # connection, fail with error. try: nsxlib.bridge_endpoint_profile.get_id_by_name_or_id(bep_id) except nsxlib_exc.ManagerError as e: msg = (_("Error while retrieving bridge endpoint profile " "%(bep_id)s from NSX backend. Check that the profile " "exits and there are not multiple profiles with " "the given name. Exception: %(exc)s") % {'bep_id': bep_id, 'exc': e}) raise n_exc.InvalidInput(error_message=msg) interface_name, seg_id = self._get_conn_parameters( admin_ctx, gw_connection) try: # Use search API for listing bridge endpoints on NSX for provided # VLAN id, transport zone id, and Bridge endpoint profile endpoints = nsxlib.search_all_resource_by_attributes( nsxlib.bridge_endpoint.resource_type, bridge_endpoint_profile_id=bep_id, vlan_transport_zone_id=interface_name, vlan=seg_id) endpoint_map = dict((endpoint['id'], endpoint['bridge_endpoint_profile_id']) for endpoint in endpoints) except nsxlib_exc.ManagerError as e: msg = (_("Error while retrieving endpoints for bridge endpoint " "profile %(bep_id)s s from NSX backend. " "Exception: %(exc)s") % {'bep_id': bep_id, 'exc': e}) raise n_exc.InvalidInput(error_message=msg) # get all bridge endpoint ports with db_api.CONTEXT_WRITER.using(admin_ctx): port_filters = {'device_owner': [nsx_constants.BRIDGE_ENDPOINT]} ports = self._core_plugin.get_ports( admin_ctx, filters=port_filters) for port in ports: device_id = port.get('device_id') if endpoint_map.get(device_id) == bep_id: # This device is using the same vlan id and bridge endpoint # profile as the one requested. Not ok. msg = (_("Cannot create multiple connections with the " "same segmentation id %(seg_id)s for bridge " "endpoint profile %(bep_id)s") % {'seg_id': seg_id, 'bep_id': bep_id}) raise n_exc.InvalidInput(error_message=msg)
def _validate_interface_list(self, interfaces): # In NSXv, interface is mapped to a vDS VLAN port group. # Since HA is not supported, only one interface is expected if len(interfaces) != 1: msg = _("Only a single interface is supported for one L2 gateway") raise n_exc.InvalidInput(error_message=msg) if not self._nsxv.vcns.validate_network(interfaces[0]['name']): msg = _("Configured interface not found") raise n_exc.InvalidInput(error_message=msg)
def _check_advertisment_overlap(self, context, ipsec_site_conn): """Validate there is no overlapping advertisement of networks The plugin advertise all no-snat routers networks + vpn local networks. The NSX does not allow different Tier1 router to advertise the same subnets """ admin_con = context.elevated() srv_id = ipsec_site_conn.get('vpnservice_id') srv = self.vpn_plugin._get_vpnservice(admin_con, srv_id) this_router = srv['router_id'] this_cidr = srv['subnet']['cidr'] # get all subnets of no-snat routers all_routers = self._core_plugin.get_routers(admin_con) nosnat_routers = [rtr for rtr in all_routers if (rtr['id'] != this_router and rtr.get('external_gateway_info') and not rtr['external_gateway_info'].get( 'enable_snat', cfg.CONF.enable_snat_by_default))] for rtr in nosnat_routers: if rtr['id'] == this_router: continue # go over the subnets of this router subnets = self._core_plugin._find_router_subnets_cidrs( admin_con, rtr['id']) if subnets and netaddr.IPSet(subnets) & netaddr.IPSet([this_cidr]): msg = (_("Cannot create connection with overlapping local " "cidrs %(local)s which was already advertised by " "no-snat router %(rtr)s") % {'local': subnets, 'rtr': rtr['id']}) raise nsx_exc.NsxVpnValidationError(details=msg) # add all vpn local subnets connections = self.vpn_plugin.get_ipsec_site_connections(admin_con) for conn in connections: # skip this connection and connections in non active state if (conn['id'] == ipsec_site_conn.get('id') or conn['status'] != constants.ACTIVE): continue # check the service local address conn_srv_id = conn.get('vpnservice_id') conn_srv = self.vpn_plugin._get_vpnservice(admin_con, conn_srv_id) if conn_srv['router_id'] == this_router: continue conn_cidr = conn_srv['subnet']['cidr'] if netaddr.IPSet([conn_cidr]) & netaddr.IPSet([this_cidr]): msg = (_("Cannot create connection with overlapping local " "cidr %(local)s which was already advertised by " "router %(rtr)s and connection %(conn)s") % { 'local': conn_cidr, 'rtr': conn_srv['router_id'], 'conn': conn['id']}) raise nsx_exc.NsxVpnValidationError(details=msg)
def _get_proxy_edges(self, context): proxy_edge_ips = [] db_edge_ips = get_db_internal_edge_ips(context, self.az.name) if len(db_edge_ips) > len(self.az.mgt_net_proxy_ips): error = (_('Number of configured metadata proxy IPs is smaller ' 'than number of Edges which are already provisioned ' 'for availability zone %s'), self.az.name) raise nsxv_exc.NsxPluginException(err_msg=error) pool = eventlet.GreenPool(min(MAX_INIT_THREADS, len(self.az.mgt_net_proxy_ips))) # Edge IPs that exist in both lists have to be validated that their # Edge appliance settings are valid for edge_inner_ip in pool.imap( self._setup_proxy_edge_route_and_connectivity, list(set(db_edge_ips) & set(self.az.mgt_net_proxy_ips))): proxy_edge_ips.append(edge_inner_ip) # Edges that exist only in the CFG list, should be paired with Edges # that exist only in the DB list. The existing Edge from the list will # be reconfigured to match the new config edge_to_convert_ips = ( list(set(db_edge_ips) - set(self.az.mgt_net_proxy_ips))) edge_ip_to_set = ( list(set(self.az.mgt_net_proxy_ips) - set(db_edge_ips))) if edge_to_convert_ips: if cfg.CONF.nsxv.metadata_initializer: for edge_inner_ip in pool.imap( self._setup_proxy_edge_external_interface_ip, zip(edge_to_convert_ips, edge_ip_to_set)): proxy_edge_ips.append(edge_inner_ip) else: error = _('Metadata initialization is incomplete on ' 'initializer node') raise nsxv_exc.NsxPluginException(err_msg=error) # Edges that exist in the CFG list but do not have a matching DB # element will be created. remaining_cfg_ips = edge_ip_to_set[len(edge_to_convert_ips):] if remaining_cfg_ips: if cfg.CONF.nsxv.metadata_initializer: for edge_inner_ip in pool.imap( self._setup_new_proxy_edge, remaining_cfg_ips): proxy_edge_ips.append(edge_inner_ip) pool.waitall() else: error = _('Metadata initialization is incomplete on ' 'initializer node') raise nsxv_exc.NsxPluginException(err_msg=error) return proxy_edge_ips
def backend_allocate(self, address_request): try: # allocate a specific IP if isinstance(address_request, ipam_req.SpecificAddressRequest): # This handles both specific and automatic address requests ip_address = str(address_request.address) # If this is the subnet gateway IP - no need to allocate it subnet = self.get_details() if str(subnet.gateway_ip) == ip_address: LOG.info("Skip allocation of gateway-ip for pool %s", self._nsx_pool_id) return ip_address else: # Allocate any free IP ip_address = None response = self.nsxlib_ipam.allocate(self._nsx_pool_id, ip_addr=ip_address) ip_address = response['allocation_id'] except nsx_lib_exc.ManagerError as e: LOG.error("NSX IPAM failed to allocate ip %(ip)s of subnet " "%(id)s: %(e)s; code %(code)s", {'e': e, 'ip': ip_address, 'id': self._subnet_id, 'code': e.error_code}) if e.error_code == error.ERR_CODE_IPAM_POOL_EXHAUSTED: # No more IP addresses available on the pool raise ipam_exc.IpAddressGenerationFailure( subnet_id=self._subnet_id) if e.error_code == error.ERR_CODE_IPAM_SPECIFIC_IP: # The NSX backend does not support allocation of specific IPs # prior to version 2.0. msg = (_("NSX-V3 IPAM driver does not support allocation of a " "specific ip %s for port") % ip_address) raise NotImplementedError(msg) if e.error_code == error.ERR_CODE_IPAM_IP_ALLOCATED: # This IP is already in use raise ipam_exc.IpAddressAlreadyAllocated( ip=ip_address, subnet_id=self._subnet_id) if e.error_code == error.ERR_CODE_OBJECT_NOT_FOUND: msg = (_("NSX-V3 IPAM failed to allocate: pool %s was not " "found") % self._nsx_pool_id) raise ipam_exc.IpamValueInvalid(message=msg) else: # another backend error raise ipam_exc.IPAllocationFailed() except Exception as e: LOG.error("NSX IPAM failed to allocate ip %(ip)s of subnet " "%(id)s: %(e)s", {'e': e, 'ip': ip_address, 'id': self._subnet_id}) # handle unexpected failures raise ipam_exc.IPAllocationFailed() return ip_address
def _validate_device_list(self, devices): # In NSXv3, one L2 gateway is mapped to one bridge cluster. # So we expect only one device to be configured as part of # a L2 gateway resource. The name of the device must be the bridge # cluster's UUID. if len(devices) != 1: msg = _("Only a single device is supported for one L2 gateway") raise n_exc.InvalidInput(error_message=msg) if not uuidutils.is_uuid_like(devices[0]['device_name']): msg = _("Device name must be configured with a UUID") raise n_exc.InvalidInput(error_message=msg)
def init_from_config_section(self, az_name): az_info = self.get_az_opts() if self._has_native_dhcp_metadata(): # The optional parameters will get the global values if not # defined for this AZ self.metadata_proxy = az_info.get('metadata_proxy') if not self.metadata_proxy: raise nsx_exc.NsxInvalidConfiguration( opt_name="metadata_proxy", opt_value='None', reason=(_("metadata_proxy for availability zone %s " "must be defined") % az_name)) self.dhcp_profile = az_info.get('dhcp_profile') if not self.dhcp_profile: raise nsx_exc.NsxInvalidConfiguration( opt_name="dhcp_profile", opt_value='None', reason=(_("dhcp_profile for availability zone %s " "must be defined") % az_name)) native_metadata_route = az_info.get('native_metadata_route') if native_metadata_route: self.native_metadata_route = native_metadata_route else: self.metadata_proxy = None self.dhcp_profile = None self.native_metadata_route = None default_overlay_tz = az_info.get('default_overlay_tz') if default_overlay_tz: self.default_overlay_tz = default_overlay_tz default_vlan_tz = az_info.get('default_vlan_tz') if default_vlan_tz: self.default_vlan_tz = default_vlan_tz default_tier0_router = az_info.get('default_tier0_router') if default_tier0_router: self.default_tier0_router = default_tier0_router dns_domain = az_info.get('dns_domain') if dns_domain: self.dns_domain = dns_domain nameservers = az_info.get('nameservers') if nameservers: self.nameservers = nameservers edge_cluster = az_info.get('edge_cluster') if edge_cluster: self.edge_cluster = edge_cluster
def create(self, context, pol, completor): # find out the edge to be updated, by the listener of this policy listener = pol['listener'] lb_id = listener['loadbalancer_id'] lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding( context.session, lb_id) if not lb_binding: msg = _( 'No suitable Edge found for listener %s') % listener['id'] raise n_exc.BadRequest(resource='edge-lbaas', msg=msg) if (listener['protocol'] == lb_const.LB_PROTOCOL_HTTPS or listener['protocol'] == lb_const.LB_PROTOCOL_TERMINATED_HTTPS): msg = _( 'L7 policy is not supported for %(prot)s listener %(ls)s') % { 'prot': listener['protocol'], 'ls': pol['listener_id']} raise n_exc.BadRequest(resource='edge-lbaas', msg=msg) edge_id = lb_binding['edge_id'] app_rule = policy_to_application_rule(pol) app_rule_id = None try: with locking.LockManager.get_lock(edge_id): # create the backend application rule for this policy h = (self.vcns.create_app_rule(edge_id, app_rule))[0] app_rule_id = lb_common.extract_resource_id(h['location']) # add the nsx application rule (neutron policy) to the nsx # virtual server (neutron listener) vse_id = self._get_vse_id(context, pol) if vse_id: self._add_app_rule_to_virtual_server( edge_id, vse_id, app_rule_id, pol['position']) except Exception as e: with excutils.save_and_reraise_exception(): completor(success=False) LOG.error('Failed to create L7policy on edge %(edge)s: ' '%(err)s', {'edge': edge_id, 'err': e}) if app_rule_id: # Failed to add the rule to the vip: delete the rule # from the backend. try: self.vcns.delete_app_rule(edge_id, app_rule_id) except Exception: pass # save the nsx application rule id in the DB nsxv_db.add_nsxv_lbaas_l7policy_binding(context.session, pol['id'], edge_id, app_rule_id) # complete the transaction completor(success=True)
def _check_services_requirements(self): try: error = None nsx_svc.check_services_requirements(self.cluster) except nsx_exc.InvalidVersion: error = _("Unable to run Neutron with config option '%s', as NSX " "does not support it") % cfg.CONF.NSX.agent_mode except nsx_exc.ServiceClusterUnavailable: error = _("Unmet dependency for config option " "'%s'") % cfg.CONF.NSX.agent_mode if error: LOG.exception(error) raise nsx_exc.NsxPluginException(err_msg=error)
def init_from_config_line(self, config_line): values = config_line.split(':') if len(values) < 4 or len(values) > 5: raise nsx_exc.NsxInvalidConfiguration( opt_name="availability_zones", opt_value=config_line, reason=_("Expected 4 or 5 values per zone")) self.resource_pool = values[1] self.datastore_id = values[2] # validate the edge_ha if values[3].lower() == "true": self.edge_ha = True elif values[3].lower() == "false": self.edge_ha = False else: raise nsx_exc.NsxInvalidConfiguration( opt_name="availability_zones", opt_value=config_line, reason=_("Expected the 4th value to be true/false")) # HA datastore id is relevant only with edge_ha if not self.edge_ha and len(values) == 5: raise nsx_exc.NsxInvalidConfiguration( opt_name="availability_zones", opt_value=config_line, reason=_("Expected HA datastore ID only when edge_ha is " "enabled")) self.ha_datastore_id = values[4] if len(values) == 5 else None # Some parameters are not supported in this format. # using the global ones instead. self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random self.datacenter_moid = cfg.CONF.nsxv.datacenter_moid self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool self.external_network = cfg.CONF.nsxv.external_network self.vdn_scope_id = cfg.CONF.nsxv.vdn_scope_id self.dvs_id = cfg.CONF.nsxv.dvs_id self.edge_host_groups = cfg.CONF.nsxv.edge_host_groups self.exclusive_dhcp_edge = cfg.CONF.nsxv.exclusive_dhcp_edge self.bind_floatingip_to_all_interfaces = ( cfg.CONF.nsxv.bind_floatingip_to_all_interfaces) # No support for metadata per az self.az_metadata_support = False self.mgt_net_moid = None self.mgt_net_proxy_ips = [] self.mgt_net_proxy_netmask = None self.mgt_net_default_gateway = None
def _validate_connector_type(data, valid_values=None): if not data: # A connector type is compulsory msg = _("A connector type is required to create a gateway device") return msg connector_types = (valid_values if valid_values else [NetworkTypes.GRE, NetworkTypes.STT, NetworkTypes.BRIDGE, 'ipsec%s' % NetworkTypes.GRE, 'ipsec%s' % NetworkTypes.STT]) if data not in connector_types: msg = _("Unknown connector type: %s") % data return msg
def _validate_port_vnic_type(self, context, port_data, network_id): vnic_type = port_data.get(pbin.VNIC_TYPE) if vnic_type and vnic_type not in SUPPORTED_VNIC_TYPES: err_msg = _("Invalid port vnic-type '%(vnic_type)s'." "Supported vnic-types are %(valid_types)s.") % { 'vnic_type': vnic_type, 'valid_types': SUPPORTED_VNIC_TYPES } raise exceptions.InvalidInput(error_message=err_msg) direct_vnic_type = vnic_type in VNIC_TYPES_DIRECT_PASSTHROUGH if direct_vnic_type: self._validate_vnic_type_direct_passthrough_for_network( context, network_id) return direct_vnic_type
def delete(self, context, policy, completor): vs_client = self.core_plugin.nsxpolicy.load_balancer.virtual_server policy_name = utils.get_name_and_uuid(policy['name'] or 'policy', policy['id']) try: vs_client.remove_lb_rule(policy['listener_id'], policy_name) except nsx_exc.NsxResourceNotFound: pass except nsxlib_exc.ManagerError: completor(success=False) msg = (_('Failed to delete L7 policy: %(policy)s') % { 'policy': policy['id'] }) raise n_exc.BadRequest(resource='lbaas-l7policy', msg=msg) completor(success=True)
def validate_ike_policy(self, context, ike_policy): # Call general validations super(IPsecV3Validator, self).validate_ike_policy(context, ike_policy) # Call specific NSX validations self._validate_policy_lifetime(ike_policy, "IKE") self._validate_policy_auth_algorithm(ike_policy, "IKE") self._validate_policy_encryption_algorithm(ike_policy, "IKE") self._validate_policy_pfs(ike_policy, "IKE") # 'aggressive' phase1-negotiation-mode is not supported if ike_policy.get('phase1-negotiation-mode', 'main') != 'main': msg = _("Unsupported phase1-negotiation-mode: %s! Only 'main' is " "supported.") % ike_policy['phase1-negotiation-mode'] raise nsx_exc.NsxVpnValidationError(details=msg)
def validate_tier0(self, tier0_groups_dict, tier0_uuid): err_msg = None try: lrouter = self._router_client.get(tier0_uuid) except exceptions.ResourceNotFound: err_msg = (_("Tier0 router %s not found at the backend. Either a " "valid UUID must be specified or a default tier0 " "router UUID must be configured in nsx.ini") % tier0_uuid) else: edge_cluster_uuid = lrouter.get('edge_cluster_id') if not edge_cluster_uuid: err_msg = _("Failed to get edge cluster uuid from tier0 " "router %s at the backend") % lrouter else: edge_cluster = self.nsxlib.get_edge_cluster(edge_cluster_uuid) member_index_list = [ member['member_index'] for member in edge_cluster['members'] ] if len(member_index_list) < MIN_EDGE_NODE_NUM: err_msg = _("%(act_num)s edge members found in " "edge_cluster %(cluster_id)s, however we " "require at least %(exp_num)s edge nodes " "in edge cluster for use.") % { 'act_num': len(member_index_list), 'exp_num': MIN_EDGE_NODE_NUM, 'cluster_id': edge_cluster_uuid } if err_msg: raise n_exc.InvalidInput(error_message=err_msg) else: tier0_groups_dict[tier0_uuid] = { 'edge_cluster_uuid': edge_cluster_uuid, 'member_index_list': member_index_list }
def validate_ipsec_policy(self, context, ipsec_policy): # Call general validations super(IPsecV3Validator, self).validate_ipsec_policy(context, ipsec_policy) # Call specific NSX validations self._validate_policy_lifetime(ipsec_policy, "IPSec") self._validate_policy_auth_algorithm(ipsec_policy, "IPSec") self._validate_policy_encryption_algorithm(ipsec_policy, "IPSec") self._validate_policy_pfs(ipsec_policy, "IPSec") # Ensure IPSec policy encap mode is tunnel mode = ipsec_policy.get('encapsulation_mode') if mode and mode not in ipsec_utils.ENCAPSULATION_MODE_MAP.keys(): msg = _("Unsupported encapsulation mode: %s. Only 'tunnel' mode " "is supported.") % mode raise nsx_exc.NsxVpnValidationError(details=msg) # Ensure IPSec policy transform protocol is esp prot = ipsec_policy.get('transform_protocol') if prot and prot not in ipsec_utils.TRANSFORM_PROTOCOL_MAP.keys(): msg = _("Unsupported transform protocol: %s. Only 'esp' protocol " "is supported.") % prot raise nsx_exc.NsxVpnValidationError(details=msg)
def _extract_external_gw(self, context, router, is_extract=True): r = router['router'] gw_info = constants.ATTR_NOT_SPECIFIED # First extract the gateway info in case of updating # gateway before edge is deployed. if 'external_gateway_info' in r: gw_info = r.get('external_gateway_info', {}) if is_extract: del r['external_gateway_info'] network_id = (gw_info.get('network_id') if gw_info else None) if network_id: ext_net = self._get_network(context.elevated(), network_id) if not ext_net.external: msg = (_("Network '%s' is not a valid external network") % network_id) raise n_exc.BadRequest(resource='router', msg=msg) subnets = self._get_subnets_by_network(context.elevated(), network_id) if not subnets: msg = _("Cannot update gateway on Network '%s' " "with no subnet") % network_id raise n_exc.BadRequest(resource='router', msg=msg) return gw_info
def get_lb_flavor_size(flavor_plugin, context, flavor_id): if not flavor_id: return lb_const.DEFAULT_LB_SIZE else: flavor = flavors_plugin.FlavorsPlugin.get_flavor( flavor_plugin, context, flavor_id) flavor_size = flavor['name'] if flavor_size in lb_const.LB_FLAVOR_SIZES: return flavor_size.upper() else: err_msg = (_("Invalid flavor size %(flavor)s, only 'small', " "'medium', or 'large' are supported") % { 'flavor': flavor_size }) raise n_exc.InvalidInput(error_message=err_msg)
def validate_obj_azs(self, availability_zones): """Verify that the availability zones exist, and only 1 hint was set. """ # For now we support only 1 hint per network/router # TODO(asarfaty): support multiple hints if len(availability_zones) > 1: err_msg = _("Can't use multiple availability zone hints") raise n_exc.InvalidInput(error_message=err_msg) # check that all hints appear in the predefined list of availability # zones diff = (set(availability_zones) - set(self.get_azs_names())) if diff: raise az_exc.AvailabilityZoneNotFound(availability_zone=diff.pop())
def create_policy(self, context, policy): policy_id = policy.id tags = self._get_tags(context, policy) result = self._nsxlib_qos.create( tags=tags, name=policy.name, description=policy.description) if not result or not validators.is_attr_set(result.get('id')): msg = _("Unable to create QoS switching profile on the backend") raise nsx_exc.NsxPluginException(err_msg=msg) profile_id = result['id'] # Add the mapping entry of the policy_id <-> profile_id nsx_db.add_qos_policy_profile_mapping(context.session, policy_id, profile_id)
def init_profile_id(self): """Init the service insertion profile ID Initialize the profile id that should be assigned to the redirect rules from the nsx configuration and verify that it exists on backend. """ if not cfg.CONF.nsxv.service_insertion_profile_id: raise cfg.RequiredOptError("service_profile_id") self._profile_id = cfg.CONF.nsxv.service_insertion_profile_id # Verify that this moref exists if not self._nsxv.vcns.validate_inventory(self._profile_id): error = (_("Configured service profile ID: %s not found") % self._profile_id) raise nsx_exc.NsxPluginException(err_msg=error)
def _get_lb_flavor_size(self, context, flavor_id): if not flavor_id: return vcns_const.SERVICE_SIZE_MAPPING['lb'] else: flavor = flavors_plugin.FlavorsPlugin.get_flavor( self.flavor_plugin, context, flavor_id) flavor_size = flavor['name'] if flavor_size.lower() in vcns_const.ALLOWED_EDGE_SIZES: return flavor_size.lower() else: err_msg = (_("Invalid flavor size %(flavor)s, only %(sizes)s " "are supported") % {'flavor': flavor_size, 'sizes': vcns_const.ALLOWED_EDGE_SIZES}) raise n_exc.InvalidInput(error_message=err_msg)
def _get_internal_network_and_subnet(self, context): internal_net = None internal_subnet = None # Try to find internal net, internal subnet. If not found, create new net_list = nsxv_db.get_nsxv_internal_network( context.session, vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE) if net_list: internal_net = net_list[0]['network_id'] if internal_net: internal_subnet = self.nsxv_plugin.get_subnets( context, fields=['id'], filters={'network_id': [internal_net]})[0]['id'] if internal_net is None or internal_subnet is None: if cfg.CONF.nsxv.metadata_initializer: # Couldn't find net, subnet - create new try: internal_net, internal_subnet = ( self._create_metadata_internal_network( context, INTERNAL_SUBNET)) except Exception as e: nsxv_db.delete_nsxv_internal_network( context.session, vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE) # if network is created, clean up if internal_net: self.nsxv_plugin.delete_network(context, internal_net) LOG.exception( _LE("Exception %s while creating internal " "network for metadata service"), e) return # Update the new network_id in DB nsxv_db.create_nsxv_internal_network( context.session, nsxv_constants.INTER_EDGE_PURPOSE, internal_net) else: error = _('Metadata initialization is incomplete on ' 'initializer node') raise nsxv_exc.NsxPluginException(err_msg=error) return internal_net, internal_subnet
def _validate_member_lb_connectivity(self, context, member, completor): lb = member['pool'].get('loadbalancer') if not lb: msg = (_('Member %s loadbalancer object is missing') % member['id']) raise n_exc.BadRequest(resource='lbaas-vip', msg=msg) subnet_id = lb.get('vip_subnet_id') network = lb_utils.get_network_from_subnet(context, self.core_plugin, subnet_id) if not network.get('router:external'): return # If VIP is attached to an external network, loadbalancer_mgr might not # attach it to a router. If not, set the LB service connectivity path # to the member subnet's router. service_client = self.core_plugin.nsxpolicy.load_balancer.lb_service service = service_client.get(lb['id']) if not service.get('connectivity_path'): router_id = lb_utils.get_router_from_network( context, self.core_plugin, member['subnet_id']) if not self.core_plugin.service_router_has_services( context, router_id): self.core_plugin.create_service_router(context, router_id) connectivity_path = self.core_plugin.nsxpolicy.tier1.get_path( router_id) tags = lb_utils.get_tags(self.core_plugin, router_id, lb_const.LR_ROUTER_TYPE, lb['tenant_id'], context.project_name) try: service_client.update(lb['id'], tags=tags, connectivity_path=connectivity_path) p_utils.update_router_lb_vip_advertisement( context, self.core_plugin, router_id) except Exception as e: with excutils.save_and_reraise_exception(): completor(success=False) LOG.error( 'Failed to set connectivity for loadbalancer ' '%(lb)s on subnet %(sub)s with error %(err)s', { 'lb': lb['id'], 'sub': member['subnet_id'], 'err': e })
def _validate_vnic_type_direct_passthrough_for_network( self, context, network_id): supported_network_types = (c_utils.NsxVNetworkTypes.VLAN, c_utils.NsxVNetworkTypes.FLAT, c_utils.NsxVNetworkTypes.PORTGROUP) if not self._validate_network_type(context, network_id, supported_network_types): msg_info = { 'vnic_types': VNIC_TYPES_DIRECT_PASSTHROUGH, 'networks': supported_network_types } err_msg = _("%(vnic_types)s port vnic-types are only supported " "for ports on networks of types " "%(networks)s.") % msg_info raise exceptions.InvalidInput(error_message=err_msg)
def add_nsgroup(self, nsgroup_id): for group in self._suggest_nested_group(nsgroup_id): try: LOG.debug("Adding NSGroup %s to nested group %s", nsgroup_id, group) firewall.add_nsgroup_member(group, firewall.NSGROUP, nsgroup_id) break except firewall.NSGroupIsFull: LOG.debug("Nested group %(group_id)s is full, trying the " "next group..", {'group_id': group}) else: raise nsx_exc.NsxPluginException( err_msg=_("Reached the maximum supported amount of " "security groups."))
def allocate_edge_vnic(session, edge_id, network_id): """Allocate an available edge vnic to network.""" with session.begin(subtransactions=True): bindings = (session.query(nsxv_models.NsxvEdgeVnicBinding). filter_by(edge_id=edge_id, network_id=None).all()) for binding in bindings: if binding['tunnel_index'] % constants.MAX_TUNNEL_NUM == 1: binding['network_id'] = network_id session.add(binding) return binding msg = (_("Edge VNIC: Failed to allocate one available vnic on edge_id: " ":%(edge_id)s to network_id: %(network_id)s") % {'edge_id': edge_id, 'network_id': network_id}) LOG.error(msg) raise nsx_exc.NsxPluginException(err_msg=msg)
def validate_vpnservice(self, context, vpnservice): """Called upon create/update of a service""" self._validate_backend_version() # Call general validations super(IPsecV3Validator, self).validate_vpnservice(context, vpnservice) # Call specific NSX validations self._validate_router(context, vpnservice['router_id']) if not vpnservice['subnet_id']: # we currently do not support multiple subnets so a subnet must # be defined msg = _("Subnet must be defined in a service") raise nsx_exc.NsxVpnValidationError(details=msg)
def add_nsgroup(self, nsgroup_id): for group in self._suggest_nested_group(nsgroup_id): try: LOG.debug("Adding NSGroup %s to nested group %s", nsgroup_id, group) self.nsx.add_nsgroup_members(group, firewall.NSGROUP, [nsgroup_id]) break except exceptions.NSGroupIsFull: LOG.debug("Nested group %(group_id)s is full, trying the " "next group..", {'group_id': group}) else: raise exceptions.ManagerError( details=_("Reached the maximum supported amount of " "security groups."))
def _update_external_interface_on_routers(self, context, target_router_id, router_ids): ext_net_ids = self._get_ext_net_ids(context, router_ids) if len(ext_net_ids) > 1: LOG.error( "Can't configure external interface on multiple " "external networks %(networks)s for routers %(routers)s", { 'networks': ext_net_ids, 'routers': router_ids }) msg = _("Can't configure external interface on multiple external " "networks") raise nsx_exc.NsxPluginException(err_msg=msg) gateway_primary_addr = None gateway_mask = None gateway_nexthop = None secondary = [] if not ext_net_ids: ext_net_id = None else: ext_net_id = ext_net_ids[0] for router_id in router_ids: router_qry = context.session.query(l3_db_models.Router) router = router_qry.filter_by(id=router_id).one() addr, mask, nexthop = self.plugin._get_external_attachment_info( context, router) if addr: if not gateway_primary_addr: gateway_primary_addr = addr else: secondary.append(addr) if mask and not gateway_mask: gateway_mask = mask if nexthop and not gateway_nexthop: gateway_nexthop = nexthop secondary.extend( self.plugin._get_floatingips_by_router(context, router_id)) LOG.debug( 'Configure ext interface as following, ext_net: %s, ' 'primaryAddress: %s, netmask: %s, nexthop: %s, secondary: ' '%s.', ext_net_id, gateway_primary_addr, gateway_mask, gateway_nexthop, secondary) self.edge_manager.update_external_interface(self.nsx_v, context, target_router_id, ext_net_id, gateway_primary_addr, gateway_mask, secondary)
def _get_rule_match_conditions(self, rule): match_conditions = [] # values in rule have already been validated in LBaaS API, # we won't need to valid anymore in driver, and just get # the LB rule mapping from the dict. match_type = lb_const.LB_RULE_MATCH_TYPE[rule.compare_type] if rule.type == lb_const.L7_RULE_TYPE_COOKIE: header_value = rule.key + '=' + rule.value match_conditions.append({ 'type': 'LbHttpRequestHeaderCondition', 'match_type': match_type, 'header_name': 'Cookie', 'header_value': header_value }) elif rule.type == lb_const.L7_RULE_TYPE_FILE_TYPE: match_conditions.append({ 'type': 'LbHttpRequestUriCondition', 'match_type': match_type, 'uri': '*.' + rule.value }) elif rule.type == lb_const.L7_RULE_TYPE_HEADER: match_conditions.append({ 'type': 'LbHttpRequestHeaderCondition', 'match_type': match_type, 'header_name': rule.key, 'header_value': rule.value }) elif rule.type == lb_const.L7_RULE_TYPE_HOST_NAME: match_conditions.append({ 'type': 'LbHttpRequestHeaderCondition', 'match_type': match_type, 'header_name': 'Host', 'header_value': rule.value }) elif rule.type == lb_const.L7_RULE_TYPE_PATH: match_conditions.append({ 'type': 'LbHttpRequestUriCondition', 'match_type': match_type, 'uri': rule.value }) else: msg = (_('l7rule type %(type)s is not supported in LBaaS') % { 'type': rule.type }) LOG.error(msg) raise n_exc.BadRequest(resource='lbaas-l7rule', msg=msg) return match_conditions
def validate_vpnservice(self, context, vpnservice): if not vpnservice.get('tenant_id'): # This will happen during update. # nothing significant like router or subnet can be changes # so we can skip it. return v = self._get_validator_for_project(vpnservice['tenant_id']) # first make sure the router&subnet plugin matches the vpnservice router_id = vpnservice['router_id'] p = self.core_plugin._get_plugin_from_router_id(context, router_id) if self.validators.get(p.plugin_type()) != v: err_msg = _('Router & subnet should belong to the same plugin ' 'as the VPN service') raise nsx_exc.NsxVpnValidationError(details=err_msg) return v.validate_vpnservice(context, vpnservice)
def _validate_vnic_type_direct_passthrough_for_network(self, context, network_id, plugin_type): supported_network_types = SUPPORTED_V_NETWORK_TYPES if plugin_type == projectpluginmap.NsxPlugins.NSX_T: supported_network_types = SUPPORTED_T_NETWORK_TYPES if not self._validate_network_type(context, network_id, supported_network_types): msg_info = { 'vnic_types': VNIC_TYPES_DIRECT_PASSTHROUGH, 'networks': supported_network_types} err_msg = _("%(vnic_types)s port vnic-types are only supported " "for ports on networks of types " "%(networks)s") % msg_info raise exceptions.InvalidInput(error_message=err_msg)
def _get_monitor_policy_client(self, hm): lb_client = self.core_plugin.nsxpolicy.load_balancer if hm['type'] == lb_const.LB_HEALTH_MONITOR_TCP: return lb_client.lb_monitor_profile_tcp elif hm['type'] == lb_const.LB_HEALTH_MONITOR_HTTP: return lb_client.lb_monitor_profile_http elif hm['type'] == lb_const.LB_HEALTH_MONITOR_HTTPS: return lb_client.lb_monitor_profile_https elif hm['type'] == lb_const.LB_HEALTH_MONITOR_PING: return lb_client.lb_monitor_profile_icmp else: msg = (_('Cannot create health monitor %(monitor)s with ' 'type %(type)s') % { 'monitor': hm['id'], 'type': hm['type'] }) raise n_exc.InvalidInput(error_message=msg)
def remove_router_interface(self, context, router_id, interface_info): # If a loadbalancer is attached to this Edge appliance, we cannot # detach the subnet from the exclusive router. subnet = interface_info.get('subnet_id') if not subnet and interface_info.get('port_id'): port = self.plugin.get_port(context, interface_info['port_id']) port_subnets = [ fixed_ip['subnet_id'] for fixed_ip in port.get('fixed_ips', []) ] subnet = port_subnets[0] if subnet and self._check_lb_on_subnet(context, subnet): error = _('Cannot delete router interface while loadbalancers are ' 'provisioned on attached subnet') raise nsxv_exc.NsxPluginException(err_msg=error) info = super(nsx_v.NsxVPluginV2, self.plugin).remove_router_interface( context, router_id, interface_info) router_db = self.plugin._get_router(context, router_id) subnet = self.plugin.get_subnet(context, info['subnet_id']) network_id = subnet['network_id'] with locking.LockManager.get_lock( self._get_router_edge_id(context, router_id)): if router_db.gw_port and router_db.enable_snat: # First update nat rules self.plugin._update_nat_rules(context, router_db) ports = self.plugin._get_router_interface_ports_by_network( context, router_id, network_id) self.plugin._update_subnets_and_dnat_firewall(context, router_db) # No subnet on the network connects to the edge vnic if not ports: edge_utils.delete_interface(self.nsx_v, context, router_id, network_id, dist=False) else: address_groups = self.plugin._get_address_groups( context, router_id, network_id) edge_utils.update_internal_interface(self.nsx_v, context, router_id, network_id, address_groups) return info
def get_nat_config(self, edge_id): if edge_id not in self._edges: raise Exception(_("Edge %s does not exist") % edge_id) edge = self._edges[edge_id] rules = edge['nat_rules'] if rules is None: rules = { 'rules': { 'natRulesDtos': [] }, 'version': 1 } header = { 'status': 200 } rules['version'] = 1 return (header, rules)
def update(self, context, old_listener, new_listener, completor, certificate=None): nsxlib_lb = self.core_plugin.nsxlib.load_balancer vs_client = nsxlib_lb.virtual_server app_client = nsxlib_lb.application_profile vs_name = None tags = None if new_listener['name'] != old_listener['name']: vs_name = utils.get_name_and_uuid( new_listener['name'] or 'listener', new_listener['id']) tags = self._get_listener_tags(context, new_listener) binding = nsx_db.get_nsx_lbaas_listener_binding( context.session, old_listener['loadbalancer_id'], old_listener['id']) if not binding: msg = (_('Cannot find listener %(listener)s binding on NSX ' 'backend'), { 'listener': old_listener['id'] }) raise n_exc.BadRequest(resource='lbaas-listener', msg=msg) try: vs_id = binding['lb_vs_id'] app_profile_id = binding['app_profile_id'] updated_kwargs = self._get_virtual_server_kwargs( context, new_listener, vs_name, tags, app_profile_id, certificate) vs_client.update(vs_id, **updated_kwargs) if vs_name: app_client.update(app_profile_id, display_name=vs_name, tags=tags) completor(success=True) except Exception as e: with excutils.save_and_reraise_exception(): completor(success=False) LOG.error( 'Failed to update listener %(listener)s with ' 'error %(error)s', { 'listener': old_listener['id'], 'error': e })
def validate_ipsec_site_connection(self, context, ipsec_site_conn): if not ipsec_site_conn.get('tenant_id'): # nothing we can do here. return v = self._get_validator_for_project(ipsec_site_conn['tenant_id']) # first make sure the plugin is the same as the one of the vpnservice srv_id = ipsec_site_conn.get('vpnservice_id') srv = self.vpn_plugin._get_vpnservice(context, srv_id) srv_validator = self._get_validator_for_project(srv['tenant_id']) if v != srv_validator: err_msg = _('VPN service should belong to the same plugin ' 'as the connection') raise nsx_exc.NsxVpnValidationError(details=err_msg) return v.validate_ipsec_site_connection(context, ipsec_site_conn)
def add_vip_as_secondary_ip(vcns, edge_id, vip): """ Edge appliance requires that a VIP will be configured as a primary or a secondary IP address on an interface. To do so, we locate an interface which is connected to the same subnet that vip belongs to. This can be a regular interface, on a sub-interface on a trunk. """ if not vip_as_secondary_ip(vcns, edge_id, vip, add_address_to_address_groups): msg = _('Failed to add VIP %(vip)s as secondary IP on ' 'Edge %(edge_id)s') % { 'vip': vip, 'edge_id': edge_id } raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
def create(self, context, pol): # find out the edge to be updated, by the listener of this policy lb_id = pol.listener.loadbalancer_id lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding( context.session, lb_id) if not lb_binding: msg = _('No suitable Edge found for listener %s') % pol.listener_id raise n_exc.BadRequest(resource='edge-lbaas', msg=msg) edge_id = lb_binding['edge_id'] app_rule = policy_to_application_rule(pol) app_rule_id = None try: with locking.LockManager.get_lock(edge_id): # create the backend application rule for this policy h = (self.vcns.create_app_rule(edge_id, app_rule))[0] app_rule_id = lb_common.extract_resource_id(h['location']) # add the nsx application rule (neutron policy) to the nsx # virtual server (neutron listener) vse_id = self._get_vse_id(context, pol) if vse_id: self._add_app_rule_to_virtual_server( edge_id, vse_id, app_rule_id, pol.position) except Exception as e: with excutils.save_and_reraise_exception(): self.lbv2_driver.l7policy.failed_completion(context, pol) LOG.error( 'Failed to create L7policy on edge %(edge)s: ' '%(err)s', { 'edge': edge_id, 'err': e }) if app_rule_id: # Failed to add the rule to the vip: delete the rule # from the backend. try: self.vcns.delete_app_rule(edge_id, app_rule_id) except Exception: pass # save the nsx application rule id in the DB nsxv_db.add_nsxv_lbaas_l7policy_binding(context.session, pol.id, edge_id, app_rule_id) # complete the transaction self.lbv2_driver.l7policy.successful_completion(context, pol)
def convert_lbaas_app_profile(name, sess_persist, protocol): """ Create app profile dict for lbaas VIP. Neutron-lbaas VIP objects breaks into an application profile object, and a virtual server object in NSXv. """ vcns_app_profile = { 'insertXForwardedFor': False, 'name': name, 'serverSslEnabled': False, 'sslPassthrough': False, 'template': protocol, } # Since SSL Termination is not supported right now, so just use # sslPassthrough method if the protocol is HTTPS. if protocol == lb_const.LB_PROTOCOL_HTTPS: vcns_app_profile['sslPassthrough'] = True if sess_persist: persist_type = sess_persist.get('type') if persist_type: # If protocol is not HTTP, only source_ip is supported if (protocol != lb_const.LB_PROTOCOL_HTTP and persist_type != lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP): msg = (_('Invalid %(protocol)s persistence method: %(type)s') % { 'protocol': protocol, 'type': persist_type }) raise n_exc.BadRequest(resource='edge-lbaas', msg=msg) persistence = { 'method': lb_const.SESSION_PERSISTENCE_METHOD_MAP.get(persist_type) } if persist_type in lb_const.SESSION_PERSISTENCE_COOKIE_MAP: persistence.update({ 'cookieName': sess_persist.get('cookie_name', 'default_cookie_name'), 'cookieMode': lb_const.SESSION_PERSISTENCE_COOKIE_MAP[persist_type] }) vcns_app_profile['persistence'] = persistence return vcns_app_profile