Adding credsmgr support in devstack

Change-Id: Ied7da6e314d81426e60063f7347dbeb1dc05216b
This commit is contained in:
harsha.dhake 2019-03-27 16:25:01 +05:30
parent bc94150974
commit d05c20bb60
9 changed files with 280 additions and 25 deletions

4
.gitignore vendored
View File

@ -9,3 +9,7 @@ build/*
creds_manager/build/* creds_manager/build/*
.testrepository .testrepository
openstack openstack
.DS_Store
devstack/.DS_Store
.gitreview

View File

@ -1,4 +1,4 @@
[gerrit] [gerrit]
host=review.openstack.org host=review.openstack.org
port=29418 port=29418
project=openstack/omni.git project=x/omni.git

View File

@ -26,15 +26,15 @@ Following lines need to be added in local.conf to enable Omni plugin:
*3. Parameters required for Omni drivers:* *3. Parameters required for Omni drivers:*
================== ===== ================== =====
--------------------------- -------------------------------------
AWS GCE AWS GCE
================== ===== ================== =====
SECRET_KEY ZONE AWS_SECRET_KEY ZONE
ACCESS_KEY PROJECT_ID AWS_ACCESS_KEY PROJECT_ID
REGION_NAME REGION AWS_REGION_NAME REGION
AVAILABILITY_ZONE AWS_AVAILABILITY_ZONE
================== ===== ================== =====
Run stack.sh in your devstack tree to get started. Run stack.sh in your devstack tree to get started.

179
devstack/lib/creds_mgr Normal file
View File

@ -0,0 +1,179 @@
#!/bin/bash -xe
# Save trace setting
XTRACE=$(set +o | grep xtrace)
set +o xtrace
PROJECT_NAME="credsmgr"
OMNI_DATA_DIR="/opt/stack/omni"
CINDER_DIR="/opt/stack/cinder"
NOVA_DIR="/opt/stack/nova"
CREDSMGR_DIR="/opt/stack/credsmgr"
CREDSMGR_SERVICE_NAME=devstack@credsmgr.service
STACK_USER="stack"
CREDSMGR_CONF="/etc/credsmgr/credsmgr.conf"
CREDSMGR_URL="http://${SERVICE_HOST}:8091/"
FERNET_SALT=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)
FERNET_PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)
function install_credsmgr {
install_dependencies
sudo cp -R $OMNI_DATA_DIR/creds_manager/credsmgr $CREDSMGR_DIR/lib/python2.?/site-packages/
sudo cp -R $OMNI_DATA_DIR/creds_manager/etc/* /etc/
# Remove the default credsmgr.conf and write the file afresh.
sudo rm -f /etc/credsmgr/credsmgr.conf
# Grant permissions on /etc folders
sudo chown -R $STACK_USER:$STACK_USER /etc/credsmgr
sudo chown -R $STACK_USER:$STACK_USER /etc/logrotate.d
sudo chown -R $STACK_USER:$STACK_USER /etc/rsyslog.d
create_service_file
init_credsmgr
update_credsmgr_config
create_credsmgr_accounts
configure_creds_decryption_for_ostack_components $NOVA_CONF
configure_creds_decryption_for_ostack_components $NEUTRON_CONF
configure_creds_decryption_for_ostack_components $GLANCE_API_CONF
configure_creds_decryption_for_ostack_components $CINDER_CONF
# Change the code in specific services' file to fetch credsmgr endpoints in the service_catalog object created in their contexts
fetch_credsmgr_in_service_catalog
restart_services
start_credsmgr_service
sleep 20
# Create and associate credentials with tenant id
create_and_associate_credentials
}
function install_dependencies {
# Create virtualenv and install credsmgr dependencies
virtualenv $CREDSMGR_DIR
export PBR_VERSION=1.8.1
$CREDSMGR_DIR/bin/python $CREDSMGR_DIR/bin/pip install \
-chttps://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/newton \
-r $OMNI_DATA_DIR/creds_manager/requirements.txt
cp -r $OMNI_DATA_DIR/credsmgrclient $CREDSMGR_DIR/lib/python2.?/site-packages/
cd $OMNI_DATA_DIR/creds_manager
$CREDSMGR_DIR/bin/python setup.py install
}
function create_service_file {
cat <<EOF | sudo tee /etc/systemd/system/$CREDSMGR_SERVICE_NAME
[Unit]
Description=Devstack $CREDSMGR_SERVICE_NAME
After=network.target
ConditionPathExists=/opt/stack/credsmgr/bin/python
ConditionPathExists=/opt/stack/credsmgr/bin/credsmgr-api
[Service]
Type=simple
User=stack
WorkingDirectory=/opt/stack/credsmgr
ExecStart=/opt/stack/credsmgr/bin/python /opt/stack/credsmgr/bin/credsmgr-api --config-file /etc/credsmgr/credsmgr.conf
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=credsmgr_api
PIDFile=/var/run/credsmgr/credsmgr.pid
PermissionsStartOnly=True
[Install]
WantedBy=multi-user.target
EOF
}
function init_credsmgr {
recreate_database credsmgr
time_start "dbsync"
local dburl
dburl=$(database_connection_url credsmgr)
iniset $CREDSMGR_CONF database connection $dburl
$CREDSMGR_DIR/bin/python $CREDSMGR_DIR/bin/credsmgr-manage
time_stop "dbsync"
}
function update_credsmgr_config {
iniset $CREDSMGR_CONF DEFAULT credsmgr_api_listen_port 8091
iniset $CREDSMGR_CONF DEFAULT credsmgr_api_use_ssl False
iniset $CREDSMGR_CONF DEFAULT credsmgr_api_workers 1
iniset $CREDSMGR_CONF keystone_authtoken auth_type password
iniset $CREDSMGR_CONF keystone_authtoken auth_url "http://${SERVICE_HOST}/identity"
iniset $CREDSMGR_CONF keystone_authtoken username "credsmgr"
iniset $CREDSMGR_CONF keystone_authtoken password $SERVICE_PASSWORD
iniset $CREDSMGR_CONF keystone_authtoken user_domain_name "$SERVICE_DOMAIN_NAME"
iniset $CREDSMGR_CONF keystone_authtoken project_name "service"
iniset $CREDSMGR_CONF keystone_authtoken project_domain_name "$SERVICE_DOMAIN_NAME"
iniset $CREDSMGR_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $CREDSMGR_CONF credsmgr encryptor "credsmgrclient.encryption.noop.NoEncryption"
# uncomment following code when encryptor class is "credsmgrclient.encryption.fernet.FernetKeyEncryption"
# iniset $CREDSMGR_CONF credsmgr fernet_salt $FERNET_SALT
# iniset $CREDSMGR_CONF credsmgr fernet_password $FERNET_PASSWORD
}
function restart_credsmgr_service {
sudo systemctl restart $CREDSMGR_SERVICE_NAME
}
function start_credsmgr_service {
sudo systemctl start $CREDSMGR_SERVICE_NAME
}
function stop_credsmgr_service {
sudo systemctl stop $CREDSMGR_SERVICE_NAME
}
function create_credsmgr_accounts {
create_service_user "credsmgr"
get_or_create_service $PROJECT_NAME $PROJECT_NAME "Credentials manager"
get_or_create_endpoint $PROJECT_NAME $OS_REGION_NAME $CREDSMGR_URL \
$CREDSMGR_URL $CREDSMGR_URL
}
function configure_creds_decryption_for_ostack_components {
local conf_file=$1
iniset $conf_file credsmgr encryptor "credsmgrclient.encryption.noop.NoEncryption"
# uncomment following code when encryptor class is "credsmgrclient.encryption.fernet.FernetKeyEncryption"
# iniset $conf_file credsmgr fernet_salt $FERNET_SALT
# iniset $conf_file credsmgr fernet_password $FERNET_PASSWORD
}
# Few services have service_catalog object prepopulated with selected services' endpoints.
# We need to edit this code to make it fetch credsmgr endpoints as well.
function fetch_credsmgr_in_service_catalog {
# Change cinder's context.py file to fetch the credsmgr endpoints along with other endpoints.
sudo sed -i "s/'image'/'image', 'credsmgr'/g" ${CINDER_DIR}/cinder/context.py
sudo sed -i -e "s/, 'placement'/, 'placement', 'credsmgr'/g" ${NOVA_DIR}/nova/context.py
# Use this space to add similar code as above to edit the code in the specific services if required
# .
# .
# .
}
function create_and_associate_credentials {
source $TOP_DIR/openrc "" "" "" ""
local token
local tenant_id
token=$(openstack token issue -c id -f value)
tenant_id=$(openstack project show "admin" -f value -c id)
cred_id=$(curl $CREDSMGR_URL/v1/credentials/aws -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X POST -d "{\"aws_access_key_id\": \"${AWS_ACCESS_KEY}\", \"aws_secret_access_key\": \"${AWS_SECRET_KEY}\"}")
cred_id=$(echo $cred_id | awk {'print$2'} | cut -d"}" -f1 | tr -d '"')
curl -i $CREDSMGR_URL/v1/credentials/aws/$cred_id/association -H "X-Auth-Token: $token" -H "Content-Type: application/json" -X POST -d "{\"tenant_id\": \"${tenant_id}\"}"
}
# Restore xtrace
$XTRACE
## mode: shell-script
## End:

View File

@ -8,19 +8,19 @@ DIST_PACKAGES="/usr/local/lib/python2.7/dist-packages"
ENTRY_POINT="$DIST_PACKAGES/glance_store-*.dist-info/entry_points.txt" ENTRY_POINT="$DIST_PACKAGES/glance_store-*.dist-info/entry_points.txt"
NEUTRON_ENTRY_POINT="/opt/stack/neutron/neutron.egg-info/entry_points.txt" NEUTRON_ENTRY_POINT="/opt/stack/neutron/neutron.egg-info/entry_points.txt"
ML2_CONF="/etc/neutron/plugins/ml2/ml2_conf.ini" ML2_CONF="/etc/neutron/plugins/ml2/ml2_conf.ini"
NOVA_CPU_CONF="/etc/nova/nova-cpu.conf"
# Functions # Functions
# ------------ # ------------
function set_aws_keys_and_region { function set_aws_region_and_az {
local conf_file=$1 local conf_file=$1
iniset $conf_file AWS secret_key ${AWS_SECRET_KEY}
iniset $conf_file AWS access_key ${AWS_ACCESS_KEY}
iniset $conf_file AWS region_name ${AWS_REGION_NAME} iniset $conf_file AWS region_name ${AWS_REGION_NAME}
iniset $conf_file AWS az ${AWS_AVAILABILITY_ZONE}
} }
function configure_glance { function configure_glance {
set_aws_keys_and_region $GLANCE_API_CONF set_aws_region_and_az $GLANCE_API_CONF
iniset $GLANCE_API_CONF DEFAULT show_multiple_locations True iniset $GLANCE_API_CONF DEFAULT show_multiple_locations True
iniset $GLANCE_API_CONF glance_store default_store aws iniset $GLANCE_API_CONF glance_store default_store aws
iniset $GLANCE_API_CONF glance_store stores aws iniset $GLANCE_API_CONF glance_store stores aws
@ -34,33 +34,52 @@ function configure_glance {
} }
function configure_cinder { function configure_cinder {
set_aws_keys_and_region $CINDER_CONF set_aws_region_and_az $CINDER_CONF
iniset $CINDER_CONF AWS az ${AWS_AVAILABILITY_ZONE}
iniset $CINDER_CONF AWS volume_driver ${AWS_CINDER_DRIVER} iniset $CINDER_CONF AWS volume_driver ${AWS_CINDER_DRIVER}
iniset $CINDER_CONF DEFAULT enable_force_upload ${ENABLE_FORCE_UPLOAD} iniset $CINDER_CONF DEFAULT enable_force_upload ${ENABLE_FORCE_UPLOAD}
iniset $CINDER_CONF DEFAULT enabled_backends AWS iniset $CINDER_CONF DEFAULT enabled_backends AWS
iniset $CINDER_CONF DEFAULT volumes_dir ${VOLUME_DIR} iniset $CINDER_CONF DEFAULT volumes_dir ${VOLUME_DIR}
iniset $CINDER_CONF DEFAULT os_privileged_user_name ${CINDER_USER} iniset $CINDER_CONF DEFAULT os_privileged_user_name ${CINDER_USER}
iniset $CINDER_CONF DEFAULT default_volume_type AWS iniset $CINDER_CONF DEFAULT default_volume_type AWS
iniset $CINDER_CONF DEFAULT os_region_name AWS iniset $CINDER_CONF DEFAULT os_region_name ${OS_REGION_NAME}
} }
function configure_nova { function configure_nova {
set_aws_keys_and_region $NOVA_CONF set_aws_region_and_az $NOVA_CONF
iniset $NOVA_CONF DEFAULT compute_driver ${AWS_COMPUTE_DRIVER} iniset $NOVA_CONF DEFAULT compute_driver ${AWS_COMPUTE_DRIVER}
iniset $NOVA_CONF DEFAULT glance_api_insecure True iniset $NOVA_CONF DEFAULT glance_api_insecure True
iniset $NOVA_CONF DEFAULT cinder_api_insecure True iniset $NOVA_CONF DEFAULT cinder_api_insecure True
iniset $NOVA_CONF DEFAULT vnc_enabled True iniset $NOVA_CONF DEFAULT vnc_enabled True
iniset $NOVA_CONF DEFAULT osapi_compute_extension ${COMPUTE_EXTENSION} iniset $NOVA_CONF DEFAULT osapi_compute_extension ${COMPUTE_EXTENSION}
iniset $NOVA_CONF DEFAULT force_dhcp_release True iniset $NOVA_CONF DEFAULT force_dhcp_release True
iniset $NOVA_CONF keystone_authtoken identity_uri "http://${SERVICE_HOST}/identity"
iniset $NOVA_CONF keystone_authtoken username nova
iniset $NOVA_CONF keystone_authtoken admin_user nova
iniset $NOVA_CONF keystone_authtoken password $SERVICE_PASSWORD
iniset $NOVA_CONF keystone_authtoken project_name $SERVICE_PROJECT_NAME
iniset $NOVA_CONF keystone_authtoken admin_password $SERVICE_PASSWORD
iniset $NOVA_CONF keystone_authtoken admin_tenant_name $SERVICE_PROJECT_NAME
iniset $NOVA_CONF keystone_authtoken region_name ${OS_REGION_NAME}
set_aws_region_and_az $NOVA_CPU_CONF
iniset $NOVA_CPU_CONF keystone_authtoken identity_uri "http://${SERVICE_HOST}/identity"
iniset $NOVA_CPU_CONF keystone_authtoken username nova
iniset $NOVA_CPU_CONF keystone_authtoken admin_user nova
iniset $NOVA_CPU_CONF keystone_authtoken password $SERVICE_PASSWORD
iniset $NOVA_CPU_CONF keystone_authtoken project_name $SERVICE_PROJECT_NAME
iniset $NOVA_CPU_CONF keystone_authtoken admin_password $SERVICE_PASSWORD
iniset $NOVA_CPU_CONF keystone_authtoken admin_tenant_name $SERVICE_PROJECT_NAME
iniset $NOVA_CPU_CONF keystone_authtoken region_name ${OS_REGION_NAME}
} }
function configure_neutron { function configure_neutron {
set_aws_keys_and_region $NEUTRON_CONF set_aws_region_and_az $NEUTRON_CONF
iniset $NEUTRON_CONF AWS az ${AWS_AVAILABILITY_ZONE}
iniset $NEUTRON_CONF DEFAULT core_plugin ${CORE_PLUGIN} iniset $NEUTRON_CONF DEFAULT core_plugin ${CORE_PLUGIN}
iniset $NEUTRON_CONF DEFAULT service_plugins ${AWS_SERVICE_PLUGIN} iniset $NEUTRON_CONF DEFAULT service_plugins ${AWS_SERVICE_PLUGIN}
iniset $NEUTRON_CONF nova region_name AWS iniset $NEUTRON_CONF nova region_name ${OS_REGION_NAME}
iniset $NEUTRON_CONF keystone_authtoken auth_uri "http://${SERVICE_HOST}/identity"
iniset $ML2_CONF ml2 type_drivers ${ML2_DRIVERS} iniset $ML2_CONF ml2 type_drivers ${ML2_DRIVERS}
iniset $ML2_CONF ml2 tenant_network_types ${ML2_TENANT} iniset $ML2_CONF ml2 tenant_network_types ${ML2_TENANT}

View File

@ -5,16 +5,29 @@ cp /opt/stack/omni/devstack/lib/* $TOP_DIR/lib/
sudo apt-get install crudini -y sudo apt-get install crudini -y
sudo pip install -r /opt/stack/omni/requirements.txt sudo pip install -r /opt/stack/omni/requirements.txt
if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then if [[ "$1" == "stack" && "$2" == "pre-install" ]]; then
if [ "$OMNI_PROVIDER" != "gce" ] && [ "$OMNI_PROVIDER" != "aws" ]; then if [ "$OMNI_PROVIDER" != "gce" ] && [ "$OMNI_PROVIDER" != "aws" ]; then
echo "$OMNI_PROVIDER is not supported" echo "$OMNI_PROVIDER is not supported"
exit 1 exit 1
fi fi
if [ "$OMNI_PROVIDER" == "aws" ]; then
if [ -z "$AWS_ACCESS_KEY" ] || [ -z "$AWS_SECRET_KEY" ]; then
echo "AWS_ACCESS_KEY and AWS_SECRET_KEY are not provided"
exit 1
fi
fi
fi fi
if [[ "$1" == "stack" && "$2" == "extra" ]]; then if [[ "$1" == "stack" && "$2" == "extra" ]]; then
source $TOP_DIR/lib/omni_$OMNI_PROVIDER source $TOP_DIR/lib/omni_$OMNI_PROVIDER
source $TOP_DIR/lib/common_functions source $TOP_DIR/lib/common_functions
if [ "$OMNI_PROVIDER" == "aws" ]; then
source $TOP_DIR/lib/creds_mgr
install_credsmgr
fi
configure_glance configure_glance
configure_cinder configure_cinder
configure_nova configure_nova
@ -22,3 +35,10 @@ if [[ "$1" == "stack" && "$2" == "extra" ]]; then
copy_omni_files copy_omni_files
restart_services restart_services
fi fi
if [[ "$1" == "unstack" ]]; then
if [ "$OMNI_PROVIDER" == "aws" ]; then
source $TOP_DIR/lib/creds_mgr
stop_credsmgr_service
fi
fi

View File

@ -186,6 +186,10 @@ class AwsMechanismDriver(api.MechanismDriver):
raise NetworkWithMultipleAZs() raise NetworkWithMultipleAZs()
aws_az = network_az_hints[0] aws_az = network_az_hints[0]
else: else:
aws_az = cfg.CONF.AWS.az
LOG.info("AZ details missing in context, so fetching from the"
" conf file. aws_az: %s", aws_az)
if aws_az is None:
raise AzNotProvided() raise AzNotProvided()
self._validate_az(aws_az) self._validate_az(aws_az)
ec2_subnet_id = self.aws_utils.create_subnet_and_tags( ec2_subnet_id = self.aws_utils.create_subnet_and_tags(
@ -209,8 +213,20 @@ class AwsMechanismDriver(api.MechanismDriver):
if ',' in aws_az: if ',' in aws_az:
raise NetworkWithMultipleAZs() raise NetworkWithMultipleAZs()
session = self.aws_utils.get_keystone_session() session = self.aws_utils.get_keystone_session()
azmgr_url = session.get_endpoint(service_type='azmanager', azmgr_url = ''
region_name=cfg.CONF.nova_region_name) try:
azmgr_url = session.get_endpoint(service_type='azmanager',
region_name=cfg.CONF.nova_region_name)
if not (azmgr_url and azmgr_url.strip()):
LOG.warning("AZ manager endpoint not found. Proceeding without"
" validating the AZ information. Error: "
"None or empty endpoint found.")
return
except Exception as e:
LOG.error("Error in finding AZ manager endpoint. "
"Proceeding without validating the AZ information. "
"Error: %s" % e)
return
zones = self._send_request(session, azmgr_url) zones = self._send_request(session, azmgr_url)
if aws_az not in zones: if aws_az not in zones:
LOG.error("Provided az %s not found in zones %s", aws_az, zones) LOG.error("Provided az %s not found in zones %s", aws_az, zones)

View File

@ -46,10 +46,27 @@ aws_opts = [
help='Listen to keypair delete notifications and act on them') help='Listen to keypair delete notifications and act on them')
] ]
keystone_authtoken_group = cfg.OptGroup(name='keystone_authtoken',
title='Options to connect to Keystone')
keystone_authtoken_opts = [
cfg.StrOpt('identity_uri', help='Keystone url'),
cfg.StrOpt('username', help='Keystone Username'),
cfg.StrOpt('password', help='Keystone Password'),
cfg.StrOpt('project_name', help='Project name'),
cfg.StrOpt('region_name', help='AWS region name'),
cfg.StrOpt('admin_user', help='Keystone admin username'),
cfg.StrOpt('admin_password', help='Keystone admin password'),
cfg.StrOpt('admin_tenant_name', help='Keystone admin tenant name')
]
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_group(aws_group) CONF.register_group(aws_group)
CONF.register_opts(aws_opts, group=aws_group) CONF.register_opts(aws_opts, group=aws_group)
CONF.register_group(keystone_authtoken_group)
CONF.register_opts(keystone_authtoken_opts, group=keystone_authtoken_group)
EC2_STATE_MAP = { EC2_STATE_MAP = {
"pending": power_state.NOSTATE, "pending": power_state.NOSTATE,

View File

@ -137,9 +137,9 @@ class RestClient(object):
os_username = os.getenv('OS_USERNAME') os_username = os.getenv('OS_USERNAME')
os_password = os.getenv('OS_PASSWORD') os_password = os.getenv('OS_PASSWORD')
os_tenant_name = os.getenv('OS_TENANT_NAME') os_tenant_name = os.getenv('OS_PROJECT_NAME')
self.glance_endpoint = os_auth_url.replace('keystone/v3', 'glance') self.glance_endpoint = os_auth_url.replace('identity/v3', 'image')
sys.stdout.write('Using glance endpoint: ' + self.glance_endpoint) sys.stdout.write('Using glance endpoint: ' + self.glance_endpoint)
v3_auth = v3.Password(auth_url=os_auth_url, username=os_username, v3_auth = v3.Password(auth_url=os_auth_url, username=os_username,