Skip to content

vmware: Expose external customer traits #543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: stable/2023.2-m3
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nova/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
BIGVM_EXCLUSIVE_TRAIT = 'CUSTOM_HANA_EXCLUSIVE_HOST'

EXTERNAL_CUSTOMER_SUPPORTED_TRAIT = 'CUSTOM_EXTERNAL_CUSTOMER_SUPPORTED'
EXTERNAL_CUSTOMER_DOMAIN_TRAIT = 'CUSTOM_EXTERNAL_CUSTOMER_{}'

_FILE_CACHE = {}

Expand Down
34 changes: 34 additions & 0 deletions nova/virt/vmwareapi/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,40 @@ def update_provider_tree(self, provider_tree, nodename, allocations=None):
# where cpu traits are added. In the vmware world, this is where we
# would add nested providers representing tenant VDC and similar.

self._update_provider_tree_for_external_customers(
provider_tree, nodename, stats['hostgroups'])

def _update_provider_tree_for_external_customers(self, provider_tree,
nodename, hostgroups):
existing_traits = {
t for t in provider_tree.data(nodename).traits
if t.startswith(tuple(
utils.EXTERNAL_CUSTOMER_DOMAIN_TRAIT.format(
prefix.upper().removesuffix('-').replace('-', '_'))
for prefix in CONF.external_customer_domain_name_prefixes)) or
t == utils.EXTERNAL_CUSTOMER_SUPPORTED_TRAIT}

wanted_traits = set()
# we can have generic host groups and special ones per domain
for prefix in CONF.external_customer_domain_name_prefixes:
hg_prefix = prefix.removesuffix('-')

for hg_name in hostgroups:
if not hg_name.startswith(hg_prefix):
continue

trait = utils.EXTERNAL_CUSTOMER_DOMAIN_TRAIT.format(
hg_name.upper().replace('-', '_'))
wanted_traits.add(trait)

if wanted_traits:
wanted_traits.add(utils.EXTERNAL_CUSTOMER_SUPPORTED_TRAIT)

traits_to_add = wanted_traits - existing_traits
provider_tree.add_traits(nodename, *traits_to_add)
traits_to_remove = existing_traits - wanted_traits
provider_tree.remove_traits(nodename, *traits_to_remove)

def prepare_for_spawn(self, instance):
"""Perform pre-checks for spawn."""
self._vmops.prepare_for_spawn(instance)
Expand Down
22 changes: 22 additions & 0 deletions nova/virt/vmwareapi/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@
from oslo_utils import units
from oslo_utils import versionutils
from oslo_vmware import exceptions as vexc
from oslo_vmware import vim_util as vutil

import nova.conf
from nova import context
from nova import exception
from nova import objects
from nova.objects import fields as obj_fields
from nova.virt.vmwareapi import cluster_util
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
Expand Down Expand Up @@ -98,6 +100,9 @@ def update_status(self):
# Get cpu, memory stats from the cluster
per_host_stats = vm_util.get_stats_from_cluster_per_host(
self._session, self._cluster)

cluster_hostgroups = cluster_util.fetch_cluster_groups(
self._session, self._cluster, group_type="host")
except (vexc.VimConnectionException, vexc.VimAttributeException) as ex:
# VimAttributeException is thrown when vpxd service is down
LOG.warning("Failed to connect with %(node)s. "
Expand Down Expand Up @@ -133,11 +138,28 @@ def update_status(self):
data[self._cluster_node_name] = self._merge_stats(
self._cluster_node_name, cluster_stats, defaults)

data[self._cluster_node_name]['hostgroups'] = {}
for hg in cluster_hostgroups.values():
# ignore empty hostgroups
if not getattr(hg, 'host', None):
continue

data[self._cluster_node_name]['hostgroups'][hg.name] = [
vutil.get_moref_value(h_ref) for h_ref in hg.host]
for h_ref in hg.host:
host_ref_value = vutil.get_moref_value(h_ref)
h_name = per_host_stats[host_ref_value]["name"]
data[h_name].setdefault('hostgroups', []).append(hg.name)

self._stats = data
if self._auto_service_disabled:
self._set_host_enabled(True)
return data

@property
def hostgroups(self):
return self._stats[self._cluster_node_name].get('hostgroups', {})

def _merge_stats(self, host, stats, defaults):
result = deepcopy(defaults)
result["hypervisor_hostname"] = host
Expand Down