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:
Pablo Bovina 2021-09-08 01:29:12 -03:00
parent 914e6bc6c4
commit e535293c68
33 changed files with 291 additions and 6475 deletions

View File

@ -326,16 +326,6 @@ itemNotFound (404)
"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": [
{
"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.
---------
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
----

View File

@ -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())

View File

@ -54,10 +54,10 @@ def reset_config_target():
conn = psycopg2.connect("dbname=sysinv user=postgres")
with conn:
with conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute("update i_host set config_target=NULL where "
"recordtype!='profile'",)
cur.execute("update i_host set config_target=NULL",)
LOG.info("Reset host config_target completed")
if __name__ == "__main__":
sys.exit(main())

View File

@ -4,7 +4,7 @@
#
# Copyright (C) 2019 Intel Corporation
#
# Copyright (c) 2019 Wind River Systems, Inc.
# Copyright (c) 2021 Wind River Systems, Inc.
#
# lib/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_CONF_DIR/policy.json
sudo rm -f $SYSINV_CONF_DIR/profileSchema.xsd
sudo rm -f $SYSINV_ETC_MOTDD/10-system
sudo rm -f $SYSINV_CONF_DIR/upgrades/delete_load.sh
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 -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 640 $SYSINV_DIR/etc/sysinv/profileSchema.xsd $SYSINV_CONF_DIR/profileSchema.xsd
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 -d -m 755 $SYSINV_CONF_DIR/upgrades

View File

@ -29,7 +29,6 @@ features:
- Node role and role profiles.
- Core and memory (including huge page) assignments.
- Network Interfaces and storage assignments.
- Bulk configuration of nodes through system profiles.
- |
User Interface:

View File

@ -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 -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-controller-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-controller-model.txt

View File

@ -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 -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-controller-model.txt %{buildroot}%{local_etc_sysinv}/crushmap-controller-model.txt

View File

@ -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>

View File

@ -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>

View File

@ -64,7 +64,6 @@ from sysinv.api.controllers.v1 import ntp
from sysinv.api.controllers.v1 import partition
from sysinv.api.controllers.v1 import pci_device
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 pv
from sysinv.api.controllers.v1 import registry_image
@ -135,9 +134,6 @@ class V1(base.APIBase):
imemory = [link.Link]
"Links to the imemory resource"
iprofile = [link.Link]
"Links to the iprofile resource"
iuser = [link.Link]
"Links to the iuser resource"
@ -348,14 +344,6 @@ class V1(base.APIBase):
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',
pecan.request.host_url,
'iinterfaces', ''),
@ -896,7 +884,6 @@ class Controller(rest.RestController):
ipvs = pv.PVController()
idisks = disk.DiskController()
partitions = partition.PartitionController()
iprofile = profile.ProfileController()
iuser = user.UserController()
idns = dns.DNSController()
intp = ntp.NTPController()

View File

@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations
# 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
# replace ihost_uuid and inode_uuid with corresponding
patch_obj = jsonpatch.JsonPatch(patch)
from_profile = False
action = None
for p in patch_obj:
if p['path'] == '/ihost_uuid':
@ -395,9 +394,6 @@ class CPUController(rest.RestController):
except exception.SysinvException:
p['value'] = None
if p['path'] == '/allocated_function':
from_profile = True
if p['path'] == '/action':
value = p['value']
patch.remove(p)
@ -428,8 +424,7 @@ class CPUController(rest.RestController):
# Semantic checks
ihost = pecan.request.dbapi.ihost_get(cpu.forihostid)
_check_host(ihost)
if not from_profile:
_check_cpu(cpu, ihost)
_check_cpu(cpu, ihost)
# Update only the fields that have changed
try:
@ -463,7 +458,7 @@ class CPUController(rest.RestController):
##############
# UTILS
##############
def _update(cpu_uuid, cpu_values, from_profile=False):
def _update(cpu_uuid, cpu_values):
# Get CPU
cpu = objects.cpu.get_by_uuid(
pecan.request.context, cpu_uuid)
@ -471,8 +466,7 @@ def _update(cpu_uuid, cpu_values, from_profile=False):
# Semantic checks
ihost = pecan.request.dbapi.ihost_get(cpu.forihostid)
_check_host(ihost)
if not from_profile:
_check_cpu(cpu, ihost)
_check_cpu(cpu, ihost)
# Update cpu
pecan.request.dbapi.icpu_update(cpu_uuid, cpu_values)

