def update_port(context, id, port): """Update values of a port. : param context: neutron api request context : param id: UUID representing the port to update. : param port: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. """ LOG.info("update_port %s for tenant %s" % (id, context.tenant_id)) with context.session.begin(): port_db = db_api.port_find(context, id=id, scope=db_api.ONE) if not port_db: raise exceptions.PortNotFound(port_id=id) address_pairs = [] fixed_ips = port["port"].pop("fixed_ips", None) if fixed_ips: ipam_driver = ipam.IPAM_REGISTRY.get_strategy( port_db["network"]["ipam_strategy"]) ipam_driver.deallocate_ip_address( context, port_db, ipam_reuse_after=CONF.QUARK.ipam_reuse_after) addresses = [] for fixed_ip in fixed_ips: subnet_id = fixed_ip.get("subnet_id") ip_address = fixed_ip.get("ip_address") if not (subnet_id and ip_address): raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id and ip_address required") # Note: we don't allow overlapping subnets, thus subnet_id is # ignored. addresses.append(ipam_driver.allocate_ip_address( context, port_db["network_id"], id, CONF.QUARK.ipam_reuse_after, ip_address=ip_address)) port["port"]["addresses"] = addresses mac_address_string = str(netaddr.EUI(port_db.mac_address, dialect=netaddr.mac_unix)) address_pairs = [{'mac_address': mac_address_string, 'ip_address': address.get('address_readable', '')} for address in addresses] group_ids, security_groups = v.make_security_group_list( context, port["port"].pop("security_groups", None)) net_driver = registry.DRIVER_REGISTRY.get_driver( port_db.network["network_plugin"]) net_driver.update_port(context, port_id=port_db.backend_key, security_groups=group_ids, allowed_pairs=address_pairs) port["port"]["security_groups"] = security_groups port = db_api.port_update(context, port_db, **port["port"]) return v._make_port_dict(port)
def update_port(context, id, port): """Update values of a port. : param context: neutron api request context : param id: UUID representing the port to update. : param port: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. """ LOG.info("update_port %s for tenant %s" % (id, context.tenant_id)) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) if not port_db: raise exceptions.PortNotFound(port_id=id) address_pairs = [] fixed_ips = port["port"].pop("fixed_ips", None) if fixed_ips: ipam_driver.deallocate_ip_address( context, port_db, ipam_reuse_after=CONF.QUARK.ipam_reuse_after) addresses = [] for fixed_ip in fixed_ips: subnet_id = fixed_ip.get("subnet_id") ip_address = fixed_ip.get("ip_address") if not (subnet_id and ip_address): raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id and ip_address required") # Note: we don't allow overlapping subnets, thus subnet_id is # ignored. addresses.append( ipam_driver.allocate_ip_address(context, port_db["network_id"], id, CONF.QUARK.ipam_reuse_after, ip_address=ip_address)) port["port"]["addresses"] = addresses mac_address_string = str( netaddr.EUI(port_db.mac_address, dialect=netaddr.mac_unix)) address_pairs = [{ 'mac_address': mac_address_string, 'ip_address': address.get('address_readable', '') } for address in addresses] group_ids, security_groups = v.make_security_group_list( context, port["port"].pop("security_groups", None)) net_driver.update_port(context, port_id=port_db.backend_key, security_groups=group_ids, allowed_pairs=address_pairs) port["port"]["security_groups"] = security_groups port = db_api.port_update(context, port_db, **port["port"]) return v._make_port_dict(port)
def update_port(self, context, id, port): """Update values of a port. : param context: quantum api request context : param id: UUID representing the port to update. : param port: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in quantum/api/v2/attributes.py. """ LOG.info("update_port %s for tenant %s" % (id, context.tenant_id)) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) if not port_db: raise exceptions.PortNotFound(port_id=id) fixed_ips = port["port"].pop("fixed_ips", None) if fixed_ips: addresses = [] for fixed_ip in fixed_ips: subnet_id = fixed_ip.get("subnet_id") ip_address = fixed_ip.get("ip_address") if not (subnet_id and ip_address): raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id and ip_address required") # Note: we don't allow overlapping subnets, thus subnet_id is # ignored. addresses.append(self.ipam_driver.allocate_ip_address( context, port_db["network_id"], id, self.ipam_reuse_after, ip_address=ip_address)) port["port"]["addresses"] = addresses port = db_api.port_update(context, port_db, **port["port"]) return self._make_port_dict(port)
def test_update_port_sets_vlan_tag(self): self.context.session.add = mock.Mock() mock_port = models.Port(id=1, network_id="2", ip_addresses=[], tags=[]) db_api.port_update(self.context, mock_port, vlan_id=1) self.assertEqual(mock_port.tags, [tags.VlanTag().serialize(1)])
def update_port(context, id, port): """Update values of a port. : param context: neutron api request context : param id: UUID representing the port to update. : param port: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. """ LOG.info("update_port %s for tenant %s" % (id, context.tenant_id)) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) if not port_db: raise exceptions.PortNotFound(port_id=id) port_dict = port["port"] fixed_ips = port_dict.pop("fixed_ips", None) admin_only = ["mac_address", "device_owner", "bridge", "admin_state_up", "device_id"] always_filter = ["network_id", "backend_key"] utils.filter_body(context, port_dict, admin_only=admin_only, always_filter=always_filter) # Pre-check the requested fixed_ips before making too many db trips. # Note that this is the only check we need, since this call replaces # the entirety of the IP addresses document if fixed_ips are provided. if fixed_ips: quota.QUOTAS.limit_check(context, context.tenant_id, fixed_ips_per_port=len(fixed_ips)) # TODO(anyone): security groups are not currently supported on port create, # nor on isolated networks today. Please see RM8615 new_security_groups = utils.pop_param(port_dict, "security_groups") if new_security_groups is not None: if not STRATEGY.is_parent_network(port_db["network_id"]): raise q_exc.TenantNetworkSecurityGroupsNotImplemented() if new_security_groups is not None and not port_db["device_id"]: raise q_exc.SecurityGroupsRequireDevice() group_ids, security_group_mods = _make_security_group_list( context, new_security_groups) quota.QUOTAS.limit_check(context, context.tenant_id, security_groups_per_port=len(group_ids)) if fixed_ips is not None: # NOTE(mdietz): we want full control over IPAM since # we're allocating by subnet instead of # network. ipam_driver = ipam.IPAM_REGISTRY.get_strategy( ipam.QuarkIpamANY.get_name()) addresses, subnet_ids = [], [] ip_addresses = {} for fixed_ip in fixed_ips: subnet_id = fixed_ip.get("subnet_id") ip_address = fixed_ip.get("ip_address") if not (subnet_id or ip_address): raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id or ip_address required") if ip_address and not subnet_id: raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id required for ip_address allocation") if subnet_id and ip_address: ip_netaddr = netaddr.IPAddress(ip_address).ipv6() ip_addresses[ip_netaddr] = subnet_id else: subnet_ids.append(subnet_id) port_ips = set([netaddr.IPAddress(int(a["address"])) for a in port_db["ip_addresses"]]) new_ips = set([a for a in ip_addresses.keys()]) ips_to_allocate = list(new_ips - port_ips) ips_to_deallocate = list(port_ips - new_ips) for ip in ips_to_allocate: if ip in ip_addresses: # NOTE: Fix for RM10187 - we were losing the list of IPs if # more than one IP was to be allocated. Track an # aggregate list instead, and add it to the running total # after each allocate allocated = [] ipam_driver.allocate_ip_address( context, allocated, port_db["network_id"], port_db["id"], reuse_after=None, ip_addresses=[ip], subnets=[ip_addresses[ip]]) addresses.extend(allocated) for ip in ips_to_deallocate: ipam_driver.deallocate_ips_by_port( context, port_db, ip_address=ip) for subnet_id in subnet_ids: ipam_driver.allocate_ip_address( context, addresses, port_db["network_id"], port_db["id"], reuse_after=CONF.QUARK.ipam_reuse_after, subnets=[subnet_id]) # Need to return all existing addresses and the new ones if addresses: port_dict["addresses"] = port_db["ip_addresses"] port_dict["addresses"].extend(addresses) net_driver = registry.DRIVER_REGISTRY.get_driver( port_db.network["network_plugin"]) # TODO(anyone): What do we want to have happen here if this fails? Is it # ok to continue to keep the IPs but fail to apply security # groups? Is there a clean way to have a multi-status? Since # we're in a beta-y status, I'm going to let this sit for # a future patch where we have time to solve it well. kwargs = {} if new_security_groups is not None: kwargs["security_groups"] = security_group_mods net_driver.update_port(context, port_id=port_db["backend_key"], mac_address=port_db["mac_address"], device_id=port_db["device_id"], **kwargs) port_dict["security_groups"] = security_group_mods with context.session.begin(): port = db_api.port_update(context, port_db, **port_dict) # NOTE(mdietz): fix for issue 112, we wanted the IPs to be in # allocated_at order, so get a fresh object every time if port_db in context.session: context.session.expunge(port_db) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) return v._make_port_dict(port_db)
def update_port(context, id, port): """Update values of a port. : param context: neutron api request context : param id: UUID representing the port to update. : param port: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. """ LOG.info("update_port %s for tenant %s" % (id, context.tenant_id)) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) if not port_db: raise exceptions.PortNotFound(port_id=id) fixed_ips = port["port"].pop("fixed_ips", None) if fixed_ips is not None: # NOTE(mdietz): we want full control over IPAM since # we're allocating by subnet instead of # network. ipam_driver = ipam.IPAM_REGISTRY.get_strategy( ipam.QuarkIpamANY.get_name()) addresses, subnet_ids = [], [] ip_addresses = {} for fixed_ip in fixed_ips: subnet_id = fixed_ip.get("subnet_id") ip_address = fixed_ip.get("ip_address") if not (subnet_id or ip_address): raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id or ip_address required") if ip_address and not subnet_id: raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id required for ip_address allocation") if subnet_id and ip_address: ip_netaddr = netaddr.IPAddress(ip_address).ipv6() ip_addresses[ip_netaddr] = subnet_id else: subnet_ids.append(subnet_id) port_ips = set([netaddr.IPAddress(int(a["address"])) for a in port_db["ip_addresses"]]) new_ips = set([a for a in ip_addresses.keys()]) ips_to_allocate = list(new_ips - port_ips) ips_to_deallocate = list(port_ips - new_ips) for ip in ips_to_allocate: if ip in ip_addresses: ipam_driver.allocate_ip_address( context, addresses, port_db["network_id"], port_db["id"], reuse_after=None, ip_address=ip, subnets=[ip_addresses[ip]]) for ip in ips_to_deallocate: ipam_driver.deallocate_ips_by_port( context, port_db, ip_address=ip) for subnet_id in subnet_ids: ipam_driver.allocate_ip_address( context, addresses, port_db["network_id"], port_db["id"], reuse_after=CONF.QUARK.ipam_reuse_after, subnets=[subnet_id]) # Need to return all existing addresses and the new ones if addresses: port["port"]["addresses"] = port_db["ip_addresses"] port["port"]["addresses"].extend(addresses) group_ids, security_groups = v.make_security_group_list( context, port["port"].pop("security_groups", None)) net_driver = registry.DRIVER_REGISTRY.get_driver( port_db.network["network_plugin"]) net_driver.update_port(context, port_id=port_db.backend_key, security_groups=group_ids) port["port"]["security_groups"] = security_groups with context.session.begin(): port = db_api.port_update(context, port_db, **port["port"]) # NOTE(mdietz): fix for issue 112, we wanted the IPs to be in # allocated_at order, so get a fresh object every time if port_db in context.session: context.session.expunge(port_db) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) return v._make_port_dict(port_db)
def update_port(context, id, port): """Update values of a port. : param context: neutron api request context : param id: UUID representing the port to update. : param port: dictionary with keys indicating fields to update. valid keys are those that have a value of True for 'allow_put' as listed in the RESOURCE_ATTRIBUTE_MAP object in neutron/api/v2/attributes.py. """ LOG.info("update_port %s for tenant %s" % (id, context.tenant_id)) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) if not port_db: raise exceptions.PortNotFound(port_id=id) port_dict = port["port"] fixed_ips = port_dict.pop("fixed_ips", None) admin_only = [ "mac_address", "device_owner", "bridge", "admin_state_up", "device_id" ] always_filter = ["network_id", "backend_key"] utils.filter_body(context, port_dict, admin_only=admin_only, always_filter=always_filter) if fixed_ips is not None: # NOTE(mdietz): we want full control over IPAM since # we're allocating by subnet instead of # network. ipam_driver = ipam.IPAM_REGISTRY.get_strategy( ipam.QuarkIpamANY.get_name()) addresses, subnet_ids = [], [] ip_addresses = {} for fixed_ip in fixed_ips: subnet_id = fixed_ip.get("subnet_id") ip_address = fixed_ip.get("ip_address") if not (subnet_id or ip_address): raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id or ip_address required") if ip_address and not subnet_id: raise exceptions.BadRequest( resource="fixed_ips", msg="subnet_id required for ip_address allocation") if subnet_id and ip_address: ip_netaddr = netaddr.IPAddress(ip_address).ipv6() ip_addresses[ip_netaddr] = subnet_id else: subnet_ids.append(subnet_id) port_ips = set([ netaddr.IPAddress(int(a["address"])) for a in port_db["ip_addresses"] ]) new_ips = set([a for a in ip_addresses.keys()]) ips_to_allocate = list(new_ips - port_ips) ips_to_deallocate = list(port_ips - new_ips) for ip in ips_to_allocate: if ip in ip_addresses: ipam_driver.allocate_ip_address(context, addresses, port_db["network_id"], port_db["id"], reuse_after=None, ip_address=ip, subnets=[ip_addresses[ip]]) for ip in ips_to_deallocate: ipam_driver.deallocate_ips_by_port(context, port_db, ip_address=ip) for subnet_id in subnet_ids: ipam_driver.allocate_ip_address( context, addresses, port_db["network_id"], port_db["id"], reuse_after=CONF.QUARK.ipam_reuse_after, subnets=[subnet_id]) # Need to return all existing addresses and the new ones if addresses: port_dict["addresses"] = port_db["ip_addresses"] port_dict["addresses"].extend(addresses) group_ids, security_groups = v.make_security_group_list( context, port_dict.pop("security_groups", None)) net_driver = registry.DRIVER_REGISTRY.get_driver( port_db.network["network_plugin"]) net_driver.update_port(context, port_id=port_db.backend_key, security_groups=group_ids) port_dict["security_groups"] = security_groups with context.session.begin(): port = db_api.port_update(context, port_db, **port_dict) # NOTE(mdietz): fix for issue 112, we wanted the IPs to be in # allocated_at order, so get a fresh object every time if port_db in context.session: context.session.expunge(port_db) port_db = db_api.port_find(context, id=id, scope=db_api.ONE) return v._make_port_dict(port_db)