Skip to content

Commit 260713d

Browse files
dustin-cowlessoulxu
authored andcommitted
Provider Config File: Enable loading and merging of provider configs
This series implements the referenced blueprint to allow for specifying custom resource provider traits and inventories via yaml config files. This fourth commit adds the config option, release notes, documentation, functional tests, and calls to the previously implemented functions in order to load provider config files and merge them to the provider tree. Change-Id: I59c5758c570acccb629f7010d3104e00d79976e4 Blueprint: provider-config-file
1 parent a7735d5 commit 260713d

File tree

8 files changed

+545
-3
lines changed

8 files changed

+545
-3
lines changed

doc/source/admin/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ instance for these kind of workloads.
113113
ports-with-resource-requests
114114
virtual-persistent-memory
115115
emulated-tpm
116+
managing-resource-providers
116117

117118

118119
Additional guides
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
==============================================
2+
Managing Resource Providers Using Config Files
3+
==============================================
4+
5+
In order to facilitate management of resource provider information in the
6+
Placement API, Nova provides `a method`__ for admins to add custom inventory
7+
and traits to resource providers using YAML files.
8+
9+
__ https://specs.openstack.org/openstack/nova-specs/specs/ussuri/approved/provider-config-file.html
10+
11+
.. note::
12+
13+
Only ``CUSTOM_*`` resource classes and traits may be managed this way.
14+
15+
Placing Files
16+
-------------
17+
18+
Nova-compute will search for ``*.yaml`` files in the path specified in
19+
:oslo.config:option:`compute.provider_config_location`. These files will be
20+
loaded and validated for errors on nova-compute startup. If there are any
21+
errors in the files, nova-compute will fail to start up.
22+
23+
Administrators should ensure that provider config files have appropriate
24+
permissions and ownership. See the `specification`__ and `admin guide`__
25+
for more details.
26+
27+
__ https://specs.openstack.org/openstack/nova-specs/specs/ussuri/approved/provider-config-file.html
28+
__ https://docs.openstack.org/nova/latest/admin/managing-resource-providers.html
29+
30+
.. note::
31+
32+
The files are loaded once at nova-compute startup and any changes or new
33+
files will not be recognized until the next nova-compute startup.
34+
35+
Examples
36+
--------
37+
38+
Resource providers to target can be identified by either UUID or name. In
39+
addition, the value ``$COMPUTE_NODE`` can be used in the UUID field to
40+
identify all nodes managed by the service.
41+
42+
If an entry does not include any additional inventory or traits, it will be
43+
logged at load time but otherwise ignored. In the case of a resource provider
44+
being identified by both ``$COMPUTE_NODE`` and individual UUID/name, the
45+
values in the ``$COMPUTE_NODE`` entry will be ignored for *that provider* only
46+
if the explicit entry includes inventory or traits.
47+
48+
.. note::
49+
50+
In the case that a resource provider is identified more than once by
51+
explicit UUID/name, the nova-compute service will fail to start. This
52+
is a global requirement across all supplied ``provider.yaml`` files.
53+
54+
.. code-block:: yaml
55+
56+
meta:
57+
schema_version: '1.0'
58+
providers:
59+
- identification:
60+
name: 'EXAMPLE_RESOURCE_PROVIDER'
61+
# Additional valid identification examples:
62+
# uuid: '$COMPUTE_NODE'
63+
# uuid: '5213b75d-9260-42a6-b236-f39b0fd10561'
64+
inventories:
65+
additional:
66+
- CUSTOM_EXAMPLE_RESOURCE_CLASS:
67+
total: 100
68+
reserved: 0
69+
min_unit: 1
70+
max_unit: 10
71+
step_size: 1
72+
allocation_ratio: 1.0
73+
traits:
74+
additional:
75+
- 'CUSTOM_EXAMPLE_TRAIT'
76+
77+
Schema Example
78+
--------------
79+
.. code-block:: yaml
80+
81+
type: object
82+
properties:
83+
# This property is used to track where the provider.yaml file originated.
84+
# It is reserved for internal use and should never be set in a provider.yaml
85+
# file supplied by an end user.
86+
__source_file:
87+
not: {}
88+
meta:
89+
type: object
90+
properties:
91+
# Version ($Major, $minor) of the schema must successfully parse
92+
# documents conforming to ($Major, 0..N). Any breaking schema change
93+
# (e.g. removing fields, adding new required fields, imposing a stricter
94+
# pattern on a value, etc.) must bump $Major.
95+
schema_version:
96+
type: string
97+
pattern: '^1\.([0-9]|[1-9][0-9]+)$'
98+
required:
99+
- schema_version
100+
additionalProperties: true
101+
providers:
102+
type: array
103+
items:
104+
type: object
105+
properties:
106+
identification:
107+
$ref: '#/provider_definitions/provider_identification'
108+
inventories:
109+
$ref: '#/provider_definitions/provider_inventories'
110+
traits:
111+
$ref: '#/provider_definitions/provider_traits'
112+
required:
113+
- identification
114+
additionalProperties: true
115+
required:
116+
- meta
117+
additionalProperties: true
118+
119+
provider_definitions:
120+
provider_identification:
121+
# Identify a single provider to configure. Exactly one identification
122+
# method should be used. Currently `uuid` or `name` are supported, but
123+
# future versions may support others.
124+
# The uuid can be set to the sentinel value `$COMPUTE_NODE` which will
125+
# cause the consuming compute service to apply the configuration to
126+
# to all compute node root providers it manages that are not otherwise
127+
# specified using a uuid or name.
128+
type: object
129+
properties:
130+
uuid:
131+
oneOf:
132+
# TODO(sean-k-mooney): replace this with type uuid when we can depend
133+
# on a version of the jsonschema lib that implements draft 8 or later
134+
# of the jsonschema spec.
135+
- type: string
136+
pattern: '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$'
137+
- type: string
138+
const: '$COMPUTE_NODE'
139+
name:
140+
type: string
141+
minLength: 1
142+
# This introduces the possibility of an unsupported key name being used to
143+
# get by schema validation, but is necessary to support forward
144+
# compatibility with new identification methods. This should be checked
145+
# after schema validation.
146+
minProperties: 1
147+
maxProperties: 1
148+
additionalProperties: false
149+
provider_inventories:
150+
# Allows the admin to specify various adjectives to create and manage
151+
# providers' inventories. This list of adjectives can be extended in the
152+
# future as the schema evolves to meet new use cases. As of v1.0, only one
153+
# adjective, `additional`, is supported.
154+
type: object
155+
properties:
156+
additional:
157+
type: array
158+
items:
159+
patternProperties:
160+
# Allows any key name matching the resource class pattern,
161+
# check to prevent conflicts with virt driver owned resouces classes
162+
# will be done after schema validation.
163+
^[A-Z0-9_]{1,255}$:
164+
type: object
165+
properties:
166+
# Any optional properties not populated will be given a default value by
167+
# placement. If overriding a pre-existing provider values will not be
168+
# preserved from the existing inventory.
169+
total:
170+
type: integer
171+
reserved:
172+
type: integer
173+
min_unit:
174+
type: integer
175+
max_unit:
176+
type: integer
177+
step_size:
178+
type: integer
179+
allocation_ratio:
180+
type: number
181+
required:
182+
- total
183+
# The defined properties reflect the current placement data
184+
# model. While defining those in the schema and not allowing
185+
# additional properties means we will need to bump the schema
186+
# version if they change, that is likely to be part of a large
187+
# change that may have other impacts anyway. The benefit of
188+
# stricter validation of property names outweighs the (small)
189+
# chance of having to bump the schema version as described above.
190+
additionalProperties: false
191+
# This ensures only keys matching the pattern above are allowed
192+
additionalProperties: false
193+
additionalProperties: true
194+
provider_traits:
195+
# Allows the admin to specify various adjectives to create and manage
196+
# providers' traits. This list of adjectives can be extended in the
197+
# future as the schema evolves to meet new use cases. As of v1.0, only one
198+
# adjective, `additional`, is supported.
199+
type: object
200+
properties:
201+
additional:
202+
type: array
203+
items:
204+
# Allows any value matching the trait pattern here, additional
205+
# validation will be done after schema validation.
206+
type: string
207+
pattern: '^[A-Z0-9_]{1,255}$'
208+
additionalProperties: true
209+
210+
.. note::
211+
212+
When creating a ``provider.yaml`` config file it is recommended to use the
213+
schema provided by nova to validate the config using a simple jsonschema
214+
validator rather than starting the nova compute agent to enable faster
215+
iteration.
216+