View File

@ -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
#
@ -26,100 +26,6 @@ VSWITCH_MIN_CORES = 0
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):
for f in CORE_FUNCTIONS:
if s.lower() == f.lower():
@ -127,31 +33,6 @@ def lookup_function(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):
platform_cores = 0
vswitch_cores = 0

View File

@ -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 memory
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 sensor as sensor_api
from sysinv.api.controllers.v1 import sensorgroup
@ -460,9 +459,6 @@ class Host(base.APIBase):
isystem_uuid = types.uuid
"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})
"This peers of this host in the cluster"
@ -567,9 +563,6 @@ class Host(base.APIBase):
for k in self.fields:
setattr(self, k, kwargs.get(k))
self.fields.append('iprofile_uuid')
setattr(self, 'iprofile_uuid', kwargs.get('iprofile_uuid', None))
self.fields.append('peers')
setattr(self, 'peers', kwargs.get('peers', None))
@ -903,7 +896,6 @@ class HostUpdate(object):
self.ihost_orig = dict(ihost_orig)
self.ihost_patch = dict(ihost_patch)
self._delta = list(delta)
self._iprofile_uuid = None
self._ihost_val_prenotify = {}
self._ihost_val = {}
@ -946,14 +938,6 @@ class HostUpdate(object):
def nextstep(self, 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
def configure_required(self):
return self._configure_required
@ -1502,8 +1486,7 @@ class HostController(rest.RestController):
pecan.request.context, ihost_dict['rootfs_device'])
controller_ihost = pecan.request.rpcapi.create_ihost(
pecan.request.context, ihost_dict)
if 'recordtype' in ihost_dict and \
ihost_dict['recordtype'] != "profile":
if 'recordtype' in ihost_dict:
pecan.request.rpcapi.configure_ihost(
pecan.request.context,
controller_ihost)
@ -1756,8 +1739,7 @@ class HostController(rest.RestController):
" contain(s) a management mac address"
" from local network adapters")
self._patch(ihost_obj[0]['uuid'],
changed_paths, None)
self._patch(ihost_obj[0]['uuid'], changed_paths)
else:
self._do_post(new_host)
@ -1829,34 +1811,28 @@ class HostController(rest.RestController):
"""
utils.validate_patch(patch)
profile_uuid = None
optimizable = 0
optimize_list = ['/uptime', '/location', '/serialid', '/task']
for p in patch:
# Check if this patch contains a profile
path = p['path']
if path == '/iprofile_uuid':
profile_uuid = p['value']
patch.remove(p)
if path in optimize_list:
optimizable += 1
if len(patch) == optimizable:
return self._patch(uuid, patch, profile_uuid)
return self._patch(uuid, patch)
elif (pecan.request.user_agent.startswith('mtce') or
pecan.request.user_agent.startswith('vim')):
return self._patch_sys(uuid, patch, profile_uuid)
return self._patch_sys(uuid, patch)
else:
return self._patch_gen(uuid, patch, profile_uuid)
return self._patch_gen(uuid, patch)
@cutils.synchronized(LOCK_NAME_SYS)
def _patch_sys(self, uuid, patch, profile_uuid):
return self._patch(uuid, patch, profile_uuid)
def _patch_sys(self, uuid, patch):
return self._patch(uuid, patch)
@cutils.synchronized(LOCK_NAME)
def _patch_gen(self, uuid, patch, profile_uuid):
return self._patch(uuid, patch, profile_uuid)
def _patch_gen(self, uuid, patch):
return self._patch(uuid, patch)
@staticmethod
def _validate_capability_is_not_set(old, new):
@ -1914,7 +1890,7 @@ class HostController(rest.RestController):
"name={}, value={}. ").format(
capability, new_value))
def _patch(self, uuid, patch, myprofile_uuid):
def _patch(self, uuid, patch):
log_start = cutils.timestamped("ihost_patch_start")
patch_obj = jsonpatch.JsonPatch(patch)
@ -2004,8 +1980,6 @@ class HostController(rest.RestController):
hostupdate.notify_mtce,
hostupdate.skip_notify_mtce))
hostupdate.iprofile_uuid = myprofile_uuid
if self.stage_action(myaction, hostupdate):
LOG.info("%s Action staged: %s" %
(hostupdate.displayid, myaction))
@ -2409,13 +2383,6 @@ class HostController(rest.RestController):
ihost = objects.host.get_by_uuid(pecan.request.context,
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.hostname is None:
host = ihost.uuid
@ -4641,7 +4608,6 @@ class HostController(rest.RestController):
constants.VIM_SERVICES_DISABLE_FAILED,
constants.VIM_SERVICES_DISABLE_EXTEND,
constants.VIM_SERVICES_DELETE_FAILED,
constants.APPLY_PROFILE_ACTION,
constants.SUBFUNCTION_CONFIG_ACTION]
if action not in valid_actions:
@ -4727,8 +4693,6 @@ class HostController(rest.RestController):
self.update_vim_progress_status(action, hostupdate)
elif action == constants.VIM_SERVICES_DELETE_FAILED:
self.update_vim_progress_status(action, hostupdate)
elif action == constants.APPLY_PROFILE_ACTION:
self._check_apply_profile(hostupdate)
elif action == constants.SUBFUNCTION_CONFIG_ACTION:
self._check_subfunction_config(hostupdate)
self._semantic_check_nova_local_storage(
@ -4783,20 +4747,6 @@ class HostController(rest.RestController):
else:
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
def check_notify_mtce(action, hostupdate):
"""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)
hostupdate.nextstep = hostupdate.EXIT_UPDATE_PREVAL
rc = False
elif action == constants.APPLY_PROFILE_ACTION:
self._stage_apply_profile_action(hostupdate)
elif action == constants.SUBFUNCTION_CONFIG_ACTION:
# Not a mtc action; disable mtc checks and config
self._stage_subfunction_config(hostupdate)
@ -6655,18 +6603,6 @@ class HostController(rest.RestController):
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
def _check_subfunction_config(hostupdate):
"""Check subfunction config."""

