Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    device_id = port_attrs["device_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)

    if not STRATEGY.is_parent_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context, network_id=[net_id],
                                           tenant_id=[context.tenant_id])

        quota.QUOTAS.limit_check(
            context, context.tenant_id,
            ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
    net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))

    addresses = []
    mac = None
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:
        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac):
            if fixed_ips:
                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")
                    ipam_driver.allocate_ip_address(
                        context, addresses, net["id"], port_id,
                        CONF.QUARK.ipam_reuse_after, segment_id=segment_id,
                        ip_address=ip_address, subnets=[subnet_id],
                        mac_address=mac)
            else:
                ipam_driver.allocate_ip_address(
                    context, addresses, net["id"], port_id,
                    CONF.QUARK.ipam_reuse_after, segment_id=segment_id,
                    mac_address=mac)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(context, address)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net, port_id, mac_address):
            mac = ipam_driver.allocate_mac_address(
                context, net["id"], port_id, CONF.QUARK.ipam_reuse_after,
                mac_address=mac_address)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(context,
                                                           mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id):
            backend_port = net_driver.create_port(context, net["id"],
                                                  port_id=port_id,
                                                  security_groups=group_ids,
                                                  device_id=device_id)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port):
            LOG.info("Rolling back backend port...")
            try:
                net_driver.delete_port(context, backend_port["uuid"])
            except Exception:
                LOG.exception(
                    "Couldn't rollback backend port %s" % backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(
                    context, addresses=addresses, mac_address=mac["address"],
                    backend_key=backend_port["uuid"], **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception(
                    "Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net, port_id, mac_address)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
Beispiel #4
0
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)
Beispiel #5
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    addresses = []

    with context.session.begin():
        port_id = uuidutils.generate_uuid()

        net = db_api.network_find(context, id=net_id, segment_id=segment_id, scope=db_api.ONE)
        if not net:
            # Maybe it's a tenant network
            net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
            if not net:
                raise exceptions.NetworkNotFound(net_id=net_id)

        if not STRATEGY.is_parent_network(net_id):
            quota.QUOTAS.limit_check(context, context.tenant_id, ports_per_network=len(net.get("ports", [])) + 1)

        ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
        if fixed_ips:
            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")
                addresses.extend(
                    ipam_driver.allocate_ip_address(
                        context, net["id"], port_id, CONF.QUARK.ipam_reuse_after, ip_address=ip_address
                    )
                )
        else:
            addresses.extend(ipam_driver.allocate_ip_address(context, net["id"], port_id, CONF.QUARK.ipam_reuse_after))

        group_ids, security_groups = v.make_security_group_list(context, port["port"].pop("security_groups", None))
        mac = ipam_driver.allocate_mac_address(
            context, net["id"], port_id, CONF.QUARK.ipam_reuse_after, mac_address=mac_address
        )
        mac_address_string = str(netaddr.EUI(mac["address"], dialect=netaddr.mac_unix))
        address_pairs = [
            {"mac_address": mac_address_string, "ip_address": address.get("address_readable", "")}
            for address in addresses
        ]
        net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
        backend_port = net_driver.create_port(
            context, net["id"], port_id=port_id, security_groups=group_ids, allowed_pairs=address_pairs
        )

        port_attrs["network_id"] = net["id"]
        port_attrs["id"] = port_id
        port_attrs["security_groups"] = security_groups

        LOG.info("Including extra plugin attrs: %s" % backend_port)
        port_attrs.update(backend_port)
        new_port = db_api.port_create(
            context, addresses=addresses, mac_address=mac["address"], backend_key=backend_port["uuid"], **port_attrs
        )

        # Include any driver specific bits
    return v._make_port_dict(new_port)
Beispiel #6
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    addresses = []

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context,
                              id=net_id,
                              shared=True,
                              segment_id=segment_id,
                              scope=db_api.ONE)
    if not net:
        # Maybe it's a tenant network
        net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

    quota.QUOTAS.limit_check(context,
                             context.tenant_id,
                             ports_per_network=len(net.get('ports', [])) + 1)

    if fixed_ips:
        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")
            addresses.append(
                ipam_driver.allocate_ip_address(context,
                                                net["id"],
                                                port_id,
                                                CONF.QUARK.ipam_reuse_after,
                                                ip_address=ip_address))
    else:
        addresses.append(
            ipam_driver.allocate_ip_address(context, net["id"], port_id,
                                            CONF.QUARK.ipam_reuse_after))

    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))
    mac = ipam_driver.allocate_mac_address(context,
                                           net["id"],
                                           port_id,
                                           CONF.QUARK.ipam_reuse_after,
                                           mac_address=mac_address)
    mac_address_string = str(
        netaddr.EUI(mac['address'], dialect=netaddr.mac_unix))
    address_pairs = [{
        'mac_address': mac_address_string,
        'ip_address': address.get('address_readable', '')
    } for address in addresses]
    backend_port = net_driver.create_port(context,
                                          net["id"],
                                          port_id=port_id,
                                          security_groups=group_ids,
                                          allowed_pairs=address_pairs)

    port_attrs["network_id"] = net["id"]
    port_attrs["id"] = port_id
    port_attrs["security_groups"] = security_groups
    new_port = db_api.port_create(context,
                                  addresses=addresses,
                                  mac_address=mac["address"],
                                  backend_key=backend_port["uuid"],
                                  **port_attrs)
    return v._make_port_dict(new_port)
