Inventory: store BMC password in Openstack Barbican.

Replacing existing mechanism of storing BMC passwords in Inventory.
Porting all the changes made in SysInv to Inventory to make them on par.
Inventory is going to use Barbican API instead of keyring to store
BMC passwords for MTCE as well.

Depends-On: I7102a9662f3757c062ab310737f4ba08379d0100
Change-Id: I74e971495fa7538d77cfebc28d76fd752af69f5e
Story: 2003108
Task: 27700
Signed-off-by: Alex Kozyrev <alex.kozyrev@windriver.com>
This commit is contained in:
Alex Kozyrev 2019-01-21 10:27:34 -05:00
parent 887bd34471
commit 938d9551c4
8 changed files with 89 additions and 70 deletions

View File

@ -1,2 +1,2 @@
SRC_DIR="inventory"
TIS_PATCH_VER=1
TIS_PATCH_VER=2

View File

@ -78,7 +78,6 @@ import xml.etree.ElementTree as ET
import xml.etree.ElementTree as et
LOG = log.getLogger(__name__)
KEYRING_BM_SERVICE = "BM"
ERR_CODE_LOCK_SOLE_SERVICE_PROVIDER = "-1003"
@ -1819,15 +1818,10 @@ class HostController(rest.RestController):
LOG.info("notify systemconfig of host-delete which will"
"also do stors, lvgs, pvs, ceph crush remove")
# tell conductor to delete the keystore entry associated
# tell conductor to delete the barbican secret associated
# with this host (if present)
try:
pecan.request.rpcapi.unconfigure_keystore_account(
pecan.request.context,
KEYRING_BM_SERVICE,
pecan.request.rpcapi.delete_barbican_secret(pecan.request.context,
ihost.uuid)
except exception.NotFound:
pass
# Notify patching to drop the host
if ihost.hostname is not None:
@ -2295,7 +2289,7 @@ class HostController(rest.RestController):
_("Host-add Rejected: bm_ip %s already exists") %
phost['bm_ip'])
# Update keyring with updated board management credentials, if supplied
# Update barbican with updated board management credentials if supplied
if (ohost['bm_username'] and phost['bm_username'] and
(ohost['bm_username'] != phost['bm_username'])):
if not password_exists:
@ -2306,13 +2300,11 @@ class HostController(rest.RestController):
ohost['bm_username'],
phost['bm_username'])))
if password_exists:
# The conductor will handle creating the keystore acct
pecan.request.rpcapi.configure_keystore_account(
pecan.request.context,
KEYRING_BM_SERVICE,
if password_exists and patch_bm_password:
pecan.request.rpcapi.create_barbican_secret(pecan.request.context,
phost['uuid'],
patch_bm_password)
LOG.info("%s bm semantic checks for user_agent %s passed" %
(phost['hostname'], pecan.request.user_agent))

View File

@ -31,7 +31,6 @@ Commands are received via RPC calls.
"""
import grp
import keyring
import os
import oslo_messaging as messaging
import pwd
@ -1912,35 +1911,20 @@ class ConductorManager(base_manager.BaseConductorManager):
network_type)
return "%s-cinder-%s" % ADDRESS_FORMAT_ARGS
def configure_keystore_account(self, context, service_name,
username, password):
"""Synchronously, have a conductor configure a ks(keyring) account.
Does the following tasks:
- call keyring API to create an account under a service.
def create_barbican_secret(self, context, name, payload):
"""Calls Barbican API to create a secret
:param context: request context.
:param service_name: the keystore service.
:param username: account username
:param password: account password
:param name: secret name
:param payload: secret payload
"""
if not service_name.strip():
raise exception.InventoryException(_(
"Keystore service is a blank value"))
self._openstack.create_barbican_secret(context=context,
name=name, payload=payload)
keyring.set_password(service_name, username, password)
def unconfigure_keystore_account(self, context, service_name, username):
"""Synchronously, have a conductor unconfigure a ks(keyring) account.
Does the following tasks:
- call keyring API to delete an account under a service.
def delete_barbican_secret(self, context, name):
"""Calls Barbican API to delete a secret
:param context: request context.
:param service_name: the keystore service.
:param username: account username
:param name: secret name
"""
try:
keyring.delete_password(service_name, username)
except keyring.errors.PasswordDeleteError:
pass
self._openstack.delete_barbican_secret(context=context, name=name)

View File

@ -11,6 +11,7 @@
""" Inventory Openstack Utilities and helper functions."""
from barbicanclient.v1 import client as barbican_client_v1
from cinderclient.v2 import client as cinder_client_v2
from inventory.common import constants
from inventory.common import exception
@ -70,6 +71,9 @@ keystone_opts = [
cfg.StrOpt('nova_region_name',
default='RegionOne',
help=_("Nova Region Name")),
cfg.StrOpt('barbican_region_name',
default='RegionOne',
help=_("Barbican Region Name")),
cfg.StrOpt('username',
default='inventory',
help=_("Inventory keystone user name")),
@ -96,6 +100,7 @@ class OpenStackOperator(object):
def __init__(self, dbapi):
self.dbapi = dbapi
self.barbican_client = None
self.cinder_client = None
self.keystone_client = None
self.keystone_session = None
@ -795,6 +800,58 @@ class OpenStackOperator(object):
return volume_types_list
#################
# Barbican
#################
def _get_barbicanclient(self):
if not self.barbican_client:
self.barbican_client = barbican_client_v1.Client(
session=self._get_keystone_session(),
auth_url=self.auth_url,
endpoint_type='internalURL',
region_name=cfg.CONF.KEYSTONE_AUTHTOKEN.barbican_region_name)
return self.barbican_client
def get_barbican_secret_by_name(self, context, name):
try:
client = self._get_barbicanclient()
secret_list = client.secrets.list(name=name)
secret = next(iter(secret_list), None)
return secret
except Exception:
LOG.error("Unable to find Barbican secret %s", name)
return None
def create_barbican_secret(self, context, name, payload):
if not payload:
LOG.error("Empty password is passed to Barbican %s" % name)
return None
try:
client = self._get_barbicanclient()
secret = self.get_barbican_secret_by_name(context, name)
if secret:
client.secrets.delete(secret.secret_ref)
secret = client.secrets.create(name, payload)
secret.store()
return secret.secret_ref
except Exception:
LOG.error("Unable to create Barbican secret %s" % name)
return None
def delete_barbican_secret(self, context, name):
try:
client = self._get_barbicanclient()
secret = self.get_barbican_secret_by_name(context=context,
name=name)
if not secret:
LOG.error("Unable to delete unknown Barbican secret %s" % name)
return False
client.secrets.delete(secret_ref=secret.secret_ref)
return True
except Exception:
LOG.error("Unable to delete Barbican secret %s" % name)
return False
#########################
# Primary Region Inventory
# Region specific methods

View File

@ -516,40 +516,29 @@ class ConductorAPI(object):
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
return cctxt.call(context, 'update_cpu_config')
def configure_keystore_account(self, context, service_name,
username, password, topic=None):
"""Synchronously, have a conductor configure a ks(keyring) account.
Does the following tasks:
- call keyring API to create an account under a service.
def create_barbican_secret(self, context, name, payload, topic=None):
"""Calls Barbican API to create a secret
:param context: request context.
:param service_name: the keystore service.
:param username: account username
:param password: account password
:param name: secret name
:param payload: secret payload
"""
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
return cctxt.call(context,
'configure_keystore_account',
service_name=service_name,
username=username, password=password)
'create_barbican_secret',
name=name,
payload=payload)
def unconfigure_keystore_account(self, context,
service_name, username, topic=None):
"""Synchronously, have a conductor unconfigure a ks(keyring) account.
Does the following tasks:
- call keyring API to delete an account under a service.
def delete_barbican_secret(self, context, name, topic=None):
"""Calls Barbican API to delete a secret
:param context: request context.
:param service_name: the keystore service.
:param username: account username
:param name: secret name
"""
cctxt = self.client.prepare(topic=topic or self.topic, version='1.0')
return cctxt.call(context,
'unconfigure_keystore_account',
service_name=service_name,
username=username)
'delete_barbican_secret',
name=name)
def reload_snmp_config(self, context, topic=None):
"""Synchronously, have a conductor reload the SNMP configuration.

View File

@ -31,7 +31,6 @@ oslo.utils>=3.5.0 # Apache-2.0
osprofiler>=1.4.0 # Apache-2.0
python-cinderclient>=3.1.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
keyring
keystonemiddleware>=4.12.0 # Apache-2.0
oslo.messaging!=5.25.0,>=5.24.2 # Apache-2.0
retrying!=1.3.0,>=1.2.3 # Apache-2.0

View File

@ -26,7 +26,6 @@ testtools!=1.2.0,>=0.9.36
tempest-lib<0.5.0,>=0.4.0
ipaddr
pytest
keyring
pyudev
libvirt-python>=1.2.5
migrate

View File

@ -19,5 +19,4 @@ testresources>=0.2.4 # Apache-2.0/BSD
tempest>=16.1.0 # Apache-2.0
httplib2
python-keystoneclient
keyring
pyOpenSSL>=0.14 # Apache-2.0