View File

@ -698,7 +698,7 @@ def _set_defaults(interface):
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
if 'vlan_id' in interface.keys() and interface['vlan_id'] is not None:
if not str(interface['vlan_id']).isdigit():
@ -712,7 +712,7 @@ def _check_interface_vlan_id(op, interface, ihost, from_profile=False):
return interface
def _check_interface_name(op, interface, ihost, from_profile=False):
def _check_interface_name(op, interface, ihost):
ihost_id = interface['forihostid']
ifname = interface['ifname']
iftype = interface['iftype']
@ -763,7 +763,7 @@ def _check_interface_name(op, interface, ihost, from_profile=False):
return interface
def _check_interface_mtu(interface, ihost, from_profile=False):
def _check_interface_mtu(interface, ihost):
# Check imtu
if 'imtu' in interface.keys() and interface['imtu'] is not None:
if not str(interface['imtu']).isdigit():
@ -774,7 +774,7 @@ def _check_interface_mtu(interface, ihost, from_profile=False):
return interface
def _check_interface_sriov(interface, ihost, from_profile=False):
def _check_interface_sriov(interface, ihost):
sriov_update = False
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']
# Check interface name for validity
_check_interface_name(op, interface, ihost, existing_interface)
_check_interface_name(op, interface, ihost)
if op == "add":
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)
def _update_ipv6_address_mode(interface, mode=None, pool=None,
from_profile=False):
def _update_ipv6_address_mode(interface, mode=None, pool=None):
mode = interface['ipv6_mode'] if not mode else mode
pool = interface['ipv6_pool'] if not pool else 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)
def _update_ipv4_address_mode(interface, mode=None, pool=None,
interface_profile=False):
def _update_ipv4_address_mode(interface, mode=None, pool=None):
mode = interface['ipv4_mode'] if not mode else mode
pool = interface['ipv4_pool'] if not pool else 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)
@ -1528,13 +1526,11 @@ def _add_extended_attributes(ihost, interface, attributes):
if attributes.get('ipv4_mode'):
_update_ipv4_address_mode(interface_data,
attributes.get('ipv4_mode'),
attributes.get('ipv4_pool'),
attributes.get('interface_profile'))
attributes.get('ipv4_pool'))
if attributes.get('ipv6_mode'):
_update_ipv6_address_mode(interface_data,
attributes.get('ipv6_mode'),
attributes.get('ipv6_pool'),
attributes.get('interface_profile'))
attributes.get('ipv6_pool'))
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
# request e.g. through profile.py while still passing
# through interface semantic checks and osd configuration
# request while still passing through interface semantic checks and osd
# configuration
# Hence, not declared inside a class
#
# Param:
# interface - dictionary of interface values
def _create(interface, from_profile=False):
def _create(interface):
# Get host
ihostId = interface.get('forihostid') or interface.get('ihost_uuid')
ihost = pecan.request.dbapi.ihost_get(ihostId)
@ -1776,21 +1772,19 @@ def _create(interface, from_profile=False):
interface.update({'used_by': []})
# 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
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
if not from_profile:
interface = _set_defaults(interface)
interface = _set_defaults(interface)
# 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)
interface = set_interface_mac(ihost, interface)
# Select appropriate MAC address from lower interface(s)
interface = set_interface_mac(ihost, interface)
new_interface = pecan.request.dbapi.iinterface_create(
forihostid,
@ -1845,8 +1839,8 @@ def _create(interface, from_profile=False):
return new_interface
def _check(op, interface, ports=None, ifaces=None, from_profile=False,
existing_interface=None, datanetworks=None):
def _check(op, interface, ports=None, ifaces=None, existing_interface=None,
datanetworks=None):
# Semantic checks
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:
_check_host(ihost)
if not from_profile:
if ports:
_check_ports(op, interface, ihost, ports)
if ifaces:
interfaces = pecan.request.dbapi.iinterface_get_by_ihost(interface['ihost_uuid'])
if len(ifaces) > 1 and \
interface['iftype'] == constants.INTERFACE_TYPE_VLAN:
# Can only have one interface associated to vlan interface type
if ports:
_check_ports(op, interface, ihost, ports)
if ifaces:
interfaces = pecan.request.dbapi.iinterface_get_by_ihost(interface['ihost_uuid'])
if len(ifaces) > 1 and \
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(
_("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(
_("Can only have one lower interface for ethernet type."
"(%s)" % ifaces))
lower = pecan.request.dbapi.iinterface_get(ifaces[0],
interface['ihost_uuid'])
if not (lower['iftype'] == constants.INTERFACE_TYPE_ETHERNET
and lower['ifclass'] ==
constants.INTERFACE_CLASS_PCI_SRIOV):
# Can only have pci_sriov ethernet type lower interface
# associated to ethernet interface type
raise wsme.exc.ClientSideError(
_("Can only use pci-sriov ethernet interface for "
"ethernet type. (%s)" % ifaces))
_("Can only have one lower interface for ethernet type."
"(%s)" % ifaces))
lower = pecan.request.dbapi.iinterface_get(ifaces[0],
interface['ihost_uuid'])
if not (lower['iftype'] == constants.INTERFACE_TYPE_ETHERNET
and lower['ifclass'] ==
constants.INTERFACE_CLASS_PCI_SRIOV):
# Can only have pci_sriov ethernet type lower interface
# 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 iface in interfaces:
if iface['uuid'] == i or iface['ifname'] == i:
existing_iface = copy.deepcopy(iface)
for i in ifaces:
for iface in interfaces:
if iface['uuid'] == i or iface['ifname'] == i:
existing_iface = copy.deepcopy(iface)
# Get host
ihost = pecan.request.dbapi.ihost_get(
iface.get('forihostid'))
# Get host
ihost = pecan.request.dbapi.ihost_get(
iface.get('forihostid'))
if 'vlan_id' not in iface:
iface['vlan_id'] = None
if 'vlan_id' not in iface:
iface['vlan_id'] = None
if 'aemode' not in iface:
iface['aemode'] = None
if 'aemode' not in iface:
iface['aemode'] = None
if 'txhashpolicy' not in iface:
iface['txhashpolicy'] = None
if 'txhashpolicy' not in iface:
iface['txhashpolicy'] = None
if 'primary_reselect' not in iface:
iface['primary_reselect'] = None
if 'primary_reselect' not in iface:
iface['primary_reselect'] = None
_check_interface_data(
"modify", iface, ihost, existing_iface, datanetworks)
_check_interface_data(
"modify", iface, ihost, existing_iface, datanetworks)
interface = _check_interface_data(
op, interface, ihost, existing_interface, datanetworks)
interface = _check_interface_data(
op, interface, ihost, existing_interface, datanetworks)
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)
@ -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)
def _delete(interface, from_profile=False):
def _delete(interface):
ihost = pecan.request.dbapi.ihost_get(interface['forihostid']).as_dict()
if not from_profile:
check_host = True
if (cutils.is_aio_simplex_system(pecan.request.dbapi)
and interface['ifclass'] == constants.INTERFACE_CLASS_PCI_SRIOV
and interface['iftype'] == constants.INTERFACE_TYPE_VF):
# user can delete interface SR-IOV VF without host lock in AIO-SX
check_host = False
check_host = True
if (cutils.is_aio_simplex_system(pecan.request.dbapi)
and interface['ifclass'] == constants.INTERFACE_CLASS_PCI_SRIOV
and interface['iftype'] == constants.INTERFACE_TYPE_VF):
# user can delete interface SR-IOV VF without host lock in AIO-SX
check_host = False
if check_host:
_check_host(ihost)
if check_host:
_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")
raise wsme.exc.ClientSideError(msg)
@ -2075,3 +2069,5 @@ def _is_interface_address_allowed(interface):
elif interface['ifclass'] == constants.INTERFACE_CLASS_PLATFORM:
return True
return False
# TODO (pbovina): Move utils methods within InterfaceController class

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2013-2018 Wind River Systems, Inc.
# Copyright (c) 2013-2021 Wind River Systems, Inc.
#
import os
@ -175,26 +175,25 @@ class InterfaceNetworkController(rest.RestController):
constants.IPV4_DISABLED, None)
# Assign an address to the interface
if host.recordtype != "profile":
_update_host_address(host, interface_obj, network_type)
if network_type == constants.NETWORK_TYPE_MGMT:
ethernet_port_mac = None
if not interface_obj.uses:
# Get the ethernet port associated with the interface
interface_ports = pecan.request.dbapi.ethernet_port_get_by_interface(
interface_obj.uuid)
for p in interface_ports:
if p is not None:
ethernet_port_mac = p.mac
break
else:
tmp_interface = interface_obj.as_dict()
ethernet_port_mac = tmp_interface['imac']
_update_host_mgmt_mac(host, ethernet_port_mac)
cutils.perform_distributed_cloud_config(pecan.request.dbapi,
_update_host_address(host, interface_obj, network_type)
if network_type == constants.NETWORK_TYPE_MGMT:
ethernet_port_mac = None
if not interface_obj.uses:
# Get the ethernet port associated with the interface
interface_ports = pecan.request.dbapi.ethernet_port_get_by_interface(
interface_obj.uuid)
for p in interface_ports:
if p is not None:
ethernet_port_mac = p.mac
break
else:
tmp_interface = interface_obj.as_dict()
ethernet_port_mac = tmp_interface['imac']
_update_host_mgmt_mac(host, ethernet_port_mac)
cutils.perform_distributed_cloud_config(pecan.request.dbapi,
interface_id)
elif network_type == constants.NETWORK_TYPE_OAM:
pecan.request.rpcapi.initialize_oam_config(pecan.request.context, host)
elif network_type == constants.NETWORK_TYPE_OAM:
pecan.request.rpcapi.initialize_oam_config(pecan.request.context, host)
return InterfaceNetwork.convert_with_links(result)

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2013-2020 Wind River Systems, Inc.
# Copyright (c) 2013-2021 Wind River Systems, Inc.
#
import jsonpatch
@ -590,7 +590,7 @@ def _check(op, lvg):
return lvg
def _create(lvg, iprofile=None, applyprofile=None):
def _create(lvg):
# Get host
ihostId = lvg.get('forihostid') or lvg.get('ihost_uuid')
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
ilvgs = pecan.request.dbapi.ilvg_get_all(forihostid=forihostid)
lvg_in_db = False
if not iprofile:
for vg in ilvgs:
if vg['lvm_vg_name'] == lvg['lvm_vg_name']:
lvg_in_db = True
# User is adding again so complain
if (vg['vg_state'] == constants.LVG_ADD or
vg['vg_state'] == constants.PROVISIONED):
raise wsme.exc.ClientSideError(_("Volume Group (%s) "
"already present" %
vg['lvm_vg_name']))
for vg in ilvgs:
if vg['lvm_vg_name'] == lvg['lvm_vg_name']:
lvg_in_db = True
# User is adding again so complain
if (vg['vg_state'] == constants.LVG_ADD or
vg['vg_state'] == constants.PROVISIONED):
raise wsme.exc.ClientSideError(_("Volume Group (%s) "
"already present" %
vg['lvm_vg_name']))
# 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
# VG as unusable because of LV corruption
if vg['vg_state'] == constants.LVG_DEL:
# User changed mind and is re-adding
values = {'vg_state': constants.LVG_ADD}
if applyprofile:
# inherit the capabilities,
if 'capabilities' in lvg and lvg['capabilities']:
values['capabilities'] = lvg['capabilities']
try:
LOG.info("Update ilvg values: %s" % values)
pecan.request.dbapi.ilvg_update(vg.id, values)
except exception.HTTPNotFound:
msg = _("LVG update failed: host (%s) LVG (%s)"
% (ihost['hostname'], vg['lvm_pv_name']))
raise wsme.exc.ClientSideError(msg)
ret_lvg = vg
break
# 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
# VG as unusable because of LV corruption
if vg['vg_state'] == constants.LVG_DEL:
# User changed mind and is re-adding
values = {'vg_state': constants.LVG_ADD}
try:
LOG.info("Update ilvg values: %s" % values)
pecan.request.dbapi.ilvg_update(vg.id, values)
except exception.HTTPNotFound:
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:
# 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']
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
LOG.info("%s defined from create %s applyprofile=%s" %
(constants.LVG_CINDER_PARAM_LVM_TYPE, lvg_caps,
applyprofile))
LOG.info("%s defined from create %s" %
(constants.LVG_CINDER_PARAM_LVM_TYPE, lvg_caps))
else:
# Default LVM type
lvg_caps_dict = {

View File

@ -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
#
@ -630,7 +630,7 @@ def _semantic_checks(operation, partition):
return partition
def _create(partition, iprofile=None, applyprofile=None):
def _create(partition):
# Reject operation if we are upgrading the system.
ihostid = partition.get('forihostid') or partition.get('ihost_uuid')
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
if (ihost.invprovision in [constants.PROVISIONED,
constants.PROVISIONING] and
not iprofile):
constants.PROVISIONING]):
partition['status'] = constants.PARTITION_CREATE_IN_SVC_STATUS
else:
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
# configuration
if (ihost.invprovision in [constants.PROVISIONED,
constants.PROVISIONING] and
not iprofile):
constants.PROVISIONING]):
# Instruct puppet to implement the change
pecan.request.rpcapi.update_partition_config(pecan.request.context,
partition)

