summaryrefslogtreecommitdiff
path: root/doc/source/reference/update-provider-tree.rst
blob: bc204c5a9ee9db368456e073143346b0cc794986 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
..
      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.

====================================
 ComputeDriver.update_provider_tree
====================================

This provides details on the ``ComputeDriver`` abstract method
``update_provider_tree`` for developers implementing this method in their own
virt drivers.

Background
----------
In the movement towards using placement for scheduling and resource management,
the virt driver method ``get_available_resource`` was initially superseded by
``get_inventory`` (now gone), whereby the driver could specify its inventory in
terms understood by placement. In Queens, a ``get_traits`` driver method was
added. But ``get_inventory`` was limited to expressing only inventory (not
traits or aggregates). And both of these methods were limited to the resource
provider corresponding to the compute node.

Developments such as Nested Resource Providers necessitate the ability
for the virt driver to have deeper control over what the resource tracker
configures in placement on behalf of the compute node. This need is filled by
the virt driver method ``update_provider_tree`` and its consumption by the
resource tracker, allowing full control over the placement representation of
the compute node and its associated providers.

The Method
----------
``update_provider_tree`` accepts the following parameters:

* A ``nova.compute.provider_tree.ProviderTree`` object representing all the
  providers in the tree associated with the compute node, and any sharing
  providers (those with the ``MISC_SHARES_VIA_AGGREGATE`` trait) associated via
  aggregate with any of those providers (but not *their* tree- or
  aggregate-associated providers), as currently known by placement. This
  object is fully owned by the ``update_provider_tree`` method, and can
  therefore be modified without locking/concurrency considerations. In other
  words, the parameter is passed *by reference* with the expectation that the
  virt driver will modify the object. Note, however, that it may contain
  providers not directly owned/controlled by the compute host. Care must be
  taken not to remove or modify such providers inadvertently. In addition,
  providers may be associated with traits and/or aggregates maintained by
  outside agents. The ``update_provider_tree`` method must therefore also be
  careful only to add/remove traits/aggregates it explicitly controls.
* String name of the compute node (i.e. ``ComputeNode.hypervisor_hostname``)
  for which the caller is requesting updated provider information. Drivers may
  use this to help identify the compute node provider in the ProviderTree.
  Drivers managing more than one node (e.g. ironic) may also use it as a cue to
  indicate which node is being processed by the caller.
* Dictionary of ``allocations`` data of the form:

  .. code::

    { $CONSUMER_UUID: {
          # The shape of each "allocations" dict below is identical
          # to the return from GET /allocations/{consumer_uuid}
          "allocations": {
              $RP_UUID: {
                  "generation": $RP_GEN,
                  "resources": {
                      $RESOURCE_CLASS: $AMOUNT,
                      ...
                  },
              },
              ...
          },
          "project_id": $PROJ_ID,
          "user_id": $USER_ID,
          "consumer_generation": $CONSUMER_GEN,
      },
      ...
    }

  If ``None``, and the method determines that any inventory needs to be moved
  (from one provider to another and/or to a different resource class), the
  ``ReshapeNeeded`` exception must be raised. Otherwise, this dict must be
  edited in place to indicate the desired final state of allocations. Drivers
  should *only* edit allocation records for providers whose inventories are
  being affected by the reshape operation. For more information about the
  reshape operation, refer to the `spec <http://specs.openstack.org/openstack/
  nova-specs/specs/stein/approved/reshape-provider-tree.html>`_.

The virt driver is expected to update the ProviderTree object with current
resource provider and inventory information. When the method returns, the
ProviderTree should represent the correct hierarchy of nested resource
providers associated with this compute node, as well as the inventory,
aggregates, and traits associated with those resource providers.

.. note:: Despite the name, a ProviderTree instance may in fact contain more
          than one tree. For purposes of this specification, the ProviderTree
          passed to ``update_provider_tree`` will contain:

          * the entire tree associated with the compute node; and
          * any sharing providers (those with the ``MISC_SHARES_VIA_AGGREGATE``
            trait) which are associated via aggregate with any of the providers
            in the compute node's tree. The sharing providers will be
            presented as lone roots in the ProviderTree, even if they happen to
            be part of a tree themselves.

          Consider the example below. ``SSP`` is a shared storage provider and
          ``BW1`` and ``BW2`` are shared bandwidth providers; all three have
          the ``MISC_SHARES_VIA_AGGREGATE`` trait::

                     CN1                 SHR_ROOT               CN2
                    /   \       agg1    /   /\     agg1        /   \
               NUMA1     NUMA2--------SSP--/--\-----------NUMA1     NUMA2
              /     \   /    \            /    \         /     \   /    \
            PF1    PF2 PF3   PF4--------BW1   BW2------PF1    PF2 PF3   PF4
                                 agg2             agg3

          When ``update_provider_tree`` is invoked for ``CN1``, it is passed a
          ProviderTree containing::

                     CN1 (root)
                    /   \       agg1
               NUMA1     NUMA2-------SSP (root)
              /     \   /    \
            PF1    PF2 PF3   PF4------BW1 (root)
                                 agg2

