# # Copyright (c) 2017 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # import collections import abc import itertools import netaddr import os import six from sqlalchemy.orm.exc import NoResultFound from sysinv.common import constants from sysinv.common import utils from sysinv.common import exception @six.add_metaclass(abc.ABCMeta) class BasePuppet(object): """Base class to encapsulate puppet operations for hiera configuration""" CONFIG_WORKDIR = '/tmp/config' DEFAULT_REGION_NAME = 'RegionOne' DEFAULT_SERVICE_PROJECT_NAME = 'services' SYSTEM_CONTROLLER_SERVICES = [ 'keystone', 'glance', 'nova', 'neutron', 'cinder', 'dcorch' ] def __init__(self, operator): self._operator = operator @property def dbapi(self): return self._operator.dbapi @property def context(self): return self._operator.context @staticmethod def _generate_random_password(length=16): suffix = "Ti0*" num = (length / 2) - len(suffix) / 2 return os.urandom(num).encode('hex') + suffix def _get_system(self): system = self.context.get('_system', None) if system is None: system = self.dbapi.isystem_get_one() self.context['_system'] = system return system def _sdn_enabled(self): if self.dbapi is None: return False system = self._get_system() return system.capabilities.get('sdn_enabled', False) def _https_enabled(self): if self.dbapi is None: return False system = self._get_system() return system.capabilities.get('https_enabled', False) def _region_config(self): if self.dbapi is None: return False system = self._get_system() return system.capabilities.get('region_config', False) def _distributed_cloud_role(self): if self.dbapi is None: return None system = self._get_system() return system.distributed_cloud_role def _region_name(self): """Returns the local region name of the system""" if self.dbapi is None: return self.DEFAULT_REGION_NAME system = self._get_system() return system.region_name def _get_service_project_name(self): if self.dbapi is None: return self.DEFAULT_SERVICE_PROJECT_NAME system = self._get_system() return system.service_project_name def _get_service(self, service_name): if self.dbapi is None: return None try: service = self.dbapi.service_get(service_name) except exception.ServiceNotFound: # service not configured return None return service def _get_shared_services(self): if self.dbapi is None: return [] system = self._get_system() return system.capabilities.get('shared_services', []) def _get_address_by_name(self, name, networktype): """ Retrieve an address entry by name and scoped by network type """ addresses = self.context.setdefault('_address_names', {}) address_name = utils.format_address_name(name, networktype) address = addresses.get(address_name) if address is None: address = self.dbapi.address_get_by_name(address_name) addresses[address_name] = address return address def _get_management_address(self): address = self._get_address_by_name( constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_MGMT) return address.address def _get_pxeboot_address(self): address = self._get_address_by_name( constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_PXEBOOT) return address.address def _get_oam_address(self): address = self._get_address_by_name( constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_OAM) return address.address def _get_host_cpu_list(self, host, function=None, threads=False): """ Retreive a list of CPUs for the host, filtered by function and thread siblings (if supplied) """ cpus = [] for c in self.dbapi.icpu_get_by_ihost(host.id): if c.thread != 0 and not threads: continue if c.allocated_function == function or not function: cpus.append(c) return cpus def _get_service_parameters(self, service=None): service_parameters = [] if self.dbapi is None: return service_parameters try: service_parameters = self.dbapi.service_parameter_get_all( service=service) # the service parameter has not been added except NoResultFound: pass return service_parameters @staticmethod def _service_parameter_lookup_one(service_parameters, section, name, default): for param in service_parameters: if param['section'] == section and param['name'] == name: return param['value'] return default def _format_service_parameter(self, service_parameters, section, group, name): parameter = {} key = group + name value = self._service_parameter_lookup_one(service_parameters, section, name, 'undef') if value != 'undef': parameter[key] = value return parameter @staticmethod def _format_url_address(address): """Format the URL address according to RFC 2732""" try: addr = netaddr.IPAddress(address) if addr.version == constants.IPV6_FAMILY: return "[%s]" % address else: return str(address) except netaddr.AddrFormatError: return address @staticmethod def _format_range_set(items): # Generate a pretty-printed value of ranges, such as 3-6,8-9,12-17 ranges = [] for k, iterable in itertools.groupby(enumerate(sorted(items)), lambda x: x[1] - x[0]): rng = list(iterable) if len(rng) == 1: s = str(rng[0][1]) else: s = "%s-%s" % (rng[0][1], rng[-1][1]) ranges.append(s) return ','.join(ranges) def _get_numa_index_list(self, obj): """Create map of objects indexed by numa node""" obj_lists = collections.defaultdict(list) for index, o in enumerate(obj): o["_index"] = index obj_lists[o.numa_node].append(o) return obj_lists