File diff suppressed because it is too large Load Diff

View File

@ -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()

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2013-2017 Wind River Systems, Inc.
# Copyright (c) 2013-2021 Wind River Systems, Inc.
#
import jsonpatch
@ -357,14 +357,14 @@ class PVController(rest.RestController):
# This method allows creating a physical volume through a non-HTTP
# request e.g. through profile.py while still passing
# through physical volume semantic checks and osd configuration
# request while still passing through physical volume semantic checks and osd
# configuration
# Hence, not declared inside a class
#
# Param:
# pv - dictionary of physical volume values
# 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)
# Get host
ihostId = pv.get('forihostid') or pv.get('ihost_uuid')
@ -427,7 +427,7 @@ def _create(pv, iprofile=None):
values)
# 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)
raise wsme.exc.ClientSideError(
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
# Since physical volumes are reported as device nodes and not device
# paths, we need to translate this, but not for local storage profiles.
if ihost['recordtype'] != 'profile':
if 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']
# paths, we need to translate this
if 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']
# relationship checks
# - 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 -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 (pbovina): Move utils methods within PVController class

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2013-2019 Wind River Systems, Inc.
# Copyright (c) 2013-2021 Wind River Systems, Inc.
#
from eventlet.green import subprocess
@ -518,16 +518,6 @@ class StorageController(rest.RestController):
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):
ihost_id = stor['forihostid']
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
# request e.g. through profile.py while still passing
# through istor semantic checks and osd configuration
# Hence, not declared inside a class
# request
#
# Param:
# stor - dictionary of stor values
# iprofile - True when created by a storage profile
def _create(stor, iprofile=None):
def _create(stor):
LOG.debug("storage._create stor with params: %s" % stor)
# Init
@ -820,10 +807,7 @@ def _create(stor, iprofile=None):
stor.update({'forihostid': forihostid})
# SEMANTIC CHECKS
if iprofile:
_check_profile(stor)
else:
_check_host(stor)
_check_host(stor)
try:
idisk_uuid = _check_disk(stor)
@ -834,12 +818,11 @@ def _create(stor, iprofile=None):
# Assign the function if necessary.
function = stor['function']
if function:
if function == constants.STOR_FUNCTION_OSD and not iprofile:
if function == constants.STOR_FUNCTION_OSD:
osd_create = True
else:
function = stor['function'] = constants.STOR_FUNCTION_OSD
if not iprofile:
osd_create = True
osd_create = True
create_attrs = {}
create_attrs.update(stor)
@ -880,32 +863,31 @@ def _create(stor, iprofile=None):
create_attrs['fortierid'] = tier.id
if not iprofile:
try:
journal_location = \
_check_journal_location(stor['journal_location'],
stor,
constants.ACTION_CREATE_JOURNAL)
except exception.InvalidUUID as e:
raise wsme.exc.ClientSideError(_(str(e)))
try:
journal_location = \
_check_journal_location(stor['journal_location'],
stor,
constants.ACTION_CREATE_JOURNAL)
except exception.InvalidUUID as e:
raise wsme.exc.ClientSideError(_(str(e)))
# If the journal is collocated, make sure its size is set to the
# default one.
if 'uuid' in stor and journal_location == stor['uuid']:
stor['journal_size_mib'] = CONF.journal.journal_default_size
elif journal_location:
if not stor['journal_size_mib']:
stor['journal_size_mib'] = \
CONF.journal.journal_default_size
# If the journal is collocated, make sure its size is set to the
# default one.
if 'uuid' in stor and journal_location == stor['uuid']:
stor['journal_size_mib'] = CONF.journal.journal_default_size
elif journal_location:
if not stor['journal_size_mib']:
stor['journal_size_mib'] = \
CONF.journal.journal_default_size
journal_istor = pecan.request.dbapi.istor_get(journal_location)
journal_idisk_uuid = journal_istor.idisk_uuid
journal_istor = pecan.request.dbapi.istor_get(journal_location)
journal_idisk_uuid = journal_istor.idisk_uuid
# Find out if there is enough space to keep the journal on the
# journal stor.
_check_journal_space(journal_idisk_uuid,
journal_location,
stor['journal_size_mib'])
# Find out if there is enough space to keep the journal on the
# journal stor.
_check_journal_space(journal_idisk_uuid,
journal_location,
stor['journal_size_mib'])
elif function == constants.STOR_FUNCTION_JOURNAL:
# 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
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
# collocation. For collocation: stor['journal_location'] =
# 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_size", new_journal.get("size_mib"))
if not iprofile:
# Update the state of the storage tier
try:
pecan.request.dbapi.storage_tier_update(
tier.id,
{'status': constants.SB_TIER_STATUS_IN_USE})
except exception.StorageTierNotFound as e:
# Shouldn't happen. Log exception. Stor is created but tier status
# is not updated.
LOG.exception(e)
# Update the state of the storage tier
try:
pecan.request.dbapi.storage_tier_update(
tier.id,
{'status': constants.SB_TIER_STATUS_IN_USE})
except exception.StorageTierNotFound as e:
# Shouldn't happen. Log exception. Stor is created but tier status
# is not updated.
LOG.exception(e)
# Apply runtime manifests for OSDs on "available" nodes.
runtime_manifests = False

