Configure VIM to use pod based OpenStack services

When kubernetes is configured and the OpenStack application has
been installed, the VIM will be configured to access the OpenStack
services running in pods (keystone, nova, rabbitmq, etc...).

In order to support this, some extensions were done to the sysinv
helm code to allow parts of the OpenStack application
configuration to be retrieved (e.g. endpoint info). Changes
were also required to dnsmasq configuration to get resolution of
pod based names (e.g. keystone.openstack.svc.cluster.local)
working properly.

This commit is just the first step and has limitations. There is
no trigger to reconfigure the VIM after the OpenStack application
has been installed - a controller lock/unlock is required.

Story: 2003910
Task: 27852

Change-Id: I1c6dcdecd1365104457009196bbcf06b19c95489
Signed-off-by: Bart Wensley <barton.wensley@windriver.com>
This commit is contained in:
Bart Wensley 2018-11-15 14:39:39 -06:00
parent d5a090a45f
commit 4a43480f6b
14 changed files with 386 additions and 59 deletions

View File

@ -35,11 +35,15 @@ class platform::nfv {
include ::nfv
include ::nfv::vim
class { '::nfv::nfvi':
rabbit_host => $::platform::amqp::params::host,
rabbit_port => $::platform::amqp::params::port,
rabbit_userid => $::platform::amqp::params::auth_user,
rabbit_password => $::platform::amqp::params::auth_password,
if !$::platform::kubernetes::params::enabled {
class { '::nfv::nfvi':
rabbit_host => $::platform::amqp::params::host,
rabbit_port => $::platform::amqp::params::port,
rabbit_userid => $::platform::amqp::params::auth_user,
rabbit_password => $::platform::amqp::params::auth_password,
}
} else {
include ::nfv::nfvi
}
}

View File

@ -104,6 +104,18 @@ dhcp-boot=tag:efi,tag:mgmt,EFI/grubx64.efi,<%= @mgmt_hostname %>,<%= @mgmt_contr
# Do not forward queries for plain names (no dots)
domain-needed
# Query the upstream servers in the order they appear. This is necessary when
# kubernetes is configured, to ensure we send queries for kubernetes names
# (ending in .cluster.local) to the kubernetes dns server first. In the future,
# we could add the kubernetes dns server using the "server" option, which would
# allow us to force all cluster.local names to go to that server.
strict-order
# Only keep entries in the cache for 5 seconds. This is required because the
# kubernetes dns server will reply to queries for services that do not yet
# exist with an SOA record containing a long TTL, which will result in dns
# queries failing for a very long time, even after the service comes up (e.g.
# after a host is rebooted).
max-cache-ttl=5
local=//
port=53
bogus-priv

View File

@ -22,7 +22,6 @@ class nfv::nfvi (
$openstack_auth_host = '127.0.0.1',
$openstack_auth_port = 5000,
$openstack_keyring_service = undef,
$openstack_nova_api_host = '127.0.0.1',
$keystone_region_name = 'RegionOne',
$keystone_service_name = 'keystone',
$keystone_service_type = 'identity',

View File

@ -57,6 +57,7 @@ from oslo_config import cfg
from sysinv.common import exception
from sysinv.common import constants
from sysinv.helm import common as helm_common
from sysinv.openstack.common import log as logging
from sysinv.openstack.common.gettextutils import _
from oslo_concurrency import lockutils
@ -1805,3 +1806,16 @@ def extract_tarfile(target_dir, tarfile):
except subprocess.CalledProcessError as e:
LOG.error("Error while extracting tarfile %s: %s" % (tarfile, e))
return False
def is_openstack_installed(dbapi):
""" Checks whether the OpenStack application is installed. """
# TODO(Bart): When the sysinv/armada integration is complete, this will
# be updated to check the status of the openstack application.
controller_0 = dbapi.ihost_get_by_hostname(constants.CONTROLLER_0_HOSTNAME)
labels = dbapi.label_get_all(hostid=controller_0.id)
for label in labels:
if label.label_key == helm_common.LABEL_CONTROLLER and \
label.label_value == helm_common.LABEL_VALUE_ENABLED:
return True
return False

View File

@ -160,3 +160,6 @@ class CeilometerHelm(openstack.OpenstackBaseHelm):
self.SERVICE_NAME, self.AUTH_USERS)
},
}
def get_region_name(self):
return self._get_service_region_name(self.SERVICE_NAME)

