Backend Keystone authentication
Change methods used in backend to authenticate with keystone. Use autodetection mechanizm for API version and refactor config options specified in Octavia. Change-Id: Id0deee2714040d271f43a537c27f410e2f4e3ef2 Closes-Bug: #1620668 Closes-Bug: #1618691
This commit is contained in:
parent
7476aea667
commit
076e016bb2
@ -42,22 +42,24 @@ function build_octavia_worker_image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function create_octavia_accounts {
|
function create_octavia_accounts {
|
||||||
create_service_user "neutron"
|
create_service_user "octavia"
|
||||||
|
|
||||||
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
|
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
|
||||||
|
|
||||||
local neutron_service=$(get_or_create_service "octavia" \
|
local octavia_service=$(get_or_create_service "octavia" \
|
||||||
"octavia" "Octavia Service")
|
"octavia" "Octavia Service")
|
||||||
get_or_create_endpoint $neutron_service \
|
get_or_create_endpoint $octavia_service \
|
||||||
"$REGION_NAME" \
|
"$REGION_NAME" \
|
||||||
"$OCTAVIA_PROTOCOL://$SERVICE_HOST:$OCTAVIA_PORT/" \
|
"$OCTAVIA_PROTOCOL://$SERVICE_HOST:$OCTAVIA_PORT/" \
|
||||||
"$OCTAVIA_PROTOCOL://$SERVICE_HOST:$OCTAVIA_PORT/" \
|
"$OCTAVIA_PROTOCOL://$SERVICE_HOST:$OCTAVIA_PORT/" \
|
||||||
"$OCTAVIA_PROTOCOL://$SERVICE_HOST:$OCTAVIA_PORT/"
|
"$OCTAVIA_PROTOCOL://$SERVICE_HOST:$OCTAVIA_PORT/"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
function octavia_configure {
|
function octavia_configure {
|
||||||
|
|
||||||
|
create_octavia_cache_dir
|
||||||
|
|
||||||
sudo mkdir -m 755 -p $OCTAVIA_CONF_DIR
|
sudo mkdir -m 755 -p $OCTAVIA_CONF_DIR
|
||||||
safe_chown $STACK_USER $OCTAVIA_CONF_DIR
|
safe_chown $STACK_USER $OCTAVIA_CONF_DIR
|
||||||
|
|
||||||
@ -67,16 +69,20 @@ function octavia_configure {
|
|||||||
|
|
||||||
iniset $OCTAVIA_CONF database connection "mysql+pymysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:3306/octavia"
|
iniset $OCTAVIA_CONF database connection "mysql+pymysql://${DATABASE_USER}:${DATABASE_PASSWORD}@${DATABASE_HOST}:3306/octavia"
|
||||||
|
|
||||||
if [ "$OCTAVIA_AUTH_VERSION" == "2" ] ; then
|
# Configure keystone auth_token for all users
|
||||||
AUTH_URI=${KEYSTONE_AUTH_URI%/v3}/v2.0
|
configure_auth_token_middleware $OCTAVIA_CONF octavia $OCTAVIA_AUTH_CACHE_DIR
|
||||||
else
|
|
||||||
AUTH_URI=${KEYSTONE_AUTH_URI}
|
# Ensure config is set up properly for authentication as admin
|
||||||
fi
|
iniset $OCTAVIA_CONF service_auth auth_url $KEYSTONE_AUTH_URI
|
||||||
iniset $OCTAVIA_CONF keystone_authtoken auth_uri ${AUTH_URI}
|
iniset $OCTAVIA_CONF service_auth auth_type password
|
||||||
iniset $OCTAVIA_CONF keystone_authtoken admin_user ${OCTAVIA_ADMIN_USER}
|
iniset $OCTAVIA_CONF service_auth username $OCTAVIA_USERNAME
|
||||||
iniset $OCTAVIA_CONF keystone_authtoken admin_tenant_name ${OCTAVIA_ADMIN_TENANT_NAME}
|
iniset $OCTAVIA_CONF service_auth password $OCTAVIA_PASSWORD
|
||||||
iniset $OCTAVIA_CONF keystone_authtoken admin_password ${OCTAVIA_ADMIN_PASSWORD}
|
iniset $OCTAVIA_CONF service_auth user_domain_name $OCTAVIA_USER_DOMAIN_NAME
|
||||||
iniset $OCTAVIA_CONF keystone_authtoken auth_version ${OCTAVIA_AUTH_VERSION}
|
iniset $OCTAVIA_CONF service_auth project_name $OCTAVIA_PROJECT_NAME
|
||||||
|
iniset $OCTAVIA_CONF service_auth project_domain_name $OCTAVIA_PROJECT_DOMAIN_NAME
|
||||||
|
iniset $OCTAVIA_CONF service_auth cafile $SSL_BUNDLE_FILE
|
||||||
|
iniset $OCTAVIA_CONF service_auth signing_dir $signing_dir
|
||||||
|
iniset $OCTAVIA_CONF service_auth memcached_servers $SERVICE_HOST:11211
|
||||||
|
|
||||||
# Setting other required default options
|
# Setting other required default options
|
||||||
iniset $OCTAVIA_CONF controller_worker amphora_driver ${OCTAVIA_AMPHORA_DRIVER}
|
iniset $OCTAVIA_CONF controller_worker amphora_driver ${OCTAVIA_AMPHORA_DRIVER}
|
||||||
@ -373,6 +379,15 @@ function octavia_cleanup {
|
|||||||
openstack keypair delete ${OCTAVIA_AMP_SSH_KEY_NAME}
|
openstack keypair delete ${OCTAVIA_AMP_SSH_KEY_NAME}
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
sudo rm -rf $NOVA_STATE_PATH $NOVA_AUTH_CACHE_DIR
|
||||||
|
}
|
||||||
|
|
||||||
|
# create_octavia_cache_dir() - Part of the configure_octavia() process
|
||||||
|
function create_octavia_cache_dir {
|
||||||
|
# Create cache dir
|
||||||
|
sudo install -d -o $STACK_USER $OCTAVIA_AUTH_CACHE_DIR
|
||||||
|
rm -f $OCTAVIA_AUTH_CACHE_DIR/*
|
||||||
}
|
}
|
||||||
|
|
||||||
# check for service enabled
|
# check for service enabled
|
||||||
|
@ -10,6 +10,7 @@ TRIPLEO_IMAGE_ELEMENTS_BRANCH=${TRIPLEO_IMAGE_ELEMENTS_BRANCH:-master}
|
|||||||
TRIPLEO_IMAGE_ELEMENTS_DIR=$DEST/tripleo-image-elements
|
TRIPLEO_IMAGE_ELEMENTS_DIR=$DEST/tripleo-image-elements
|
||||||
OCTAVIA_BIN_DIR=${OCTAVIA_BIN_DIR:-$(get_python_exec_prefix)}
|
OCTAVIA_BIN_DIR=${OCTAVIA_BIN_DIR:-$(get_python_exec_prefix)}
|
||||||
OCTAVIA_CONF_DIR=${OCTAVIA_CONF_DIR:-"/etc/octavia"}
|
OCTAVIA_CONF_DIR=${OCTAVIA_CONF_DIR:-"/etc/octavia"}
|
||||||
|
OCTAVIA_AUTH_CACHE_DIR=${OCTAVIA_AUTH_CACHE_DIR:-"/var/cache/octavia"}
|
||||||
OCTAVIA_SSH_DIR=${OCTAVIA_SSH_DIR:-${OCTAVIA_CONF_DIR}/.ssh}
|
OCTAVIA_SSH_DIR=${OCTAVIA_SSH_DIR:-${OCTAVIA_CONF_DIR}/.ssh}
|
||||||
OCTAVIA_CERTS_DIR=${OCTAVIA_CERTS_DIR:-${OCTAVIA_CONF_DIR}/certs}
|
OCTAVIA_CERTS_DIR=${OCTAVIA_CERTS_DIR:-${OCTAVIA_CONF_DIR}/certs}
|
||||||
OCTAVIA_DHCLIENT_DIR=${OCTAVIA_DHCLIENT_DIR:-${OCTAVIA_CONF_DIR}/dhcp}
|
OCTAVIA_DHCLIENT_DIR=${OCTAVIA_DHCLIENT_DIR:-${OCTAVIA_CONF_DIR}/dhcp}
|
||||||
@ -21,13 +22,11 @@ OCTAVIA_AMPHORA_DRIVER=${OCTAVIA_AMPHORA_DRIVER:-"amphora_haproxy_rest_driver"}
|
|||||||
OCTAVIA_NETWORK_DRIVER=${OCTAVIA_NETWORK_DRIVER:-"allowed_address_pairs_driver"}
|
OCTAVIA_NETWORK_DRIVER=${OCTAVIA_NETWORK_DRIVER:-"allowed_address_pairs_driver"}
|
||||||
OCTAVIA_COMPUTE_DRIVER=${OCTAVIA_COMPUTE_DRIVER:-"compute_nova_driver"}
|
OCTAVIA_COMPUTE_DRIVER=${OCTAVIA_COMPUTE_DRIVER:-"compute_nova_driver"}
|
||||||
|
|
||||||
OCTAVIA_ADMIN_USER=${OCTAVIA_ADMIN_USER:-"admin"}
|
OCTAVIA_USERNAME=${OCTAVIA_ADMIN_USER:-"admin"}
|
||||||
OCTAVIA_USER=${OCTAVIA_USER:-${OCTAVIA_ADMIN_USER}}
|
|
||||||
OCTAVIA_PASSWORD=${OCTAVIA_PASSWORD:-${ADMIN_PASSWORD}}
|
OCTAVIA_PASSWORD=${OCTAVIA_PASSWORD:-${ADMIN_PASSWORD}}
|
||||||
OCTAVIA_TENANT_ID=${OCTAVIA_TENANT_ID:-${ADMIN_TENANT_ID}}
|
OCTAVIA_PROJECT_NAME=${OCTAVIA_PROJECT_NAME:-$OCTAVIA_USERNAME}
|
||||||
OCTAVIA_AUTH_VERSION=${OCTAVIA_AUTH_VERSION:-"2"}
|
OCTAVIA_USER_DOMAIN_NAME=${OCTAVIA_USER_DOMAIN_NAME:-"Default"}
|
||||||
OCTAVIA_ADMIN_TENANT_NAME=${OCTAVIA_ADMIN_TENANT_NAME:-${OCTAVIA_ADMIN_USER}}
|
OCTAVIA_PROJECT_DOMAIN_NAME=${OCTAVIA_PROJECT_DOMAIN_NAME:-"Default"}
|
||||||
OCTAVIA_ADMIN_PASSWORD=${OCTAVIA_ADMIN_PASSWORD:-${ADMIN_PASSWORD}}
|
|
||||||
|
|
||||||
OCTAVIA_PROTOCOL=${OCTAVIA_PROTOCOL:-"http"}
|
OCTAVIA_PROTOCOL=${OCTAVIA_PROTOCOL:-"http"}
|
||||||
OCTAVIA_PORT=${OCTAVIA_PORT:-"9876"}
|
OCTAVIA_PORT=${OCTAVIA_PORT:-"9876"}
|
||||||
|
@ -47,8 +47,6 @@
|
|||||||
# noop_event_streamer
|
# noop_event_streamer
|
||||||
# event_streamer_driver = noop_event_streamer
|
# event_streamer_driver = noop_event_streamer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[keystone_authtoken]
|
[keystone_authtoken]
|
||||||
# This group of config options are imported from keystone middleware. Thus the
|
# This group of config options are imported from keystone middleware. Thus the
|
||||||
# option names should match the names declared in the middleware.
|
# option names should match the names declared in the middleware.
|
||||||
@ -59,11 +57,6 @@
|
|||||||
# insecure = False
|
# insecure = False
|
||||||
# cafile =
|
# cafile =
|
||||||
|
|
||||||
[keystone_authtoken_v3]
|
|
||||||
# If using Keystone v3
|
|
||||||
# admin_user_domain = default
|
|
||||||
# admin_project_domain = default
|
|
||||||
|
|
||||||
[certificates]
|
[certificates]
|
||||||
# cert_generator = local_cert_generator
|
# cert_generator = local_cert_generator
|
||||||
|
|
||||||
@ -238,22 +231,17 @@
|
|||||||
# vrrp_garp_refresh_interval = 5
|
# vrrp_garp_refresh_interval = 5
|
||||||
# vrrp_garp_refresh_count = 2
|
# vrrp_garp_refresh_count = 2
|
||||||
|
|
||||||
[glance]
|
[service_auth]
|
||||||
# The name of the glance service in the keystone catalog
|
# memcached_servers =
|
||||||
# service_name =
|
# signing_dir =
|
||||||
# Custom glance endpoint if override is necessary
|
# cafile = /opt/stack/data/ca-bundle.pem
|
||||||
# endpoint =
|
# project_domain_name = Default
|
||||||
|
# project_name = admin
|
||||||
# Region in Identity service catalog to use for communication with the OpenStack services.
|
# user_domain_name = Default
|
||||||
# region_name =
|
# password = password
|
||||||
|
# username = admin
|
||||||
# Endpoint type in Identity service catalog to use for communication with
|
# auth_type = password
|
||||||
# the OpenStack services.
|
# auth_url = http://localhost:5555/
|
||||||
# endpoint_type = publicURL
|
|
||||||
|
|
||||||
# CA certificates file to verify glance connections when TLS is enabled
|
|
||||||
# insecure = False
|
|
||||||
# ca_certificates_file =
|
|
||||||
|
|
||||||
[nova]
|
[nova]
|
||||||
# The name of the nova service in the keystone catalog
|
# The name of the nova service in the keystone catalog
|
||||||
@ -261,28 +249,44 @@
|
|||||||
# Custom nova endpoint if override is necessary
|
# Custom nova endpoint if override is necessary
|
||||||
# endpoint =
|
# endpoint =
|
||||||
|
|
||||||
# Region in Identity service catalog to use for communication with the OpenStack services.
|
# Region in Identity service catalog to use for communication with the
|
||||||
# region_name =
|
# OpenStack services.
|
||||||
|
# region_name =
|
||||||
# Endpoint type in Identity service catalog to use for communication with
|
|
||||||
# the OpenStack services.
|
# Endpoint type in Identity service catalog to use for communication with
|
||||||
# endpoint_type = publicURL
|
# the OpenStack services.
|
||||||
|
# endpoint_type = publicURL
|
||||||
# CA certificates file to verify nova connections when TLS is enabled
|
|
||||||
# insecure = False
|
# CA certificates file to verify neutron connections when TLS is enabled
|
||||||
# ca_certificates_file =
|
# insecure = False
|
||||||
|
# ca_certificates_file =
|
||||||
# Flag to enable nova anti-affinity capabilities to place amphorae on
|
|
||||||
# different hosts
|
[glance]
|
||||||
# enable_anti_affinity = False
|
# The name of the glance service in the keystone catalog
|
||||||
|
# service_name =
|
||||||
[neutron]
|
# Custom glance endpoint if override is necessary
|
||||||
# The name of the neutron service in the keystone catalog
|
# endpoint =
|
||||||
# service_name =
|
|
||||||
# Custom neutron endpoint if override is necessary
|
# Region in Identity service catalog to use for communication with the
|
||||||
# endpoint =
|
# OpenStack services.
|
||||||
|
# region_name =
|
||||||
# Region in Identity service catalog to use for communication with the OpenStack services.
|
|
||||||
|
# Endpoint type in Identity service catalog to use for communication with
|
||||||
|
# the OpenStack services.
|
||||||
|
# endpoint_type = publicURL
|
||||||
|
|
||||||
|
# CA certificates file to verify neutron connections when TLS is enabled
|
||||||
|
# insecure = False
|
||||||
|
# ca_certificates_file =
|
||||||
|
|
||||||
|
[neutron]
|
||||||
|
# The name of the neutron service in the keystone catalog
|
||||||
|
# service_name =
|
||||||
|
# Custom neutron endpoint if override is necessary
|
||||||
|
# endpoint =
|
||||||
|
|
||||||
|
# Region in Identity service catalog to use for communication with the
|
||||||
|
# OpenStack services.
|
||||||
# region_name =
|
# region_name =
|
||||||
|
|
||||||
# Endpoint type in Identity service catalog to use for communication with
|
# Endpoint type in Identity service catalog to use for communication with
|
||||||
|
@ -27,9 +27,7 @@ from octavia.i18n import _LE
|
|||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
CONF.import_group('certificates', 'octavia.common.config')
|
|
||||||
|
|
||||||
|
|
||||||
class BarbicanACLAuth(barbican_common.BarbicanAuth):
|
class BarbicanACLAuth(barbican_common.BarbicanAuth):
|
||||||
@ -39,8 +37,9 @@ class BarbicanACLAuth(barbican_common.BarbicanAuth):
|
|||||||
def get_barbican_client(cls, project_id=None):
|
def get_barbican_client(cls, project_id=None):
|
||||||
if not cls._barbican_client:
|
if not cls._barbican_client:
|
||||||
try:
|
try:
|
||||||
|
session = keystone.KeystoneSession().get_session()
|
||||||
cls._barbican_client = barbican_client.Client(
|
cls._barbican_client = barbican_client.Client(
|
||||||
session=keystone.get_session(),
|
session=session,
|
||||||
region_name=CONF.certificates.region_name,
|
region_name=CONF.certificates.region_name,
|
||||||
interface=CONF.certificates.endpoint_type
|
interface=CONF.certificates.endpoint_type
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,7 @@ from glanceclient import client as glance_client
|
|||||||
from neutronclient.neutron import client as neutron_client
|
from neutronclient.neutron import client as neutron_client
|
||||||
from novaclient import api_versions
|
from novaclient import api_versions
|
||||||
from novaclient import client as nova_client
|
from novaclient import client as nova_client
|
||||||
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
|
|
||||||
@ -21,6 +22,8 @@ from octavia.common import keystone
|
|||||||
from octavia.i18n import _LE
|
from octavia.i18n import _LE
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
GLANCE_VERSION = '2'
|
GLANCE_VERSION = '2'
|
||||||
NEUTRON_VERSION = '2.0'
|
NEUTRON_VERSION = '2.0'
|
||||||
NOVA_VERSION = '2.1'
|
NOVA_VERSION = '2.1'
|
||||||
@ -44,9 +47,10 @@ class NovaAuth(object):
|
|||||||
:return: a Nova Client object.
|
:return: a Nova Client object.
|
||||||
:raises Exception: if the client cannot be created
|
:raises Exception: if the client cannot be created
|
||||||
"""
|
"""
|
||||||
|
ksession = keystone.KeystoneSession()
|
||||||
if not cls.nova_client:
|
if not cls.nova_client:
|
||||||
kwargs = {'region_name': region,
|
kwargs = {'region_name': region,
|
||||||
'session': keystone.get_session(),
|
'session': ksession.get_session(),
|
||||||
'endpoint_type': endpoint_type,
|
'endpoint_type': endpoint_type,
|
||||||
'insecure': insecure}
|
'insecure': insecure}
|
||||||
if service_name:
|
if service_name:
|
||||||
@ -82,9 +86,10 @@ class NeutronAuth(object):
|
|||||||
:return: a Neutron Client object.
|
:return: a Neutron Client object.
|
||||||
:raises Exception: if the client cannot be created
|
:raises Exception: if the client cannot be created
|
||||||
"""
|
"""
|
||||||
|
ksession = keystone.KeystoneSession()
|
||||||
if not cls.neutron_client:
|
if not cls.neutron_client:
|
||||||
kwargs = {'region_name': region,
|
kwargs = {'region_name': region,
|
||||||
'session': keystone.get_session(),
|
'session': ksession.get_session(),
|
||||||
'endpoint_type': endpoint_type,
|
'endpoint_type': endpoint_type,
|
||||||
'insecure': insecure}
|
'insecure': insecure}
|
||||||
if service_name:
|
if service_name:
|
||||||
@ -120,9 +125,10 @@ class GlanceAuth(object):
|
|||||||
:return: a Glance Client object.
|
:return: a Glance Client object.
|
||||||
:raises Exception: if the client cannot be created
|
:raises Exception: if the client cannot be created
|
||||||
"""
|
"""
|
||||||
|
ksession = keystone.KeystoneSession()
|
||||||
if not cls.glance_client:
|
if not cls.glance_client:
|
||||||
kwargs = {'region_name': region,
|
kwargs = {'region_name': region,
|
||||||
'session': keystone.get_session(),
|
'session': ksession.get_session(),
|
||||||
'interface': endpoint_type}
|
'interface': endpoint_type}
|
||||||
if service_name:
|
if service_name:
|
||||||
kwargs['service_name'] = service_name
|
kwargs['service_name'] = service_name
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
Routines for configuring Octavia
|
Routines for configuring Octavia
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_db import options as db_options
|
from oslo_db import options as db_options
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -41,6 +42,7 @@ core_opts = [
|
|||||||
cfg.StrOpt('api_extensions_path', default="",
|
cfg.StrOpt('api_extensions_path', default="",
|
||||||
help=_("The path for API extensions")),
|
help=_("The path for API extensions")),
|
||||||
cfg.StrOpt('auth_strategy', default='keystone',
|
cfg.StrOpt('auth_strategy', default='keystone',
|
||||||
|
choices=('noauth', 'keystone'),
|
||||||
help=_("The type of authentication to use")),
|
help=_("The type of authentication to use")),
|
||||||
cfg.BoolOpt('allow_bulk', default=True,
|
cfg.BoolOpt('allow_bulk', default=True,
|
||||||
help=_("Allow the usage of the bulk API")),
|
help=_("Allow the usage of the bulk API")),
|
||||||
@ -142,13 +144,6 @@ oslo_messaging_opts = [
|
|||||||
help=_('topic name for communicating events through a queue')),
|
help=_('topic name for communicating events through a queue')),
|
||||||
]
|
]
|
||||||
|
|
||||||
keystone_authtoken_v3_opts = [
|
|
||||||
cfg.StrOpt('admin_user_domain', default='default',
|
|
||||||
help=_('Admin user keystone authentication domain')),
|
|
||||||
cfg.StrOpt('admin_project_domain', default='default',
|
|
||||||
help=_('Admin project keystone authentication domain'))
|
|
||||||
]
|
|
||||||
|
|
||||||
haproxy_amphora_opts = [
|
haproxy_amphora_opts = [
|
||||||
cfg.StrOpt('base_path',
|
cfg.StrOpt('base_path',
|
||||||
default='/var/lib/octavia',
|
default='/var/lib/octavia',
|
||||||
@ -289,12 +284,22 @@ certificate_opts = [
|
|||||||
cfg.StrOpt('barbican_auth',
|
cfg.StrOpt('barbican_auth',
|
||||||
default='barbican_acl_auth',
|
default='barbican_acl_auth',
|
||||||
help='Name of the Barbican authentication method to use'),
|
help='Name of the Barbican authentication method to use'),
|
||||||
|
cfg.StrOpt('service_name',
|
||||||
|
help=_('The name of the certificate service in the keystone'
|
||||||
|
'catalog')),
|
||||||
|
cfg.StrOpt('endpoint', help=_('A new endpoint to override the endpoint '
|
||||||
|
'in the keystone catalog.')),
|
||||||
cfg.StrOpt('region_name',
|
cfg.StrOpt('region_name',
|
||||||
help='Region in Identity service catalog to use for '
|
help='Region in Identity service catalog to use for '
|
||||||
'communication with the barbican service.'),
|
'communication with the barbican service.'),
|
||||||
cfg.StrOpt('endpoint_type',
|
cfg.StrOpt('endpoint_type',
|
||||||
default='publicURL',
|
default='publicURL',
|
||||||
help='The endpoint_type to be used for barbican service.')
|
help='The endpoint_type to be used for barbican service.'),
|
||||||
|
cfg.StrOpt('ca_certificates_file',
|
||||||
|
help=_('CA certificates file path')),
|
||||||
|
cfg.BoolOpt('insecure',
|
||||||
|
default=False,
|
||||||
|
help=_('Disable certificate validation on SSL connections ')),
|
||||||
]
|
]
|
||||||
|
|
||||||
house_keeping_opts = [
|
house_keeping_opts = [
|
||||||
@ -436,9 +441,6 @@ cfg.CONF.register_opts(anchor_opts, group='anchor')
|
|||||||
cfg.CONF.register_cli_opts(core_cli_opts)
|
cfg.CONF.register_cli_opts(core_cli_opts)
|
||||||
cfg.CONF.register_opts(certificate_opts, group='certificates')
|
cfg.CONF.register_opts(certificate_opts, group='certificates')
|
||||||
cfg.CONF.register_cli_opts(healthmanager_opts, group='health_manager')
|
cfg.CONF.register_cli_opts(healthmanager_opts, group='health_manager')
|
||||||
cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token')
|
|
||||||
cfg.CONF.register_opts(keystone_authtoken_v3_opts,
|
|
||||||
group='keystone_authtoken_v3')
|
|
||||||
cfg.CONF.register_opts(nova_opts, group='nova')
|
cfg.CONF.register_opts(nova_opts, group='nova')
|
||||||
cfg.CONF.register_opts(glance_opts, group='glance')
|
cfg.CONF.register_opts(glance_opts, group='glance')
|
||||||
cfg.CONF.register_opts(neutron_opts, group='neutron')
|
cfg.CONF.register_opts(neutron_opts, group='neutron')
|
||||||
@ -454,6 +456,9 @@ db_options.set_defaults(cfg.CONF, connection=_SQL_CONNECTION_DEFAULT,
|
|||||||
|
|
||||||
logging.register_options(cfg.CONF)
|
logging.register_options(cfg.CONF)
|
||||||
|
|
||||||
|
ks_loading.register_auth_conf_options(cfg.CONF, constants.SERVICE_AUTH)
|
||||||
|
ks_loading.register_session_conf_options(cfg.CONF, constants.SERVICE_AUTH)
|
||||||
|
|
||||||
|
|
||||||
def init(args, **kwargs):
|
def init(args, **kwargs):
|
||||||
cfg.CONF(args=args, project='octavia',
|
cfg.CONF(args=args, project='octavia',
|
||||||
@ -469,30 +474,3 @@ def setup_logging(conf):
|
|||||||
product_name = "octavia"
|
product_name = "octavia"
|
||||||
logging.setup(conf, product_name)
|
logging.setup(conf, product_name)
|
||||||
LOG.info(_LI("Logging enabled!"))
|
LOG.info(_LI("Logging enabled!"))
|
||||||
|
|
||||||
|
|
||||||
# def load_paste_app(app_name):
|
|
||||||
# """Builds and returns a WSGI app from a paste config file.
|
|
||||||
|
|
||||||
# :param app_name: Name of the application to load
|
|
||||||
# :raises ConfigFilesNotFoundError when config file cannot be located
|
|
||||||
# :raises RuntimeError when application cannot be loaded from config file
|
|
||||||
# """
|
|
||||||
|
|
||||||
# config_path = cfg.CONF.find_file(cfg.CONF.api_paste_config)
|
|
||||||
# if not config_path:
|
|
||||||
# raise cfg.ConfigFilesNotFoundError(
|
|
||||||
# config_files=[cfg.CONF.api_paste_config])
|
|
||||||
# config_path = os.path.abspath(config_path)
|
|
||||||
# LOG.info(_LI("Config paste file: %s"), config_path)
|
|
||||||
|
|
||||||
# try:
|
|
||||||
# app = deploy.loadapp("config:%s" % config_path, name=app_name)
|
|
||||||
# except (LookupError, ImportError):
|
|
||||||
# msg = (_("Unable to load %(app_name)s from "
|
|
||||||
# "configuration file %(config_path)s.") %
|
|
||||||
# {'app_name': app_name,
|
|
||||||
# 'config_path': config_path})
|
|
||||||
# LOG.exception(msg)
|
|
||||||
# raise RuntimeError(msg)
|
|
||||||
# return app
|
|
||||||
|
@ -252,6 +252,9 @@ NOVA_21 = '2.1'
|
|||||||
NOVA_3 = '3'
|
NOVA_3 = '3'
|
||||||
NOVA_VERSIONS = (NOVA_1, NOVA_21, NOVA_3)
|
NOVA_VERSIONS = (NOVA_1, NOVA_21, NOVA_3)
|
||||||
|
|
||||||
|
# Auth sections
|
||||||
|
SERVICE_AUTH = 'service_auth'
|
||||||
|
|
||||||
RPC_NAMESPACE_CONTROLLER_AGENT = 'controller'
|
RPC_NAMESPACE_CONTROLLER_AGENT = 'controller'
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,59 +12,32 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from keystoneauth1.identity import v2 as v2_client
|
from keystoneauth1 import loading as ks_loading
|
||||||
from keystoneauth1.identity import v3 as v3_client
|
|
||||||
from keystoneauth1 import session
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
|
||||||
|
|
||||||
from octavia.i18n import _LE
|
|
||||||
|
|
||||||
|
from octavia.common import constants
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token')
|
|
||||||
cfg.CONF.import_group('keystone_authtoken_v3', 'octavia.common.config')
|
|
||||||
|
|
||||||
_SESSION = None
|
class KeystoneSession:
|
||||||
|
|
||||||
|
def __init__(self, section=constants.SERVICE_AUTH):
|
||||||
|
self._session = None
|
||||||
|
self.section = section
|
||||||
|
ks_loading.register_auth_conf_options(cfg.CONF, self.section)
|
||||||
|
ks_loading.register_session_conf_options(cfg.CONF, self.section)
|
||||||
|
|
||||||
def get_session():
|
def get_session(self):
|
||||||
"""Initializes a Keystone session.
|
"""Initializes a Keystone session.
|
||||||
|
|
||||||
:return: a Keystone Session object
|
:return: a Keystone Session object
|
||||||
:raises Exception: if the session cannot be established
|
"""
|
||||||
"""
|
if not self._session:
|
||||||
global _SESSION
|
self._auth = ks_loading.load_auth_from_conf_options(
|
||||||
if not _SESSION:
|
cfg.CONF, self.section)
|
||||||
|
self._session = ks_loading.load_session_from_conf_options(
|
||||||
|
cfg.CONF, self.section, auth=self._auth)
|
||||||
|
|
||||||
kwargs = {'auth_url': cfg.CONF.keystone_authtoken.auth_uri,
|
return self._session
|
||||||
'username': cfg.CONF.keystone_authtoken.admin_user,
|
|
||||||
'password': cfg.CONF.keystone_authtoken.admin_password}
|
|
||||||
|
|
||||||
if cfg.CONF.keystone_authtoken.auth_version == '2':
|
|
||||||
client = v2_client
|
|
||||||
kwargs['tenant_name'] = (cfg.CONF.keystone_authtoken.
|
|
||||||
admin_tenant_name)
|
|
||||||
elif cfg.CONF.keystone_authtoken.auth_version == '3':
|
|
||||||
client = v3_client
|
|
||||||
kwargs['project_name'] = (cfg.CONF.keystone_authtoken.
|
|
||||||
admin_tenant_name)
|
|
||||||
kwargs['user_domain_name'] = (cfg.CONF.keystone_authtoken_v3.
|
|
||||||
admin_user_domain)
|
|
||||||
kwargs['project_domain_name'] = (cfg.CONF.keystone_authtoken_v3.
|
|
||||||
admin_project_domain)
|
|
||||||
else:
|
|
||||||
raise Exception('Unknown keystone version!')
|
|
||||||
|
|
||||||
try:
|
|
||||||
kc = client.Password(**kwargs)
|
|
||||||
_SESSION = session.Session(
|
|
||||||
auth=kc, verify=(cfg.CONF.keystone_authtoken.cafile or
|
|
||||||
not cfg.CONF.keystone_authtoken.insecure))
|
|
||||||
except Exception:
|
|
||||||
with excutils.save_and_reraise_exception():
|
|
||||||
LOG.exception(_LE("Error creating Keystone session."))
|
|
||||||
|
|
||||||
return _SESSION
|
|
||||||
|
@ -26,10 +26,7 @@ from octavia.i18n import _LE, _LW
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
CONF.import_group('glance', 'octavia.common.config')
|
|
||||||
CONF.import_group('keystone_authtoken', 'octavia.common.config')
|
|
||||||
CONF.import_group('networking', 'octavia.common.config')
|
CONF.import_group('networking', 'octavia.common.config')
|
||||||
CONF.import_group('nova', 'octavia.common.config')
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_amp_image_id_by_tag(client, image_tag, image_owner):
|
def _extract_amp_image_id_by_tag(client, image_tag, image_owner):
|
||||||
|
@ -29,7 +29,6 @@ DNS_INT_EXT_ALIAS = 'dns-integration'
|
|||||||
SEC_GRP_EXT_ALIAS = 'security-group'
|
SEC_GRP_EXT_ALIAS = 'security-group'
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
CONF.import_group('neutron', 'octavia.common.config')
|
|
||||||
|
|
||||||
|
|
||||||
class BaseNeutronDriver(base.AbstractNetworkDriver):
|
class BaseNeutronDriver(base.AbstractNetworkDriver):
|
||||||
|
@ -10,9 +10,15 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import copy
|
||||||
import itertools
|
import itertools
|
||||||
|
import operator
|
||||||
|
|
||||||
|
from keystoneauth1 import loading as ks_loading
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
import octavia.common.config
|
import octavia.common.config
|
||||||
|
from octavia.common import constants
|
||||||
|
|
||||||
|
|
||||||
def list_opts():
|
def list_opts():
|
||||||
@ -22,13 +28,31 @@ def list_opts():
|
|||||||
('amphora_agent', octavia.common.config.amphora_agent_opts),
|
('amphora_agent', octavia.common.config.amphora_agent_opts),
|
||||||
('networking', octavia.common.config.networking_opts),
|
('networking', octavia.common.config.networking_opts),
|
||||||
('oslo_messaging', octavia.common.config.oslo_messaging_opts),
|
('oslo_messaging', octavia.common.config.oslo_messaging_opts),
|
||||||
('keystone_authtoken_v3',
|
|
||||||
octavia.common.config.keystone_authtoken_v3_opts),
|
|
||||||
('haproxy_amphora', octavia.common.config.haproxy_amphora_opts),
|
('haproxy_amphora', octavia.common.config.haproxy_amphora_opts),
|
||||||
('health_manager', octavia.common.config.healthmanager_opts),
|
('health_manager', octavia.common.config.healthmanager_opts),
|
||||||
('controller_worker', octavia.common.config.controller_worker_opts),
|
('controller_worker', octavia.common.config.controller_worker_opts),
|
||||||
('task_flow', octavia.common.config.task_flow_opts),
|
('task_flow', octavia.common.config.task_flow_opts),
|
||||||
('certificates', octavia.common.config.certificate_opts),
|
('certificates', octavia.common.config.certificate_opts),
|
||||||
('house_keeping', octavia.common.config.house_keeping_opts),
|
('house_keeping', octavia.common.config.house_keeping_opts),
|
||||||
('keepalived_vrrp', octavia.common.config.keepalived_vrrp_opts)
|
('keepalived_vrrp', octavia.common.config.keepalived_vrrp_opts),
|
||||||
|
('nova', octavia.common.config.nova_opts),
|
||||||
|
('neutron', octavia.common.config.neutron_opts),
|
||||||
|
('glance', octavia.common.config.glance_opts),
|
||||||
|
add_auth_opts(),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def add_auth_opts():
|
||||||
|
opts = ks_loading.register_session_conf_options(
|
||||||
|
cfg.CONF, constants.SERVICE_AUTH)
|
||||||
|
opt_list = copy.deepcopy(opts)
|
||||||
|
opt_list.insert(0, ks_loading.get_auth_common_conf_options()[0])
|
||||||
|
# NOTE(mhickey): There are a lot of auth plugins, we just generate
|
||||||
|
# the config options for a few common ones
|
||||||
|
plugins = ['password', 'v2password', 'v3password']
|
||||||
|
for name in plugins:
|
||||||
|
for plugin_option in ks_loading.get_auth_plugin_conf_options(name):
|
||||||
|
if all(option.name != plugin_option.name for option in opt_list):
|
||||||
|
opt_list.append(plugin_option)
|
||||||
|
opt_list.sort(key=operator.attrgetter('name'))
|
||||||
|
return (constants.SERVICE_AUTH, opt_list)
|
||||||
|
@ -36,12 +36,9 @@ class TestBarbicanACLAuth(base.TestCase):
|
|||||||
conf.config(group="certificates", endpoint_type='publicURL')
|
conf.config(group="certificates", endpoint_type='publicURL')
|
||||||
super(TestBarbicanACLAuth, self).setUp()
|
super(TestBarbicanACLAuth, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch('keystoneauth1.session.Session', mock.Mock())
|
||||||
def test_get_barbican_client(self):
|
def test_get_barbican_client(self):
|
||||||
# There should be no existing client
|
|
||||||
self.assertIsNone(keystone._SESSION)
|
|
||||||
|
|
||||||
# Mock out the keystone session and get the client
|
# Mock out the keystone session and get the client
|
||||||
keystone._SESSION = mock.MagicMock()
|
|
||||||
acl_auth_object = barbican_acl.BarbicanACLAuth()
|
acl_auth_object = barbican_acl.BarbicanACLAuth()
|
||||||
bc1 = acl_auth_object.get_barbican_client()
|
bc1 = acl_auth_object.get_barbican_client()
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import mock
|
|||||||
import neutronclient.v2_0
|
import neutronclient.v2_0
|
||||||
import novaclient.v2
|
import novaclient.v2
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_config import fixture as oslo_fixture
|
|
||||||
|
|
||||||
from octavia.common import clients
|
from octavia.common import clients
|
||||||
from octavia.common import keystone
|
from octavia.common import keystone
|
||||||
@ -27,15 +26,13 @@ CONF = cfg.CONF
|
|||||||
class TestNovaAuth(base.TestCase):
|
class TestNovaAuth(base.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
|
||||||
conf.config(group="keystone_authtoken", auth_version='2')
|
|
||||||
|
|
||||||
# Reset the session and client
|
# Reset the session and client
|
||||||
clients.NovaAuth.nova_client = None
|
clients.NovaAuth.nova_client = None
|
||||||
keystone._SESSION = None
|
keystone._SESSION = None
|
||||||
|
|
||||||
super(TestNovaAuth, self).setUp()
|
super(TestNovaAuth, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch('keystoneauth1.session.Session', mock.Mock())
|
||||||
def test_get_nova_client(self):
|
def test_get_nova_client(self):
|
||||||
# There should be no existing client
|
# There should be no existing client
|
||||||
self.assertIsNone(
|
self.assertIsNone(
|
||||||
@ -67,15 +64,13 @@ class TestNovaAuth(base.TestCase):
|
|||||||
class TestNeutronAuth(base.TestCase):
|
class TestNeutronAuth(base.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
|
||||||
conf.config(group="keystone_authtoken", auth_version='2')
|
|
||||||
|
|
||||||
# Reset the session and client
|
# Reset the session and client
|
||||||
clients.NeutronAuth.neutron_client = None
|
clients.NeutronAuth.neutron_client = None
|
||||||
keystone._SESSION = None
|
keystone._SESSION = None
|
||||||
|
|
||||||
super(TestNeutronAuth, self).setUp()
|
super(TestNeutronAuth, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch('keystoneauth1.session.Session', mock.Mock())
|
||||||
def test_get_neutron_client(self):
|
def test_get_neutron_client(self):
|
||||||
# There should be no existing client
|
# There should be no existing client
|
||||||
self.assertIsNone(
|
self.assertIsNone(
|
||||||
@ -107,15 +102,13 @@ class TestNeutronAuth(base.TestCase):
|
|||||||
class TestGlanceAuth(base.TestCase):
|
class TestGlanceAuth(base.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
|
||||||
conf.config(group="keystone_authtoken", auth_version='2')
|
|
||||||
|
|
||||||
# Reset the session and client
|
# Reset the session and client
|
||||||
clients.GlanceAuth.glance_client = None
|
clients.GlanceAuth.glance_client = None
|
||||||
keystone._SESSION = None
|
keystone._SESSION = None
|
||||||
|
|
||||||
super(TestGlanceAuth, self).setUp()
|
super(TestGlanceAuth, self).setUp()
|
||||||
|
|
||||||
|
@mock.patch('keystoneauth1.session.Session', mock.Mock())
|
||||||
def test_get_glance_client(self):
|
def test_get_glance_client(self):
|
||||||
# There should be no existing client
|
# There should be no existing client
|
||||||
self.assertIsNone(
|
self.assertIsNone(
|
||||||
|
@ -91,7 +91,6 @@ class TestNovaClient(base.TestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||||
conf.config(group="keystone_authtoken", auth_version='2')
|
|
||||||
self.net_name = "lb-mgmt-net"
|
self.net_name = "lb-mgmt-net"
|
||||||
conf.config(group="networking", lb_network_name=self.net_name)
|
conf.config(group="networking", lb_network_name=self.net_name)
|
||||||
conf.config(group="controller_worker", amp_boot_network_list=[1, 2])
|
conf.config(group="controller_worker", amp_boot_network_list=[1, 2])
|
||||||
|
@ -33,7 +33,6 @@ class TestAmphoraFlows(base.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestAmphoraFlows, self).setUp()
|
super(TestAmphoraFlows, self).setUp()
|
||||||
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
self.conf = self.useFixture(oslo_fixture.Config(cfg.CONF))
|
||||||
self.conf.config(group="keystone_authtoken", auth_version=AUTH_VERSION)
|
|
||||||
self.conf.config(
|
self.conf.config(
|
||||||
group="controller_worker",
|
group="controller_worker",
|
||||||
amphora_driver='amphora_haproxy_rest_driver')
|
amphora_driver='amphora_haproxy_rest_driver')
|
||||||
|
@ -36,7 +36,6 @@ AMPHORA_ID = uuidutils.generate_uuid()
|
|||||||
COMPUTE_ID = uuidutils.generate_uuid()
|
COMPUTE_ID = uuidutils.generate_uuid()
|
||||||
LB_NET_IP = '192.0.2.1'
|
LB_NET_IP = '192.0.2.1'
|
||||||
PORT_ID = uuidutils.generate_uuid()
|
PORT_ID = uuidutils.generate_uuid()
|
||||||
AUTH_VERSION = '2'
|
|
||||||
SERVER_GRPOUP_ID = uuidutils.generate_uuid()
|
SERVER_GRPOUP_ID = uuidutils.generate_uuid()
|
||||||
|
|
||||||
|
|
||||||
@ -70,7 +69,6 @@ class TestComputeTasks(base.TestCase):
|
|||||||
conf.config(group="controller_worker", amp_active_wait_sec=AMP_WAIT)
|
conf.config(group="controller_worker", amp_active_wait_sec=AMP_WAIT)
|
||||||
conf.config(group="controller_worker",
|
conf.config(group="controller_worker",
|
||||||
amp_secgroup_list=AMP_SEC_GROUPS)
|
amp_secgroup_list=AMP_SEC_GROUPS)
|
||||||
conf.config(group="keystone_authtoken", auth_version=AUTH_VERSION)
|
|
||||||
conf.config(group="controller_worker", amp_image_owner_id='')
|
conf.config(group="controller_worker", amp_image_owner_id='')
|
||||||
|
|
||||||
_amphora_mock.id = AMPHORA_ID
|
_amphora_mock.id = AMPHORA_ID
|
||||||
|
@ -70,7 +70,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
self.k_session = mock.patch(
|
self.k_session = mock.patch(
|
||||||
'octavia.common.keystone.get_session').start()
|
'keystoneauth1.session.Session').start()
|
||||||
self.driver = allowed_address_pairs.AllowedAddressPairsDriver()
|
self.driver = allowed_address_pairs.AllowedAddressPairsDriver()
|
||||||
|
|
||||||
@mock.patch('octavia.network.drivers.neutron.base.BaseNeutronDriver.'
|
@mock.patch('octavia.network.drivers.neutron.base.BaseNeutronDriver.'
|
||||||
|
@ -49,7 +49,7 @@ class TestBaseNeutronNetworkDriver(base.TestCase):
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
self.k_session = mock.patch(
|
self.k_session = mock.patch(
|
||||||
'octavia.common.keystone.get_session').start()
|
'keystoneauth1.session.Session').start()
|
||||||
self.driver = self._instantiate_partial_abc(
|
self.driver = self._instantiate_partial_abc(
|
||||||
neutron_base.BaseNeutronDriver)
|
neutron_base.BaseNeutronDriver)
|
||||||
|
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
prelude: >
|
||||||
|
Extended support for Keystone API v3.
|
||||||
|
features:
|
||||||
|
- Octavia supports different Keystone APIs and choose authentication
|
||||||
|
mechanism based on configuration specified in "keystone_authtoken" section
|
||||||
|
of octavia.conf file.
|
||||||
|
upgrade:
|
||||||
|
- From configuration file section "keystone_authtoken_v3" was removed and all
|
||||||
|
parameters are stored in "keystone_authtoken" section of configuration
|
||||||
|
file.
|
Loading…
Reference in New Issue
Block a user