View File

@ -492,14 +492,10 @@ def _set_defaults(tier):
# This method allows creating a storage tier through a non-HTTP
# request e.g. through profile.py while still passing
# through physical volume semantic checks and osd configuration
# Hence, not declared inside a class
#
# request
# Param:
# tier - dictionary of storage tier values
# iprofile - True when created by a storage profile
def _create(self, tier, iprofile=None):
def _create(self, tier):
LOG.info("storage_tier._create with initial params: %s" % tier)
# Set defaults - before checks to allow for optional attributes

View File

@ -79,7 +79,6 @@ POWERON_ACTION = 'power-on'
POWEROFF_ACTION = 'power-off'
SWACT_ACTION = 'swact'
FORCE_SWACT_ACTION = 'force-swact'
APPLY_PROFILE_ACTION = 'apply-profile'
SUBFUNCTION_CONFIG_ACTION = 'subfunction_config'
VIM_SERVICES_ENABLED = 'services-enabled'
VIM_SERVICES_DISABLED = 'services-disabled'
@ -109,8 +108,7 @@ MTCE_ACTIONS = [REBOOT_ACTION,
VIM_ACTIONS = [LOCK_ACTION,
FORCE_LOCK_ACTION]
CONFIG_ACTIONS = [SUBFUNCTION_CONFIG_ACTION,
APPLY_PROFILE_ACTION]
CONFIG_ACTIONS = [SUBFUNCTION_CONFIG_ACTION]
# Personalities
CONTROLLER = 'controller'
@ -976,12 +974,6 @@ CEPH_CRUSH_MAP_APPLIED = '.crushmap_applied'
CEPH_CRUSH_MAP_DEPTH = 3
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
NOVA_PCI_ALIAS_GPU_NAME = "gpu"

View File

@ -236,62 +236,6 @@ class Connection(object):
: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
def inode_create(self, forihostid, values):
"""Create a new inode for a host.

View File

@ -34,7 +34,6 @@ from sqlalchemy import or_
from sqlalchemy.orm import contains_eager
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import subqueryload
from sqlalchemy.orm import with_polymorphic
from sqlalchemy.orm.exc import DetachedInstanceError
from sqlalchemy.orm.exc import MultipleResultsFound
@ -1460,59 +1459,6 @@ class Connection(api.Connection):
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):
query = model_query(models.inode)
query = add_identity_filter(query, inode_id)
@ -2379,17 +2325,13 @@ class Connection(api.Connection):
self._interface_ratelimit_encode(values)
is_profile = values.get('interface_profile', False)
with _session_for_write() as session:
# interface = models.Interfaces()
if hasattr(obj, 'uses') and values.get('uses'):
for i in list(values['uses']):
try:
if is_profile:
uses_if = self._interface_get(models.Interfaces, i, obj=obj)
else:
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
obj.uses.append(uses_if)
except NoResultFound:
raise exception.InvalidParameterValue(
@ -2402,10 +2344,7 @@ class Connection(api.Connection):
if hasattr(obj, 'used_by') and values.get('used_by'):
for i in list(values['used_by']):
try:
if is_profile:
uses_if = self._interface_get(models.Interfaces, i, obj=obj)
else:
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
uses_if = self._interface_get(models.Interfaces, i, values['forihostid'], obj=obj)
obj.used_by.append(uses_if)
except NoResultFound:
raise exception.InvalidParameterValue(
@ -5980,10 +5919,8 @@ class Connection(api.Connection):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
values['host_id'] = int(host_id)
if 'sensor_profile' in values:
values.pop('sensor_profile')
# The id is null for ae sensors with more than one member
# sensor
temp_id = obj.id
@ -6258,10 +6195,8 @@ class Connection(api.Connection):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
values['host_id'] = int(host_id)
if 'sensorgroup_profile' in values:
values.pop('sensorgroup_profile')
temp_id = obj.id
obj.update(values)
if obj.id is None:

View File

@ -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.')

View File

@ -116,7 +116,6 @@ class isystem(Base):
class ihost(Base):
recordTypeEnum = Enum('standard',
'profile',
'sprofile',
'reserve1',
'reserve2',
@ -135,7 +134,6 @@ class ihost(Base):
'worker',
'network',
'storage',
'profile',
'reserve1',
'reserve2',
'edgeworker',

View File

@ -69,7 +69,6 @@ from sysinv.objects import ntp
from sysinv.objects import pci_device
from sysinv.objects import peer
from sysinv.objects import port
from sysinv.objects import profile
from sysinv.objects import ptp
from sysinv.objects import ptp_instance
from sysinv.objects import ptp_interface
@ -135,7 +134,6 @@ system = system.System
cluster = cluster.Cluster
peer = peer.Peer
host = host.Host
profile = profile.Profile
node = node.Node
cpu = cpu.CPU
memory = memory.Memory
@ -222,7 +220,6 @@ __all__ = ("system",
"cluster",
"peer",
"host",
"profile",
"node",
"cpu",
"memory",

View File

@ -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)

View File

@ -3084,37 +3084,6 @@ class TestPatchStdDuplexControllerVIM(TestHost):
self.assertEqual(constants.VIM_SERVICES_DELETE_FAILED,
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):
# Create controller-0 (AIO)
c0_host = self._create_controller_0(

View File

@ -513,27 +513,6 @@ class InterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
self.assertEqual(http_client.OK, response.status_int)
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):
for key in first:
if key in second:
@ -563,518 +542,6 @@ class InterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
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
class InterfaceAIOVlanOverDataEthernet(InterfaceTestCase):

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2019 Wind River Systems, Inc.
# Copyright (c) 2021 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -160,30 +160,6 @@ class TestListKubeHostUpgrade(TestKubeHostUpgrade):
self.assertEqual(upgrade['host_id'], host_id)
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):
# Create hosts
self._create_controller_0()

View File

@ -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'])