View File

@ -24,6 +24,7 @@ class CinderHelm(openstack.OpenstackBaseHelm):
]
SERVICE_NAME = 'cinder'
SERVICE_TYPE = 'volume'
AUTH_USERS = ['cinder']
@property
@ -237,3 +238,17 @@ class CinderHelm(openstack.OpenstackBaseHelm):
pass
return backend
def get_region_name(self):
return self._get_service_region_name(self.SERVICE_NAME)
def get_service_name_v2(self):
return self._get_configured_service_name(self.SERVICE_NAME, 'v2')
def get_service_type_v2(self):
service_type = self._get_configured_service_type(
self.SERVICE_NAME, 'v2')
if service_type is None:
return self.SERVICE_TYPE + 'v2'
else:
return service_type

View File

@ -42,6 +42,10 @@ LABEL_CONTROLLER = 'openstack-control-plane'
LABEL_COMPUTE_LABEL = 'openstack-compute-node'
LABEL_OPENVSWITCH = 'openvswitch'
# Label values
LABEL_VALUE_ENABLED = 'enabled'
LABEL_VALUE_DISABLED = 'disabled'
# Image Tagging
DOCKER_SRC_OSH = 'openstackhelm'
DOCKER_SRC_STX = 'starlingx'

View File

@ -26,6 +26,7 @@ class GlanceHelm(openstack.OpenstackBaseHelm):
]
SERVICE_NAME = 'glance'
SERVICE_TYPE = 'image'
AUTH_USERS = ['glance']
@property
@ -161,3 +162,16 @@ class GlanceHelm(openstack.OpenstackBaseHelm):
pass
return backend
def get_region_name(self):
return self._get_service_region_name(self.SERVICE_NAME)
def get_service_name(self):
return self._get_configured_service_name(self.SERVICE_NAME)
def get_service_type(self):
service_type = self._get_configured_service_type(self.SERVICE_NAME)
if service_type is None:
return self.SERVICE_TYPE
else:
return service_type

View File

@ -100,3 +100,6 @@ class HeatHelm(openstack.OpenstackBaseHelm):
self.SERVICE_NAME, [self.SERVICE_NAME])
},
}
def get_region_name(self):
return self._get_service_region_name(self.SERVICE_NAME)

View File

@ -508,3 +508,109 @@ class HelmOperator(object):
except Exception:
LOG.exception("failed to delete overrides file: %s" % filepath)
raise
class HelmOperatorData(HelmOperator):
"""Class to allow retrieval of helm managed data"""
@helm_context
def get_keystone_auth_data(self):
keystone_operator = self.chart_operators[constants.HELM_CHART_KEYSTONE]
auth_data = {
'admin_user_name':
keystone_operator.get_admin_user_name(),
'admin_project_name':
keystone_operator.get_admin_project_name(),
'auth_host':
'keystone-api.openstack.svc.cluster.local',
'admin_user_domain':
keystone_operator.get_admin_user_domain(),
'admin_project_domain':
keystone_operator.get_admin_project_domain(),
}
return auth_data
@helm_context
def get_nova_endpoint_data(self):
nova_operator = self.chart_operators[constants.HELM_CHART_NOVA]
endpoint_data = {
'endpoint_override':
'http://nova-api.openstack.svc.cluster.local:8774',
'region_name':
nova_operator.get_region_name(),
}
return endpoint_data
@helm_context
def get_nova_oslo_messaging_data(self):
nova_operator = self.chart_operators[constants.HELM_CHART_NOVA]
endpoints_overrides = nova_operator._get_endpoints_overrides()
auth_data = {
'host':
'rabbitmq.openstack.svc.cluster.local',
'port':
5672,
'virt_host':
'nova',
'username':
endpoints_overrides['oslo_messaging']['auth']['nova']
['username'],
'password':
endpoints_overrides['oslo_messaging']['auth']['nova']
['password'],
}
return auth_data
@helm_context
def get_cinder_endpoint_data(self):
cinder_operator = self.chart_operators[constants.HELM_CHART_CINDER]
endpoint_data = {
'region_name':
cinder_operator.get_region_name(),
'service_name':
cinder_operator.get_service_name_v2(),
'service_type':
cinder_operator.get_service_type_v2(),
}
return endpoint_data
@helm_context
def get_glance_endpoint_data(self):
glance_operator = self.chart_operators[constants.HELM_CHART_GLANCE]
endpoint_data = {
'region_name':
glance_operator.get_region_name(),
'service_name':
glance_operator.get_service_name(),
'service_type':
glance_operator.get_service_type(),
}
return endpoint_data
@helm_context
def get_neutron_endpoint_data(self):
neutron_operator = self.chart_operators[constants.HELM_CHART_NEUTRON]
endpoint_data = {
'region_name':
neutron_operator.get_region_name(),
}
return endpoint_data
@helm_context
def get_heat_endpoint_data(self):
heat_operator = self.chart_operators[constants.HELM_CHART_HEAT]
endpoint_data = {
'region_name':
heat_operator.get_region_name(),
}
return endpoint_data
@helm_context
def get_ceilometer_endpoint_data(self):
ceilometer_operator = \
self.chart_operators[constants.HELM_CHART_CEILOMETER]
endpoint_data = {
'region_name':
ceilometer_operator.get_region_name(),
}
return endpoint_data

