1362 lines
38 KiB
ReStructuredText
1362 lines
38 KiB
ReStructuredText
..
|
|
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
|
License.
|
|
|
|
http://creativecommons.org/licenses/by/3.0/legalcode
|
|
|
|
==================================================
|
|
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
|
|
<https://blueprints.launchpad.net/neutron/+spec/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
|
|
<https://blueprints.launchpad.net/ironic/+spec/network-provider>`_. 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
|
|
<https://blueprints.launchpad.net/ironic/+spec/network-provider>`_ 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`` and
|
|
``plug_vifs``. Currently Nova puts a network on one port at random - see
|
|
`ports cannot be mapped to networks
|
|
<https://bugs.launchpad.net/ironic/+bug/1405131>`_. 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
|
|
|
|
.. NOTE: This section was not present at the time this spec was approved.
|
|
|
|
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
|
|
<https://blueprints.launchpad.net/ironic/+spec/network-provider>`_.
|
|
|
|
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
|
|
<https://blueprints.launchpad.net/ironic/+spec/network-provider>`_).
|
|
|
|
* 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
|
|
<https://blueprints.launchpad.net/ironic/+spec/network-provider>`_.
|
|
|
|
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
|
|
<https://blueprints.launchpad.net/ironic/+spec/network-provider>`_.
|
|
|
|
|
|
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
|