nova/compute/resource_tracker.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
from nova.compute import claims
3232
from nova.compute import monitors
33+
from nova.compute import provider_config
3334
from nova.compute import stats as compute_stats
3435
from nova.compute import task_states
3536
from nova.compute import utils as compute_utils
@@ -112,6 +113,11 @@ def __init__(self, host, driver, reportclient=None):
112113
# and value of this sub-dict is a set of Resource obj
113114
self.assigned_resources = collections.defaultdict(
114115
lambda: collections.defaultdict(set))
116+
# Retrieves dict of provider config data. This can fail with
117+
# nova.exception.ProviderConfigException if invalid or conflicting
118+
# data exists in the provider config files.
119+
self.provider_configs = provider_config.get_provider_configs(
120+
CONF.compute.provider_config_location)
115121
# Set of ids for providers identified in provider config files that
116122
# are not found on the provider tree. These are tracked to facilitate
117123
# smarter logging.
@@ -1155,6 +1161,9 @@ def _update_to_placement(self, context, compute_node, startup):
11551161

11561162
self.provider_tree = prov_tree
11571163

1164+
# This merges in changes from the provider config files loaded in init
1165+
self._merge_provider_configs(self.provider_configs, prov_tree)
1166+
11581167
# Flush any changes. If we processed ReshapeNeeded above, allocs is not
11591168
# None, and this will hit placement's POST /reshaper route.
11601169
self.reportclient.update_from_provider_tree(context, prov_tree,
@@ -1714,6 +1723,7 @@ def _merge_provider_configs(self, provider_configs, provider_tree):
17141723
:param provider_tree: The provider tree to be updated in place
17151724
"""
17161725
processed_providers = {}
1726+
provider_custom_traits = {}
17171727
for uuid_or_name, provider_data in provider_configs.items():
17181728
additional_traits = provider_data.get(
17191729
"traits", {}).get("additional", [])
@@ -1758,10 +1768,23 @@ def _merge_provider_configs(self, provider_configs, provider_tree):
17581768
'current_uuid': current_uuid
17591769
}
17601770
)
1761-
processed_providers[current_uuid] = source_file_name
1771+
1772+
# NOTE(sean-k-mooney): since each provider should be processed
1773+
# at most once if a provider has custom traits they were
1774+
# set either in previous iteration, the virt driver or via the
1775+
# the placement api. As a result we must ignore them when
1776+
# checking for duplicate traits so we construct a set of the
1777+
# existing custom traits.
1778+
if current_uuid not in provider_custom_traits:
1779+
provider_custom_traits[current_uuid] = {
1780+
trait for trait in provider.traits
1781+
if trait.startswith('CUSTOM')
1782+
}
1783+
existing_custom_traits = provider_custom_traits[current_uuid]
17621784

17631785
if additional_traits:
17641786
intersect = set(provider.traits) & set(additional_traits)
1787+
intersect -= existing_custom_traits
17651788
if intersect:
17661789
invalid = ','.join(intersect)
17671790
raise ValueError(_(
@@ -1797,6 +1820,8 @@ def _merge_provider_configs(self, provider_configs, provider_tree):
17971820
provider_tree.update_inventory(
17981821
provider.uuid, merged_inventory)
17991822

1823+
processed_providers[current_uuid] = source_file_name
1824+
18001825
def _get_providers_to_update(self, uuid_or_name, provider_tree,
18011826
source_file):
18021827
"""Identifies the providers to be updated.

nova/conf/compute.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -967,6 +967,19 @@
967967
968968
* -1 means unlimited
969969
* Any integer >= 0 represents the maximum allowed
970+
"""),
971+
cfg.StrOpt('provider_config_location',
972+
default='/etc/nova/provider_config/',
973+
help="""
974+
Location of YAML files containing resource provider configuration data.
975+
976+
These files allow the operator to specify additional custom inventory and
977+
traits to assign to one or more resource providers.
978+
979+
Additional documentation is available here:
980+
981+
https://docs.openstack.org/nova/latest/admin/managing-resource-providers.html
982+
970983
"""),
971984
]
972985

0 commit comments

Comments
 (0)