38 KiB
Ironic Neutron Integration
https://bugs.launchpad.net/ironic/+bug/1526403
The current Ironic implementation only supports flat networks. For isolation of tenant networks Ironic should be able to pass information to Neutron to allow for provisioning of the baremetal server onto the tenant network.
Problem description
Ironic currently provisions servers only on flat networks hence providing no network isolation between tenants. Ironic should allow end users to utilize a baremetal instance in the same isolated (e.g. VLAN, VXLAN) networks as their virtual machines are.
In order to provide the required network isolation, Ironic should be able to provide the requisite connectivity information (using LLDP) to the Neutron ML2 plugin to allow drivers to provision the top-of-rack (ToR) switch for the baremetal server.
Ironic also poses new challenges for Neutron, for example, the concepts of link aggregation and multiple networks per node. This spec covers the concept of link aggregation where multiple interfaces on the bare metal server connect to switch ports of a single LAG and belong to the same network. However,this spec does not cover:
- the case of trunked ports belonging to multiple networks - this will need a separate spec and implementation in Neutron, see vlan-aware-vms.
- the case where the bare metal server has multiple interfaces that belong to different networks. This may require the capability to specify which NICs belong to which network. It is in scope but the method of deciding which interface gets which network will be decided elsewhere.
Proposed change
When nodes are enrolled/introspected in Ironic, local link (e.g. LLDP) information should be recorded for each port. The option of creating a portgroup to specify an aggregation of said ports should be made available.
Ironic should then send the local link information to Neutron in the form of a port binding profile. For each portgroup, the port binding profile will contain a list of the local link information for each port in that portgroup. For each port not belonging to a portgroup, the port binding profile will contain only the local link information for that particular port. Therefore the length of the list of local link information can be used by Neutron to determine whether to plumb the network for a single port or for a portgroup (in the case of a portgroup there may be additional switch configurations necessary to manage the associated LAG). Each port binding profile sent to the Neutron port create API will result in the creation of a single Neutron port. In this way, each portgroup can represent a LAG for which all member switch ports will belong to the same network and to the same network segment.
The node should first be placed on a provisioning network and then onto the tenant network as specified in the network-provider spec. To help facilitate this there will be a variable stored in the binding profile to record whether a port binding has been requested. This will allow Ironic to defer binding until Ironic is able to populate the extra information that is required by Neutron.
Note also, there will be no support for PXE booting after deploy (i.e. local disk installation only). The reason for this is because the nodes will not be able to PXE boot if they cannot reach the TFTP server. Local boot will need to be used for any node deployed outside of the provisioning network. Instance netboot should not be permitted when this feature is used. This limitation could be addressed if routing was set up from every tenant network to the TFTP server or if Ironic would work with a TFTP server per tenant network, but these options are out of scope in this spec.
Note
It may be possible for virtual media drivers to support both netboot and localboot when provisioning/tenant networks are isolated. This is because virtual media drivers boot the bare metal using out of band means using BMC and hence bare metal server's NICs don't require to access Ironic conductor when booting the instance.
A supportive ML2 driver can then use the information supplied to provision the port.
The Ironic port object will be updated with a new local_link_connection field dict supplying the following values:
- switch_id
- port_id
- switch_info
These fields are in string format. The information could be gathered by using LLDP based on the LLDP TLV counterparts of chassis_id, port_id and system_name, although it is not strictly required to populate these fields with LLDP values. For example, the switch_id field is used to identify a switch and could be an LLDP based MAC address or an OpenFlow based datapath_id. The switch_info field could be used to distinguish different switch models or some other vendor specific identifier. The switch_id and port_id fields are required and the switch_info field can be optionally populated. The key point is that Ironic and Neutron should share the same understanding of this information in order to connect the Ironic instance to the appropriate Neutron network.
To facilitate link aggregation a new portgroup object will be created. In addition to the base object it will have the following fields:
- id
- uuid
- name
- node_id
- address
- extra
- internal_info
- standalone_ports_supported
The 'address' field represents the MAC address for bonded NICs of the bare metal server. The 'extra' field can be used to hold any additional information that operators or developers want to store in the portgroup. The 'internal_info' field is used to store internal metadata. This field is read-only. The 'standalone_ports_supported' indicates whether ports that are members of this portgroup can be used as stand-alone ports.
The Ironic port object will then have the following fields added to support new functionality:
- local_link_connection
- portgroup_id
- pxe_enabled
If there are multiple pxe_enabled ports or portgroups, dhcpboot options will be set for all portgroups and all pxe_enabled ports not belonging to any portgroup.
The following port binding related information needs to be passed to Neutron:
Field Name | Description |
---|---|
vnic_type | Type of the profile ('baremetal' in this case). This would allow at least basic filtering for Ironic ports by ML2 drivers. |
local_link_information | A list of local link connection information either from all Ironic ports in a particular portgroup or from a single Ironic port not belonging to any portgroup. |
host_id | This should be set to the Ironic node uuid. |
A JSON example to describe the structure is:
- {"port":
-
- {
-
<all other fields>,
"vnic_type": "baremetal",
"host_id": <Ironic node UUID>,
"binding:profile": {
- "local_link_information": [
-
- {
-
"switch_id": xxx,
"port_id": xxx,
"switch_info": zzz,
<optional more information>
},
- {
-
"switch_id": xxx,
"port_id": yyy,
"switch_info": zzz,
<optional more information>
} ]
<some more profile fields>
}
}
}
Alternatives
The current model of prescribing flat networks could be maintained with the same flat network being used for everything. This is not so much an alternative to the proposal in this spec, but rather staying with the existing solution.
Data model impact
The proposed change will be to add the following fields to the port object with their data type and default value for migrations:
Field Name | Field Type | Migration Value |
---|---|---|
local_link_connection | dict_or_none | None |
portgroup_id | int_or_none | None |
pxe_enabled | bool | True |
All existing ports will have pxe_enabled
set to
true
so that the current behavior is not changed. The
portgroup relationship is a 1:n relationship with the port.
The portgroup object is proposed with the following fields and data types:
Field Name | Field Type |
---|---|
id | int |
uuid | str |
name | str_or_none |
node_id | int_or_none |
address | str |
extra | dict_or_none |
internal_info | dict_or_none |
standalone_ports_supported | bool |
created_at | datetime_or_str_or_none |
updated_at | datetime_or_str_or_none |
State Machine Impact
The state machine will not be directly impacted, however, changes to the new portgroup object and additions of portgroups will only be allowed when a node is in a particular set of states.
Change to port membership of a portgroup can be made when the node is in a MANAGEABLE/INSPECTING/ENROLL state. Any port updates that update local_link_connection or pxe_enabled can only be made when the node is in a MANAGEABLE/INSPECTING/ENROLL state. The reason for limiting to these states is because updating these new port attributes should result in an update of local_link_information in the binding_profile, which would trigger an update in Neutron. It might be safest to only allow this when the node is not in a state where uninterrupted connectivity is expected. These limitations will also ensure that Neutron port updates should only happen during a state change and not automatically with any port-update call.
REST API impact
The following port API methods will be affected:
/v1/ports
Retrieve a list of ports.
Method type GET.
The http response code(s) are unchanged. An additional reason for the 404 error http response code would be if the portgroup resource is specified but is not found.
New parameter can be included:
portgroup (uuid_or_name)
- UUID or logical name of a portgroup to only get ports for that portgroup.
Body:
- None
Response:
- JSON schema definition of Port
/v1/ports/(port_uuid)
Retrieve information about the given port.
Method type GET.
The http response code(s) are unchanged.
Parameter:
port_uuid (uuid)
- UUID of the port.
Body:
- None
Response:
- JSON schema definition of Port
/v1/ports
Create a new port.
Method type POST.
The http response code(s) are unchanged.
Parameter:
- None
Body:
- JSON schema definition of Port
Response:
- JSON schema definition of Port
/v1/ports/(port_uuid)
Update an existing port.
Method type PATCH.
The http response code(s) are unchanged.
Parameter:
port_uuid (uuid)
- UUID of the port.
Body:
- JSON schema definition of PortPatch
Response:
- JSON schema definition of Port
- JSON schema definition of Port (data sample):
{
"address": "fe:54:00:77:07:d9",
"created_at": "2015-05-12T10:00:00.529243+00:00",
"extra": {
"foo": "bar",
},
"links": [
{
"href": "http://localhost:6385/v1/ports/
1004e542-2f9f-4d9b-b8b9-5b719fa6613f",
"rel": "self"
},
{
"href": "http://localhost:6385/ports/
1004e542-2f9f-4d9b-b8b9-5b719fa6613f",
"rel": "bookmark"
}
],
"node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd",
"updated_at": "2015-05-15T09:04:12.011844+00:00",
"uuid": "1004e542-2f9f-4d9b-b8b9-5b719fa6613f",
"local_link_connection": {
"swwitch_id": "0a:1b:2c:3d:4e:5f",
"port_id": "Ethernet3/1",
"switch_info": "switch1",
},
"portgroup_uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"pxe_enabled": true
}
- JSON schema definition of PortPatch would be a subset of JSON schema of Port.
The following API methods will be added in support of the new portgroup model:
/v1/portgroups
Retrieve a list of portgroups.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax (e.g. if address is not mac-address format)
- 404 for resource (e.g. node) not found
Parameters:
node (uuid_or_name)
- UUID or name of a node, to only get portgroups for that node.address (macaddress)
- MAC address of a portgroup, to only get portgroup which has this MAC address.marker (uuid)
- pagination marker for large data sets.limit (int)
- maximum number of resources to return in a single result.sort_key (unicode)
- column to sort results by. Default: id.sort_dir (unicode)
- direction to sort. "asc" or "desc". Default: asc.
Body:
- None
Response:
- JSON schema definition of PortgroupCollection
/v1/portgroups/(portgroup_ident)
Retrieve information about the given portgroup.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. portgroup) not found
Parameters:
portgroup_ident (uuid_or_name)
- UUID or logical name of a portgroup.
Body:
- None
Response:
- JSON schema definition of Portgroup
/v1/portgroups
Create a new portgroup.
Method type POST.
Normal http response code will be 201.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 409 for resource conflict (e.g. if portgroup name already exists because the name should be unique)
Parameters:
- None
Body:
- JSON schema definition of Portgroup
Response:
- JSON schema definition of Portgroup
/v1/portgroups/(portgroup_ident)
Delete a portgroup.
Method type DELETE.
Normal http response code will be 204.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. portgroup) not found
Parameters:
portgroup_ident (uuid_or_name)
- UUID or logical name of a portgroup.
Body:
- None
Response:
- N/A
/v1/portgroups/(portgroup_ident)
Update an existing portgroup.
Method type PATCH.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. portgroup) not found
- 409 for resource conflict (e.g. if portgroup name already exists because the name should be unique)
Parameters:
portgroup_ident (uuid_or_name)
- UUID or logical name of a portgroup.
Body:
- JSON schema definition of PortgroupPatch
Response:
- JSON schema definition of Portgroup
/v1/portgroups/detail
Retrieve a list of portgroups with detail. The additional 'detail' option would return all fields, whereas without it only a subset of fields would be returned, namely uuid and address.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. node) not found
Parameters:
node (uuid_or_name)
- UUID or name of a node, to only get portgroups for that node.address (macaddress)
- MAC address of a portgroup, to only get portgroup which has this MAC address.marker (uuid)
- pagination marker for large data sets.limit (int)
- maximum number of resources to return in a single result.sort_key (unicode)
- column to sort results by. Default: id.sort_dir (unicode)
- direction to sort. "asc" or "desc". Default: asc.
Body:
- None
Response:
- JSON schema definition of PortgroupCollection with detail.
/v1/nodes/(node_ident)/portgroups
Retrieve a list of portgroups for node.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. node) not found
Parameters:
node_ident (uuid_or_name)
- UUID or logical name of a node.
Body:
- None
Response:
- JSON schema definition of PortgroupCollection.
/v1/nodes/(node_ident)/portgroups/detail
Retrieve a list of portgroups with detail for node.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. node) not found
Parameters:
node_ident (uuid_or_name)
- UUID or logical name of a node.
Body:
- None
Response:
- JSON schema definition of PortgroupCollection with detail.
/v1/portgroups/(portgroup_ident)/ports
Retrieve a list of ports for portgroup.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. portgroup) not found
Parameters:
portgroup_ident (uuid_or_name)
- UUID or logical name of a portgroup.
Body:
- None
Response:
- JSON schema definition of PortCollection.
/v1/portgroups/(portgroup_ident)/ports/detail
Retrieve a list of ports with detail for portgroup.
Method type GET.
Normal http response code will be 200.
Expected error http response code(s):
- 400 for bad query or malformed syntax
- 404 for resource (e.g. portgroup) not found
Parameters:
portgroup_ident (uuid_or_name)
- UUID or logical name of a portgroup.
Body:
- None
Response:
- JSON schema definition of PortCollection with detail.
- JSON schema definition of Portgroup (data sample):
{
"address": "fe:54:00:77:07:d9",
"created_at": "2015-05-12T10:10:00.529243+00:00",
"extra": {
"foo": "bar",
},
"internal_info": {},
"links": [
{
"href": "http://localhost:6385/v1/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"rel": "self"
},
{
"href": "http://localhost:6385/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"rel": "bookmark"
}
],
"node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd",
"standalone_ports_supported": true,
"updated_at": "2015-05-15T09:04:12.011844+00:00",
"uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"name": "node1_portgroup1"
}
- JSON schema definition of PortgroupCollection:
{
"portgroups": [
{
"address": "fe:54:00:77:07:d9",
"links": [
{
"href": "http://localhost:6385/v1/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"rel": "self"
},
{
"href": "http://localhost:6385/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"rel": "bookmark"
}
],
"name": "node1_portgroup1",
"uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4"
}
]
}
- JSON schema definition of PortgroupCollection with detail:
{
"portgroups": [
{
"address": "fe:54:00:77:07:d9",
"created_at": "2016-08-18T22:28:48.165105+00:00",
"extra": {},
"internal_info": {},
"links": [
{
"href": "http://127.0.0.1:6385/v1/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"rel": "self"
},
{
"href": "http://127.0.0.1:6385/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4",
"rel": "bookmark"
}
],
"name": "node1_portgroup1",
"node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd",
"ports": [
{
"href": "http://127.0.0.1:6385/v1/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4/ports",
"rel": "self"
},
{
"href": "http://127.0.0.1:6385/portgroups/
6eb02b44-18a3-4659-8c0b-8d2802581ae4/ports",
"rel": "bookmark"
}
],
"standalone_ports_supported": true,
"updated_at": "2016-11-04T17:46:09+00:00",
"uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4"
}
]
}
- JSON schema definition of PortgroupPatch would be a subset of JSON schema of Portgroup.
Does the API microversion need to increment?
- Yes.
Example use case including typical API samples for both data supplied by the caller and the response.
Example of port create.
- Data supplied:
{ "address": "fe:54:00:77:07:d9", "node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd", "local_link_connection": { "switch_id": "0a:1b:2c:3d:4e:5f", "port_id": "Ethernet3/1", "switch_info": "switch1", }, "pxe_enabled": true }
- Response 201 with body:
{ "address": "fe:54:00:77:07:d9", "node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd", "local_link_connection": { "switch_id": "0a:1b:2c:3d:4e:5f", "port_id": "Ethernet3/1", "switch_info": "switch1", }, "pxe_enabled": true "created_at": "2015-05-12T10:00:00.529243+00:00", "extra": { }, "links": [ { "href": "http://localhost:6385/v1/ports/ 1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "rel": "self" }, { "href": "http://localhost:6385/ports/ 1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "rel": "bookmark" } ], "updated_at": null, "uuid": "1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "portgroup_uuid": null, }
Example of portgroup create.
- Data supplied:
{ "address": "fe:54:00:77:07:d9", "node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd", "standalone_ports_supported": true, "name": "node1_portgroup1" }
- Response 201 with body:
{ "address": "fe:54:00:77:07:d9", "node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd", "name": "node1_portgroup1" "created_at": "2015-05-12T10:10:00.529243+00:00", "extra": { }, "internal_info": {}, "links": [ { "href": "http://localhost:6385/v1/portgroups/ 6eb02b44-18a3-4659-8c0b-8d2802581ae4", "rel": "self" }, { "href": "http://localhost:6385/portgroups/ 6eb02b44-18a3-4659-8c0b-8d2802581ae4", "rel": "bookmark" } ], "standalone_ports_supported": true, "updated_at": null, "uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4", }
Example of port update.
- Parameter "port_uuid"="1004e542-2f9f-4d9b-b8b9-5b719fa6613f"
- Data supplied (JSON PATCH syntax where "op" can be add/replace/delete):
[{"path": "/portgroup_uuid", "value": "6eb02b44-18a3-4659-8c0b-8d2802581ae4", "op": "add"}]
- Response 200 with body:
{ "address": "fe:54:00:77:07:d9", "node_uuid": "e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd", "local_link_connection": { "switch_id": "0a:1b:2c:3d:4e:5f", "port_id": "Ethernet3/1", "switch_info": "switch1", }, "pxe_enabled": true "created_at": "2015-05-12T10:00:00.529243+00:00", "extra": { }, "links": [ { "href": "http://localhost:6385/v1/ports/ 1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "rel": "self" }, { "href": "http://localhost:6385/ports/ 1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "rel": "bookmark" } ], "updated_at": "2015-05-12T10:20:00.529243+00:00", "uuid": "1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "portgroup_uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4", }
- Note that the port update API should support updating the portgroup_id of the port object. This will allow operators to migrate existing deployments.
Example of port list.
- Parameter "node_uuid"="e7a6f1e2-7176-4fe8-b8e9-ed71c77d74dd"
- Response 200 with body:
{"ports": [ { "address": "fe:54:00:77:07:d9", "links": [ { "href": "http://localhost:6385/v1/ports/ 1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "rel": "self" }, { "href": "http://localhost:6385/ports/ 1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "rel": "bookmark" } ], "uuid": "1004e542-2f9f-4d9b-b8b9-5b719fa6613f", "portgroup_uuid": "6eb02b44-18a3-4659-8c0b-8d2802581ae4", } ]}
- Note that portgroup_uuid is now returned in the response.
Discuss any policy changes, and discuss what things a deployer needs to think about when defining their policy.
- Ironic has an admin-only policy so policy definitions should not be a concern.
- A deployer should be aware of the capabilities of the particular ML2 driver for supporting use of the new local_link_information that will be passed to it via the binding_profile.
Is a corresponding change in the client library and CLI necessary?
- The client library and CLI should be updated to support the new APIs.
Is this change discoverable by clients? Not all clients will upgrade at the same time, so this change must work with older clients without breaking them.
- The changes to the API will be backward-compatible so older clients will still continue to work as-is.
Client (CLI) impact
The python-ironicclient and OSC would need updated to support the new portgroups APIs.
Example usage of the new methods:
For ports, the CLI would support port creation with new optional parameters specifying the new port attributes (local_link_connection, portgroup_id and pxe_enabled) and would also support update of these attributes. As examples:
"ironic" CLI:
- ironic port-create -a <address> -n <node> [-e <key=value>] [--local-link-connection <local_link_connection>] [--portgroup-uuid <portgroup_uuid>] [--pxe-enabled <pxe_enabled>]
- ironic port-update port_uuid replace portgroup_uuid=<portgroup_uuid>
- ironic port-list [--detail] [--address <mac-address>] [--portgroup-uuid <portgroup_uuid>]
"openstack baremetal" CLI:
- openstack baremetal port create --node <node> [--local-link-connection <key=value>] [--portgroup-uuid <portgroup_uuid>] [--pxe-enabled <boolean>] <address>
- openstack baremetal port set [--portgroup-uuid <portgroup_uuid>] <port>
- openstack baremetal port list --address <mac-address>] [--node <node>] [--portgroup-uuid <portgroup_uuid>]
For portgroups, the CLI would support the following new methods:
"ironic" CLI:
ironic portgroup-create --node <node> [--name <portgroupname>] [--address <mac-address>] [-e <key=value>]
ironic portgroup-delete <portgroup_uuid>
ironic portgroup-list [--detail] [--node <node>] [--address <mac-address>] [--limit <limit>] [--marker <portgroup_uuid] [--sort-key <field>] [--sort-dir <direction>]
ironic portgroup-show [--address] <id>
- <id> is the UUID of the portgroup (or MAC address if --address is specified)
ironic portgroup-update <portgroup_uuid> <op> <path=value> [<path=value> ... ]
- <op> is add, remove or replace.
- <path=value> is the attribute to add, remove or replace. Can be specified multiple times. For 'remove' only <path> is necessary.
Note: Even though the ironic CLI includes 'ironic node-port-list', we are NOT going to provide a corresponding 'ironic node-portgroup-list'. Rather, the list of portgroups of a node will be available via ironic portgroup-list --node.
"openstack baremetal" CLI:
- openstack baremetal portgroup create --node <uuid> [--name NAME] [--extra <key=value>] [--support-standalone-ports | --unsupport-standalone-ports] <address>
- openstack baremetal portgroup delete <portgroup> [<portgroup> ...]
- openstack baremetal portgroup list [--marker <portgroup>] [--address <mac-address>] [--node <node>] [--sort <key>[:<direction>]] [--long | --fields <field> [<field> ...]]
- openstack baremetal portgroup show [--address] [--fields <field> [<field> ...]] <portgroup>
- openstack baremetal portgroup set [--address] [--name NAME] [--node <uuid>] [--extra <key=value>] [--support-standalone-ports | --unsupport-standalone-ports] [--fields <field> [<field> ...]] <portgroup>
- openstack baremetal portgroup unset [--name] [--extra <key>] [--node <uuid>] <portgroup>
- To add ports to a portgroup, the portgroup should first be created and then port_update or port create called.
The python-ironicclient would also need the Port detailed resource extended to include the new port attributes.
RPC API impact
No impact on existing API calls.
New RPC API calls would be needed:
- update_portgroup
- destroy_portgroup
These new API calls will use call(). As for the existing API call for update_port, the new API call for update_portgroup should request an update for DHCP if the address field is updated.
To roll this change out to an existing deployment, the ironic-conductor should be upgraded before the ironic-api.
Driver API impact
The NeutronDHCPApi class in ironic/dhcp/neutron
updates
Neutron ports with DHCP options. The vifs are obtained in
ironic/common/network
by extracting
vif_port_id
from the extra
attributes of
Ironic ports. This method should be updated if vifs are bound to
portgroups as well as ports.
The complementary network-provider spec provides details regarding the workflow of the network flip and the point at which the binding profile will be passed to Neutron to bind the port.
Nova driver impact
There will be changes necessary to the Nova driver. Proposed changes are:
To enable the mapping between Neutron ports and Ironic ports and portgroups.
The Ironic Nova driver has methods
macs_for_instance
,dhcp_options_for_instance
,extra_options_for_instance
andplug_vifs
. Currently Nova puts a network on one port at random - see ports cannot be mapped to networks. This bug has high priority and the issue is being addressed. Once addressed, these methods should determine the number of Neutron ports that are created as well as the mapping between Neutron and Ironic ports. These methods should be updated to not only account for Ironic ports but also Ironic portgroups. The selection process would be:- Select all Ironic ports that do not belong to Ironic portgroups (possible if the Ironic port list API returns portgroup_uuid as standard, as suggested in the above section)
- Select all Ironic portgroups
This modified functionality could be implemented using a new config flag in Nova to allow toggling between the old and the new methods. The flag could help de-couple the upgrading of Nova and of Ironic.
Ramdisk impact
N/A
Security impact
The new REST API calls for portgroups should not be usable by the end user. Only operators and administrators should be able to manage portgroups and local_link_connection data of ports, because these settings are used to configure the network. This is satisfied because Ironic is an admin-only API, so there should be no security impact.
Other end user impact
Using the binding profile to enable flipping between provisioning and tenant networks means there will be no support for PXE booting after deploy (i.e. local disk installation only). How to allow operators to deploy instances using either net-boot or local boot using the same Ironic conductor should be discussed in the complementary network-provider spec.
Scalability impact
There will be more API calls made to Ironic in order to create and use portgroups but impact on scalability should be negligible.
Performance Impact
None.
Other deployer impact
New database columns are added to the port table and a new database table portgroup is introduced, so this will require a database migration.
Deployers will need to deploy an ML2 mechanism driver that supports connecting baremetal resources to Neutron networks.
If using Nova, deployers will need to deploy a version of Nova that supports this feature. Deployers will need to set a flag in the Nova config file to turn this new feature on or off, which would be important when upgrading Nova and Ironic.
Deployers should be aware that automated upgrade or migration for already-provisioned nodes is not supported. Deployers should follow this recommendation for upgrading a node in an existing deployment to use this new feature:
- Upgrade the OpenStack services.
- Update the flag in the Nova config file to turn this feature on.
- Move node into the MANAGEABLE state.
- Update node driver field (see network-provider spec).
- Create Ironic portgroups.
- Update Ironic port membership to portgroups.
- Update Ironic ports with local_link_connection data.
- Move node into the AVAILABLE state.
Developer impact
Neutron ML2 mechanism drivers should support this feature by using the data passed in binding profile to dynamically configure relevant ports and port-channels on the relevant switch(es).
Implementation
Assignee(s)
- laura-moore
- yhvh (Will Stevenson)
- bertiefulton
- sukhdev-8
Work Items
- Extend port table.
- Create the new portgroup table.
- Implement extension to port APIs.
- Implement the new portgroup APIs.
- Implement the extension to the RPC API.
- Implement the changes to the Nova driver to get and use the binding profile.
- Implement the changes needed to get vifs for updating Neutron port DHCP options.
- Implement tests for the new functionality.
- Implement updates to the python-ironicclient.
- Update documentation.
Dependencies
Network flip is dependent on network-provider spec.
VLAN provisioning on switch(es) is dependent on ML2 driver functionality being developed to support this feature.
Testing
Existing default behaviour will be tested in the gate by default.
New tests will need to be written to test the new APIs and database updates.
Simulation of connecting real hardware to real switches for testing purposes is described in network-provider spec.
Upgrades and Backwards Compatibility
Default behavior is the current behavior, so this change should be fully backwards compatible.
Documentation Impact
This feature will be fully documented.
References
Discussions on the topic include:
- https://etherpad.openstack.org/p/YVR-neutron-ironic
- https://etherpad.openstack.org/p/liberty-ironic-network-isolation
- Logs from https://wiki.openstack.org/wiki/Meetings/Ironic-neutron
- The network provider spec enabling the network flip between provisioning and tenant network: https://review.openstack.org/#/c/187829