Remove host hardware sysinv profile
The Host Hardware Profiles for creating re-usable configuration templates for hosts are no longer maintained or supported and should be removed from code. Including : CPU, Interface, Storage and Memory profiles. profile categories: * cpu * memory * storage * interfaces topics: * remove objects * update models * update documentation * remove import/export profile apis * remove and update unit tests * new version script for migration upgrade Test Plan / Failure Path: PASS: Verify profile feature is removed on system upgrade without existing previous profiles. PASS: Verify profile feature is removed on system upgrade with existing previous profiles. PASS: Verify profile feature is removed on fresh install. Regression: PASS: Verify that the Horizon GUI remains navigable. PASS: Verify non-affected system commands remains listed. Story: 2009163 Task: 43159 Signed-off-by: Pablo Bovina <pablo.bovina@windriver.com> Depends-On: https://review.opendev.org/c/starlingx/config/+/806800 Change-Id: Id828365920ce179e347acf0de5d3ed6af09efcbd
This commit is contained in:
parent
914e6bc6c4
commit
e535293c68
@ -326,16 +326,6 @@ itemNotFound (404)
|
|||||||
"rel": "bookmark"
|
"rel": "bookmark"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"iprofile": [
|
|
||||||
{
|
|
||||||
"href": "http://10.10.10.2:6385/v1/iprofile/",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://10.10.10.2:6385/iprofile/",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"servicenodes": [
|
"servicenodes": [
|
||||||
{
|
{
|
||||||
"href": "http://10.10.10.2:6385/v1/servicenodes/",
|
"href": "http://10.10.10.2:6385/v1/servicenodes/",
|
||||||
@ -3619,457 +3609,6 @@ This will remove from the interface the datanetwork assigned.
|
|||||||
This operation does not accept a request body.
|
This operation does not accept a request body.
|
||||||
|
|
||||||
|
|
||||||
---------
|
|
||||||
Profiles
|
|
||||||
---------
|
|
||||||
|
|
||||||
These APIs allow the create, display and delete of host profiles. This
|
|
||||||
includes interface profiles, cpu profiles, and volume profiles. NOTE
|
|
||||||
that the same record is used in the database for both hosts and host
|
|
||||||
profiles.
|
|
||||||
|
|
||||||
********************
|
|
||||||
Lists all profiles
|
|
||||||
********************
|
|
||||||
|
|
||||||
.. rest_method:: GET /v1/iprofile
|
|
||||||
|
|
||||||
**Normal response codes**
|
|
||||||
|
|
||||||
200
|
|
||||||
|
|
||||||
**Error response codes**
|
|
||||||
|
|
||||||
computeFault (400, 500, ...), serviceUnavailable (503), badRequest (400),
|
|
||||||
unauthorized (401), forbidden (403), badMethod (405), overLimit (413),
|
|
||||||
itemNotFound (404)
|
|
||||||
|
|
||||||
**Response parameters**
|
|
||||||
|
|
||||||
.. csv-table::
|
|
||||||
:header: "Parameter", "Style", "Type", "Description"
|
|
||||||
:widths: 20, 20, 20, 60
|
|
||||||
|
|
||||||
"iprofiles (Optional)", "plain", "xsd:list", "The list of profile entities."
|
|
||||||
"recordtype (Optional)", "plain", "xsd:string", "Indicates that the record is being used for host profile rather than a host."
|
|
||||||
"hostname (Optional)", "plain", "xsd:string", "The name of the profile."
|
|
||||||
"uuid (Optional)", "plain", "csapi:UUID", "The universally unique identifier for this object."
|
|
||||||
"links (Optional)", "plain", "xsd:list", "For convenience, resources contain links to themselves. This allows a client to easily obtain rather than construct resource URIs. The following types of link relations are associated with resources: a self link containing a versioned link to the resource, and a bookmark link containing a permanent link to a resource that is appropriate for long term storage."
|
|
||||||
"created_at (Optional)", "plain", "xsd:dateTime", "The time when the object was created."
|
|
||||||
"updated_at (Optional)", "plain", "xsd:dateTime", "The time when the object was last updated."
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
{
|
|
||||||
"iprofiles": [
|
|
||||||
{
|
|
||||||
"uuid": "b6bde724-4fda-4941-ae3f-15abd3d4107b",
|
|
||||||
"recordtype": "profile",
|
|
||||||
"task": null,
|
|
||||||
"reserved": "False",
|
|
||||||
"mgmt_ip": null,
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"personality": null,
|
|
||||||
"created_at": "2014-09-29T13:36:36.760707+00:00",
|
|
||||||
"hostname": "ifprofile-type-1",
|
|
||||||
"updated_at": null,
|
|
||||||
"id": 23,
|
|
||||||
"ihost_uuid": null,
|
|
||||||
"profiletype": null,
|
|
||||||
"location": {
|
|
||||||
},
|
|
||||||
"action": "none",
|
|
||||||
"profilename": null,
|
|
||||||
"operational": "disabled",
|
|
||||||
"administrative": "locked",
|
|
||||||
"availability": "offline",
|
|
||||||
"uptime": 0,
|
|
||||||
"mgmt_mac": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"uuid": "85b8d979-a1d5-4b06-8666-22646d45dcdf",
|
|
||||||
"recordtype": "profile",
|
|
||||||
"task": null,
|
|
||||||
"reserved": "False",
|
|
||||||
"mgmt_ip": null,
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"personality": null,
|
|
||||||
"created_at": "2014-09-29T13:42:40.592612+00:00",
|
|
||||||
"hostname": "ifprofile-type-2",
|
|
||||||
"updated_at": null,
|
|
||||||
"id": 24,
|
|
||||||
"ihost_uuid": null,
|
|
||||||
"profiletype": null,
|
|
||||||
"location": {
|
|
||||||
},
|
|
||||||
"action": "none",
|
|
||||||
"profilename": null,
|
|
||||||
"operational": "disabled",
|
|
||||||
"administrative": "locked",
|
|
||||||
"availability": "offline",
|
|
||||||
"uptime": 0,
|
|
||||||
"mgmt_mac": null
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
This operation does not accept a request body.
|
|
||||||
|
|
||||||
********************************************
|
|
||||||
Shows information about a specific profile
|
|
||||||
********************************************
|
|
||||||
|
|
||||||
.. rest_method:: GET /v1/iprofile/{profile_id}
|
|
||||||
|
|
||||||
**Normal response codes**
|
|
||||||
|
|
||||||
200
|
|
||||||
|
|
||||||
**Error response codes**
|
|
||||||
|
|
||||||
computeFault (400, 500, ...), serviceUnavailable (503), badRequest (400),
|
|
||||||
unauthorized (401), forbidden (403), badMethod (405), overLimit (413),
|
|
||||||
itemNotFound (404)
|
|
||||||
|
|
||||||
**Request parameters**
|
|
||||||
|
|
||||||
.. csv-table::
|
|
||||||
:header: "Parameter", "Style", "Type", "Description"
|
|
||||||
:widths: 20, 20, 20, 60
|
|
||||||
|
|
||||||
"profile_id", "URI", "csapi:UUID", "The unique identifier of an existing profile."
|
|
||||||
|
|
||||||
**Response parameters**
|
|
||||||
|
|
||||||
.. csv-table::
|
|
||||||
:header: "Parameter", "Style", "Type", "Description"
|
|
||||||
:widths: 20, 20, 20, 60
|
|
||||||
|
|
||||||
"recordtype (Optional)", "plain", "xsd:string", "Indicates that the record is being used for host profile rather than a host."
|
|
||||||
"hostname (Optional)", "plain", "xsd:string", "The name of the profile."
|
|
||||||
"ports (Optional)", "plain", "xsd:list", "Links to the ports of the profile."
|
|
||||||
"interfaces (Optional)", "plain", "xsd:list", "Links to the interfaces of the profile."
|
|
||||||
"idisks (Optional)", "plain", "xsd:list", "Links to the disks of the profile."
|
|
||||||
"partitions (Optional)", "plain", "xsd:list", "Links to the partitions of the profile."
|
|
||||||
"istors (Optional)", "plain", "xsd:list", "Links to the physical volume storage resources of the profile."
|
|
||||||
"ipvs (Optional)", "plain", "xsd:list", "Links to the physical volumes of the profile."
|
|
||||||
"ilvgs (Optional)", "plain", "xsd:list", "Links to the logical volume group storage resources of the profile."
|
|
||||||
"inodes (Optional)", "plain", "xsd:list", "Links to the NUMA Nodes of the profile."
|
|
||||||
"icpus (Optional)", "plain", "xsd:list", "Links to the logical cores (CPUs) of the profile."
|
|
||||||
"uuid (Optional)", "plain", "csapi:UUID", "The universally unique identifier for this object."
|
|
||||||
"links (Optional)", "plain", "xsd:list", "For convenience, resources contain links to themselves. This allows a client to easily obtain rather than construct resource URIs. The following types of link relations are associated with resources: a self link containing a versioned link to the resource, and a bookmark link containing a permanent link to a resource that is appropriate for long term storage."
|
|
||||||
"created_at (Optional)", "plain", "xsd:dateTime", "The time when the object was created."
|
|
||||||
"updated_at (Optional)", "plain", "xsd:dateTime", "The time when the object was last updated."
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
{
|
|
||||||
"ports" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/ports"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/ports"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"operational" : "disabled",
|
|
||||||
"imemorys" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/ihosts/85b8d979-a1d5-4b06-8666-22646d45dcdf/imemorys"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/ihosts/85b8d979-a1d5-4b06-8666-22646d45dcdf/imemorys"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"iinterfaces" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/iinterfaces"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/iinterfaces"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"personality" : null,
|
|
||||||
"serialId" : null,
|
|
||||||
"hostname" : "ifprofile-type-2",
|
|
||||||
"profilename" : null,
|
|
||||||
"uuid" : "85b8d979-a1d5-4b06-8666-22646d45dcdf",
|
|
||||||
"profiletype" : null,
|
|
||||||
"ihost_uuid" : null,
|
|
||||||
"created_at" : "2014-09-29T13:42:40.592612+00:00",
|
|
||||||
"availability" : "offline",
|
|
||||||
"recordtype" : "profile",
|
|
||||||
"istors" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/istors"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/istors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"idisks" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/idisks"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf/idisks"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"uptime" : 0,
|
|
||||||
"icpus" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/ihosts/85b8d979-a1d5-4b06-8666-22646d45dcdf/icpus"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/ihosts/85b8d979-a1d5-4b06-8666-22646d45dcdf/icpus"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"id" : 24,
|
|
||||||
"mgmt_ip" : null,
|
|
||||||
"links" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/iprofile/85b8d979-a1d5-4b06-8666-22646d45dcdf"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"location" : {},
|
|
||||||
"inodes" : [
|
|
||||||
{
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://128.224.151.244:6385/v1/ihosts/85b8d979-a1d5-4b06-8666-22646d45dcdf/inodes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"rel" : "bookmark",
|
|
||||||
"href" : "http://128.224.151.244:6385/ihosts/85b8d979-a1d5-4b06-8666-22646d45dcdf/inodes"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"task" : null,
|
|
||||||
"mgmt_mac" : null,
|
|
||||||
"invprovision" : null,
|
|
||||||
"administrative" : "locked",
|
|
||||||
"updated_at" : null,
|
|
||||||
"action" : "none",
|
|
||||||
"reserved" : "False"
|
|
||||||
}
|
|
||||||
|
|
||||||
This operation does not accept a request body.
|
|
||||||
|
|
||||||
*******************
|
|
||||||
Creates a profile
|
|
||||||
*******************
|
|
||||||
|
|
||||||
.. rest_method:: POST /v1/iprofile
|
|
||||||
|
|
||||||
**Normal response codes**
|
|
||||||
|
|
||||||
200
|
|
||||||
|
|
||||||
**Error response codes**
|
|
||||||
|
|
||||||
badMediaType (415)
|
|
||||||
|
|
||||||
**Request parameters**
|
|
||||||
|
|
||||||
.. csv-table::
|
|
||||||
:header: "Parameter", "Style", "Type", "Description"
|
|
||||||
:widths: 20, 20, 20, 60
|
|
||||||
|
|
||||||
"profilename (Optional)", "plain", "xsd:string", "The name for the new profile."
|
|
||||||
"profiletype (Optional)", "plain", "xsd:string", "The type of profile to be created. Valid values are: ``if``, ``cpu`` or ``stor``."
|
|
||||||
"ihost_uuid (Optional)", "plain", "csapi:UUID", "The UUID of the Host to create the profile based on."
|
|
||||||
|
|
||||||
**Response parameters**
|
|
||||||
|
|
||||||
.. csv-table::
|
|
||||||
:header: "Parameter", "Style", "Type", "Description"
|
|
||||||
:widths: 20, 20, 20, 60
|
|
||||||
|
|
||||||
"recordtype (Optional)", "plain", "xsd:string", "Indicates that the record is being used for host profile rather than a host."
|
|
||||||
"hostname (Optional)", "plain", "xsd:string", "The name of the profile."
|
|
||||||
"ports (Optional)", "plain", "xsd:list", "Links to the ports of the profile."
|
|
||||||
"interfaces (Optional)", "plain", "xsd:list", "Links to the interfaces of the profile."
|
|
||||||
"idisks (Optional)", "plain", "xsd:list", "Links to the disks of the profile."
|
|
||||||
"partitions (Optional)", "plain", "xsd:list", "Links to the partitions of the profile."
|
|
||||||
"istors (Optional)", "plain", "xsd:list", "Links to the physical volume storage resources of the profile."
|
|
||||||
"ipvs (Optional)", "plain", "xsd:list", "Links to the physical volumes of the profile."
|
|
||||||
"ilvgs (Optional)", "plain", "xsd:list", "Links to the logical volume group storage resources of the profile."
|
|
||||||
"inodes (Optional)", "plain", "xsd:list", "Links to the NUMA Nodes of the profile."
|
|
||||||
"icpus (Optional)", "plain", "xsd:list", "Links to the logical cores (CPUs) of the profile."
|
|
||||||
"uuid (Optional)", "plain", "csapi:UUID", "The universally unique identifier for this object."
|
|
||||||
"links (Optional)", "plain", "xsd:list", "For convenience, resources contain links to themselves. This allows a client to easily obtain rather than construct resource URIs. The following types of link relations are associated with resources: a self link containing a versioned link to the resource, and a bookmark link containing a permanent link to a resource that is appropriate for long term storage."
|
|
||||||
"created_at (Optional)", "plain", "xsd:dateTime", "The time when the object was created."
|
|
||||||
"updated_at (Optional)", "plain", "xsd:dateTime", "The time when the object was last updated."
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
{
|
|
||||||
"profilename": "ifprofile-type-1",
|
|
||||||
"profiletype": "if",
|
|
||||||
"ihost_uuid": "959f785b-6387-4b98-aa30-bc861061d7a1"
|
|
||||||
}
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
{
|
|
||||||
"ports": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/ports",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/ports",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"reserved": "False",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"idisks": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/idisks",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/idisks",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"availability": "offline",
|
|
||||||
"updated_at": null,
|
|
||||||
"ihost_uuid": null,
|
|
||||||
"id": 23,
|
|
||||||
"icpus": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/ihosts/b6bde724-4fda-4941-ae3f-15abd3d4107b/icpus",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/ihosts/b6bde724-4fda-4941-ae3f-15abd3d4107b/icpus",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"uptime": 0,
|
|
||||||
"uuid": "b6bde724-4fda-4941-ae3f-15abd3d4107b",
|
|
||||||
"mgmt_ip": null,
|
|
||||||
"hostname": "ifprofile-type-1",
|
|
||||||
"istors": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/istors",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/istors",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"operational": "disabled",
|
|
||||||
"location": {
|
|
||||||
},
|
|
||||||
"invprovision": null,
|
|
||||||
"administrative": "locked",
|
|
||||||
"personality": null,
|
|
||||||
"iinterfaces": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/iinterfaces",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/iprofile/b6bde724-4fda-4941-ae3f-15abd3d4107b/iinterfaces",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"profiletype": null,
|
|
||||||
"mgmt_mac": null,
|
|
||||||
"task": null,
|
|
||||||
"recordtype": "profile",
|
|
||||||
"created_at": "2014-09-29T13:36:36.760707+00:00",
|
|
||||||
"action": "none",
|
|
||||||
"profilename": null,
|
|
||||||
"serialId": null,
|
|
||||||
"inodes": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/ihosts/b6bde724-4fda-4941-ae3f-15abd3d4107b/inodes",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/ihosts/b6bde724-4fda-4941-ae3f-15abd3d4107b/inodes",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"imemorys": [
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/v1/ihosts/b6bde724-4fda-4941-ae3f-15abd3d4107b/imemorys",
|
|
||||||
"rel": "self"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"href": "http://192.168.204.2:6385/ihosts/b6bde724-4fda-4941-ae3f-15abd3d4107b/imemorys",
|
|
||||||
"rel": "bookmark"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
****************************
|
|
||||||
Deletes a specific profile
|
|
||||||
****************************
|
|
||||||
|
|
||||||
.. rest_method:: DELETE /v1/iprofile/{profile_id}
|
|
||||||
|
|
||||||
**Normal response codes**
|
|
||||||
|
|
||||||
204
|
|
||||||
|
|
||||||
**Request parameters**
|
|
||||||
|
|
||||||
.. csv-table::
|
|
||||||
:header: "Parameter", "Style", "Type", "Description"
|
|
||||||
:widths: 20, 20, 20, 60
|
|
||||||
|
|
||||||
"profile_id", "URI", "csapi:UUID", "The unique identifier of an existing profile."
|
|
||||||
|
|
||||||
This operation does not accept a request body.
|
|
||||||
|
|
||||||
----
|
----
|
||||||
DNS
|
DNS
|
||||||
----
|
----
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# Copyright (c) 2021 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
# This script will delete hosts which recordtype is a profile.
|
|
||||||
# This is required because host hardware profiles
|
|
||||||
# for creating re-usable configuration had been removed from GUI, CLI and
|
|
||||||
# API endpoinds. Profiles created prior the upgrade should be deleted.
|
|
||||||
|
|
||||||
import psycopg2
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from psycopg2.extras import RealDictCursor
|
|
||||||
from controllerconfig.common import log
|
|
||||||
|
|
||||||
LOG = log.get_logger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
action = None
|
|
||||||
from_release = None
|
|
||||||
to_release = None
|
|
||||||
arg = 1
|
|
||||||
|
|
||||||
while arg < len(sys.argv):
|
|
||||||
if arg == 1:
|
|
||||||
from_release = sys.argv[arg]
|
|
||||||
elif arg == 2:
|
|
||||||
to_release = sys.argv[arg] # noqa
|
|
||||||
elif arg == 3:
|
|
||||||
action = sys.argv[arg]
|
|
||||||
else:
|
|
||||||
print("Invalid option %s." % sys.argv[arg])
|
|
||||||
return 1
|
|
||||||
arg += 1
|
|
||||||
|
|
||||||
log.configure()
|
|
||||||
|
|
||||||
LOG.debug("%s invoked with from_release = %s to_release = %s action = %s"
|
|
||||||
% (sys.argv[0], from_release, to_release, action))
|
|
||||||
|
|
||||||
if action == "migrate":
|
|
||||||
if from_release == '21.05':
|
|
||||||
try:
|
|
||||||
delete_profile_host()
|
|
||||||
except Exception as ex:
|
|
||||||
LOG.exception(ex)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
|
|
||||||
def delete_profile_host():
|
|
||||||
conn = psycopg2.connect("dbname=sysinv user=postgres")
|
|
||||||
with conn:
|
|
||||||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
|
||||||
cur.execute("delete from i_host where recordtype='profile'")
|
|
||||||
|
|
||||||
LOG.info("Delete profile hosts completed")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
@ -54,10 +54,10 @@ def reset_config_target():
|
|||||||
conn = psycopg2.connect("dbname=sysinv user=postgres")
|
conn = psycopg2.connect("dbname=sysinv user=postgres")
|
||||||
with conn:
|
with conn:
|
||||||
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
with conn.cursor(cursor_factory=RealDictCursor) as cur:
|
||||||
cur.execute("update i_host set config_target=NULL where "
|
cur.execute("update i_host set config_target=NULL",)
|
||||||
"recordtype!='profile'",)
|
|
||||||
|
|
||||||
LOG.info("Reset host config_target completed")
|
LOG.info("Reset host config_target completed")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(main())
|
sys.exit(main())
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# Copyright (C) 2019 Intel Corporation
|
# Copyright (C) 2019 Intel Corporation
|
||||||
#
|
#
|
||||||
# Copyright (c) 2019 Wind River Systems, Inc.
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# lib/config
|
# lib/config
|
||||||
# Functions to control the configuration and operation of stx-config
|
# Functions to control the configuration and operation of stx-config
|
||||||
@ -109,7 +109,6 @@ function cleanup_sysinv {
|
|||||||
|
|
||||||
sudo rm -f $SYSINV_ETC_GOENABLEDD/sysinv_goenabled_check.sh
|
sudo rm -f $SYSINV_ETC_GOENABLEDD/sysinv_goenabled_check.sh
|
||||||
sudo rm -f $SYSINV_CONF_DIR/policy.json
|
sudo rm -f $SYSINV_CONF_DIR/policy.json
|
||||||
sudo rm -f $SYSINV_CONF_DIR/profileSchema.xsd
|
|
||||||
sudo rm -f $SYSINV_ETC_MOTDD/10-system
|
sudo rm -f $SYSINV_ETC_MOTDD/10-system
|
||||||
sudo rm -f $SYSINV_CONF_DIR/upgrades/delete_load.sh
|
sudo rm -f $SYSINV_CONF_DIR/upgrades/delete_load.sh
|
||||||
sudo rm -f $STX_OCF_ROOT/resource.d/platform/sysinv-api
|
sudo rm -f $STX_OCF_ROOT/resource.d/platform/sysinv-api
|
||||||
@ -249,7 +248,6 @@ function install_sysinv {
|
|||||||
sudo install -p -D -m 755 $SYSINV_DIR/etc/sysinv/sysinv_goenabled_check.sh $SYSINV_ETC_GOENABLEDD/sysinv_goenabled_check.sh
|
sudo install -p -D -m 755 $SYSINV_DIR/etc/sysinv/sysinv_goenabled_check.sh $SYSINV_ETC_GOENABLEDD/sysinv_goenabled_check.sh
|
||||||
sudo install -d -m 755 $SYSINV_CONF_DIR
|
sudo install -d -m 755 $SYSINV_CONF_DIR
|
||||||
sudo install -p -D -m 755 $SYSINV_DIR/etc/sysinv/policy.json $SYSINV_CONF_DIR/policy.json
|
sudo install -p -D -m 755 $SYSINV_DIR/etc/sysinv/policy.json $SYSINV_CONF_DIR/policy.json
|
||||||
sudo install -p -D -m 640 $SYSINV_DIR/etc/sysinv/profileSchema.xsd $SYSINV_CONF_DIR/profileSchema.xsd
|
|
||||||
sudo install -d -m 755 $SYSINV_ETC_MOTDD
|
sudo install -d -m 755 $SYSINV_ETC_MOTDD
|
||||||
sudo install -p -D -m 755 $SYSINV_DIR/etc/sysinv/motd-system $SYSINV_ETC_MOTDD/10-system
|
sudo install -p -D -m 755 $SYSINV_DIR/etc/sysinv/motd-system $SYSINV_ETC_MOTDD/10-system
|
||||||
sudo install -d -m 755 $SYSINV_CONF_DIR/upgrades
|
sudo install -d -m 755 $SYSINV_CONF_DIR/upgrades
|
||||||
|
@ -29,7 +29,6 @@ features:
|
|||||||
- Node role and role profiles.
|
- Node role and role profiles.
|
||||||
- Core and memory (including huge page) assignments.
|
- Core and memory (including huge page) assignments.
|
||||||
- Network Interfaces and storage assignments.
|
- Network Interfaces and storage assignments.
|
||||||
- Bulk configuration of nodes through system profiles.
|
|
||||||
- |
|
- |
|
||||||
User Interface:
|
User Interface:
|
||||||
|
|
||||||
|
@ -89,7 +89,6 @@ install -p -D -m 755 etc/sysinv/sysinv_goenabled_check.sh %{buildroot}%{local_et
|
|||||||
|
|
||||||
install -d -m 755 %{buildroot}%{local_etc_sysinv}
|
install -d -m 755 %{buildroot}%{local_etc_sysinv}
|
||||||
install -p -D -m 755 etc/sysinv/policy.json %{buildroot}%{local_etc_sysinv}/policy.json
|
install -p -D -m 755 etc/sysinv/policy.json %{buildroot}%{local_etc_sysinv}/policy.json
|
||||||
install -p -D -m 640 etc/sysinv/profileSchema.xsd %{buildroot}%{local_etc_sysinv}/profileSchema.xsd
|
|
||||||
|
|
||||||
install -p -D -m 644 etc/sysinv/crushmap-storage-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-storage-model.txt
|
install -p -D -m 644 etc/sysinv/crushmap-storage-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-storage-model.txt
|
||||||
install -p -D -m 644 etc/sysinv/crushmap-controller-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-controller-model.txt
|
install -p -D -m 644 etc/sysinv/crushmap-controller-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-controller-model.txt
|
||||||
|
@ -90,7 +90,6 @@ install -p -D -m 755 etc/sysinv/sysinv_goenabled_check.sh %{buildroot}%{local_et
|
|||||||
|
|
||||||
install -d -m 755 %{buildroot}%{local_etc_sysinv}
|
install -d -m 755 %{buildroot}%{local_etc_sysinv}
|
||||||
install -p -D -m 644 etc/sysinv/policy.json %{buildroot}%{local_etc_sysinv}/policy.json
|
install -p -D -m 644 etc/sysinv/policy.json %{buildroot}%{local_etc_sysinv}/policy.json
|
||||||
install -p -D -m 640 etc/sysinv/profileSchema.xsd %{buildroot}%{local_etc_sysinv}/profileSchema.xsd
|
|
||||||
|
|
||||||
install -p -D -m 644 etc/sysinv/crushmap-storage-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-storage-model.txt
|
install -p -D -m 644 etc/sysinv/crushmap-storage-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-storage-model.txt
|
||||||
install -p -D -m 644 etc/sysinv/crushmap-controller-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-controller-model.txt
|
install -p -D -m 644 etc/sysinv/crushmap-controller-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-controller-model.txt
|
||||||
|
@ -1,354 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<xs:complexType name="Processor">
|
|
||||||
<xs:attribute type="xs:byte" name="index" />
|
|
||||||
<xs:attribute type="xs:byte" name="numberOfCores" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="CPUProfile">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="processor" minOccurs="1">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element type="xs:byte" name="numberOfProcessor" />
|
|
||||||
<xs:element type="xs:byte" name="coresPerProcessor" />
|
|
||||||
<xs:element type="xs:boolean" name="hyperThreading" minOccurs="0" maxOccurs="1" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="platformCores" minOccurs="1">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
|
||||||
<xs:element name="processor" type="Processor" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="vswitchCores" minOccurs="0">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
|
||||||
<xs:element name="processor" type="Processor" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="sharedCores" minOccurs="0">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
|
||||||
<xs:element name="processor" type="Processor" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute type="xs:string" name="name" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="memoryAllocation">
|
|
||||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
|
||||||
<xs:element name="processor" type="processorMemory" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="processorMemory">
|
|
||||||
<xs:attribute type="xs:nonNegativeInteger" name="index" use="required" />
|
|
||||||
<xs:attribute type="xs:nonNegativeInteger" name="size" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="MemoryProfile">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element type="xs:byte" name="numberOfProcessor" />
|
|
||||||
<xs:element name="platformReservedMiB" type="memoryAllocation" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="vmHugePages2M" type="memoryAllocation" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="vmHugePages1G" type="memoryAllocation" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="vsHugePagesNr" type="memoryAllocation" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="vsHugePagesSz" type="memoryAllocation" minOccurs="0" maxOccurs="1"/>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute type="xs:string" name="name" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:simpleType name="TxPolicy">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:enumeration value="layer3+4" />
|
|
||||||
<xs:enumeration value="layer2+3" />
|
|
||||||
<xs:enumeration value="layer2" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:complexType name="AeModePolicy">
|
|
||||||
<xs:attribute name="txPolicy" type="TxPolicy" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="AeMode">
|
|
||||||
<xs:choice minOccurs="1" maxOccurs="1">
|
|
||||||
<xs:element name="activeStandby" />
|
|
||||||
<xs:element name="balanced" type="AeModePolicy" />
|
|
||||||
<xs:element name="ieee802.3ad" type="AeModePolicy" />
|
|
||||||
</xs:choice>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:simpleType name="Ipv4Mode">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:enumeration value="disabled" />
|
|
||||||
<xs:enumeration value="static" />
|
|
||||||
<xs:enumeration value="dhcp" />
|
|
||||||
<xs:enumeration value="pool" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:simpleType name="Ipv6Mode">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:enumeration value="disabled" />
|
|
||||||
<xs:enumeration value="static" />
|
|
||||||
<xs:enumeration value="auto" />
|
|
||||||
<xs:enumeration value="link-local" />
|
|
||||||
<xs:enumeration value="pool" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
|
|
||||||
<xs:complexType name="interface">
|
|
||||||
<xs:attribute name="name" type="xs:string" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="interfaces">
|
|
||||||
<xs:sequence minOccurs="1" maxOccurs="unbounded">
|
|
||||||
<xs:element type="interface" name="interface" >
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="providerNetwork">
|
|
||||||
<xs:attribute name="name" type="xs:string" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="providerNetworks">
|
|
||||||
<xs:sequence maxOccurs="unbounded" minOccurs="0">
|
|
||||||
<xs:element type="providerNetwork" name="providerNetwork" />
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="IpPool">
|
|
||||||
<xs:attribute name="name" use="required">
|
|
||||||
</xs:attribute>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="ipv4">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="pool" type="IpPool" minOccurs="0" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="mode" type="Ipv4Mode" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="ipv6">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="pool" type="IpPool" minOccurs="0" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="mode" type="Ipv6Mode" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="dataclassNetwork">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="providerNetworks" type="providerNetworks" minOccurs="1" maxOccurs="unbounded">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="ipv4" type="ipv4" minOccurs="1" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="ipv6" type="ipv6" minOccurs="1" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="routes" type="routes" minOccurs="0" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="externalNetwork">
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="pciPassthrough">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="providerNetworks" type="providerNetworks" minOccurs="1" maxOccurs="unbounded">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="pciSriov">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="providerNetworks" type="providerNetworks" minOccurs="1" maxOccurs="unbounded">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="virtualFunctions" type="xs:nonNegativeInteger" use="required" />
|
|
||||||
<xs:attribute name="virtualFunctionDriver" type="xs:string" />
|
|
||||||
<xs:attribute name="maxTxRate" type="xs:nonNegativeInteger" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="route">
|
|
||||||
<xs:attribute name="network" type="xs:string" />
|
|
||||||
<xs:attribute name="metric" type="xs:integer" />
|
|
||||||
<xs:attribute name="gateway" type="xs:string" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="routes">
|
|
||||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
|
||||||
<xs:element name="route" type="route">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:simpleType name="pciAddress">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:pattern value="[0-9a-fA-F]{1,4}[:][0-9a-fA-F]{1,2}[:][0-9a-fA-F]{1,2}[.][0-9a-fA-F]" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:simpleType name="pciClass">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:enumeration value="Ethernet controller" />
|
|
||||||
<xs:enumeration value="Network controller" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:complexType name="ethernetInterface">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="port" minOccurs="1" maxOccurs="1">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:attribute name="name" use="optional" />
|
|
||||||
<xs:attribute name="pciAddress" type="pciAddress" use="optional" />
|
|
||||||
<xs:attribute name="class" type="pciClass" use="required" />
|
|
||||||
<xs:attribute name="device" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="networks" minOccurs="0">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:choice minOccurs="1" maxOccurs="2">
|
|
||||||
<xs:element name="dataclassNetwork" type="dataclassNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="clusterhostNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="mgmtNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="oamNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="pciPassthrough" type="pciPassthrough" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="pciSriov" type="pciSriov" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:choice>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="ifName" type="xs:string" use="required" />
|
|
||||||
<xs:attribute name="mtu" type="xs:positiveInteger" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:simpleType name="VlanId">
|
|
||||||
<xs:restriction base="xs:short">
|
|
||||||
<xs:minInclusive value="1" />
|
|
||||||
<xs:maxInclusive value="4094" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:complexType name="vlanInterface">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="networks">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:choice minOccurs="1" maxOccurs="2">
|
|
||||||
<xs:element name="mgmtNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="oamNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="dataclassNetwork" type="dataclassNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="clusterhostNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:choice>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="ifName" type="xs:string" use="required" />
|
|
||||||
<xs:attribute name="interface" type="xs:string" use="required" />
|
|
||||||
<xs:attribute name="vlanId" type="VlanId" use="required"/>
|
|
||||||
<xs:attribute name="mtu" type="xs:positiveInteger" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="aeInterface">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="networks" minOccurs="0">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:choice minOccurs="1" maxOccurs="2">
|
|
||||||
<xs:element name="mgmtNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="oamNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="dataclassNetwork" type="dataclassNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="clusterhostNetwork" type="externalNetwork" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:choice>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="interfaces" type="interfaces">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="aeMode" type="AeMode" minOccurs="1" maxOccurs="1">
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute name="ifName" type="xs:string" use="required" />
|
|
||||||
<xs:attribute name="mtu" type="xs:positiveInteger" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
<xs:complexType name="InterfaceProfile">
|
|
||||||
<xs:choice maxOccurs="unbounded">
|
|
||||||
<xs:element type="ethernetInterface" name="ethernetInterface">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element type="vlanInterface" name="vlanInterface">
|
|
||||||
</xs:element>
|
|
||||||
<xs:element type="aeInterface" name="aeInterface">
|
|
||||||
</xs:element>
|
|
||||||
</xs:choice>
|
|
||||||
<xs:attribute type="xs:string" name="name" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:simpleType name="volumeFunction">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:enumeration value="osd" />
|
|
||||||
<xs:enumeration value="journal" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:complexType name="Disk">
|
|
||||||
<xs:simpleContent>
|
|
||||||
<xs:extension base="xs:string">
|
|
||||||
<xs:attribute type="xs:string" name="path" use="required" />
|
|
||||||
<xs:attribute type="xs:positiveInteger" name="size" use="required" />
|
|
||||||
<xs:attribute type="volumeFunction" name="volumeFunc" use="optional" />
|
|
||||||
<xs:attribute type="xs:positiveInteger" name="journalSize" use="optional" />
|
|
||||||
<xs:attribute type="xs:string" name="journalLocation" use="optional" />
|
|
||||||
<xs:attribute type="xs:string" name="tier" use="optional" />
|
|
||||||
</xs:extension>
|
|
||||||
</xs:simpleContent>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="StorageProfile">
|
|
||||||
<xs:sequence maxOccurs="unbounded">
|
|
||||||
<xs:element type="Disk" name="disk" minOccurs="0" />
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute type="xs:string" name="name" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:simpleType name="Lvm_vg_name">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:enumeration value="nova-local" />
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:complexType name="Lvg">
|
|
||||||
<xs:simpleContent>
|
|
||||||
<xs:extension base="xs:string">
|
|
||||||
<xs:attribute type="Lvm_vg_name" name="lvm_vg_name" use="required" />
|
|
||||||
</xs:extension>
|
|
||||||
</xs:simpleContent>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="LocalStorageProfile">
|
|
||||||
<xs:sequence maxOccurs="unbounded">
|
|
||||||
<xs:element type="Disk" name="disk" minOccurs="0" />
|
|
||||||
<xs:element type="Lvg" name="lvg" minOccurs="0" />
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute type="xs:string" name="name" use="required" />
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:element name="profiles">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:choice maxOccurs="unbounded">
|
|
||||||
<xs:element name="cpuProfile" type="CPUProfile" maxOccurs="unbounded" minOccurs="0" nillable="true" />
|
|
||||||
<xs:element name="memoryProfile" type="MemoryProfile" maxOccurs="unbounded" minOccurs="0" nillable="true" />
|
|
||||||
<xs:element name="interfaceProfile" type="InterfaceProfile" maxOccurs="unbounded" minOccurs="0" nillable="true" />
|
|
||||||
<xs:element name="storageProfile" type="StorageProfile" maxOccurs="unbounded" minOccurs="0" nillable="true" />
|
|
||||||
<xs:element name="localstorageProfile" type="LocalStorageProfile" maxOccurs="unbounded" minOccurs="0" nillable="true" />
|
|
||||||
</xs:choice>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
|
|
||||||
</xs:schema>
|
|
@ -1,339 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<profiles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="profileSchema.xsd">
|
|
||||||
<!--This is a typical 2 processors by 10 physical cores compute node
|
|
||||||
Taken from HP380 -->
|
|
||||||
<cpuProfile name="cpu-2x10">
|
|
||||||
<processor>
|
|
||||||
<!--number of processors on the server-->
|
|
||||||
<numberOfProcessor>2</numberOfProcessor>
|
|
||||||
<!--number of physical cores in each processor.
|
|
||||||
Specify number of the physical cores here.
|
|
||||||
To see logical core mapping, turn on the hyper-threading below-->
|
|
||||||
<coresPerProcessor>10</coresPerProcessor>
|
|
||||||
<!--use optional hyperThreading to enable hyper-thread to the -->
|
|
||||||
<!--profile. Enabling hyper-threading will make the profile looks-->
|
|
||||||
<!--like what it is as if the host has it hyper-threading enabled. -->
|
|
||||||
<hyperThreading>false</hyperThreading>
|
|
||||||
</processor>
|
|
||||||
|
|
||||||
<!--platformCores section defines physical cores assign to platform functions on each processor -->
|
|
||||||
<platformCores>
|
|
||||||
<!--Each processor tag defines number of physical cores to be assigned to platform function on
|
|
||||||
a processor indicated by the index.
|
|
||||||
processor index starts from 0 to numberOfProcessor -1.
|
|
||||||
Each processor (indicated by index) should only appear once-->
|
|
||||||
<processor index="0" numberOfCores="1"></processor>
|
|
||||||
</platformCores>
|
|
||||||
|
|
||||||
<!--vswitchCores section defines physical cores assign to vswitch functions on each processor
|
|
||||||
This setting only apply to the compute nodes. -->
|
|
||||||
<vswitchCores>
|
|
||||||
<!--Each processor tag defines number of physical cores to be assigned to vswitch function on
|
|
||||||
a processor indicated by the index.
|
|
||||||
processor index starts from 0 to numberOfProcessor -1.
|
|
||||||
Each processor (indicated by index) should only appear once-->
|
|
||||||
<processor index="0" numberOfCores="2"></processor>
|
|
||||||
</vswitchCores>
|
|
||||||
|
|
||||||
<!--remaining cores on each processor are assigned to guest VMs-->
|
|
||||||
</cpuProfile>
|
|
||||||
|
|
||||||
<!--this setup is taken from HP380 -->
|
|
||||||
<memoryProfile name="mem-profile">
|
|
||||||
<!--number of CPUs on the motherboard-->
|
|
||||||
<numberOfProcessor>2</numberOfProcessor>
|
|
||||||
|
|
||||||
<!--platformReservedMiB section defines the memory to be reserved for platform functions-->
|
|
||||||
<platformReservedMiB>
|
|
||||||
<!--Each processor tag defines number of physical cores to be assigned to vswitch function on
|
|
||||||
a processor indicated by the index.
|
|
||||||
processor index starts from 0 to numberOfProcessor -1.
|
|
||||||
Each processor (indicated by index) should only appear once.
|
|
||||||
The size is in MB-->
|
|
||||||
<processor index="0" size="4000"></processor>
|
|
||||||
<processor index="1" size="2000"></processor>
|
|
||||||
</platformReservedMiB>
|
|
||||||
|
|
||||||
<!--vmHugePages2M section defines number of 2M bytes huge page assigned to each processor-->
|
|
||||||
<vmHugePages2M>
|
|
||||||
<!--Each processor tag defines number of physical cores to be assigned to vswitch function on
|
|
||||||
a processor indicated by the index.
|
|
||||||
processor index starts from 0 to numberOfProcessor -1.
|
|
||||||
Each processor (indicated by index) should only appear once. -->
|
|
||||||
<processor index="0" size="29096"></processor>
|
|
||||||
<processor index="1" size="30129"></processor>
|
|
||||||
</vmHugePages2M>
|
|
||||||
|
|
||||||
<!--vmHugePages1G section defines number of 1G bytes huge page assigned to each processor-->
|
|
||||||
<vmHugePages1G>
|
|
||||||
<!--Each processor tag defines number of physical cores to be assigned to vswitch function on
|
|
||||||
a processor indicated by the index.
|
|
||||||
processor index starts from 0 to numberOfProcessor -1.
|
|
||||||
Each processor (indicated by index) should only appear once. -->
|
|
||||||
<processor index="0" size="0"></processor>
|
|
||||||
<processor index="1" size="0"></processor>
|
|
||||||
</vmHugePages1G>
|
|
||||||
</memoryProfile>
|
|
||||||
|
|
||||||
<!--This setup is taken from wildcat7_12-->
|
|
||||||
<storageProfile name="storage-profile">
|
|
||||||
<!--The disk tags below define each device,
|
|
||||||
path: device path
|
|
||||||
size: minimum size (in GiB)
|
|
||||||
volumeFunc: volume function to be assigned to the device
|
|
||||||
For 'osd' function:
|
|
||||||
journalSize: the size of the ceph journal in GiB, if absent defaults to journal_default_size in sysinv.conf
|
|
||||||
journalLocation: location of the journal partition, mandatory if multiple journal functions are defined,
|
|
||||||
if absent defaults to the single available journal drive.
|
|
||||||
If no device with journal function is configured then the journals for all OSDs will be collocated on the
|
|
||||||
same device with the OSD data (partition #1 is for the data and partition #2 for the journl).
|
|
||||||
In this case the size of the journal will be journal_default_size.-->
|
|
||||||
<disk path="/dev/sdb" size="223" volumeFunc="osd" journalSize="2" journalLocation="/dev/sdd" />
|
|
||||||
<disk path="/dev/sdc" size="223" volumeFunc="osd" journalLocation="/dev/sde" />
|
|
||||||
<disk path="/dev/sdd" size="223" volumeFunc="journal" />
|
|
||||||
<disk path="/dev/sde" size="223" volumeFunc="journal" />
|
|
||||||
</storageProfile>
|
|
||||||
|
|
||||||
<storageProfile name="storage-profile-coloc-no-tier">
|
|
||||||
<!--The disk tags below define each device,
|
|
||||||
path: device path
|
|
||||||
size: minimum size (in GiB)
|
|
||||||
volumeFunc: volume function to be assigned to the device
|
|
||||||
For 'osd' function:
|
|
||||||
journalSize: the size of the ceph journal in GiB, if absent defaults to journal_default_size in sysinv.conf
|
|
||||||
journalLocation: location of the journal partition, mandatory if multiple journal functions are defined,
|
|
||||||
if absent defaults to the single available journal drive.
|
|
||||||
tier: storage tier for OSDs. If this is not specified, then the
|
|
||||||
primary system default tier, 'storage', is used.
|
|
||||||
If no device with journal function is configured then the journals for all OSDs will be collocated on the
|
|
||||||
same device with the OSD data (partition #1 is for the data and partition #2 for the journl).
|
|
||||||
In this case the size of the journal will be journal_default_size.
|
|
||||||
-->
|
|
||||||
<disk path="/dev/disk/by-path/pci-0000:00:0d.0-ata-2.0" size="50" volumeFunc="osd"/>
|
|
||||||
<disk path="/dev/disk/by-path/pci-0000:00:0d.0-ata-3.0" size="50" volumeFunc="osd"/>
|
|
||||||
</storageProfile>
|
|
||||||
|
|
||||||
<storageProfile name="storage-profile-journal-no-tier">
|
|
||||||
<!--The disk tags below define each device,
|
|
||||||
path: device path
|
|
||||||
size: minimum size (in GiB)
|
|
||||||
volumeFunc: volume function to be assigned to the device
|
|
||||||
For 'osd' function:
|
|
||||||
journalSize: the size of the ceph journal in GiB, if absent defaults to journal_default_size in sysinv.conf
|
|
||||||
journalLocation: location of the journal partition, mandatory if multiple journal functions are defined,
|
|
||||||
if absent defaults to the single available journal drive.
|
|
||||||
tier: storage tier for OSDs. If this is not specified, then the
|
|
||||||
primary system default tier, 'storage', is used.
|
|
||||||
If no device with journal function is configured then the journals for all OSDs will be collocated on the
|
|
||||||
same device with the OSD data (partition #1 is for the data and partition #2 for the journl).
|
|
||||||
In this case the size of the journal will be journal_default_size.
|
|
||||||
-->
|
|
||||||
<disk path="/dev/disk/by-path/pci-0000:00:0d.0-ata-2.0" size="50" volumeFunc="osd"/>
|
|
||||||
<disk path="/dev/disk/by-path/pci-0000:00:0d.0-ata-3.0" size="50" volumeFunc="journal"/>
|
|
||||||
</storageProfile>
|
|
||||||
|
|
||||||
<storageProfile name="storage-profile-coloc-two-tiers">
|
|
||||||
<!--The disk tags below define each device,
|
|
||||||
path: device path
|
|
||||||
size: minimum size (in GiB)
|
|
||||||
volumeFunc: volume function to be assigned to the device
|
|
||||||
For 'osd' function:
|
|
||||||
journalSize: the size of the ceph journal in GiB, if absent defaults to journal_default_size in sysinv.conf
|
|
||||||
journalLocation: location of the journal partition, mandatory if multiple journal functions are defined,
|
|
||||||
if absent defaults to the single available journal drive.
|
|
||||||
tier: storage tier for OSDs. If this is not specified, then the
|
|
||||||
primary system default tier, 'storage', is used.
|
|
||||||
If no device with journal function is configured then the journals for all OSDs will be collocated on the
|
|
||||||
same device with the OSD data (partition #1 is for the data and partition #2 for the journl).
|
|
||||||
In this case the size of the journal will be journal_default_size.
|
|
||||||
-->
|
|
||||||
<disk path="/dev/disk/by-path/pci-0000:00:0d.0-ata-2.0" size="50" volumeFunc="osd" tier="storage"/>
|
|
||||||
<disk path="/dev/disk/by-path/pci-0000:00:0d.0-ata-3.0" size="50" volumeFunc="osd" tier="gold"/>
|
|
||||||
</storageProfile>
|
|
||||||
|
|
||||||
<localstorageProfile name="localstorage-profile_localimage">
|
|
||||||
<!--The disk tags below define each device,
|
|
||||||
node: device node
|
|
||||||
size: minimum size (in GiB).
|
|
||||||
The lvg tags below define the local volume group
|
|
||||||
lvm_vg_name: local volume group name
|
|
||||||
-->
|
|
||||||
<disk path="/dev/sdb" size="223" />
|
|
||||||
<lvg lvm_vg_name="nova-local" />
|
|
||||||
</localstorageProfile>
|
|
||||||
|
|
||||||
<localstorageProfile name="localstorage-profile_remote">
|
|
||||||
<!--The disk tags below define each device,
|
|
||||||
node: device node
|
|
||||||
size: minimum size (in MB).
|
|
||||||
The lvg tags below define the local volume group
|
|
||||||
lvm_vg_name: local volume group name
|
|
||||||
-->
|
|
||||||
<disk path="/dev/sdb" size="223" />
|
|
||||||
<lvg lvm_vg_name="nova-local" />
|
|
||||||
</localstorageProfile>
|
|
||||||
|
|
||||||
|
|
||||||
<interfaceProfile name="if-hp380-profile">
|
|
||||||
<!--This is a typical Ethernet interface definition.
|
|
||||||
It defines:
|
|
||||||
'ifName', name of the interface
|
|
||||||
'mtu', mtu of the interface, and
|
|
||||||
Ethernet port associated to this Ethernet interface (see port section below)
|
|
||||||
-->
|
|
||||||
<ethernetInterface ifName="eth0" mtu="1500" >
|
|
||||||
<!--An Ethernet port is identified by its class, device and pciAddress in order to match to a physical
|
|
||||||
Ethernet port on a host when the profile is applied to it.
|
|
||||||
Alternatively, port name can be chosen as a replacement of pciAddress.
|
|
||||||
Note that the pciAddress is directly associated with the hardware, it is the recommended identifier.
|
|
||||||
Each Ethernet port must have its pciAddress unless Ethernet port name is chosen for the matching,
|
|
||||||
in which case each Ethernet port must have its name defined.
|
|
||||||
If both pciAddress and port name are provided for each Ethernet port, only pciAddress will be used
|
|
||||||
for matching the physical Ethernet port when the profile is applied to a host.
|
|
||||||
name: Ethernet port name
|
|
||||||
pciAddress: pci address of the Ethernet port, formed in 4 section of hexadecimal digits as:
|
|
||||||
XXXX:XX:XX.X
|
|
||||||
note: each 'X' represents a hexadecimal digit.
|
|
||||||
class: pci class, valid values are:
|
|
||||||
Ethernet controller
|
|
||||||
Network controller
|
|
||||||
device: name of the device
|
|
||||||
-->
|
|
||||||
<port name="eth0" pciAddress="0000:03:00.0" class="Ethernet controller" device="NetXtreme BCM5719 Gigabit Ethernet PCIe" />
|
|
||||||
</ethernetInterface>
|
|
||||||
<ethernetInterface ifName="data0" mtu="1500" >
|
|
||||||
<port name="eth1" pciAddress="0000:03:00.1" class="Ethernet controller" device="NetXtreme BCM5719 Gigabit Ethernet PCIe" />
|
|
||||||
<!--An ethInterface can be used as data, cluster-host, oam, mgmt, pci-passthrough or pci-sriov networks. Network
|
|
||||||
type can be specified by adding the network type in the networks section.
|
|
||||||
An ethInterface can also be setup as combination of 2 network types. Only mgmt and cluster-host network can
|
|
||||||
be combined.
|
|
||||||
-->
|
|
||||||
<networks>
|
|
||||||
<dataclassNetwork>
|
|
||||||
<!--one or more provider network is required for a dataclassNetwork-->
|
|
||||||
<providerNetworks>
|
|
||||||
<providerNetwork name="group0-data0" />
|
|
||||||
<providerNetwork name="group0-data0b" />
|
|
||||||
</providerNetworks>
|
|
||||||
<!--specify ipv4 address mode, valid values are:
|
|
||||||
disabled,
|
|
||||||
pool,
|
|
||||||
dhcp, and
|
|
||||||
static-->
|
|
||||||
<ipv4 mode="disabled"></ipv4>
|
|
||||||
<!--specify ipv4 address mode, valid values are:
|
|
||||||
automaticAssignment
|
|
||||||
disabled,
|
|
||||||
pool,
|
|
||||||
linkLocal, and
|
|
||||||
static-->
|
|
||||||
<ipv6 mode="link-local"></ipv6>
|
|
||||||
</dataclassNetwork>
|
|
||||||
</networks>
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<ethernetInterface ifName="eth2" mtu="1500" >
|
|
||||||
<port name="eth2" pciAddress="0000:03:00.2" class="Ethernet controller" device="NetXtreme BCM5719 Gigabit Ethernet PCIe" />
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<ethernetInterface ifName="passthrough-0" mtu="1500" >
|
|
||||||
<!--This ethernetInterface is defined as pci-passthrough network. See networks section-->
|
|
||||||
<port name="eth3" pciAddress="0000:03:00.3" class="Ethernet controller" device="NetXtreme BCM5719 Gigabit Ethernet PCIe" />
|
|
||||||
<networks>
|
|
||||||
<pciPassthrough>
|
|
||||||
<providerNetworks>
|
|
||||||
<providerNetwork name="data1" />
|
|
||||||
</providerNetworks>
|
|
||||||
</pciPassthrough>
|
|
||||||
</networks>
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<ethernetInterface ifName="eth4" mtu="1600" >
|
|
||||||
<!--This ethernetInterface is defined as pci-sriov network. See networks section-->
|
|
||||||
<port name="eth4" pciAddress="0000:04:00.0" class="Ethernet controller" device="82599ES 10-Gigabit SFI/SFP+ Network Connection" />
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<ethernetInterface ifName="eth5" mtu="1500" >
|
|
||||||
<port name="eth5" pciAddress="0000:04:00.1" class="Ethernet controller" device="82599ES 10-Gigabit SFI/SFP+ Network Connection" />
|
|
||||||
<networks>
|
|
||||||
<mgmtNetwork/>
|
|
||||||
</networks>
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<ethernetInterface ifName="data1" mtu="1500" >
|
|
||||||
<port name="eth6" pciAddress="0000:07:00.0" class="Ethernet controller" device="82599ES 10-Gigabit SFI/SFP+ Network Connection" />
|
|
||||||
<networks>
|
|
||||||
<dataclassNetwork>
|
|
||||||
<providerNetworks>
|
|
||||||
<providerNetwork name="group0-data1" />
|
|
||||||
</providerNetworks>
|
|
||||||
<ipv4 mode="disabled"></ipv4>
|
|
||||||
<ipv6 mode="disabled"></ipv6>
|
|
||||||
</dataclassNetwork>
|
|
||||||
</networks>
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<ethernetInterface ifName="eth7" mtu="1500" >
|
|
||||||
<port name="eth7" pciAddress="0000:07:00.1" class="Ethernet controller" device="82599ES 10-Gigabit SFI/SFP+ Network Connection" />
|
|
||||||
</ethernetInterface>
|
|
||||||
|
|
||||||
<!--A vlan interface is defined with:
|
|
||||||
ifName, name of the vlan
|
|
||||||
interface, name of an Ethernet or an aggregrated Ethernet interface on which to run the vlan
|
|
||||||
vlanId, vlan id, valid value between 1 and 4094
|
|
||||||
mtu, mtu of the vlan interface-->
|
|
||||||
<vlanInterface ifName="cluster0" interface="eth4" vlanId="303" mtu="1500">
|
|
||||||
<!--A vlanInterface can be defined as data, cluster-host, oam, or mgmt networks by adding
|
|
||||||
the network type in the networks section.-->
|
|
||||||
<networks>
|
|
||||||
<clusterhostNetwork/>
|
|
||||||
</networks>
|
|
||||||
</vlanInterface>
|
|
||||||
|
|
||||||
<!--A aggregrated Ethernet interface is defined with:
|
|
||||||
ifName, name of the vlan
|
|
||||||
mtu, mtu of the vlan interface-->
|
|
||||||
<aeInterface ifName="ae0" mtu="1500">
|
|
||||||
<!--Aggregated Ethernet interface need to define 1 or more interfaces that it uses.
|
|
||||||
Add an interface used by this aeInterface by adding a interface section in the interfaces section,-->
|
|
||||||
<interfaces>
|
|
||||||
<!--An interface being used by the aggregrated ethernet interface. Identified by 'name'-->
|
|
||||||
<interface name="eth0"/>
|
|
||||||
<interface name="eth2" />
|
|
||||||
</interfaces>
|
|
||||||
<!--Specify one of the 3 valid aggregated Ethernet modes below-->
|
|
||||||
<aeMode>
|
|
||||||
<!--valid aggregated Ethernet mode values are:
|
|
||||||
activeStandby,
|
|
||||||
balanced, and
|
|
||||||
ieee802.3ad
|
|
||||||
txPolicy is required when ieee802.3ad or balanced is chosen. valid txPolicy values are:
|
|
||||||
layer3+4
|
|
||||||
layer2
|
|
||||||
layer2+3
|
|
||||||
-->
|
|
||||||
<ieee802.3ad txPolicy="layer3+4" />
|
|
||||||
</aeMode>
|
|
||||||
</aeInterface>
|
|
||||||
|
|
||||||
<vlanInterface ifName="vlan11" interface="ae0" vlanId="11" mtu="1600">
|
|
||||||
<networks>
|
|
||||||
<dataclassNetwork>
|
|
||||||
<!--This dataclassNetwork uses ip address pools. See ipv4 and ipv6 tag below
|
|
||||||
-->
|
|
||||||
<providerNetworks>
|
|
||||||
<providerNetwork name="group0-ext0" />
|
|
||||||
</providerNetworks>
|
|
||||||
<ipv4 mode="pool">
|
|
||||||
<!--pool needs to be specified with its name. The pool will not verified until the profile is applied
|
|
||||||
to a host.-->
|
|
||||||
<pool name="pool-1" />
|
|
||||||
</ipv4>
|
|
||||||
<ipv6 mode="pool">
|
|
||||||
<pool name="pool-2" />
|
|
||||||
</ipv6>
|
|
||||||
</dataclassNetwork>
|
|
||||||
</networks>
|
|
||||||
</vlanInterface>
|
|
||||||
</interfaceProfile>
|
|
||||||
</profiles>
|
|
@ -64,7 +64,6 @@ from sysinv.api.controllers.v1 import ntp
|
|||||||
from sysinv.api.controllers.v1 import partition
|
from sysinv.api.controllers.v1 import partition
|
||||||
from sysinv.api.controllers.v1 import pci_device
|
from sysinv.api.controllers.v1 import pci_device
|
||||||
from sysinv.api.controllers.v1 import port
|
from sysinv.api.controllers.v1 import port
|
||||||
from sysinv.api.controllers.v1 import profile
|
|
||||||
from sysinv.api.controllers.v1 import ptp
|
from sysinv.api.controllers.v1 import ptp
|
||||||
from sysinv.api.controllers.v1 import pv
|
from sysinv.api.controllers.v1 import pv
|
||||||
from sysinv.api.controllers.v1 import registry_image
|
from sysinv.api.controllers.v1 import registry_image
|
||||||
@ -135,9 +134,6 @@ class V1(base.APIBase):
|
|||||||
imemory = [link.Link]
|
imemory = [link.Link]
|
||||||
"Links to the imemory resource"
|
"Links to the imemory resource"
|
||||||
|
|
||||||
iprofile = [link.Link]
|
|
||||||
"Links to the iprofile resource"
|
|
||||||
|
|
||||||
iuser = [link.Link]
|
iuser = [link.Link]
|
||||||
"Links to the iuser resource"
|
"Links to the iuser resource"
|
||||||
|
|
||||||
@ -348,14 +344,6 @@ class V1(base.APIBase):
|
|||||||
bookmark=True)
|
bookmark=True)
|
||||||
]
|
]
|
||||||
|
|
||||||
v1.iprofile = [link.Link.make_link('self', pecan.request.host_url,
|
|
||||||
'iprofile', ''),
|
|
||||||
link.Link.make_link('bookmark',
|
|
||||||
pecan.request.host_url,
|
|
||||||
'iprofile', '',
|
|
||||||
bookmark=True)
|
|
||||||
]
|
|
||||||
|
|
||||||
v1.iinterfaces = [link.Link.make_link('self',
|
v1.iinterfaces = [link.Link.make_link('self',
|
||||||
pecan.request.host_url,
|
pecan.request.host_url,
|
||||||
'iinterfaces', ''),
|
'iinterfaces', ''),
|
||||||
@ -896,7 +884,6 @@ class Controller(rest.RestController):
|
|||||||
ipvs = pv.PVController()
|
ipvs = pv.PVController()
|
||||||
idisks = disk.DiskController()
|
idisks = disk.DiskController()
|
||||||
partitions = partition.PartitionController()
|
partitions = partition.PartitionController()
|
||||||
iprofile = profile.ProfileController()
|
|
||||||
iuser = user.UserController()
|
iuser = user.UserController()
|
||||||
idns = dns.DNSController()
|
idns = dns.DNSController()
|
||||||
intp = ntp.NTPController()
|
intp = ntp.NTPController()
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
@ -377,7 +377,6 @@ class CPUController(rest.RestController):
|
|||||||
# only allow patching allocated_function and capabilities
|
# only allow patching allocated_function and capabilities
|
||||||
# replace ihost_uuid and inode_uuid with corresponding
|
# replace ihost_uuid and inode_uuid with corresponding
|
||||||
patch_obj = jsonpatch.JsonPatch(patch)
|
patch_obj = jsonpatch.JsonPatch(patch)
|
||||||
from_profile = False
|
|
||||||
action = None
|
action = None
|
||||||
for p in patch_obj:
|
for p in patch_obj:
|
||||||
if p['path'] == '/ihost_uuid':
|
if p['path'] == '/ihost_uuid':
|
||||||
@ -395,9 +394,6 @@ class CPUController(rest.RestController):
|
|||||||
except exception.SysinvException:
|
except exception.SysinvException:
|
||||||
p['value'] = None
|
p['value'] = None
|
||||||
|
|
||||||
if p['path'] == '/allocated_function':
|
|
||||||
from_profile = True
|
|
||||||
|
|
||||||
if p['path'] == '/action':
|
if p['path'] == '/action':
|
||||||
value = p['value']
|
value = p['value']
|
||||||
patch.remove(p)
|
patch.remove(p)
|
||||||
@ -428,8 +424,7 @@ class CPUController(rest.RestController):
|
|||||||
# Semantic checks
|
# Semantic checks
|
||||||
ihost = pecan.request.dbapi.ihost_get(cpu.forihostid)
|
ihost = pecan.request.dbapi.ihost_get(cpu.forihostid)
|
||||||
_check_host(ihost)
|
_check_host(ihost)
|
||||||
if not from_profile:
|
_check_cpu(cpu, ihost)
|
||||||
_check_cpu(cpu, ihost)
|
|
||||||
|
|
||||||
# Update only the fields that have changed
|
# Update only the fields that have changed
|
||||||
try:
|
try:
|
||||||
@ -463,7 +458,7 @@ class CPUController(rest.RestController):
|
|||||||
##############
|
##############
|
||||||
# UTILS
|
# UTILS
|
||||||
##############
|
##############
|
||||||
def _update(cpu_uuid, cpu_values, from_profile=False):
|
def _update(cpu_uuid, cpu_values):
|
||||||
# Get CPU
|
# Get CPU
|
||||||
cpu = objects.cpu.get_by_uuid(
|
cpu = objects.cpu.get_by_uuid(
|
||||||
pecan.request.context, cpu_uuid)
|
pecan.request.context, cpu_uuid)
|
||||||
@ -471,8 +466,7 @@ def _update(cpu_uuid, cpu_values, from_profile=False):
|
|||||||
# Semantic checks
|
# Semantic checks
|
||||||
ihost = pecan.request.dbapi.ihost_get(cpu.forihostid)
|
ihost = pecan.request.dbapi.ihost_get(cpu.forihostid)
|
||||||
_check_host(ihost)
|
_check_host(ihost)
|
||||||
if not from_profile:
|
_check_cpu(cpu, ihost)
|
||||||
_check_cpu(cpu, ihost)
|
|
||||||
|
|
||||||
# Update cpu
|
# Update cpu
|
||||||
pecan.request.dbapi.icpu_update(cpu_uuid, cpu_values)
|
pecan.request.dbapi.icpu_update(cpu_uuid, cpu_values)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2013-2020 Wind River Systems, Inc.
|
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -26,100 +26,6 @@ VSWITCH_MIN_CORES = 0
|
|||||||
VSWITCH_MAX_CORES = 8
|
VSWITCH_MAX_CORES = 8
|
||||||
|
|
||||||
|
|
||||||
class CpuProfile(object):
|
|
||||||
class CpuConfigure(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.platform = 0
|
|
||||||
self.vswitch = 0
|
|
||||||
self.shared = 0
|
|
||||||
self.vms = 0
|
|
||||||
self.numa_node = 0
|
|
||||||
|
|
||||||
# cpus is a list of icpu sorted by numa_node, core and thread
|
|
||||||
# if not, provide a node list sorted by numa_node (id might not be reliable)
|
|
||||||
def __init__(self, cpus, nodes=None):
|
|
||||||
if nodes is not None:
|
|
||||||
cpus = CpuProfile.sort_cpu_by_numa_node(cpus, nodes)
|
|
||||||
cores = []
|
|
||||||
|
|
||||||
self.number_of_cpu = 0
|
|
||||||
self.cores_per_cpu = 0
|
|
||||||
self.hyper_thread = False
|
|
||||||
self.processors = []
|
|
||||||
cur_processor = None
|
|
||||||
|
|
||||||
for cpu in cpus:
|
|
||||||
key = '{0}-{1}'.format(cpu.numa_node, cpu.core)
|
|
||||||
if key not in cores:
|
|
||||||
cores.append(key)
|
|
||||||
else:
|
|
||||||
self.hyper_thread = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if cur_processor is None or cur_processor.numa_node != cpu.numa_node:
|
|
||||||
cur_processor = CpuProfile.CpuConfigure()
|
|
||||||
cur_processor.numa_node = cpu.numa_node
|
|
||||||
self.processors.append(cur_processor)
|
|
||||||
|
|
||||||
if cpu.allocated_function == constants.PLATFORM_FUNCTION:
|
|
||||||
cur_processor.platform += 1
|
|
||||||
elif cpu.allocated_function == constants.VSWITCH_FUNCTION:
|
|
||||||
cur_processor.vswitch += 1
|
|
||||||
elif cpu.allocated_function == constants.SHARED_FUNCTION:
|
|
||||||
cur_processor.shared += 1
|
|
||||||
elif cpu.allocated_function == constants.APPLICATION_FUNCTION:
|
|
||||||
cur_processor.vms += 1
|
|
||||||
|
|
||||||
self.number_of_cpu = len(self.processors)
|
|
||||||
self.cores_per_cpu = len(cores) // self.number_of_cpu
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def sort_cpu_by_numa_node(cpus, nodes):
|
|
||||||
newlist = []
|
|
||||||
for node in nodes:
|
|
||||||
for cpu in cpus:
|
|
||||||
if cpu.forinodeid == node.id:
|
|
||||||
cpu.numa_node = node.numa_node
|
|
||||||
newlist.append(cpu)
|
|
||||||
return newlist
|
|
||||||
|
|
||||||
|
|
||||||
class HostCpuProfile(CpuProfile):
|
|
||||||
def __init__(self, subfunctions, cpus, nodes=None):
|
|
||||||
super(HostCpuProfile, self).__init__(cpus, nodes)
|
|
||||||
self.subfunctions = subfunctions
|
|
||||||
|
|
||||||
# see if a cpu profile is applicable to this host
|
|
||||||
def profile_applicable(self, profile):
|
|
||||||
if self.number_of_cpu == profile.number_of_cpu and \
|
|
||||||
self.cores_per_cpu == profile.cores_per_cpu:
|
|
||||||
return self.check_profile_core_functions(profile)
|
|
||||||
return False # Profile is not applicable to host
|
|
||||||
|
|
||||||
def check_profile_core_functions(self, profile):
|
|
||||||
platform_cores = 0
|
|
||||||
vswitch_cores = 0
|
|
||||||
shared_cores = 0
|
|
||||||
vm_cores = 0
|
|
||||||
for cpu in profile.processors:
|
|
||||||
platform_cores += cpu.platform
|
|
||||||
vswitch_cores += cpu.vswitch
|
|
||||||
shared_cores += cpu.shared
|
|
||||||
vm_cores += cpu.vms
|
|
||||||
|
|
||||||
error_string = ""
|
|
||||||
if platform_cores == 0:
|
|
||||||
error_string = "There must be at least one core for %s." % \
|
|
||||||
constants.PLATFORM_FUNCTION
|
|
||||||
elif constants.WORKER in self.subfunctions and vswitch_cores == 0:
|
|
||||||
error_string = "There must be at least one core for %s." % \
|
|
||||||
constants.VSWITCH_FUNCTION
|
|
||||||
elif constants.WORKER in self.subfunctions and vm_cores == 0:
|
|
||||||
error_string = "There must be at least one core for %s." % \
|
|
||||||
constants.APPLICATION_FUNCTION
|
|
||||||
return error_string
|
|
||||||
|
|
||||||
|
|
||||||
def lookup_function(s):
|
def lookup_function(s):
|
||||||
for f in CORE_FUNCTIONS:
|
for f in CORE_FUNCTIONS:
|
||||||
if s.lower() == f.lower():
|
if s.lower() == f.lower():
|
||||||
@ -127,31 +33,6 @@ def lookup_function(s):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
|
|
||||||
def check_profile_core_functions(personality, profile):
|
|
||||||
|
|
||||||
platform_cores = 0
|
|
||||||
vswitch_cores = 0
|
|
||||||
shared_cores = 0
|
|
||||||
vm_cores = 0
|
|
||||||
for cpu in profile.processors:
|
|
||||||
platform_cores += cpu.platform
|
|
||||||
vswitch_cores += cpu.vswitch
|
|
||||||
shared_cores += cpu.shared
|
|
||||||
vm_cores += cpu.vms
|
|
||||||
|
|
||||||
error_string = ""
|
|
||||||
if platform_cores == 0:
|
|
||||||
error_string = "There must be at least one core for %s." % \
|
|
||||||
constants.PLATFORM_FUNCTION
|
|
||||||
elif constants.WORKER in personality and vswitch_cores == 0:
|
|
||||||
error_string = "There must be at least one core for %s." % \
|
|
||||||
constants.VSWITCH_FUNCTION
|
|
||||||
elif constants.WORKER in personality and vm_cores == 0:
|
|
||||||
error_string = "There must be at least one core for %s." % \
|
|
||||||
constants.APPLICATION_FUNCTION
|
|
||||||
return error_string
|
|
||||||
|
|
||||||
|
|
||||||
def check_core_functions(personality, icpus):
|
def check_core_functions(personality, icpus):
|
||||||
platform_cores = 0
|
platform_cores = 0
|
||||||
vswitch_cores = 0
|
vswitch_cores = 0
|
||||||
|
@ -67,7 +67,6 @@ from sysinv.api.controllers.v1 import lvg as lvg_api
|
|||||||
from sysinv.api.controllers.v1 import host_fs as host_fs_api
|
from sysinv.api.controllers.v1 import host_fs as host_fs_api
|
||||||
from sysinv.api.controllers.v1 import memory
|
from sysinv.api.controllers.v1 import memory
|
||||||
from sysinv.api.controllers.v1 import node as node_api
|
from sysinv.api.controllers.v1 import node as node_api
|
||||||
from sysinv.api.controllers.v1 import profile
|
|
||||||
from sysinv.api.controllers.v1 import pv as pv_api
|
from sysinv.api.controllers.v1 import pv as pv_api
|
||||||
from sysinv.api.controllers.v1 import sensor as sensor_api
|
from sysinv.api.controllers.v1 import sensor as sensor_api
|
||||||
from sysinv.api.controllers.v1 import sensorgroup
|
from sysinv.api.controllers.v1 import sensorgroup
|
||||||
@ -460,9 +459,6 @@ class Host(base.APIBase):
|
|||||||
isystem_uuid = types.uuid
|
isystem_uuid = types.uuid
|
||||||
"The UUID of the system this host belongs to"
|
"The UUID of the system this host belongs to"
|
||||||
|
|
||||||
iprofile_uuid = types.uuid
|
|
||||||
"The UUID of the iprofile to apply to host"
|
|
||||||
|
|
||||||
peers = types.MultiType({dict})
|
peers = types.MultiType({dict})
|
||||||
"This peers of this host in the cluster"
|
"This peers of this host in the cluster"
|
||||||
|
|
||||||
@ -567,9 +563,6 @@ class Host(base.APIBase):
|
|||||||
for k in self.fields:
|
for k in self.fields:
|
||||||
setattr(self, k, kwargs.get(k))
|
setattr(self, k, kwargs.get(k))
|
||||||
|
|
||||||
self.fields.append('iprofile_uuid')
|
|
||||||
setattr(self, 'iprofile_uuid', kwargs.get('iprofile_uuid', None))
|
|
||||||
|
|
||||||
self.fields.append('peers')
|
self.fields.append('peers')
|
||||||
setattr(self, 'peers', kwargs.get('peers', None))
|
setattr(self, 'peers', kwargs.get('peers', None))
|
||||||
|
|
||||||
@ -903,7 +896,6 @@ class HostUpdate(object):
|
|||||||
self.ihost_orig = dict(ihost_orig)
|
self.ihost_orig = dict(ihost_orig)
|
||||||
self.ihost_patch = dict(ihost_patch)
|
self.ihost_patch = dict(ihost_patch)
|
||||||
self._delta = list(delta)
|
self._delta = list(delta)
|
||||||
self._iprofile_uuid = None
|
|
||||||
self._ihost_val_prenotify = {}
|
self._ihost_val_prenotify = {}
|
||||||
self._ihost_val = {}
|
self._ihost_val = {}
|
||||||
|
|
||||||
@ -946,14 +938,6 @@ class HostUpdate(object):
|
|||||||
def nextstep(self, val):
|
def nextstep(self, val):
|
||||||
self._nextstep = val
|
self._nextstep = val
|
||||||
|
|
||||||
@property
|
|
||||||
def iprofile_uuid(self):
|
|
||||||
return self._iprofile_uuid
|
|
||||||
|
|
||||||
@iprofile_uuid.setter
|
|
||||||
def iprofile_uuid(self, val):
|
|
||||||
self._iprofile_uuid = val
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def configure_required(self):
|
def configure_required(self):
|
||||||
return self._configure_required
|
return self._configure_required
|
||||||
@ -1502,8 +1486,7 @@ class HostController(rest.RestController):
|
|||||||
pecan.request.context, ihost_dict['rootfs_device'])
|
pecan.request.context, ihost_dict['rootfs_device'])
|
||||||
controller_ihost = pecan.request.rpcapi.create_ihost(
|
controller_ihost = pecan.request.rpcapi.create_ihost(
|
||||||
pecan.request.context, ihost_dict)
|
pecan.request.context, ihost_dict)
|
||||||
if 'recordtype' in ihost_dict and \
|
if 'recordtype' in ihost_dict:
|
||||||
ihost_dict['recordtype'] != "profile":
|
|
||||||
pecan.request.rpcapi.configure_ihost(
|
pecan.request.rpcapi.configure_ihost(
|
||||||
pecan.request.context,
|
pecan.request.context,
|
||||||
controller_ihost)
|
controller_ihost)
|
||||||
@ -1756,8 +1739,7 @@ class HostController(rest.RestController):
|
|||||||
" contain(s) a management mac address"
|
" contain(s) a management mac address"
|
||||||
" from local network adapters")
|
" from local network adapters")
|
||||||
|
|
||||||
self._patch(ihost_obj[0]['uuid'],
|
self._patch(ihost_obj[0]['uuid'], changed_paths)
|
||||||
changed_paths, None)
|
|
||||||
else:
|
else:
|
||||||
self._do_post(new_host)
|
self._do_post(new_host)
|
||||||
|
|
||||||
@ -1829,34 +1811,28 @@ class HostController(rest.RestController):
|
|||||||
"""
|
"""
|
||||||
utils.validate_patch(patch)
|
utils.validate_patch(patch)
|
||||||
|
|
||||||
profile_uuid = None
|
|
||||||
optimizable = 0
|
optimizable = 0
|
||||||
optimize_list = ['/uptime', '/location', '/serialid', '/task']
|
optimize_list = ['/uptime', '/location', '/serialid', '/task']
|
||||||
for p in patch:
|
for p in patch:
|
||||||
# Check if this patch contains a profile
|
|
||||||
path = p['path']
|
path = p['path']
|
||||||
if path == '/iprofile_uuid':
|
|
||||||
profile_uuid = p['value']
|
|
||||||
patch.remove(p)
|
|
||||||
|
|
||||||
if path in optimize_list:
|
if path in optimize_list:
|
||||||
optimizable += 1
|
optimizable += 1
|
||||||
|
|
||||||
if len(patch) == optimizable:
|
if len(patch) == optimizable:
|
||||||
return self._patch(uuid, patch, profile_uuid)
|
return self._patch(uuid, patch)
|
||||||
elif (pecan.request.user_agent.startswith('mtce') or
|
elif (pecan.request.user_agent.startswith('mtce') or
|
||||||
pecan.request.user_agent.startswith('vim')):
|
pecan.request.user_agent.startswith('vim')):
|
||||||
return self._patch_sys(uuid, patch, profile_uuid)
|
return self._patch_sys(uuid, patch)
|
||||||
else:
|
else:
|
||||||
return self._patch_gen(uuid, patch, profile_uuid)
|
return self._patch_gen(uuid, patch)
|
||||||
|
|
||||||
@cutils.synchronized(LOCK_NAME_SYS)
|
@cutils.synchronized(LOCK_NAME_SYS)
|
||||||
def _patch_sys(self, uuid, patch, profile_uuid):
|
def _patch_sys(self, uuid, patch):
|
||||||
return self._patch(uuid, patch, profile_uuid)
|
return self._patch(uuid, patch)
|
||||||
|
|
||||||
@cutils.synchronized(LOCK_NAME)
|
@cutils.synchronized(LOCK_NAME)
|
||||||
def _patch_gen(self, uuid, patch, profile_uuid):
|
def _patch_gen(self, uuid, patch):
|
||||||
return self._patch(uuid, patch, profile_uuid)
|
return self._patch(uuid, patch)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _validate_capability_is_not_set(old, new):
|
def _validate_capability_is_not_set(old, new):
|
||||||
@ -1914,7 +1890,7 @@ class HostController(rest.RestController):
|
|||||||
"name={}, value={}. ").format(
|
"name={}, value={}. ").format(
|
||||||
capability, new_value))
|
capability, new_value))
|
||||||
|
|
||||||
def _patch(self, uuid, patch, myprofile_uuid):
|
def _patch(self, uuid, patch):
|
||||||
log_start = cutils.timestamped("ihost_patch_start")
|
log_start = cutils.timestamped("ihost_patch_start")
|
||||||
|
|
||||||
patch_obj = jsonpatch.JsonPatch(patch)
|
patch_obj = jsonpatch.JsonPatch(patch)
|
||||||
@ -2004,8 +1980,6 @@ class HostController(rest.RestController):
|
|||||||
hostupdate.notify_mtce,
|
hostupdate.notify_mtce,
|
||||||
hostupdate.skip_notify_mtce))
|
hostupdate.skip_notify_mtce))
|
||||||
|
|
||||||
hostupdate.iprofile_uuid = myprofile_uuid
|
|
||||||
|
|
||||||
if self.stage_action(myaction, hostupdate):
|
if self.stage_action(myaction, hostupdate):
|
||||||
LOG.info("%s Action staged: %s" %
|
LOG.info("%s Action staged: %s" %
|
||||||
(hostupdate.displayid, myaction))
|
(hostupdate.displayid, myaction))
|
||||||
@ -2409,13 +2383,6 @@ class HostController(rest.RestController):
|
|||||||
ihost = objects.host.get_by_uuid(pecan.request.context,
|
ihost = objects.host.get_by_uuid(pecan.request.context,
|
||||||
ihost_id)
|
ihost_id)
|
||||||
|
|
||||||
# Do not allow profiles to be deleted by system host-delete
|
|
||||||
if ihost['recordtype'] == "profile":
|
|
||||||
LOG.error("host %s of recordtype %s cannot be deleted via "
|
|
||||||
"host-delete command."
|
|
||||||
% (ihost['uuid'], ihost['recordtype']))
|
|
||||||
raise exception.HTTPNotFound
|
|
||||||
|
|
||||||
if ihost['administrative'] == constants.ADMIN_UNLOCKED:
|
if ihost['administrative'] == constants.ADMIN_UNLOCKED:
|
||||||
if ihost.hostname is None:
|
if ihost.hostname is None:
|
||||||
host = ihost.uuid
|
host = ihost.uuid
|
||||||
@ -4641,7 +4608,6 @@ class HostController(rest.RestController):
|
|||||||
constants.VIM_SERVICES_DISABLE_FAILED,
|
constants.VIM_SERVICES_DISABLE_FAILED,
|
||||||
constants.VIM_SERVICES_DISABLE_EXTEND,
|
constants.VIM_SERVICES_DISABLE_EXTEND,
|
||||||
constants.VIM_SERVICES_DELETE_FAILED,
|
constants.VIM_SERVICES_DELETE_FAILED,
|
||||||
constants.APPLY_PROFILE_ACTION,
|
|
||||||
constants.SUBFUNCTION_CONFIG_ACTION]
|
constants.SUBFUNCTION_CONFIG_ACTION]
|
||||||
|
|
||||||
if action not in valid_actions:
|
if action not in valid_actions:
|
||||||
@ -4727,8 +4693,6 @@ class HostController(rest.RestController):
|
|||||||
self.update_vim_progress_status(action, hostupdate)
|
self.update_vim_progress_status(action, hostupdate)
|
||||||
elif action == constants.VIM_SERVICES_DELETE_FAILED:
|
elif action == constants.VIM_SERVICES_DELETE_FAILED:
|
||||||
self.update_vim_progress_status(action, hostupdate)
|
self.update_vim_progress_status(action, hostupdate)
|
||||||
elif action == constants.APPLY_PROFILE_ACTION:
|
|
||||||
self._check_apply_profile(hostupdate)
|
|
||||||
elif action == constants.SUBFUNCTION_CONFIG_ACTION:
|
elif action == constants.SUBFUNCTION_CONFIG_ACTION:
|
||||||
self._check_subfunction_config(hostupdate)
|
self._check_subfunction_config(hostupdate)
|
||||||
self._semantic_check_nova_local_storage(
|
self._semantic_check_nova_local_storage(
|
||||||
@ -4783,20 +4747,6 @@ class HostController(rest.RestController):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _check_apply_profile(hostupdate):
|
|
||||||
ihost = hostupdate.ihost_orig
|
|
||||||
if (ihost['administrative'] == constants.ADMIN_UNLOCKED and
|
|
||||||
not utils.is_host_simplex_controller(ihost)):
|
|
||||||
raise wsme.exc.ClientSideError(
|
|
||||||
_("Can not apply profile to an 'unlocked' host %s; "
|
|
||||||
"Please 'Lock' first." % hostupdate.displayid))
|
|
||||||
|
|
||||||
if utils.get_system_mode() == constants.SYSTEM_MODE_SIMPLEX:
|
|
||||||
raise wsme.exc.ClientSideError(_(
|
|
||||||
"Applying a profile on a simplex system is not allowed."))
|
|
||||||
return True
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def check_notify_mtce(action, hostupdate):
|
def check_notify_mtce(action, hostupdate):
|
||||||
"""Determine whether mtce should be notified of this patch request
|
"""Determine whether mtce should be notified of this patch request
|
||||||
@ -6636,8 +6586,6 @@ class HostController(rest.RestController):
|
|||||||
self._handle_vim_services_delete_failed(hostupdate)
|
self._handle_vim_services_delete_failed(hostupdate)
|
||||||
hostupdate.nextstep = hostupdate.EXIT_UPDATE_PREVAL
|
hostupdate.nextstep = hostupdate.EXIT_UPDATE_PREVAL
|
||||||
rc = False
|
rc = False
|
||||||
elif action == constants.APPLY_PROFILE_ACTION:
|
|
||||||
self._stage_apply_profile_action(hostupdate)
|
|
||||||
elif action == constants.SUBFUNCTION_CONFIG_ACTION:
|
elif action == constants.SUBFUNCTION_CONFIG_ACTION:
|
||||||
# Not a mtc action; disable mtc checks and config
|
# Not a mtc action; disable mtc checks and config
|
||||||
self._stage_subfunction_config(hostupdate)
|
self._stage_subfunction_config(hostupdate)
|
||||||
@ -6655,18 +6603,6 @@ class HostController(rest.RestController):
|
|||||||
|
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _stage_apply_profile_action(hostupdate):
|
|
||||||
"""Stage apply profile action."""
|
|
||||||
LOG.info("%s _stage_apply_profile_action uuid=%s profile_uuid=%s" %
|
|
||||||
(hostupdate.displayid,
|
|
||||||
hostupdate.ihost_patch['uuid'],
|
|
||||||
hostupdate.iprofile_uuid))
|
|
||||||
profile.apply_profile(hostupdate.ihost_patch['uuid'],
|
|
||||||
hostupdate.iprofile_uuid)
|
|
||||||
hostupdate.notify_mtce = False
|
|
||||||
hostupdate.configure_required = False
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _check_subfunction_config(hostupdate):
|
def _check_subfunction_config(hostupdate):
|
||||||
"""Check subfunction config."""
|
"""Check subfunction config."""
|
||||||
|
@ -698,7 +698,7 @@ def _set_defaults(interface):
|
|||||||
return interface_merged
|
return interface_merged
|
||||||
|
|
||||||
|
|
||||||
def _check_interface_vlan_id(op, interface, ihost, from_profile=False):
|
def _check_interface_vlan_id(op, interface, ihost):
|
||||||
# Check vlan_id
|
# Check vlan_id
|
||||||
if 'vlan_id' in interface.keys() and interface['vlan_id'] is not None:
|
if 'vlan_id' in interface.keys() and interface['vlan_id'] is not None:
|
||||||
if not str(interface['vlan_id']).isdigit():
|
if not str(interface['vlan_id']).isdigit():
|
||||||
@ -712,7 +712,7 @@ def _check_interface_vlan_id(op, interface, ihost, from_profile=False):
|
|||||||
return interface
|
return interface
|
||||||
|
|
||||||
|
|
||||||
def _check_interface_name(op, interface, ihost, from_profile=False):
|
def _check_interface_name(op, interface, ihost):
|
||||||
ihost_id = interface['forihostid']
|
ihost_id = interface['forihostid']
|
||||||
ifname = interface['ifname']
|
ifname = interface['ifname']
|
||||||
iftype = interface['iftype']
|
iftype = interface['iftype']
|
||||||
@ -763,7 +763,7 @@ def _check_interface_name(op, interface, ihost, from_profile=False):
|
|||||||
return interface
|
return interface
|
||||||
|
|
||||||
|
|
||||||
def _check_interface_mtu(interface, ihost, from_profile=False):
|
def _check_interface_mtu(interface, ihost):
|
||||||
# Check imtu
|
# Check imtu
|
||||||
if 'imtu' in interface.keys() and interface['imtu'] is not None:
|
if 'imtu' in interface.keys() and interface['imtu'] is not None:
|
||||||
if not str(interface['imtu']).isdigit():
|
if not str(interface['imtu']).isdigit():
|
||||||
@ -774,7 +774,7 @@ def _check_interface_mtu(interface, ihost, from_profile=False):
|
|||||||
return interface
|
return interface
|
||||||
|
|
||||||
|
|
||||||
def _check_interface_sriov(interface, ihost, from_profile=False):
|
def _check_interface_sriov(interface, ihost):
|
||||||
sriov_update = False
|
sriov_update = False
|
||||||
|
|
||||||
if 'ifclass' in interface.keys() and not interface['ifclass']:
|
if 'ifclass' in interface.keys() and not interface['ifclass']:
|
||||||
@ -1116,7 +1116,7 @@ def _check_interface_data(op, interface, ihost, existing_interface,
|
|||||||
ihost_uuid = interface['ihost_uuid']
|
ihost_uuid = interface['ihost_uuid']
|
||||||
|
|
||||||
# Check interface name for validity
|
# Check interface name for validity
|
||||||
_check_interface_name(op, interface, ihost, existing_interface)
|
_check_interface_name(op, interface, ihost)
|
||||||
|
|
||||||
if op == "add":
|
if op == "add":
|
||||||
this_interface_id = 0
|
this_interface_id = 0
|
||||||
@ -1477,21 +1477,19 @@ def _allocate_pool_address(interface_id, pool_uuid, address_name=None):
|
|||||||
interface_id, pool_uuid, address_name)
|
interface_id, pool_uuid, address_name)
|
||||||
|
|
||||||
|
|
||||||
def _update_ipv6_address_mode(interface, mode=None, pool=None,
|
def _update_ipv6_address_mode(interface, mode=None, pool=None):
|
||||||
from_profile=False):
|
|
||||||
mode = interface['ipv6_mode'] if not mode else mode
|
mode = interface['ipv6_mode'] if not mode else mode
|
||||||
pool = interface['ipv6_pool'] if not pool else pool
|
pool = interface['ipv6_pool'] if not pool else pool
|
||||||
utils.update_address_mode(interface, constants.IPV6_FAMILY, mode, pool)
|
utils.update_address_mode(interface, constants.IPV6_FAMILY, mode, pool)
|
||||||
if mode == constants.IPV6_POOL and not from_profile:
|
if mode == constants.IPV6_POOL:
|
||||||
_allocate_pool_address(interface['id'], pool)
|
_allocate_pool_address(interface['id'], pool)
|
||||||
|
|
||||||
|
|
||||||
def _update_ipv4_address_mode(interface, mode=None, pool=None,
|
def _update_ipv4_address_mode(interface, mode=None, pool=None):
|
||||||
interface_profile=False):
|
|
||||||
mode = interface['ipv4_mode'] if not mode else mode
|
mode = interface['ipv4_mode'] if not mode else mode
|
||||||
pool = interface['ipv4_pool'] if not pool else pool
|
pool = interface['ipv4_pool'] if not pool else pool
|
||||||
utils.update_address_mode(interface, constants.IPV4_FAMILY, mode, pool)
|
utils.update_address_mode(interface, constants.IPV4_FAMILY, mode, pool)
|
||||||
if mode == constants.IPV4_POOL and not interface_profile:
|
if mode == constants.IPV4_POOL:
|
||||||
_allocate_pool_address(interface['id'], pool)
|
_allocate_pool_address(interface['id'], pool)
|
||||||
|
|
||||||
|
|
||||||
@ -1528,13 +1526,11 @@ def _add_extended_attributes(ihost, interface, attributes):
|
|||||||
if attributes.get('ipv4_mode'):
|
if attributes.get('ipv4_mode'):
|
||||||
_update_ipv4_address_mode(interface_data,
|
_update_ipv4_address_mode(interface_data,
|
||||||
attributes.get('ipv4_mode'),
|
attributes.get('ipv4_mode'),
|
||||||
attributes.get('ipv4_pool'),
|
attributes.get('ipv4_pool'))
|
||||||
attributes.get('interface_profile'))
|
|
||||||
if attributes.get('ipv6_mode'):
|
if attributes.get('ipv6_mode'):
|
||||||
_update_ipv6_address_mode(interface_data,
|
_update_ipv6_address_mode(interface_data,
|
||||||
attributes.get('ipv6_mode'),
|
attributes.get('ipv6_mode'),
|
||||||
attributes.get('ipv6_pool'),
|
attributes.get('ipv6_pool'))
|
||||||
attributes.get('interface_profile'))
|
|
||||||
|
|
||||||
|
|
||||||
def _update_ports(op, interface, ihost, ports):
|
def _update_ports(op, interface, ihost, ports):
|
||||||
@ -1728,13 +1724,13 @@ def update_upper_interface_macs(ihost, interface):
|
|||||||
|
|
||||||
|
|
||||||
# This method allows creating an interface through a non-HTTP
|
# This method allows creating an interface through a non-HTTP
|
||||||
# request e.g. through profile.py while still passing
|
# request while still passing through interface semantic checks and osd
|
||||||
# through interface semantic checks and osd configuration
|
# configuration
|
||||||
# Hence, not declared inside a class
|
# Hence, not declared inside a class
|
||||||
#
|
#
|
||||||
# Param:
|
# Param:
|
||||||
# interface - dictionary of interface values
|
# interface - dictionary of interface values
|
||||||
def _create(interface, from_profile=False):
|
def _create(interface):
|
||||||
# Get host
|
# Get host
|
||||||
ihostId = interface.get('forihostid') or interface.get('ihost_uuid')
|
ihostId = interface.get('forihostid') or interface.get('ihost_uuid')
|
||||||
ihost = pecan.request.dbapi.ihost_get(ihostId)
|
ihost = pecan.request.dbapi.ihost_get(ihostId)
|
||||||
@ -1776,21 +1772,19 @@ def _create(interface, from_profile=False):
|
|||||||
interface.update({'used_by': []})
|
interface.update({'used_by': []})
|
||||||
|
|
||||||
# Check mtu before setting defaults
|
# Check mtu before setting defaults
|
||||||
interface = _check_interface_mtu(interface, ihost, from_profile=from_profile)
|
interface = _check_interface_mtu(interface, ihost)
|
||||||
|
|
||||||
# Check vlan_id before setting defaults
|
# Check vlan_id before setting defaults
|
||||||
interface = _check_interface_vlan_id("add", interface, ihost, from_profile=from_profile)
|
interface = _check_interface_vlan_id("add", interface, ihost)
|
||||||
|
|
||||||
# Set defaults - before checks to allow for optional attributes
|
# Set defaults - before checks to allow for optional attributes
|
||||||
if not from_profile:
|
interface = _set_defaults(interface)
|
||||||
interface = _set_defaults(interface)
|
|
||||||
|
|
||||||
# Semantic checks
|
# Semantic checks
|
||||||
interface = _check("add", interface, ports=ports, ifaces=uses_if, from_profile=from_profile)
|
interface = _check("add", interface, ports=ports, ifaces=uses_if)
|
||||||
|
|
||||||
if not from_profile:
|
# Select appropriate MAC address from lower interface(s)
|
||||||
# Select appropriate MAC address from lower interface(s)
|
interface = set_interface_mac(ihost, interface)
|
||||||
interface = set_interface_mac(ihost, interface)
|
|
||||||
|
|
||||||
new_interface = pecan.request.dbapi.iinterface_create(
|
new_interface = pecan.request.dbapi.iinterface_create(
|
||||||
forihostid,
|
forihostid,
|
||||||
@ -1845,8 +1839,8 @@ def _create(interface, from_profile=False):
|
|||||||
return new_interface
|
return new_interface
|
||||||
|
|
||||||
|
|
||||||
def _check(op, interface, ports=None, ifaces=None, from_profile=False,
|
def _check(op, interface, ports=None, ifaces=None, existing_interface=None,
|
||||||
existing_interface=None, datanetworks=None):
|
datanetworks=None):
|
||||||
# Semantic checks
|
# Semantic checks
|
||||||
ihost = pecan.request.dbapi.ihost_get(interface['ihost_uuid']).as_dict()
|
ihost = pecan.request.dbapi.ihost_get(interface['ihost_uuid']).as_dict()
|
||||||
|
|
||||||
@ -1864,63 +1858,64 @@ def _check(op, interface, ports=None, ifaces=None, from_profile=False,
|
|||||||
|
|
||||||
if check_host:
|
if check_host:
|
||||||
_check_host(ihost)
|
_check_host(ihost)
|
||||||
if not from_profile:
|
|
||||||
if ports:
|
if ports:
|
||||||
_check_ports(op, interface, ihost, ports)
|
_check_ports(op, interface, ihost, ports)
|
||||||
if ifaces:
|
|
||||||
interfaces = pecan.request.dbapi.iinterface_get_by_ihost(interface['ihost_uuid'])
|
if ifaces:
|
||||||
if len(ifaces) > 1 and \
|
interfaces = pecan.request.dbapi.iinterface_get_by_ihost(interface['ihost_uuid'])
|
||||||
interface['iftype'] == constants.INTERFACE_TYPE_VLAN:
|
if len(ifaces) > 1 and \
|
||||||
# Can only have one interface associated to vlan interface type
|
interface['iftype'] == constants.INTERFACE_TYPE_VLAN:
|
||||||
|
# Can only have one interface associated to vlan interface type
|
||||||
|
raise wsme.exc.ClientSideError(
|
||||||
|
_("Can only have one interface for vlan type. (%s)" % ifaces))
|
||||||
|
if interface['iftype'] == constants.INTERFACE_TYPE_ETHERNET:
|
||||||
|
if len(ifaces) > 1:
|
||||||
raise wsme.exc.ClientSideError(
|
raise wsme.exc.ClientSideError(
|
||||||
_("Can only have one interface for vlan type. (%s)" % ifaces))
|
_("Can only have one lower interface for ethernet type."
|
||||||
if interface['iftype'] == constants.INTERFACE_TYPE_ETHERNET:
|
"(%s)" % ifaces))
|
||||||
if len(ifaces) > 1:
|
lower = pecan.request.dbapi.iinterface_get(ifaces[0],
|
||||||
raise wsme.exc.ClientSideError(
|
interface['ihost_uuid'])
|
||||||
_("Can only have one lower interface for ethernet type."
|
if not (lower['iftype'] == constants.INTERFACE_TYPE_ETHERNET
|
||||||
"(%s)" % ifaces))
|
and lower['ifclass'] ==
|
||||||
lower = pecan.request.dbapi.iinterface_get(ifaces[0],
|
constants.INTERFACE_CLASS_PCI_SRIOV):
|
||||||
interface['ihost_uuid'])
|
# Can only have pci_sriov ethernet type lower interface
|
||||||
if not (lower['iftype'] == constants.INTERFACE_TYPE_ETHERNET
|
# associated to ethernet interface type
|
||||||
and lower['ifclass'] ==
|
raise wsme.exc.ClientSideError(
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV):
|
_("Can only use pci-sriov ethernet interface for "
|
||||||
# Can only have pci_sriov ethernet type lower interface
|
"ethernet type. (%s)" % ifaces))
|
||||||
# associated to ethernet interface type
|
|
||||||
raise wsme.exc.ClientSideError(
|
|
||||||
_("Can only use pci-sriov ethernet interface for "
|
|
||||||
"ethernet type. (%s)" % ifaces))
|
|
||||||
|
|
||||||
for i in ifaces:
|
for i in ifaces:
|
||||||
for iface in interfaces:
|
for iface in interfaces:
|
||||||
if iface['uuid'] == i or iface['ifname'] == i:
|
if iface['uuid'] == i or iface['ifname'] == i:
|
||||||
existing_iface = copy.deepcopy(iface)
|
existing_iface = copy.deepcopy(iface)
|
||||||
|
|
||||||
# Get host
|
# Get host
|
||||||
ihost = pecan.request.dbapi.ihost_get(
|
ihost = pecan.request.dbapi.ihost_get(
|
||||||
iface.get('forihostid'))
|
iface.get('forihostid'))
|
||||||
|
|
||||||
if 'vlan_id' not in iface:
|
if 'vlan_id' not in iface:
|
||||||
iface['vlan_id'] = None
|
iface['vlan_id'] = None
|
||||||
|
|
||||||
if 'aemode' not in iface:
|
if 'aemode' not in iface:
|
||||||
iface['aemode'] = None
|
iface['aemode'] = None
|
||||||
|
|
||||||
if 'txhashpolicy' not in iface:
|
if 'txhashpolicy' not in iface:
|
||||||
iface['txhashpolicy'] = None
|
iface['txhashpolicy'] = None
|
||||||
|
|
||||||
if 'primary_reselect' not in iface:
|
if 'primary_reselect' not in iface:
|
||||||
iface['primary_reselect'] = None
|
iface['primary_reselect'] = None
|
||||||
|
|
||||||
_check_interface_data(
|
_check_interface_data(
|
||||||
"modify", iface, ihost, existing_iface, datanetworks)
|
"modify", iface, ihost, existing_iface, datanetworks)
|
||||||
|
|
||||||
interface = _check_interface_data(
|
interface = _check_interface_data(
|
||||||
op, interface, ihost, existing_interface, datanetworks)
|
op, interface, ihost, existing_interface, datanetworks)
|
||||||
|
|
||||||
return interface
|
return interface
|
||||||
|
|
||||||
|
|
||||||
def _update(interface_uuid, interface_values, from_profile):
|
def _update(interface_uuid, interface_values):
|
||||||
return objects.interface.get_by_uuid(pecan.request.context, interface_uuid)
|
return objects.interface.get_by_uuid(pecan.request.context, interface_uuid)
|
||||||
|
|
||||||
|
|
||||||
@ -1968,21 +1963,20 @@ def _clear_interface_state_fault(hostname, interface_uuid):
|
|||||||
FM.clear_fault(fm_constants.FM_ALARM_ID_NETWORK_INTERFACE, entity_instance_id)
|
FM.clear_fault(fm_constants.FM_ALARM_ID_NETWORK_INTERFACE, entity_instance_id)
|
||||||
|
|
||||||
|
|
||||||
def _delete(interface, from_profile=False):
|
def _delete(interface):
|
||||||
ihost = pecan.request.dbapi.ihost_get(interface['forihostid']).as_dict()
|
ihost = pecan.request.dbapi.ihost_get(interface['forihostid']).as_dict()
|
||||||
|
|
||||||
if not from_profile:
|
check_host = True
|
||||||
check_host = True
|
if (cutils.is_aio_simplex_system(pecan.request.dbapi)
|
||||||
if (cutils.is_aio_simplex_system(pecan.request.dbapi)
|
and interface['ifclass'] == constants.INTERFACE_CLASS_PCI_SRIOV
|
||||||
and interface['ifclass'] == constants.INTERFACE_CLASS_PCI_SRIOV
|
and interface['iftype'] == constants.INTERFACE_TYPE_VF):
|
||||||
and interface['iftype'] == constants.INTERFACE_TYPE_VF):
|
# user can delete interface SR-IOV VF without host lock in AIO-SX
|
||||||
# user can delete interface SR-IOV VF without host lock in AIO-SX
|
check_host = False
|
||||||
check_host = False
|
|
||||||
|
|
||||||
if check_host:
|
if check_host:
|
||||||
_check_host(ihost)
|
_check_host(ihost)
|
||||||
|
|
||||||
if not from_profile and interface['iftype'] == 'ethernet' and not interface['uses']:
|
if interface['iftype'] == 'ethernet' and not interface['uses']:
|
||||||
msg = _("Cannot delete a system created ethernet interface")
|
msg = _("Cannot delete a system created ethernet interface")
|
||||||
raise wsme.exc.ClientSideError(msg)
|
raise wsme.exc.ClientSideError(msg)
|
||||||
|
|
||||||
@ -2075,3 +2069,5 @@ def _is_interface_address_allowed(interface):
|
|||||||
elif interface['ifclass'] == constants.INTERFACE_CLASS_PLATFORM:
|
elif interface['ifclass'] == constants.INTERFACE_CLASS_PLATFORM:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# TODO (pbovina): Move utils methods within InterfaceController class
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2018 Wind River Systems, Inc.
|
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -175,26 +175,25 @@ class InterfaceNetworkController(rest.RestController):
|
|||||||
constants.IPV4_DISABLED, None)
|
constants.IPV4_DISABLED, None)
|
||||||
|
|
||||||
# Assign an address to the interface
|
# Assign an address to the interface
|
||||||
if host.recordtype != "profile":
|
_update_host_address(host, interface_obj, network_type)
|
||||||
_update_host_address(host, interface_obj, network_type)
|
if network_type == constants.NETWORK_TYPE_MGMT:
|
||||||
if network_type == constants.NETWORK_TYPE_MGMT:
|
ethernet_port_mac = None
|
||||||
ethernet_port_mac = None
|
if not interface_obj.uses:
|
||||||
if not interface_obj.uses:
|
# Get the ethernet port associated with the interface
|
||||||
# Get the ethernet port associated with the interface
|
interface_ports = pecan.request.dbapi.ethernet_port_get_by_interface(
|
||||||
interface_ports = pecan.request.dbapi.ethernet_port_get_by_interface(
|
interface_obj.uuid)
|
||||||
interface_obj.uuid)
|
for p in interface_ports:
|
||||||
for p in interface_ports:
|
if p is not None:
|
||||||
if p is not None:
|
ethernet_port_mac = p.mac
|
||||||
ethernet_port_mac = p.mac
|
break
|
||||||
break
|
else:
|
||||||
else:
|
tmp_interface = interface_obj.as_dict()
|
||||||
tmp_interface = interface_obj.as_dict()
|
ethernet_port_mac = tmp_interface['imac']
|
||||||
ethernet_port_mac = tmp_interface['imac']
|
_update_host_mgmt_mac(host, ethernet_port_mac)
|
||||||
_update_host_mgmt_mac(host, ethernet_port_mac)
|
cutils.perform_distributed_cloud_config(pecan.request.dbapi,
|
||||||
cutils.perform_distributed_cloud_config(pecan.request.dbapi,
|
|
||||||
interface_id)
|
interface_id)
|
||||||
elif network_type == constants.NETWORK_TYPE_OAM:
|
elif network_type == constants.NETWORK_TYPE_OAM:
|
||||||
pecan.request.rpcapi.initialize_oam_config(pecan.request.context, host)
|
pecan.request.rpcapi.initialize_oam_config(pecan.request.context, host)
|
||||||
|
|
||||||
return InterfaceNetwork.convert_with_links(result)
|
return InterfaceNetwork.convert_with_links(result)
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2020 Wind River Systems, Inc.
|
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|
||||||
import jsonpatch
|
import jsonpatch
|
||||||
@ -590,7 +590,7 @@ def _check(op, lvg):
|
|||||||
return lvg
|
return lvg
|
||||||
|
|
||||||
|
|
||||||
def _create(lvg, iprofile=None, applyprofile=None):
|
def _create(lvg):
|
||||||
# Get host
|
# Get host
|
||||||
ihostId = lvg.get('forihostid') or lvg.get('ihost_uuid')
|
ihostId = lvg.get('forihostid') or lvg.get('ihost_uuid')
|
||||||
ihost = pecan.request.dbapi.ihost_get(ihostId)
|
ihost = pecan.request.dbapi.ihost_get(ihostId)
|
||||||
@ -611,48 +611,41 @@ def _create(lvg, iprofile=None, applyprofile=None):
|
|||||||
# See if this volume group already exists
|
# See if this volume group already exists
|
||||||
ilvgs = pecan.request.dbapi.ilvg_get_all(forihostid=forihostid)
|
ilvgs = pecan.request.dbapi.ilvg_get_all(forihostid=forihostid)
|
||||||
lvg_in_db = False
|
lvg_in_db = False
|
||||||
if not iprofile:
|
for vg in ilvgs:
|
||||||
for vg in ilvgs:
|
if vg['lvm_vg_name'] == lvg['lvm_vg_name']:
|
||||||
if vg['lvm_vg_name'] == lvg['lvm_vg_name']:
|
lvg_in_db = True
|
||||||
lvg_in_db = True
|
# User is adding again so complain
|
||||||
# User is adding again so complain
|
if (vg['vg_state'] == constants.LVG_ADD or
|
||||||
if (vg['vg_state'] == constants.LVG_ADD or
|
vg['vg_state'] == constants.PROVISIONED):
|
||||||
vg['vg_state'] == constants.PROVISIONED):
|
raise wsme.exc.ClientSideError(_("Volume Group (%s) "
|
||||||
raise wsme.exc.ClientSideError(_("Volume Group (%s) "
|
"already present" %
|
||||||
"already present" %
|
vg['lvm_vg_name']))
|
||||||
vg['lvm_vg_name']))
|
|
||||||
|
|
||||||
# Prevent re-adding so that we don't end up in a state where
|
# Prevent re-adding so that we don't end up in a state where
|
||||||
# the cloud admin has removed a subset of the PVs rendering the
|
# the cloud admin has removed a subset of the PVs rendering the
|
||||||
# VG as unusable because of LV corruption
|
# VG as unusable because of LV corruption
|
||||||
if vg['vg_state'] == constants.LVG_DEL:
|
if vg['vg_state'] == constants.LVG_DEL:
|
||||||
# User changed mind and is re-adding
|
# User changed mind and is re-adding
|
||||||
values = {'vg_state': constants.LVG_ADD}
|
values = {'vg_state': constants.LVG_ADD}
|
||||||
if applyprofile:
|
try:
|
||||||
# inherit the capabilities,
|
LOG.info("Update ilvg values: %s" % values)
|
||||||
if 'capabilities' in lvg and lvg['capabilities']:
|
pecan.request.dbapi.ilvg_update(vg.id, values)
|
||||||
values['capabilities'] = lvg['capabilities']
|
except exception.HTTPNotFound:
|
||||||
|
msg = _("LVG update failed: host (%s) LVG (%s)"
|
||||||
try:
|
% (ihost['hostname'], vg['lvm_pv_name']))
|
||||||
LOG.info("Update ilvg values: %s" % values)
|
raise wsme.exc.ClientSideError(msg)
|
||||||
pecan.request.dbapi.ilvg_update(vg.id, values)
|
ret_lvg = vg
|
||||||
except exception.HTTPNotFound:
|
break
|
||||||
msg = _("LVG update failed: host (%s) LVG (%s)"
|
|
||||||
% (ihost['hostname'], vg['lvm_pv_name']))
|
|
||||||
raise wsme.exc.ClientSideError(msg)
|
|
||||||
ret_lvg = vg
|
|
||||||
break
|
|
||||||
|
|
||||||
if not lvg_in_db:
|
if not lvg_in_db:
|
||||||
# Add the default volume group parameters
|
# Add the default volume group parameters
|
||||||
if lvg['lvm_vg_name'] == constants.LVG_CINDER_VOLUMES and not iprofile:
|
if lvg['lvm_vg_name'] == constants.LVG_CINDER_VOLUMES:
|
||||||
lvg_caps = lvg['capabilities']
|
lvg_caps = lvg['capabilities']
|
||||||
|
|
||||||
if (constants.LVG_CINDER_PARAM_LVM_TYPE in lvg_caps) or applyprofile:
|
if (constants.LVG_CINDER_PARAM_LVM_TYPE in lvg_caps):
|
||||||
# defined from create or inherit the capabilities
|
# defined from create or inherit the capabilities
|
||||||
LOG.info("%s defined from create %s applyprofile=%s" %
|
LOG.info("%s defined from create %s" %
|
||||||
(constants.LVG_CINDER_PARAM_LVM_TYPE, lvg_caps,
|
(constants.LVG_CINDER_PARAM_LVM_TYPE, lvg_caps))
|
||||||
applyprofile))
|
|
||||||
else:
|
else:
|
||||||
# Default LVM type
|
# Default LVM type
|
||||||
lvg_caps_dict = {
|
lvg_caps_dict = {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2017-2018 Wind River Systems, Inc.
|
# Copyright (c) 2017-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -630,7 +630,7 @@ def _semantic_checks(operation, partition):
|
|||||||
return partition
|
return partition
|
||||||
|
|
||||||
|
|
||||||
def _create(partition, iprofile=None, applyprofile=None):
|
def _create(partition):
|
||||||
# Reject operation if we are upgrading the system.
|
# Reject operation if we are upgrading the system.
|
||||||
ihostid = partition.get('forihostid') or partition.get('ihost_uuid')
|
ihostid = partition.get('forihostid') or partition.get('ihost_uuid')
|
||||||
ihost = pecan.request.dbapi.ihost_get(ihostid)
|
ihost = pecan.request.dbapi.ihost_get(ihostid)
|
||||||
@ -653,8 +653,7 @@ def _create(partition, iprofile=None, applyprofile=None):
|
|||||||
|
|
||||||
# Set the status of the new partition
|
# Set the status of the new partition
|
||||||
if (ihost.invprovision in [constants.PROVISIONED,
|
if (ihost.invprovision in [constants.PROVISIONED,
|
||||||
constants.PROVISIONING] and
|
constants.PROVISIONING]):
|
||||||
not iprofile):
|
|
||||||
partition['status'] = constants.PARTITION_CREATE_IN_SVC_STATUS
|
partition['status'] = constants.PARTITION_CREATE_IN_SVC_STATUS
|
||||||
else:
|
else:
|
||||||
partition['status'] = constants.PARTITION_CREATE_ON_UNLOCK_STATUS
|
partition['status'] = constants.PARTITION_CREATE_ON_UNLOCK_STATUS
|
||||||
@ -678,8 +677,7 @@ def _create(partition, iprofile=None, applyprofile=None):
|
|||||||
# - PROVISIONING: AIO (after config_controller) and before worker
|
# - PROVISIONING: AIO (after config_controller) and before worker
|
||||||
# configuration
|
# configuration
|
||||||
if (ihost.invprovision in [constants.PROVISIONED,
|
if (ihost.invprovision in [constants.PROVISIONED,
|
||||||
constants.PROVISIONING] and
|
constants.PROVISIONING]):
|
||||||
not iprofile):
|
|
||||||
# Instruct puppet to implement the change
|
# Instruct puppet to implement the change
|
||||||
pecan.request.rpcapi.update_partition_config(pecan.request.context,
|
pecan.request.rpcapi.update_partition_config(pecan.request.context,
|
||||||
partition)
|
partition)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,409 +0,0 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
|
|
||||||
import netaddr
|
|
||||||
import six
|
|
||||||
|
|
||||||
from oslo_log import log
|
|
||||||
from sysinv._i18n import _
|
|
||||||
from sysinv.common import constants
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class InvalidProfileData(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Network(object):
|
|
||||||
def __init__(self, node, networkType):
|
|
||||||
self.networkType = networkType
|
|
||||||
self.providerNetworks = []
|
|
||||||
|
|
||||||
providerNetworksNode = node.find('providerNetworks')
|
|
||||||
if providerNetworksNode:
|
|
||||||
for pnetNode in providerNetworksNode.findall('providerNetwork'):
|
|
||||||
pnetName = pnetNode.get('name')
|
|
||||||
self.addProviderNetwork(pnetName)
|
|
||||||
|
|
||||||
def addProviderNetwork(self, pnet):
|
|
||||||
if pnet not in self.providerNetworks:
|
|
||||||
self.providerNetworks.append(pnet)
|
|
||||||
# ignore if provider network is duplicated within one interface
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
if len(self.providerNetworks) == 0:
|
|
||||||
# caller will do the translation
|
|
||||||
raise InvalidProfileData("At least one provider network must be selected.")
|
|
||||||
|
|
||||||
|
|
||||||
class DataclassNetwork(Network):
|
|
||||||
def __init__(self, node):
|
|
||||||
|
|
||||||
super(DataclassNetwork, self).__init__(node, constants.NETWORK_TYPE_DATA)
|
|
||||||
self.ipv4Mode = DataclassNetwork.getIpMode(node, "ipv4")
|
|
||||||
self.ipv6Mode = DataclassNetwork.getIpMode(node, "ipv6")
|
|
||||||
self.routes = DataclassNetwork.getRoutes(node)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def getRoutes(node):
|
|
||||||
routesNode = node.find('routes')
|
|
||||||
if routesNode is None:
|
|
||||||
return []
|
|
||||||
|
|
||||||
routes = []
|
|
||||||
for routeNode in routesNode.findall('route'):
|
|
||||||
route = {}
|
|
||||||
route['metric'] = int(routeNode.get('metric'))
|
|
||||||
network = routeNode.get('network')
|
|
||||||
gateway = routeNode.get('gateway')
|
|
||||||
|
|
||||||
try:
|
|
||||||
addr = netaddr.IPAddress(gateway)
|
|
||||||
except netaddr.core.AddrFormatError:
|
|
||||||
raise InvalidProfileData(_('%s is not a valid IP address') % gateway)
|
|
||||||
|
|
||||||
try:
|
|
||||||
net = netaddr.IPNetwork(network)
|
|
||||||
except netaddr.core.AddrFormatError:
|
|
||||||
raise InvalidProfileData(_('%s is not a valid network') % network)
|
|
||||||
|
|
||||||
if addr.format() != gateway:
|
|
||||||
raise InvalidProfileData(_('%s is not a valid IP address') % gateway)
|
|
||||||
|
|
||||||
if net.version != addr.version:
|
|
||||||
raise InvalidProfileData(_('network "%s" and gateway "%s" must be the same version.') %
|
|
||||||
(network, gateway))
|
|
||||||
|
|
||||||
route['network'] = net.network.format()
|
|
||||||
route['prefix'] = net.prefixlen
|
|
||||||
route['gateway'] = gateway
|
|
||||||
route['family'] = net.version
|
|
||||||
|
|
||||||
routes.append(route)
|
|
||||||
return routes
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def getIpMode(node, name):
|
|
||||||
modeNode = node.find(name)
|
|
||||||
if modeNode is None:
|
|
||||||
raise InvalidProfileData(_('%s is required for a datanetwork') % name)
|
|
||||||
|
|
||||||
mode = modeNode.get('mode')
|
|
||||||
pool = None
|
|
||||||
if mode == 'pool':
|
|
||||||
poolNode = modeNode.find('pool')
|
|
||||||
if poolNode is None:
|
|
||||||
raise InvalidProfileData(_('A pool is required for a %s defined as "pool"') % name)
|
|
||||||
|
|
||||||
pool = poolNode.get('name')
|
|
||||||
|
|
||||||
return {'mode': mode, 'pool': pool}
|
|
||||||
|
|
||||||
|
|
||||||
class ExternalNetwork(object):
|
|
||||||
def __init__(self, node, networktype):
|
|
||||||
self.networkType = networktype
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class PciPassthrough(Network):
|
|
||||||
def __init__(self, node):
|
|
||||||
super(PciPassthrough, self).__init__(node, constants.NETWORK_TYPE_PCI_PASSTHROUGH)
|
|
||||||
|
|
||||||
|
|
||||||
class PciSriov(Network):
|
|
||||||
def __init__(self, node):
|
|
||||||
super(PciSriov, self).__init__(node, constants.NETWORK_TYPE_PCI_SRIOV)
|
|
||||||
self.virtualFunctions = int(node.get('virtualFunctions'))
|
|
||||||
self.virtualFunctionDriver = node.get('virtualFunctionDriver')
|
|
||||||
self.maxTxRate = node.get('maxTxRate')
|
|
||||||
|
|
||||||
|
|
||||||
class Interface(object):
|
|
||||||
def __init__(self, ifNode):
|
|
||||||
|
|
||||||
self.providerNetworks = []
|
|
||||||
self.networks = []
|
|
||||||
self.name = ifNode.get('ifName')
|
|
||||||
self.mtu = ifNode.get('mtu')
|
|
||||||
self.ipv4Mode = {'mode': None, 'pool': None}
|
|
||||||
self.ipv6Mode = {'mode': None, 'pool': None}
|
|
||||||
self.routes = []
|
|
||||||
self.virtualFunctions = 0
|
|
||||||
self.virtualFunctionDriver = None
|
|
||||||
self.maxTxRate = None
|
|
||||||
networksNode = ifNode.find('networks')
|
|
||||||
if networksNode is not None:
|
|
||||||
for netNode in networksNode:
|
|
||||||
self.addNetwork(netNode)
|
|
||||||
|
|
||||||
def getNetworkMap(self):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def addNetwork(self, node):
|
|
||||||
tag = node.tag
|
|
||||||
networkMap = self.getNetworkMap()
|
|
||||||
if tag in networkMap:
|
|
||||||
network = networkMap[tag](node)
|
|
||||||
self.networks.append(network)
|
|
||||||
if network.networkType == constants.NETWORK_TYPE_DATA:
|
|
||||||
self.ipv4Mode = network.ipv4Mode
|
|
||||||
self.ipv6Mode = network.ipv6Mode
|
|
||||||
self.routes = network.routes
|
|
||||||
elif network.networkType == constants.NETWORK_TYPE_PCI_SRIOV:
|
|
||||||
self.virtualFunctions = network.virtualFunctions
|
|
||||||
self.virtualFunctionDriver = network.virtualFunctionDriver
|
|
||||||
self.maxTxRate = network.maxTxRate
|
|
||||||
|
|
||||||
if isinstance(network, Network):
|
|
||||||
self.providerNetworks = network.providerNetworks
|
|
||||||
|
|
||||||
else:
|
|
||||||
raise InvalidProfileData(_('network type (%s) not recognizable') % tag)
|
|
||||||
|
|
||||||
def validate(self):
|
|
||||||
# raise InvalidProfileData exception with detail msg
|
|
||||||
numberOfNetworks = len(self.networks)
|
|
||||||
|
|
||||||
if numberOfNetworks > 2:
|
|
||||||
raise InvalidProfileData(_('Too many network types selected for the interface.'))
|
|
||||||
|
|
||||||
# when change, make sure modify the displayText as well
|
|
||||||
combineTypes = [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_CLUSTER_HOST]
|
|
||||||
displayText = _('Only mgmt and cluster-host network types can be combined on a single interface')
|
|
||||||
if numberOfNetworks == 2:
|
|
||||||
if self.networks[0].networkType not in combineTypes or \
|
|
||||||
self.networks[1].networkType not in combineTypes:
|
|
||||||
raise InvalidProfileData(displayText)
|
|
||||||
|
|
||||||
if self.networks[0].networkType == self.networks[1].networkType:
|
|
||||||
raise InvalidProfileData(_('Interface can not combine with 2 networks with the same type.'))
|
|
||||||
|
|
||||||
try:
|
|
||||||
for network in self.networks:
|
|
||||||
network.validate()
|
|
||||||
except InvalidProfileData as e:
|
|
||||||
raise InvalidProfileData(_(six.text_type(e) + ' Interface: %s') % self.name)
|
|
||||||
|
|
||||||
def getNetworks(self):
|
|
||||||
pnets = ''
|
|
||||||
networkTypes = ''
|
|
||||||
hasNT = False
|
|
||||||
for network in self.networks:
|
|
||||||
if network.networkType is None:
|
|
||||||
continue
|
|
||||||
|
|
||||||
hasNT = True
|
|
||||||
if networkTypes:
|
|
||||||
networkTypes += ','
|
|
||||||
networkTypes = networkTypes + network.networkType
|
|
||||||
if hasattr(network, 'providerNetworks'):
|
|
||||||
# there should be only one network has providerNetwork
|
|
||||||
for pnet in network.providerNetworks:
|
|
||||||
if pnets:
|
|
||||||
pnets += ','
|
|
||||||
pnets = pnets + pnet
|
|
||||||
|
|
||||||
if not hasNT:
|
|
||||||
networkTypes = None
|
|
||||||
pnets = None
|
|
||||||
|
|
||||||
return networkTypes, pnets
|
|
||||||
|
|
||||||
|
|
||||||
class EthInterface(Interface):
|
|
||||||
def __init__(self, ifNode):
|
|
||||||
super(EthInterface, self).__init__(ifNode)
|
|
||||||
self.port, self.pciAddress, self.pclass, self.pdevice = self.getPort(ifNode)
|
|
||||||
|
|
||||||
def getPort(self, ifNode):
|
|
||||||
portNode = ifNode.find('port')
|
|
||||||
if portNode is None:
|
|
||||||
raise InvalidProfileData(_('Ethernet interface %s requires an Ethernet port ') %
|
|
||||||
ifNode.get('ifName'))
|
|
||||||
|
|
||||||
pciAddress = ''
|
|
||||||
tmp = portNode.get('pciAddress')
|
|
||||||
try:
|
|
||||||
pciAddress = EthInterface.formatPciAddress(tmp)
|
|
||||||
except InvalidProfileData as exc:
|
|
||||||
raise InvalidProfileData(six.text_type(exc) + _('Interface %s, pciAddress %s') %
|
|
||||||
(ifNode.get('ifName'), tmp))
|
|
||||||
|
|
||||||
pclass = portNode.get('class')
|
|
||||||
if pclass:
|
|
||||||
pclass = pclass.strip()
|
|
||||||
|
|
||||||
pdevice = portNode.get('device')
|
|
||||||
if pdevice:
|
|
||||||
pdevice = pdevice.strip()
|
|
||||||
|
|
||||||
return portNode.get('name'), pciAddress, pclass, pdevice
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def formatPciAddress(value):
|
|
||||||
# To parse a [X]:[X]:[X].[X] formatted pci address into [04x]:[02x]:[02x].[01x] pci address format
|
|
||||||
if value:
|
|
||||||
section_list1 = value.split(':')
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
if len(section_list1) != 3:
|
|
||||||
raise InvalidProfileData(_('pciAddress is not well formatted.'))
|
|
||||||
|
|
||||||
section_list2 = section_list1[2].split('.')
|
|
||||||
if len(section_list2) != 2:
|
|
||||||
raise InvalidProfileData(_('pciAddress is not well formatted.'))
|
|
||||||
|
|
||||||
try:
|
|
||||||
sec1 = int(section_list1[0], 16)
|
|
||||||
sec2 = int(section_list1[1], 16)
|
|
||||||
sec3 = int(section_list2[0], 16)
|
|
||||||
sec4 = int(section_list2[1], 16)
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
raise InvalidProfileData(_('pciAddress is not well formatted.'))
|
|
||||||
|
|
||||||
result = '{0:04x}:{1:02x}:{2:02x}.{3:01x}'.format(sec1, sec2, sec3, sec4)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def getNetworkMap(self):
|
|
||||||
return {
|
|
||||||
'dataclassNetwork': lambda node: DataclassNetwork(node),
|
|
||||||
'clusterhostNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_CLUSTER_HOST),
|
|
||||||
'oamNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_OAM),
|
|
||||||
'mgmtNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_MGMT),
|
|
||||||
'pciPassthrough': lambda node: PciPassthrough(node),
|
|
||||||
'pciSriov': lambda node: PciSriov(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class AeInterface(Interface):
|
|
||||||
def __init__(self, ifNode):
|
|
||||||
super(AeInterface, self).__init__(ifNode)
|
|
||||||
self.usesIf = []
|
|
||||||
aeModeNode = ifNode.find('aeMode') # aeMode is mandatory required by schema
|
|
||||||
node = aeModeNode[0] # it is mandatory required by schema
|
|
||||||
|
|
||||||
if node.tag == 'activeStandby':
|
|
||||||
self.aeMode = 'activeStandby'
|
|
||||||
self.txPolicy = None
|
|
||||||
self.primary_reselect = node.get('primary_reselect')
|
|
||||||
elif node.tag == 'balanced':
|
|
||||||
self.aeMode = 'balanced'
|
|
||||||
self.txPolicy = node.get('txPolicy')
|
|
||||||
self.primary_reselect = None
|
|
||||||
elif node.tag == 'ieee802.3ad':
|
|
||||||
self.aeMode = '802.3ad'
|
|
||||||
self.txPolicy = node.get('txPolicy')
|
|
||||||
self.primary_reselect = None
|
|
||||||
|
|
||||||
node = ifNode.find('interfaces')
|
|
||||||
if node:
|
|
||||||
for usesIfNode in node.findall('interface'):
|
|
||||||
self.addUsesIf(usesIfNode.get('name'))
|
|
||||||
|
|
||||||
def addUsesIf(self, ifName):
|
|
||||||
if not ifName:
|
|
||||||
raise InvalidProfileData(_('Interface name value cannot be empty.'))
|
|
||||||
if ifName == self.name:
|
|
||||||
raise InvalidProfileData(_('Aggregrated ethernet interface (%s) cannot use itself.') % self.name)
|
|
||||||
|
|
||||||
if ifName not in self.usesIf:
|
|
||||||
self.usesIf.append(ifName)
|
|
||||||
|
|
||||||
def getNetworkMap(self):
|
|
||||||
return {
|
|
||||||
'dataclassNetwork': lambda node: DataclassNetwork(node),
|
|
||||||
'clusterhostNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_CLUSTER_HOST),
|
|
||||||
'oamNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_OAM),
|
|
||||||
'mgmtNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_MGMT)
|
|
||||||
}
|
|
||||||
|
|
||||||
def validateWithIfNames(self, allInterfaceNames):
|
|
||||||
# raise InvalidProfileData exception if invalid
|
|
||||||
if len(self.usesIf) == 0:
|
|
||||||
msg = _('Aggregrated ethernet interface (%s) should have at least one interface.') % self.name
|
|
||||||
raise InvalidProfileData(msg)
|
|
||||||
|
|
||||||
for usesIfName in self.usesIf:
|
|
||||||
if usesIfName not in allInterfaceNames:
|
|
||||||
msg = _('Aggregrated ethernet interface (%s) uses a undeclared interface (%s)') % \
|
|
||||||
(self.name, usesIfName)
|
|
||||||
raise InvalidProfileData(msg)
|
|
||||||
super(AeInterface, self).validate()
|
|
||||||
|
|
||||||
|
|
||||||
class VlanInterface(Interface):
|
|
||||||
def __init__(self, ifNode):
|
|
||||||
super(VlanInterface, self).__init__(ifNode)
|
|
||||||
self.vlanId = int(ifNode.get('vlanId'))
|
|
||||||
usesIf = ifNode.get('interface')
|
|
||||||
|
|
||||||
if not usesIf:
|
|
||||||
raise InvalidProfileData(_('<usesIf> value cannot be empty.'))
|
|
||||||
if usesIf == self.name:
|
|
||||||
raise InvalidProfileData(_('vlan interface (%s) cannot use itself.') % self.name)
|
|
||||||
self.usesIfName = usesIf
|
|
||||||
self.usesIf = [usesIf]
|
|
||||||
|
|
||||||
def getNetworkMap(self):
|
|
||||||
return {
|
|
||||||
'dataclassNetwork': lambda node: DataclassNetwork(node),
|
|
||||||
'clusterhostNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_CLUSTER_HOST),
|
|
||||||
'oamNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_OAM),
|
|
||||||
'mgmtNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_MGMT)
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def isEthInterface(ifName, ethIfMap):
|
|
||||||
return ifName in ethIfMap
|
|
||||||
|
|
||||||
def validateWithIfNames(self, allInterfaceNames, aeIfMap, vlanIfMap, ethIfMap):
|
|
||||||
# raise InvalidProfileData exception if invalid
|
|
||||||
if self.usesIfName not in allInterfaceNames:
|
|
||||||
msg = _('vlan interface (%s) uses a undeclared interface (%s)') % \
|
|
||||||
(self.name, self.usesIfName)
|
|
||||||
raise InvalidProfileData(msg)
|
|
||||||
|
|
||||||
isEthIf = self.isEthInterface(self.usesIfName, ethIfMap)
|
|
||||||
|
|
||||||
good = True
|
|
||||||
if not isEthIf:
|
|
||||||
ifNameToCheck = [self.usesIfName]
|
|
||||||
|
|
||||||
while len(ifNameToCheck) > 0:
|
|
||||||
ifName = ifNameToCheck.pop(0)
|
|
||||||
if ifName in aeIfMap:
|
|
||||||
aeIf = aeIfMap[ifName]
|
|
||||||
for n in aeIf.usesIf:
|
|
||||||
ifNameToCheck.append(n)
|
|
||||||
elif ifName in vlanIfMap:
|
|
||||||
good = False
|
|
||||||
break # not good,a vlan in uses tree
|
|
||||||
|
|
||||||
if not good:
|
|
||||||
raise InvalidProfileData(_('A vlan interface cannot use a vlan interface.'))
|
|
||||||
|
|
||||||
super(VlanInterface, self).validate()
|
|
@ -16,7 +16,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2017 Wind River Systems, Inc.
|
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|
||||||
import jsonpatch
|
import jsonpatch
|
||||||
@ -357,14 +357,14 @@ class PVController(rest.RestController):
|
|||||||
|
|
||||||
|
|
||||||
# This method allows creating a physical volume through a non-HTTP
|
# This method allows creating a physical volume through a non-HTTP
|
||||||
# request e.g. through profile.py while still passing
|
# request while still passing through physical volume semantic checks and osd
|
||||||
# through physical volume semantic checks and osd configuration
|
# configuration
|
||||||
# Hence, not declared inside a class
|
# Hence, not declared inside a class
|
||||||
#
|
#
|
||||||
# Param:
|
# Param:
|
||||||
# pv - dictionary of physical volume values
|
# pv - dictionary of physical volume values
|
||||||
# iprofile - True when created by a storage profile
|
# iprofile - True when created by a storage profile
|
||||||
def _create(pv, iprofile=None):
|
def _create(pv):
|
||||||
LOG.debug("pv._create with initial params: %s" % pv)
|
LOG.debug("pv._create with initial params: %s" % pv)
|
||||||
# Get host
|
# Get host
|
||||||
ihostId = pv.get('forihostid') or pv.get('ihost_uuid')
|
ihostId = pv.get('forihostid') or pv.get('ihost_uuid')
|
||||||
@ -427,7 +427,7 @@ def _create(pv, iprofile=None):
|
|||||||
values)
|
values)
|
||||||
|
|
||||||
# semantic check for root disk
|
# semantic check for root disk
|
||||||
if iprofile is not True and constants.WARNING_MESSAGE_INDEX in pv:
|
if constants.WARNING_MESSAGE_INDEX in pv:
|
||||||
warning_message_index = pv.get(constants.WARNING_MESSAGE_INDEX)
|
warning_message_index = pv.get(constants.WARNING_MESSAGE_INDEX)
|
||||||
raise wsme.exc.ClientSideError(
|
raise wsme.exc.ClientSideError(
|
||||||
constants.PV_WARNINGS[warning_message_index])
|
constants.PV_WARNINGS[warning_message_index])
|
||||||
@ -714,11 +714,10 @@ def _check_device(new_pv, ihost):
|
|||||||
new_pv['disk_or_part_device_path'] = new_pv_device.device_path
|
new_pv['disk_or_part_device_path'] = new_pv_device.device_path
|
||||||
|
|
||||||
# Since physical volumes are reported as device nodes and not device
|
# Since physical volumes are reported as device nodes and not device
|
||||||
# paths, we need to translate this, but not for local storage profiles.
|
# paths, we need to translate this
|
||||||
if ihost['recordtype'] != 'profile':
|
if new_pv_device.device_node:
|
||||||
if new_pv_device.device_node:
|
new_pv['disk_or_part_device_node'] = new_pv_device.device_node
|
||||||
new_pv['disk_or_part_device_node'] = new_pv_device.device_node
|
new_pv['lvm_pv_name'] = new_pv['disk_or_part_device_node']
|
||||||
new_pv['lvm_pv_name'] = new_pv['disk_or_part_device_node']
|
|
||||||
|
|
||||||
# relationship checks
|
# relationship checks
|
||||||
# - Only one pv for cinder-volumes
|
# - Only one pv for cinder-volumes
|
||||||
@ -899,3 +898,4 @@ def delete_pv(pv_uuid, force=False):
|
|||||||
# TODO (rchurch): Fix system host-pv-add 1 cinder-volumes <disk uuid> => no error message
|
# TODO (rchurch): Fix system host-pv-add 1 cinder-volumes <disk uuid> => no error message
|
||||||
# TODO (rchurch): Fix system host-pv-add -t disk 1 cinder-volumes <disk uuid> => confusing message
|
# TODO (rchurch): Fix system host-pv-add -t disk 1 cinder-volumes <disk uuid> => confusing message
|
||||||
# TODO (rchurch): remove the -t options and use path/node/uuid to derive the type of PV
|
# TODO (rchurch): remove the -t options and use path/node/uuid to derive the type of PV
|
||||||
|
# TODO (pbovina): Move utils methods within PVController class
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2019 Wind River Systems, Inc.
|
# Copyright (c) 2013-2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
|
|
||||||
from eventlet.green import subprocess
|
from eventlet.green import subprocess
|
||||||
@ -518,16 +518,6 @@ class StorageController(rest.RestController):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def _check_profile(stor):
|
|
||||||
# semantic check: whether system has a ceph backend
|
|
||||||
if not StorageBackendConfig.has_backend_configured(
|
|
||||||
pecan.request.dbapi,
|
|
||||||
constants.SB_TYPE_CEPH
|
|
||||||
):
|
|
||||||
raise wsme.exc.ClientSideError(_(
|
|
||||||
"System must have a %s backend" % constants.SB_TYPE_CEPH))
|
|
||||||
|
|
||||||
|
|
||||||
def _check_host(stor):
|
def _check_host(stor):
|
||||||
ihost_id = stor['forihostid']
|
ihost_id = stor['forihostid']
|
||||||
ihost = pecan.request.dbapi.ihost_get(ihost_id)
|
ihost = pecan.request.dbapi.ihost_get(ihost_id)
|
||||||
@ -794,14 +784,11 @@ def _check_journal(old_foristor, new_foristor):
|
|||||||
|
|
||||||
|
|
||||||
# This method allows creating a stor through a non-HTTP
|
# This method allows creating a stor through a non-HTTP
|
||||||
# request e.g. through profile.py while still passing
|
# request
|
||||||
# through istor semantic checks and osd configuration
|
|
||||||
# Hence, not declared inside a class
|
|
||||||
#
|
#
|
||||||
# Param:
|
# Param:
|
||||||
# stor - dictionary of stor values
|
# stor - dictionary of stor values
|
||||||
# iprofile - True when created by a storage profile
|
def _create(stor):
|
||||||
def _create(stor, iprofile=None):
|
|
||||||
|
|
||||||
LOG.debug("storage._create stor with params: %s" % stor)
|
LOG.debug("storage._create stor with params: %s" % stor)
|
||||||
# Init
|
# Init
|
||||||
@ -820,10 +807,7 @@ def _create(stor, iprofile=None):
|
|||||||
stor.update({'forihostid': forihostid})
|
stor.update({'forihostid': forihostid})
|
||||||
|
|
||||||
# SEMANTIC CHECKS
|
# SEMANTIC CHECKS
|
||||||
if iprofile:
|
_check_host(stor)
|
||||||
_check_profile(stor)
|
|
||||||
else:
|
|
||||||
_check_host(stor)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
idisk_uuid = _check_disk(stor)
|
idisk_uuid = _check_disk(stor)
|
||||||
@ -834,12 +818,11 @@ def _create(stor, iprofile=None):
|
|||||||
# Assign the function if necessary.
|
# Assign the function if necessary.
|
||||||
function = stor['function']
|
function = stor['function']
|
||||||
if function:
|
if function:
|
||||||
if function == constants.STOR_FUNCTION_OSD and not iprofile:
|
if function == constants.STOR_FUNCTION_OSD:
|
||||||
osd_create = True
|
osd_create = True
|
||||||
else:
|
else:
|
||||||
function = stor['function'] = constants.STOR_FUNCTION_OSD
|
function = stor['function'] = constants.STOR_FUNCTION_OSD
|
||||||
if not iprofile:
|
osd_create = True
|
||||||
osd_create = True
|
|
||||||
|
|
||||||
create_attrs = {}
|
create_attrs = {}
|
||||||
create_attrs.update(stor)
|
create_attrs.update(stor)
|
||||||
@ -880,32 +863,31 @@ def _create(stor, iprofile=None):
|
|||||||
|
|
||||||
create_attrs['fortierid'] = tier.id
|
create_attrs['fortierid'] = tier.id
|
||||||
|
|
||||||
if not iprofile:
|
try:
|
||||||
try:
|
journal_location = \
|
||||||
journal_location = \
|
_check_journal_location(stor['journal_location'],
|
||||||
_check_journal_location(stor['journal_location'],
|
stor,
|
||||||
stor,
|
constants.ACTION_CREATE_JOURNAL)
|
||||||
constants.ACTION_CREATE_JOURNAL)
|
except exception.InvalidUUID as e:
|
||||||
except exception.InvalidUUID as e:
|
raise wsme.exc.ClientSideError(_(str(e)))
|
||||||
raise wsme.exc.ClientSideError(_(str(e)))
|
|
||||||
|
|
||||||
# If the journal is collocated, make sure its size is set to the
|
# If the journal is collocated, make sure its size is set to the
|
||||||
# default one.
|
# default one.
|
||||||
if 'uuid' in stor and journal_location == stor['uuid']:
|
if 'uuid' in stor and journal_location == stor['uuid']:
|
||||||
stor['journal_size_mib'] = CONF.journal.journal_default_size
|
stor['journal_size_mib'] = CONF.journal.journal_default_size
|
||||||
elif journal_location:
|
elif journal_location:
|
||||||
if not stor['journal_size_mib']:
|
if not stor['journal_size_mib']:
|
||||||
stor['journal_size_mib'] = \
|
stor['journal_size_mib'] = \
|
||||||
CONF.journal.journal_default_size
|
CONF.journal.journal_default_size
|
||||||
|
|
||||||
journal_istor = pecan.request.dbapi.istor_get(journal_location)
|
journal_istor = pecan.request.dbapi.istor_get(journal_location)
|
||||||
journal_idisk_uuid = journal_istor.idisk_uuid
|
journal_idisk_uuid = journal_istor.idisk_uuid
|
||||||
|
|
||||||
# Find out if there is enough space to keep the journal on the
|
# Find out if there is enough space to keep the journal on the
|
||||||
# journal stor.
|
# journal stor.
|
||||||
_check_journal_space(journal_idisk_uuid,
|
_check_journal_space(journal_idisk_uuid,
|
||||||
journal_location,
|
journal_location,
|
||||||
stor['journal_size_mib'])
|
stor['journal_size_mib'])
|
||||||
|
|
||||||
elif function == constants.STOR_FUNCTION_JOURNAL:
|
elif function == constants.STOR_FUNCTION_JOURNAL:
|
||||||
# Check that the journal stor resides on a device of SSD type.
|
# Check that the journal stor resides on a device of SSD type.
|
||||||
@ -938,7 +920,7 @@ def _create(stor, iprofile=None):
|
|||||||
|
|
||||||
# Journals are created only for OSDs
|
# Journals are created only for OSDs
|
||||||
if new_stor.get("function") == constants.STOR_FUNCTION_OSD:
|
if new_stor.get("function") == constants.STOR_FUNCTION_OSD:
|
||||||
if iprofile or not journal_location:
|
if not journal_location:
|
||||||
# iprofile either provides a valid location or assumes
|
# iprofile either provides a valid location or assumes
|
||||||
# collocation. For collocation: stor['journal_location'] =
|
# collocation. For collocation: stor['journal_location'] =
|
||||||
# stor['uuid'], since sometimes we get the UUID of the newly
|
# stor['uuid'], since sometimes we get the UUID of the newly
|
||||||
@ -954,16 +936,15 @@ def _create(stor, iprofile=None):
|
|||||||
setattr(new_stor, "journal_location", new_journal.get("onistor_uuid"))
|
setattr(new_stor, "journal_location", new_journal.get("onistor_uuid"))
|
||||||
setattr(new_stor, "journal_size", new_journal.get("size_mib"))
|
setattr(new_stor, "journal_size", new_journal.get("size_mib"))
|
||||||
|
|
||||||
if not iprofile:
|
# Update the state of the storage tier
|
||||||
# Update the state of the storage tier
|
try:
|
||||||
try:
|
pecan.request.dbapi.storage_tier_update(
|
||||||
pecan.request.dbapi.storage_tier_update(
|
tier.id,
|
||||||
tier.id,
|
{'status': constants.SB_TIER_STATUS_IN_USE})
|
||||||
{'status': constants.SB_TIER_STATUS_IN_USE})
|
except exception.StorageTierNotFound as e:
|
||||||
except exception.StorageTierNotFound as e:
|
# Shouldn't happen. Log exception. Stor is created but tier status
|
||||||
# Shouldn't happen. Log exception. Stor is created but tier status
|
# is not updated.
|
||||||
# is not updated.
|
LOG.exception(e)
|
||||||
LOG.exception(e)
|
|
||||||
|
|
||||||
# Apply runtime manifests for OSDs on "available" nodes.
|
# Apply runtime manifests for OSDs on "available" nodes.
|
||||||
runtime_manifests = False
|
runtime_manifests = False
|
||||||
|
@ -492,14 +492,10 @@ def _set_defaults(tier):
|
|||||||
|
|
||||||
|
|
||||||
# This method allows creating a storage tier through a non-HTTP
|
# This method allows creating a storage tier through a non-HTTP
|
||||||
# request e.g. through profile.py while still passing
|
# request
|
||||||
# through physical volume semantic checks and osd configuration
|
|
||||||
# Hence, not declared inside a class
|
|
||||||
#
|
|
||||||
# Param:
|
# Param:
|
||||||
# tier - dictionary of storage tier values
|
# tier - dictionary of storage tier values
|
||||||
# iprofile - True when created by a storage profile
|
def _create(self, tier):
|
||||||
def _create(self, tier, iprofile=None):
|
|
||||||
LOG.info("storage_tier._create with initial params: %s" % tier)
|
LOG.info("storage_tier._create with initial params: %s" % tier)
|
||||||
|
|
||||||
# Set defaults - before checks to allow for optional attributes
|
# Set defaults - before checks to allow for optional attributes
|
||||||
|
@ -79,7 +79,6 @@ POWERON_ACTION = 'power-on'
|
|||||||
POWEROFF_ACTION = 'power-off'
|
POWEROFF_ACTION = 'power-off'
|
||||||
SWACT_ACTION = 'swact'
|
SWACT_ACTION = 'swact'
|
||||||
FORCE_SWACT_ACTION = 'force-swact'
|
FORCE_SWACT_ACTION = 'force-swact'
|
||||||
APPLY_PROFILE_ACTION = 'apply-profile'
|
|
||||||
SUBFUNCTION_CONFIG_ACTION = 'subfunction_config'
|
SUBFUNCTION_CONFIG_ACTION = 'subfunction_config'
|
||||||
VIM_SERVICES_ENABLED = 'services-enabled'
|
VIM_SERVICES_ENABLED = 'services-enabled'
|
||||||
VIM_SERVICES_DISABLED = 'services-disabled'
|
VIM_SERVICES_DISABLED = 'services-disabled'
|
||||||
@ -109,8 +108,7 @@ MTCE_ACTIONS = [REBOOT_ACTION,
|
|||||||
VIM_ACTIONS = [LOCK_ACTION,
|
VIM_ACTIONS = [LOCK_ACTION,
|
||||||
FORCE_LOCK_ACTION]
|
FORCE_LOCK_ACTION]
|
||||||
|
|
||||||
CONFIG_ACTIONS = [SUBFUNCTION_CONFIG_ACTION,
|
CONFIG_ACTIONS = [SUBFUNCTION_CONFIG_ACTION]
|
||||||
APPLY_PROFILE_ACTION]
|
|
||||||
|
|
||||||
# Personalities
|
# Personalities
|
||||||
CONTROLLER = 'controller'
|
CONTROLLER = 'controller'
|
||||||
@ -976,12 +974,6 @@ CEPH_CRUSH_MAP_APPLIED = '.crushmap_applied'
|
|||||||
CEPH_CRUSH_MAP_DEPTH = 3
|
CEPH_CRUSH_MAP_DEPTH = 3
|
||||||
CEPH_CRUSH_TIER_SUFFIX = "-tier"
|
CEPH_CRUSH_TIER_SUFFIX = "-tier"
|
||||||
|
|
||||||
# Profiles
|
|
||||||
PROFILE_TYPE_CPU = 'cpu'
|
|
||||||
PROFILE_TYPE_INTERFACE = 'if'
|
|
||||||
PROFILE_TYPE_STORAGE = 'stor'
|
|
||||||
PROFILE_TYPE_MEMORY = 'memory'
|
|
||||||
PROFILE_TYPE_LOCAL_STORAGE = 'localstg'
|
|
||||||
|
|
||||||
# PCI Alias types and names
|
# PCI Alias types and names
|
||||||
NOVA_PCI_ALIAS_GPU_NAME = "gpu"
|
NOVA_PCI_ALIAS_GPU_NAME = "gpu"
|
||||||
|
@ -236,62 +236,6 @@ class Connection(object):
|
|||||||
:param server: The id or uuid of a server.
|
:param server: The id or uuid of a server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def interface_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
"""Return a list of interface profiles.
|
|
||||||
|
|
||||||
:param limit: Maximum number of profiles to return.
|
|
||||||
:param marker: the last item of the previous page; we return the next
|
|
||||||
result set.
|
|
||||||
:param sort_key: Attribute by which results should be sorted.
|
|
||||||
:param sort_dir: direction in which results should be sorted.
|
|
||||||
(asc, desc)
|
|
||||||
:param session: The DB session instance to use during the model query
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def cpu_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
"""Return a list of cpu profiles.
|
|
||||||
|
|
||||||
:param limit: Maximum number of profiles to return.
|
|
||||||
:param marker: the last item of the previous page; we return the next
|
|
||||||
result set.
|
|
||||||
:param sort_key: Attribute by which results should be sorted.
|
|
||||||
:param sort_dir: direction in which results should be sorted.
|
|
||||||
(asc, desc)
|
|
||||||
:param session: The DB session instance to use during the model query
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def memory_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
"""Return a list of memory profiles.
|
|
||||||
|
|
||||||
:param limit: Maximum number of profiles to return.
|
|
||||||
:param marker: the last item of the previous page; we return the next
|
|
||||||
result set.
|
|
||||||
:param sort_key: Attribute by which results should be sorted.
|
|
||||||
:param sort_dir: direction in which results should be sorted.
|
|
||||||
(asc, desc)
|
|
||||||
:param session: The DB session instance to use during the model query
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def storage_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
"""Return a list of storage profiles.
|
|
||||||
|
|
||||||
:param limit: Maximum number of profiles to return.
|
|
||||||
:param marker: the last item of the previous page; we return the next
|
|
||||||
result set.
|
|
||||||
:param sort_key: Attribute by which results should be sorted.
|
|
||||||
:param sort_dir: direction in which results should be sorted.
|
|
||||||
(asc, desc)
|
|
||||||
:param session: The DB session instance to use during the model query
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def inode_create(self, forihostid, values):
|
def inode_create(self, forihostid, values):
|
||||||
"""Create a new inode for a host.
|
"""Create a new inode for a host.
|
||||||
|
@ -34,7 +34,6 @@ from sqlalchemy import or_
|
|||||||
|
|
||||||
from sqlalchemy.orm import contains_eager
|
from sqlalchemy.orm import contains_eager
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from sqlalchemy.orm import subqueryload
|
|
||||||
from sqlalchemy.orm import with_polymorphic
|
from sqlalchemy.orm import with_polymorphic
|
||||||
from sqlalchemy.orm.exc import DetachedInstanceError
|
from sqlalchemy.orm.exc import DetachedInstanceError
|
||||||
from sqlalchemy.orm.exc import MultipleResultsFound
|
from sqlalchemy.orm.exc import MultipleResultsFound
|
||||||
@ -1460,59 +1459,6 @@ class Connection(api.Connection):
|
|||||||
|
|
||||||
query.delete()
|
query.delete()
|
||||||
|
|
||||||
def interface_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
|
|
||||||
ports = with_polymorphic(models.Ports, '*', flat=True)
|
|
||||||
interfaces = with_polymorphic(models.Interfaces, '*', flat=True)
|
|
||||||
|
|
||||||
query = model_query(models.ihost, session=session).\
|
|
||||||
filter_by(recordtype="profile"). \
|
|
||||||
join(models.ihost.ports). \
|
|
||||||
options(subqueryload(models.ihost.ports.of_type(ports)),
|
|
||||||
subqueryload(models.ihost.interfaces.of_type(interfaces)))
|
|
||||||
|
|
||||||
return _paginate_query(models.ihost, limit, marker,
|
|
||||||
sort_key, sort_dir, query)
|
|
||||||
|
|
||||||
def cpu_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
|
|
||||||
query = model_query(models.ihost, session=session).\
|
|
||||||
filter_by(recordtype="profile"). \
|
|
||||||
join(models.ihost.cpus). \
|
|
||||||
options(subqueryload(models.ihost.cpus),
|
|
||||||
subqueryload(models.ihost.nodes))
|
|
||||||
|
|
||||||
return _paginate_query(models.ihost, limit, marker,
|
|
||||||
sort_key, sort_dir, query)
|
|
||||||
|
|
||||||
def memory_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
|
|
||||||
query = model_query(models.ihost, session=session).\
|
|
||||||
filter_by(recordtype="profile"). \
|
|
||||||
join(models.ihost.memory). \
|
|
||||||
options(subqueryload(models.ihost.memory),
|
|
||||||
subqueryload(models.ihost.nodes))
|
|
||||||
|
|
||||||
return _paginate_query(models.ihost, limit, marker,
|
|
||||||
sort_key, sort_dir, query)
|
|
||||||
|
|
||||||
def storage_profile_get_list(self, limit=None, marker=None,
|
|
||||||
sort_key=None, sort_dir=None, session=None):
|
|
||||||
|
|
||||||
query = model_query(models.ihost, session=session).\
|
|
||||||
filter_by(recordtype="profile").\
|
|
||||||
join(models.ihost.disks).\
|
|
||||||
outerjoin(models.ihost.partitions).\
|
|
||||||
outerjoin(models.ihost.stors).\
|
|
||||||
outerjoin(models.ihost.pvs).\
|
|
||||||
outerjoin(models.ihost.lvgs)
|
|
||||||
|
|
||||||
return _paginate_query(models.ihost, limit, marker,
|
|
||||||
sort_key, sort_dir, query)
|
|
||||||
|
|
||||||
def _node_get(self, inode_id):
|
def _node_get(self, inode_id):
|
||||||
query = model_query(models.inode)
|
query = model_query(models.inode)
|
||||||
query = add_identity_filter(query, inode_id)
|
query = add_identity_filter(query, inode_id)
|
||||||
@ -2379,17 +2325,13 @@ class Connection(api.Connection):
|
|||||||
|
|
||||||
self._interface_ratelimit_encode(values)
|
self._interface_ratelimit_encode(values)
|
||||||
|
|
||||||
is_profile = values.get('interface_profile', False)
|
|
||||||
with _session_for_write() as session:
|
with _session_for_write() as session:
|
||||||
|
|
||||||
# interface = models.Interfaces()
|
# interface = models.Interfaces()
|
||||||
if hasattr(obj, 'uses') and values.get('uses'):
|
if hasattr(obj, 'uses') and values.get('uses'):
|
||||||
for i in list(values['uses']):
|
for i in list(values['uses']):
|
||||||
try:
|
try:
|
||||||
if is_profile:
|
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
|
||||||
uses_if = self._interface_get(models.Interfaces, i, obj=obj)
|
|
||||||
else:
|
|
||||||
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
|
|
||||||
obj.uses.append(uses_if)
|
obj.uses.append(uses_if)
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
raise exception.InvalidParameterValue(
|
raise exception.InvalidParameterValue(
|
||||||
@ -2402,10 +2344,7 @@ class Connection(api.Connection):
|
|||||||
if hasattr(obj, 'used_by') and values.get('used_by'):
|
if hasattr(obj, 'used_by') and values.get('used_by'):
|
||||||
for i in list(values['used_by']):
|
for i in list(values['used_by']):
|
||||||
try:
|
try:
|
||||||
if is_profile:
|
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
|
||||||
uses_if = self._interface_get(models.Interfaces, i, obj=obj)
|
|
||||||
else:
|
|
||||||
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
|
|
||||||
obj.used_by.append(uses_if)
|
obj.used_by.append(uses_if)
|
||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
raise exception.InvalidParameterValue(
|
raise exception.InvalidParameterValue(
|
||||||
@ -5980,10 +5919,8 @@ class Connection(api.Connection):
|
|||||||
if not values.get('uuid'):
|
if not values.get('uuid'):
|
||||||
values['uuid'] = uuidutils.generate_uuid()
|
values['uuid'] = uuidutils.generate_uuid()
|
||||||
values['host_id'] = int(host_id)
|
values['host_id'] = int(host_id)
|
||||||
|
|
||||||
if 'sensor_profile' in values:
|
if 'sensor_profile' in values:
|
||||||
values.pop('sensor_profile')
|
values.pop('sensor_profile')
|
||||||
|
|
||||||
# The id is null for ae sensors with more than one member
|
# The id is null for ae sensors with more than one member
|
||||||
# sensor
|
# sensor
|
||||||
temp_id = obj.id
|
temp_id = obj.id
|
||||||
@ -6258,10 +6195,8 @@ class Connection(api.Connection):
|
|||||||
if not values.get('uuid'):
|
if not values.get('uuid'):
|
||||||
values['uuid'] = uuidutils.generate_uuid()
|
values['uuid'] = uuidutils.generate_uuid()
|
||||||
values['host_id'] = int(host_id)
|
values['host_id'] = int(host_id)
|
||||||
|
|
||||||
if 'sensorgroup_profile' in values:
|
if 'sensorgroup_profile' in values:
|
||||||
values.pop('sensorgroup_profile')
|
values.pop('sensorgroup_profile')
|
||||||
|
|
||||||
temp_id = obj.id
|
temp_id = obj.id
|
||||||
obj.update(values)
|
obj.update(values)
|
||||||
if obj.id is None:
|
if obj.id is None:
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
#
|
||||||
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
from sqlalchemy import MetaData, Table, Column, Integer, Enum, String
|
||||||
|
from sqlalchemy.dialects import postgresql
|
||||||
|
|
||||||
|
|
||||||
|
ENGINE = 'InnoDB'
|
||||||
|
CHARSET = 'utf8'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
i_host = Table('i_host',
|
||||||
|
meta,
|
||||||
|
Column('id', Integer,
|
||||||
|
primary_key=True, nullable=False),
|
||||||
|
mysql_engine=ENGINE, mysql_charset=CHARSET,
|
||||||
|
autoload=True)
|
||||||
|
|
||||||
|
if migrate_engine.url.get_dialect() is postgresql.dialect:
|
||||||
|
old_recordTypeEnum = Enum('standard',
|
||||||
|
'profile',
|
||||||
|
'sprofile',
|
||||||
|
'reserve1',
|
||||||
|
'reserve2',
|
||||||
|
name='recordtypeEnum')
|
||||||
|
|
||||||
|
recordTypeEnum = Enum('standard',
|
||||||
|
'sprofile',
|
||||||
|
'reserve1',
|
||||||
|
'reserve2',
|
||||||
|
name='recordtypeEnum')
|
||||||
|
|
||||||
|
old_personalityEnum = Enum('controller',
|
||||||
|
'worker',
|
||||||
|
'network',
|
||||||
|
'storage',
|
||||||
|
'profile',
|
||||||
|
'reserve1',
|
||||||
|
'reserve2',
|
||||||
|
name='invPersonalityEnum')
|
||||||
|
|
||||||
|
personalityEnum = Enum('controller',
|
||||||
|
'worker',
|
||||||
|
'network',
|
||||||
|
'storage',
|
||||||
|
'reserve1',
|
||||||
|
'reserve2',
|
||||||
|
name='invPersonalityEnum')
|
||||||
|
|
||||||
|
migrate_engine.execute("delete from partition using i_host"
|
||||||
|
" where i_host.recordtype='profile'"
|
||||||
|
" and partition.forihostid=i_host.id")
|
||||||
|
|
||||||
|
migrate_engine.execute("delete from i_host where recordtype='profile'")
|
||||||
|
|
||||||
|
personality_col = i_host.c.personality
|
||||||
|
personality_col.alter(Column('personality', String(60)))
|
||||||
|
old_personalityEnum.drop(bind=migrate_engine, checkfirst=False)
|
||||||
|
personalityEnum.create(bind=migrate_engine, checkfirst=False)
|
||||||
|
migrate_engine.execute('ALTER TABLE i_host ALTER COLUMN personality '
|
||||||
|
'TYPE "invPersonalityEnum" USING '
|
||||||
|
'personality::text::"invPersonalityEnum"')
|
||||||
|
|
||||||
|
recordtype_col = i_host.c.recordtype
|
||||||
|
recordtype_col.alter(Column('recordtype', String(60)))
|
||||||
|
old_recordTypeEnum.drop(bind=migrate_engine, checkfirst=False)
|
||||||
|
recordTypeEnum.create(bind=migrate_engine, checkfirst=False)
|
||||||
|
migrate_engine.execute('ALTER TABLE i_host ALTER COLUMN recordtype '
|
||||||
|
'TYPE "recordtypeEnum" USING '
|
||||||
|
'recordtype::text::"recordtypeEnum"')
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade(migrate_engine):
|
||||||
|
meta = MetaData()
|
||||||
|
meta.bind = migrate_engine
|
||||||
|
|
||||||
|
# As per other openstack components, downgrade is
|
||||||
|
# unsupported in this release.
|
||||||
|
raise NotImplementedError('SysInv database downgrade is unsupported.')
|
@ -116,7 +116,6 @@ class isystem(Base):
|
|||||||
class ihost(Base):
|
class ihost(Base):
|
||||||
|
|
||||||
recordTypeEnum = Enum('standard',
|
recordTypeEnum = Enum('standard',
|
||||||
'profile',
|
|
||||||
'sprofile',
|
'sprofile',
|
||||||
'reserve1',
|
'reserve1',
|
||||||
'reserve2',
|
'reserve2',
|
||||||
@ -135,7 +134,6 @@ class ihost(Base):
|
|||||||
'worker',
|
'worker',
|
||||||
'network',
|
'network',
|
||||||
'storage',
|
'storage',
|
||||||
'profile',
|
|
||||||
'reserve1',
|
'reserve1',
|
||||||
'reserve2',
|
'reserve2',
|
||||||
'edgeworker',
|
'edgeworker',
|
||||||
|
@ -69,7 +69,6 @@ from sysinv.objects import ntp
|
|||||||
from sysinv.objects import pci_device
|
from sysinv.objects import pci_device
|
||||||
from sysinv.objects import peer
|
from sysinv.objects import peer
|
||||||
from sysinv.objects import port
|
from sysinv.objects import port
|
||||||
from sysinv.objects import profile
|
|
||||||
from sysinv.objects import ptp
|
from sysinv.objects import ptp
|
||||||
from sysinv.objects import ptp_instance
|
from sysinv.objects import ptp_instance
|
||||||
from sysinv.objects import ptp_interface
|
from sysinv.objects import ptp_interface
|
||||||
@ -135,7 +134,6 @@ system = system.System
|
|||||||
cluster = cluster.Cluster
|
cluster = cluster.Cluster
|
||||||
peer = peer.Peer
|
peer = peer.Peer
|
||||||
host = host.Host
|
host = host.Host
|
||||||
profile = profile.Profile
|
|
||||||
node = node.Node
|
node = node.Node
|
||||||
cpu = cpu.CPU
|
cpu = cpu.CPU
|
||||||
memory = memory.Memory
|
memory = memory.Memory
|
||||||
@ -222,7 +220,6 @@ __all__ = ("system",
|
|||||||
"cluster",
|
"cluster",
|
||||||
"peer",
|
"peer",
|
||||||
"host",
|
"host",
|
||||||
"profile",
|
|
||||||
"node",
|
"node",
|
||||||
"cpu",
|
"cpu",
|
||||||
"memory",
|
"memory",
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2013-2016 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
||||||
# coding=utf-8
|
|
||||||
#
|
|
||||||
|
|
||||||
from sysinv.db import api as db_api
|
|
||||||
from sysinv.objects import base
|
|
||||||
from sysinv.objects import utils
|
|
||||||
|
|
||||||
|
|
||||||
class Profile(base.SysinvObject):
|
|
||||||
|
|
||||||
dbapi = db_api.get_instance()
|
|
||||||
|
|
||||||
fields = {
|
|
||||||
'id': int,
|
|
||||||
'recordtype': utils.str_or_none,
|
|
||||||
|
|
||||||
# 'created_at': utils.datetime_str_or_none,
|
|
||||||
# 'updated_at': utils.datetime_str_or_none,
|
|
||||||
'hostname': utils.str_or_none,
|
|
||||||
'personality': utils.str_or_none,
|
|
||||||
# Host is working on a blocking process
|
|
||||||
'reserved': utils.str_or_none,
|
|
||||||
# NOTE: instance_uuid must be read-only when server is provisioned
|
|
||||||
'uuid': utils.str_or_none,
|
|
||||||
|
|
||||||
# NOTE: driver should be read-only after server is created
|
|
||||||
'invprovision': utils.str_or_none,
|
|
||||||
'mgmt_mac': utils.str_or_none,
|
|
||||||
'mgmt_ip': utils.str_or_none,
|
|
||||||
|
|
||||||
# Board management members
|
|
||||||
'bm_ip': utils.str_or_none,
|
|
||||||
'bm_mac': utils.str_or_none,
|
|
||||||
'bm_type': utils.str_or_none,
|
|
||||||
'bm_username': utils.str_or_none,
|
|
||||||
|
|
||||||
'location': utils.dict_or_none,
|
|
||||||
# 'reservation': utils.str_or_none,
|
|
||||||
'serialid': utils.str_or_none,
|
|
||||||
'administrative': utils.str_or_none,
|
|
||||||
'operational': utils.str_or_none,
|
|
||||||
'availability': utils.str_or_none,
|
|
||||||
'action': utils.str_or_none,
|
|
||||||
'task': utils.str_or_none,
|
|
||||||
'uptime': utils.int_or_none,
|
|
||||||
|
|
||||||
'boot_device': utils.str_or_none,
|
|
||||||
'rootfs_device': utils.str_or_none,
|
|
||||||
'install_output': utils.str_or_none,
|
|
||||||
'console': utils.str_or_none,
|
|
||||||
'tboot': utils.str_or_none,
|
|
||||||
}
|
|
||||||
|
|
||||||
@base.remotable_classmethod
|
|
||||||
def get_by_uuid(cls, context, uuid):
|
|
||||||
return cls.dbapi.ihost_get(uuid)
|
|
||||||
|
|
||||||
def save_changes(self, context, updates):
|
|
||||||
self.dbapi.ihost_update(self.uuid, # pylint: disable=no-member
|
|
||||||
updates)
|
|
@ -3084,37 +3084,6 @@ class TestPatchStdDuplexControllerVIM(TestHost):
|
|||||||
self.assertEqual(constants.VIM_SERVICES_DELETE_FAILED,
|
self.assertEqual(constants.VIM_SERVICES_DELETE_FAILED,
|
||||||
result['vim_progress_status'])
|
result['vim_progress_status'])
|
||||||
|
|
||||||
def test_apply_profile_action_bad_profile_id(self):
|
|
||||||
# Note: Including this testcase for completeness (wanted to cover each
|
|
||||||
# action. The testcases in test_interface.py cover the success case.
|
|
||||||
|
|
||||||
# Create controller-0
|
|
||||||
self._create_controller_0(
|
|
||||||
invprovision=constants.PROVISIONED,
|
|
||||||
administrative=constants.ADMIN_UNLOCKED,
|
|
||||||
operational=constants.OPERATIONAL_ENABLED,
|
|
||||||
availability=constants.AVAILABILITY_ONLINE)
|
|
||||||
|
|
||||||
# Create controller-1
|
|
||||||
c1_host = self._create_controller_1(
|
|
||||||
invprovision=constants.PROVISIONED,
|
|
||||||
administrative=constants.ADMIN_LOCKED,
|
|
||||||
operational=constants.OPERATIONAL_ENABLED,
|
|
||||||
availability=constants.AVAILABILITY_ONLINE)
|
|
||||||
|
|
||||||
# Apply profile to controller-1 and verify it was rejected
|
|
||||||
self.assertRaises(webtest.app.AppError,
|
|
||||||
self.patch_json,
|
|
||||||
'/ihosts/%s' % c1_host['hostname'],
|
|
||||||
[{'path': '/action',
|
|
||||||
'value': constants.APPLY_PROFILE_ACTION,
|
|
||||||
'op': 'replace'},
|
|
||||||
{'path': '/iprofile_uuid',
|
|
||||||
'value': 'notarealuuid',
|
|
||||||
'op': 'replace'}
|
|
||||||
],
|
|
||||||
headers={'User-Agent': 'sysinv-test'})
|
|
||||||
|
|
||||||
def test_subfunction_config_action(self):
|
def test_subfunction_config_action(self):
|
||||||
# Create controller-0 (AIO)
|
# Create controller-0 (AIO)
|
||||||
c0_host = self._create_controller_0(
|
c0_host = self._create_controller_0(
|
||||||
|
@ -513,27 +513,6 @@ class InterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
|||||||
self.assertEqual(http_client.OK, response.status_int)
|
self.assertEqual(http_client.OK, response.status_int)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def _create_and_apply_profile(self, host):
|
|
||||||
ifprofile = {
|
|
||||||
'ihost_uuid': host.uuid,
|
|
||||||
'profilename': 'ifprofile-node1',
|
|
||||||
'profiletype': constants.PROFILE_TYPE_INTERFACE
|
|
||||||
}
|
|
||||||
response = self.post_json('/iprofile', ifprofile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
list_data = self.get_json('/iprofile')
|
|
||||||
profile_uuid = list_data['iprofiles'][0]['uuid']
|
|
||||||
|
|
||||||
self.get_json('/iprofile/%s/iinterfaces' % profile_uuid)
|
|
||||||
self.get_json('/iprofile/%s/ethernet_ports' % profile_uuid)
|
|
||||||
|
|
||||||
result = self.patch_dict_json('/ihosts/%s' % host.id,
|
|
||||||
headers={'User-Agent': 'sysinv'},
|
|
||||||
action=constants.APPLY_PROFILE_ACTION,
|
|
||||||
iprofile_uuid=profile_uuid)
|
|
||||||
self.assertEqual(http_client.OK, result.status_int)
|
|
||||||
|
|
||||||
def is_interface_equal(self, first, second):
|
def is_interface_equal(self, first, second):
|
||||||
for key in first:
|
for key in first:
|
||||||
if key in second:
|
if key in second:
|
||||||
@ -563,518 +542,6 @@ class InterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
|
|||||||
self._setup_configuration()
|
self._setup_configuration()
|
||||||
|
|
||||||
|
|
||||||
class InterfaceControllerEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where all platform interfaces are
|
|
||||||
# ethernet interfaces.
|
|
||||||
self._create_host(constants.CONTROLLER, admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_ethernet('oam', constants.NETWORK_TYPE_OAM)
|
|
||||||
self._create_ethernet('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_ethernet('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
self.get_json('/ihosts/%s/iinterfaces' % self.controller.uuid)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceControllerEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_controller_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceControllerBond(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where all platform interfaces are
|
|
||||||
# aggregated ethernet interfaces.
|
|
||||||
self._create_host(constants.CONTROLLER, admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_bond('oam', constants.NETWORK_TYPE_OAM)
|
|
||||||
self._create_bond('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_bond('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceControllerBond, self).setUp()
|
|
||||||
|
|
||||||
def test_controller_bond_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceControllerVlanOverBond(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where all platform interfaces are
|
|
||||||
# vlan interfaces over aggregated ethernet interfaces
|
|
||||||
self._create_host(constants.CONTROLLER, admin=constants.ADMIN_LOCKED)
|
|
||||||
bond = self._create_bond('pxeboot', constants.NETWORK_TYPE_PXEBOOT)
|
|
||||||
self._create_vlan('oam', constants.NETWORK_TYPE_OAM,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 1, bond)
|
|
||||||
self._create_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, bond)
|
|
||||||
self._create_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3, bond)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceControllerVlanOverBond, self).setUp()
|
|
||||||
|
|
||||||
def test_controller_vlan_over_bond_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceControllerVlanOverEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where all platform interfaces are
|
|
||||||
# vlan interfaces over ethernet interfaces
|
|
||||||
self._create_host(constants.CONTROLLER, admin=constants.ADMIN_LOCKED)
|
|
||||||
port, iface = self._create_ethernet(
|
|
||||||
'pxeboot', constants.NETWORK_TYPE_PXEBOOT)
|
|
||||||
self._create_vlan('oam', constants.NETWORK_TYPE_OAM,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 1, iface)
|
|
||||||
self._create_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, iface)
|
|
||||||
self._create_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3, iface)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceControllerVlanOverEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_controller_vlan_over_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceEthernetOverSriov(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# ethernet aside from a VF over SR-IOV interface.
|
|
||||||
self._create_host(constants.CONTROLLER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
|
|
||||||
lower_port, lower_iface = self._create_sriov(
|
|
||||||
'sriov1', sriov_numvfs=2)
|
|
||||||
self._create_vf('vf1', lower_iface=lower_iface, sriov_numvfs=1,
|
|
||||||
sriov_vf_driver='vfio', datanetworks='group0-data1')
|
|
||||||
port, iface = self._create_ethernet(
|
|
||||||
'pxeboot', constants.NETWORK_TYPE_PXEBOOT, lower_iface=lower_iface)
|
|
||||||
self._create_vlan('oam', constants.NETWORK_TYPE_OAM,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 1, lower_iface)
|
|
||||||
self._create_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, lower_iface)
|
|
||||||
self._create_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3, lower_iface)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceEthernetOverSriov, self).setUp()
|
|
||||||
|
|
||||||
def test_ethernet_over_sriov_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceWorkerEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
self._create_host(constants.CONTROLLER, admin=constants.ADMIN_UNLOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# worker and all interfaces are ethernet interfaces.
|
|
||||||
self._create_host(constants.WORKER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_ethernet('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
host=self.worker)
|
|
||||||
self._create_ethernet('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
host=self.worker)
|
|
||||||
self._create_ethernet('data',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-data0', host=self.worker)
|
|
||||||
self._create_ethernet('sriov',
|
|
||||||
constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-data1', host=self.worker)
|
|
||||||
self._create_ethernet('pthru',
|
|
||||||
constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext0', host=self.worker)
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('slow',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-ext1', host=self.worker))
|
|
||||||
port['dpdksupport'] = False
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('mlx4',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-ext2', host=self.worker))
|
|
||||||
port['driver'] = 'mlx4_core'
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('mlx5',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-ext3', host=self.worker))
|
|
||||||
port['driver'] = 'mlx5_core'
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceWorkerEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_worker_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.worker)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceWorkerVlanOverEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
self._create_host(constants.CONTROLLER)
|
|
||||||
self._create_datanetworks()
|
|
||||||
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# worker and all interfaces are vlan interfaces over ethernet
|
|
||||||
# interfaces.
|
|
||||||
self._create_host(constants.WORKER, admin=constants.ADMIN_LOCKED)
|
|
||||||
port, iface = self._create_ethernet(
|
|
||||||
'pxeboot', constants.NETWORK_TYPE_PXEBOOT, host=self.worker)
|
|
||||||
self._create_worker_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, iface)
|
|
||||||
self._create_worker_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3)
|
|
||||||
self._create_worker_vlan('data', constants.INTERFACE_CLASS_DATA,
|
|
||||||
constants.NETWORK_TYPE_DATA, 5,
|
|
||||||
datanetworks='group0-ext0')
|
|
||||||
self._create_ethernet('sriov',
|
|
||||||
constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-data0', host=self.worker)
|
|
||||||
self._create_ethernet('pthru',
|
|
||||||
constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-data1', host=self.worker)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceWorkerVlanOverEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_worker_vlan_over_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.worker)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceWorkerBond(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
self._create_host(constants.CONTROLLER, admin=constants.ADMIN_UNLOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# worker and all interfaces are aggregated ethernet interfaces.
|
|
||||||
self._create_host(constants.WORKER, admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_worker_bond('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_worker_bond('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
self._create_worker_bond('data',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
datanetworks='group0-data0')
|
|
||||||
self._create_ethernet('sriov',
|
|
||||||
constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-ext0', host=self.worker)
|
|
||||||
self._create_ethernet('pthru',
|
|
||||||
constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext1', host=self.worker)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceWorkerBond, self).setUp()
|
|
||||||
|
|
||||||
def test_worker_bond_profile(self):
|
|
||||||
self._create_and_apply_profile(self.worker)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceWorkerVlanOverBond(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
self._create_host(constants.CONTROLLER)
|
|
||||||
self._create_datanetworks()
|
|
||||||
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# worker and all interfaces are vlan interfaces over aggregated
|
|
||||||
# ethernet interfaces.
|
|
||||||
self._create_host(constants.WORKER, admin=constants.ADMIN_LOCKED)
|
|
||||||
bond = self._create_worker_bond('pxeboot',
|
|
||||||
constants.NETWORK_TYPE_PXEBOOT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM)
|
|
||||||
self._create_worker_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, bond)
|
|
||||||
self._create_worker_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3,
|
|
||||||
bond)
|
|
||||||
bond2 = self._create_worker_bond('bond2', constants.NETWORK_TYPE_NONE)
|
|
||||||
self._create_worker_vlan('data',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
5, bond2,
|
|
||||||
datanetworks='group0-ext0')
|
|
||||||
|
|
||||||
self._create_worker_bond('bond3', constants.NETWORK_TYPE_NONE)
|
|
||||||
|
|
||||||
self._create_ethernet('sriov',
|
|
||||||
constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-data0', host=self.worker)
|
|
||||||
self._create_ethernet('pthru',
|
|
||||||
constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-data1', host=self.worker)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceWorkerVlanOverBond, self).setUp()
|
|
||||||
|
|
||||||
def test_worker_vlan_over_bond_profile(self):
|
|
||||||
self._create_and_apply_profile(self.worker)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceWorkerVlanOverDataEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
self._create_host(constants.CONTROLLER)
|
|
||||||
self._create_datanetworks()
|
|
||||||
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# worker and all interfaces are vlan interfaces over data ethernet
|
|
||||||
# interfaces.
|
|
||||||
self._create_host(constants.WORKER, admin=constants.ADMIN_LOCKED)
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('data',
|
|
||||||
constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-data0', host=self.worker))
|
|
||||||
self._create_ethernet('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
host=self.worker)
|
|
||||||
self._create_ethernet('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
host=self.worker)
|
|
||||||
self._create_worker_vlan('data2', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA, 5,
|
|
||||||
iface, datanetworks='group0-ext0')
|
|
||||||
self._create_ethernet('sriov',
|
|
||||||
constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-ext1', host=self.worker)
|
|
||||||
self._create_ethernet('pthru',
|
|
||||||
constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext2', host=self.worker)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceWorkerVlanOverDataEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_worker_vlan_over_data_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.worker)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceAIOEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# ethernet interfaces.
|
|
||||||
self._create_host(constants.CONTROLLER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
self._create_ethernet('oam', constants.NETWORK_TYPE_OAM)
|
|
||||||
self._create_ethernet('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_ethernet('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
self._create_ethernet('data', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-data0')
|
|
||||||
self._create_ethernet('sriov', constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-data1')
|
|
||||||
self._create_ethernet('pthru', constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext0')
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('slow', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-ext1'))
|
|
||||||
port['dpdksupport'] = False
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('mlx4', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-ext2'))
|
|
||||||
port['driver'] = 'mlx4_core'
|
|
||||||
port, iface = (
|
|
||||||
self._create_ethernet('mlx5', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-ext3'))
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceAIOEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_AIO_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceAIOVlanOverEthernet(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# vlan interfaces over ethernet interfaces.
|
|
||||||
self._create_host(constants.CONTROLLER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
port, iface = self._create_ethernet(
|
|
||||||
'pxeboot', constants.NETWORK_TYPE_PXEBOOT)
|
|
||||||
self._create_vlan('oam', constants.NETWORK_TYPE_OAM,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 1, iface)
|
|
||||||
self._create_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, iface)
|
|
||||||
self._create_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3)
|
|
||||||
self._create_ethernet('data', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
datanetworks='group0-ext0')
|
|
||||||
self._create_ethernet('sriov', constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-ext1')
|
|
||||||
self._create_ethernet('pthru', constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext2')
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceAIOVlanOverEthernet, self).setUp()
|
|
||||||
|
|
||||||
def test_AIO_vlan_over_ethernet_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceAIOBond(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# aggregated ethernet interfaces.
|
|
||||||
self._create_host(constants.CONTROLLER,
|
|
||||||
subfunction=constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
self._create_bond('oam', constants.NETWORK_TYPE_OAM)
|
|
||||||
self._create_bond('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_bond('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
self._create_bond('data', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
datanetworks='group0-data0')
|
|
||||||
self._create_ethernet('sriov', constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
datanetworks='group0-ext0')
|
|
||||||
self._create_ethernet('pthru', constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
datanetworks='group0-ext1')
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceAIOBond, self).setUp()
|
|
||||||
|
|
||||||
def test_AIO_bond_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceAIOVlanOverBond(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# vlan interfaces over aggregated ethernet interfaces.
|
|
||||||
self._create_host(constants.CONTROLLER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
bond = self._create_bond('pxeboot', constants.NETWORK_TYPE_PXEBOOT)
|
|
||||||
self._create_vlan('oam', constants.NETWORK_TYPE_OAM,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 1, bond)
|
|
||||||
self._create_vlan('mgmt', constants.NETWORK_TYPE_MGMT,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 2, bond)
|
|
||||||
self._create_vlan('cluster', constants.NETWORK_TYPE_CLUSTER_HOST,
|
|
||||||
constants.INTERFACE_CLASS_PLATFORM, 3, bond)
|
|
||||||
bond2 = self._create_bond('bond4', constants.NETWORK_TYPE_NONE)
|
|
||||||
self._create_vlan('data', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
5, bond2,
|
|
||||||
datanetworks='group0-ext0')
|
|
||||||
self._create_ethernet('sriov', constants.NETWORK_TYPE_PCI_SRIOV,
|
|
||||||
constants.INTERFACE_CLASS_PCI_SRIOV,
|
|
||||||
'group0-ext1')
|
|
||||||
self._create_ethernet('pthru', constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext2')
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceAIOVlanOverBond, self).setUp()
|
|
||||||
|
|
||||||
def test_AIO_vlan_over_bond_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceAIOVfOverSriov(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# ethernet aside from a VF over SR-IOV interface.
|
|
||||||
self._create_host(constants.CONTROLLER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
self._create_ethernet('oam', constants.NETWORK_TYPE_OAM)
|
|
||||||
self._create_ethernet('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_ethernet('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
self._create_ethernet('data', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-data0')
|
|
||||||
self._create_ethernet('pthru', constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext0')
|
|
||||||
lower_port, lower_iface = self._create_sriov(
|
|
||||||
'sriov1', sriov_numvfs=2, datanetworks='group0-data0')
|
|
||||||
self._create_vf('vf1', lower_iface=lower_iface, sriov_numvfs=1,
|
|
||||||
sriov_vf_driver='vfio', datanetworks='group0-data1')
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceAIOVfOverSriov, self).setUp()
|
|
||||||
|
|
||||||
def test_AIO_vf_over_sriov_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceAIOVfWithRatelimitOverSriov(InterfaceTestCase):
|
|
||||||
|
|
||||||
def _setup_configuration(self):
|
|
||||||
# Setup a sample configuration where the personality is set to a
|
|
||||||
# controller with a worker subfunction and all interfaces are
|
|
||||||
# ethernet aside from a VF over SR-IOV interface.
|
|
||||||
self._create_host(constants.CONTROLLER, constants.WORKER,
|
|
||||||
admin=constants.ADMIN_LOCKED)
|
|
||||||
self._create_datanetworks()
|
|
||||||
self._create_ethernet('oam', constants.NETWORK_TYPE_OAM)
|
|
||||||
self._create_ethernet('mgmt', constants.NETWORK_TYPE_MGMT)
|
|
||||||
self._create_ethernet('cluster', constants.NETWORK_TYPE_CLUSTER_HOST)
|
|
||||||
self._create_ethernet('data', constants.NETWORK_TYPE_DATA,
|
|
||||||
constants.INTERFACE_CLASS_DATA,
|
|
||||||
'group0-data0')
|
|
||||||
self._create_ethernet('pthru', constants.NETWORK_TYPE_PCI_PASSTHROUGH,
|
|
||||||
constants.INTERFACE_CLASS_PCI_PASSTHROUGH,
|
|
||||||
'group0-ext0')
|
|
||||||
lower_port, lower_iface = self._create_sriov(
|
|
||||||
'sriov1', sriov_numvfs=3, datanetworks='group0-data0')
|
|
||||||
self._create_vf('vf1', lower_iface=lower_iface, sriov_numvfs=1,
|
|
||||||
sriov_vf_driver='vfio', datanetworks='group0-data1')
|
|
||||||
self._create_vf('vf2', lower_iface=lower_iface, sriov_numvfs=1,
|
|
||||||
sriov_vf_driver='vfio', datanetworks='group0-data1',
|
|
||||||
max_tx_rate=100)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(InterfaceAIOVfWithRatelimitOverSriov, self).setUp()
|
|
||||||
|
|
||||||
def test_AIO_vf_with_ratelimit_over_sriov_profile(self):
|
|
||||||
self._create_and_apply_profile(self.controller)
|
|
||||||
|
|
||||||
|
|
||||||
# Test that the unsupported config is rejected
|
# Test that the unsupported config is rejected
|
||||||
class InterfaceAIOVlanOverDataEthernet(InterfaceTestCase):
|
class InterfaceAIOVlanOverDataEthernet(InterfaceTestCase):
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2019 Wind River Systems, Inc.
|
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
#
|
#
|
||||||
@ -160,30 +160,6 @@ class TestListKubeHostUpgrade(TestKubeHostUpgrade):
|
|||||||
self.assertEqual(upgrade['host_id'], host_id)
|
self.assertEqual(upgrade['host_id'], host_id)
|
||||||
host_id += 1
|
host_id += 1
|
||||||
|
|
||||||
def test_all_ignore_profile(self):
|
|
||||||
# Create hosts
|
|
||||||
self._create_controller_0()
|
|
||||||
self._create_controller_1()
|
|
||||||
worker = self._create_worker(mgmt_ip='192.168.24.12')
|
|
||||||
self._create_worker(mgmt_ip='192.168.24.13',
|
|
||||||
unit=1,
|
|
||||||
recordtype='profile')
|
|
||||||
data = self.get_json('/kube_host_upgrades')
|
|
||||||
self.assertEqual(3, len(data['kube_host_upgrades']))
|
|
||||||
host_id = 1
|
|
||||||
for upgrade in data['kube_host_upgrades']:
|
|
||||||
self.assertIn('id', upgrade)
|
|
||||||
assert (uuidutils.is_uuid_like(upgrade['uuid']))
|
|
||||||
self.assertEqual(upgrade['target_version'], None)
|
|
||||||
self.assertEqual(upgrade['status'], None)
|
|
||||||
if upgrade['host_id'] == worker.id:
|
|
||||||
self.assertEqual(upgrade['control_plane_version'], 'N/A')
|
|
||||||
else:
|
|
||||||
self.assertEqual(upgrade['control_plane_version'], 'v1.42.1')
|
|
||||||
self.assertEqual(upgrade['kubelet_version'], 'v1.42.2')
|
|
||||||
self.assertEqual(upgrade['host_id'], host_id)
|
|
||||||
host_id += 1
|
|
||||||
|
|
||||||
def test_all_no_dynamic_info(self):
|
def test_all_no_dynamic_info(self):
|
||||||
# Create hosts
|
# Create hosts
|
||||||
self._create_controller_0()
|
self._create_controller_0()
|
||||||
|
@ -1,384 +0,0 @@
|
|||||||
# 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.
|
|
||||||
#
|
|
||||||
# Copyright (c) 2017 Wind River Systems, Inc.
|
|
||||||
#
|
|
||||||
|
|
||||||
import mock
|
|
||||||
from six.moves import http_client
|
|
||||||
|
|
||||||
from sysinv.common import constants
|
|
||||||
from sysinv.common import utils as cutils
|
|
||||||
from sysinv.db import api as dbapi
|
|
||||||
from sysinv.tests.api import base
|
|
||||||
from sysinv.tests.db import utils as dbutils
|
|
||||||
|
|
||||||
HEADER = {'User-Agent': 'sysinv'}
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileTestCase(base.FunctionalTest):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(ProfileTestCase, self).setUp()
|
|
||||||
self.dbapi = dbapi.get_instance()
|
|
||||||
self.system = dbutils.create_test_isystem()
|
|
||||||
self.load = dbutils.create_test_load()
|
|
||||||
self.controller = dbutils.create_test_ihost(
|
|
||||||
id='1',
|
|
||||||
uuid=None,
|
|
||||||
forisystemid=self.system.id,
|
|
||||||
hostname='controller-0',
|
|
||||||
personality=constants.CONTROLLER,
|
|
||||||
subfunctions=constants.CONTROLLER,
|
|
||||||
invprovision=constants.PROVISIONED,
|
|
||||||
)
|
|
||||||
self.worker = dbutils.create_test_ihost(
|
|
||||||
id='2',
|
|
||||||
uuid=None,
|
|
||||||
forisystemid=self.system.id,
|
|
||||||
hostname='worker-0',
|
|
||||||
personality=constants.WORKER,
|
|
||||||
subfunctions=constants.WORKER,
|
|
||||||
mgmt_mac='01:02.03.04.05.C0',
|
|
||||||
mgmt_ip='192.168.24.12',
|
|
||||||
invprovision=constants.PROVISIONED,
|
|
||||||
)
|
|
||||||
self.profile = {
|
|
||||||
'profilename': 'profile-node1',
|
|
||||||
'ihost_uuid': self.controller.uuid,
|
|
||||||
}
|
|
||||||
self.ctrlnode = self.dbapi.inode_create(self.controller.id,
|
|
||||||
dbutils.get_test_node(id=1))
|
|
||||||
self.ctrlcpu = self.dbapi.icpu_create(
|
|
||||||
self.controller.id,
|
|
||||||
dbutils.get_test_icpu(id=1, cpu=0,
|
|
||||||
forihostid=self.controller.id,
|
|
||||||
forinodeid=self.ctrlnode.id,))
|
|
||||||
|
|
||||||
self.ctrlif = dbutils.create_test_interface(
|
|
||||||
forihostid=self.controller.id)
|
|
||||||
self.port1 = dbutils.create_test_ethernet_port(
|
|
||||||
id='1', name=self.ctrlif.ifname, host_id=self.controller.id,
|
|
||||||
interface_id=self.ctrlif.id, mac='08:00:27:43:60:11')
|
|
||||||
|
|
||||||
self.ctrlmemory = self.dbapi.imemory_create(
|
|
||||||
self.controller.id,
|
|
||||||
dbutils.get_test_imemory(id=1,
|
|
||||||
hugepages_configured=True,
|
|
||||||
forinodeid=self.ctrlcpu.forinodeid))
|
|
||||||
|
|
||||||
self.compnode = self.dbapi.inode_create(self.worker.id,
|
|
||||||
dbutils.get_test_node(id=2))
|
|
||||||
self.compcpu = self.dbapi.icpu_create(
|
|
||||||
self.worker.id,
|
|
||||||
dbutils.get_test_icpu(id=5, cpu=3,
|
|
||||||
forinodeid=self.compnode.id,
|
|
||||||
forihostid=self.worker.id))
|
|
||||||
self.compcpuapp = self.dbapi.icpu_create(
|
|
||||||
self.worker.id,
|
|
||||||
dbutils.get_test_icpu(id=6, cpu=4, forinodeid=self.compnode.id, forihostid=self.worker.id,
|
|
||||||
allocated_function=constants.APPLICATION_FUNCTION))
|
|
||||||
self.compmemory = self.dbapi.imemory_create(
|
|
||||||
self.worker.id,
|
|
||||||
dbutils.get_test_imemory(id=2, Hugepagesize=constants.MIB_1G,
|
|
||||||
forinodeid=self.compcpu.forinodeid))
|
|
||||||
|
|
||||||
self.disk = self.dbapi.idisk_create(
|
|
||||||
self.worker.id,
|
|
||||||
dbutils.get_test_idisk(device_node='/dev/sdb',
|
|
||||||
device_type=constants.DEVICE_TYPE_HDD))
|
|
||||||
self.lvg = self.dbapi.ilvg_create(
|
|
||||||
self.worker.id,
|
|
||||||
dbutils.get_test_lvg(lvm_vg_name=constants.LVG_NOVA_LOCAL))
|
|
||||||
self.pv = self.dbapi.ipv_create(
|
|
||||||
self.worker.id,
|
|
||||||
dbutils.get_test_pv(lvm_vg_name=constants.LVG_NOVA_LOCAL,
|
|
||||||
disk_or_part_uuid=self.disk.uuid))
|
|
||||||
|
|
||||||
def _get_path(self, path=None):
|
|
||||||
if path:
|
|
||||||
return '/iprofile/' + path
|
|
||||||
else:
|
|
||||||
return '/iprofile'
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileCreateTestCase(ProfileTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(ProfileCreateTestCase, self).setUp()
|
|
||||||
|
|
||||||
def create_profile(self, profiletype):
|
|
||||||
self.profile["profiletype"] = profiletype
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
def test_create_cpu_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_CPU
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
def test_create_interface_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_INTERFACE
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
def test_create_memory_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_MEMORY
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
def test_create_storage_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_STORAGE
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileDeleteTestCase(ProfileTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(ProfileDeleteTestCase, self).setUp()
|
|
||||||
|
|
||||||
def test_delete_cpu_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_CPU
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
profile_data = self.get_json('%s' % self._get_path())
|
|
||||||
cpuprofile_data = self.get_json(
|
|
||||||
'%s' % self._get_path(profile_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(post_response.json['uuid'], cpuprofile_data['uuid'])
|
|
||||||
self.delete(
|
|
||||||
'%s/%s' % (self._get_path(), post_response.json['uuid']))
|
|
||||||
|
|
||||||
def test_delete_interface_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_INTERFACE
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
profile_data = self.get_json('%s' % self._get_path())
|
|
||||||
ifprofile_data = self.get_json(
|
|
||||||
'%s' % self._get_path(profile_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(post_response.json['uuid'], ifprofile_data['uuid'])
|
|
||||||
self.delete(
|
|
||||||
'%s/%s' % (self._get_path(), post_response.json['uuid']))
|
|
||||||
|
|
||||||
def test_delete_memory_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_MEMORY
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
profile_data = self.get_json('%s' % self._get_path())
|
|
||||||
memprofile_data = self.get_json(
|
|
||||||
'%s' % self._get_path(profile_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(post_response.json['uuid'], memprofile_data['uuid'])
|
|
||||||
self.delete(
|
|
||||||
'%s/%s' % (self._get_path(), post_response.json['uuid']))
|
|
||||||
|
|
||||||
def test_delete_storage_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_STORAGE
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
profile_data = self.get_json('%s' % self._get_path())
|
|
||||||
storprofile_data = self.get_json(
|
|
||||||
'%s' % self._get_path(profile_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(post_response.json['uuid'], storprofile_data['uuid'])
|
|
||||||
self.delete(
|
|
||||||
'%s/%s' % (self._get_path(), post_response.json['uuid']))
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileShowTestCase(ProfileTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(ProfileShowTestCase, self).setUp()
|
|
||||||
|
|
||||||
def test_show_cpu_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_CPU
|
|
||||||
self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
show_data = self.get_json(
|
|
||||||
'%s/icpus' % self._get_path(list_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(self.ctrlcpu.allocated_function,
|
|
||||||
show_data['icpus'][0]['allocated_function'])
|
|
||||||
|
|
||||||
def test_show_interface_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_INTERFACE
|
|
||||||
self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
show_data = self.get_json('%s/iinterfaces' % self._get_path(
|
|
||||||
list_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(self.ctrlif.ifname,
|
|
||||||
show_data['iinterfaces'][0]['ifname'])
|
|
||||||
self.assertEqual(self.ctrlif.iftype,
|
|
||||||
show_data['iinterfaces'][0]['iftype'])
|
|
||||||
|
|
||||||
@mock.patch.object(cutils, 'is_virtual')
|
|
||||||
def test_show_memory_success(self, mock_is_virtual):
|
|
||||||
mock_is_virtual.return_value = True
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_MEMORY
|
|
||||||
self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
show_data = self.get_json(
|
|
||||||
'%s/imemorys' % self._get_path(list_data['iprofiles'][0]['uuid']))
|
|
||||||
self.assertEqual(self.ctrlmemory.platform_reserved_mib,
|
|
||||||
show_data['imemorys'][0]['platform_reserved_mib'])
|
|
||||||
self.assertEqual(self.ctrlmemory.vm_hugepages_nr_2M,
|
|
||||||
show_data['imemorys'][0]['vm_hugepages_nr_2M_pending'])
|
|
||||||
self.assertEqual(self.ctrlmemory.vm_hugepages_nr_1G,
|
|
||||||
show_data['imemorys'][0]['vm_hugepages_nr_1G_pending'])
|
|
||||||
|
|
||||||
def test_show_storage_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_STORAGE
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
profile_uuid = list_data['iprofiles'][0]['uuid']
|
|
||||||
show_data = self.get_json(
|
|
||||||
'%s/idisks' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(self.disk.device_path,
|
|
||||||
show_data['idisks'][0]['device_path'])
|
|
||||||
show_data = self.get_json(
|
|
||||||
'%s/ipvs' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(self.pv.pv_type,
|
|
||||||
show_data['ipvs'][0]['pv_type'])
|
|
||||||
show_data = self.get_json(
|
|
||||||
'%s/ilvgs' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(self.lvg.lvm_vg_name,
|
|
||||||
show_data['ilvgs'][0]['lvm_vg_name'])
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileListTestCase(ProfileTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(ProfileListTestCase, self).setUp()
|
|
||||||
|
|
||||||
def test_list_cpu_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_CPU
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
self.assertEqual(post_response.json['uuid'],
|
|
||||||
list_data['iprofiles'][0]['uuid'])
|
|
||||||
|
|
||||||
def test_list_interface_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_INTERFACE
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
self.assertEqual(post_response.json['uuid'],
|
|
||||||
list_data['iprofiles'][0]['uuid'])
|
|
||||||
|
|
||||||
def test_list_memory_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_MEMORY
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
self.assertEqual(post_response.json['uuid'],
|
|
||||||
list_data['iprofiles'][0]['uuid'])
|
|
||||||
|
|
||||||
def test_list_storage_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_STORAGE
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
post_response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
self.assertEqual(post_response.json['uuid'],
|
|
||||||
list_data['iprofiles'][0]['uuid'])
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileApplyTestCase(ProfileTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(ProfileApplyTestCase, self).setUp()
|
|
||||||
|
|
||||||
def test_apply_cpu_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_CPU
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
profile_uuid = list_data['iprofiles'][0]['uuid']
|
|
||||||
result = self.patch_dict_json('/ihosts/%s' % self.worker.id,
|
|
||||||
headers=HEADER,
|
|
||||||
action=constants.APPLY_PROFILE_ACTION,
|
|
||||||
iprofile_uuid=profile_uuid)
|
|
||||||
self.assertEqual(http_client.OK, result.status_int)
|
|
||||||
|
|
||||||
hostcpu_r = self.get_json(
|
|
||||||
'/ihosts/%s/icpus' % self.worker.uuid)
|
|
||||||
profile_r = self.get_json(
|
|
||||||
'%s/icpus' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(hostcpu_r['icpus'][0]['allocated_function'],
|
|
||||||
profile_r['icpus'][0]['allocated_function'])
|
|
||||||
|
|
||||||
@mock.patch.object(cutils, 'is_virtual')
|
|
||||||
def test_apply_memory_success(self, mock_is_virtual):
|
|
||||||
mock_is_virtual.return_value = True
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_MEMORY
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
profile_uuid = list_data['iprofiles'][0]['uuid']
|
|
||||||
result = self.patch_dict_json('/ihosts/%s' % self.worker.id,
|
|
||||||
headers=HEADER,
|
|
||||||
action=constants.APPLY_PROFILE_ACTION,
|
|
||||||
iprofile_uuid=profile_uuid)
|
|
||||||
self.assertEqual(http_client.OK, result.status_int)
|
|
||||||
|
|
||||||
hostmem_r = self.get_json(
|
|
||||||
'/ihosts/%s/imemorys' % self.worker.uuid)
|
|
||||||
profile_r = self.get_json(
|
|
||||||
'%s/imemorys' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(hostmem_r['imemorys'][0]['platform_reserved_mib'],
|
|
||||||
profile_r['imemorys'][0]['platform_reserved_mib'])
|
|
||||||
self.assertEqual(hostmem_r['imemorys'][0]['vm_hugepages_nr_2M_pending'],
|
|
||||||
profile_r['imemorys'][0]['vm_hugepages_nr_2M_pending'])
|
|
||||||
self.assertEqual(hostmem_r['imemorys'][0]['vm_hugepages_nr_1G_pending'],
|
|
||||||
profile_r['imemorys'][0]['vm_hugepages_nr_1G_pending'])
|
|
||||||
self.assertEqual(hostmem_r['imemorys'][0]['vswitch_hugepages_reqd'],
|
|
||||||
profile_r['imemorys'][0]['vswitch_hugepages_reqd'])
|
|
||||||
|
|
||||||
def test_apply_storage_success(self):
|
|
||||||
self.profile["profiletype"] = constants.PROFILE_TYPE_LOCAL_STORAGE
|
|
||||||
self.profile["ihost_uuid"] = self.worker.uuid
|
|
||||||
response = self.post_json('%s' % self._get_path(), self.profile)
|
|
||||||
self.assertEqual(http_client.OK, response.status_int)
|
|
||||||
|
|
||||||
list_data = self.get_json('%s' % self._get_path())
|
|
||||||
profile_uuid = list_data['iprofiles'][0]['uuid']
|
|
||||||
|
|
||||||
# Delete Physical volume and disassociate it from disk
|
|
||||||
self.delete('/ipvs/%s' % self.pv.uuid)
|
|
||||||
self.dbapi.idisk_update(self.disk.uuid,
|
|
||||||
{'foripvid': None, 'foristorid': None})
|
|
||||||
# Delete Local Volume
|
|
||||||
self.delete('/ilvgs/%s' % self.lvg.uuid)
|
|
||||||
|
|
||||||
# Apply storage profile
|
|
||||||
result = self.patch_dict_json('/ihosts/%s' % self.worker.id,
|
|
||||||
headers=HEADER,
|
|
||||||
action=constants.APPLY_PROFILE_ACTION,
|
|
||||||
iprofile_uuid=profile_uuid)
|
|
||||||
self.assertEqual(http_client.OK, result.status_int)
|
|
||||||
|
|
||||||
hostdisk_r = self.get_json(
|
|
||||||
'/ihosts/%s/idisks' % self.worker.uuid)
|
|
||||||
profile_r = self.get_json(
|
|
||||||
'%s/idisks' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(hostdisk_r['idisks'][0]['device_path'],
|
|
||||||
profile_r['idisks'][0]['device_path'])
|
|
||||||
|
|
||||||
hostpv_r = self.get_json(
|
|
||||||
'/ihosts/%s/ipvs' % self.worker.uuid)
|
|
||||||
profile_r = self.get_json(
|
|
||||||
'%s/ipvs' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(hostpv_r['ipvs'][1]['pv_type'],
|
|
||||||
profile_r['ipvs'][0]['pv_type'])
|
|
||||||
if not profile_r['ipvs'][0].get('disk_or_part_device_path'):
|
|
||||||
self.assertEqual(hostpv_r['ipvs'][1]['lvm_pv_name'],
|
|
||||||
profile_r['ipvs'][0]['lvm_pv_name'])
|
|
||||||
|
|
||||||
hostlvg_r = self.get_json(
|
|
||||||
'/ihosts/%s/ilvgs' % self.worker.uuid)
|
|
||||||
profile_r = self.get_json(
|
|
||||||
'%s/ilvgs' % self._get_path(profile_uuid))
|
|
||||||
self.assertEqual(hostlvg_r['ilvgs'][0]['lvm_vg_name'],
|
|
||||||
profile_r['ilvgs'][0]['lvm_vg_name'])
|
|
Loading…
Reference in New Issue
Block a user