Beispiel #7
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    addresses = []

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, id=net_id, shared=True,
                              segment_id=segment_id, scope=db_api.ONE)
    if not net:
        # Maybe it's a tenant network
        net = db_api.network_find(context, id=net_id, scope=db_api.ONE)
        if not net:
            raise exceptions.NetworkNotFound(net_id=net_id)

    quota.QUOTAS.limit_check(
        context, context.tenant_id,
        ports_per_network=len(net.get('ports', [])) + 1)

    if fixed_ips:
        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")
            addresses.append(ipam_driver.allocate_ip_address(
                context, net["id"], port_id, CONF.QUARK.ipam_reuse_after,
                ip_address=ip_address))
    else:
        addresses.append(ipam_driver.allocate_ip_address(
            context, net["id"], port_id, CONF.QUARK.ipam_reuse_after))

    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))
    mac = ipam_driver.allocate_mac_address(context, net["id"], port_id,
                                           CONF.QUARK.ipam_reuse_after,
                                           mac_address=mac_address)
    mac_address_string = str(netaddr.EUI(mac['address'],
                                         dialect=netaddr.mac_unix))
    address_pairs = [{'mac_address': mac_address_string,
                      'ip_address': address.get('address_readable', '')}
                     for address in addresses]
    backend_port = net_driver.create_port(context, net["id"], port_id=port_id,
                                          security_groups=group_ids,
                                          allowed_pairs=address_pairs)

    port_attrs["network_id"] = net["id"]
    port_attrs["id"] = port_id
    port_attrs["security_groups"] = security_groups
    new_port = db_api.port_create(
        context, addresses=addresses, mac_address=mac["address"],
        backend_key=backend_port["uuid"], **port_attrs)
    return v._make_port_dict(new_port)