View File

@ -379,3 +379,6 @@ class NeutronHelm(openstack.OpenstackBaseHelm):
}
return overrides
def get_region_name(self):
return self._get_service_region_name(self.SERVICE_NAME)

View File

@ -420,3 +420,6 @@ class NovaHelm(openstack.OpenstackBaseHelm):
}
host_list.append(host_nova)
return host_list
def get_region_name(self):
return self._get_service_region_name(self.SERVICE_NAME)

View File

@ -76,6 +76,31 @@ class OpenstackBaseHelm(base.BaseHelm):
return self._region_name()
def _get_configured_service_name(self, service, version=None):
if self._region_config():
service_config = self._get_service_config(service)
if service_config is not None:
name = 'service_name'
if version is not None:
name = version + '_' + name
service_name = service_config.capabilities.get(name)
if service_name is not None:
return service_name
elif version is not None:
return service + version
else:
return service
def _get_configured_service_type(self, service, version=None):
if self._region_config():
service_config = self._get_service_config(service)
if service_config is not None:
stype = 'service_type'
if version is not None:
stype = version + '_' + stype
return service_config.capabilities.get(stype)
return None
def _get_or_generate_password(self, chart, namespace, field):
# Get password from the db for the specified chart overrides
if not self.dbapi:

View File

