Merge "support sub provider"
This commit is contained in:
commit
b727c1670a
670
cyborg/agent/provider_tree.py
Normal file
670
cyborg/agent/provider_tree.py
Normal file
@ -0,0 +1,670 @@
|
||||
# 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.
|
||||
|
||||
"""An object describing a tree of resource providers and their inventories.
|
||||
|
||||
This object is not stored in the Nova API or cell databases; rather, this
|
||||
object is constructed and used by the scheduler report client to track state
|
||||
changes for resources on the hypervisor or baremetal node. As such, there are
|
||||
no remoteable methods nor is there any interaction with the nova.db modules.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import copy
|
||||
|
||||
import os_traits
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from cyborg.common.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
_LOCK_NAME = 'provider-tree-lock'
|
||||
|
||||
# Point-in-time representation of a resource provider in the tree.
|
||||
# Note that, whereas namedtuple enforces read-only-ness of instances as a
|
||||
# whole, nothing prevents modification of the internals of attributes of
|
||||
# complex types (children/inventory/traits/aggregates). However, any such
|
||||
# modifications still have no effect on the ProviderTree the instance came
|
||||
# from. Like, you can Sharpie a moustache on a Polaroid of my face, but that
|
||||
# doesn't make a moustache appear on my actual face.
|
||||
ProviderData = collections.namedtuple(
|
||||
'ProviderData', ['uuid', 'name', 'generation', 'parent_uuid', 'inventory',
|
||||
'traits', 'aggregates'])
|
||||
|
||||
|
||||
class _Provider(object):
|
||||
"""Represents a resource provider in the tree.
|
||||
|
||||
All operations against the tree should be done using the ProviderTree
|
||||
interface, since it controls thread-safety.
|
||||
"""
|
||||
|
||||
def __init__(self, name, uuid=None, generation=None, parent_uuid=None):
|
||||
if uuid is None:
|
||||
uuid = uuidutils.generate_uuid()
|
||||
self.uuid = uuid
|
||||
self.name = name
|
||||
self.generation = generation
|
||||
self.parent_uuid = parent_uuid
|
||||
# Contains a dict, keyed by uuid of child resource providers having
|
||||
# this provider as a parent
|
||||
self.children = {}
|
||||
# dict of inventory records, keyed by resource class
|
||||
self.inventory = {}
|
||||
# Set of trait names
|
||||
self.traits = set()
|
||||
# Set of aggregate UUIDs
|
||||
self.aggregates = set()
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, pdict):
|
||||
"""Factory method producing a _Provider based on a dict with
|
||||
appropriate keys.
|
||||
|
||||
:param pdict: Dictionary representing a provider, with keys 'name',
|
||||
'uuid', 'generation', 'parent_provider_uuid'. Of these,
|
||||
only 'name' is mandatory.
|
||||
"""
|
||||
return cls(pdict['name'], uuid=pdict.get('uuid'),
|
||||
generation=pdict.get('generation'),
|
||||
parent_uuid=pdict.get('parent_provider_uuid'))
|
||||
|
||||
def data(self):
|
||||
"""A collection of all informations of a provider.
|
||||
|
||||
:Return: a collections.namedtuple
|
||||
include inventory, traits, aggregates, uuid, name, generation,
|
||||
and parent_uuid.
|
||||
"""
|
||||
inventory = copy.deepcopy(self.inventory)
|
||||
traits = copy.copy(self.traits)
|
||||
aggregates = copy.copy(self.aggregates)
|
||||
return ProviderData(
|
||||
self.uuid, self.name, self.generation, self.parent_uuid,
|
||||
inventory, traits, aggregates)
|
||||
|
||||
def get_provider_uuids(self):
|
||||
"""Returns a list, in top-down traversal order, of UUIDs of this
|
||||
provider and all its descendants.
|
||||
"""
|
||||
ret = [self.uuid]
|
||||
for child in self.children.values():
|
||||
ret.extend(child.get_provider_uuids())
|
||||
return ret
|
||||
|
||||
def find(self, search):
|
||||
"""Find an expect one in the provider tree by match the serach.
|
||||
|
||||
:param search: it can be the either name or uuid of an expect provider.
|
||||
:return: the expect _Provider object or None.
|
||||
"""
|
||||
if self.name == search or self.uuid == search:
|
||||
return self
|
||||
if search in self.children:
|
||||
return self.children[search]
|
||||
if self.children:
|
||||
for child in self.children.values():
|
||||
# We already searched for the child by UUID above, so here we
|
||||
# just check for a child name match
|
||||
if child.name == search:
|
||||
return child
|
||||
subchild = child.find(search)
|
||||
if subchild:
|
||||
return subchild
|
||||
return None
|
||||
|
||||
def add_child(self, provider):
|
||||
self.children[provider.uuid] = provider
|
||||
|
||||
def remove_child(self, provider):
|
||||
if provider.uuid in self.children:
|
||||
del self.children[provider.uuid]
|
||||
|
||||
def has_inventory(self):
|
||||
"""Returns whether the provider has any inventory records at all."""
|
||||
return self.inventory != {}
|
||||
|
||||
def has_inventory_changed(self, new):
|
||||
"""Returns whether the inventory has changed for the provider."""
|
||||
cur = self.inventory
|
||||
if set(cur) != set(new):
|
||||
return True
|
||||
for key, cur_rec in cur.items():
|
||||
new_rec = new[key]
|
||||
# If the new record contains new fields (e.g. we're adding on
|
||||
# `reserved` or `allocation_ratio`) we want to make sure to pick
|
||||
# them up
|
||||
if set(new_rec) - set(cur_rec):
|
||||
return True
|
||||
for rec_key, cur_val in cur_rec.items():
|
||||
if rec_key not in new_rec:
|
||||
# Deliberately don't want to compare missing keys in the
|
||||
# *new* inventory record. For instance, we will be passing
|
||||
# in fields like allocation_ratio in the current dict but
|
||||
# the resource tracker may only pass in the total field. We
|
||||
# want to return that inventory didn't change when the
|
||||
# total field values are the same even if the
|
||||
# allocation_ratio field is missing from the new record.
|
||||
continue
|
||||
if new_rec[rec_key] != cur_val:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _update_generation(self, generation):
|
||||
if generation is not None and generation != self.generation:
|
||||
msg_args = {
|
||||
'rp_uuid': self.uuid,
|
||||
'old': self.generation,
|
||||
'new': generation,
|
||||
}
|
||||
LOG.debug("Updating resource provider %(rp_uuid)s generation "
|
||||
"from %(old)s to %(new)s", msg_args)
|
||||
self.generation = generation
|
||||
|
||||
def update_inventory(self, inventory, generation):
|
||||
"""Update the stored inventory for the provider along with a resource
|
||||
provider generation to set the provider to. The method returns whether
|
||||
the inventory has changed.
|
||||
"""
|
||||
self._update_generation(generation)
|
||||
if self.has_inventory_changed(inventory):
|
||||
self.inventory = copy.deepcopy(inventory)
|
||||
return True
|
||||
return False
|
||||
|
||||
def have_traits_changed(self, new):
|
||||
"""Returns whether the provider's traits have changed."""
|
||||
return set(new) != self.traits
|
||||
|
||||
def update_traits(self, new, generation=None):
|
||||
"""Update the stored traits for the provider along with a resource
|
||||
provider generation to set the provider to. The method returns whether
|
||||
the traits have changed.
|
||||
"""
|
||||
self._update_generation(generation)
|
||||
if self.have_traits_changed(new):
|
||||
self.traits = set(new) # create a copy of the new traits
|
||||
return True
|
||||
return False
|
||||
|
||||
def has_traits(self, traits):
|
||||
"""Query whether the provider has certain traits.
|
||||
|
||||
:param traits: Iterable of string trait names to look for.
|
||||
:return: True if this provider has *all* of the specified traits; False
|
||||
if any of the specified traits are absent. Returns True if
|
||||
the traits parameter is empty.
|
||||
"""
|
||||
return not bool(set(traits) - self.traits)
|
||||
|
||||
def have_aggregates_changed(self, new):
|
||||
"""Returns whether the provider's aggregates have changed."""
|
||||
return set(new) != self.aggregates
|
||||
|
||||
def update_aggregates(self, new, generation=None):
|
||||
"""Update the stored aggregates for the provider along with a resource
|
||||
provider generation to set the provider to. The method returns whether
|
||||
the aggregates have changed.
|
||||
"""
|
||||
self._update_generation(generation)
|
||||
if self.have_aggregates_changed(new):
|
||||
self.aggregates = set(new) # create a copy of the new aggregates
|
||||
return True
|
||||
return False
|
||||
|
||||
def in_aggregates(self, aggregates):
|
||||
"""Query whether the provider is a member of certain aggregates.
|
||||
|
||||
:param aggregates: Iterable of string aggregate UUIDs to look for.
|
||||
:return: True if this provider is a member of *all* of the specified
|
||||
aggregates; False if any of the specified aggregates are
|
||||
absent. Returns True if the aggregates parameter is empty.
|
||||
"""
|
||||
return not bool(set(aggregates) - self.aggregates)
|
||||
|
||||
|
||||
class ProviderTree(object):
|
||||
|
||||
def __init__(self):
|
||||
"""Create an empty provider tree."""
|
||||
self.lock = lockutils.internal_lock(_LOCK_NAME)
|
||||
self.roots = []
|
||||
|
||||
def get_provider_uuids(self, name_or_uuid=None):
|
||||
"""Return a list, in top-down traversable order, of the UUIDs of all
|
||||
providers (in a subtree).
|
||||
|
||||
:param name_or_uuid: Provider name or UUID representing the root of a
|
||||
subtree for which to return UUIDs. If not
|
||||
specified, the method returns all UUIDs in the
|
||||
ProviderTree.
|
||||
"""
|
||||
if name_or_uuid is not None:
|
||||
with self.lock:
|
||||
return self._find_with_lock(name_or_uuid).get_provider_uuids()
|
||||
|
||||
# If no name_or_uuid, get UUIDs for all providers recursively.
|
||||
ret = []
|
||||
with self.lock:
|
||||
for root in self.roots:
|
||||
ret.extend(root.get_provider_uuids())
|
||||
return ret
|
||||
|
||||
def populate_from_iterable(self, provider_dicts):
|
||||
"""Populates this ProviderTree from an iterable of provider dicts.
|
||||
|
||||
This method will ADD providers to the tree if provider_dicts contains
|
||||
providers that do not exist in the tree already and will REPLACE
|
||||
providers in the tree if provider_dicts contains providers that are
|
||||
already in the tree. This method will NOT remove providers from the
|
||||
tree that are not in provider_dicts. But if a parent provider is in
|
||||
provider_dicts and the descendents are not, this method will remove the
|
||||
descendents from the tree.
|
||||
|
||||
:param provider_dicts: An iterable of dicts of resource provider
|
||||
information. If a provider is present in
|
||||
provider_dicts, all its descendants must also be
|
||||
present.
|
||||
:raises: ValueError if any provider in provider_dicts has a parent that
|
||||
is not in this ProviderTree or elsewhere in provider_dicts.
|
||||
"""
|
||||
if not provider_dicts:
|
||||
return
|
||||
|
||||
# Map of provider UUID to provider dict for the providers we're
|
||||
# *adding* via this method.
|
||||
to_add_by_uuid = {pd['uuid']: pd for pd in provider_dicts}
|
||||
|
||||
with self.lock:
|
||||
# Sanity check for orphans. Every parent UUID must either be None
|
||||
# (the provider is a root), or be in the tree already, or exist as
|
||||
# a key in to_add_by_uuid (we're adding it).
|
||||
all_parents = set([None]) | set(to_add_by_uuid)
|
||||
# NOTE(efried): Can't use get_provider_uuids directly because we're
|
||||
# already under lock.
|
||||
for root in self.roots:
|
||||
all_parents |= set(root.get_provider_uuids())
|
||||
missing_parents = set()
|
||||
for pd in to_add_by_uuid.values():
|
||||
parent_uuid = pd.get('parent_provider_uuid')
|
||||
if parent_uuid not in all_parents:
|
||||
missing_parents.add(parent_uuid)
|
||||
if missing_parents:
|
||||
raise ValueError(
|
||||
_("The following parents were not found: %s") %
|
||||
', '.join(missing_parents))
|
||||
|
||||
# Ready to do the work.
|
||||
# Use to_add_by_uuid to keep track of which providers are left to
|
||||
# be added.
|
||||
while to_add_by_uuid:
|
||||
# Find a provider that's suitable to inject.
|
||||
for uuid, pd in to_add_by_uuid.items():
|
||||
# Roots are always okay to inject (None won't be a key in
|
||||
# to_add_by_uuid). Otherwise, we have to make sure we
|
||||
# already added the parent (and, by recursion, all
|
||||
# ancestors) if present in the input.
|
||||
parent_uuid = pd.get('parent_provider_uuid')
|
||||
if parent_uuid not in to_add_by_uuid:
|
||||
break
|
||||
else:
|
||||
# This should never happen - we already ensured all parents
|
||||
# exist in the tree, which means we can't have any branches
|
||||
# that don't wind up at the root, which means we can't have
|
||||
# cycles. But to quell the paranoia...
|
||||
raise ValueError(
|
||||
_("Unexpectedly failed to find parents already in the"
|
||||
"tree for any of the following: %s") %
|
||||
','.join(set(to_add_by_uuid)))
|
||||
|
||||
# Add or replace the provider, either as a root or under its
|
||||
# parent
|
||||
try:
|
||||
self._remove_with_lock(uuid)
|
||||
except ValueError:
|
||||
# Wasn't there in the first place - fine.
|
||||
pass
|
||||
|
||||
provider = _Provider.from_dict(pd)
|
||||
if parent_uuid is None:
|
||||
self.roots.append(provider)
|
||||
else:
|
||||
parent = self._find_with_lock(parent_uuid)
|
||||
parent.add_child(provider)
|
||||
|
||||
# Remove this entry to signify we're done with it.
|
||||
to_add_by_uuid.pop(uuid)
|
||||
|
||||
def _remove_with_lock(self, name_or_uuid):
|
||||
found = self._find_with_lock(name_or_uuid)
|
||||
if found.parent_uuid:
|
||||
parent = self._find_with_lock(found.parent_uuid)
|
||||
parent.remove_child(found)
|
||||
else:
|
||||
self.roots.remove(found)
|
||||
|
||||
def remove(self, name_or_uuid):
|
||||
"""Safely removes the provider identified by the supplied name_or_uuid
|
||||
parameter and all of its children from the tree.
|
||||
|
||||
:raises ValueError if name_or_uuid points to a non-existing provider.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
remove from the tree.
|
||||
"""
|
||||
with self.lock:
|
||||
self._remove_with_lock(name_or_uuid)
|
||||
|
||||
def new_root(self, name, uuid, generation=None):
|
||||
"""Adds a new root provider to the tree, returning its UUID.
|
||||
|
||||
:param name: The name of the new root provider
|
||||
:param uuid: The UUID of the new root provider
|
||||
:param generation: Generation to set for the new root provider
|
||||
:returns: the UUID of the new provider
|
||||
:raises: ValueError if a provider with the specified uuid already
|
||||
exists in the tree.
|
||||
"""
|
||||
|
||||
with self.lock:
|
||||
exists = True
|
||||
try:
|
||||
self._find_with_lock(uuid)
|
||||
except ValueError:
|
||||
exists = False
|
||||
|
||||
if exists:
|
||||
err = _("Provider %s already exists.")
|
||||
raise ValueError(err % uuid)
|
||||
|
||||
p = _Provider(name, uuid=uuid, generation=generation)
|
||||
self.roots.append(p)
|
||||
return p.uuid
|
||||
|
||||
def _find_with_lock(self, name_or_uuid):
|
||||
for root in self.roots:
|
||||
found = root.find(name_or_uuid)
|
||||
if found:
|
||||
return found
|
||||
raise ValueError(_("No such provider %s") % name_or_uuid)
|
||||
|
||||
def data(self, name_or_uuid):
|
||||
"""Return a point-in-time copy of the specified provider's data.
|
||||
|
||||
:param name_or_uuid: Either name or UUID of the resource provider whose
|
||||
data is to be returned.
|
||||
:return: ProviderData object representing the specified provider.
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
"""
|
||||
with self.lock:
|
||||
return self._find_with_lock(name_or_uuid).data()
|
||||
|
||||
def exists(self, name_or_uuid):
|
||||
"""Given either a name or a UUID, return True if the tree contains the
|
||||
provider, False otherwise.
|
||||
"""
|
||||
with self.lock:
|
||||
try:
|
||||
self._find_with_lock(name_or_uuid)
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def new_child(self, name, parent, uuid=None, generation=None):
|
||||
"""Creates a new child provider with the given name and uuid under the
|
||||
given parent.
|
||||
|
||||
:param name: The name of the new child provider
|
||||
:param parent: Either name or UUID of the parent provider
|
||||
:param uuid: The UUID of the new child provider
|
||||
:param generation: Generation to set for the new child provider
|
||||
:returns: the UUID of the new provider
|
||||
|
||||
:raises ValueError if a provider with the specified uuid or name
|
||||
already exists; or if parent_uuid points to a nonexistent
|
||||
provider.
|
||||
"""
|
||||
with self.lock:
|
||||
try:
|
||||
self._find_with_lock(uuid or name)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
err = _("Provider %s already exists.")
|
||||
raise ValueError(err % (uuid or name))
|
||||
|
||||
parent_node = self._find_with_lock(parent)
|
||||
p = _Provider(name, uuid, generation, parent_node.uuid)
|
||||
parent_node.add_child(p)
|
||||
return p.uuid
|
||||
|
||||
def has_inventory(self, name_or_uuid):
|
||||
"""Returns True if the provider identified by name_or_uuid has any
|
||||
inventory records at all.
|
||||
|
||||
:raises: ValueError if a provider with uuid was not found in the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider
|
||||
"""
|
||||
with self.lock:
|
||||
p = self._find_with_lock(name_or_uuid)
|
||||
return p.has_inventory()
|
||||
|
||||
def has_inventory_changed(self, name_or_uuid, inventory):
|
||||
"""Returns True if the supplied inventory is different for the provider
|
||||
with the supplied name or UUID.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
query inventory for.
|
||||
:param inventory: dict, keyed by resource class, of inventory
|
||||
information.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.has_inventory_changed(inventory)
|
||||
|
||||
def update_inventory(self, name_or_uuid, inventory, generation=None):
|
||||
"""Given a name or UUID of a provider and a dict of inventory resource
|
||||
records, update the provider's inventory and set the provider's
|
||||
generation.
|
||||
|
||||
:returns: True if the inventory has changed.
|
||||
|
||||
:note: The provider's generation is always set to the supplied
|
||||
generation, even if there were no changes to the inventory.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
update inventory for.
|
||||
:param inventory: dict, keyed by resource class, of inventory
|
||||
information.
|
||||
:param generation: The resource provider generation to set. If not
|
||||
specified, the provider's generation is not changed.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.update_inventory(inventory, generation)
|
||||
|
||||
def has_sharing_provider(self, resource_class):
|
||||
"""Returns whether the specified provider_tree contains any sharing
|
||||
providers of inventory of the specified resource_class.
|
||||
"""
|
||||
for rp_uuid in self.get_provider_uuids():
|
||||
pdata = self.data(rp_uuid)
|
||||
has_rc = resource_class in pdata.inventory
|
||||
is_sharing = os_traits.MISC_SHARES_VIA_AGGREGATE in pdata.traits
|
||||
if has_rc and is_sharing:
|
||||
return True
|
||||
return False
|
||||
|
||||
def has_traits(self, name_or_uuid, traits):
|
||||
"""Given a name or UUID of a provider, query whether that provider has
|
||||
*all* of the specified traits.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
query for traits.
|
||||
:param traits: Iterable of string trait names to search for.
|
||||
:return: True if this provider has *all* of the specified traits; False
|
||||
if any of the specified traits are absent. Returns True if
|
||||
the traits parameter is empty, even if the provider has no
|
||||
traits.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.has_traits(traits)
|
||||
|
||||
def have_traits_changed(self, name_or_uuid, traits):
|
||||
"""Returns True if the specified traits list is different for the
|
||||
provider with the specified name or UUID.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
query traits for.
|
||||
:param traits: Iterable of string trait names to compare against the
|
||||
provider's traits.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.have_traits_changed(traits)
|
||||
|
||||
def update_traits(self, name_or_uuid, traits, generation=None):
|
||||
"""Given a name or UUID of a provider and an iterable of string trait
|
||||
names, update the provider's traits and set the provider's generation.
|
||||
|
||||
:returns: True if the traits list has changed.
|
||||
|
||||
:note: The provider's generation is always set to the supplied
|
||||
generation, even if there were no changes to the traits.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
update traits for.
|
||||
:param traits: Iterable of string trait names to set.
|
||||
:param generation: The resource provider generation to set. If None,
|
||||
the provider's generation is not changed.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.update_traits(traits, generation=generation)
|
||||
|
||||
def add_traits(self, name_or_uuid, *traits):
|
||||
"""Set traits on a provider, without affecting existing traits.
|
||||
|
||||
:param name_or_uuid: The name or UUID of the provider whose traits are
|
||||
to be affected.
|
||||
:param traits: String names of traits to be added.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
final_traits = provider.traits | set(traits)
|
||||
provider.update_traits(final_traits)
|
||||
|
||||
def remove_traits(self, name_or_uuid, *traits):
|
||||
"""Unset traits on a provider, without affecting other existing traits.
|
||||
|
||||
:param name_or_uuid: The name or UUID of the provider whose traits are
|
||||
to be affected.
|
||||
:param traits: String names of traits to be removed.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
final_traits = provider.traits - set(traits)
|
||||
provider.update_traits(final_traits)
|
||||
|
||||
def in_aggregates(self, name_or_uuid, aggregates):
|
||||
"""Given a name or UUID of a provider, query whether that provider is a
|
||||
member of *all* the specified aggregates.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
query for aggregates.
|
||||
:param aggregates: Iterable of string aggregate UUIDs to search for.
|
||||
:return: True if this provider is associated with *all* of the
|
||||
specified aggregates; False if any of the specified aggregates
|
||||
are absent. Returns True if the aggregates parameter is
|
||||
empty, even if the provider has no aggregate associations.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.in_aggregates(aggregates)
|
||||
|
||||
def have_aggregates_changed(self, name_or_uuid, aggregates):
|
||||
"""Returns True if the specified aggregates list is different for the
|
||||
provider with the specified name or UUID.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
query aggregates for.
|
||||
:param aggregates: Iterable of string aggregate UUIDs to compare
|
||||
against the provider's aggregates.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.have_aggregates_changed(aggregates)
|
||||
|
||||
def update_aggregates(self, name_or_uuid, aggregates, generation=None):
|
||||
"""Given a name or UUID of a provider and an iterable of string
|
||||
aggregate UUIDs, update the provider's aggregates and set the
|
||||
provider's generation.
|
||||
|
||||
:returns: True if the aggregates list has changed.
|
||||
|
||||
:note: The provider's generation is always set to the supplied
|
||||
generation, even if there were no changes to the aggregates.
|
||||
|
||||
:raises: ValueError if a provider with name_or_uuid was not found in
|
||||
the tree.
|
||||
:param name_or_uuid: Either name or UUID of the resource provider to
|
||||
update aggregates for.
|
||||
:param aggregates: Iterable of string aggregate UUIDs to set.
|
||||
:param generation: The resource provider generation to set. If None,
|
||||
the provider's generation is not changed.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
return provider.update_aggregates(aggregates,
|
||||
generation=generation)
|
||||
|
||||
def add_aggregates(self, name_or_uuid, *aggregates):
|
||||
"""Set aggregates on a provider, without affecting existing aggregates.
|
||||
|
||||
:param name_or_uuid: The name or UUID of the provider whose aggregates
|
||||
are to be affected.
|
||||
:param aggregates: String UUIDs of aggregates to be added.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
final_aggs = provider.aggregates | set(aggregates)
|
||||
provider.update_aggregates(final_aggs)
|
||||
|
||||
def remove_aggregates(self, name_or_uuid, *aggregates):
|
||||
"""Unset aggregates on a provider, without affecting other existing
|
||||
aggregates.
|
||||
|
||||
:param name_or_uuid: The name or UUID of the provider whose aggregates
|
||||
are to be affected.
|
||||
:param aggregates: String UUIDs of aggregates to be removed.
|
||||
"""
|
||||
with self.lock:
|
||||
provider = self._find_with_lock(name_or_uuid)
|
||||
final_aggs = provider.aggregates - set(aggregates)
|
||||
provider.update_aggregates(final_aggs)
|
70
cyborg/agent/rc_fields.py
Normal file
70
cyborg/agent/rc_fields.py
Normal file
@ -0,0 +1,70 @@
|
||||
#
|
||||
# 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.
|
||||
"""Standard Resource Class Fields."""
|
||||
|
||||
# NOTE(cdent): This is kept as its own independent file as it is used by
|
||||
# both the placement and nova sides of the placement interaction. On the
|
||||
# placement side we don't want to import all the nova fields, nor all the
|
||||
# nova objects (which are automatically loaded and registered if the
|
||||
# nova.objects package is imported).
|
||||
|
||||
import re
|
||||
|
||||
from oslo_versionedobjects import fields
|
||||
|
||||
|
||||
class ResourceClass(fields.StringField):
|
||||
"""Classes of resources provided to consumers."""
|
||||
|
||||
CUSTOM_NAMESPACE = 'CUSTOM_'
|
||||
"""All non-standard resource classes must begin with this string."""
|
||||
|
||||
VCPU = 'VCPU'
|
||||
MEMORY_MB = 'MEMORY_MB'
|
||||
DISK_GB = 'DISK_GB'
|
||||
PCI_DEVICE = 'PCI_DEVICE'
|
||||
SRIOV_NET_VF = 'SRIOV_NET_VF'
|
||||
NUMA_SOCKET = 'NUMA_SOCKET'
|
||||
NUMA_CORE = 'NUMA_CORE'
|
||||
NUMA_THREAD = 'NUMA_THREAD'
|
||||
NUMA_MEMORY_MB = 'NUMA_MEMORY_MB'
|
||||
IPV4_ADDRESS = 'IPV4_ADDRESS'
|
||||
VGPU = 'VGPU'
|
||||
VGPU_DISPLAY_HEAD = 'VGPU_DISPLAY_HEAD'
|
||||
|
||||
# The ordering here is relevant. If you must add a value, only
|
||||
# append.
|
||||
STANDARD = (VCPU, MEMORY_MB, DISK_GB, PCI_DEVICE, SRIOV_NET_VF,
|
||||
NUMA_SOCKET, NUMA_CORE, NUMA_THREAD, NUMA_MEMORY_MB,
|
||||
IPV4_ADDRESS, VGPU, VGPU_DISPLAY_HEAD)
|
||||
|
||||
# This is the set of standard resource classes that existed before
|
||||
# we opened up for custom resource classes in version 1.1 of various
|
||||
# objects in nova/objects/resource_provider.py
|
||||
V1_0 = (VCPU, MEMORY_MB, DISK_GB, PCI_DEVICE, SRIOV_NET_VF, NUMA_SOCKET,
|
||||
NUMA_CORE, NUMA_THREAD, NUMA_MEMORY_MB, IPV4_ADDRESS)
|
||||
|
||||
@classmethod
|
||||
def normalize_name(cls, rc_name):
|
||||
if rc_name is None:
|
||||
return None
|
||||
# Replace non-alphanumeric characters with underscores
|
||||
norm_name = re.sub('[^0-9A-Za-z]+', '_', rc_name)
|
||||
# Bug #1762789: Do .upper after replacing non alphanumerics.
|
||||
norm_name = norm_name.upper()
|
||||
norm_name = cls.CUSTOM_NAMESPACE + norm_name
|
||||
return norm_name
|
||||
|
||||
|
||||
class ResourceClassField(fields.AutoTypedField):
|
||||
AUTO_TYPE = ResourceClass()
|
@ -139,6 +139,15 @@ class NotFound(CyborgException):
|
||||
code = http_client.NOT_FOUND
|
||||
|
||||
|
||||
class ServiceNotFound(NotFound):
|
||||
msg_fmt = _("Service %(service_id)s could not be found.")
|
||||
|
||||
|
||||
class ConfGroupForServiceTypeNotFound(ServiceNotFound):
|
||||
msg_fmt = _("No conf group name could be found for service type "
|
||||
"%(stype)s.")
|
||||
|
||||
|
||||
class AcceleratorNotFound(NotFound):
|
||||
_msg_fmt = _("Accelerator %(uuid)s could not be found.")
|
||||
|
||||
@ -196,3 +205,87 @@ class AttributeInvalid(CyborgException):
|
||||
|
||||
class AttributeAlreadyExists(CyborgException):
|
||||
_msg_fmt = _("Attribute with uuid %(uuid)s already exists.")
|
||||
|
||||
|
||||
# An exception with this name is used on both sides of the placement/
|
||||
# cyborg interaction.
|
||||
class ResourceProviderInUse(CyborgException):
|
||||
msg_fmt = _("Resource provider has allocations.")
|
||||
|
||||
|
||||
class ResourceProviderRetrievalFailed(CyborgException):
|
||||
msg_fmt = _("Failed to get resource provider with UUID %(uuid)s")
|
||||
|
||||
|
||||
class ResourceProviderAggregateRetrievalFailed(CyborgException):
|
||||
msg_fmt = _("Failed to get aggregates for resource provider with UUID"
|
||||
" %(uuid)s")
|
||||
|
||||
|
||||
class ResourceProviderTraitRetrievalFailed(CyborgException):
|
||||
msg_fmt = _("Failed to get traits for resource provider with UUID"
|
||||
" %(uuid)s")
|
||||
|
||||
|
||||
class ResourceProviderCreationFailed(CyborgException):
|
||||
msg_fmt = _("Failed to create resource provider %(name)s")
|
||||
|
||||
|
||||
class ResourceProviderDeletionFailed(CyborgException):
|
||||
msg_fmt = _("Failed to delete resource provider %(uuid)s")
|
||||
|
||||
|
||||
class ResourceProviderUpdateFailed(CyborgException):
|
||||
msg_fmt = _("Failed to update resource provider via URL %(url)s: "
|
||||
"%(error)s")
|
||||
|
||||
|
||||
class ResourceProviderNotFound(NotFound):
|
||||
msg_fmt = _("No such resource provider %(name_or_uuid)s.")
|
||||
|
||||
|
||||
class ResourceProviderSyncFailed(CyborgException):
|
||||
msg_fmt = _("Failed to synchronize the placement service with resource "
|
||||
"provider information supplied by the compute host.")
|
||||
|
||||
|
||||
class PlacementAPIConnectFailure(CyborgException):
|
||||
msg_fmt = _("Unable to communicate with the Placement API.")
|
||||
|
||||
|
||||
class PlacementAPIConflict(CyborgException):
|
||||
"""Any 409 error from placement APIs should use (a subclass of) this
|
||||
exception.
|
||||
"""
|
||||
msg_fmt = _("A conflict was encountered attempting to invoke the "
|
||||
"placement API at URL %(url)s: %(error)s")
|
||||
|
||||
|
||||
class ResourceProviderUpdateConflict(PlacementAPIConflict):
|
||||
"""A 409 caused by generation mismatch from attempting to update an
|
||||
existing provider record or its associated data (aggregates, traits, etc.).
|
||||
"""
|
||||
msg_fmt = _("A conflict was encountered attempting to update resource "
|
||||
"provider %(uuid)s (generation %(generation)d): %(error)s")
|
||||
|
||||
|
||||
class InvalidResourceClass(Invalid):
|
||||
msg_fmt = _("Resource class '%(resource_class)s' invalid.")
|
||||
|
||||
|
||||
class InvalidResourceAmount(Invalid):
|
||||
msg_fmt = _("Resource amounts must be integers. Received '%(amount)s'.")
|
||||
|
||||
|
||||
class InvalidInventory(Invalid):
|
||||
msg_fmt = _("Inventory for '%(resource_class)s' on "
|
||||
"resource provider '%(resource_provider)s' invalid.")
|
||||
|
||||
|
||||
# An exception with this name is used on both sides of the placement/
|
||||
# cyborg interaction.
|
||||
class InventoryInUse(InvalidInventory):
|
||||
# NOTE(mriedem): This message cannot change without impacting the
|
||||
# cyborg.services.client.report._RE_INV_IN_USE regex.
|
||||
msg_fmt = _("Inventory for '%(resource_classes)s' on "
|
||||
"resource provider '%(resource_provider)s' in use.")
|
||||
|
@ -15,15 +15,23 @@
|
||||
|
||||
"""Utilities and helper functions."""
|
||||
|
||||
from oslo_log import log
|
||||
from oslo_concurrency import lockutils
|
||||
import six
|
||||
|
||||
from keystoneauth1 import loading as ks_loading
|
||||
from os_service_types import service_types
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_log import log
|
||||
|
||||
from cyborg.common import exception
|
||||
import cyborg.conf
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
synchronized = lockutils.synchronized_with_prefix('cyborg-')
|
||||
_SERVICE_TYPES = service_types.ServiceTypes()
|
||||
CONF = cyborg.conf.CONF
|
||||
|
||||
|
||||
def safe_rstrip(value, chars=None):
|
||||
@ -41,3 +49,62 @@ def safe_rstrip(value, chars=None):
|
||||
return value
|
||||
|
||||
return value.rstrip(chars) or value
|
||||
|
||||
|
||||
def get_ksa_adapter(service_type, ksa_auth=None, ksa_session=None,
|
||||
min_version=None, max_version=None):
|
||||
"""Construct a keystoneauth1 Adapter for a given service type.
|
||||
|
||||
We expect to find a conf group whose name corresponds to the service_type's
|
||||
project according to the service-types-authority. That conf group must
|
||||
provide at least ksa adapter options. Depending how the result is to be
|
||||
used, ksa auth and/or session options may also be required, or the relevant
|
||||
parameter supplied.
|
||||
|
||||
:param service_type: String name of the service type for which the Adapter
|
||||
is to be constructed.
|
||||
:param ksa_auth: A keystoneauth1 auth plugin. If not specified, we attempt
|
||||
to find one in ksa_session. Failing that, we attempt to
|
||||
load one from the conf.
|
||||
:param ksa_session: A keystoneauth1 Session. If not specified, we attempt
|
||||
to load one from the conf.
|
||||
:param min_version: The minimum major version of the adapter's endpoint,
|
||||
intended to be used as the lower bound of a range with
|
||||
max_version.
|
||||
If min_version is given with no max_version it is as
|
||||
if max version is 'latest'.
|
||||
:param max_version: The maximum major version of the adapter's endpoint,
|
||||
intended to be used as the upper bound of a range with
|
||||
min_version.
|
||||
:return: A keystoneauth1 Adapter object for the specified service_type.
|
||||
:raise: ConfGroupForServiceTypeNotFound If no conf group name could be
|
||||
found for the specified service_type.
|
||||
"""
|
||||
# Get the conf group corresponding to the service type.
|
||||
confgrp = _SERVICE_TYPES.get_project_name(service_type)
|
||||
if not confgrp or not hasattr(CONF, confgrp):
|
||||
# Try the service type as the conf group. This is necessary for e.g.
|
||||
# placement, while it's still part of the nova project.
|
||||
# Note that this might become the first thing we try if/as we move to
|
||||
# using service types for conf group names in general.
|
||||
confgrp = service_type
|
||||
if not confgrp or not hasattr(CONF, confgrp):
|
||||
raise exception.ConfGroupForServiceTypeNotFound(stype=service_type)
|
||||
|
||||
# Ensure we have an auth.
|
||||
# NOTE(efried): This could be None, and that could be okay - e.g. if the
|
||||
# result is being used for get_endpoint() and the conf only contains
|
||||
# endpoint_override.
|
||||
if not ksa_auth:
|
||||
if ksa_session and ksa_session.auth:
|
||||
ksa_auth = ksa_session.auth
|
||||
else:
|
||||
ksa_auth = ks_loading.load_auth_from_conf_options(CONF, confgrp)
|
||||
|
||||
if not ksa_session:
|
||||
ksa_session = ks_loading.load_session_from_conf_options(
|
||||
CONF, confgrp, auth=ksa_auth)
|
||||
|
||||
return ks_loading.load_adapter_from_conf_options(
|
||||
CONF, confgrp, session=ksa_session, auth=ksa_auth,
|
||||
min_version=min_version, max_version=max_version)
|
||||
|
@ -13,13 +13,16 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Cyborg Default Config Setting"""
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
||||
from oslo_config import cfg
|
||||
from keystoneauth1 import loading as k_loading
|
||||
from oslo_config import cfg
|
||||
|
||||
from cyborg.common.i18n import _
|
||||
from cyborg.conf import utils as confutils
|
||||
|
||||
|
||||
exc_log_opts = [
|
||||
@ -63,17 +66,30 @@ path_opts = [
|
||||
]
|
||||
|
||||
PLACEMENT_CONF_SECTION = 'placement'
|
||||
DEFAULT_SERVICE_TYPE = 'placement'
|
||||
|
||||
placement_group = cfg.OptGroup(
|
||||
PLACEMENT_CONF_SECTION,
|
||||
title='Placement Service Options',
|
||||
help="Configuration options for connecting to the placement API service")
|
||||
|
||||
placement_opts = [
|
||||
cfg.StrOpt('region_name',
|
||||
help=_('Name of placement region to use. Useful if keystone '
|
||||
'manages more than one region.')),
|
||||
cfg.StrOpt('endpoint_type',
|
||||
default='public',
|
||||
choices=['public', 'admin', 'internal'],
|
||||
help=_('Type of the placement endpoint to use. This endpoint '
|
||||
'will be looked up in the keystone catalog and should '
|
||||
'be one of public, internal or admin.')),
|
||||
cfg.BoolOpt(
|
||||
'randomize_allocation_candidates',
|
||||
default=False,
|
||||
help=_('If True, when limiting allocation candidate results, the '
|
||||
'results will be a random sampling of the full result set. '
|
||||
'If False, allocation candidates are returned in a '
|
||||
'deterministic but undefined order. That is, all things '
|
||||
'being equal, two requests for allocation candidates will '
|
||||
'return the same results in the same order; but no guarantees '
|
||||
'are made as to how that order is determined.')),
|
||||
]
|
||||
|
||||
|
||||
@ -84,9 +100,9 @@ def register_opts(conf):
|
||||
|
||||
|
||||
def register_placement_opts(cfg=cfg.CONF):
|
||||
cfg.register_opts(k_loading.get_session_conf_options(),
|
||||
group=PLACEMENT_CONF_SECTION)
|
||||
cfg.register_group(placement_group)
|
||||
cfg.register_opts(placement_opts, group=PLACEMENT_CONF_SECTION)
|
||||
confutils.register_ksa_opts(cfg, placement_group, DEFAULT_SERVICE_TYPE)
|
||||
|
||||
|
||||
DEFAULT_OPTS = (exc_log_opts + service_opts + path_opts)
|
||||
@ -95,5 +111,13 @@ PLACEMENT_OPTS = (placement_opts)
|
||||
|
||||
def list_opts():
|
||||
return {
|
||||
PLACEMENT_CONF_SECTION: PLACEMENT_OPTS, 'DEFAULT': DEFAULT_OPTS
|
||||
PLACEMENT_CONF_SECTION: (
|
||||
placement_opts +
|
||||
k_loading.get_session_conf_options() +
|
||||
k_loading.get_auth_common_conf_options() +
|
||||
k_loading.get_auth_plugin_conf_options('password') +
|
||||
k_loading.get_auth_plugin_conf_options('v2password') +
|
||||
k_loading.get_auth_plugin_conf_options('v3password') +
|
||||
confutils.get_ksa_adapter_opts(DEFAULT_SERVICE_TYPE)),
|
||||
'DEFAULT': DEFAULT_OPTS
|
||||
}
|
||||
|
91
cyborg/conf/utils.py
Normal file
91
cyborg/conf/utils.py
Normal file
@ -0,0 +1,91 @@
|
||||
# Copyright 2017 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
"""Common utilities for conf providers.
|
||||
|
||||
This module does not provide any actual conf options.
|
||||
"""
|
||||
from keystoneauth1 import loading as ks_loading
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
_ADAPTER_VERSION_OPTS = ('version', 'min_version', 'max_version')
|
||||
|
||||
|
||||
def get_ksa_adapter_opts(default_service_type, deprecated_opts=None):
|
||||
"""Get auth, Session, and Adapter conf options from keystonauth1.loading.
|
||||
|
||||
:param default_service_type: Default for the service_type conf option on
|
||||
the Adapter.
|
||||
:param deprecated_opts: dict of deprecated opts to register with the ksa
|
||||
Adapter opts. Works the same as the
|
||||
deprecated_opts kwarg to:
|
||||
keystoneauth1.loading.session.Session.register_conf_options
|
||||
:return: List of cfg.Opts.
|
||||
"""
|
||||
opts = ks_loading.get_adapter_conf_options(include_deprecated=False,
|
||||
deprecated_opts=deprecated_opts)
|
||||
|
||||
for opt in opts[:]:
|
||||
# Remove version-related opts. Required/supported versions are
|
||||
# something the code knows about, not the operator.
|
||||
if opt.dest in _ADAPTER_VERSION_OPTS:
|
||||
opts.remove(opt)
|
||||
|
||||
# Override defaults that make sense for nova
|
||||
cfg.set_defaults(opts,
|
||||
valid_interfaces=['internal', 'public'],
|
||||
service_type=default_service_type)
|
||||
return opts
|
||||
|
||||
|
||||
def _dummy_opt(name):
|
||||
# A config option that can't be set by the user, so it behaves as if it's
|
||||
# ignored; but consuming code may expect it to be present in a conf group.
|
||||
return cfg.Opt(name, type=lambda x: None)
|
||||
|
||||
|
||||
def register_ksa_opts(conf, group, default_service_type, include_auth=True,
|
||||
deprecated_opts=None):
|
||||
"""Register keystoneauth auth, Session, and Adapter opts.
|
||||
|
||||
:param conf: oslo_config.cfg.CONF in which to register the options
|
||||
:param group: Conf group, or string name thereof, in which to register the
|
||||
options.
|
||||
:param default_service_type: Default for the service_type conf option on
|
||||
the Adapter.
|
||||
:param include_auth: For service types where Nova is acting on behalf of
|
||||
the user, auth should come from the user context.
|
||||
In those cases, set this arg to False to avoid
|
||||
registering ksa auth options.
|
||||
:param deprecated_opts: dict of deprecated opts to register with the ksa
|
||||
Session or Adapter opts. See docstring for
|
||||
the deprecated_opts param of:
|
||||
keystoneauth1.loading.session.Session.register_conf_options
|
||||
"""
|
||||
# ksa register methods need the group name as a string. oslo doesn't care.
|
||||
group = getattr(group, 'name', group)
|
||||
ks_loading.register_session_conf_options(
|
||||
conf, group, deprecated_opts=deprecated_opts)
|
||||
if include_auth:
|
||||
ks_loading.register_auth_conf_options(conf, group)
|
||||
conf.register_opts(get_ksa_adapter_opts(
|
||||
default_service_type, deprecated_opts=deprecated_opts), group=group)
|
||||
# Have to register dummies for the version-related opts we removed
|
||||
for name in _ADAPTER_VERSION_OPTS:
|
||||
conf.register_opt(_dummy_opt(name), group=group)
|
||||
|
||||
|
||||
# NOTE(efried): Required for docs build.
|
||||
def list_opts():
|
||||
return {}
|
15
cyborg/services/client/__init__.py
Normal file
15
cyborg/services/client/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2018 Intel, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Client for call other project API."""
|
1997
cyborg/services/client/report.py
Normal file
1997
cyborg/services/client/report.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -162,6 +162,26 @@ function configure_auth_for {
|
||||
iniset $CYBORG_CONF_FILE $service_config_section cafile $SSL_BUNDLE_FILE
|
||||
}
|
||||
|
||||
function configure_cyborg_placement {
|
||||
# Use the provided config file path or default to $CYBORG_CONF.
|
||||
local section=${1:-placement}
|
||||
local auth_section=${2:-keystone_authtoken}
|
||||
iniset $CYBORG_CONF_FILE $section auth_section $auth_section
|
||||
iniset $CYBORG_CONF_FILE $section auth_type "password"
|
||||
iniset $CYBORG_CONF_FILE $section auth_url "$KEYSTONE_SERVICE_URI"
|
||||
iniset $CYBORG_CONF_FILE $section username $section
|
||||
iniset $CYBORG_CONF_FILE $section password "$SERVICE_PASSWORD"
|
||||
iniset $CYBORG_CONF_FILE $section user_domain_name "$SERVICE_DOMAIN_NAME"
|
||||
iniset $CYBORG_CONF_FILE $section project_name "$SERVICE_TENANT_NAME"
|
||||
iniset $CYBORG_CONF_FILE $section project_domain_name "$SERVICE_DOMAIN_NAME"
|
||||
# TODO(cdent): auth_strategy, which is common to see in these
|
||||
# blocks is not currently used here. For the time being the
|
||||
# placement api uses the auth_strategy configuration setting
|
||||
# established by the nova api. This avoids, for the time, being,
|
||||
# creating redundant configuration items that are just used for
|
||||
# testing.
|
||||
}
|
||||
|
||||
# configure_cyborg_conductor() - Is used by configure_cyborg().
|
||||
# Sets conductor specific settings.
|
||||
function configure_cyborg_conductor {
|
||||
@ -171,6 +191,7 @@ function configure_cyborg_conductor {
|
||||
|
||||
# this one is needed for lookup of Cyborg API endpoint via Keystone
|
||||
configure_auth_for service_catalog
|
||||
configure_cyborg_placement
|
||||
|
||||
sudo cp $CYBORG_DIR/etc/cyborg/rootwrap.conf $CYBORG_ROOTWRAP_CONF
|
||||
sudo cp -r $CYBORG_DIR/etc/cyborg/rootwrap.d $CYBORG_CONF_DIR
|
||||
|
Loading…
Reference in New Issue
Block a user