Merge "Add network_data
field to ironic node object"
This commit is contained in:
commit
ff8a0c71b0
@ -442,6 +442,7 @@ Response
|
||||
- allocation_uuid: allocation_uuid
|
||||
- retired: retired
|
||||
- retired_reason: retired_reason
|
||||
- network_data: network_data
|
||||
|
||||
**Example detailed list of Nodes:**
|
||||
|
||||
@ -491,6 +492,9 @@ only the specified set.
|
||||
.. versionadded:: 1.65
|
||||
Introduced the ``lessee`` field.
|
||||
|
||||
.. versionadded:: 1.66
|
||||
Introduced the ``network_data`` field.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
Error codes: 400,403,404,406
|
||||
|
@ -1012,6 +1012,13 @@ name:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
network_data:
|
||||
description: |
|
||||
Static network configuration for the node to eventually pass to node's
|
||||
operating system.
|
||||
in: body
|
||||
required: false
|
||||
type: JSON
|
||||
network_interface:
|
||||
description: |
|
||||
Which Network Interface provider to use when plumbing the network
|
||||
|
@ -38,6 +38,7 @@
|
||||
"maintenance_reason": null,
|
||||
"management_interface": null,
|
||||
"name": "test_node_classic",
|
||||
"network_data": {},
|
||||
"network_interface": "flat",
|
||||
"owner": null,
|
||||
"portgroups": [
|
||||
|
@ -41,6 +41,7 @@
|
||||
"maintenance_reason": null,
|
||||
"management_interface": null,
|
||||
"name": "test_node_classic",
|
||||
"network_data": {},
|
||||
"network_interface": "flat",
|
||||
"owner": null,
|
||||
"portgroups": [
|
||||
|
@ -42,6 +42,7 @@
|
||||
"maintenance_reason": "Replacing the hard drive",
|
||||
"management_interface": null,
|
||||
"name": "test_node_classic",
|
||||
"network_data": {},
|
||||
"network_interface": "flat",
|
||||
"owner": null,
|
||||
"portgroups": [
|
||||
|
@ -43,6 +43,7 @@
|
||||
"maintenance_reason": null,
|
||||
"management_interface": null,
|
||||
"name": "test_node_classic",
|
||||
"network_data": {},
|
||||
"network_interface": "flat",
|
||||
"owner": "john doe",
|
||||
"portgroups": [
|
||||
@ -148,6 +149,7 @@
|
||||
"maintenance_reason": null,
|
||||
"management_interface": "ipmitool",
|
||||
"name": "test_node_dynamic",
|
||||
"network_data": {},
|
||||
"network_interface": "flat",
|
||||
"owner": "43e61ec9-8e42-4dcb-bc45-30d66aa93e5b",
|
||||
"portgroups": [
|
||||
|
@ -2,6 +2,13 @@
|
||||
REST API Version History
|
||||
========================
|
||||
|
||||
1.66 (Victoria, master)
|
||||
-----------------------
|
||||
|
||||
Add ``network_data`` field to the node object, that will be used by
|
||||
stand-alone ironic to pass L3 network configuration information to
|
||||
ramdisk.
|
||||
|
||||
1.65 (Ussuri, 15.0)
|
||||
---------------------
|
||||
|
||||
|
580
ironic/api/controllers/v1/network-data-schema.json
Normal file
580
ironic/api/controllers/v1/network-data-schema.json
Normal file
@ -0,0 +1,580 @@
|
||||
{
|
||||
"$schema": "http://openstack.org/nova/network_data.json#",
|
||||
"id": "http://openstack.org/nova/network_data.json",
|
||||
"type": "object",
|
||||
"title": "OpenStack Nova network metadata schema",
|
||||
"description": "Schema of Nova instance network configuration information",
|
||||
"required": [
|
||||
"links",
|
||||
"networks",
|
||||
"services"
|
||||
],
|
||||
"properties": {
|
||||
"links": {
|
||||
"$id": "#/properties/links",
|
||||
"type": "array",
|
||||
"title": "L2 interfaces settings",
|
||||
"items": {
|
||||
"$id": "#/properties/links/items",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/l2_link"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/l2_bond"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/l2_vlan"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"networks": {
|
||||
"$id": "#/properties/networks",
|
||||
"type": "array",
|
||||
"title": "L3 networks",
|
||||
"items": {
|
||||
"$id": "#/properties/networks/items",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/l3_ipv4_network"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/l3_ipv6_network"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"$ref": "#/definitions/services"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"l2_address": {
|
||||
"$id": "#/definitions/l2_address",
|
||||
"type": "string",
|
||||
"pattern": "(?i)^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$",
|
||||
"title": "L2 interface address",
|
||||
"examples": [
|
||||
"fa:16:3e:9c:bf:3d"
|
||||
]
|
||||
},
|
||||
"l2_id": {
|
||||
"$id": "#/definitions/l2_id",
|
||||
"type": "string",
|
||||
"title": "L2 interface ID",
|
||||
"examples": [
|
||||
"eth0"
|
||||
]
|
||||
},
|
||||
"l2_mtu": {
|
||||
"$id": "#/definitions/l2_mtu",
|
||||
"title": "L2 interface MTU",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"examples": [
|
||||
1500
|
||||
]
|
||||
},
|
||||
"l2_vif_id": {
|
||||
"$id": "#/definitions/l2_vif_id",
|
||||
"type": "string",
|
||||
"title": "Virtual interface ID",
|
||||
"examples": [
|
||||
"cd9f6d46-4a3a-43ab-a466-994af9db96fc"
|
||||
]
|
||||
},
|
||||
"l2_link": {
|
||||
"$id": "#/definitions/l2_link",
|
||||
"type": "object",
|
||||
"title": "L2 interface configuration settings",
|
||||
"required": [
|
||||
"ethernet_mac_address",
|
||||
"id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/l2_id"
|
||||
},
|
||||
"ethernet_mac_address": {
|
||||
"$ref": "#/definitions/l2_address"
|
||||
},
|
||||
"mtu": {
|
||||
"$ref": "#/definitions/l2_mtu"
|
||||
},
|
||||
"type": {
|
||||
"$id": "#/definitions/l2_link/properties/type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"bridge",
|
||||
"dvs",
|
||||
"hw_veb",
|
||||
"hyperv",
|
||||
"ovs",
|
||||
"tap",
|
||||
"vhostuser",
|
||||
"vif",
|
||||
"phy"
|
||||
],
|
||||
"title": "Interface type",
|
||||
"examples": [
|
||||
"bridge"
|
||||
]
|
||||
},
|
||||
"vif_id": {
|
||||
"$ref": "#/definitions/l2_vif_id"
|
||||
}
|
||||
}
|
||||
},
|
||||
"l2_bond": {
|
||||
"$id": "#/definitions/l2_bond",
|
||||
"type": "object",
|
||||
"title": "L2 bonding interface configuration settings",
|
||||
"required": [
|
||||
"ethernet_mac_address",
|
||||
"id",
|
||||
"type",
|
||||
"bond_mode",
|
||||
"bond_links"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/l2_id"
|
||||
},
|
||||
"ethernet_mac_address": {
|
||||
"$ref": "#/definitions/l2_address"
|
||||
},
|
||||
"mtu": {
|
||||
"$ref": "#/definitions/l2_mtu"
|
||||
},
|
||||
"type": {
|
||||
"$id": "#/definitions/l2_bond/properties/type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"bond"
|
||||
],
|
||||
"title": "Interface type",
|
||||
"examples": [
|
||||
"bond"
|
||||
]
|
||||
},
|
||||
"vif_id": {
|
||||
"$ref": "#/definitions/l2_vif_id"
|
||||
},
|
||||
"bond_mode": {
|
||||
"$id": "#/definitions/bond/properties/bond_mode",
|
||||
"type": "string",
|
||||
"title": "Port bonding type",
|
||||
"enum": [
|
||||
"802.1ad",
|
||||
"balance-rr",
|
||||
"active-backup",
|
||||
"balance-xor",
|
||||
"broadcast",
|
||||
"balance-tlb",
|
||||
"balance-alb"
|
||||
],
|
||||
"examples": [
|
||||
"802.1ad"
|
||||
]
|
||||
},
|
||||
"bond_links": {
|
||||
"$id": "#/definitions/bond/properties/bond_links",
|
||||
"type": "array",
|
||||
"title": "Port bonding links",
|
||||
"items": {
|
||||
"$id": "#/definitions/bond/properties/bond_links/items",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"l2_vlan": {
|
||||
"$id": "#/definitions/l2_vlan",
|
||||
"type": "object",
|
||||
"title": "L2 VLAN interface configuration settings",
|
||||
"required": [
|
||||
"vlan_mac_address",
|
||||
"id",
|
||||
"type",
|
||||
"vlan_link",
|
||||
"vlan_id"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/l2_id"
|
||||
},
|
||||
"vlan_mac_address": {
|
||||
"$ref": "#/definitions/l2_address"
|
||||
},
|
||||
"mtu": {
|
||||
"$ref": "#/definitions/l2_mtu"
|
||||
},
|
||||
"type": {
|
||||
"$id": "#/definitions/l2_vlan/properties/type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"vlan"
|
||||
],
|
||||
"title": "VLAN interface type",
|
||||
"examples": [
|
||||
"vlan"
|
||||
]
|
||||
},
|
||||
"vif_id": {
|
||||
"$ref": "#/definitions/l2_vif_id"
|
||||
},
|
||||
"vlan_id": {
|
||||
"$id": "#/definitions/l2_vlan/properties/vlan_id",
|
||||
"type": "integer",
|
||||
"title": "VLAN ID"
|
||||
},
|
||||
"vlan_link": {
|
||||
"$id": "#/definitions/l2_vlan/properties/vlan_link",
|
||||
"type": "string",
|
||||
"title": "VLAN link name"
|
||||
}
|
||||
}
|
||||
},
|
||||
"l3_id": {
|
||||
"$id": "#/definitions/l3_id",
|
||||
"type": "string",
|
||||
"title": "Network name",
|
||||
"examples": [
|
||||
"network0"
|
||||
]
|
||||
},
|
||||
"l3_link": {
|
||||
"$id": "#/definitions/l3_link",
|
||||
"type": "string",
|
||||
"title": "L2 network link to use for L3 interface",
|
||||
"examples": [
|
||||
"99e88329-f20d-4741-9593-25bf07847b16"
|
||||
]
|
||||
},
|
||||
"l3_network_id": {
|
||||
"$id": "#/definitions/l3_network_id",
|
||||
"type": "string",
|
||||
"title": "Network ID",
|
||||
"examples": [
|
||||
"99e88329-f20d-4741-9593-25bf07847b16"
|
||||
]
|
||||
},
|
||||
"l3_ipv4_type": {
|
||||
"$id": "#/definitions/l3_ipv4_type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ipv4",
|
||||
"ipv4_dhcp"
|
||||
],
|
||||
"title": "L3 IPv4 network type",
|
||||
"examples": [
|
||||
"ipv4_dhcp"
|
||||
]
|
||||
},
|
||||
"l3_ipv6_type": {
|
||||
"$id": "#/definitions/l3_ipv6_type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ipv6",
|
||||
"ipv6_dhcp",
|
||||
"ipv6_slaac"
|
||||
],
|
||||
"title": "L3 IPv6 network type",
|
||||
"examples": [
|
||||
"ipv6_dhcp"
|
||||
]
|
||||
},
|
||||
"l3_ipv4_host": {
|
||||
"$id": "#/definitions/l3_ipv4_host",
|
||||
"type": "string",
|
||||
"pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
|
||||
"title": "L3 IPv4 host address",
|
||||
"examples": [
|
||||
"192.168.81.99"
|
||||
]
|
||||
},
|
||||
"l3_ipv6_host": {
|
||||
"$id": "#/definitions/l3_ipv6_host",
|
||||
"type": "string",
|
||||
"pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(/[0-9]{1,2})?$",
|
||||
"title": "L3 IPv6 host address",
|
||||
"examples": [
|
||||
"2001:db8:3:4::192.168.81.99"
|
||||
]
|
||||
},
|
||||
"l3_ipv4_netmask": {
|
||||
"$id": "#/definitions/l3_ipv4_netmask",
|
||||
"type": "string",
|
||||
"pattern": "^(254|252|248|240|224|192|128|0)\\.0\\.0\\.0|255\\.(254|252|248|240|224|192|128|0)\\.0\\.0|255\\.255\\.(254|252|248|240|224|192|128|0)\\.0|255\\.255\\.255\\.(254|252|248|240|224|192|128|0)$",
|
||||
"title": "L3 IPv4 network mask",
|
||||
"examples": [
|
||||
"255.255.252.0"
|
||||
]
|
||||
},
|
||||
"l3_ipv6_netmask": {
|
||||
"$id": "#/definitions/l3_ipv6_netmask",
|
||||
"type": "string",
|
||||
"pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7})|(::))$",
|
||||
"title": "L3 IPv6 network mask",
|
||||
"examples": [
|
||||
"ffff:ffff:ffff:ffff::"
|
||||
]
|
||||
},
|
||||
"l3_ipv4_nw": {
|
||||
"$id": "#/definitions/l3_ipv4_nw",
|
||||
"type": "string",
|
||||
"pattern": "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$",
|
||||
"title": "L3 IPv4 network address",
|
||||
"examples": [
|
||||
"0.0.0.0"
|
||||
]
|
||||
},
|
||||
"l3_ipv6_nw": {
|
||||
"$id": "#/definitions/l3_ipv6_nw",
|
||||
"type": "string",
|
||||
"pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7})|(::))$",
|
||||
"title": "L3 IPv6 network address",
|
||||
"examples": [
|
||||
"8000::"
|
||||
]
|
||||
},
|
||||
"l3_ipv4_gateway": {
|
||||
"$id": "#/definitions/l3_ipv4_gateway",
|
||||
"type": "string",
|
||||
"pattern": "^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",
|
||||
"title": "L3 IPv4 gateway address",
|
||||
"examples": [
|
||||
"192.168.200.1"
|
||||
]
|
||||
},
|
||||
"l3_ipv6_gateway": {
|
||||
"$id": "#/definitions/l3_ipv6_gateway",
|
||||
"type": "string",
|
||||
"pattern": "^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$",
|
||||
"title": "L3 IPv6 gateway address",
|
||||
"examples": [
|
||||
"2001:db8:3:4::192.168.81.99"
|
||||
]
|
||||
},
|
||||
"l3_ipv4_network_route": {
|
||||
"$id": "#/definitions/l3_ipv4_network_route",
|
||||
"type": "object",
|
||||
"title": "L3 IPv4 routing configuration item",
|
||||
"required": [
|
||||
"gateway",
|
||||
"netmask",
|
||||
"network"
|
||||
],
|
||||
"properties": {
|
||||
"network": {
|
||||
"$ref": "#/definitions/l3_ipv4_nw"
|
||||
},
|
||||
"netmask": {
|
||||
"$ref": "#/definitions/l3_ipv4_netmask"
|
||||
},
|
||||
"gateway": {
|
||||
"$ref": "#/definitions/l3_ipv4_gateway"
|
||||
},
|
||||
"services": {
|
||||
"$ref": "#/definitions/ipv4_services"
|
||||
}
|
||||
}
|
||||
},
|
||||
"l3_ipv6_network_route": {
|
||||
"$id": "#/definitions/l3_ipv6_network_route",
|
||||
"type": "object",
|
||||
"title": "L3 IPv6 routing configuration item",
|
||||
"required": [
|
||||
"gateway",
|
||||
"netmask",
|
||||
"network"
|
||||
],
|
||||
"properties": {
|
||||
"network": {
|
||||
"$ref": "#/definitions/l3_ipv6_nw"
|
||||
},
|
||||
"netmask": {
|
||||
"$ref": "#/definitions/l3_ipv6_netmask"
|
||||
},
|
||||
"gateway": {
|
||||
"$ref": "#/definitions/l3_ipv6_gateway"
|
||||
},
|
||||
"services": {
|
||||
"$ref": "#/definitions/ipv6_services"
|
||||
}
|
||||
}
|
||||
},
|
||||
"l3_ipv4_network": {
|
||||
"$id": "#/definitions/l3_ipv4_network",
|
||||
"type": "object",
|
||||
"title": "L3 IPv4 network configuration",
|
||||
"required": [
|
||||
"id",
|
||||
"link",
|
||||
"network_id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/l3_id"
|
||||
},
|
||||
"link": {
|
||||
"$ref": "#/definitions/l3_link"
|
||||
},
|
||||
"network_id": {
|
||||
"$ref": "#/definitions/l3_network_id"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "#/definitions/l3_ipv4_type"
|
||||
},
|
||||
"ip_address": {
|
||||
"$ref": "#/definitions/l3_ipv4_host"
|
||||
},
|
||||
"netmask": {
|
||||
"$ref": "#/definitions/l3_ipv4_netmask"
|
||||
},
|
||||
"routes": {
|
||||
"$id": "#/definitions/l3_ipv4_network/routes",
|
||||
"type": "array",
|
||||
"title": "L3 IPv4 network routes",
|
||||
"items": {
|
||||
"$ref": "#/definitions/l3_ipv4_network_route"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"l3_ipv6_network": {
|
||||
"$id": "#/definitions/l3_ipv6_network",
|
||||
"type": "object",
|
||||
"title": "L3 IPv6 network configuration",
|
||||
"required": [
|
||||
"id",
|
||||
"link",
|
||||
"network_id",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/l3_id"
|
||||
},
|
||||
"link": {
|
||||
"$ref": "#/definitions/l3_link"
|
||||
},
|
||||
"network_id": {
|
||||
"$ref": "#/definitions/l3_network_id"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "#/definitions/l3_ipv6_type"
|
||||
},
|
||||
"ip_address": {
|
||||
"$ref": "#/definitions/l3_ipv6_host"
|
||||
},
|
||||
"netmask": {
|
||||
"$ref": "#/definitions/l3_ipv6_netmask"
|
||||
},
|
||||
"routes": {
|
||||
"$id": "#/definitions/properties/l3_ipv6_network/routes",
|
||||
"type": "array",
|
||||
"title": "L3 IPv6 network routes",
|
||||
"items": {
|
||||
"$ref": "#/definitions/l3_ipv6_network_route"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv4_service": {
|
||||
"$id": "#/definitions/ipv4_service",
|
||||
"type": "object",
|
||||
"title": "Service on a IPv4 network",
|
||||
"required": [
|
||||
"address",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "#/definitions/l3_ipv4_host"
|
||||
},
|
||||
"type": {
|
||||
"$id": "#/definitions/ipv4_service/properties/type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dns"
|
||||
],
|
||||
"title": "Service type",
|
||||
"examples": [
|
||||
"dns"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv6_service": {
|
||||
"$id": "#/definitions/ipv6_service",
|
||||
"type": "object",
|
||||
"title": "Service on a IPv6 network",
|
||||
"required": [
|
||||
"address",
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "#/definitions/l3_ipv6_host"
|
||||
},
|
||||
"type": {
|
||||
"$id": "#/definitions/ipv4_service/properties/type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"dns"
|
||||
],
|
||||
"title": "Service type",
|
||||
"examples": [
|
||||
"dns"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ipv4_services": {
|
||||
"$id": "#/definitions/ipv4_services",
|
||||
"type": "array",
|
||||
"title": "Network services on IPv4 network",
|
||||
"items": {
|
||||
"$id": "#/definitions/ipv4_services/items",
|
||||
"$ref": "#/definitions/ipv4_service"
|
||||
}
|
||||
},
|
||||
"ipv6_services": {
|
||||
"$id": "#/definitions/ipv6_services",
|
||||
"type": "array",
|
||||
"title": "Network services on IPv6 network",
|
||||
"items": {
|
||||
"$id": "#/definitions/ipv6_services/items",
|
||||
"$ref": "#/definitions/ipv6_service"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"$id": "#/definitions/services",
|
||||
"type": "array",
|
||||
"title": "Network services",
|
||||
"items": {
|
||||
"$id": "#/definitions/services/items",
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ipv4_service"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/ipv6_service"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -15,9 +15,12 @@
|
||||
|
||||
import datetime
|
||||
from http import client as http_client
|
||||
import json
|
||||
import os
|
||||
|
||||
from ironic_lib import metrics_utils
|
||||
import jsonschema
|
||||
from jsonschema import exceptions as json_schema_exc
|
||||
from oslo_log import log
|
||||
from oslo_utils import strutils
|
||||
from oslo_utils import uuidutils
|
||||
@ -115,6 +118,10 @@ ALLOWED_TARGET_POWER_STATES = (ir_states.POWER_ON,
|
||||
_NODE_DESCRIPTION_MAX_LENGTH = 4096
|
||||
|
||||
|
||||
NETWORK_DATA_SCHEMA = os.path.join(
|
||||
os.path.dirname(__file__), 'network-data-schema.json')
|
||||
|
||||
|
||||
def get_nodes_controller_reserved_names():
|
||||
global _NODES_CONTROLLER_RESERVED_WORDS
|
||||
if _NODES_CONTROLLER_RESERVED_WORDS is None:
|
||||
@ -179,6 +186,28 @@ def update_state_in_older_versions(obj):
|
||||
obj.provision_state = ir_states.INSPECTING
|
||||
|
||||
|
||||
def validate_network_data(network_data):
|
||||
"""Validates node network_data field.
|
||||
|
||||
This method validates network data configuration against JSON
|
||||
schema.
|
||||
|
||||
:param network_data: a network_data field to validate
|
||||
:raises: Invalid if network data is not schema-compliant
|
||||
"""
|
||||
with open(NETWORK_DATA_SCHEMA, 'rb') as fl:
|
||||
network_data_schema = json.load(fl)
|
||||
|
||||
try:
|
||||
jsonschema.validate(network_data, network_data_schema)
|
||||
|
||||
except json_schema_exc.ValidationError as e:
|
||||
# NOTE: Even though e.message is deprecated in general, it is
|
||||
# said in jsonschema documentation to use this still.
|
||||
msg = _("Invalid network_data: %s ") % e.message
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
|
||||
class BootDeviceController(rest.RestController):
|
||||
|
||||
_custom_actions = {
|
||||
@ -1265,6 +1294,9 @@ class Node(base.APIBase):
|
||||
retired_reason = atypes.wsattr(str)
|
||||
"""Indicates the reason for a node's retirement."""
|
||||
|
||||
network_data = atypes.wsattr({str: types.jsontype})
|
||||
"""Static network configuration JSON ironic will hand over to the node."""
|
||||
|
||||
# NOTE(tenbrae): "conductor_affinity" shouldn't be presented on the
|
||||
# API because it's an internal value. Don't add it here.
|
||||
|
||||
@ -1485,7 +1517,9 @@ class Node(base.APIBase):
|
||||
automated_clean=None, protected=False,
|
||||
protected_reason=None, owner=None,
|
||||
allocation_uuid='982ddb5b-bce5-4d23-8fb8-7f710f648cd5',
|
||||
retired=False, retired_reason=None, lessee=None)
|
||||
retired=False, retired_reason=None, lessee=None,
|
||||
network_data={})
|
||||
|
||||
# NOTE(matty_dubs): The chassis_uuid getter() is based on the
|
||||
# _chassis_uuid variable:
|
||||
sample._chassis_uuid = 'edcad704-b2da-41d5-96d9-afd580ecfa12'
|
||||
@ -1746,7 +1780,7 @@ class NodesController(rest.RestController):
|
||||
'instance_info', 'driver_internal_info',
|
||||
'clean_step', 'deploy_step',
|
||||
'raid_config', 'target_raid_config',
|
||||
'traits']
|
||||
'traits', 'network_data']
|
||||
|
||||
_subcontroller_map = {
|
||||
'ports': port.PortsController,
|
||||
@ -2231,6 +2265,9 @@ class NodesController(rest.RestController):
|
||||
msg = _("Allocation UUID cannot be specified, use allocations API")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if node.network_data is not atypes.Unset:
|
||||
validate_network_data(node.network_data)
|
||||
|
||||
# NOTE(tenbrae): get_topic_for checks if node.driver is in the hash
|
||||
# ring and raises NoValidHost if it is not.
|
||||
# We need to ensure that node has a UUID before it can
|
||||
@ -2293,6 +2330,12 @@ class NodesController(rest.RestController):
|
||||
"characters") % _NODE_DESCRIPTION_MAX_LENGTH
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
network_data_fields = api_utils.get_patch_values(
|
||||
patch, '/network_data')
|
||||
|
||||
for network_data in network_data_fields:
|
||||
validate_network_data(network_data)
|
||||
|
||||
def _authorize_patch_and_get_node(self, node_ident, patch):
|
||||
# deal with attribute-specific policy rules
|
||||
policy_checks = []
|
||||
|
@ -491,6 +491,7 @@ VERSIONED_FIELDS = {
|
||||
'retired': versions.MINOR_61_NODE_RETIRED,
|
||||
'retired_reason': versions.MINOR_61_NODE_RETIRED,
|
||||
'lessee': versions.MINOR_65_NODE_LESSEE,
|
||||
'network_data': versions.MINOR_66_NODE_NETWORK_DATA,
|
||||
}
|
||||
|
||||
for field in V31_FIELDS:
|
||||
|
@ -103,6 +103,7 @@ BASE_VERSION = 1
|
||||
# v1.63: Add support for indicators
|
||||
# v1.64: Add network_type to port.local_link_connection
|
||||
# v1.65: Add lessee to the node object.
|
||||
# v1.66: Add support for node network_data field.
|
||||
|
||||
MINOR_0_JUNO = 0
|
||||
MINOR_1_INITIAL_VERSION = 1
|
||||
@ -170,6 +171,7 @@ MINOR_62_AGENT_TOKEN = 62
|
||||
MINOR_63_INDICATORS = 63
|
||||
MINOR_64_LOCAL_LINK_CONNECTION_NETWORK_TYPE = 64
|
||||
MINOR_65_NODE_LESSEE = 65
|
||||
MINOR_66_NODE_NETWORK_DATA = 66
|
||||
|
||||
# When adding another version, update:
|
||||
# - MINOR_MAX_VERSION
|
||||
@ -177,7 +179,7 @@ MINOR_65_NODE_LESSEE = 65
|
||||
# explanation of what changed in the new version
|
||||
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
|
||||
|
||||
MINOR_MAX_VERSION = MINOR_65_NODE_LESSEE
|
||||
MINOR_MAX_VERSION = MINOR_66_NODE_NETWORK_DATA
|
||||
|
||||
# String representations of the minor and maximum versions
|
||||
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
||||
|
@ -231,11 +231,11 @@ RELEASE_MAPPING = {
|
||||
}
|
||||
},
|
||||
'master': {
|
||||
'api': '1.65',
|
||||
'api': '1.66',
|
||||
'rpc': '1.50',
|
||||
'objects': {
|
||||
'Allocation': ['1.1'],
|
||||
'Node': ['1.34'],
|
||||
'Node': ['1.35', '1.34'],
|
||||
'Conductor': ['1.3'],
|
||||
'Chassis': ['1.3'],
|
||||
'DeployTemplate': ['1.1'],
|
||||
|
@ -0,0 +1,30 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Add nodes.network_data field
|
||||
|
||||
Revision ID: cf1a80fdb352
|
||||
Revises: b2ad35726bb0
|
||||
Create Date: 2020-03-20 22:41:14.163881
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'cf1a80fdb352'
|
||||
down_revision = 'b2ad35726bb0'
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.add_column('nodes', sa.Column('network_data', sa.Text(),
|
||||
nullable=True))
|
@ -197,6 +197,7 @@ class Node(Base):
|
||||
retired = Column(Boolean, nullable=True, default=False,
|
||||
server_default=false())
|
||||
retired_reason = Column(Text, nullable=True)
|
||||
network_data = Column(db_types.JsonEncodedDict)
|
||||
storage_interface = Column(String(255), nullable=True)
|
||||
power_interface = Column(String(255), nullable=True)
|
||||
vendor_interface = Column(String(255), nullable=True)
|
||||
|
@ -67,7 +67,6 @@ RESCUE_LIKE_STATES = (states.RESCUING, states.RESCUEWAIT, states.RESCUEFAIL,
|
||||
|
||||
DISK_LAYOUT_PARAMS = ('root_gb', 'swap_mb', 'ephemeral_gb')
|
||||
|
||||
|
||||
# All functions are called from deploy() directly or indirectly.
|
||||
# They are split for stub-out.
|
||||
|
||||
|
@ -75,7 +75,8 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.32: Add description field
|
||||
# Version 1.33: Add retired and retired_reason fields
|
||||
# Version 1.34: Add lessee field
|
||||
VERSION = '1.34'
|
||||
# Version 1.35: Add network_data field
|
||||
VERSION = '1.35'
|
||||
|
||||
dbapi = db_api.get_instance()
|
||||
|
||||
@ -164,6 +165,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
'description': object_fields.StringField(nullable=True),
|
||||
'retired': objects.fields.BooleanField(nullable=True),
|
||||
'retired_reason': object_fields.StringField(nullable=True),
|
||||
'network_data': object_fields.FlexibleDictField(nullable=True),
|
||||
}
|
||||
|
||||
def as_dict(self, secure=False):
|
||||
@ -549,6 +551,21 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
elif self.conductor_group:
|
||||
self.conductor_group = ''
|
||||
|
||||
def _convert_network_data_field(self, target_version,
|
||||
remove_unavailable_fields=True):
|
||||
# NOTE(etingof): The default value for `network_data` is an empty
|
||||
# dict. Therefore we can't use generic version adjustment
|
||||
# routine.
|
||||
field_is_set = self.obj_attr_is_set('network_data')
|
||||
if target_version >= (1, 35):
|
||||
if not field_is_set:
|
||||
self.network_data = {}
|
||||
elif field_is_set:
|
||||
if remove_unavailable_fields:
|
||||
delattr(self, 'network_data')
|
||||
elif self.network_data:
|
||||
self.network_data = {}
|
||||
|
||||
# NOTE (yolanda): new method created to avoid repeating code in
|
||||
# _convert_to_version, and to avoid pep8 too complex error
|
||||
def _adjust_field_to_version(self, field_name, field_default_value,
|
||||
@ -606,6 +623,8 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
should be set to False (or removed).
|
||||
Version 1.34: lessee was added. For versions prior to this, it should
|
||||
be set to None or removed.
|
||||
Version 1.35: network_data was added. For versions prior to this, it
|
||||
should be set to empty dict (or removed).
|
||||
|
||||
:param target_version: the desired version of the object
|
||||
:param remove_unavailable_fields: True to remove fields that are
|
||||
@ -621,6 +640,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
('automated_clean', 28), ('protected_reason', 29),
|
||||
('owner', 30), ('allocation_id', 31), ('description', 32),
|
||||
('retired_reason', 33), ('lessee', 34)]
|
||||
|
||||
for name, minor in fields:
|
||||
self._adjust_field_to_version(name, None, target_version,
|
||||
1, minor, remove_unavailable_fields)
|
||||
@ -637,14 +657,17 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
self._adjust_field_to_version('retired', False, target_version,
|
||||
1, 33, remove_unavailable_fields)
|
||||
|
||||
self._convert_network_data_field(target_version,
|
||||
remove_unavailable_fields)
|
||||
|
||||
|
||||
@base.IronicObjectRegistry.register
|
||||
class NodePayload(notification.NotificationPayloadBase):
|
||||
"""Base class used for all notification payloads about a Node object."""
|
||||
# NOTE: This payload does not include the Node fields "chassis_id",
|
||||
# "driver_info", "driver_internal_info", "instance_info", "raid_config",
|
||||
# "reservation", or "target_raid_config". These were excluded for reasons
|
||||
# including:
|
||||
# "network_data", "reservation", or "target_raid_config". These were
|
||||
# excluded for reasons including:
|
||||
# - increased complexity needed for creating the payload
|
||||
# - sensitive information in the fields that shouldn't be exposed to
|
||||
# external services
|
||||
|
113
ironic/tests/json_samples/network_data.json
Normal file
113
ironic/tests/json_samples/network_data.json
Normal file
@ -0,0 +1,113 @@
|
||||
{
|
||||
"links": [
|
||||
{
|
||||
"id": "interface2",
|
||||
"type": "vif",
|
||||
"ethernet_mac_address": "a0:36:9f:2c:e8:70",
|
||||
"vif_id": "e1c90e9f-eafc-4e2d-8ec9-58b91cebb53d",
|
||||
"mtu": 1500
|
||||
},
|
||||
{
|
||||
"id": "interface0",
|
||||
"type": "phy",
|
||||
"ethernet_mac_address": "a0:36:9f:2c:e8:80",
|
||||
"mtu": 9000
|
||||
},
|
||||
{
|
||||
"id": "interface1",
|
||||
"type": "phy",
|
||||
"ethernet_mac_address": "a0:36:9f:2c:e8:81",
|
||||
"mtu": 9000
|
||||
},
|
||||
{
|
||||
"id": "bond0",
|
||||
"type": "bond",
|
||||
"bond_links": [
|
||||
"interface0",
|
||||
"interface1"
|
||||
],
|
||||
"ethernet_mac_address": "a0:36:9f:2c:e8:82",
|
||||
"bond_mode": "802.1ad",
|
||||
"bond_xmit_hash_policy": "layer3+4",
|
||||
"bond_miimon": 100
|
||||
},
|
||||
{
|
||||
"id": "vlan0",
|
||||
"type": "vlan",
|
||||
"vlan_link": "bond0",
|
||||
"vlan_id": 101,
|
||||
"vlan_mac_address": "a0:36:9f:2c:e8:80",
|
||||
"vif_id": "e1c90e9f-eafc-4e2d-8ec9-58b91cebb53f"
|
||||
}
|
||||
],
|
||||
"networks": [
|
||||
{
|
||||
"id": "private-ipv4",
|
||||
"type": "ipv4",
|
||||
"link": "interface0",
|
||||
"ip_address": "10.184.0.244",
|
||||
"netmask": "255.255.240.0",
|
||||
"routes": [
|
||||
{
|
||||
"network": "10.0.0.0",
|
||||
"netmask": "255.0.0.0",
|
||||
"gateway": "11.0.0.1"
|
||||
},
|
||||
{
|
||||
"network": "0.0.0.0",
|
||||
"netmask": "0.0.0.0",
|
||||
"gateway": "23.253.157.1"
|
||||
}
|
||||
],
|
||||
"network_id": "da5bb487-5193-4a65-a3df-4a0055a8c0d7"
|
||||
},
|
||||
{
|
||||
"id": "private-ipv4",
|
||||
"type": "ipv6",
|
||||
"link": "interface0",
|
||||
"ip_address": "2001:cdba::3257:9652/24",
|
||||
"routes": [
|
||||
{
|
||||
"network": "::",
|
||||
"netmask": "::",
|
||||
"gateway": "fd00::1"
|
||||
},
|
||||
{
|
||||
"network": "::",
|
||||
"netmask": "ffff:ffff:ffff::",
|
||||
"gateway": "fd00::1:1"
|
||||
}
|
||||
],
|
||||
"network_id": "da5bb487-5193-4a65-a3df-4a0055a8c0d8"
|
||||
},
|
||||
{
|
||||
"id": "publicnet-ipv4",
|
||||
"type": "ipv4",
|
||||
"link": "vlan0",
|
||||
"ip_address": "23.253.157.244",
|
||||
"netmask": "255.255.255.0",
|
||||
"dns_nameservers": [
|
||||
"69.20.0.164",
|
||||
"69.20.0.196"
|
||||
],
|
||||
"routes": [
|
||||
{
|
||||
"network": "0.0.0.0",
|
||||
"netmask": "0.0.0.0",
|
||||
"gateway": "23.253.157.1"
|
||||
}
|
||||
],
|
||||
"network_id": "62611d6f-66cb-4270-8b1f-503ef0dd4736"
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"type": "dns",
|
||||
"address": "8.8.8.8"
|
||||
},
|
||||
{
|
||||
"type": "dns",
|
||||
"address": "8.8.4.4"
|
||||
}
|
||||
]
|
||||
}
|
@ -16,6 +16,7 @@ Tests for the API /nodes/ methods.
|
||||
import datetime
|
||||
from http import client as http_client
|
||||
import json
|
||||
import os
|
||||
from urllib import parse as urlparse
|
||||
|
||||
import fixtures
|
||||
@ -42,12 +43,20 @@ from ironic.common import states
|
||||
from ironic.conductor import rpcapi
|
||||
from ironic import objects
|
||||
from ironic.objects import fields as obj_fields
|
||||
from ironic import tests as tests_root
|
||||
from ironic.tests import base
|
||||
from ironic.tests.unit.api import base as test_api_base
|
||||
from ironic.tests.unit.api import utils as test_api_utils
|
||||
from ironic.tests.unit.objects import utils as obj_utils
|
||||
|
||||
|
||||
with open(
|
||||
os.path.join(
|
||||
os.path.dirname(tests_root.__file__),
|
||||
'json_samples', 'network_data.json')) as fl:
|
||||
NETWORK_DATA = json.load(fl)
|
||||
|
||||
|
||||
class TestNodeObject(base.TestCase):
|
||||
|
||||
def test_node_init(self):
|
||||
@ -138,6 +147,7 @@ class TestListNodes(test_api_base.BaseApiTest):
|
||||
self.assertNotIn('retired', data['nodes'][0])
|
||||
self.assertNotIn('retired_reason', data['nodes'][0])
|
||||
self.assertNotIn('lessee', data['nodes'][0])
|
||||
self.assertNotIn('network_data', data['nodes'][0])
|
||||
|
||||
def test_get_one(self):
|
||||
node = obj_utils.create_test_node(self.context,
|
||||
@ -403,6 +413,19 @@ class TestListNodes(test_api_base.BaseApiTest):
|
||||
headers={api_base.Version.string: '1.65'})
|
||||
self.assertEqual(data['lessee'], "some-lucky-project")
|
||||
|
||||
def test_node_network_data_hidden_in_lower_version(self):
|
||||
self._test_node_field_hidden_in_lower_version('network_data',
|
||||
'1.65', '1.66')
|
||||
|
||||
def test_node_network_data(self):
|
||||
node = obj_utils.create_test_node(
|
||||
self.context, network_data=NETWORK_DATA,
|
||||
provision_state='active',
|
||||
uuid=uuidutils.generate_uuid())
|
||||
data = self.get_json('/nodes/%s' % node.uuid,
|
||||
headers={api_base.Version.string: '1.66'})
|
||||
self.assertEqual(data['network_data'], NETWORK_DATA)
|
||||
|
||||
def test_get_one_custom_fields(self):
|
||||
node = obj_utils.create_test_node(self.context,
|
||||
chassis_id=self.chassis.id)
|
||||
@ -684,6 +707,7 @@ class TestListNodes(test_api_base.BaseApiTest):
|
||||
self.assertIn('allocation_uuid', data['nodes'][0])
|
||||
self.assertIn('retired', data['nodes'][0])
|
||||
self.assertIn('retired_reason', data['nodes'][0])
|
||||
self.assertIn('network_data', data['nodes'][0])
|
||||
|
||||
def test_detail_using_query(self):
|
||||
node = obj_utils.create_test_node(self.context,
|
||||
@ -722,6 +746,7 @@ class TestListNodes(test_api_base.BaseApiTest):
|
||||
self.assertNotIn('chassis_id', data['nodes'][0])
|
||||
self.assertIn('retired', data['nodes'][0])
|
||||
self.assertIn('retired_reason', data['nodes'][0])
|
||||
self.assertIn('network_data', data['nodes'][0])
|
||||
|
||||
def test_detail_query_false(self):
|
||||
obj_utils.create_test_node(self.context)
|
||||
@ -3655,6 +3680,36 @@ class TestPatch(test_api_base.BaseApiTest):
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code)
|
||||
|
||||
def test_update_network_data(self):
|
||||
node = obj_utils.create_test_node(self.context,
|
||||
uuid=uuidutils.generate_uuid(),
|
||||
provision_state='active')
|
||||
self.mock_update_node.return_value = node
|
||||
headers = {api_base.Version.string: '1.66'}
|
||||
|
||||
response = self.patch_json('/nodes/%s' % node.uuid,
|
||||
[{'path': '/network_data',
|
||||
'value': NETWORK_DATA,
|
||||
'op': 'replace'}],
|
||||
headers=headers)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(http_client.OK, response.status_code)
|
||||
|
||||
def test_update_network_data_old_api(self):
|
||||
node = obj_utils.create_test_node(self.context,
|
||||
uuid=uuidutils.generate_uuid())
|
||||
self.mock_update_node.return_value = node
|
||||
headers = {api_base.Version.string: '1.62'}
|
||||
|
||||
response = self.patch_json('/nodes/%s' % node.uuid,
|
||||
[{'path': '/network_data',
|
||||
'value': NETWORK_DATA,
|
||||
'op': 'replace'}],
|
||||
headers=headers,
|
||||
expect_errors=True)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code)
|
||||
|
||||
@mock.patch.object(api_utils, 'check_multiple_node_policies_and_retrieve',
|
||||
autospec=True)
|
||||
def test_patch_policy_update(self, mock_cmnpar):
|
||||
|
@ -969,6 +969,13 @@ class MigrationCheckersMixin(object):
|
||||
col_names = [column.name for column in allocations.c]
|
||||
self.assertIn('owner', col_names)
|
||||
|
||||
def _check_cf1a80fdb352(self, engine, data):
|
||||
nodes = db_utils.get_table(engine, 'nodes')
|
||||
col_names = [column.name for column in nodes.c]
|
||||
self.assertIn('network_data', col_names)
|
||||
self.assertIsInstance(
|
||||
nodes.c.network_data.type, sqlalchemy.types.String)
|
||||
|
||||
def _pre_upgrade_cd2c80feb331(self, engine):
|
||||
data = {
|
||||
'node_uuid': uuidutils.generate_uuid(),
|
||||
|
@ -228,6 +228,7 @@ def get_test_node(**kw):
|
||||
'retired': kw.get('retired', False),
|
||||
'retired_reason': kw.get('retired_reason', None),
|
||||
'lessee': kw.get('lessee', None),
|
||||
'network_data': kw.get('network_data'),
|
||||
}
|
||||
|
||||
for iface in drivers_base.ALL_INTERFACES:
|
||||
|
@ -676,7 +676,7 @@ class TestObject(_LocalTest, _TestObject):
|
||||
# version bump. It is an MD5 hash of the object fields and remotable methods.
|
||||
# The fingerprint values should only be changed if there is a version bump.
|
||||
expected_object_fingerprints = {
|
||||
'Node': '1.34-ae873e627cf30bf28fe9f98a807b6200',
|
||||
'Node': '1.35-aee8ecf5c4d0ed590eb484762aee7fca',
|
||||
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
||||
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
||||
'Port': '1.9-0cb9202a4ec442e8c0d87a324155eaaf',
|
||||
|
Loading…
x
Reference in New Issue
Block a user