diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 56b26f8118..197ab938e9 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -907,6 +907,7 @@ SERVICE_TYPE_GLANCE = 'glance' SERVICE_TYPE_BARBICAN = 'barbican' SERVICE_TYPE_DOCKER = 'docker' SERVICE_TYPE_HTTP = 'http' +SERVICE_TYPE_OPENSTACK = 'openstack' SERVICE_PARAM_SECTION_MURANO_RABBITMQ = 'rabbitmq' SERVICE_PARAM_SECTION_MURANO_ENGINE = 'engine' @@ -1124,6 +1125,10 @@ SERVICE_PARAM_HTTP_PORT_HTTPS = 'https_port' SERVICE_PARAM_HTTP_PORT_HTTP_DEFAULT = 8080 SERVICE_PARAM_HTTP_PORT_HTTPS_DEFAULT = 8443 +# Openstack Service Parameters +SERVICE_PARAM_SECTION_OPENSTACK_HELM = 'helm' +SERVICE_PARAM_NAME_ENDPOINT_DOMAIN = "endpoint_domain" + # TIS part number, CPE = combined load, STD = standard load TIS_STD_BUILD = 'Standard' TIS_AIO_BUILD = 'All-in-one' diff --git a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py index 0312e90e15..6344bf34ae 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py +++ b/sysinv/sysinv/sysinv/sysinv/common/service_parameter.py @@ -687,6 +687,14 @@ def _validate_docker_insecure_registry_bool(name, value): "Parameter '%s' must be a valid bool string." % name)) +def _validate_domain(name, value): + """Check if domain name is valid""" + if not cutils.is_valid_domain_name(value): + raise wsme.exc.ClientSideError(_( + "Parameter '%s' includes an invalid domain name '%s'." % + (name, value))) + + # LDAP Identity Service Parameters (mandatory) SERVICE_PARAM_IDENTITY_LDAP_URL = 'url' @@ -1582,6 +1590,17 @@ HTTPD_PORT_PARAMETER_RESOURCE = { 'openstack::horizon::params::https_port', } +OPENSTACK_HELM_PARAMETER_OPTIONAL = [ + constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN, +] +OPENSTACK_HELM_PARAMETER_VALIDATOR = { + constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN: _validate_domain, +} +OPENSTACK_HELM_PARAMETER_RESOURCE = { + constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN: + 'openstack::helm::params::endpoint_domain', +} + # Service Parameter Schema SERVICE_PARAM_MANDATORY = 'mandatory' SERVICE_PARAM_OPTIONAL = 'optional' @@ -1777,6 +1796,13 @@ SERVICE_PARAMETER_SCHEMA = { SERVICE_PARAM_RESOURCE: HTTPD_PORT_PARAMETER_RESOURCE, }, }, + constants.SERVICE_TYPE_OPENSTACK: { + constants.SERVICE_PARAM_SECTION_OPENSTACK_HELM: { + SERVICE_PARAM_OPTIONAL: OPENSTACK_HELM_PARAMETER_OPTIONAL, + SERVICE_PARAM_VALIDATOR: OPENSTACK_HELM_PARAMETER_VALIDATOR, + SERVICE_PARAM_RESOURCE: OPENSTACK_HELM_PARAMETER_RESOURCE, + }, + }, } SERVICE_PARAMETER_MAX_LENGTH = 255 diff --git a/sysinv/sysinv/sysinv/sysinv/common/utils.py b/sysinv/sysinv/sysinv/sysinv/common/utils.py index 12d2be41c3..8266eb6fbd 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/common/utils.py @@ -1855,6 +1855,19 @@ def is_valid_domain_or_ip(url_str): else: # check ipv6 without port return is_valid_ipv6(url_str) + + +def is_valid_domain_name(value): + """ Validate domain name based on RFC specs including IDN """ + p = re.compile( + r'^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|' + r'([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|' + r'([a-zA-Z0-9][-_.a-zA-Z0-9]{0,61}[a-zA-Z0-9]))\.' + r'([a-zA-Z]{2,13}|[a-zA-Z0-9-]{2,30}.[a-zA-Z]{2,3})$' + ) + m = p.match(value) + if m: + return True else: return False diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index 03b8548fa2..bfce9b634f 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -7102,7 +7102,9 @@ class ConductorManager(service.PeriodicService): [constants.CONTROLLER, constants.WORKER, constants.STORAGE]) - + elif service == constants.SERVICE_TYPE_OPENSTACK: + # Do nothing. Does not need to update target config of any hosts + pass else: # All other services personalities = [constants.CONTROLLER] diff --git a/sysinv/sysinv/sysinv/sysinv/helm/glance.py b/sysinv/sysinv/sysinv/sysinv/helm/glance.py index b3fc0d4392..301a9ddb06 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/glance.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/glance.py @@ -86,6 +86,11 @@ class GlanceHelm(openstack.OpenstackBaseHelm): def _get_endpoints_overrides(self): return { + 'image': { + 'host_fqdn_override': + self._get_endpoints_host_fqdn_overrides( + constants.HELM_CHART_GLANCE), + }, 'identity': { 'auth': self._get_endpoints_identity_overrides( self.SERVICE_NAME, self.AUTH_USERS), diff --git a/sysinv/sysinv/sysinv/sysinv/helm/horizon.py b/sysinv/sysinv/sysinv/sysinv/helm/horizon.py index e6f07f86f3..f7d3734b6e 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/horizon.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/horizon.py @@ -45,6 +45,11 @@ class HorizonHelm(openstack.OpenstackBaseHelm): def _get_endpoints_overrides(self): return { + 'dashboard': { + 'host_fqdn_override': + self._get_endpoints_host_fqdn_overrides( + constants.HELM_CHART_HORIZON), + }, 'oslo_db': { 'auth': self._get_endpoints_oslo_db_overrides( self.SERVICE_NAME, [self.SERVICE_NAME]) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/keystone.py b/sysinv/sysinv/sysinv/sysinv/helm/keystone.py index 56b430ceeb..9166f02ecd 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/keystone.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/keystone.py @@ -244,6 +244,9 @@ class KeystoneHelm(openstack.OpenstackBaseHelm): 'identity': { 'auth': self._get_endpoints_identity_overrides( self.SERVICE_NAME, []), + 'host_fqdn_override': + self._get_endpoints_host_fqdn_overrides( + self.SERVICE_NAME), }, 'oslo_cache': { 'auth': { diff --git a/sysinv/sysinv/sysinv/sysinv/helm/neutron.py b/sysinv/sysinv/sysinv/sysinv/helm/neutron.py index a256490f87..1f3973a59f 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/neutron.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/neutron.py @@ -384,6 +384,11 @@ class NeutronHelm(openstack.OpenstackBaseHelm): 'auth': self._get_endpoints_identity_overrides( self.SERVICE_NAME, self.AUTH_USERS), }, + 'network': { + 'host_fqdn_override': + self._get_endpoints_host_fqdn_overrides( + self.SERVICE_NAME), + }, 'oslo_cache': { 'auth': { 'memcached_secret_key': diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova.py b/sysinv/sysinv/sysinv/sysinv/helm/nova.py index d7875721f6..61f03e55a0 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova.py @@ -191,8 +191,17 @@ class NovaHelm(openstack.OpenstackBaseHelm): return overrides def _get_novncproxy_base_url(self): - oam_addr = self._get_oam_address(), - url = "http://%s:6080/vnc_auto.html" % oam_addr + # Get the openstack endpoint public domain name + endpoint_domain = self._get_service_parameter( + constants.SERVICE_TYPE_OPENSTACK, + constants.SERVICE_PARAM_SECTION_OPENSTACK_HELM, + constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN) + if endpoint_domain is not None: + location = "%s.%s" % (constants.HELM_CHART_HORIZON, + str(endpoint_domain.value).lower()) + else: + location = self._get_oam_address() + url = "http://%s:6080/vnc_auto.html" % location return url def _get_virt_type(self): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py b/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py index b3d3f067b5..7d8c67f5d1 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova_api_proxy.py @@ -71,5 +71,10 @@ class NovaApiProxyHelm(openstack.OpenstackBaseHelm): 'identity': { 'auth': self._get_endpoints_identity_overrides( nova_service_name, self.AUTH_USERS), - } + }, + 'compute': { + 'host_fqdn_override': + self._get_endpoints_host_fqdn_overrides( + constants.HELM_CHART_NOVA), + }, } diff --git a/sysinv/sysinv/sysinv/sysinv/helm/openstack.py b/sysinv/sysinv/sysinv/sysinv/helm/openstack.py index c5c8d52679..84cd64a7ed 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/openstack.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/openstack.py @@ -191,6 +191,18 @@ class OpenstackBaseHelm(base.BaseHelm): }) return overrides + def _get_endpoints_host_fqdn_overrides(self, service_name): + overrides = {'public': {}} + endpoint_domain = self._get_service_parameter( + constants.SERVICE_TYPE_OPENSTACK, + constants.SERVICE_PARAM_SECTION_OPENSTACK_HELM, + constants.SERVICE_PARAM_NAME_ENDPOINT_DOMAIN) + if endpoint_domain is not None: + overrides['public'].update({ + 'host': service_name + '.' + str(endpoint_domain.value).lower() + }) + return overrides + def _get_endpoints_oslo_db_overrides(self, service_name, users): overrides = { 'admin': {