@ -6,6 +6,7 @@
from sysinv.common import constants
from sysinv.common import utils
from sysinv.helm import helm
from . import openstack
@ -44,10 +45,6 @@ class NfvPuppet(openstack.OpenstackBasePuppet):
self._get_service_region_name(self.SERVICE_NAME),
'nfv::keystone::auth::tenant': self._get_service_tenant_name(),
'nfv::nfvi::nova_endpoint_override':
self._get_nova_endpoint_url(),
'nfv::nfvi::openstack_nova_api_host':
self._get_management_address(),
'nfv::nfvi::host_listener_host':
self._get_management_address(),
@ -64,52 +61,16 @@ class NfvPuppet(openstack.OpenstackBasePuppet):
'nfv::nfvi::platform_keyring_service':
self.PLATFORM_KEYRING_SERVICE,
# TODO(Bart Wensley): When we switch to the pod based keystone,
# this will change to use those credentials.
'nfv::nfvi::openstack_username':
self._operator.keystone.get_admin_user_name(),
'nfv::nfvi::openstack_tenant':
self._operator.keystone.get_admin_project_name(),
'nfv::nfvi::openstack_auth_host':
self._keystone_auth_address(),
'nfv::nfvi::openstack_user_domain':
self._operator.keystone.get_admin_user_domain(),
'nfv::nfvi::openstack_project_domain':
self._operator.keystone.get_admin_project_domain(),
'nfv::nfvi::openstack_keyring_service':
self.PLATFORM_KEYRING_SERVICE,
'nfv::nfvi::keystone_region_name': self._keystone_region_name(),
'nfv::nfvi::keystone_service_name':
self._operator.keystone.get_service_name(),
'nfv::nfvi::keystone_service_type':
self._operator.keystone.get_service_type(),
'nfv::nfvi::cinder_region_name':
self._operator.cinder.get_region_name(),
'nfv::nfvi::cinder_service_name':
self._operator.cinder.get_service_name_v2(),
'nfv::nfvi::cinder_service_type':
self._operator.cinder.get_service_type_v2(),
'nfv::nfvi::cinder_endpoint_disabled':
not self._operator.cinder.is_service_enabled(),
'nfv::nfvi::glance_region_name':
self._operator.glance.get_region_name(),
'nfv::nfvi::glance_service_name':
self._operator.glance.get_service_name(),
'nfv::nfvi::glance_service_type':
self._operator.glance.get_service_type(),
'nfv::nfvi::neutron_region_name':
self._operator.neutron.get_region_name(),
'nfv::nfvi::nova_region_name':
self._operator.nova.get_region_name(),
'nfv::nfvi::sysinv_region_name':
self._operator.sysinv.get_region_name(),
'nfv::nfvi::heat_region_name':
self._operator.heat.get_region_name(),
'nfv::nfvi::patching_region_name':
self._operator.patching.get_region_name(),
'nfv::nfvi::ceilometer_region_name':
self._operator.ceilometer.get_region_name(),
'nfv::nfvi::fm_region_name':
self._operator.fm.get_region_name(),
@ -123,19 +84,180 @@ class NfvPuppet(openstack.OpenstackBasePuppet):
}
if self._kubernetes_enabled():
vim_disabled = {
# Disable VIM plugins for resources not yet
# (and which may never be) active.
'nfv::vim::block_storage_plugin_disabled': True,
'nfv::vim::compute_plugin_disabled': True,
'nfv::vim::network_plugin_disabled': True,
'nfv::vim::image_plugin_disabled': True,
'nfv::vim::guest_plugin_disabled': True,
'nfv::nfvi::nova_endpoint_disabled': True,
'nfv::nfvi::neutron_endpoint_disabled': True
}
if utils.is_openstack_installed(self.dbapi):
helm_data = helm.HelmOperatorData(self.dbapi)
config.update(vim_disabled)
# The openstack services are authenticated with pod based
# keystone.
keystone_auth_data = helm_data.get_keystone_auth_data()
openstack_auth_config = {
'nfv::nfvi::openstack_username':
keystone_auth_data['admin_user_name'],
'nfv::nfvi::openstack_tenant':
keystone_auth_data['admin_project_name'],
'nfv::nfvi::openstack_auth_host':
keystone_auth_data['auth_host'],
'nfv::nfvi::openstack_user_domain':
keystone_auth_data['admin_user_domain'],
'nfv::nfvi::openstack_project_domain':
keystone_auth_data['admin_project_domain'],
'nfv::nfvi::openstack_keyring_service':
self.PLATFORM_KEYRING_SERVICE,
}
config.update(openstack_auth_config)
# Nova is running in a pod
nova_endpoint_data = helm_data.get_nova_endpoint_data()
nova_config = {
'nfv::nfvi::nova_endpoint_override':
nova_endpoint_data['endpoint_override'],
'nfv::nfvi::nova_region_name':
nova_endpoint_data['region_name'],
}
config.update(nova_config)
# Cinder is running in a pod
cinder_endpoint_data = helm_data.get_cinder_endpoint_data()
cinder_config = {
'nfv::nfvi::cinder_region_name':
cinder_endpoint_data['region_name'],
'nfv::nfvi::cinder_service_name':
cinder_endpoint_data['service_name'],
'nfv::nfvi::cinder_service_type':
cinder_endpoint_data['service_type'],
}
config.update(cinder_config)
# Glance is running in a pod
glance_endpoint_data = helm_data.get_glance_endpoint_data()
glance_config = {
'nfv::nfvi::glance_region_name':
glance_endpoint_data['region_name'],
'nfv::nfvi::glance_service_name':
glance_endpoint_data['service_name'],
'nfv::nfvi::glance_service_type':
glance_endpoint_data['service_type'],
}
config.update(glance_config)
# Neutron is running in a pod
neutron_endpoint_data = helm_data.get_neutron_endpoint_data()
neutron_config = {
'nfv::nfvi::neutron_region_name':
neutron_endpoint_data['region_name'],
}
config.update(neutron_config)
# Heat is running in a pod
heat_endpoint_data = helm_data.get_heat_endpoint_data()
heat_config = {
'nfv::nfvi::heat_region_name':
heat_endpoint_data['region_name'],
}
config.update(heat_config)
# Ceilometer is running in a pod
ceilometer_endpoint_data = \
helm_data.get_ceilometer_endpoint_data()
ceilometer_config = {
'nfv::nfvi::ceilometer_region_name':
ceilometer_endpoint_data['region_name'],
}
config.update(ceilometer_config)
# The openstack rabbitmq is running in a pod
nova_oslo_messaging_data = \
helm_data.get_nova_oslo_messaging_data()
rabbit_config = {
'nfv::nfvi::rabbit_host':
nova_oslo_messaging_data['host'],
'nfv::nfvi::rabbit_port':
nova_oslo_messaging_data['port'],
'nfv::nfvi::rabbit_virtual_host':
nova_oslo_messaging_data['virt_host'],
'nfv::nfvi::rabbit_userid':
nova_oslo_messaging_data['username'],
'nfv::nfvi::rabbit_password':
nova_oslo_messaging_data['password'],
}
config.update(rabbit_config)
else:
# The openstack auth info is still required as the VIM will
# audit some keystone entities (e.g. tenants). Point it to
# the platform keystone.
openstack_auth_config = {
'nfv::nfvi::openstack_username':
self._operator.keystone.get_admin_user_name(),
'nfv::nfvi::openstack_tenant':
self._operator.keystone.get_admin_project_name(),
'nfv::nfvi::openstack_auth_host':
self._keystone_auth_address(),
'nfv::nfvi::openstack_user_domain':
self._operator.keystone.get_admin_user_domain(),
'nfv::nfvi::openstack_project_domain':
self._operator.keystone.get_admin_project_domain(),
'nfv::nfvi::openstack_keyring_service':
self.PLATFORM_KEYRING_SERVICE,
}
config.update(openstack_auth_config)
vim_disabled = {
# Disable VIM plugins for resources not yet active.
'nfv::vim::block_storage_plugin_disabled': True,
'nfv::vim::compute_plugin_disabled': True,
'nfv::vim::network_plugin_disabled': True,
'nfv::vim::image_plugin_disabled': True,
'nfv::vim::guest_plugin_disabled': True,
'nfv::nfvi::nova_endpoint_disabled': True,
'nfv::nfvi::neutron_endpoint_disabled': True,
'nfv::nfvi::cinder_endpoint_disabled': True,
}
config.update(vim_disabled)
else:
# The openstack services are authenticated with platform keystone.
openstack_auth_config = {
'nfv::nfvi::openstack_username':
self._operator.keystone.get_admin_user_name(),
'nfv::nfvi::openstack_tenant':
self._operator.keystone.get_admin_project_name(),
'nfv::nfvi::openstack_auth_host':
self._keystone_auth_address(),
'nfv::nfvi::openstack_user_domain':
self._operator.keystone.get_admin_user_domain(),
'nfv::nfvi::openstack_project_domain':
self._operator.keystone.get_admin_project_domain(),
'nfv::nfvi::openstack_keyring_service':
self.PLATFORM_KEYRING_SERVICE,
}
config.update(openstack_auth_config)
openstack_config = {
'nfv::nfvi::nova_endpoint_override':
self._get_nova_endpoint_url(),
'nfv::nfvi::nova_region_name':
self._operator.nova.get_region_name(),
'nfv::nfvi::cinder_region_name':
self._operator.cinder.get_region_name(),
'nfv::nfvi::cinder_service_name':
self._operator.cinder.get_service_name_v2(),
'nfv::nfvi::cinder_service_type':
self._operator.cinder.get_service_type_v2(),
'nfv::nfvi::cinder_endpoint_disabled':
not self._operator.cinder.is_service_enabled(),
'nfv::nfvi::glance_region_name':
self._operator.glance.get_region_name(),
'nfv::nfvi::glance_service_name':
self._operator.glance.get_service_name(),
'nfv::nfvi::glance_service_type':
self._operator.glance.get_service_type(),
'nfv::nfvi::neutron_region_name':
self._operator.neutron.get_region_name(),
'nfv::nfvi::heat_region_name':
self._operator.heat.get_region_name(),
'nfv::nfvi::ceilometer_region_name':
self._operator.ceilometer.get_region_name(),
}
config.update(openstack_config)
return config