Beispiel #8
0
def create_port(context, port):
    """Create a port

    Create a port which is a connection point of a device (e.g., a VM
    NIC) to attach to a L2 Neutron network.
    : param context: neutron api request context
    : param port: dictionary describing the port, with keys
        as listed in the RESOURCE_ATTRIBUTE_MAP object in
        neutron/api/v2/attributes.py.  All keys will be populated.
    """
    LOG.info("create_port for tenant %s" % context.tenant_id)
    port_attrs = port["port"]

    admin_only = ["mac_address", "device_owner", "bridge", "admin_state_up"]
    utils.filter_body(context, port_attrs, admin_only=admin_only)

    port_attrs = port["port"]
    mac_address = utils.pop_param(port_attrs, "mac_address", None)
    segment_id = utils.pop_param(port_attrs, "segment_id")
    fixed_ips = utils.pop_param(port_attrs, "fixed_ips")
    net_id = port_attrs["network_id"]
    device_id = port_attrs["device_id"]

    port_id = uuidutils.generate_uuid()

    net = db_api.network_find(context, id=net_id, scope=db_api.ONE)

    if not net:
        raise exceptions.NetworkNotFound(net_id=net_id)

    # NOTE (Perkins): If a device_id is given, try to prevent multiple ports
    # from being created for a device already attached to the network
    if device_id:
        existing_ports = db_api.port_find(context,
                                          network_id=net_id,
                                          device_id=device_id,
                                          scope=db_api.ONE)
        if existing_ports:
            raise exceptions.BadRequest(
                resource="port",
                msg="This device is already connected to the "
                "requested network via another port")

    if not STRATEGY.is_parent_network(net_id):
        # We don't honor segmented networks when they aren't "shared"
        segment_id = None
        port_count = db_api.port_count_all(context,
                                           network_id=[net_id],
                                           tenant_id=[context.tenant_id])

        quota.QUOTAS.limit_check(context,
                                 context.tenant_id,
                                 ports_per_network=port_count + 1)
    else:
        if not segment_id:
            raise q_exc.AmbiguousNetworkId(net_id=net_id)

    ipam_driver = ipam.IPAM_REGISTRY.get_strategy(net["ipam_strategy"])
    net_driver = registry.DRIVER_REGISTRY.get_driver(net["network_plugin"])
    group_ids, security_groups = v.make_security_group_list(
        context, port["port"].pop("security_groups", None))

    addresses = []
    mac = None
    backend_port = None

    with utils.CommandManager().execute() as cmd_mgr:

        @cmd_mgr.do
        def _allocate_ips(fixed_ips, net, port_id, segment_id, mac):
            if fixed_ips:
                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")
                    ipam_driver.allocate_ip_address(
                        context,
                        addresses,
                        net["id"],
                        port_id,
                        CONF.QUARK.ipam_reuse_after,
                        segment_id=segment_id,
                        ip_address=ip_address,
                        subnets=[subnet_id],
                        mac_address=mac)
            else:
                ipam_driver.allocate_ip_address(context,
                                                addresses,
                                                net["id"],
                                                port_id,
                                                CONF.QUARK.ipam_reuse_after,
                                                segment_id=segment_id,
                                                mac_address=mac)

        @cmd_mgr.undo
        def _allocate_ips_undo(addr):
            LOG.info("Rolling back IP addresses...")
            if addresses:
                for address in addresses:
                    try:
                        with context.session.begin():
                            ipam_driver.deallocate_ip_address(context, address)
                    except Exception:
                        LOG.exception("Couldn't release IP %s" % address)

        @cmd_mgr.do
        def _allocate_mac(net, port_id, mac_address):
            mac = ipam_driver.allocate_mac_address(context,
                                                   net["id"],
                                                   port_id,
                                                   CONF.QUARK.ipam_reuse_after,
                                                   mac_address=mac_address)
            return mac

        @cmd_mgr.undo
        def _allocate_mac_undo(mac):
            LOG.info("Rolling back MAC address...")
            if mac:
                try:
                    with context.session.begin():
                        ipam_driver.deallocate_mac_address(
                            context, mac["address"])
                except Exception:
                    LOG.exception("Couldn't release MAC %s" % mac)

        @cmd_mgr.do
        def _allocate_backend_port(mac, addresses, net, port_id):
            backend_port = net_driver.create_port(context,
                                                  net["id"],
                                                  port_id=port_id,
                                                  security_groups=group_ids,
                                                  device_id=device_id)
            return backend_port

        @cmd_mgr.undo
        def _allocate_back_port_undo(backend_port):
            LOG.info("Rolling back backend port...")
            try:
                net_driver.delete_port(context, backend_port["uuid"])
            except Exception:
                LOG.exception("Couldn't rollback backend port %s" %
                              backend_port)

        @cmd_mgr.do
        def _allocate_db_port(port_attrs, backend_port, addresses, mac):
            port_attrs["network_id"] = net["id"]
            port_attrs["id"] = port_id
            port_attrs["security_groups"] = security_groups

            LOG.info("Including extra plugin attrs: %s" % backend_port)
            port_attrs.update(backend_port)
            with context.session.begin():
                new_port = db_api.port_create(context,
                                              addresses=addresses,
                                              mac_address=mac["address"],
                                              backend_key=backend_port["uuid"],
                                              **port_attrs)

            return new_port

        @cmd_mgr.undo
        def _allocate_db_port_undo(new_port):
            LOG.info("Rolling back database port...")
            if not new_port:
                return
            try:
                with context.session.begin():
                    db_api.port_delete(context, new_port)
            except Exception:
                LOG.exception("Couldn't rollback db port %s" % backend_port)

        # addresses, mac, backend_port, new_port
        mac = _allocate_mac(net, port_id, mac_address)
        _allocate_ips(fixed_ips, net, port_id, segment_id, mac)
        backend_port = _allocate_backend_port(mac, addresses, net, port_id)
        new_port = _allocate_db_port(port_attrs, backend_port, addresses, mac)

    return v._make_port_dict(new_port)
Beispiel #9
0
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)