Include bios registry fields in bios API
Provide the fields in the BIOS setting API - ``/v1/nodes/{node}/bios/{setting}``, and in the BIOS setting list API when details are requested - ``/v1/nodes/<node>/bios?detail=True``. Story: #2008571 Task: #42483 Change-Id: Ie86ec57e428e2bb2efd099a839105e51a94824ab
This commit is contained in:
parent
caa4c8fd29
commit
e15440370c
@ -19,6 +19,53 @@ List all Bios settings by Node
|
|||||||
|
|
||||||
Return a list of Bios settings associated with ``node_ident``.
|
Return a list of Bios settings associated with ``node_ident``.
|
||||||
|
|
||||||
|
.. versionadded:: 1.74
|
||||||
|
Added additional fields from bios registry which can be retrieved using
|
||||||
|
``?detail=True`` (see detailed response below).
|
||||||
|
Added ``fields`` selector to query for particular fields.
|
||||||
|
|
||||||
|
Normal response code: 200
|
||||||
|
|
||||||
|
Error codes: 404
|
||||||
|
|
||||||
|
Request
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
|
- node_ident: node_ident
|
||||||
|
- fields: fields
|
||||||
|
- detail: detail
|
||||||
|
|
||||||
|
Response
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
|
- bios: bios_settings
|
||||||
|
- created_at: created_at
|
||||||
|
- updated_at: updated_at
|
||||||
|
- links: links
|
||||||
|
- name: bios_setting_name
|
||||||
|
- value: bios_setting_value
|
||||||
|
|
||||||
|
**Example list of a Node's Bios settings:**
|
||||||
|
|
||||||
|
.. literalinclude:: samples/node-bios-list-response.json
|
||||||
|
|
||||||
|
List detailed Bios settings by Node
|
||||||
|
===================================
|
||||||
|
|
||||||
|
.. rest_method:: GET /v1/nodes/{node_ident}/bios/?detail=True
|
||||||
|
|
||||||
|
Return a list of detailed Bios settings associated with ``node_ident``.
|
||||||
|
The detailed list includes the BIOS Attribute Registry information
|
||||||
|
retrieved via Redfish.
|
||||||
|
|
||||||
|
.. versionadded:: 1.74
|
||||||
|
Introduced
|
||||||
|
|
||||||
|
|
||||||
Normal response code: 200
|
Normal response code: 200
|
||||||
|
|
||||||
Error codes: 404
|
Error codes: 404
|
||||||
@ -41,10 +88,19 @@ Response
|
|||||||
- links: links
|
- links: links
|
||||||
- name: bios_setting_name
|
- name: bios_setting_name
|
||||||
- value: bios_setting_value
|
- value: bios_setting_value
|
||||||
|
- attribute_type: bios_setting_attribute_type
|
||||||
|
- allowable_values: bios_setting_allowable_values
|
||||||
|
- lower_bound: bios_setting_lower_bound
|
||||||
|
- max_length: bios_setting_max_length
|
||||||
|
- min_length: bios_setting_min_length
|
||||||
|
- read_only: bios_setting_read_only
|
||||||
|
- reset_required: bios_setting_reset_required
|
||||||
|
- unique: bios_setting_unique
|
||||||
|
- upper_bound: bios_setting_upper_bound
|
||||||
|
|
||||||
**Example list of a Node's Bios settings:**
|
**Example list of a Node's Bios settings:**
|
||||||
|
|
||||||
.. literalinclude:: samples/node-bios-list-response.json
|
.. literalinclude:: samples/node-bios-list-details-response.json
|
||||||
|
|
||||||
|
|
||||||
Show single Bios setting of a Node
|
Show single Bios setting of a Node
|
||||||
@ -55,6 +111,9 @@ Show single Bios setting of a Node
|
|||||||
Return the content of the specific bios ``bios_setting`` associated with
|
Return the content of the specific bios ``bios_setting`` associated with
|
||||||
``node_ident``.
|
``node_ident``.
|
||||||
|
|
||||||
|
. versionadded:: 1.74
|
||||||
|
Introduced fields from the BIOS registry.
|
||||||
|
|
||||||
Normal response code: 200
|
Normal response code: 200
|
||||||
|
|
||||||
Error codes: 404
|
Error codes: 404
|
||||||
@ -78,6 +137,15 @@ Response
|
|||||||
- links: links
|
- links: links
|
||||||
- name: bios_setting_name
|
- name: bios_setting_name
|
||||||
- value: bios_setting_value
|
- value: bios_setting_value
|
||||||
|
- attribute_type: bios_setting_attribute_type
|
||||||
|
- allowable_values: bios_setting_allowable_values
|
||||||
|
- lower_bound: bios_setting_lower_bound
|
||||||
|
- max_length: bios_setting_max_length
|
||||||
|
- min_length: bios_setting_min_length
|
||||||
|
- read_only: bios_setting_read_only
|
||||||
|
- reset_required: bios_setting_reset_required
|
||||||
|
- unique: bios_setting_unique
|
||||||
|
- upper_bound: bios_setting_upper_bound
|
||||||
|
|
||||||
**Example details of a Node's Bios setting details:**
|
**Example details of a Node's Bios setting details:**
|
||||||
|
|
||||||
|
@ -505,12 +505,75 @@ bios_interface:
|
|||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
bios_setting_allowable_values:
|
||||||
|
description: |
|
||||||
|
A list of allowable values when the attribute_type is "Enumeration",
|
||||||
|
otherwise None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: array
|
||||||
|
bios_setting_attribute_type:
|
||||||
|
description: |
|
||||||
|
A string describing the type of the Bios setting - "Enumeration",
|
||||||
|
"Integer", "String", "Boolean", or "Password". May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
bios_setting_lower_bound:
|
||||||
|
description: |
|
||||||
|
The lowest allowed value when attribute_type is "Integer".
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
bios_setting_max_length:
|
||||||
|
description: |
|
||||||
|
The maximum length when attribute_type is "String".
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
bios_setting_min_length:
|
||||||
|
description: |
|
||||||
|
The minimum length when attribute_type is "String".
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
bios_setting_name:
|
bios_setting_name:
|
||||||
description: |
|
description: |
|
||||||
The name of a Bios setting for a Node, eg. "virtualization".
|
The name of a Bios setting for a Node, eg. "virtualization".
|
||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
bios_setting_read_only:
|
||||||
|
description: |
|
||||||
|
This Bios seting is read only and can't be changed.
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
bios_setting_reset_required:
|
||||||
|
description: |
|
||||||
|
After setting this Bios setting a node reboot is required.
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
bios_setting_unique:
|
||||||
|
description: |
|
||||||
|
This Bios setting is unique to this node.
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
bios_setting_upper_bound:
|
||||||
|
description: |
|
||||||
|
The lowest allowed value when attribute_type is "Integer".
|
||||||
|
May be None.
|
||||||
|
in: body
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
bios_setting_value:
|
bios_setting_value:
|
||||||
description: |
|
description: |
|
||||||
The value of a Bios setting for a Node, eg. "on".
|
The value of a Bios setting for a Node, eg. "on".
|
||||||
@ -520,7 +583,9 @@ bios_setting_value:
|
|||||||
bios_settings:
|
bios_settings:
|
||||||
description: |
|
description: |
|
||||||
Optional list of one or more Bios settings. It includes following fields
|
Optional list of one or more Bios settings. It includes following fields
|
||||||
"created_at", "updated_at", "links", "name", "value".
|
"created_at", "updated_at", "links", "name", "value", "attribute_type",
|
||||||
|
"allowable_values", "lower_bound", "max_length", "min_length", "read_only",
|
||||||
|
"reset_required", "unique", "upper_bound"
|
||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: array
|
type: array
|
||||||
|
@ -12,7 +12,16 @@
|
|||||||
"rel": "bookmark"
|
"rel": "bookmark"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "virtualization",
|
"name": "Virtualization",
|
||||||
"value": "on"
|
"value": "Enabled",
|
||||||
|
"attribute_type": "Enumeration",
|
||||||
|
"allowable_values": ["Enabled", "Disabled"],
|
||||||
|
"lower_bound": None,
|
||||||
|
"max_length": None,
|
||||||
|
"min_length": None,
|
||||||
|
"read_only": false,
|
||||||
|
"reset_required": None,
|
||||||
|
"unique": None,
|
||||||
|
"upper_bound": None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
api-ref/source/samples/node-bios-list-details-response.json
Normal file
30
api-ref/source/samples/node-bios-list-details-response.json
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"bios": [
|
||||||
|
{
|
||||||
|
"created_at": "2016-08-18T22:28:49.653974+00:00",
|
||||||
|
"updated_at": "2016-08-18T22:28:49.653974+00:00",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"href": "http://127.0.0.1:6385/v1/nodes/6d85703a-565d-469a-96ce-30b6de53079d/bios/virtualization",
|
||||||
|
"rel": "self"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"href": "http://127.0.0.1:6385/v1/nodes/6d85703a-565d-469a-96ce-30b6de53079d/bios/virtualization",
|
||||||
|
"rel": "bookmark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "Virtualization",
|
||||||
|
"value": "Enabled",
|
||||||
|
"attribute_type": "Enumeration",
|
||||||
|
"allowable_values": ["Enabled", "Disabled"],
|
||||||
|
"lower_bound": None,
|
||||||
|
"max_length": None,
|
||||||
|
"min_length": None,
|
||||||
|
"read_only": false,
|
||||||
|
"reset_required": None,
|
||||||
|
"unique": None,
|
||||||
|
"upper_bound": None
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -13,8 +13,8 @@
|
|||||||
"rel": "bookmark"
|
"rel": "bookmark"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"name": "virtualization",
|
"name": "Virtualization",
|
||||||
"value": "on"
|
"value": "Enabled"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,19 @@
|
|||||||
REST API Version History
|
REST API Version History
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
1.74 (Xena)
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Add support for BIOS registry fields which include details about the BIOS
|
||||||
|
setting. Included in the ``/v1/nodes/{node_ident}/bios/{setting}`` response.
|
||||||
|
Add a new selector to include the fields in the BIOS settings list:
|
||||||
|
* ``/v1/nodes/{node_ident}/bios/?detail=``
|
||||||
|
Also add a fields selector to the the BIOS settings list:
|
||||||
|
* ``/v1/nodes/{node_ident}/bios/?fields=``
|
||||||
|
|
||||||
1.73 (Xena)
|
1.73 (Xena)
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
Add a new ``deploy`` verb as an alias to ``active`` and
|
Add a new ``deploy`` verb as an alias to ``active`` and
|
||||||
``undeploy`` verb as an alias to ``deleted``.
|
``undeploy`` verb as an alias to ``deleted``.
|
||||||
|
|
||||||
|
@ -25,23 +25,34 @@ from ironic import objects
|
|||||||
|
|
||||||
METRICS = metrics_utils.get_metrics_logger(__name__)
|
METRICS = metrics_utils.get_metrics_logger(__name__)
|
||||||
|
|
||||||
|
_DEFAULT_RETURN_FIELDS = ('name', 'value')
|
||||||
|
_DEFAULT_FIELDS_WITH_REGISTRY = ('name', 'value', 'attribute_type',
|
||||||
|
'allowable_values', 'lower_bound',
|
||||||
|
'max_length', 'min_length', 'read_only',
|
||||||
|
'reset_required', 'unique', 'upper_bound')
|
||||||
|
|
||||||
def convert_with_links(rpc_bios, node_uuid):
|
|
||||||
|
def convert_with_links(rpc_bios, node_uuid, detail=None, fields=None):
|
||||||
"""Build a dict containing a bios setting value."""
|
"""Build a dict containing a bios setting value."""
|
||||||
|
|
||||||
|
if detail:
|
||||||
|
fields = _DEFAULT_FIELDS_WITH_REGISTRY
|
||||||
|
|
||||||
bios = api_utils.object_to_dict(
|
bios = api_utils.object_to_dict(
|
||||||
rpc_bios,
|
rpc_bios,
|
||||||
include_uuid=False,
|
include_uuid=False,
|
||||||
fields=('name', 'value'),
|
fields=fields,
|
||||||
link_resource='nodes',
|
link_resource='nodes',
|
||||||
link_resource_args="%s/bios/%s" % (node_uuid, rpc_bios.name),
|
link_resource_args="%s/bios/%s" % (node_uuid, rpc_bios.name),
|
||||||
)
|
)
|
||||||
return bios
|
return bios
|
||||||
|
|
||||||
|
|
||||||
def collection_from_list(node_ident, bios_settings):
|
def collection_from_list(node_ident, bios_settings, detail=None, fields=None):
|
||||||
bios_list = []
|
bios_list = []
|
||||||
for bios_setting in bios_settings:
|
for bios_setting in bios_settings:
|
||||||
bios_list.append(convert_with_links(bios_setting, node_ident))
|
bios_list.append(convert_with_links(bios_setting, node_ident,
|
||||||
|
detail, fields))
|
||||||
return {'bios': bios_list}
|
return {'bios': bios_list}
|
||||||
|
|
||||||
|
|
||||||
@ -54,14 +65,23 @@ class NodeBiosController(rest.RestController):
|
|||||||
|
|
||||||
@METRICS.timer('NodeBiosController.get_all')
|
@METRICS.timer('NodeBiosController.get_all')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
def get_all(self):
|
@args.validate(fields=args.string_list, detail=args.boolean)
|
||||||
|
def get_all(self, detail=None, fields=None):
|
||||||
"""List node bios settings."""
|
"""List node bios settings."""
|
||||||
node = api_utils.check_node_policy_and_retrieve(
|
node = api_utils.check_node_policy_and_retrieve(
|
||||||
'baremetal:node:bios:get', self.node_ident)
|
'baremetal:node:bios:get', self.node_ident)
|
||||||
|
|
||||||
|
# The BIOS detail and fields query were added in a later
|
||||||
|
# version, check if they are valid based on version
|
||||||
|
allow_query = api_utils.allow_query_bios
|
||||||
|
fields = api_utils.get_request_return_fields(fields, detail,
|
||||||
|
_DEFAULT_RETURN_FIELDS,
|
||||||
|
allow_query, allow_query)
|
||||||
|
|
||||||
settings = objects.BIOSSettingList.get_by_node_id(
|
settings = objects.BIOSSettingList.get_by_node_id(
|
||||||
api.request.context, node.id)
|
api.request.context, node.id)
|
||||||
return collection_from_list(self.node_ident, settings)
|
return collection_from_list(self.node_ident, settings,
|
||||||
|
detail, fields)
|
||||||
|
|
||||||
@METRICS.timer('NodeBiosController.get_one')
|
@METRICS.timer('NodeBiosController.get_one')
|
||||||
@method.expose()
|
@method.expose()
|
||||||
@ -81,4 +101,11 @@ class NodeBiosController(rest.RestController):
|
|||||||
raise exception.BIOSSettingNotFound(node=node.uuid,
|
raise exception.BIOSSettingNotFound(node=node.uuid,
|
||||||
name=setting_name)
|
name=setting_name)
|
||||||
|
|
||||||
return {setting_name: convert_with_links(setting, node.uuid)}
|
# Return fields based on version
|
||||||
|
if api_utils.allow_query_bios():
|
||||||
|
fields = _DEFAULT_FIELDS_WITH_REGISTRY
|
||||||
|
else:
|
||||||
|
fields = _DEFAULT_RETURN_FIELDS
|
||||||
|
|
||||||
|
return {setting_name: convert_with_links(setting, node.uuid,
|
||||||
|
fields=fields)}
|
||||||
|
@ -1321,18 +1321,27 @@ def allow_detail_query():
|
|||||||
return api.request.version.minor >= versions.MINOR_43_ENABLE_DETAIL_QUERY
|
return api.request.version.minor >= versions.MINOR_43_ENABLE_DETAIL_QUERY
|
||||||
|
|
||||||
|
|
||||||
|
def allow_query_bios():
|
||||||
|
"""Check if BIOS queries should be allowed based on version"""
|
||||||
|
|
||||||
|
return api.request.version.minor >= versions.MINOR_74_BIOS_REGISTRY
|
||||||
|
|
||||||
|
|
||||||
def allow_reset_interfaces():
|
def allow_reset_interfaces():
|
||||||
"""Check if passing a reset_interfaces query string is allowed."""
|
"""Check if passing a reset_interfaces query string is allowed."""
|
||||||
return api.request.version.minor >= versions.MINOR_45_RESET_INTERFACES
|
return api.request.version.minor >= versions.MINOR_45_RESET_INTERFACES
|
||||||
|
|
||||||
|
|
||||||
def get_request_return_fields(fields, detail, default_fields):
|
def get_request_return_fields(fields, detail, default_fields,
|
||||||
|
check_detail_version=allow_detail_query,
|
||||||
|
check_fields_version=None):
|
||||||
"""Calculate fields to return from an API request
|
"""Calculate fields to return from an API request
|
||||||
|
|
||||||
The fields query and detail=True query can not be passed into a request at
|
The fields query and detail=True query can not be passed into a request at
|
||||||
the same time. To use the detail query we need to be on a version of the
|
the same time. To use the detail query we need to be on a version of the
|
||||||
API greater than 1.43. This function raises an InvalidParameterValue
|
API greater than expected, likewise some APIs require a certain version for
|
||||||
exception if either of these conditions are not met.
|
the fields query. This function raises an InvalidParameterValue exception
|
||||||
|
if any of these conditions are not met.
|
||||||
|
|
||||||
If these checks pass then this function will return either the fields
|
If these checks pass then this function will return either the fields
|
||||||
passed in or the default fields provided.
|
passed in or the default fields provided.
|
||||||
@ -1341,15 +1350,24 @@ def get_request_return_fields(fields, detail, default_fields):
|
|||||||
:param detail: The detail query passed into the API request.
|
:param detail: The detail query passed into the API request.
|
||||||
:param default_fields: The default fields to return if fields=None and
|
:param default_fields: The default fields to return if fields=None and
|
||||||
detail=None.
|
detail=None.
|
||||||
|
:param check_detail_version: Function to check if detail query is allowed
|
||||||
|
based on the version.
|
||||||
|
:param check_fields_version: Function to check if fields query is allowed
|
||||||
|
based on the version.
|
||||||
:raises: InvalidParameterValue if there is an invalid combination of query
|
:raises: InvalidParameterValue if there is an invalid combination of query
|
||||||
strings or API version.
|
strings or API version.
|
||||||
:returns: 'fields' passed in value or 'default_fields'
|
:returns: 'fields' passed in value or 'default_fields'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if detail is not None and not allow_detail_query():
|
if detail is not None and not check_detail_version():
|
||||||
raise exception.InvalidParameterValue(
|
raise exception.InvalidParameterValue(
|
||||||
"Invalid query parameter ?detail=%s received." % detail)
|
"Invalid query parameter ?detail=%s received." % detail)
|
||||||
|
|
||||||
|
if (fields is not None and callable(check_fields_version)
|
||||||
|
and not check_fields_version()):
|
||||||
|
raise exception.InvalidParameterValue(
|
||||||
|
"Invalid query parameter ?fields=%s received." % fields)
|
||||||
|
|
||||||
if fields is not None and detail:
|
if fields is not None and detail:
|
||||||
raise exception.InvalidParameterValue(
|
raise exception.InvalidParameterValue(
|
||||||
"Can not specify ?detail=True and fields in the same request.")
|
"Can not specify ?detail=True and fields in the same request.")
|
||||||
|
@ -111,6 +111,7 @@ BASE_VERSION = 1
|
|||||||
# v1.71: Add signifier for Scope based roles.
|
# v1.71: Add signifier for Scope based roles.
|
||||||
# v1.72: Add agent_status and agent_status_message to /v1/heartbeat
|
# v1.72: Add agent_status and agent_status_message to /v1/heartbeat
|
||||||
# v1.73: Add support for deploy and undeploy verbs
|
# v1.73: Add support for deploy and undeploy verbs
|
||||||
|
# v1.74: Add bios registry to /v1/nodes/{node}/bios/{setting}
|
||||||
|
|
||||||
MINOR_0_JUNO = 0
|
MINOR_0_JUNO = 0
|
||||||
MINOR_1_INITIAL_VERSION = 1
|
MINOR_1_INITIAL_VERSION = 1
|
||||||
@ -186,6 +187,7 @@ MINOR_70_CLEAN_DISABLE_RAMDISK = 70
|
|||||||
MINOR_71_RBAC_SCOPES = 71
|
MINOR_71_RBAC_SCOPES = 71
|
||||||
MINOR_72_HEARTBEAT_STATUS = 72
|
MINOR_72_HEARTBEAT_STATUS = 72
|
||||||
MINOR_73_DEPLOY_UNDEPLOY_VERBS = 73
|
MINOR_73_DEPLOY_UNDEPLOY_VERBS = 73
|
||||||
|
MINOR_74_BIOS_REGISTRY = 74
|
||||||
|
|
||||||
# When adding another version, update:
|
# When adding another version, update:
|
||||||
# - MINOR_MAX_VERSION
|
# - MINOR_MAX_VERSION
|
||||||
@ -193,7 +195,7 @@ MINOR_73_DEPLOY_UNDEPLOY_VERBS = 73
|
|||||||
# explanation of what changed in the new version
|
# explanation of what changed in the new version
|
||||||
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
|
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
|
||||||
|
|
||||||
MINOR_MAX_VERSION = MINOR_73_DEPLOY_UNDEPLOY_VERBS
|
MINOR_MAX_VERSION = MINOR_74_BIOS_REGISTRY
|
||||||
|
|
||||||
# String representations of the minor and maximum versions
|
# String representations of the minor and maximum versions
|
||||||
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
_MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
||||||
|
@ -320,10 +320,11 @@ RELEASE_MAPPING = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'master': {
|
'master': {
|
||||||
'api': '1.73',
|
'api': '1.74',
|
||||||
'rpc': '1.54',
|
'rpc': '1.54',
|
||||||
'objects': {
|
'objects': {
|
||||||
'Allocation': ['1.1'],
|
'Allocation': ['1.1'],
|
||||||
|
'BIOSSetting': ['1.1'],
|
||||||
'Node': ['1.35'],
|
'Node': ['1.35'],
|
||||||
'Conductor': ['1.3'],
|
'Conductor': ['1.3'],
|
||||||
'Chassis': ['1.3'],
|
'Chassis': ['1.3'],
|
||||||
|
@ -1385,8 +1385,7 @@ def store_agent_certificate(node, agent_verify_ca):
|
|||||||
def node_cache_bios_settings(task, node):
|
def node_cache_bios_settings(task, node):
|
||||||
"""Do caching of bios settings if supported by driver"""
|
"""Do caching of bios settings if supported by driver"""
|
||||||
try:
|
try:
|
||||||
LOG.debug('BF getting BIOS info for node %s',
|
LOG.debug('Getting BIOS info for node %s', node.uuid)
|
||||||
node.uuid)
|
|
||||||
task.driver.bios.cache_bios_settings(task)
|
task.driver.bios.cache_bios_settings(task)
|
||||||
except exception.UnsupportedDriverExtension:
|
except exception.UnsupportedDriverExtension:
|
||||||
LOG.warning('BIOS settings are not supported for node %s, '
|
LOG.warning('BIOS settings are not supported for node %s, '
|
||||||
|
@ -1054,10 +1054,12 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
{
|
{
|
||||||
'name': String,
|
'name': String,
|
||||||
'value': String,
|
'value': String,
|
||||||
|
additional settings from BIOS registry
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': String,
|
'name': String,
|
||||||
'value': String,
|
'value': String,
|
||||||
|
additional settings from BIOS registry
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
@ -1081,10 +1083,12 @@ class Connection(object, metaclass=abc.ABCMeta):
|
|||||||
{
|
{
|
||||||
'name': String,
|
'name': String,
|
||||||
'value': String,
|
'value': String,
|
||||||
|
additional settings from BIOS registry
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': String,
|
'name': String,
|
||||||
'value': String,
|
'value': String,
|
||||||
|
additional settings from BIOS registry
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""Add fields from BIOS registry
|
||||||
|
|
||||||
|
Revision ID: 2bbd96b6ccb9
|
||||||
|
Revises: ac00b586ab95
|
||||||
|
Create Date: 2021-04-29 08:52:23.938863
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '2bbd96b6ccb9'
|
||||||
|
down_revision = 'ac00b586ab95'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('bios_settings', sa.Column('attribute_type',
|
||||||
|
sa.String(length=255), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('allowable_values',
|
||||||
|
sa.Text(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('lower_bound',
|
||||||
|
sa.Integer(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('max_length',
|
||||||
|
sa.Integer(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('min_length',
|
||||||
|
sa.Integer(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('read_only',
|
||||||
|
sa.Boolean(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('reset_required',
|
||||||
|
sa.Boolean(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('unique',
|
||||||
|
sa.Boolean(), nullable=True))
|
||||||
|
op.add_column('bios_settings', sa.Column('upper_bound',
|
||||||
|
sa.Integer(), nullable=True))
|
@ -1675,6 +1675,15 @@ class Connection(api.Connection):
|
|||||||
node_id=node_id,
|
node_id=node_id,
|
||||||
name=setting['name'],
|
name=setting['name'],
|
||||||
value=setting['value'],
|
value=setting['value'],
|
||||||
|
attribute_type=setting.get('attribute_type'),
|
||||||
|
allowable_values=setting.get('allowable_values'),
|
||||||
|
lower_bound=setting.get('lower_bound'),
|
||||||
|
max_length=setting.get('max_length'),
|
||||||
|
min_length=setting.get('min_length'),
|
||||||
|
read_only=setting.get('read_only'),
|
||||||
|
reset_required=setting.get('reset_required'),
|
||||||
|
unique=setting.get('unique'),
|
||||||
|
upper_bound=setting.get('upper_bound'),
|
||||||
version=version)
|
version=version)
|
||||||
bios_settings.append(bios_setting)
|
bios_settings.append(bios_setting)
|
||||||
session.add(bios_setting)
|
session.add(bios_setting)
|
||||||
@ -1695,6 +1704,18 @@ class Connection(api.Connection):
|
|||||||
node_id=node_id, name=setting['name'])
|
node_id=node_id, name=setting['name'])
|
||||||
ref = query.one()
|
ref = query.one()
|
||||||
ref.update({'value': setting['value'],
|
ref.update({'value': setting['value'],
|
||||||
|
'attribute_type':
|
||||||
|
setting.get('attribute_type'),
|
||||||
|
'allowable_values':
|
||||||
|
setting.get('allowable_values'),
|
||||||
|
'lower_bound': setting.get('lower_bound'),
|
||||||
|
'max_length': setting.get('max_length'),
|
||||||
|
'min_length': setting.get('min_length'),
|
||||||
|
'read_only': setting.get('read_only'),
|
||||||
|
'reset_required':
|
||||||
|
setting.get('reset_required'),
|
||||||
|
'unique': setting.get('unique'),
|
||||||
|
'upper_bound': setting.get('upper_bound'),
|
||||||
'version': version})
|
'version': version})
|
||||||
bios_settings.append(ref)
|
bios_settings.append(ref)
|
||||||
session.flush()
|
session.flush()
|
||||||
|
@ -339,6 +339,15 @@ class BIOSSetting(Base):
|
|||||||
primary_key=True, nullable=False)
|
primary_key=True, nullable=False)
|
||||||
name = Column(String(255), primary_key=True, nullable=False)
|
name = Column(String(255), primary_key=True, nullable=False)
|
||||||
value = Column(Text, nullable=True)
|
value = Column(Text, nullable=True)
|
||||||
|
attribute_type = Column(String(255), nullable=True)
|
||||||
|
allowable_values = Column(db_types.JsonEncodedList, nullable=True)
|
||||||
|
lower_bound = Column(Integer, nullable=True)
|
||||||
|
max_length = Column(Integer, nullable=True)
|
||||||
|
min_length = Column(Integer, nullable=True)
|
||||||
|
read_only = Column(Boolean, nullable=True)
|
||||||
|
reset_required = Column(Boolean, nullable=True)
|
||||||
|
unique = Column(Boolean, nullable=True)
|
||||||
|
upper_bound = Column(Integer, nullable=True)
|
||||||
|
|
||||||
|
|
||||||
class Allocation(Base):
|
class Allocation(Base):
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from oslo_utils import versionutils
|
||||||
from oslo_versionedobjects import base as object_base
|
from oslo_versionedobjects import base as object_base
|
||||||
|
|
||||||
from ironic.db import api as dbapi
|
from ironic.db import api as dbapi
|
||||||
@ -23,14 +24,29 @@ from ironic.objects import fields as object_fields
|
|||||||
@base.IronicObjectRegistry.register
|
@base.IronicObjectRegistry.register
|
||||||
class BIOSSetting(base.IronicObject):
|
class BIOSSetting(base.IronicObject):
|
||||||
# Version 1.0: Initial version
|
# Version 1.0: Initial version
|
||||||
VERSION = '1.0'
|
# Version 1.1: Added registry
|
||||||
|
VERSION = '1.1'
|
||||||
|
|
||||||
dbapi = dbapi.get_instance()
|
dbapi = dbapi.get_instance()
|
||||||
|
|
||||||
|
registry_fields = ('attribute_type', 'allowable_values', 'lower_bound',
|
||||||
|
'max_length', 'min_length', 'read_only',
|
||||||
|
'reset_required', 'unique', 'upper_bound')
|
||||||
|
|
||||||
fields = {
|
fields = {
|
||||||
'node_id': object_fields.StringField(nullable=False),
|
'node_id': object_fields.StringField(nullable=False),
|
||||||
'name': object_fields.StringField(nullable=False),
|
'name': object_fields.StringField(nullable=False),
|
||||||
'value': object_fields.StringField(nullable=True),
|
'value': object_fields.StringField(nullable=True),
|
||||||
|
'attribute_type': object_fields.StringField(nullable=True),
|
||||||
|
'allowable_values': object_fields.ListOfStringsField(
|
||||||
|
nullable=True),
|
||||||
|
'lower_bound': object_fields.IntegerField(nullable=True),
|
||||||
|
'max_length': object_fields.IntegerField(nullable=True),
|
||||||
|
'min_length': object_fields.IntegerField(nullable=True),
|
||||||
|
'read_only': object_fields.BooleanField(nullable=True),
|
||||||
|
'reset_required': object_fields.BooleanField(nullable=True),
|
||||||
|
'unique': object_fields.BooleanField(nullable=True),
|
||||||
|
'upper_bound': object_fields.IntegerField(nullable=True)
|
||||||
}
|
}
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
@ -50,9 +66,12 @@ class BIOSSetting(base.IronicObject):
|
|||||||
:raises: BIOSSettingAlreadyExists if the setting record already exists.
|
:raises: BIOSSettingAlreadyExists if the setting record already exists.
|
||||||
"""
|
"""
|
||||||
values = self.do_version_changes_for_db()
|
values = self.do_version_changes_for_db()
|
||||||
setting = [{'name': values['name'], 'value': values['value']}]
|
settings = {'name': values['name'], 'value': values['value']}
|
||||||
|
for r in self.registry_fields:
|
||||||
|
settings[r] = values.get(r)
|
||||||
|
|
||||||
db_bios_setting = self.dbapi.create_bios_setting_list(
|
db_bios_setting = self.dbapi.create_bios_setting_list(
|
||||||
values['node_id'], setting, values['version'])
|
values['node_id'], [settings], values['version'])
|
||||||
self._from_db_object(self._context, self, db_bios_setting[0])
|
self._from_db_object(self._context, self, db_bios_setting[0])
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
@ -72,9 +91,13 @@ class BIOSSetting(base.IronicObject):
|
|||||||
:raises: BIOSSettingNotFound if the bios setting name is not found.
|
:raises: BIOSSettingNotFound if the bios setting name is not found.
|
||||||
"""
|
"""
|
||||||
values = self.do_version_changes_for_db()
|
values = self.do_version_changes_for_db()
|
||||||
setting = [{'name': values['name'], 'value': values['value']}]
|
|
||||||
|
settings = {'name': values['name'], 'value': values['value']}
|
||||||
|
for r in self.registry_fields:
|
||||||
|
settings[r] = values.get(r)
|
||||||
|
|
||||||
updated_bios_setting = self.dbapi.update_bios_setting_list(
|
updated_bios_setting = self.dbapi.update_bios_setting_list(
|
||||||
values['node_id'], setting, values['version'])
|
values['node_id'], [settings], values['version'])
|
||||||
self._from_db_object(self._context, self, updated_bios_setting[0])
|
self._from_db_object(self._context, self, updated_bios_setting[0])
|
||||||
|
|
||||||
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
# NOTE(xek): We don't want to enable RPC on this call just yet. Remotable
|
||||||
@ -111,6 +134,40 @@ class BIOSSetting(base.IronicObject):
|
|||||||
"""
|
"""
|
||||||
cls.dbapi.delete_bios_setting_list(node_id, [name])
|
cls.dbapi.delete_bios_setting_list(node_id, [name])
|
||||||
|
|
||||||
|
def _convert_to_version(self, target_version,
|
||||||
|
remove_unavailable_fields=True):
|
||||||
|
"""Convert to the target version.
|
||||||
|
|
||||||
|
Convert the object to the target version. The target version may be
|
||||||
|
the same, older, or newer than the version of the object. This is
|
||||||
|
used for DB interactions as well as for serialization/deserialization.
|
||||||
|
|
||||||
|
Version 1.74: remove registry field for unsupported versions if
|
||||||
|
remove_unavailable_fields is True.
|
||||||
|
|
||||||
|
:param target_version: the desired version of the object
|
||||||
|
:param remove_unavailable_fields: True to remove fields that are
|
||||||
|
unavailable in the target version; set this to True when
|
||||||
|
(de)serializing. False to set the unavailable fields to appropriate
|
||||||
|
values; set this to False for DB interactions.
|
||||||
|
"""
|
||||||
|
target_version = versionutils.convert_version_to_tuple(target_version)
|
||||||
|
|
||||||
|
for field in self.get_registry_fields():
|
||||||
|
field_is_set = self.obj_attr_is_set(field)
|
||||||
|
if target_version >= (1, 74):
|
||||||
|
# target version supports the major/minor specified
|
||||||
|
if not field_is_set:
|
||||||
|
# set it to its default value if it is not set
|
||||||
|
setattr(self, field, None)
|
||||||
|
elif field_is_set:
|
||||||
|
# target version does not support the field, and it is set
|
||||||
|
if remove_unavailable_fields:
|
||||||
|
# (De)serialising: remove unavailable fields
|
||||||
|
delattr(self, field)
|
||||||
|
elif self.registry:
|
||||||
|
setattr(self, field, None)
|
||||||
|
|
||||||
|
|
||||||
@base.IronicObjectRegistry.register
|
@base.IronicObjectRegistry.register
|
||||||
class BIOSSettingList(base.IronicObjectListBase, base.IronicObject):
|
class BIOSSettingList(base.IronicObjectListBase, base.IronicObject):
|
||||||
|
@ -6685,7 +6685,7 @@ class TestBIOS(test_api_base.BaseApiTest):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestBIOS, self).setUp()
|
super(TestBIOS, self).setUp()
|
||||||
self.version = "1.40"
|
self.version = "1.74"
|
||||||
self.node = obj_utils.create_test_node(
|
self.node = obj_utils.create_test_node(
|
||||||
self.context, id=1)
|
self.context, id=1)
|
||||||
self.bios = obj_utils.create_test_bios_setting(self.context,
|
self.bios = obj_utils.create_test_bios_setting(self.context,
|
||||||
@ -6718,13 +6718,40 @@ class TestBIOS(test_api_base.BaseApiTest):
|
|||||||
|
|
||||||
expected_json = {
|
expected_json = {
|
||||||
'virtualization': {
|
'virtualization': {
|
||||||
|
'allowable_values': ['on', 'off'],
|
||||||
|
'attribute_type': 'Enumeration',
|
||||||
'created_at': ret['virtualization']['created_at'],
|
'created_at': ret['virtualization']['created_at'],
|
||||||
'updated_at': ret['virtualization']['updated_at'],
|
|
||||||
'links': [
|
'links': [
|
||||||
{'href': 'http://localhost/v1/nodes/%s/bios/virtualization'
|
{'href': 'http://localhost/v1/nodes/%s/bios/virtualization'
|
||||||
% self.node.uuid, u'rel': u'self'},
|
% self.node.uuid, u'rel': u'self'},
|
||||||
{'href': 'http://localhost/nodes/%s/bios/virtualization'
|
{'href': 'http://localhost/nodes/%s/bios/virtualization'
|
||||||
% self.node.uuid, u'rel': u'bookmark'}],
|
% self.node.uuid, u'rel': u'bookmark'}],
|
||||||
|
'lower_bound': None,
|
||||||
|
'min_length': None,
|
||||||
|
'max_length': None,
|
||||||
|
'name': 'virtualization',
|
||||||
|
'read_only': False,
|
||||||
|
'reset_required': True,
|
||||||
|
'unique': False,
|
||||||
|
'updated_at': None,
|
||||||
|
'upper_bound': None,
|
||||||
|
'value': 'on'}}
|
||||||
|
|
||||||
|
self.assertEqual(expected_json, ret)
|
||||||
|
|
||||||
|
def test_get_one_bios_no_registry(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios/virtualization' % self.node.uuid,
|
||||||
|
headers={api_base.Version.string: "1.73"})
|
||||||
|
|
||||||
|
expected_json = {
|
||||||
|
'virtualization': {
|
||||||
|
'created_at': ret['virtualization']['created_at'],
|
||||||
|
'updated_at': ret['virtualization']['updated_at'],
|
||||||
|
'links': [
|
||||||
|
{'href': 'http://localhost/v1/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'self'},
|
||||||
|
{'href': 'http://localhost/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'bookmark'}],
|
||||||
'name': 'virtualization', 'value': 'on'}}
|
'name': 'virtualization', 'value': 'on'}}
|
||||||
self.assertEqual(expected_json, ret)
|
self.assertEqual(expected_json, ret)
|
||||||
|
|
||||||
@ -6742,6 +6769,88 @@ class TestBIOS(test_api_base.BaseApiTest):
|
|||||||
self.assertIn("fake_setting", ret.json['error_message'])
|
self.assertIn("fake_setting", ret.json['error_message'])
|
||||||
self.assertNotIn(self.node.id, ret.json['error_message'])
|
self.assertNotIn(self.node.id, ret.json['error_message'])
|
||||||
|
|
||||||
|
def test_get_all_bios_with_detail(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios?detail=True' % self.node.uuid,
|
||||||
|
headers={api_base.Version.string: self.version})
|
||||||
|
|
||||||
|
expected_json = [
|
||||||
|
{'allowable_values': ['on', 'off'],
|
||||||
|
'attribute_type': 'Enumeration',
|
||||||
|
'created_at': ret['bios'][0]['created_at'],
|
||||||
|
'links': [
|
||||||
|
{'href': 'http://localhost/v1/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'self'},
|
||||||
|
{'href': 'http://localhost/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'bookmark'}],
|
||||||
|
'lower_bound': None,
|
||||||
|
'max_length': None,
|
||||||
|
'min_length': None,
|
||||||
|
'name': 'virtualization',
|
||||||
|
'read_only': False,
|
||||||
|
'reset_required': True,
|
||||||
|
'unique': False,
|
||||||
|
'updated_at': None,
|
||||||
|
'upper_bound': None,
|
||||||
|
'value': 'on'}]
|
||||||
|
|
||||||
|
self.assertEqual({'bios': expected_json}, ret)
|
||||||
|
|
||||||
|
def test_get_all_bios_detail_false(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios?detail=False' % self.node.uuid,
|
||||||
|
headers={api_base.Version.string: self.version})
|
||||||
|
|
||||||
|
expected_json = [
|
||||||
|
{'created_at': ret['bios'][0]['created_at'],
|
||||||
|
'updated_at': ret['bios'][0]['updated_at'],
|
||||||
|
'links': [
|
||||||
|
{'href': 'http://localhost/v1/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'self'},
|
||||||
|
{'href': 'http://localhost/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'bookmark'}],
|
||||||
|
'name': 'virtualization', 'value': 'on'}]
|
||||||
|
self.assertEqual({'bios': expected_json}, ret)
|
||||||
|
|
||||||
|
def test_get_all_bios_detail_old_version(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios?detail=True' % self.node.uuid,
|
||||||
|
headers={api_base.Version.string: "1.73"},
|
||||||
|
expect_errors=True)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.BAD_REQUEST, ret.status_int)
|
||||||
|
|
||||||
|
def test_get_bios_fields_old_version(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios?fields=name,read_only'
|
||||||
|
% self.node.uuid,
|
||||||
|
headers={api_base.Version.string: "1.73"},
|
||||||
|
expect_errors=True)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.BAD_REQUEST, ret.status_int)
|
||||||
|
|
||||||
|
def test_get_bios_detail_and_fields(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios?detail=True?fields=name,read_only'
|
||||||
|
% self.node.uuid,
|
||||||
|
headers={api_base.Version.string: "1.74"},
|
||||||
|
expect_errors=True)
|
||||||
|
|
||||||
|
self.assertEqual(http_client.BAD_REQUEST, ret.status_int)
|
||||||
|
|
||||||
|
def test_get_bios_fields(self):
|
||||||
|
ret = self.get_json('/nodes/%s/bios?fields=name,read_only'
|
||||||
|
% self.node.uuid,
|
||||||
|
headers={api_base.Version.string: self.version})
|
||||||
|
|
||||||
|
expected_json = [
|
||||||
|
{'created_at': ret['bios'][0]['created_at'],
|
||||||
|
'links': [
|
||||||
|
{'href': 'http://localhost/v1/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'self'},
|
||||||
|
{'href': 'http://localhost/nodes/%s/bios/virtualization'
|
||||||
|
% self.node.uuid, 'rel': 'bookmark'}],
|
||||||
|
'name': 'virtualization',
|
||||||
|
'read_only': False,
|
||||||
|
'updated_at': None}]
|
||||||
|
|
||||||
|
self.assertEqual({'bios': expected_json}, ret)
|
||||||
|
|
||||||
|
|
||||||
class TestTraits(test_api_base.BaseApiTest):
|
class TestTraits(test_api_base.BaseApiTest):
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ class ReleaseMappingsTestCase(base.TestCase):
|
|||||||
self.assertIn('master', release_mappings.RELEASE_MAPPING)
|
self.assertIn('master', release_mappings.RELEASE_MAPPING)
|
||||||
model_names = set((s.__name__ for s in models.Base.__subclasses__()))
|
model_names = set((s.__name__ for s in models.Base.__subclasses__()))
|
||||||
exceptions = set(['NodeTag', 'ConductorHardwareInterfaces',
|
exceptions = set(['NodeTag', 'ConductorHardwareInterfaces',
|
||||||
'NodeTrait', 'BIOSSetting', 'DeployTemplateStep'])
|
'NodeTrait', 'DeployTemplateStep'])
|
||||||
# NOTE(xek): As a rule, all models which can be changed between
|
# NOTE(xek): As a rule, all models which can be changed between
|
||||||
# releases or are sent through RPC should have their counterpart
|
# releases or are sent through RPC should have their counterpart
|
||||||
# versioned objects.
|
# versioned objects.
|
||||||
|
@ -705,6 +705,40 @@ class MigrationCheckersMixin(object):
|
|||||||
bios_settings.c.name == setting['name'])).execute().first()
|
bios_settings.c.name == setting['name'])).execute().first()
|
||||||
self.assertEqual('on', setting['value'])
|
self.assertEqual('on', setting['value'])
|
||||||
|
|
||||||
|
def _check_2bbd96b6ccb9(self, engine, data):
|
||||||
|
bios_settings = db_utils.get_table(engine, 'bios_settings')
|
||||||
|
col_names = [column.name for column in bios_settings.c]
|
||||||
|
self.assertIn('attribute_type', col_names)
|
||||||
|
self.assertIn('allowable_values', col_names)
|
||||||
|
self.assertIn('lower_bound', col_names)
|
||||||
|
self.assertIn('max_length', col_names)
|
||||||
|
self.assertIn('min_length', col_names)
|
||||||
|
self.assertIn('read_only', col_names)
|
||||||
|
self.assertIn('reset_required', col_names)
|
||||||
|
self.assertIn('unique', col_names)
|
||||||
|
self.assertIn('upper_bound', col_names)
|
||||||
|
self.assertIsInstance(bios_settings.c.attribute_type.type,
|
||||||
|
sqlalchemy.types.String)
|
||||||
|
self.assertIsInstance(bios_settings.c.allowable_values.type,
|
||||||
|
sqlalchemy.types.TEXT)
|
||||||
|
self.assertIsInstance(bios_settings.c.lower_bound.type,
|
||||||
|
sqlalchemy.types.Integer)
|
||||||
|
self.assertIsInstance(bios_settings.c.max_length.type,
|
||||||
|
sqlalchemy.types.Integer)
|
||||||
|
self.assertIsInstance(bios_settings.c.min_length.type,
|
||||||
|
sqlalchemy.types.Integer)
|
||||||
|
self.assertIsInstance(bios_settings.c.read_only.type,
|
||||||
|
(sqlalchemy.types.Boolean,
|
||||||
|
sqlalchemy.types.Integer))
|
||||||
|
self.assertIsInstance(bios_settings.c.reset_required.type,
|
||||||
|
(sqlalchemy.types.Boolean,
|
||||||
|
sqlalchemy.types.Integer))
|
||||||
|
self.assertIsInstance(bios_settings.c.unique.type,
|
||||||
|
(sqlalchemy.types.Boolean,
|
||||||
|
sqlalchemy.types.Integer))
|
||||||
|
self.assertIsInstance(bios_settings.c.upper_bound.type,
|
||||||
|
sqlalchemy.types.Integer)
|
||||||
|
|
||||||
def _check_2d13bc3d6bba(self, engine, data):
|
def _check_2d13bc3d6bba(self, engine, data):
|
||||||
nodes = db_utils.get_table(engine, 'nodes')
|
nodes = db_utils.get_table(engine, 'nodes')
|
||||||
col_names = [column.name for column in nodes.c]
|
col_names = [column.name for column in nodes.c]
|
||||||
|
@ -29,7 +29,7 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
self.assertEqual(result['node_id'], self.node.id)
|
self.assertEqual(result['node_id'], self.node.id)
|
||||||
self.assertEqual(result['name'], 'virtualization')
|
self.assertEqual(result['name'], 'virtualization')
|
||||||
self.assertEqual(result['value'], 'on')
|
self.assertEqual(result['value'], 'on')
|
||||||
self.assertEqual(result['version'], '1.0')
|
self.assertEqual(result['version'], '1.1')
|
||||||
|
|
||||||
def test_get_bios_setting_node_not_exist(self):
|
def test_get_bios_setting_node_not_exist(self):
|
||||||
self.assertRaises(exception.NodeNotFound,
|
self.assertRaises(exception.NodeNotFound,
|
||||||
@ -50,7 +50,7 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
self.assertEqual(result[0]['node_id'], self.node.id)
|
self.assertEqual(result[0]['node_id'], self.node.id)
|
||||||
self.assertEqual(result[0]['name'], 'virtualization')
|
self.assertEqual(result[0]['name'], 'virtualization')
|
||||||
self.assertEqual(result[0]['value'], 'on')
|
self.assertEqual(result[0]['value'], 'on')
|
||||||
self.assertEqual(result[0]['version'], '1.0')
|
self.assertEqual(result[0]['version'], '1.1')
|
||||||
self.assertEqual(len(result), 1)
|
self.assertEqual(len(result), 1)
|
||||||
|
|
||||||
def test_get_bios_setting_list_node_not_exist(self):
|
def test_get_bios_setting_list_node_not_exist(self):
|
||||||
@ -61,7 +61,7 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
def test_create_bios_setting_list(self):
|
def test_create_bios_setting_list(self):
|
||||||
settings = db_utils.get_test_bios_setting_setting_list()
|
settings = db_utils.get_test_bios_setting_setting_list()
|
||||||
result = self.dbapi.create_bios_setting_list(
|
result = self.dbapi.create_bios_setting_list(
|
||||||
self.node.id, settings, '1.0')
|
self.node.id, settings, '1.1')
|
||||||
self.assertCountEqual(['virtualization', 'hyperthread', 'numlock'],
|
self.assertCountEqual(['virtualization', 'hyperthread', 'numlock'],
|
||||||
[setting.name for setting in result])
|
[setting.name for setting in result])
|
||||||
self.assertCountEqual(['on', 'enabled', 'off'],
|
self.assertCountEqual(['on', 'enabled', 'off'],
|
||||||
@ -69,7 +69,7 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
|
|
||||||
def test_create_bios_setting_list_duplicate(self):
|
def test_create_bios_setting_list_duplicate(self):
|
||||||
settings = db_utils.get_test_bios_setting_setting_list()
|
settings = db_utils.get_test_bios_setting_setting_list()
|
||||||
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.0')
|
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.1')
|
||||||
self.assertRaises(exception.BIOSSettingAlreadyExists,
|
self.assertRaises(exception.BIOSSettingAlreadyExists,
|
||||||
self.dbapi.create_bios_setting_list,
|
self.dbapi.create_bios_setting_list,
|
||||||
self.node.id, settings, '1.0')
|
self.node.id, settings, '1.0')
|
||||||
@ -81,18 +81,18 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
|
|
||||||
def test_update_bios_setting_list(self):
|
def test_update_bios_setting_list(self):
|
||||||
settings = db_utils.get_test_bios_setting_setting_list()
|
settings = db_utils.get_test_bios_setting_setting_list()
|
||||||
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.0')
|
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.1')
|
||||||
settings = [{'name': 'virtualization', 'value': 'off'},
|
settings = [{'name': 'virtualization', 'value': 'off'},
|
||||||
{'name': 'hyperthread', 'value': 'disabled'},
|
{'name': 'hyperthread', 'value': 'disabled'},
|
||||||
{'name': 'numlock', 'value': 'on'}]
|
{'name': 'numlock', 'value': 'on'}]
|
||||||
result = self.dbapi.update_bios_setting_list(
|
result = self.dbapi.update_bios_setting_list(
|
||||||
self.node.id, settings, '1.0')
|
self.node.id, settings, '1.1')
|
||||||
self.assertCountEqual(['off', 'disabled', 'on'],
|
self.assertCountEqual(['off', 'disabled', 'on'],
|
||||||
[setting.value for setting in result])
|
[setting.value for setting in result])
|
||||||
|
|
||||||
def test_update_bios_setting_list_setting_not_exist(self):
|
def test_update_bios_setting_list_setting_not_exist(self):
|
||||||
settings = db_utils.get_test_bios_setting_setting_list()
|
settings = db_utils.get_test_bios_setting_setting_list()
|
||||||
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.0')
|
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.1')
|
||||||
for setting in settings:
|
for setting in settings:
|
||||||
setting['name'] = 'bios_name'
|
setting['name'] = 'bios_name'
|
||||||
self.assertRaises(exception.BIOSSettingNotFound,
|
self.assertRaises(exception.BIOSSettingNotFound,
|
||||||
@ -106,7 +106,7 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
|
|
||||||
def test_delete_bios_setting_list(self):
|
def test_delete_bios_setting_list(self):
|
||||||
settings = db_utils.get_test_bios_setting_setting_list()
|
settings = db_utils.get_test_bios_setting_setting_list()
|
||||||
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.0')
|
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.1')
|
||||||
name_list = [setting['name'] for setting in settings]
|
name_list = [setting['name'] for setting in settings]
|
||||||
self.dbapi.delete_bios_setting_list(self.node.id, name_list)
|
self.dbapi.delete_bios_setting_list(self.node.id, name_list)
|
||||||
self.assertRaises(exception.BIOSSettingNotFound,
|
self.assertRaises(exception.BIOSSettingNotFound,
|
||||||
@ -126,7 +126,7 @@ class DbBIOSSettingTestCase(base.DbTestCase):
|
|||||||
|
|
||||||
def test_delete_bios_setting_list_setting_not_exist(self):
|
def test_delete_bios_setting_list_setting_not_exist(self):
|
||||||
settings = db_utils.get_test_bios_setting_setting_list()
|
settings = db_utils.get_test_bios_setting_setting_list()
|
||||||
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.0')
|
self.dbapi.create_bios_setting_list(self.node.id, settings, '1.1')
|
||||||
self.assertRaises(exception.BIOSSettingListNotFound,
|
self.assertRaises(exception.BIOSSettingListNotFound,
|
||||||
self.dbapi.delete_bios_setting_list,
|
self.dbapi.delete_bios_setting_list,
|
||||||
self.node.id, ['fake-bios-option'])
|
self.node.id, ['fake-bios-option'])
|
||||||
|
@ -566,7 +566,12 @@ def create_test_bios_setting(**kw):
|
|||||||
node_id = bios_setting['node_id']
|
node_id = bios_setting['node_id']
|
||||||
version = bios_setting['version']
|
version = bios_setting['version']
|
||||||
settings = [{'name': bios_setting['name'],
|
settings = [{'name': bios_setting['name'],
|
||||||
'value': bios_setting['value']}]
|
'value': bios_setting['value'],
|
||||||
|
'attribute_type': bios_setting['attribute_type'],
|
||||||
|
'allowable_values': bios_setting['allowable_values'],
|
||||||
|
'read_only': bios_setting['read_only'],
|
||||||
|
'reset_required': bios_setting['reset_required'],
|
||||||
|
'unique': bios_setting['unique']}]
|
||||||
return dbapi.create_bios_setting_list(node_id, settings, version)[0]
|
return dbapi.create_bios_setting_list(node_id, settings, version)[0]
|
||||||
|
|
||||||
|
|
||||||
@ -575,6 +580,15 @@ def get_test_bios_setting(**kw):
|
|||||||
'node_id': kw.get('node_id', '123'),
|
'node_id': kw.get('node_id', '123'),
|
||||||
'name': kw.get('name', 'virtualization'),
|
'name': kw.get('name', 'virtualization'),
|
||||||
'value': kw.get('value', 'on'),
|
'value': kw.get('value', 'on'),
|
||||||
|
'attribute_type': kw.get('attribute_type', 'Enumeration'),
|
||||||
|
'allowable_values': kw.get('allowable_values', ['on', 'off']),
|
||||||
|
'lower_bound': kw.get('lower_bound', None),
|
||||||
|
'max_length': kw.get('max_length', None),
|
||||||
|
'min_length': kw.get('max_length', None),
|
||||||
|
'read_only': kw.get('read_only', False),
|
||||||
|
'reset_required': kw.get('reset_required', True),
|
||||||
|
'unique': kw.get('unique', False),
|
||||||
|
'upper_bound': kw.get('upper_bound', None),
|
||||||
'version': kw.get('version', bios.BIOSSetting.VERSION),
|
'version': kw.get('version', bios.BIOSSetting.VERSION),
|
||||||
'created_at': kw.get('created_at'),
|
'created_at': kw.get('created_at'),
|
||||||
'updated_at': kw.get('updated_at'),
|
'updated_at': kw.get('updated_at'),
|
||||||
|
@ -42,6 +42,15 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
|
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
|
||||||
self.assertEqual(self.bios_setting['name'], bios_obj.name)
|
self.assertEqual(self.bios_setting['name'], bios_obj.name)
|
||||||
self.assertEqual(self.bios_setting['value'], bios_obj.value)
|
self.assertEqual(self.bios_setting['value'], bios_obj.value)
|
||||||
|
self.assertEqual(self.bios_setting['attribute_type'],
|
||||||
|
bios_obj.attribute_type)
|
||||||
|
self.assertEqual(self.bios_setting['allowable_values'],
|
||||||
|
bios_obj.allowable_values)
|
||||||
|
self.assertEqual(self.bios_setting['reset_required'],
|
||||||
|
bios_obj.reset_required)
|
||||||
|
self.assertEqual(self.bios_setting['read_only'],
|
||||||
|
bios_obj.read_only)
|
||||||
|
self.assertEqual(self.bios_setting['unique'], bios_obj.unique)
|
||||||
|
|
||||||
@mock.patch.object(dbapi.IMPL, 'get_bios_setting_list', autospec=True)
|
@mock.patch.object(dbapi.IMPL, 'get_bios_setting_list', autospec=True)
|
||||||
def test_get_by_node_id(self, mock_get_setting_list):
|
def test_get_by_node_id(self, mock_get_setting_list):
|
||||||
@ -67,9 +76,22 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
fake_call_args = {'node_id': self.bios_setting['node_id'],
|
fake_call_args = {'node_id': self.bios_setting['node_id'],
|
||||||
'name': self.bios_setting['name'],
|
'name': self.bios_setting['name'],
|
||||||
'value': self.bios_setting['value'],
|
'value': self.bios_setting['value'],
|
||||||
|
'attribute_type':
|
||||||
|
self.bios_setting['attribute_type'],
|
||||||
|
'allowable_values':
|
||||||
|
self.bios_setting['allowable_values'],
|
||||||
|
'read_only': self.bios_setting['read_only'],
|
||||||
|
'reset_required':
|
||||||
|
self.bios_setting['reset_required'],
|
||||||
|
'unique': self.bios_setting['unique'],
|
||||||
'version': self.bios_setting['version']}
|
'version': self.bios_setting['version']}
|
||||||
setting = [{'name': self.bios_setting['name'],
|
setting = [{'name': 'virtualization', 'value': 'on', 'attribute_type':
|
||||||
'value': self.bios_setting['value']}]
|
'Enumeration', 'allowable_values': ['on', 'off'],
|
||||||
|
'lower_bound': None, 'max_length': None,
|
||||||
|
'min_length': None, 'read_only': False,
|
||||||
|
'reset_required': True, 'unique': False,
|
||||||
|
'upper_bound': None}]
|
||||||
|
|
||||||
bios_obj = objects.BIOSSetting(context=self.context,
|
bios_obj = objects.BIOSSetting(context=self.context,
|
||||||
**fake_call_args)
|
**fake_call_args)
|
||||||
mock_create_list.return_value = [self.bios_setting]
|
mock_create_list.return_value = [self.bios_setting]
|
||||||
@ -81,6 +103,15 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
|
self.assertEqual(self.bios_setting['node_id'], bios_obj.node_id)
|
||||||
self.assertEqual(self.bios_setting['name'], bios_obj.name)
|
self.assertEqual(self.bios_setting['name'], bios_obj.name)
|
||||||
self.assertEqual(self.bios_setting['value'], bios_obj.value)
|
self.assertEqual(self.bios_setting['value'], bios_obj.value)
|
||||||
|
self.assertEqual(self.bios_setting['attribute_type'],
|
||||||
|
bios_obj.attribute_type)
|
||||||
|
self.assertEqual(self.bios_setting['allowable_values'],
|
||||||
|
bios_obj.allowable_values)
|
||||||
|
self.assertEqual(self.bios_setting['read_only'],
|
||||||
|
bios_obj.read_only)
|
||||||
|
self.assertEqual(self.bios_setting['reset_required'],
|
||||||
|
bios_obj.reset_required)
|
||||||
|
self.assertEqual(self.bios_setting['unique'], bios_obj.unique)
|
||||||
|
|
||||||
@mock.patch.object(dbapi.IMPL, 'update_bios_setting_list', autospec=True)
|
@mock.patch.object(dbapi.IMPL, 'update_bios_setting_list', autospec=True)
|
||||||
def test_save(self, mock_update_list):
|
def test_save(self, mock_update_list):
|
||||||
@ -89,7 +120,12 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
'value': self.bios_setting['value'],
|
'value': self.bios_setting['value'],
|
||||||
'version': self.bios_setting['version']}
|
'version': self.bios_setting['version']}
|
||||||
setting = [{'name': self.bios_setting['name'],
|
setting = [{'name': self.bios_setting['name'],
|
||||||
'value': self.bios_setting['value']}]
|
'value': self.bios_setting['value'],
|
||||||
|
'attribute_type': None, 'allowable_values': None,
|
||||||
|
'lower_bound': None, 'max_length': None,
|
||||||
|
'min_length': None, 'read_only': None,
|
||||||
|
'reset_required': None, 'unique': None,
|
||||||
|
'upper_bound': None}]
|
||||||
bios_obj = objects.BIOSSetting(context=self.context,
|
bios_obj = objects.BIOSSetting(context=self.context,
|
||||||
**fake_call_args)
|
**fake_call_args)
|
||||||
mock_update_list.return_value = [self.bios_setting]
|
mock_update_list.return_value = [self.bios_setting]
|
||||||
@ -111,7 +147,7 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
bios_obj_list = objects.BIOSSettingList.create(
|
bios_obj_list = objects.BIOSSettingList.create(
|
||||||
self.context, self.node_id, settings)
|
self.context, self.node_id, settings)
|
||||||
|
|
||||||
mock_create_list.assert_called_once_with(self.node_id, settings, '1.0')
|
mock_create_list.assert_called_once_with(self.node_id, settings, '1.1')
|
||||||
self.assertEqual(self.context, bios_obj_list._context)
|
self.assertEqual(self.context, bios_obj_list._context)
|
||||||
self.assertEqual(2, len(bios_obj_list))
|
self.assertEqual(2, len(bios_obj_list))
|
||||||
self.assertEqual(self.bios_setting['node_id'],
|
self.assertEqual(self.bios_setting['node_id'],
|
||||||
@ -120,7 +156,6 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
self.assertEqual(self.bios_setting['value'], bios_obj_list[0].value)
|
self.assertEqual(self.bios_setting['value'], bios_obj_list[0].value)
|
||||||
self.assertEqual(bios_setting2['node_id'], bios_obj_list[1].node_id)
|
self.assertEqual(bios_setting2['node_id'], bios_obj_list[1].node_id)
|
||||||
self.assertEqual(bios_setting2['name'], bios_obj_list[1].name)
|
self.assertEqual(bios_setting2['name'], bios_obj_list[1].name)
|
||||||
self.assertEqual(bios_setting2['value'], bios_obj_list[1].value)
|
|
||||||
|
|
||||||
@mock.patch.object(dbapi.IMPL, 'update_bios_setting_list', autospec=True)
|
@mock.patch.object(dbapi.IMPL, 'update_bios_setting_list', autospec=True)
|
||||||
def test_list_save(self, mock_update_list):
|
def test_list_save(self, mock_update_list):
|
||||||
@ -131,7 +166,7 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
bios_obj_list = objects.BIOSSettingList.save(
|
bios_obj_list = objects.BIOSSettingList.save(
|
||||||
self.context, self.node_id, settings)
|
self.context, self.node_id, settings)
|
||||||
|
|
||||||
mock_update_list.assert_called_once_with(self.node_id, settings, '1.0')
|
mock_update_list.assert_called_once_with(self.node_id, settings, '1.1')
|
||||||
self.assertEqual(self.context, bios_obj_list._context)
|
self.assertEqual(self.context, bios_obj_list._context)
|
||||||
self.assertEqual(2, len(bios_obj_list))
|
self.assertEqual(2, len(bios_obj_list))
|
||||||
self.assertEqual(self.bios_setting['node_id'],
|
self.assertEqual(self.bios_setting['node_id'],
|
||||||
@ -189,8 +224,7 @@ class TestBIOSSettingObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
|
|||||||
objects.BIOSSettingList.sync_node_setting(self.ctxt, node.id,
|
objects.BIOSSettingList.sync_node_setting(self.ctxt, node.id,
|
||||||
settings))
|
settings))
|
||||||
|
|
||||||
expected_delete = [{'name': bios_obj_1.name,
|
expected_delete = [{'name': 'virtualization', 'value': 'on'}]
|
||||||
'value': bios_obj_1.value}]
|
|
||||||
self.assertEqual(create, settings[:2])
|
self.assertEqual(create, settings[:2])
|
||||||
self.assertEqual(update, [])
|
self.assertEqual(update, [])
|
||||||
self.assertEqual(delete, expected_delete)
|
self.assertEqual(delete, expected_delete)
|
||||||
|
@ -711,7 +711,7 @@ expected_object_fingerprints = {
|
|||||||
'VolumeTargetCRUDPayload': '1.0-30dcc4735512c104a3a36a2ae1e2aeb2',
|
'VolumeTargetCRUDPayload': '1.0-30dcc4735512c104a3a36a2ae1e2aeb2',
|
||||||
'Trait': '1.0-3f26cb70c8a10a3807d64c219453e347',
|
'Trait': '1.0-3f26cb70c8a10a3807d64c219453e347',
|
||||||
'TraitList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
|
'TraitList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
|
||||||
'BIOSSetting': '1.0-fd4a791dc2139a7cc21cefbbaedfd9e7',
|
'BIOSSetting': '1.1-1137db88675a4e2d7f7bcc3a0d52345a',
|
||||||
'BIOSSettingList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
|
'BIOSSettingList': '1.0-33a2e1bb91ad4082f9f63429b77c1244',
|
||||||
'Allocation': '1.1-38937f2854722f1057ec667b12878708',
|
'Allocation': '1.1-38937f2854722f1057ec667b12878708',
|
||||||
'AllocationCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
'AllocationCRUDNotification': '1.0-59acc533c11d306f149846f922739c15',
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Provide the registry fields in the BIOS setting API and in the BIOS setting
|
||||||
|
list when detail is requested. Also added fields selector to query API.
|
||||||
|
See `story
|
||||||
|
2008571 <https://storyboard.openstack.org/#!/story/2008571>`_.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user