drop key distribution from icehouse
key distribution is being continued in feature branch here: https://github.com/openstack/keystone/tree/feature/key-dist Change-Id: I47504bec73dd7e1a6419a5509093a9d494d90108
This commit is contained in:
committed by
Morgan Fainberg
parent
7d919df6c6
commit
dd18e86ff6
@@ -1,238 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.contrib.kds.common.service
|
|
||||||
#
|
|
||||||
|
|
||||||
# IP for the server to bind to (string value)
|
|
||||||
#bind_ip=0.0.0.0
|
|
||||||
|
|
||||||
# The port for the server (integer value)
|
|
||||||
#port=9109
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.db.sqlalchemy.session
|
|
||||||
#
|
|
||||||
|
|
||||||
# the filename to use with sqlite (string value)
|
|
||||||
#sqlite_db=keystone.sqlite
|
|
||||||
|
|
||||||
# If true, use synchronous mode for sqlite (boolean value)
|
|
||||||
#sqlite_synchronous=true
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.eventlet_backdoor
|
|
||||||
#
|
|
||||||
|
|
||||||
# Enable eventlet backdoor. Acceptable values are 0, <port>,
|
|
||||||
# and <start>:<end>, where 0 results in listening on a random
|
|
||||||
# tcp port number; <port> results in listening on the
|
|
||||||
# specified port number (and not enabling backdoor if that
|
|
||||||
# port is in use); and <start>:<end> results in listening on
|
|
||||||
# the smallest unused port number within the specified range
|
|
||||||
# of port numbers. The chosen port is displayed in the
|
|
||||||
# service's log file. (string value)
|
|
||||||
#backdoor_port=<None>
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.lockutils
|
|
||||||
#
|
|
||||||
|
|
||||||
# Whether to disable inter-process locks (boolean value)
|
|
||||||
#disable_process_locking=false
|
|
||||||
|
|
||||||
# Directory to use for lock files. (string value)
|
|
||||||
#lock_path=<None>
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.log
|
|
||||||
#
|
|
||||||
|
|
||||||
# Print debugging output (set logging level to DEBUG instead
|
|
||||||
# of default WARNING level). (boolean value)
|
|
||||||
#debug=false
|
|
||||||
|
|
||||||
# Print more verbose output (set logging level to INFO instead
|
|
||||||
# of default WARNING level). (boolean value)
|
|
||||||
#verbose=false
|
|
||||||
|
|
||||||
# Log output to standard error (boolean value)
|
|
||||||
#use_stderr=true
|
|
||||||
|
|
||||||
# format string to use for log messages with context (string
|
|
||||||
# value)
|
|
||||||
#logging_context_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s] %(instance)s%(message)s
|
|
||||||
|
|
||||||
# format string to use for log messages without context
|
|
||||||
# (string value)
|
|
||||||
#logging_default_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
|
|
||||||
|
|
||||||
# data to append to log format when level is DEBUG (string
|
|
||||||
# value)
|
|
||||||
#logging_debug_format_suffix=%(funcName)s %(pathname)s:%(lineno)d
|
|
||||||
|
|
||||||
# prefix each line of exception output with this format
|
|
||||||
# (string value)
|
|
||||||
#logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
|
|
||||||
|
|
||||||
# list of logger=LEVEL pairs (list value)
|
|
||||||
#default_log_levels=amqp=WARN,amqplib=WARN,boto=WARN,keystone=INFO,qpid=WARN,sqlalchemy=WARN,suds=INFO,iso8601=WARN
|
|
||||||
|
|
||||||
# publish error events (boolean value)
|
|
||||||
#publish_errors=false
|
|
||||||
|
|
||||||
# make deprecations fatal (boolean value)
|
|
||||||
#fatal_deprecations=false
|
|
||||||
|
|
||||||
# If an instance is passed with the log message, format it
|
|
||||||
# like this (string value)
|
|
||||||
#instance_format="[instance: %(uuid)s] "
|
|
||||||
|
|
||||||
# If an instance UUID is passed with the log message, format
|
|
||||||
# it like this (string value)
|
|
||||||
#instance_uuid_format="[instance: %(uuid)s] "
|
|
||||||
|
|
||||||
# The name of logging configuration file. It does not disable
|
|
||||||
# existing loggers, but just appends specified logging
|
|
||||||
# configuration to any other existing logging options. Please
|
|
||||||
# see the Python logging module documentation for details on
|
|
||||||
# logging configuration files. (string value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/log_config
|
|
||||||
#log_config_append=<None>
|
|
||||||
|
|
||||||
# DEPRECATED. A logging.Formatter log message format string
|
|
||||||
# which may use any of the available logging.LogRecord
|
|
||||||
# attributes. This option is deprecated. Please use
|
|
||||||
# logging_context_format_string and
|
|
||||||
# logging_default_format_string instead. (string value)
|
|
||||||
#log_format=<None>
|
|
||||||
|
|
||||||
# Format string for %%(asctime)s in log records. Default:
|
|
||||||
# %(default)s (string value)
|
|
||||||
#log_date_format=%Y-%m-%d %H:%M:%S
|
|
||||||
|
|
||||||
# (Optional) Name of log file to output to. If no default is
|
|
||||||
# set, logging will go to stdout. (string value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/logfile
|
|
||||||
#log_file=<None>
|
|
||||||
|
|
||||||
# (Optional) The base directory used for relative --log-file
|
|
||||||
# paths (string value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/logdir
|
|
||||||
#log_dir=<None>
|
|
||||||
|
|
||||||
# Use syslog for logging. (boolean value)
|
|
||||||
#use_syslog=false
|
|
||||||
|
|
||||||
# syslog facility to receive log lines (string value)
|
|
||||||
#syslog_log_facility=LOG_USER
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.policy
|
|
||||||
#
|
|
||||||
|
|
||||||
# JSON file containing policy (string value)
|
|
||||||
#policy_file=policy.json
|
|
||||||
|
|
||||||
# Rule enforced when requested rule is not found (string
|
|
||||||
# value)
|
|
||||||
#policy_default_rule=default
|
|
||||||
|
|
||||||
[ssl]
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.sslutils
|
|
||||||
#
|
|
||||||
|
|
||||||
# CA certificate file to use to verify connecting clients
|
|
||||||
# (string value)
|
|
||||||
#ca_file=<None>
|
|
||||||
|
|
||||||
# Certificate file to use when starting the server securely
|
|
||||||
# (string value)
|
|
||||||
#cert_file=<None>
|
|
||||||
|
|
||||||
# Private key file to use when starting the server securely
|
|
||||||
# (string value)
|
|
||||||
#key_file=<None>
|
|
||||||
|
|
||||||
[database]
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.db.api
|
|
||||||
#
|
|
||||||
|
|
||||||
# The backend to use for db (string value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/db_backend
|
|
||||||
#backend=sqlalchemy
|
|
||||||
|
|
||||||
# Enable the experimental use of thread pooling for all DB API
|
|
||||||
# calls (boolean value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/dbapi_use_tpool
|
|
||||||
#use_tpool=false
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.db.sqlalchemy.session
|
|
||||||
#
|
|
||||||
|
|
||||||
# The SQLAlchemy connection string used to connect to the
|
|
||||||
# database (string value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_connection
|
|
||||||
# Deprecated group/name - [DATABASE]/sql_connection
|
|
||||||
# Deprecated group/name - [sql]/connection
|
|
||||||
#connection=sqlite:////keystone/openstack/common/db/$sqlite_db
|
|
||||||
|
|
||||||
# The SQLAlchemy connection string used to connect to the
|
|
||||||
# slave database (string value)
|
|
||||||
#slave_connection=
|
|
||||||
|
|
||||||
# timeout before idle sql connections are reaped (integer
|
|
||||||
# value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_idle_timeout
|
|
||||||
# Deprecated group/name - [DATABASE]/sql_idle_timeout
|
|
||||||
#idle_timeout=3600
|
|
||||||
|
|
||||||
# Minimum number of SQL connections to keep open in a pool
|
|
||||||
# (integer value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_min_pool_size
|
|
||||||
# Deprecated group/name - [DATABASE]/sql_min_pool_size
|
|
||||||
#min_pool_size=1
|
|
||||||
|
|
||||||
# Maximum number of SQL connections to keep open in a pool
|
|
||||||
# (integer value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_max_pool_size
|
|
||||||
# Deprecated group/name - [DATABASE]/sql_max_pool_size
|
|
||||||
#max_pool_size=<None>
|
|
||||||
|
|
||||||
# maximum db connection retries during startup. (setting -1
|
|
||||||
# implies an infinite retry count) (integer value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_max_retries
|
|
||||||
# Deprecated group/name - [DATABASE]/sql_max_retries
|
|
||||||
#max_retries=10
|
|
||||||
|
|
||||||
# interval between retries of opening a sql connection
|
|
||||||
# (integer value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_retry_interval
|
|
||||||
# Deprecated group/name - [DATABASE]/reconnect_interval
|
|
||||||
#retry_interval=10
|
|
||||||
|
|
||||||
# If set, use this value for max_overflow with sqlalchemy
|
|
||||||
# (integer value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_max_overflow
|
|
||||||
# Deprecated group/name - [DATABASE]/sqlalchemy_max_overflow
|
|
||||||
#max_overflow=<None>
|
|
||||||
|
|
||||||
# Verbosity of SQL debugging information. 0=None,
|
|
||||||
# 100=Everything (integer value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_connection_debug
|
|
||||||
#connection_debug=0
|
|
||||||
|
|
||||||
# Add python stack traces to SQL as comment strings (boolean
|
|
||||||
# value)
|
|
||||||
# Deprecated group/name - [DEFAULT]/sql_connection_trace
|
|
||||||
#connection_trace=false
|
|
||||||
|
|
||||||
# If set, use this value for pool_timeout with sqlalchemy
|
|
||||||
# (integer value)
|
|
||||||
# Deprecated group/name - [DATABASE]/sqlalchemy_pool_timeout
|
|
||||||
#pool_timeout=<None>
|
|
||||||
@@ -109,40 +109,40 @@
|
|||||||
# Auto-delete queues in amqp. (boolean value)
|
# Auto-delete queues in amqp. (boolean value)
|
||||||
#amqp_auto_delete=false
|
#amqp_auto_delete=false
|
||||||
|
|
||||||
# Size of RPC connection pool (integer value)
|
# Size of RPC connection pool. (integer value)
|
||||||
#rpc_conn_pool_size=30
|
#rpc_conn_pool_size=30
|
||||||
|
|
||||||
# Modules of exceptions that are permitted to be recreatedupon
|
# Modules of exceptions that are permitted to be recreated
|
||||||
# receiving exception data from an rpc call. (list value)
|
# upon receiving exception data from an rpc call. (list value)
|
||||||
#allowed_rpc_exception_modules=oslo.messaging.exceptions,nova.exception,cinder.exception,exceptions
|
#allowed_rpc_exception_modules=oslo.messaging.exceptions,nova.exception,cinder.exception,exceptions
|
||||||
|
|
||||||
# Qpid broker hostname (string value)
|
# Qpid broker hostname. (string value)
|
||||||
#qpid_hostname=localhost
|
#qpid_hostname=localhost
|
||||||
|
|
||||||
# Qpid broker port (integer value)
|
# Qpid broker port. (integer value)
|
||||||
#qpid_port=5672
|
#qpid_port=5672
|
||||||
|
|
||||||
# Qpid HA cluster host:port pairs (list value)
|
# Qpid HA cluster host:port pairs. (list value)
|
||||||
#qpid_hosts=$qpid_hostname:$qpid_port
|
#qpid_hosts=$qpid_hostname:$qpid_port
|
||||||
|
|
||||||
# Username for Qpid connection (string value)
|
# Username for Qpid connection. (string value)
|
||||||
#qpid_username=
|
#qpid_username=
|
||||||
|
|
||||||
# Password for Qpid connection (string value)
|
# Password for Qpid connection. (string value)
|
||||||
#qpid_password=
|
#qpid_password=
|
||||||
|
|
||||||
# Space separated list of SASL mechanisms to use for auth
|
# Space separated list of SASL mechanisms to use for auth.
|
||||||
# (string value)
|
# (string value)
|
||||||
#qpid_sasl_mechanisms=
|
#qpid_sasl_mechanisms=
|
||||||
|
|
||||||
# Seconds between connection keepalive heartbeats (integer
|
# Seconds between connection keepalive heartbeats. (integer
|
||||||
# value)
|
# value)
|
||||||
#qpid_heartbeat=60
|
#qpid_heartbeat=60
|
||||||
|
|
||||||
# Transport to use, either 'tcp' or 'ssl' (string value)
|
# Transport to use, either 'tcp' or 'ssl'. (string value)
|
||||||
#qpid_protocol=tcp
|
#qpid_protocol=tcp
|
||||||
|
|
||||||
# Disable Nagle algorithm (boolean value)
|
# Whether to disable the Nagle algorithm. (boolean value)
|
||||||
#qpid_tcp_nodelay=true
|
#qpid_tcp_nodelay=true
|
||||||
|
|
||||||
# The qpid topology version to use. Version 1 is what was
|
# The qpid topology version to use. Version 1 is what was
|
||||||
@@ -155,52 +155,55 @@
|
|||||||
|
|
||||||
# SSL version to use (valid only if SSL enabled). valid values
|
# SSL version to use (valid only if SSL enabled). valid values
|
||||||
# are TLSv1, SSLv23 and SSLv3. SSLv2 may be available on some
|
# are TLSv1, SSLv23 and SSLv3. SSLv2 may be available on some
|
||||||
# distributions (string value)
|
# distributions. (string value)
|
||||||
#kombu_ssl_version=
|
#kombu_ssl_version=
|
||||||
|
|
||||||
# SSL key file (valid only if SSL enabled) (string value)
|
# SSL key file (valid only if SSL enabled). (string value)
|
||||||
#kombu_ssl_keyfile=
|
#kombu_ssl_keyfile=
|
||||||
|
|
||||||
# SSL cert file (valid only if SSL enabled) (string value)
|
# SSL cert file (valid only if SSL enabled). (string value)
|
||||||
#kombu_ssl_certfile=
|
#kombu_ssl_certfile=
|
||||||
|
|
||||||
# SSL certification authority file (valid only if SSL enabled)
|
# SSL certification authority file (valid only if SSL
|
||||||
# (string value)
|
# enabled). (string value)
|
||||||
#kombu_ssl_ca_certs=
|
#kombu_ssl_ca_certs=
|
||||||
|
|
||||||
# The RabbitMQ broker address where a single node is used
|
# The RabbitMQ broker address where a single node is used.
|
||||||
# (string value)
|
# (string value)
|
||||||
#rabbit_host=localhost
|
#rabbit_host=localhost
|
||||||
|
|
||||||
# The RabbitMQ broker port where a single node is used
|
# The RabbitMQ broker port where a single node is used.
|
||||||
# (integer value)
|
# (integer value)
|
||||||
#rabbit_port=5672
|
#rabbit_port=5672
|
||||||
|
|
||||||
# RabbitMQ HA cluster host:port pairs (list value)
|
# RabbitMQ HA cluster host:port pairs. (list value)
|
||||||
#rabbit_hosts=$rabbit_host:$rabbit_port
|
#rabbit_hosts=$rabbit_host:$rabbit_port
|
||||||
|
|
||||||
# Connect over SSL for RabbitMQ (boolean value)
|
# Connect over SSL for RabbitMQ. (boolean value)
|
||||||
#rabbit_use_ssl=false
|
#rabbit_use_ssl=false
|
||||||
|
|
||||||
# The RabbitMQ userid (string value)
|
# The RabbitMQ userid. (string value)
|
||||||
#rabbit_userid=guest
|
#rabbit_userid=guest
|
||||||
|
|
||||||
# The RabbitMQ password (string value)
|
# The RabbitMQ password. (string value)
|
||||||
#rabbit_password=guest
|
#rabbit_password=guest
|
||||||
|
|
||||||
# The RabbitMQ virtual host (string value)
|
# the RabbitMQ login method (string value)
|
||||||
|
#rabbit_login_method=AMQPLAIN
|
||||||
|
|
||||||
|
# The RabbitMQ virtual host. (string value)
|
||||||
#rabbit_virtual_host=/
|
#rabbit_virtual_host=/
|
||||||
|
|
||||||
# How frequently to retry connecting with RabbitMQ (integer
|
# How frequently to retry connecting with RabbitMQ. (integer
|
||||||
# value)
|
# value)
|
||||||
#rabbit_retry_interval=1
|
#rabbit_retry_interval=1
|
||||||
|
|
||||||
# How long to backoff for between retries when connecting to
|
# How long to backoff for between retries when connecting to
|
||||||
# RabbitMQ (integer value)
|
# RabbitMQ. (integer value)
|
||||||
#rabbit_retry_backoff=2
|
#rabbit_retry_backoff=2
|
||||||
|
|
||||||
# Maximum number of RabbitMQ connection retries. Default is 0
|
# Maximum number of RabbitMQ connection retries. Default is 0
|
||||||
# (infinite retry count) (integer value)
|
# (infinite retry count). (integer value)
|
||||||
#rabbit_max_retries=0
|
#rabbit_max_retries=0
|
||||||
|
|
||||||
# Use HA queues in RabbitMQ (x-ha-policy: all). If you change
|
# Use HA queues in RabbitMQ (x-ha-policy: all). If you change
|
||||||
@@ -208,7 +211,7 @@
|
|||||||
# value)
|
# value)
|
||||||
#rabbit_ha_queues=false
|
#rabbit_ha_queues=false
|
||||||
|
|
||||||
# If passed, use a fake RabbitMQ provider (boolean value)
|
# If passed, use a fake RabbitMQ provider. (boolean value)
|
||||||
#fake_rabbit=false
|
#fake_rabbit=false
|
||||||
|
|
||||||
# ZeroMQ bind address. Should be a wildcard (*), an ethernet
|
# ZeroMQ bind address. Should be a wildcard (*), an ethernet
|
||||||
@@ -216,20 +219,20 @@
|
|||||||
# to this address. (string value)
|
# to this address. (string value)
|
||||||
#rpc_zmq_bind_address=*
|
#rpc_zmq_bind_address=*
|
||||||
|
|
||||||
# MatchMaker driver (string value)
|
# MatchMaker driver. (string value)
|
||||||
#rpc_zmq_matchmaker=oslo.messaging._drivers.matchmaker.MatchMakerLocalhost
|
#rpc_zmq_matchmaker=oslo.messaging._drivers.matchmaker.MatchMakerLocalhost
|
||||||
|
|
||||||
# ZeroMQ receiver listening port (integer value)
|
# ZeroMQ receiver listening port. (integer value)
|
||||||
#rpc_zmq_port=9501
|
#rpc_zmq_port=9501
|
||||||
|
|
||||||
# Number of ZeroMQ contexts, defaults to 1 (integer value)
|
# Number of ZeroMQ contexts, defaults to 1. (integer value)
|
||||||
#rpc_zmq_contexts=1
|
#rpc_zmq_contexts=1
|
||||||
|
|
||||||
# Maximum number of ingress messages to locally buffer per
|
# Maximum number of ingress messages to locally buffer per
|
||||||
# topic. Default is unlimited. (integer value)
|
# topic. Default is unlimited. (integer value)
|
||||||
#rpc_zmq_topic_backlog=<None>
|
#rpc_zmq_topic_backlog=<None>
|
||||||
|
|
||||||
# Directory for holding IPC sockets (string value)
|
# Directory for holding IPC sockets. (string value)
|
||||||
#rpc_zmq_ipc_dir=/var/run/openstack
|
#rpc_zmq_ipc_dir=/var/run/openstack
|
||||||
|
|
||||||
# Name of this node. Must be a valid hostname, FQDN, or IP
|
# Name of this node. Must be a valid hostname, FQDN, or IP
|
||||||
@@ -241,33 +244,33 @@
|
|||||||
# by impl_zmq. (integer value)
|
# by impl_zmq. (integer value)
|
||||||
#rpc_cast_timeout=30
|
#rpc_cast_timeout=30
|
||||||
|
|
||||||
# Heartbeat frequency (integer value)
|
# Heartbeat frequency. (integer value)
|
||||||
#matchmaker_heartbeat_freq=300
|
#matchmaker_heartbeat_freq=300
|
||||||
|
|
||||||
# Heartbeat time-to-live. (integer value)
|
# Heartbeat time-to-live. (integer value)
|
||||||
#matchmaker_heartbeat_ttl=600
|
#matchmaker_heartbeat_ttl=600
|
||||||
|
|
||||||
# Host to locate redis (string value)
|
# Host to locate redis. (string value)
|
||||||
#host=127.0.0.1
|
#host=127.0.0.1
|
||||||
|
|
||||||
# Use this port to connect to redis host. (integer value)
|
# Use this port to connect to redis host. (integer value)
|
||||||
#port=6379
|
#port=6379
|
||||||
|
|
||||||
# Password for Redis server. (optional) (string value)
|
# Password for Redis server (optional). (string value)
|
||||||
#password=<None>
|
#password=<None>
|
||||||
|
|
||||||
# Size of RPC greenthread pool (integer value)
|
# Size of RPC greenthread pool. (integer value)
|
||||||
#rpc_thread_pool_size=64
|
#rpc_thread_pool_size=64
|
||||||
|
|
||||||
# Driver or drivers to handle sending notifications (multi
|
# Driver or drivers to handle sending notifications. (multi
|
||||||
# valued)
|
# valued)
|
||||||
#notification_driver=
|
#notification_driver=
|
||||||
|
|
||||||
# AMQP topic used for OpenStack notifications (list value)
|
# AMQP topic used for OpenStack notifications. (list value)
|
||||||
# Deprecated group/name - [rpc_notifier2]/topics
|
# Deprecated group/name - [rpc_notifier2]/topics
|
||||||
#notification_topics=notifications
|
#notification_topics=notifications
|
||||||
|
|
||||||
# Seconds to wait for a response from a call (integer value)
|
# Seconds to wait for a response from a call. (integer value)
|
||||||
#rpc_response_timeout=60
|
#rpc_response_timeout=60
|
||||||
|
|
||||||
# A URL representing the messaging driver to use and its full
|
# A URL representing the messaging driver to use and its full
|
||||||
@@ -1006,7 +1009,7 @@
|
|||||||
# Options defined in oslo.messaging
|
# Options defined in oslo.messaging
|
||||||
#
|
#
|
||||||
|
|
||||||
# Matchmaker ring file (JSON) (string value)
|
# Matchmaker ring file (JSON). (string value)
|
||||||
# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
|
# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
|
||||||
#ringfile=/etc/oslo/matchmaker_ring.json
|
#ringfile=/etc/oslo/matchmaker_ring.json
|
||||||
|
|
||||||
@@ -1153,23 +1156,6 @@
|
|||||||
#cert_subject=/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost
|
#cert_subject=/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Options defined in keystone.openstack.common.sslutils
|
|
||||||
#
|
|
||||||
|
|
||||||
# CA certificate file to use to verify connecting clients
|
|
||||||
# (string value)
|
|
||||||
#ca_file=<None>
|
|
||||||
|
|
||||||
# Certificate file to use when starting the server securely
|
|
||||||
# (string value)
|
|
||||||
#cert_file=<None>
|
|
||||||
|
|
||||||
# Private key file to use when starting the server securely
|
|
||||||
# (string value)
|
|
||||||
#key_file=<None>
|
|
||||||
|
|
||||||
|
|
||||||
[stats]
|
[stats]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
import pecan
|
|
||||||
|
|
||||||
from keystone.contrib.kds.api import config as pecan_config
|
|
||||||
from keystone.contrib.kds.api import hooks
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
|
|
||||||
def get_pecan_config():
|
|
||||||
# Set up the pecan configuration
|
|
||||||
filename = pecan_config.__file__.replace('.pyc', '.py')
|
|
||||||
return pecan.configuration.conf_from_file(filename)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_app(config=None, extra_hooks=None):
|
|
||||||
app_hooks = [hooks.ConfigHook()]
|
|
||||||
|
|
||||||
if extra_hooks:
|
|
||||||
app_hooks.extend(extra_hooks)
|
|
||||||
|
|
||||||
if not config:
|
|
||||||
config = get_pecan_config()
|
|
||||||
|
|
||||||
pecan.configuration.set_config(dict(config), overwrite=True)
|
|
||||||
|
|
||||||
app = pecan.make_app('keystone.contrib.kds.api.root.RootController',
|
|
||||||
debug=CONF.debug,
|
|
||||||
hooks=app_hooks)
|
|
||||||
|
|
||||||
return app
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
# Server Specific Configurations
|
|
||||||
server = {
|
|
||||||
'port': 9109,
|
|
||||||
'host': '0.0.0.0'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Pecan Application Configurations
|
|
||||||
app = {
|
|
||||||
'root': 'keystone.contrib.kds.api.root.RootController',
|
|
||||||
'modules': ['keystone.contrib.kds.api'],
|
|
||||||
'static_root': '%(confdir)s/public',
|
|
||||||
'template_path': '%(confdir)s/templates',
|
|
||||||
'debug': False,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Custom Configurations must be in Python dictionary format::
|
|
||||||
#
|
|
||||||
# foo = {'bar': 'baz'}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
from pecan import hooks
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigHook(hooks.PecanHook):
|
|
||||||
def before(self, state):
|
|
||||||
state.request.cfg = cfg.CONF
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import pecan
|
|
||||||
|
|
||||||
from keystone.contrib.kds.api.v1 import controllers
|
|
||||||
|
|
||||||
|
|
||||||
class RootController(object):
|
|
||||||
|
|
||||||
v1 = controllers.Controller()
|
|
||||||
|
|
||||||
@pecan.expose('json')
|
|
||||||
def index(self):
|
|
||||||
pecan.response.status = 300
|
|
||||||
return {
|
|
||||||
'versions': [
|
|
||||||
self.v1.version_info(),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
|
|
||||||
from keystone.contrib.kds.api.v1.controllers import controller
|
|
||||||
|
|
||||||
|
|
||||||
Controller = controller.Controller
|
|
||||||
|
|
||||||
__all__ = ['Controller']
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import pecan
|
|
||||||
|
|
||||||
|
|
||||||
class Controller(object):
|
|
||||||
"""Version 1 API controller root."""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def version_info():
|
|
||||||
return {'status': 'stable',
|
|
||||||
'id': 'v1.0',
|
|
||||||
'links': [{
|
|
||||||
'href': '%s/v1/' % pecan.request.host_url,
|
|
||||||
'rel': 'self'}]}
|
|
||||||
|
|
||||||
@pecan.expose('json')
|
|
||||||
def index(self):
|
|
||||||
return {'version': self.version_info()}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
from wsgiref import simple_server
|
|
||||||
|
|
||||||
from keystone.openstack.common import gettextutils
|
|
||||||
|
|
||||||
PROJECT = 'kds'
|
|
||||||
gettextutils.install(PROJECT, lazy=True)
|
|
||||||
|
|
||||||
from keystone.contrib.kds.api import app
|
|
||||||
from keystone.contrib.kds.common import service
|
|
||||||
from keystone.openstack.common import log
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class Application(object):
|
|
||||||
def __init__(self):
|
|
||||||
self.app = app.setup_app()
|
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
|
||||||
return self.app(environ, start_response)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
service.prepare_service(sys.argv)
|
|
||||||
|
|
||||||
# Build and start the WSGI app
|
|
||||||
host = CONF.bind_ip
|
|
||||||
port = CONF.port
|
|
||||||
wsgi = simple_server.make_server(host, port, Application())
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
|
||||||
LOG.info(_("Serving on http://%(host)s:%(port)d"), {'host': host,
|
|
||||||
'port': port})
|
|
||||||
CONF.log_opt_values(LOG, logging.INFO)
|
|
||||||
|
|
||||||
try:
|
|
||||||
wsgi.serve_forever()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from keystone.openstack.common import gettextutils
|
|
||||||
|
|
||||||
# gettextutils.install() must run to set _ before importing any modules that
|
|
||||||
# contain static translated strings.
|
|
||||||
gettextutils.install('keystone')
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import service
|
|
||||||
from keystone.contrib.kds.db import migration
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
|
|
||||||
def do_db_version():
|
|
||||||
"""Print database's current migration level."""
|
|
||||||
print(migration.db_version())
|
|
||||||
|
|
||||||
|
|
||||||
def do_db_sync():
|
|
||||||
"""Place a database under migration control and upgrade,
|
|
||||||
creating first if necessary.
|
|
||||||
"""
|
|
||||||
return migration.db_sync(CONF.command.version)
|
|
||||||
|
|
||||||
|
|
||||||
def add_command_parsers(subparsers):
|
|
||||||
parser = subparsers.add_parser('db_version')
|
|
||||||
parser.set_defaults(func=do_db_version)
|
|
||||||
|
|
||||||
parser = subparsers.add_parser('db_sync')
|
|
||||||
parser.set_defaults(func=do_db_sync)
|
|
||||||
parser.add_argument('version', nargs='?')
|
|
||||||
|
|
||||||
|
|
||||||
command_opt = cfg.SubCommandOpt('command',
|
|
||||||
title='Commands',
|
|
||||||
help='Available commands',
|
|
||||||
handler=add_command_parsers)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
CONF.register_cli_opt(command_opt)
|
|
||||||
service.prepare_service(sys.argv)
|
|
||||||
|
|
||||||
try:
|
|
||||||
CONF.command.func()
|
|
||||||
except Exception as e:
|
|
||||||
sys.exit("ERROR: %s" % e)
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
_FATAL_EXCEPTION_FORMAT_ERRORS = False
|
|
||||||
|
|
||||||
|
|
||||||
class KdsException(Exception):
|
|
||||||
"""Base Exception class.
|
|
||||||
|
|
||||||
To correctly use this class, inherit from it and define
|
|
||||||
a 'msg_fmt' property. That message will get printf'd
|
|
||||||
with the keyword arguments provided to the constructor.
|
|
||||||
"""
|
|
||||||
|
|
||||||
msg_fmt = _('An unknown exception occurred')
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
try:
|
|
||||||
self._error_string = self.msg_fmt % kwargs
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
if _FATAL_EXCEPTION_FORMAT_ERRORS:
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
# at least get the core message out if something happened
|
|
||||||
self._error_string = self.msg_fmt
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self._error_string
|
|
||||||
|
|
||||||
|
|
||||||
class BackendException(KdsException):
|
|
||||||
msg_fmt = _("Failed to load the '%(backend)s' backend because it is not "
|
|
||||||
"allowed. Allowed backends are: %(allowed)s")
|
|
||||||
|
|
||||||
|
|
||||||
class IntegrityError(KdsException):
|
|
||||||
msg_fmt = _('Cannot set key data for %(name)s: %(reason)s')
|
|
||||||
|
|
||||||
|
|
||||||
class GroupStatusChanged(IntegrityError):
|
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
kwargs.setdefault('reason', "Can't change group status of a host")
|
|
||||||
super(GroupStatusChanged, self).__init__(**kwargs)
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.openstack.common import log
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
FILE_OPTIONS = {
|
|
||||||
None: [
|
|
||||||
cfg.StrOpt('bind_ip',
|
|
||||||
default='0.0.0.0',
|
|
||||||
help='IP for the server to bind to'),
|
|
||||||
cfg.IntOpt('port',
|
|
||||||
default=9109,
|
|
||||||
help='The port for the server')]}
|
|
||||||
|
|
||||||
|
|
||||||
def configure(conf=None):
|
|
||||||
if conf is None:
|
|
||||||
conf = CONF
|
|
||||||
|
|
||||||
for group in FILE_OPTIONS:
|
|
||||||
conf.register_opts(FILE_OPTIONS[group], group=group)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_args(args, default_config_files=None):
|
|
||||||
CONF(args=args[1:],
|
|
||||||
project='kds',
|
|
||||||
default_config_files=default_config_files)
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_service(argv=[]):
|
|
||||||
cfg.set_defaults(log.log_opts,
|
|
||||||
default_log_levels=['sqlalchemy=WARN',
|
|
||||||
'eventlet.wsgi.server=WARN'
|
|
||||||
])
|
|
||||||
parse_args(argv)
|
|
||||||
log.setup('kds')
|
|
||||||
|
|
||||||
|
|
||||||
configure()
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import exception
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
# NOTE(jamielennox): This class is a direct copy from nova, glance, heat and
|
|
||||||
# a bunch of other projects. It has been submitted to OSLO
|
|
||||||
# https://review.openstack.org/#/c/67002/ and should be synced when available.
|
|
||||||
|
|
||||||
|
|
||||||
class LazyPluggable(object):
|
|
||||||
"""A pluggable backend loaded lazily based on some value."""
|
|
||||||
|
|
||||||
def __init__(self, pivot, config_group=None, **backends):
|
|
||||||
self.__backends = backends
|
|
||||||
self.__pivot = pivot
|
|
||||||
self.__backend = None
|
|
||||||
self.__config_group = config_group
|
|
||||||
|
|
||||||
def __get_backend(self):
|
|
||||||
if not self.__backend:
|
|
||||||
if self.__config_group is None:
|
|
||||||
backend_name = CONF[self.__pivot]
|
|
||||||
else:
|
|
||||||
backend_name = CONF[self.__config_group][self.__pivot]
|
|
||||||
if backend_name not in self.__backends:
|
|
||||||
allowed = ', '.join(self.__backends.iterkeys())
|
|
||||||
raise exception.BackendException(backend=backend_name,
|
|
||||||
allowed=allowed)
|
|
||||||
|
|
||||||
backend = self.__backends[backend_name]
|
|
||||||
if isinstance(backend, tuple):
|
|
||||||
name = backend[0]
|
|
||||||
fromlist = backend[1]
|
|
||||||
else:
|
|
||||||
name = backend
|
|
||||||
fromlist = backend
|
|
||||||
|
|
||||||
self.__backend = __import__(name=name, globals=None,
|
|
||||||
locals=None, fromlist=fromlist)
|
|
||||||
return self.__backend
|
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
backend = self.__get_backend()
|
|
||||||
return getattr(backend, key)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.openstack.common.db import api as db_api
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
_BACKEND_MAPPING = {'sqlalchemy': 'keystone.contrib.kds.db.sqlalchemy.api',
|
|
||||||
'kvs': 'keystone.contrib.kds.db.kvs.api'}
|
|
||||||
|
|
||||||
IMPL = db_api.DBAPI(backend_mapping=_BACKEND_MAPPING)
|
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
|
||||||
global IMPL
|
|
||||||
IMPL = db_api.DBAPI(backend_mapping=_BACKEND_MAPPING)
|
|
||||||
|
|
||||||
|
|
||||||
def get_instance():
|
|
||||||
"""Return a DB API instance."""
|
|
||||||
return IMPL
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import abc
|
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(abc.ABCMeta)
|
|
||||||
class Connection(object):
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def set_key(self, name, key, signature, group, expiration=None):
|
|
||||||
"""Set a key for a name in the database.
|
|
||||||
|
|
||||||
If a key is set for an existing key name then a new key entry with a
|
|
||||||
new generation value is created.
|
|
||||||
|
|
||||||
:param string name: The unique name of the key to set.
|
|
||||||
:param string key: The key data to save.
|
|
||||||
:param string signature: The signature of the key data to save.
|
|
||||||
:param bool group: Whether this is a group key or not.
|
|
||||||
:param DateTime expiration: When the key should expire
|
|
||||||
(None is never expire).
|
|
||||||
|
|
||||||
:raises GroupStatusChanged: If a key exists then new keys assigned to
|
|
||||||
the name must have the same 'group' setting. If the value of group
|
|
||||||
is changed a
|
|
||||||
:class:`keystone.contrib.kds.common.exception.GroupStatusChanged`
|
|
||||||
is raised.
|
|
||||||
|
|
||||||
:returns int: The generation number of this key.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abc.abstractmethod
|
|
||||||
def get_key(self, name, generation=None, group=None):
|
|
||||||
"""Get key related to kds_id.
|
|
||||||
|
|
||||||
:param string name: The unique name of the key to fetch.
|
|
||||||
:param int generation: A specific generation of the key to retrieve. If
|
|
||||||
not specified the most recent generation is
|
|
||||||
retrieved.
|
|
||||||
:param bool group: If provided only retrieve this key if its group
|
|
||||||
value is the same.
|
|
||||||
|
|
||||||
:returns dict: A dictionary of the key information or None if not
|
|
||||||
found. Keys will contain:
|
|
||||||
|
|
||||||
- name: Unique name of the key.
|
|
||||||
- group: If this key is a group key or not.
|
|
||||||
- key: The key data.
|
|
||||||
- signature: The signature of the key data.
|
|
||||||
- generation: The generation of this key.
|
|
||||||
- expiration: When the key expires (or None).
|
|
||||||
Expired keys can be returned.
|
|
||||||
|
|
||||||
"""
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import exception
|
|
||||||
from keystone.contrib.kds.db import connection
|
|
||||||
|
|
||||||
|
|
||||||
def get_backend():
|
|
||||||
return KvsDbImpl()
|
|
||||||
|
|
||||||
|
|
||||||
class KvsDbImpl(connection.Connection):
|
|
||||||
"""A simple in-memory Key Value backend.
|
|
||||||
|
|
||||||
KVS backends are designed for use in testing and for simple debugging.
|
|
||||||
This backend should not be deployed in any production systems.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
super(KvsDbImpl, self).__init__()
|
|
||||||
self.clear()
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self._data = dict()
|
|
||||||
|
|
||||||
def set_key(self, name, key, signature, group, expiration=None):
|
|
||||||
host = self._data.setdefault(name, {'latest_generation': 0,
|
|
||||||
'keys': dict(), 'group': group})
|
|
||||||
|
|
||||||
if host['group'] != group:
|
|
||||||
raise exception.GroupStatusChanged(name=name)
|
|
||||||
|
|
||||||
host['latest_generation'] += 1
|
|
||||||
host['keys'][host['latest_generation']] = {'key': key,
|
|
||||||
'signature': signature,
|
|
||||||
'expiration': expiration}
|
|
||||||
|
|
||||||
return host['latest_generation']
|
|
||||||
|
|
||||||
def get_key(self, name, generation=None, group=None):
|
|
||||||
response = {'name': name}
|
|
||||||
try:
|
|
||||||
host = self._data[name]
|
|
||||||
if generation is None:
|
|
||||||
generation = host['latest_generation']
|
|
||||||
key_data = host['keys'][generation]
|
|
||||||
except KeyError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
response['generation'] = generation
|
|
||||||
response['group'] = host['group']
|
|
||||||
|
|
||||||
if group is not None and host['group'] != group:
|
|
||||||
return None
|
|
||||||
|
|
||||||
response.update(key_data)
|
|
||||||
return response
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
"""Database setup and migration commands."""
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import utils
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
CONF.import_opt('backend',
|
|
||||||
'keystone.openstack.common.db.api',
|
|
||||||
group='database')
|
|
||||||
|
|
||||||
_sqlalchemy_repo = 'keystone.contrib.kds.db.sqlalchemy.migration'
|
|
||||||
IMPL = utils.LazyPluggable(pivot='backend',
|
|
||||||
config_group='database',
|
|
||||||
sqlalchemy=_sqlalchemy_repo)
|
|
||||||
|
|
||||||
INIT_VERSION = 0
|
|
||||||
|
|
||||||
|
|
||||||
def db_sync(version=None):
|
|
||||||
"""Migrate the database to `version` or the most recent version."""
|
|
||||||
return IMPL.db_sync(version=version)
|
|
||||||
|
|
||||||
|
|
||||||
def db_version():
|
|
||||||
"""Display the current database version."""
|
|
||||||
return IMPL.db_version()
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from sqlalchemy.orm import exc
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import exception
|
|
||||||
from keystone.contrib.kds.db import connection
|
|
||||||
from keystone.contrib.kds.db.sqlalchemy import models
|
|
||||||
from keystone.openstack.common.db.sqlalchemy import session as db_session
|
|
||||||
|
|
||||||
|
|
||||||
def get_backend():
|
|
||||||
return SqlalchemyDbImpl()
|
|
||||||
|
|
||||||
|
|
||||||
class SqlalchemyDbImpl(connection.Connection):
|
|
||||||
|
|
||||||
def set_key(self, name, key, signature, group, expiration=None):
|
|
||||||
session = db_session.get_session()
|
|
||||||
|
|
||||||
with session.begin():
|
|
||||||
q = session.query(models.Host)
|
|
||||||
q = q.filter(models.Host.name == name)
|
|
||||||
|
|
||||||
try:
|
|
||||||
host = q.one()
|
|
||||||
except exc.NoResultFound:
|
|
||||||
host = models.Host(name=name,
|
|
||||||
latest_generation=0,
|
|
||||||
group=group)
|
|
||||||
else:
|
|
||||||
if host.group != group:
|
|
||||||
raise exception.GroupStatusChanged(name=name)
|
|
||||||
|
|
||||||
host.latest_generation += 1
|
|
||||||
host.keys.append(models.Key(signature=signature,
|
|
||||||
enc_key=key,
|
|
||||||
generation=host.latest_generation,
|
|
||||||
expiration=expiration))
|
|
||||||
|
|
||||||
session.add(host)
|
|
||||||
|
|
||||||
return host.latest_generation
|
|
||||||
|
|
||||||
def get_key(self, name, generation=None, group=None):
|
|
||||||
session = db_session.get_session()
|
|
||||||
|
|
||||||
query = session.query(models.Host, models.Key)
|
|
||||||
query = query.filter(models.Host.id == models.Key.host_id)
|
|
||||||
query = query.filter(models.Host.name == name)
|
|
||||||
|
|
||||||
if group is not None:
|
|
||||||
query = query.filter(models.Host.group == group)
|
|
||||||
|
|
||||||
if generation is not None:
|
|
||||||
query = query.filter(models.Key.generation == generation)
|
|
||||||
else:
|
|
||||||
query = query.filter(models.Host.latest_generation ==
|
|
||||||
models.Key.generation)
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = query.one()
|
|
||||||
except exc.NoResultFound:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return {'name': result.Host.name,
|
|
||||||
'group': result.Host.group,
|
|
||||||
'key': result.Key.enc_key,
|
|
||||||
'signature': result.Key.signature,
|
|
||||||
'generation': result.Key.generation,
|
|
||||||
'expiration': result.Key.expiration}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from migrate.versioning.shell import main
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main(debug=False, repository='.')
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
[db_settings]
|
|
||||||
# Used to identify which repository this database is versioned under.
|
|
||||||
# You can use the name of your project.
|
|
||||||
repository_id=kds
|
|
||||||
|
|
||||||
# The name of the database table used to track the schema version.
|
|
||||||
# This name shouldn't already be used by your project.
|
|
||||||
# If this is changed once a database is under version control, you'll need to
|
|
||||||
# change the table name in each database too.
|
|
||||||
version_table=migrate_version
|
|
||||||
|
|
||||||
# When committing a change script, Migrate will attempt to generate the
|
|
||||||
# sql for all supported databases; normally, if one of them fails - probably
|
|
||||||
# because you don't have that database installed - it is ignored and the
|
|
||||||
# commit continues, perhaps ending successfully.
|
|
||||||
# Databases in this list MUST compile successfully during a commit, or the
|
|
||||||
# entire commit will fail. List the databases your application will actually
|
|
||||||
# be using to ensure your updates to that database work properly.
|
|
||||||
# This must be a list; example: ['postgres','sqlite']
|
|
||||||
required_dbs=[]
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import sqlalchemy as sql
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade(migrate_engine):
|
|
||||||
meta = sql.MetaData()
|
|
||||||
meta.bind = migrate_engine
|
|
||||||
|
|
||||||
host_table = sql.Table('kds_hosts', meta,
|
|
||||||
sql.Column('id',
|
|
||||||
sql.Integer(),
|
|
||||||
primary_key=True,
|
|
||||||
autoincrement=True),
|
|
||||||
sql.Column('name',
|
|
||||||
sql.Text(),
|
|
||||||
nullable=False),
|
|
||||||
sql.Column('group',
|
|
||||||
sql.Boolean(),
|
|
||||||
nullable=False,
|
|
||||||
index=True),
|
|
||||||
sql.Column('latest_generation',
|
|
||||||
sql.Integer(),
|
|
||||||
nullable=False),
|
|
||||||
mysql_engine='InnoDB',
|
|
||||||
mysql_charset='utf8')
|
|
||||||
|
|
||||||
# MySQL can't put an index on an unbound TEXT type so if we do it this way
|
|
||||||
# it will make the index on the first 20 characters which will be fine.
|
|
||||||
sql.Index('name_idx', host_table.c.name, unique=True, mysql_length=20)
|
|
||||||
|
|
||||||
host_table.create(migrate_engine, checkfirst=True)
|
|
||||||
|
|
||||||
key_table = sql.Table('kds_keys', meta,
|
|
||||||
sql.Column('host_id',
|
|
||||||
sql.Integer(),
|
|
||||||
sql.ForeignKey('kds_hosts.id'),
|
|
||||||
primary_key=True,
|
|
||||||
autoincrement=False),
|
|
||||||
sql.Column('generation',
|
|
||||||
sql.Integer(),
|
|
||||||
primary_key=True,
|
|
||||||
autoincrement=False),
|
|
||||||
sql.Column('signature',
|
|
||||||
sql.LargeBinary(),
|
|
||||||
nullable=False),
|
|
||||||
sql.Column('enc_key',
|
|
||||||
sql.LargeBinary(),
|
|
||||||
nullable=False),
|
|
||||||
sql.Column('expiration',
|
|
||||||
sql.DateTime(),
|
|
||||||
nullable=True,
|
|
||||||
index=True),
|
|
||||||
mysql_engine='InnoDB',
|
|
||||||
mysql_charset='utf8')
|
|
||||||
|
|
||||||
key_table.create(migrate_engine, checkfirst=True)
|
|
||||||
|
|
||||||
|
|
||||||
def downgrade(migrate_engine):
|
|
||||||
meta = sql.MetaData()
|
|
||||||
meta.bind = migrate_engine
|
|
||||||
|
|
||||||
for name in ['kds_keys', 'kds_hosts']:
|
|
||||||
table = sql.Table(name, meta, autoload=True)
|
|
||||||
table.drop(migrate_engine, checkfirst=True)
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from keystone.openstack.common.db.sqlalchemy import migration
|
|
||||||
|
|
||||||
|
|
||||||
def _repo_path():
|
|
||||||
return os.path.join(os.path.abspath(os.path.dirname(__file__)),
|
|
||||||
'migrate_repo')
|
|
||||||
|
|
||||||
|
|
||||||
def db_version_control(version=None):
|
|
||||||
return migration.db_version_control(_repo_path(), version=version)
|
|
||||||
|
|
||||||
|
|
||||||
def db_sync(version=None):
|
|
||||||
return migration.db_sync(_repo_path(), version=version)
|
|
||||||
|
|
||||||
|
|
||||||
def db_version(version=None):
|
|
||||||
return migration.db_version(_repo_path(), version)
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import sqlalchemy as sql
|
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
|
||||||
|
|
||||||
from keystone.openstack.common.db.sqlalchemy import models
|
|
||||||
|
|
||||||
|
|
||||||
class KdsBase(models.ModelBase):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
Base = declarative_base(cls=KdsBase)
|
|
||||||
|
|
||||||
|
|
||||||
class Host(Base):
|
|
||||||
__tablename__ = 'kds_hosts'
|
|
||||||
|
|
||||||
id = sql.Column(sql.Integer(), primary_key=True, autoincrement=True)
|
|
||||||
name = sql.Column(sql.Text(), index=True, unique=True, nullable=False)
|
|
||||||
group = sql.Column(sql.Boolean(), nullable=False, index=True)
|
|
||||||
latest_generation = sql.Column(sql.Integer(), nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class Key(Base):
|
|
||||||
__tablename__ = 'kds_keys'
|
|
||||||
|
|
||||||
host_id = sql.Column(sql.Integer(),
|
|
||||||
sql.ForeignKey('kds_hosts.id'),
|
|
||||||
primary_key=True,
|
|
||||||
autoincrement=False)
|
|
||||||
|
|
||||||
generation = sql.Column(sql.Integer(),
|
|
||||||
primary_key=True,
|
|
||||||
autoincrement=False)
|
|
||||||
|
|
||||||
signature = sql.Column(sql.LargeBinary(),
|
|
||||||
nullable=False)
|
|
||||||
|
|
||||||
enc_key = sql.Column(sql.LargeBinary(),
|
|
||||||
nullable=False)
|
|
||||||
|
|
||||||
expiration = sql.Column(sql.DateTime(),
|
|
||||||
nullable=True,
|
|
||||||
index=True)
|
|
||||||
|
|
||||||
owner = sql.orm.relationship('Host',
|
|
||||||
backref=sql.orm.backref('keys',
|
|
||||||
order_by=sql.desc(
|
|
||||||
generation)))
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
# Copyright 2013 Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import base64
|
|
||||||
|
|
||||||
from Crypto.Hash import HMAC
|
|
||||||
from Crypto import Random
|
|
||||||
|
|
||||||
from keystone.openstack.common.gettextutils import _ # noqa
|
|
||||||
from keystone.openstack.common import importutils
|
|
||||||
|
|
||||||
|
|
||||||
class CryptoutilsException(Exception):
|
|
||||||
"""Generic Exception for Crypto utilities."""
|
|
||||||
|
|
||||||
message = _("An unknown error occurred in crypto utils.")
|
|
||||||
|
|
||||||
|
|
||||||
class CipherBlockLengthTooBig(CryptoutilsException):
|
|
||||||
"""The block size is too big."""
|
|
||||||
|
|
||||||
def __init__(self, requested, permitted):
|
|
||||||
msg = _("Block size of %(given)d is too big, max = %(maximum)d")
|
|
||||||
message = msg % {'given': requested, 'maximum': permitted}
|
|
||||||
super(CryptoutilsException, self).__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
class HKDFOutputLengthTooLong(CryptoutilsException):
|
|
||||||
"""The amount of Key Material asked is too much."""
|
|
||||||
|
|
||||||
def __init__(self, requested, permitted):
|
|
||||||
msg = _("Length of %(given)d is too long, max = %(maximum)d")
|
|
||||||
message = msg % {'given': requested, 'maximum': permitted}
|
|
||||||
super(CryptoutilsException, self).__init__(message)
|
|
||||||
|
|
||||||
|
|
||||||
class HKDF(object):
|
|
||||||
"""An HMAC-based Key Derivation Function implementation (RFC5869)
|
|
||||||
|
|
||||||
This class creates an object that allows to use HKDF to derive keys.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, hashtype='SHA256'):
|
|
||||||
self.hashfn = importutils.import_module('Crypto.Hash.' + hashtype)
|
|
||||||
self.max_okm_length = 255 * self.hashfn.digest_size
|
|
||||||
|
|
||||||
def extract(self, ikm, salt=None):
|
|
||||||
"""An extract function that can be used to derive a robust key given
|
|
||||||
weak Input Key Material (IKM) which could be a password.
|
|
||||||
Returns a pseudorandom key (of HashLen octets)
|
|
||||||
|
|
||||||
:param ikm: input keying material (ex a password)
|
|
||||||
:param salt: optional salt value (a non-secret random value)
|
|
||||||
"""
|
|
||||||
if salt is None:
|
|
||||||
salt = '\x00' * self.hashfn.digest_size
|
|
||||||
|
|
||||||
return HMAC.new(salt, ikm, self.hashfn).digest()
|
|
||||||
|
|
||||||
def expand(self, prk, info, length):
|
|
||||||
"""An expand function that will return arbitrary length output that can
|
|
||||||
be used as keys.
|
|
||||||
Returns a buffer usable as key material.
|
|
||||||
|
|
||||||
:param prk: a pseudorandom key of at least HashLen octets
|
|
||||||
:param info: optional string (can be a zero-length string)
|
|
||||||
:param length: length of output keying material (<= 255 * HashLen)
|
|
||||||
"""
|
|
||||||
if length > self.max_okm_length:
|
|
||||||
raise HKDFOutputLengthTooLong(length, self.max_okm_length)
|
|
||||||
|
|
||||||
N = (length + self.hashfn.digest_size - 1) / self.hashfn.digest_size
|
|
||||||
|
|
||||||
okm = ""
|
|
||||||
tmp = ""
|
|
||||||
for block in range(1, N + 1):
|
|
||||||
tmp = HMAC.new(prk, tmp + info + chr(block), self.hashfn).digest()
|
|
||||||
okm += tmp
|
|
||||||
|
|
||||||
return okm[:length]
|
|
||||||
|
|
||||||
|
|
||||||
MAX_CB_SIZE = 256
|
|
||||||
|
|
||||||
|
|
||||||
class SymmetricCrypto(object):
|
|
||||||
"""Symmetric Key Crypto object.
|
|
||||||
|
|
||||||
This class creates a Symmetric Key Crypto object that can be used
|
|
||||||
to encrypt, decrypt, or sign arbitrary data.
|
|
||||||
|
|
||||||
:param enctype: Encryption Cipher name (default: AES)
|
|
||||||
:param hashtype: Hash/HMAC type name (default: SHA256)
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, enctype='AES', hashtype='SHA256'):
|
|
||||||
self.cipher = importutils.import_module('Crypto.Cipher.' + enctype)
|
|
||||||
self.hashfn = importutils.import_module('Crypto.Hash.' + hashtype)
|
|
||||||
|
|
||||||
def new_key(self, size):
|
|
||||||
return Random.new().read(size)
|
|
||||||
|
|
||||||
def encrypt(self, key, msg, b64encode=True):
|
|
||||||
"""Encrypt the provided msg and returns the cyphertext optionally
|
|
||||||
base64 encoded.
|
|
||||||
|
|
||||||
Uses AES-128-CBC with a Random IV by default.
|
|
||||||
|
|
||||||
The plaintext is padded to reach blocksize length.
|
|
||||||
The last byte of the block is the length of the padding.
|
|
||||||
The length of the padding does not include the length byte itself.
|
|
||||||
|
|
||||||
:param key: The Encryption key.
|
|
||||||
:param msg: the plain text.
|
|
||||||
|
|
||||||
:returns encblock: a block of encrypted data.
|
|
||||||
"""
|
|
||||||
iv = Random.new().read(self.cipher.block_size)
|
|
||||||
cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv)
|
|
||||||
|
|
||||||
# CBC mode requires a fixed block size. Append padding and length of
|
|
||||||
# padding.
|
|
||||||
if self.cipher.block_size > MAX_CB_SIZE:
|
|
||||||
raise CipherBlockLengthTooBig(self.cipher.block_size, MAX_CB_SIZE)
|
|
||||||
r = len(msg) % self.cipher.block_size
|
|
||||||
padlen = self.cipher.block_size - r - 1
|
|
||||||
msg += '\x00' * padlen
|
|
||||||
msg += chr(padlen)
|
|
||||||
|
|
||||||
enc = iv + cipher.encrypt(msg)
|
|
||||||
if b64encode:
|
|
||||||
enc = base64.b64encode(enc)
|
|
||||||
return enc
|
|
||||||
|
|
||||||
def decrypt(self, key, msg, b64decode=True):
|
|
||||||
"""Decrypts the provided ciphertext, optionally base 64 encoded, and
|
|
||||||
returns the plaintext message, after padding is removed.
|
|
||||||
|
|
||||||
Uses AES-128-CBC with an IV by default.
|
|
||||||
|
|
||||||
:param key: The Encryption key.
|
|
||||||
:param msg: the ciphetext, the first block is the IV
|
|
||||||
"""
|
|
||||||
if b64decode:
|
|
||||||
msg = base64.b64decode(msg)
|
|
||||||
iv = msg[:self.cipher.block_size]
|
|
||||||
cipher = self.cipher.new(key, self.cipher.MODE_CBC, iv)
|
|
||||||
|
|
||||||
padded = cipher.decrypt(msg[self.cipher.block_size:])
|
|
||||||
l = ord(padded[-1]) + 1
|
|
||||||
plain = padded[:-l]
|
|
||||||
return plain
|
|
||||||
|
|
||||||
def sign(self, key, msg, b64encode=True):
|
|
||||||
"""Signs a message string and returns a base64 encoded signature.
|
|
||||||
|
|
||||||
Uses HMAC-SHA-256 by default.
|
|
||||||
|
|
||||||
:param key: The Signing key.
|
|
||||||
:param msg: the message to sign.
|
|
||||||
"""
|
|
||||||
h = HMAC.new(key, msg, self.hashfn)
|
|
||||||
out = h.digest()
|
|
||||||
if b64encode:
|
|
||||||
out = base64.b64encode(out)
|
|
||||||
return out
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
# Copyright 2013 IBM Corp.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import os
|
|
||||||
import ssl
|
|
||||||
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.openstack.common.gettextutils import _ # noqa
|
|
||||||
|
|
||||||
|
|
||||||
ssl_opts = [
|
|
||||||
cfg.StrOpt('ca_file',
|
|
||||||
default=None,
|
|
||||||
help="CA certificate file to use to verify "
|
|
||||||
"connecting clients"),
|
|
||||||
cfg.StrOpt('cert_file',
|
|
||||||
default=None,
|
|
||||||
help="Certificate file to use when starting "
|
|
||||||
"the server securely"),
|
|
||||||
cfg.StrOpt('key_file',
|
|
||||||
default=None,
|
|
||||||
help="Private key file to use when starting "
|
|
||||||
"the server securely"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
CONF.register_opts(ssl_opts, "ssl")
|
|
||||||
|
|
||||||
|
|
||||||
def is_enabled():
|
|
||||||
cert_file = CONF.ssl.cert_file
|
|
||||||
key_file = CONF.ssl.key_file
|
|
||||||
ca_file = CONF.ssl.ca_file
|
|
||||||
use_ssl = cert_file or key_file
|
|
||||||
|
|
||||||
if cert_file and not os.path.exists(cert_file):
|
|
||||||
raise RuntimeError(_("Unable to find cert_file : %s") % cert_file)
|
|
||||||
|
|
||||||
if ca_file and not os.path.exists(ca_file):
|
|
||||||
raise RuntimeError(_("Unable to find ca_file : %s") % ca_file)
|
|
||||||
|
|
||||||
if key_file and not os.path.exists(key_file):
|
|
||||||
raise RuntimeError(_("Unable to find key_file : %s") % key_file)
|
|
||||||
|
|
||||||
if use_ssl and (not cert_file or not key_file):
|
|
||||||
raise RuntimeError(_("When running server in SSL mode, you must "
|
|
||||||
"specify both a cert_file and key_file "
|
|
||||||
"option value in your configuration file"))
|
|
||||||
|
|
||||||
return use_ssl
|
|
||||||
|
|
||||||
|
|
||||||
def wrap(sock):
|
|
||||||
ssl_kwargs = {
|
|
||||||
'server_side': True,
|
|
||||||
'certfile': CONF.ssl.cert_file,
|
|
||||||
'keyfile': CONF.ssl.key_file,
|
|
||||||
'cert_reqs': ssl.CERT_NONE,
|
|
||||||
}
|
|
||||||
|
|
||||||
if CONF.ssl.ca_file:
|
|
||||||
ssl_kwargs['ca_certs'] = CONF.ssl.ca_file
|
|
||||||
ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED
|
|
||||||
|
|
||||||
return ssl.wrap_socket(sock, **ssl_kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
_SSL_PROTOCOLS = {
|
|
||||||
"tlsv1": ssl.PROTOCOL_TLSv1,
|
|
||||||
"sslv23": ssl.PROTOCOL_SSLv23,
|
|
||||||
"sslv3": ssl.PROTOCOL_SSLv3
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
_SSL_PROTOCOLS["sslv2"] = ssl.PROTOCOL_SSLv2
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def validate_ssl_version(version):
|
|
||||||
key = version.lower()
|
|
||||||
try:
|
|
||||||
return _SSL_PROTOCOLS[key]
|
|
||||||
except KeyError:
|
|
||||||
raise RuntimeError(_("Invalid SSL version : %s") % version)
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import webtest
|
|
||||||
|
|
||||||
import pecan.testing
|
|
||||||
|
|
||||||
from keystone.openstack.common import jsonutils
|
|
||||||
from keystone.tests.contrib.kds import base
|
|
||||||
|
|
||||||
|
|
||||||
def urljoin(*args):
|
|
||||||
return "/%s/" % "/".join([a.strip("/") for a in args])
|
|
||||||
|
|
||||||
|
|
||||||
def method_func(method):
|
|
||||||
def func(self, url, **kwargs):
|
|
||||||
kwargs['method'] = method
|
|
||||||
return self.request(url, **kwargs)
|
|
||||||
|
|
||||||
return func
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(base.BaseTestCase):
|
|
||||||
|
|
||||||
METHODS = {'get': webtest.TestApp.get,
|
|
||||||
'post': webtest.TestApp.post,
|
|
||||||
'put': webtest.TestApp.put,
|
|
||||||
'patch': webtest.TestApp.patch,
|
|
||||||
'delete': webtest.TestApp.delete,
|
|
||||||
'options': webtest.TestApp.options,
|
|
||||||
'head': webtest.TestApp.head}
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(BaseTestCase, self).setUp()
|
|
||||||
root = 'keystone.contrib.kds.api.root.RootController'
|
|
||||||
|
|
||||||
self.app_config = {
|
|
||||||
'app': {
|
|
||||||
'root': root,
|
|
||||||
'modules': ['keystone.contrib.kds.api']
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
self.app = pecan.testing.load_test_app(self.app_config)
|
|
||||||
self.addCleanup(pecan.set_config, {}, overwrite=True)
|
|
||||||
|
|
||||||
def request(self, url, method, **kwargs):
|
|
||||||
try:
|
|
||||||
json = kwargs.pop('json')
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
kwargs['content_type'] = 'application/json'
|
|
||||||
kwargs['params'] = jsonutils.dumps(json)
|
|
||||||
|
|
||||||
try:
|
|
||||||
func = self.METHODS[method.lower()]
|
|
||||||
except KeyError:
|
|
||||||
self.fail("Unsupported HTTP Method: %s" % method)
|
|
||||||
else:
|
|
||||||
return func(self.app, url, **kwargs)
|
|
||||||
|
|
||||||
get = method_func('get')
|
|
||||||
post = method_func('post')
|
|
||||||
put = method_func('put')
|
|
||||||
delete = method_func('delete')
|
|
||||||
options = method_func('options')
|
|
||||||
head = method_func('head')
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.tests.contrib.kds.api import base
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleTest(base.BaseTestCase):
|
|
||||||
|
|
||||||
def test_version(self):
|
|
||||||
resp = self.get('/')
|
|
||||||
versions = resp.json['versions']
|
|
||||||
self.assertEqual(resp.status_code, 300)
|
|
||||||
|
|
||||||
host = 'http://localhost' # webtest default
|
|
||||||
|
|
||||||
self.assertEqual(versions[0]['status'], 'stable')
|
|
||||||
self.assertEqual(versions[0]['id'], 'v1.0')
|
|
||||||
self.assertEqual(versions[0]['links'][0]['href'], '%s/v1/' % host)
|
|
||||||
self.assertEqual(versions[0]['links'][0]['rel'], 'self')
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.tests.contrib.kds.api import base
|
|
||||||
|
|
||||||
|
|
||||||
def v1_url(*args):
|
|
||||||
return base.urljoin('v1', *args)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(base.BaseTestCase):
|
|
||||||
|
|
||||||
def get(self, url, *args, **kwargs):
|
|
||||||
return super(BaseTestCase, self).get(v1_url(url), *args, **kwargs)
|
|
||||||
|
|
||||||
def post(self, url, *args, **kwargs):
|
|
||||||
return super(BaseTestCase, self).post(v1_url(url), *args, **kwargs)
|
|
||||||
|
|
||||||
def put(self, url, *args, **kwargs):
|
|
||||||
return super(BaseTestCase, self).put(v1_url(url), *args, **kwargs)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.tests.contrib.kds.api.v1 import base
|
|
||||||
|
|
||||||
|
|
||||||
class TestVersion(base.BaseTestCase):
|
|
||||||
|
|
||||||
def test_versions(self):
|
|
||||||
resp = self.get('/')
|
|
||||||
version = resp.json['version']
|
|
||||||
self.assertEqual(resp.status_code, 200)
|
|
||||||
|
|
||||||
host = 'http://localhost' # webtest default
|
|
||||||
|
|
||||||
self.assertEqual(version['id'], 'v1.0')
|
|
||||||
self.assertEqual(version['status'], 'stable')
|
|
||||||
self.assertEqual(version['links'][0]['href'], '%s/v1/' % host)
|
|
||||||
self.assertEqual(version['links'][0]['rel'], 'self')
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import service
|
|
||||||
from keystone.openstack.common.fixture import config
|
|
||||||
from keystone.openstack.common import test
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(test.BaseTestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(BaseTestCase, self).setUp()
|
|
||||||
self.config_fixture = self.useFixture(config.Config())
|
|
||||||
self.CONF = self.config_fixture.conf
|
|
||||||
|
|
||||||
service.parse_args(args=[])
|
|
||||||
|
|
||||||
def config(self, *args, **kwargs):
|
|
||||||
self.config_fixture.config(*args, **kwargs)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.contrib.kds.db import api as db_api
|
|
||||||
from keystone.tests.contrib.kds import base
|
|
||||||
from keystone.tests.contrib.kds import fixture
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(base.BaseTestCase):
|
|
||||||
|
|
||||||
scenarios = [('sqlitedb', {'sql_fixture': fixture.SqliteDb}),
|
|
||||||
('kvsdb', {'sql_fixture': fixture.KvsDb})]
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(BaseTestCase, self).setUp()
|
|
||||||
|
|
||||||
self.useFixture(self.sql_fixture())
|
|
||||||
|
|
||||||
self.DB = db_api.get_instance()
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from testscenarios import load_tests_apply_scenarios as load_tests # noqa
|
|
||||||
|
|
||||||
from keystone.contrib.kds.common import exception
|
|
||||||
from keystone.tests.contrib.kds.db import base
|
|
||||||
|
|
||||||
TEST_NAME = 'test-name'
|
|
||||||
TEST_SIG = 'test-sig'
|
|
||||||
TEST_KEY = 'test-enc'
|
|
||||||
|
|
||||||
|
|
||||||
class KeyDbTestCase(base.BaseTestCase):
|
|
||||||
|
|
||||||
def test_retrieve(self):
|
|
||||||
# Set a key and expect to get the same key back.
|
|
||||||
generation = self.DB.set_key(name=TEST_NAME,
|
|
||||||
signature=TEST_SIG,
|
|
||||||
key=TEST_KEY,
|
|
||||||
group=False)
|
|
||||||
key = self.DB.get_key(TEST_NAME)
|
|
||||||
|
|
||||||
self.assertEqual(key['name'], TEST_NAME)
|
|
||||||
self.assertEqual(key['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key['signature'], TEST_SIG)
|
|
||||||
self.assertEqual(key['generation'], generation)
|
|
||||||
self.assertIs(key['group'], False)
|
|
||||||
self.assertIsNone(key['expiration'])
|
|
||||||
|
|
||||||
def test_no_key(self):
|
|
||||||
# return None if a key is not in the database
|
|
||||||
self.assertIsNone(self.DB.get_key(TEST_NAME))
|
|
||||||
|
|
||||||
def test_generations(self):
|
|
||||||
another_key = 'another-key'
|
|
||||||
|
|
||||||
# set a key and make sure that the generation is set and returned
|
|
||||||
gen1 = self.DB.set_key(name=TEST_NAME,
|
|
||||||
signature=TEST_SIG,
|
|
||||||
key=TEST_KEY,
|
|
||||||
group=False)
|
|
||||||
|
|
||||||
key1 = self.DB.get_key(TEST_NAME)
|
|
||||||
self.assertEqual(key1['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key1['generation'], gen1)
|
|
||||||
|
|
||||||
# set a new key for the same name and make sure that the generation is
|
|
||||||
# updated
|
|
||||||
gen2 = self.DB.set_key(name=TEST_NAME,
|
|
||||||
signature='another-sig',
|
|
||||||
key=another_key,
|
|
||||||
group=False)
|
|
||||||
|
|
||||||
key2 = self.DB.get_key(TEST_NAME)
|
|
||||||
self.assertEqual(key2['generation'], gen2)
|
|
||||||
self.assertEqual(key2['key'], another_key)
|
|
||||||
|
|
||||||
# Check that if we ask specifically for the first key we get it back
|
|
||||||
key3 = self.DB.get_key(TEST_NAME, gen1)
|
|
||||||
self.assertEqual(key3['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key3['generation'], gen1)
|
|
||||||
|
|
||||||
def test_no_group_filter(self):
|
|
||||||
# install a non group key
|
|
||||||
generation = self.DB.set_key(name=TEST_NAME,
|
|
||||||
signature=TEST_SIG,
|
|
||||||
key=TEST_KEY,
|
|
||||||
group=False)
|
|
||||||
|
|
||||||
# test that if i can retrieve and specify a non-group key
|
|
||||||
key1 = self.DB.get_key(TEST_NAME)
|
|
||||||
self.assertEqual(key1['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key1['generation'], generation)
|
|
||||||
|
|
||||||
key2 = self.DB.get_key(TEST_NAME, group=False)
|
|
||||||
self.assertEqual(key2['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key2['generation'], generation)
|
|
||||||
|
|
||||||
# if i ask for a group key of that name then it should fail
|
|
||||||
key3 = self.DB.get_key(TEST_NAME, group=True)
|
|
||||||
self.assertIsNone(key3)
|
|
||||||
|
|
||||||
def test_with_group_filter(self):
|
|
||||||
# install a group key
|
|
||||||
generation = self.DB.set_key(name=TEST_NAME,
|
|
||||||
signature=TEST_SIG,
|
|
||||||
key=TEST_KEY,
|
|
||||||
group=True)
|
|
||||||
|
|
||||||
# i should be able to ask for and retrieve a group key
|
|
||||||
key1 = self.DB.get_key(TEST_NAME)
|
|
||||||
self.assertEqual(key1['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key1['generation'], generation)
|
|
||||||
|
|
||||||
key2 = self.DB.get_key(TEST_NAME, group=True)
|
|
||||||
self.assertEqual(key2['key'], TEST_KEY)
|
|
||||||
self.assertEqual(key2['generation'], generation)
|
|
||||||
|
|
||||||
# if i ask for that key but not a group key it will fail
|
|
||||||
key3 = self.DB.get_key(TEST_NAME, group=False)
|
|
||||||
self.assertIsNone(key3)
|
|
||||||
|
|
||||||
def test_cant_change_group_status(self):
|
|
||||||
group_key_name = 'name1'
|
|
||||||
host_key_name = 'name2'
|
|
||||||
|
|
||||||
# install a host and group key
|
|
||||||
self.DB.set_key(name=group_key_name,
|
|
||||||
signature=TEST_SIG,
|
|
||||||
key=TEST_KEY,
|
|
||||||
group=True)
|
|
||||||
|
|
||||||
self.DB.set_key(name=host_key_name,
|
|
||||||
signature=TEST_SIG,
|
|
||||||
key=TEST_KEY,
|
|
||||||
group=False)
|
|
||||||
|
|
||||||
# should not be able to change a group key to a host key
|
|
||||||
self.assertRaises(exception.IntegrityError, self.DB.set_key,
|
|
||||||
name=group_key_name, signature='xxx', key='xxx',
|
|
||||||
group=False)
|
|
||||||
|
|
||||||
# should not be able to change a host key to a group key
|
|
||||||
self.assertRaises(exception.IntegrityError, self.DB.set_key,
|
|
||||||
name=host_key_name, signature='xxx', key='xxx',
|
|
||||||
group=True)
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
from keystone.tests.contrib.kds.fixture import kvsdb
|
|
||||||
from keystone.tests.contrib.kds.fixture import sqlitedb
|
|
||||||
|
|
||||||
SqliteDb = sqlitedb.SqliteDb
|
|
||||||
KvsDb = kvsdb.KvsDb
|
|
||||||
|
|
||||||
__all__ = ['SqliteDb', 'KvsDb']
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import fixtures
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.contrib.kds.db import api as db_api
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class KvsDb(fixtures.Fixture):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(KvsDb, self).setUp()
|
|
||||||
|
|
||||||
CONF.set_override('backend', 'kvs', 'database')
|
|
||||||
|
|
||||||
db_api.reset()
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import fixtures
|
|
||||||
from oslo.config import cfg
|
|
||||||
|
|
||||||
from keystone.contrib.kds.db import api as db_api
|
|
||||||
from keystone.contrib.kds.db.sqlalchemy import migration
|
|
||||||
from keystone.openstack.common.db import exception as db_exception
|
|
||||||
from keystone import tests
|
|
||||||
from keystone.tests.contrib.kds import paths
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
|
||||||
|
|
||||||
|
|
||||||
class SqliteDb(fixtures.Fixture):
|
|
||||||
"""Connect to Keystone's sqlite database.
|
|
||||||
|
|
||||||
KDS is not designed with the intention that it should run within the same
|
|
||||||
database as keystone however there is nothing preventing that. There seems
|
|
||||||
to be issues regarding the conflicting CONF objects between keystone and
|
|
||||||
KDS that prevent the connection to separate databases for testing.
|
|
||||||
Therefore this fixture must simply bridge the gap back to the testing
|
|
||||||
database for keystone and setup the KDS tables.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(SqliteDb, self).setUp()
|
|
||||||
|
|
||||||
sqlite_db = os.path.abspath(paths.tmp_path('test.db'))
|
|
||||||
|
|
||||||
CONF.set_override('connection_debug', '51', 'database')
|
|
||||||
CONF.set_override('connection', 'sqlite:///%s' % sqlite_db, 'database')
|
|
||||||
|
|
||||||
db_api.reset()
|
|
||||||
|
|
||||||
tests.setup_database()
|
|
||||||
|
|
||||||
try:
|
|
||||||
migration.db_sync()
|
|
||||||
except db_exception.DbMigrationError:
|
|
||||||
migration.db_version_control(0)
|
|
||||||
migration.db_sync()
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
TEST_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__)))
|
|
||||||
TMP_DIR = os.path.join(TEST_DIR, '..', '..', 'tmp')
|
|
||||||
|
|
||||||
|
|
||||||
def root_path(*args):
|
|
||||||
return os.path.join(TEST_DIR, *args)
|
|
||||||
|
|
||||||
|
|
||||||
def test_path(*args):
|
|
||||||
return os.path.join(TEST_DIR, *args)
|
|
||||||
|
|
||||||
|
|
||||||
def tmp_path(*args):
|
|
||||||
return os.path.join(TMP_DIR, *args)
|
|
||||||
@@ -5,7 +5,6 @@ module=db
|
|||||||
module=db.sqlalchemy
|
module=db.sqlalchemy
|
||||||
module=config
|
module=config
|
||||||
module=colorizer
|
module=colorizer
|
||||||
module=crypto
|
|
||||||
module=fixture
|
module=fixture
|
||||||
module=importutils
|
module=importutils
|
||||||
module=install_venv_common
|
module=install_venv_common
|
||||||
|
|||||||
@@ -22,9 +22,3 @@ oauthlib>=0.6
|
|||||||
dogpile.cache>=0.5.0
|
dogpile.cache>=0.5.0
|
||||||
jsonschema>=2.0.0,<3.0.0
|
jsonschema>=2.0.0,<3.0.0
|
||||||
pycadf>=0.1.9
|
pycadf>=0.1.9
|
||||||
|
|
||||||
# KDS exclusive dependencies
|
|
||||||
|
|
||||||
pecan>=0.4.5
|
|
||||||
pycrypto>=2.6
|
|
||||||
WSME>=0.6
|
|
||||||
|
|||||||
@@ -64,9 +64,5 @@ warnerrors = True
|
|||||||
#autodoc_tree_root = ./keystone
|
#autodoc_tree_root = ./keystone
|
||||||
|
|
||||||
[entry_points]
|
[entry_points]
|
||||||
console_scripts =
|
|
||||||
kds-api = keystone.contrib.kds.cli.api:main
|
|
||||||
kds-manage = keystone.contrib.kds.cli.manage:main
|
|
||||||
|
|
||||||
oslo.config.opts =
|
oslo.config.opts =
|
||||||
keystone = keystone.common.config:list_opts
|
keystone = keystone.common.config:list_opts
|
||||||
|
|||||||
Reference in New Issue
Block a user