Driver implementations of ``update_provider_tree`` are expected to use public
``ProviderTree`` methods to effect changes to the provider tree passed in.
Some of the methods which may be useful are as follows:

* ``new_root``: Add a new root provider to the tree.
* ``new_child``: Add a new child under an existing provider.
* ``data``: Access information (name, UUID, parent, inventory, traits,
  aggregates) about a provider in the tree.
* ``remove``: Remove a provider **and its descendants** from the tree. Use
  caution in multiple-ownership scenarios.
* ``update_inventory``: Set the inventory for a provider.
* ``add_traits``, ``remove_traits``: Set/unset virt-owned traits for a
  provider.
* ``add_aggregates``, ``remove_aggregates``: Set/unset virt-owned aggregate
  associations for a provider.

.. note:: There is no supported mechanism for ``update_provider_tree`` to
          effect changes to allocations. This is intentional: in Nova,
          allocations are managed exclusively outside of virt. (Usually by the
          scheduler; sometimes - e.g. for migrations - by the conductor.)

Porting from get_inventory
~~~~~~~~~~~~~~~~~~~~~~~~~~
Virt driver developers wishing to move from ``get_inventory`` to
``update_provider_tree`` should use the ``ProviderTree.update_inventory``
method, specifying the compute node as the provider and the same inventory as
returned by ``get_inventory``. For example:

.. code::

  def get_inventory(self, nodename):
      inv_data = {
          'VCPU': { ... },
          'MEMORY_MB': { ... },
          'DISK_GB': { ... },
      }
      return inv_data

would become:

.. code::

  def update_provider_tree(self, provider_tree, nodename, allocations=None):
      inv_data = {
          'VCPU': { ... },
          'MEMORY_MB': { ... },
          'DISK_GB': { ... },
      }
      provider_tree.update_inventory(nodename, inv_data)

When reporting inventory for the standard resource classes ``VCPU``,
``MEMORY_MB`` and ``DISK_GB``, implementors of ``update_provider_tree`` may
need to set the ``allocation_ratio`` and ``reserved`` values in the
``inv_data`` dict based on configuration to reflect changes on the compute
for allocation ratios and reserved resource amounts back to the placement
service.

Porting from get_traits
~~~~~~~~~~~~~~~~~~~~~~~
To replace ``get_traits``, developers should use the
``ProviderTree.add_traits`` method, specifying the compute node as the
provider and the same traits as returned by ``get_traits``. For example:

.. code::

  def get_traits(self, nodename):
      traits = ['HW_CPU_X86_AVX', 'HW_CPU_X86_AVX2', 'CUSTOM_GOLD']
      return traits

would become:

.. code::

  def update_provider_tree(self, provider_tree, nodename, allocations=None):
      provider_tree.add_traits(
          nodename, 'HW_CPU_X86_AVX', 'HW_CPU_X86_AVX2', 'CUSTOM_GOLD')

.. _taxonomy_of_traits_and_capabilities:

Taxonomy of traits and capabilities
-----------------------------------

There are various types of traits:

- Some are standard (registered in
  `os-traits <https://docs.openstack.org/os-traits/latest/>`_); others
  are custom.

- Some are owned by the compute service; others can be managed by
  operators.

- Some come from driver-supported capabilities, via a mechanism which
  was `introduced <https://review.opendev.org/538498>`_ to convert
  them to standard traits on the compute node resource provider.  This
  mechanism is :ref:`documented in the configuration guide
  <compute-capabilities-as-traits>`.

This diagram may shed further light on how these traits relate to each
other and how they are managed.

.. figure:: /_static/images/traits-taxonomy.svg
   :width: 800
   :alt: Venn diagram showing taxonomy of traits and capabilities