summaryrefslogtreecommitdiff
path: root/openstack/usr/share
diff options
context:
space:
mode:
authorPedro Alvarez <pedro.alvarez@codethink.co.uk>2015-02-18 16:40:04 +0000
committerPedro Alvarez <pedro.alvarez@codethink.co.uk>2015-03-16 17:30:38 +0000
commita90c7414cd5b7697c07d8f2c60a796064ebd7f28 (patch)
tree192976e8de638f103f1f55fe5b7b1508ee7fd175 /openstack/usr/share
parent68615e3afbdf6b5ccf886161d7706616d8805371 (diff)
downloaddefinitions-a90c7414cd5b7697c07d8f2c60a796064ebd7f28.tar.gz
Keystone configuration to ansible
Diffstat (limited to 'openstack/usr/share')
-rw-r--r--openstack/usr/share/openstack/hosts1
-rw-r--r--openstack/usr/share/openstack/keystone.yml73
-rw-r--r--openstack/usr/share/openstack/keystone/keystone-paste.ini112
-rw-r--r--openstack/usr/share/openstack/keystone/keystone.conf1384
-rw-r--r--openstack/usr/share/openstack/keystone/logging.conf39
-rw-r--r--openstack/usr/share/openstack/keystone/policy.json144
-rw-r--r--openstack/usr/share/openstack/modules/README3
-rw-r--r--openstack/usr/share/openstack/modules/cinder_manage105
-rw-r--r--openstack/usr/share/openstack/modules/glance176
-rw-r--r--openstack/usr/share/openstack/modules/glance_manage158
-rw-r--r--openstack/usr/share/openstack/modules/heat_manage105
-rw-r--r--openstack/usr/share/openstack/modules/keystone_manage123
-rw-r--r--openstack/usr/share/openstack/modules/keystone_service309
-rw-r--r--openstack/usr/share/openstack/modules/neutron_floating_ip274
-rw-r--r--openstack/usr/share/openstack/modules/neutron_network282
-rw-r--r--openstack/usr/share/openstack/modules/neutron_router210
-rw-r--r--openstack/usr/share/openstack/modules/neutron_router_gateway215
-rw-r--r--openstack/usr/share/openstack/modules/neutron_router_interface249
-rw-r--r--openstack/usr/share/openstack/modules/neutron_sec_group382
-rw-r--r--openstack/usr/share/openstack/modules/neutron_subnet294
-rw-r--r--openstack/usr/share/openstack/modules/nova_flavor188
-rw-r--r--openstack/usr/share/openstack/modules/nova_manage93
-rw-r--r--openstack/usr/share/openstack/openstack-keystone-setup92
23 files changed, 4919 insertions, 92 deletions
diff --git a/openstack/usr/share/openstack/hosts b/openstack/usr/share/openstack/hosts
new file mode 100644
index 00000000..5b97818d
--- /dev/null
+++ b/openstack/usr/share/openstack/hosts
@@ -0,0 +1 @@
+localhost ansible_connection=local
diff --git a/openstack/usr/share/openstack/keystone.yml b/openstack/usr/share/openstack/keystone.yml
new file mode 100644
index 00000000..dcd96857
--- /dev/null
+++ b/openstack/usr/share/openstack/keystone.yml
@@ -0,0 +1,73 @@
+---
+- hosts: localhost
+ vars_files:
+ - "/etc/openstack/keystone.conf"
+ tasks:
+ - name: Create the keystone user.
+ user: name=keystone comment="Openstack Keystone Daemons" shell=/sbin/nologin home=/var/lib/keystone
+
+ - name: Create the /var folders for keystone
+ file: path={{ item }} state=directory owner=keystone group=keystone
+ with_items:
+ - /var/run/keystone
+ - /var/lock/keystone
+ - /var/log/keystone
+ - /var/lib/keystone
+
+ - file: path=/etc/keystone state=directory
+ - name: Add the configuration needed for lorry in /etc using templates
+ template: src=/usr/share/openstack/keystone/{{ item }} dest=/etc/keystone/{{ item }}
+ with_lines:
+ - (cd /usr/share/openstack/keystone && find -type f)
+
+ - postgresql_user: name={{ KEYSTONE_DB_USER }} password={{ KEYSTONE_DB_PASSWORD }}
+ sudo: yes
+ sudo_user: keystone
+ - postgresql_db: name=keystone owner={{ KEYSTONE_DB_USER }}
+ sudo: yes
+ sudo_user: keystone
+
+ - keystone_manage: action=dbsync
+ sudo: yes
+ sudo_user: keystone
+
+ - name: Enable and start openstack-keystone service
+ service: name=openstack-keystone.service enabled=yes state=started
+
+ - keystone_user: >
+ tenant=admin
+ tenant_description="Admin Tenant"
+ token={{ KEYSTONE_TEMPORARY_ADMIN_TOKEN }}
+ endpoint={{ KEYSTONE_ADMIN_URL }}
+
+ - keystone_user: >
+ user=admin
+ tenant=admin
+ password={{ KEYSTONE_ADMIN_PASSWORD }}
+ token={{ KEYSTONE_TEMPORARY_ADMIN_TOKEN }}
+ endpoint={{ KEYSTONE_ADMIN_URL }}
+
+ - keystone_user: >
+ role=admin
+ user=admin
+ tenant=admin
+ token={{ KEYSTONE_TEMPORARY_ADMIN_TOKEN }}
+ endpoint={{ KEYSTONE_ADMIN_URL }}
+
+ - keystone_user: >
+ tenant=service
+ tenant_description="Service Tenant"
+ token={{ KEYSTONE_TEMPORARY_ADMIN_TOKEN }}
+ endpoint={{ KEYSTONE_ADMIN_URL }}
+
+ - keystone_service: >
+ name=keystone
+ type=identity
+ description="Keystone Identity Service"
+ publicurl={{ KEYSTONE_PUBLIC_URL }}
+ internalurl={{ KEYSTONE_INTERNAL_URL }}
+ adminurl={{ KEYSTONE_ADMIN_URL }}
+ region='RegionOne'
+ token={{ KEYSTONE_TEMPORARY_ADMIN_TOKEN }}
+ endpoint={{ KEYSTONE_ADMIN_URL }}
+
diff --git a/openstack/usr/share/openstack/keystone/keystone-paste.ini b/openstack/usr/share/openstack/keystone/keystone-paste.ini
new file mode 100644
index 00000000..cd132971
--- /dev/null
+++ b/openstack/usr/share/openstack/keystone/keystone-paste.ini
@@ -0,0 +1,112 @@
+# Keystone PasteDeploy configuration file.
+
+[filter:debug]
+paste.filter_factory = keystone.common.wsgi:Debug.factory
+
+[filter:build_auth_context]
+paste.filter_factory = keystone.middleware:AuthContextMiddleware.factory
+
+[filter:token_auth]
+paste.filter_factory = keystone.middleware:TokenAuthMiddleware.factory
+
+[filter:admin_token_auth]
+paste.filter_factory = keystone.middleware:AdminTokenAuthMiddleware.factory
+
+[filter:xml_body]
+paste.filter_factory = keystone.middleware:XmlBodyMiddleware.factory
+
+[filter:xml_body_v2]
+paste.filter_factory = keystone.middleware:XmlBodyMiddlewareV2.factory
+
+[filter:xml_body_v3]
+paste.filter_factory = keystone.middleware:XmlBodyMiddlewareV3.factory
+
+[filter:json_body]
+paste.filter_factory = keystone.middleware:JsonBodyMiddleware.factory
+
+[filter:user_crud_extension]
+paste.filter_factory = keystone.contrib.user_crud:CrudExtension.factory
+
+[filter:crud_extension]
+paste.filter_factory = keystone.contrib.admin_crud:CrudExtension.factory
+
+[filter:ec2_extension]
+paste.filter_factory = keystone.contrib.ec2:Ec2Extension.factory
+
+[filter:ec2_extension_v3]
+paste.filter_factory = keystone.contrib.ec2:Ec2ExtensionV3.factory
+
+[filter:federation_extension]
+paste.filter_factory = keystone.contrib.federation.routers:FederationExtension.factory
+
+[filter:oauth1_extension]
+paste.filter_factory = keystone.contrib.oauth1.routers:OAuth1Extension.factory
+
+[filter:s3_extension]
+paste.filter_factory = keystone.contrib.s3:S3Extension.factory
+
+[filter:endpoint_filter_extension]
+paste.filter_factory = keystone.contrib.endpoint_filter.routers:EndpointFilterExtension.factory
+
+[filter:simple_cert_extension]
+paste.filter_factory = keystone.contrib.simple_cert:SimpleCertExtension.factory
+
+[filter:revoke_extension]
+paste.filter_factory = keystone.contrib.revoke.routers:RevokeExtension.factory
+
+[filter:url_normalize]
+paste.filter_factory = keystone.middleware:NormalizingFilter.factory
+
+[filter:sizelimit]
+paste.filter_factory = keystone.middleware:RequestBodySizeLimiter.factory
+
+[filter:stats_monitoring]
+paste.filter_factory = keystone.contrib.stats:StatsMiddleware.factory
+
+[filter:stats_reporting]
+paste.filter_factory = keystone.contrib.stats:StatsExtension.factory
+
+[filter:access_log]
+paste.filter_factory = keystone.contrib.access:AccessLogMiddleware.factory
+
+[app:public_service]
+paste.app_factory = keystone.service:public_app_factory
+
+[app:service_v3]
+paste.app_factory = keystone.service:v3_app_factory
+
+[app:admin_service]
+paste.app_factory = keystone.service:admin_app_factory
+
+[pipeline:public_api]
+pipeline = sizelimit url_normalize build_auth_context token_auth admin_token_auth xml_body_v2 json_body ec2_extension user_crud_extension public_service
+
+[pipeline:admin_api]
+pipeline = sizelimit url_normalize build_auth_context token_auth admin_token_auth xml_body_v2 json_body ec2_extension s3_extension crud_extension admin_service
+
+[pipeline:api_v3]
+pipeline = sizelimit url_normalize build_auth_context token_auth admin_token_auth xml_body_v3 json_body ec2_extension_v3 s3_extension simple_cert_extension service_v3
+
+[app:public_version_service]
+paste.app_factory = keystone.service:public_version_app_factory
+
+[app:admin_version_service]
+paste.app_factory = keystone.service:admin_version_app_factory
+
+[pipeline:public_version_api]
+pipeline = sizelimit url_normalize xml_body public_version_service
+
+[pipeline:admin_version_api]
+pipeline = sizelimit url_normalize xml_body admin_version_service
+
+[composite:main]
+use = egg:Paste#urlmap
+/v2.0 = public_api
+/v3 = api_v3
+/ = public_version_api
+
+[composite:admin]
+use = egg:Paste#urlmap
+/v2.0 = admin_api
+/v3 = api_v3
+/ = admin_version_api
diff --git a/openstack/usr/share/openstack/keystone/keystone.conf b/openstack/usr/share/openstack/keystone/keystone.conf
new file mode 100644
index 00000000..c35ecc15
--- /dev/null
+++ b/openstack/usr/share/openstack/keystone/keystone.conf
@@ -0,0 +1,1384 @@
+[DEFAULT]
+
+#
+# Options defined in keystone
+#
+
+# A "shared secret" that can be used to bootstrap Keystone.
+# This "token" does not represent a user, and carries no
+# explicit authorization. To disable in production (highly
+# recommended), remove AdminTokenAuthMiddleware from your
+# paste application pipelines (for example, in keystone-
+# paste.ini). (string value)
+admin_token={{ KEYSTONE_TEMPORARY_ADMIN_TOKEN }}
+
+# The IP address of the network interface for the public
+# service to listen on. (string value)
+# Deprecated group/name - [DEFAULT]/bind_host
+#public_bind_host=0.0.0.0
+
+# The IP address of the network interface for the admin
+# service to listen on. (string value)
+# Deprecated group/name - [DEFAULT]/bind_host
+#admin_bind_host=0.0.0.0
+
+# The port which the OpenStack Compute service listens on.
+# (integer value)
+compute_port=8774
+
+# The port number which the admin service listens on. (integer
+# value)
+admin_port=35357
+
+# The port number which the public service listens on.
+# (integer value)
+public_port=5000
+
+# The base public endpoint URL for Keystone that is advertised
+# to clients (NOTE: this does NOT affect how Keystone listens
+# for connections). Defaults to the base host URL of the
+# request. E.g. a request to http://server:5000/v2.0/users
+# will default to http://server:5000. You should only need to
+# set this value if the base URL contains a path (e.g.
+# /prefix/v2.0) or the endpoint should be found on a different
+# server. (string value)
+#public_endpoint=<None>
+
+# The base admin endpoint URL for Keystone that is advertised
+# to clients (NOTE: this does NOT affect how Keystone listens
+# for connections). Defaults to the base host URL of the
+# request. E.g. a request to http://server:35357/v2.0/users
+# will default to http://server:35357. You should only need to
+# set this value if the base URL contains a path (e.g.
+# /prefix/v2.0) or the endpoint should be found on a different
+# server. (string value)
+#admin_endpoint=<None>
+
+# The number of worker processes to serve the public WSGI
+# application (integer value)
+#public_workers=1
+
+# The number of worker processes to serve the admin WSGI
+# application (integer value)
+#admin_workers=1
+
+# Enforced by optional sizelimit middleware
+# (keystone.middleware:RequestBodySizeLimiter). (integer
+# value)
+#max_request_body_size=114688
+
+# Limit the sizes of user & project ID/names. (integer value)
+#max_param_size=64
+
+# Similar to max_param_size, but provides an exception for
+# token values. (integer value)
+#max_token_size=8192
+
+# During a SQL upgrade member_role_id will be used to create a
+# new role that will replace records in the assignment table
+# with explicit role grants. After migration, the
+# member_role_id will be used in the API add_user_to_project.
+# (string value)
+#member_role_id=9fe2ff9ee4384b1894a90878d3e92bab
+
+# During a SQL upgrade member_role_name will be used to create
+# a new role that will replace records in the assignment table
+# with explicit role grants. After migration, member_role_name
+# will be ignored. (string value)
+#member_role_name=_member_
+
+# The value passed as the keyword "rounds" to passlib's
+# encrypt method. (integer value)
+#crypt_strength=40000
+
+# Set this to true if you want to enable TCP_KEEPALIVE on
+# server sockets, i.e. sockets used by the Keystone wsgi
+# server for client connections. (boolean value)
+#tcp_keepalive=false
+
+# Sets the value of TCP_KEEPIDLE in seconds for each server
+# socket. Only applies if tcp_keepalive is true. Not supported
+# on OS X. (integer value)
+#tcp_keepidle=600
+
+# The maximum number of entities that will be returned in a
+# collection, with no limit set by default. This global limit
+# may be then overridden for a specific driver, by specifying
+# a list_limit in the appropriate section (e.g. [assignment]).
+# (integer value)
+#list_limit=<None>
+
+# Set this to false if you want to enable the ability for
+# user, group and project entities to be moved between domains
+# by updating their domain_id. Allowing such movement is not
+# recommended if the scope of a domain admin is being
+# restricted by use of an appropriate policy file (see
+# policy.v3cloudsample as an example). (boolean value)
+#domain_id_immutable=true
+
+# If set to true, strict password length checking is performed
+# for password manipulation. If a password exceeds the maximum
+# length, the operation will fail with an HTTP 403 Forbidden
+# error. If set to false, passwords are automatically
+# truncated to the maximum length. (boolean value)
+#strict_password_check=false
+
+
+#
+# Options defined in oslo.messaging
+#
+
+# Use durable queues in amqp. (boolean value)
+# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
+#amqp_durable_queues=false
+
+# Auto-delete queues in amqp. (boolean value)
+#amqp_auto_delete=false
+
+# Size of RPC connection pool. (integer value)
+#rpc_conn_pool_size=30
+
+# Modules of exceptions that are permitted to be recreated
+# upon receiving exception data from an rpc call. (list value)
+#allowed_rpc_exception_modules=oslo.messaging.exceptions,nova.exception,cinder.exception,exceptions
+
+# Qpid broker hostname. (string value)
+#qpid_hostname=keystone
+
+# Qpid broker port. (integer value)
+#qpid_port=5672
+
+# Qpid HA cluster host:port pairs. (list value)
+#qpid_hosts=$qpid_hostname:$qpid_port
+
+# Username for Qpid connection. (string value)
+#qpid_username=
+
+# Password for Qpid connection. (string value)
+#qpid_password=
+
+# Space separated list of SASL mechanisms to use for auth.
+# (string value)
+#qpid_sasl_mechanisms=
+
+# Seconds between connection keepalive heartbeats. (integer
+# value)
+#qpid_heartbeat=60
+
+# Transport to use, either 'tcp' or 'ssl'. (string value)
+#qpid_protocol=tcp
+
+# Whether to disable the Nagle algorithm. (boolean value)
+#qpid_tcp_nodelay=true
+
+# The qpid topology version to use. Version 1 is what was
+# originally used by impl_qpid. Version 2 includes some
+# backwards-incompatible changes that allow broker federation
+# to work. Users should update to version 2 when they are
+# able to take everything down, as it requires a clean break.
+# (integer value)
+#qpid_topology_version=1
+
+# SSL version to use (valid only if SSL enabled). valid values
+# are TLSv1, SSLv23 and SSLv3. SSLv2 may be available on some
+# distributions. (string value)
+#kombu_ssl_version=
+
+# SSL key file (valid only if SSL enabled). (string value)
+#kombu_ssl_keyfile=
+
+# SSL cert file (valid only if SSL enabled). (string value)
+#kombu_ssl_certfile=
+
+# SSL certification authority file (valid only if SSL
+# enabled). (string value)
+#kombu_ssl_ca_certs=
+
+# How long to wait before reconnecting in response to an AMQP
+# consumer cancel notification. (floating point value)
+#kombu_reconnect_delay=1.0
+
+# The RabbitMQ broker address where a single node is used.
+# (string value)
+rabbit_host={{ RABBITMQ_HOST }}
+
+# The RabbitMQ broker port where a single node is used.
+# (integer value)
+rabbit_port={{ RABBITMQ_PORT }}
+
+# RabbitMQ HA cluster host:port pairs. (list value)
+rabbit_hosts=$rabbit_host:$rabbit_port
+
+# Connect over SSL for RabbitMQ. (boolean value)
+rabbit_use_ssl=false
+
+# The RabbitMQ userid. (string value)
+rabbit_userid={{ RABBITMQ_USER }}
+
+# The RabbitMQ password. (string value)
+rabbit_password={{ RABBITMQ_PASSWORD }}
+
+# the RabbitMQ login method (string value)
+#rabbit_login_method=AMQPLAIN
+
+# The RabbitMQ virtual host. (string value)
+#rabbit_virtual_host=/
+
+# How frequently to retry connecting with RabbitMQ. (integer
+# value)
+#rabbit_retry_interval=1
+
+# How long to backoff for between retries when connecting to
+# RabbitMQ. (integer value)
+#rabbit_retry_backoff=2
+
+# Maximum number of RabbitMQ connection retries. Default is 0
+# (infinite retry count). (integer value)
+#rabbit_max_retries=0
+
+# Use HA queues in RabbitMQ (x-ha-policy: all). If you change
+# this option, you must wipe the RabbitMQ database. (boolean
+# value)
+#rabbit_ha_queues=false
+
+# If passed, use a fake RabbitMQ provider. (boolean value)
+#fake_rabbit=false
+
+# ZeroMQ bind address. Should be a wildcard (*), an ethernet
+# interface, or IP. The "host" option should point or resolve
+# to this address. (string value)
+#rpc_zmq_bind_address=*
+
+# MatchMaker driver. (string value)
+#rpc_zmq_matchmaker=oslo.messaging._drivers.matchmaker.MatchMakerLocalhost
+
+# ZeroMQ receiver listening port. (integer value)
+#rpc_zmq_port=9501
+
+# Number of ZeroMQ contexts, defaults to 1. (integer value)
+#rpc_zmq_contexts=1
+
+# Maximum number of ingress messages to locally buffer per
+# topic. Default is unlimited. (integer value)
+#rpc_zmq_topic_backlog=<None>
+
+# Directory for holding IPC sockets. (string value)
+#rpc_zmq_ipc_dir=/var/run/openstack
+
+# Name of this node. Must be a valid hostname, FQDN, or IP
+# address. Must match "host" option, if running Nova. (string
+# value)
+#rpc_zmq_host=keystone
+
+# Seconds to wait before a cast expires (TTL). Only supported
+# by impl_zmq. (integer value)
+#rpc_cast_timeout=30
+
+# Heartbeat frequency. (integer value)
+#matchmaker_heartbeat_freq=300
+
+# Heartbeat time-to-live. (integer value)
+#matchmaker_heartbeat_ttl=600
+
+# Host to locate redis. (string value)
+#host=localhost
+
+# Use this port to connect to redis host. (integer value)
+#port=6379
+
+# Password for Redis server (optional). (string value)
+#password=<None>
+
+# Size of RPC greenthread pool. (integer value)
+#rpc_thread_pool_size=64
+
+# Driver or drivers to handle sending notifications. (multi
+# valued)
+#notification_driver=
+
+# AMQP topic used for OpenStack notifications. (list value)
+# Deprecated group/name - [rpc_notifier2]/topics
+#notification_topics=notifications
+
+# Seconds to wait for a response from a call. (integer value)
+#rpc_response_timeout=60
+
+# A URL representing the messaging driver to use and its full
+# configuration. If not set, we fall back to the rpc_backend
+# option and driver specific configuration. (string value)
+#transport_url=<None>
+
+# The messaging driver to use, defaults to rabbit. Other
+# drivers include qpid and zmq. (string value)
+rpc_backend=rabbit
+
+# The default exchange under which topics are scoped. May be
+# overridden by an exchange name specified in the
+# transport_url option. (string value)
+#control_exchange=openstack
+
+
+#
+# Options defined in keystone.notifications
+#
+
+# Default publisher_id for outgoing notifications (string
+# value)
+#default_publisher_id=<None>
+
+
+#
+# Options defined in keystone.middleware.ec2_token
+#
+
+# URL to get token from ec2 request. (string value)
+#keystone_ec2_url=http://localhost:5000/v2.0/ec2tokens
+
+# Required if EC2 server requires client certificate. (string
+# value)
+#keystone_ec2_keyfile=<None>
+
+# Client certificate key filename. Required if EC2 server
+# requires client certificate. (string value)
+#keystone_ec2_certfile=<None>
+
+# A PEM encoded certificate authority to use when verifying
+# HTTPS connections. Defaults to the system CAs. (string
+# value)
+#keystone_ec2_cafile=<None>
+
+# Disable SSL certificate verification. (boolean value)
+#keystone_ec2_insecure=false
+
+
+#
+# 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
+#
+
+# Enables or disables 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_identity)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,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN
+
+# Enables or disables publication of error events. (boolean
+# value)
+#publish_errors=false
+
+# Enables or disables fatal status of deprecations. (boolean
+# value)
+#fatal_deprecations=false
+
+# The format for an instance that is passed with the log
+# message. (string value)
+#instance_format="[instance: %(uuid)s] "
+
+# The format for an instance UUID that is passed with the log
+# message. (string value)
+#instance_uuid_format="[instance: %(uuid)s] "
+
+# The name of a logging configuration file. This file is
+# appended to any existing logging configuration files. For
+# details about logging configuration files, see the Python
+# logging module documentation. (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. Existing syslog format is DEPRECATED
+# during I, and will chang in J to honor RFC5424. (boolean
+# value)
+#use_syslog=false
+
+# (Optional) Enables or disables syslog rfc5424 format for
+# logging. If enabled, prefixes the MSG part of the syslog
+# message with APP-NAME (RFC5424). The format without the APP-
+# NAME is deprecated in I, and will be removed in J. (boolean
+# value)
+#use_syslog_rfc_format=false
+
+# Syslog facility to receive log lines. (string value)
+#syslog_log_facility=LOG_USER
+
+
+#
+# Options defined in keystone.openstack.common.policy
+#
+
+# The JSON file that defines policies. (string value)
+#policy_file=policy.json
+
+# Default rule. Enforced when a requested rule is not found.
+# (string value)
+#policy_default_rule=default
+
+
+[assignment]
+
+#
+# Options defined in keystone
+#
+
+# Assignment backend driver. (string value)
+#driver=<None>
+
+# Toggle for assignment caching. This has no effect unless
+# global caching is enabled. (boolean value)
+#caching=true
+
+# TTL (in seconds) to cache assignment data. This has no
+# effect unless global caching is enabled. (integer value)
+#cache_time=<None>
+
+# Maximum number of entities that will be returned in an
+# assignment collection. (integer value)
+#list_limit=<None>
+
+
+[auth]
+
+#
+# Options defined in keystone
+#
+
+# Default auth methods. (list value)
+#methods=external,password,token
+
+# The password auth plugin module. (string value)
+#password=keystone.auth.plugins.password.Password
+
+# The token auth plugin module. (string value)
+#token=keystone.auth.plugins.token.Token
+
+# The external (REMOTE_USER) auth plugin module. (string
+# value)
+#external=keystone.auth.plugins.external.DefaultDomain
+
+
+[cache]
+
+#
+# Options defined in keystone
+#
+
+# Prefix for building the configuration dictionary for the
+# cache region. This should not need to be changed unless
+# there is another dogpile.cache region with the same
+# configuration name. (string value)
+#config_prefix=cache.keystone
+
+# Default TTL, in seconds, for any cached item in the
+# dogpile.cache region. This applies to any cached method that
+# doesn't have an explicit cache expiration time defined for
+# it. (integer value)
+#expiration_time=600
+
+# Dogpile.cache backend module. It is recommended that
+# Memcache (dogpile.cache.memcached) or Redis
+# (dogpile.cache.redis) be used in production deployments.
+# Small workloads (single process) like devstack can use the
+# dogpile.cache.memory backend. (string value)
+#backend=keystone.common.cache.noop
+
+# Use a key-mangling function (sha1) to ensure fixed length
+# cache-keys. This is toggle-able for debugging purposes, it
+# is highly recommended to always leave this set to true.
+# (boolean value)
+#use_key_mangler=true
+
+# Arguments supplied to the backend module. Specify this
+# option once per argument to be passed to the dogpile.cache
+# backend. Example format: "<argname>:<value>". (multi valued)
+#backend_argument=
+
+# Proxy classes to import that will affect the way the
+# dogpile.cache backend functions. See the dogpile.cache
+# documentation on changing-backend-behavior. (list value)
+#proxies=
+
+# Global toggle for all caching using the should_cache_fn
+# mechanism. (boolean value)
+#enabled=false
+
+# Extra debugging from the cache backend (cache keys,
+# get/set/delete/etc calls). This is only really useful if you
+# need to see the specific cache-backend get/set/delete calls
+# with the keys/values. Typically this should be left set to
+# false. (boolean value)
+#debug_cache_backend=false
+
+
+[catalog]
+
+#
+# Options defined in keystone
+#
+
+# Catalog template file name for use with the template catalog
+# backend. (string value)
+#template_file=default_catalog.templates
+
+# Catalog backend driver. (string value)
+#driver=keystone.catalog.backends.sql.Catalog
+
+# Maximum number of entities that will be returned in a
+# catalog collection. (integer value)
+#list_limit=<None>
+
+
+[credential]
+
+#
+# Options defined in keystone
+#
+
+# Credential backend driver. (string value)
+#driver=keystone.credential.backends.sql.Credential
+
+
+[database]
+
+#
+# Options defined in oslo.db
+#
+
+# The file name to use with SQLite. (string value)
+#sqlite_db=oslo.sqlite
+
+# If True, SQLite uses synchronous mode. (boolean value)
+#sqlite_synchronous=true
+
+# The back end to use for the database. (string value)
+# Deprecated group/name - [DEFAULT]/db_backend
+#backend=sqlalchemy
+
+# The SQLAlchemy connection string to use 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=<None>
+connection=postgresql://{{ KEYSTONE_DB_USER }}:{{ KEYSTONE_DB_PASSWORD }}@{{ CONTROLLER_HOST }}/keystone
+
+# The SQLAlchemy connection string to use to connect to the
+# slave database. (string value)
+#slave_connection=<None>
+
+# The SQL mode to be used for MySQL sessions. This option,
+# including the default, overrides any server-set SQL mode. To
+# use whatever SQL mode is set by the server configuration,
+# set this to no value. Example: mysql_sql_mode= (string
+# value)
+#mysql_sql_mode=TRADITIONAL
+
+# Timeout before idle SQL connections are reaped. (integer
+# value)
+# Deprecated group/name - [DEFAULT]/sql_idle_timeout
+# Deprecated group/name - [DATABASE]/sql_idle_timeout
+# Deprecated group/name - [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. Set to -1 to
+# specify 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>
+
+# Enable the experimental use of database reconnect on
+# connection lost. (boolean value)
+#use_db_reconnect=false
+
+# Seconds between database connection retries. (integer value)
+#db_retry_interval=1
+
+# If True, increases the interval between database connection
+# retries up to db_max_retry_interval. (boolean value)
+#db_inc_retry_interval=true
+
+# If db_inc_retry_interval is set, the maximum seconds between
+# database connection retries. (integer value)
+#db_max_retry_interval=10
+
+# Maximum database connection retries before error is raised.
+# Set to -1 to specify an infinite retry count. (integer
+# value)
+#db_max_retries=20
+
+
+[ec2]
+
+#
+# Options defined in keystone
+#
+
+# EC2Credential backend driver. (string value)
+#driver=keystone.contrib.ec2.backends.kvs.Ec2
+
+
+[endpoint_filter]
+
+#
+# Options defined in keystone
+#
+
+# Endpoint Filter backend driver (string value)
+#driver=keystone.contrib.endpoint_filter.backends.sql.EndpointFilter
+
+# Toggle to return all active endpoints if no filter exists.
+# (boolean value)
+#return_all_endpoints_if_no_filter=true
+
+
+[federation]
+
+#
+# Options defined in keystone
+#
+
+# Federation backend driver. (string value)
+#driver=keystone.contrib.federation.backends.sql.Federation
+
+# Value to be used when filtering assertion parameters from
+# the environment. (string value)
+#assertion_prefix=
+
+
+[identity]
+
+#
+# Options defined in keystone
+#
+
+# This references the domain to use for all Identity API v2
+# requests (which are not aware of domains). A domain with
+# this ID will be created for you by keystone-manage db_sync
+# in migration 008. The domain referenced by this ID cannot be
+# deleted on the v3 API, to prevent accidentally breaking the
+# v2 API. There is nothing special about this domain, other
+# than the fact that it must exist to order to maintain
+# support for your v2 clients. (string value)
+#default_domain_id=default
+
+# A subset (or all) of domains can have their own identity
+# driver, each with their own partial configuration file in a
+# domain configuration directory. Only values specific to the
+# domain need to be placed in the domain specific
+# configuration file. This feature is disabled by default; set
+# to true to enable. (boolean value)
+#domain_specific_drivers_enabled=false
+
+# Path for Keystone to locate the domain specific identity
+# configuration files if domain_specific_drivers_enabled is
+# set to true. (string value)
+#domain_config_dir=/etc/keystone/domains
+
+# Identity backend driver. (string value)
+#driver=keystone.identity.backends.sql.Identity
+
+# Maximum supported length for user passwords; decrease to
+# improve performance. (integer value)
+#max_password_length=4096
+
+# Maximum number of entities that will be returned in an
+# identity collection. (integer value)
+#list_limit=<None>
+
+
+[kvs]
+
+#
+# Options defined in keystone
+#
+
+# Extra dogpile.cache backend modules to register with the
+# dogpile.cache library. (list value)
+#backends=
+
+# Prefix for building the configuration dictionary for the KVS
+# region. This should not need to be changed unless there is
+# another dogpile.cache region with the same configuration
+# name. (string value)
+#config_prefix=keystone.kvs
+
+# Toggle to disable using a key-mangling function to ensure
+# fixed length keys. This is toggle-able for debugging
+# purposes, it is highly recommended to always leave this set
+# to true. (boolean value)
+#enable_key_mangler=true
+
+# Default lock timeout for distributed locking. (integer
+# value)
+#default_lock_timeout=5
+
+
+[ldap]
+
+#
+# Options defined in keystone
+#
+
+# URL for connecting to the LDAP server. (string value)
+#url=ldap://keystone
+
+# User BindDN to query the LDAP server. (string value)
+#user=<None>
+
+# Password for the BindDN to query the LDAP server. (string
+# value)
+#password=<None>
+
+# LDAP server suffix (string value)
+#suffix=cn=example,cn=com
+
+# If true, will add a dummy member to groups. This is required
+# if the objectclass for groups requires the "member"
+# attribute. (boolean value)
+#use_dumb_member=false
+
+# DN of the "dummy member" to use when "use_dumb_member" is
+# enabled. (string value)
+#dumb_member=cn=dumb,dc=nonexistent
+
+# Delete subtrees using the subtree delete control. Only
+# enable this option if your LDAP server supports subtree
+# deletion. (boolean value)
+#allow_subtree_delete=false
+
+# The LDAP scope for queries, this can be either "one"
+# (onelevel/singleLevel) or "sub" (subtree/wholeSubtree).
+# (string value)
+#query_scope=one
+
+# Maximum results per page; a value of zero ("0") disables
+# paging. (integer value)
+#page_size=0
+
+# The LDAP dereferencing option for queries. This can be
+# either "never", "searching", "always", "finding" or
+# "default". The "default" option falls back to using default
+# dereferencing configured by your ldap.conf. (string value)
+#alias_dereferencing=default
+
+# Sets the LDAP debugging level for LDAP calls. A value of 0
+# means that debugging is not enabled. This value is a
+# bitmask, consult your LDAP documentation for possible
+# values. (integer value)
+#debug_level=<None>
+
+# Override the system's default referral chasing behavior for
+# queries. (boolean value)
+#chase_referrals=<None>
+
+# Search base for users. (string value)
+#user_tree_dn=<None>
+
+# LDAP search filter for users. (string value)
+#user_filter=<None>
+
+# LDAP objectclass for users. (string value)
+#user_objectclass=inetOrgPerson
+
+# LDAP attribute mapped to user id. (string value)
+#user_id_attribute=cn
+
+# LDAP attribute mapped to user name. (string value)
+#user_name_attribute=sn
+
+# LDAP attribute mapped to user email. (string value)
+#user_mail_attribute=email
+
+# LDAP attribute mapped to password. (string value)
+#user_pass_attribute=userPassword
+
+# LDAP attribute mapped to user enabled flag. (string value)
+#user_enabled_attribute=enabled
+
+# Bitmask integer to indicate the bit that the enabled value
+# is stored in if the LDAP server represents "enabled" as a
+# bit on an integer rather than a boolean. A value of "0"
+# indicates the mask is not used. If this is not set to "0"
+# the typical value is "2". This is typically used when
+# "user_enabled_attribute = userAccountControl". (integer
+# value)
+#user_enabled_mask=0
+
+# Default value to enable users. This should match an
+# appropriate int value if the LDAP server uses non-boolean
+# (bitmask) values to indicate if a user is enabled or
+# disabled. If this is not set to "True" the typical value is
+# "512". This is typically used when "user_enabled_attribute =
+# userAccountControl". (string value)
+#user_enabled_default=True
+
+# List of attributes stripped off the user on update. (list
+# value)
+#user_attribute_ignore=default_project_id,tenants
+
+# LDAP attribute mapped to default_project_id for users.
+# (string value)
+#user_default_project_id_attribute=<None>
+
+# Allow user creation in LDAP backend. (boolean value)
+#user_allow_create=true
+
+# Allow user updates in LDAP backend. (boolean value)
+#user_allow_update=true
+
+# Allow user deletion in LDAP backend. (boolean value)
+#user_allow_delete=true
+
+# If true, Keystone uses an alternative method to determine if
+# a user is enabled or not by checking if they are a member of
+# the "user_enabled_emulation_dn" group. (boolean value)
+#user_enabled_emulation=false
+
+# DN of the group entry to hold enabled users when using
+# enabled emulation. (string value)
+#user_enabled_emulation_dn=<None>
+
+# List of additional LDAP attributes used for mapping
+# additional attribute mappings for users. Attribute mapping
+# format is <ldap_attr>:<user_attr>, where ldap_attr is the
+# attribute in the LDAP entry and user_attr is the Identity
+# API attribute. (list value)
+#user_additional_attribute_mapping=
+
+# Search base for projects (string value)
+# Deprecated group/name - [ldap]/tenant_tree_dn
+#project_tree_dn=<None>
+
+# LDAP search filter for projects. (string value)
+# Deprecated group/name - [ldap]/tenant_filter
+#project_filter=<None>
+
+# LDAP objectclass for projects. (string value)
+# Deprecated group/name - [ldap]/tenant_objectclass
+#project_objectclass=groupOfNames
+
+# LDAP attribute mapped to project id. (string value)
+# Deprecated group/name - [ldap]/tenant_id_attribute
+#project_id_attribute=cn
+
+# LDAP attribute mapped to project membership for user.
+# (string value)
+# Deprecated group/name - [ldap]/tenant_member_attribute
+#project_member_attribute=member
+
+# LDAP attribute mapped to project name. (string value)
+# Deprecated group/name - [ldap]/tenant_name_attribute
+#project_name_attribute=ou
+
+# LDAP attribute mapped to project description. (string value)
+# Deprecated group/name - [ldap]/tenant_desc_attribute
+#project_desc_attribute=description
+
+# LDAP attribute mapped to project enabled. (string value)
+# Deprecated group/name - [ldap]/tenant_enabled_attribute
+#project_enabled_attribute=enabled
+
+# LDAP attribute mapped to project domain_id. (string value)
+# Deprecated group/name - [ldap]/tenant_domain_id_attribute
+#project_domain_id_attribute=businessCategory
+
+# List of attributes stripped off the project on update. (list
+# value)
+# Deprecated group/name - [ldap]/tenant_attribute_ignore
+#project_attribute_ignore=
+
+# Allow project creation in LDAP backend. (boolean value)
+# Deprecated group/name - [ldap]/tenant_allow_create
+#project_allow_create=true
+
+# Allow project update in LDAP backend. (boolean value)
+# Deprecated group/name - [ldap]/tenant_allow_update
+#project_allow_update=true
+
+# Allow project deletion in LDAP backend. (boolean value)
+# Deprecated group/name - [ldap]/tenant_allow_delete
+#project_allow_delete=true
+
+# If true, Keystone uses an alternative method to determine if
+# a project is enabled or not by checking if they are a member
+# of the "project_enabled_emulation_dn" group. (boolean value)
+# Deprecated group/name - [ldap]/tenant_enabled_emulation
+#project_enabled_emulation=false
+
+# DN of the group entry to hold enabled projects when using
+# enabled emulation. (string value)
+# Deprecated group/name - [ldap]/tenant_enabled_emulation_dn
+#project_enabled_emulation_dn=<None>
+
+# Additional attribute mappings for projects. Attribute
+# mapping format is <ldap_attr>:<user_attr>, where ldap_attr
+# is the attribute in the LDAP entry and user_attr is the
+# Identity API attribute. (list value)
+# Deprecated group/name - [ldap]/tenant_additional_attribute_mapping
+#project_additional_attribute_mapping=
+
+# Search base for roles. (string value)
+#role_tree_dn=<None>
+
+# LDAP search filter for roles. (string value)
+#role_filter=<None>
+
+# LDAP objectclass for roles. (string value)
+#role_objectclass=organizationalRole
+
+# LDAP attribute mapped to role id. (string value)
+#role_id_attribute=cn
+
+# LDAP attribute mapped to role name. (string value)
+#role_name_attribute=ou
+
+# LDAP attribute mapped to role membership. (string value)
+#role_member_attribute=roleOccupant
+
+# List of attributes stripped off the role on update. (list
+# value)
+#role_attribute_ignore=
+
+# Allow role creation in LDAP backend. (boolean value)
+#role_allow_create=true
+
+# Allow role update in LDAP backend. (boolean value)
+#role_allow_update=true
+
+# Allow role deletion in LDAP backend. (boolean value)
+#role_allow_delete=true
+
+# Additional attribute mappings for roles. Attribute mapping
+# format is <ldap_attr>:<user_attr>, where ldap_attr is the
+# attribute in the LDAP entry and user_attr is the Identity
+# API attribute. (list value)
+#role_additional_attribute_mapping=
+
+# Search base for groups. (string value)
+#group_tree_dn=<None>
+
+# LDAP search filter for groups. (string value)
+#group_filter=<None>
+
+# LDAP objectclass for groups. (string value)
+#group_objectclass=groupOfNames
+
+# LDAP attribute mapped to group id. (string value)
+#group_id_attribute=cn
+
+# LDAP attribute mapped to group name. (string value)
+#group_name_attribute=ou
+
+# LDAP attribute mapped to show group membership. (string
+# value)
+#group_member_attribute=member
+
+# LDAP attribute mapped to group description. (string value)
+#group_desc_attribute=description
+
+# List of attributes stripped off the group on update. (list
+# value)
+#group_attribute_ignore=
+
+# Allow group creation in LDAP backend. (boolean value)
+#group_allow_create=true
+
+# Allow group update in LDAP backend. (boolean value)
+#group_allow_update=true
+
+# Allow group deletion in LDAP backend. (boolean value)
+#group_allow_delete=true
+
+# Additional attribute mappings for groups. Attribute mapping
+# format is <ldap_attr>:<user_attr>, where ldap_attr is the
+# attribute in the LDAP entry and user_attr is the Identity
+# API attribute. (list value)
+#group_additional_attribute_mapping=
+
+# CA certificate file path for communicating with LDAP
+# servers. (string value)
+#tls_cacertfile=<None>
+
+# CA certificate directory path for communicating with LDAP
+# servers. (string value)
+#tls_cacertdir=<None>
+
+# Enable TLS for communicating with LDAP servers. (boolean
+# value)
+#use_tls=false
+
+# Valid options for tls_req_cert are demand, never, and allow.
+# (string value)
+#tls_req_cert=demand
+
+
+[matchmaker_ring]
+
+#
+# Options defined in oslo.messaging
+#
+
+# Matchmaker ring file (JSON). (string value)
+# Deprecated group/name - [DEFAULT]/matchmaker_ringfile
+#ringfile=/etc/oslo/matchmaker_ring.json
+
+
+[memcache]
+
+#
+# Options defined in keystone
+#
+
+# Memcache servers in the format of "host:port". (list value)
+#servers=localhost:11211
+
+# Number of compare-and-set attempts to make when using
+# compare-and-set in the token memcache back end. (integer
+# value)
+#max_compare_and_set_retry=16
+
+
+[oauth1]
+
+#
+# Options defined in keystone
+#
+
+# Credential backend driver. (string value)
+#driver=keystone.contrib.oauth1.backends.sql.OAuth1
+
+# Duration (in seconds) for the OAuth Request Token. (integer
+# value)
+#request_token_duration=28800
+
+# Duration (in seconds) for the OAuth Access Token. (integer
+# value)
+#access_token_duration=86400
+
+
+[os_inherit]
+
+#
+# Options defined in keystone
+#
+
+# role-assignment inheritance to projects from owning domain
+# can be optionally enabled. (boolean value)
+#enabled=false
+
+
+[paste_deploy]
+
+#
+# Options defined in keystone
+#
+
+# Name of the paste configuration file that defines the
+# available pipelines. (string value)
+#config_file=keystone-paste.ini
+
+
+[policy]
+
+#
+# Options defined in keystone
+#
+
+# Policy backend driver. (string value)
+#driver=keystone.policy.backends.sql.Policy
+
+# Maximum number of entities that will be returned in a policy
+# collection. (integer value)
+#list_limit=<None>
+
+
+[revoke]
+
+#
+# Options defined in keystone
+#
+
+# An implementation of the backend for persisting revocation
+# events. (string value)
+driver=keystone.contrib.revoke.backends.sql.Revoke
+
+# This value (calculated in seconds) is added to token
+# expiration before a revocation event may be removed from the
+# backend. (integer value)
+#expiration_buffer=1800
+
+# Toggle for revocation event cacheing. This has no effect
+# unless global caching is enabled. (boolean value)
+#caching=true
+
+
+[signing]
+
+#
+# Options defined in keystone
+#
+
+# Deprecated in favor of provider in the [token] section.
+# (string value)
+#token_format=<None>
+
+# Path of the certfile for token signing. For non-production
+# environments, you may be interested in using `keystone-
+# manage pki_setup` to generate self-signed certificates.
+# (string value)
+#certfile=/etc/keystone/ssl/certs/signing_cert.pem
+
+# Path of the keyfile for token signing. (string value)
+#keyfile=/etc/keystone/ssl/private/signing_key.pem
+
+# Path of the CA for token signing. (string value)
+#ca_certs=/etc/keystone/ssl/certs/ca.pem
+
+# Path of the CA key for token signing. (string value)
+#ca_key=/etc/keystone/ssl/private/cakey.pem
+
+# Key size (in bits) for token signing cert (auto generated
+# certificate). (integer value)
+#key_size=2048
+
+# Days the token signing cert is valid for (auto generated
+# certificate). (integer value)
+#valid_days=3650
+
+# Certificate subject (auto generated certificate) for token
+# signing. (string value)
+#cert_subject=/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com
+
+
+[ssl]
+
+#
+# Options defined in keystone
+#
+
+# Toggle for SSL support on the Keystone eventlet servers.
+# (boolean value)
+#enable=false
+
+# Path of the certfile for SSL. For non-production
+# environments, you may be interested in using `keystone-
+# manage ssl_setup` to generate self-signed certificates.
+# (string value)
+#certfile=/etc/keystone/ssl/certs/keystone.pem
+
+# Path of the keyfile for SSL. (string value)
+#keyfile=/etc/keystone/ssl/private/keystonekey.pem
+
+# Path of the ca cert file for SSL. (string value)
+#ca_certs=/etc/keystone/ssl/certs/ca.pem
+
+# Path of the CA key file for SSL. (string value)
+#ca_key=/etc/keystone/ssl/private/cakey.pem
+
+# Require client certificate. (boolean value)
+#cert_required=false
+
+# SSL key length (in bits) (auto generated certificate).
+# (integer value)
+#key_size=1024
+
+# Days the certificate is valid for once signed (auto
+# generated certificate). (integer value)
+#valid_days=3650
+
+# SSL certificate subject (auto generated certificate).
+# (string value)
+#cert_subject=/C=US/ST=Unset/L=Unset/O=Unset/CN=keystone
+
+
+[stats]
+
+#
+# Options defined in keystone
+#
+
+# Stats backend driver. (string value)
+#driver=keystone.contrib.stats.backends.kvs.Stats
+
+
+[token]
+
+#
+# Options defined in keystone
+#
+
+# External auth mechanisms that should add bind information to
+# token, e.g., kerberos,x509. (list value)
+#bind=
+
+# Enforcement policy on tokens presented to Keystone with bind
+# information. One of disabled, permissive, strict, required
+# or a specifically required bind mode, e.g., kerberos or x509
+# to require binding to that authentication. (string value)
+#enforce_token_bind=permissive
+
+# Amount of time a token should remain valid (in seconds).
+# (integer value)
+#expiration=3600
+
+# Controls the token construction, validation, and revocation
+# operations. Core providers are
+# "keystone.token.providers.[pkiz|pki|uuid].Provider". The
+# default provider is pkiz. (string value)
+provider=keystone.token.providers.uuid.Provider
+
+# Token persistence backend driver. (string value)
+driver=keystone.token.backends.sql.Token
+
+# Toggle for token system cacheing. This has no effect unless
+# global caching is enabled. (boolean value)
+#caching=true
+
+# Time to cache the revocation list and the revocation events
+# if revoke extension is enabled (in seconds). This has no
+# effect unless global and token caching are enabled. (integer
+# value)
+#revocation_cache_time=3600
+
+# Time to cache tokens (in seconds). This has no effect unless
+# global and token caching are enabled. (integer value)
+#cache_time=<None>
+
+# Revoke token by token identifier. Setting revoke_by_id to
+# true enables various forms of enumerating tokens, e.g. `list
+# tokens for user`. These enumerations are processed to
+# determine the list of tokens to revoke. Only disable if you
+# are switching to using the Revoke extension with a backend
+# other than KVS, which stores events in memory. (boolean
+# value)
+#revoke_by_id=true
+
+# The hash algorithm to use for PKI tokens. This can be set to
+# any algorithm that hashlib supports. WARNING: Before
+# changing this value, the auth_token middleware must be
+# configured with the hash_algorithms, otherwise token
+# revocation will not be processed correctly. (string value)
+#hash_algorithm=md5
+
+
+[trust]
+
+#
+# Options defined in keystone
+#
+
+# Delegation and impersonation features can be optionally
+# disabled. (boolean value)
+#enabled=true
+
+# Trust backend driver. (string value)
+#driver=keystone.trust.backends.sql.Trust
+
+
diff --git a/openstack/usr/share/openstack/keystone/logging.conf b/openstack/usr/share/openstack/keystone/logging.conf
new file mode 100644
index 00000000..21d43c8d
--- /dev/null
+++ b/openstack/usr/share/openstack/keystone/logging.conf
@@ -0,0 +1,39 @@
+[loggers]
+keys=root
+
+[formatters]
+keys=normal,normal_with_name,debug
+
+[handlers]
+keys=production,file,devel
+
+[logger_root]
+level=WARNING
+handlers=file
+
+[handler_production]
+class=handlers.SysLogHandler
+level=ERROR
+formatter=normal_with_name
+args=(('127.0.0.1', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
+
+[handler_file]
+class=FileHandler
+level=DEBUG
+formatter=normal_with_name
+args=('/var/log/keystone/keystone.log', 'a')
+
+[handler_devel]
+class=StreamHandler
+level=NOTSET
+formatter=debug
+args=(sys.stdout,)
+
+[formatter_normal]
+format=%(asctime)s %(levelname)s %(message)s
+
+[formatter_normal_with_name]
+format=(%(name)s): %(asctime)s %(levelname)s %(message)s
+
+[formatter_debug]
+format=(%(name)s): %(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s
diff --git a/openstack/usr/share/openstack/keystone/policy.json b/openstack/usr/share/openstack/keystone/policy.json
new file mode 100644
index 00000000..9c7e646e
--- /dev/null
+++ b/openstack/usr/share/openstack/keystone/policy.json
@@ -0,0 +1,144 @@
+{
+ "admin_required": "role:admin or is_admin:1",
+ "service_role": "role:service",
+ "service_or_admin": "rule:admin_required or rule:service_role",
+ "owner" : "user_id:%(user_id)s",
+ "admin_or_owner": "rule:admin_required or rule:owner",
+
+ "default": "rule:admin_required",
+
+ "identity:get_region": "",
+ "identity:list_regions": "",
+ "identity:create_region": "rule:admin_required",
+ "identity:update_region": "rule:admin_required",
+ "identity:delete_region": "rule:admin_required",
+
+ "identity:get_service": "rule:admin_required",
+ "identity:list_services": "rule:admin_required",
+ "identity:create_service": "rule:admin_required",
+ "identity:update_service": "rule:admin_required",
+ "identity:delete_service": "rule:admin_required",
+
+ "identity:get_endpoint": "rule:admin_required",
+ "identity:list_endpoints": "rule:admin_required",
+ "identity:create_endpoint": "rule:admin_required",
+ "identity:update_endpoint": "rule:admin_required",
+ "identity:delete_endpoint": "rule:admin_required",
+
+ "identity:get_domain": "rule:admin_required",
+ "identity:list_domains": "rule:admin_required",
+ "identity:create_domain": "rule:admin_required",
+ "identity:update_domain": "rule:admin_required",
+ "identity:delete_domain": "rule:admin_required",
+
+ "identity:get_project": "rule:admin_required",
+ "identity:list_projects": "rule:admin_required",
+ "identity:list_user_projects": "rule:admin_or_owner",
+ "identity:create_project": "rule:admin_required",
+ "identity:update_project": "rule:admin_required",
+ "identity:delete_project": "rule:admin_required",
+
+ "identity:get_user": "rule:admin_required",
+ "identity:list_users": "rule:admin_required",
+ "identity:create_user": "rule:admin_required",
+ "identity:update_user": "rule:admin_required",
+ "identity:delete_user": "rule:admin_required",
+ "identity:change_password": "rule:admin_or_owner",
+
+ "identity:get_group": "rule:admin_required",
+ "identity:list_groups": "rule:admin_required",
+ "identity:list_groups_for_user": "rule:admin_or_owner",
+ "identity:create_group": "rule:admin_required",
+ "identity:update_group": "rule:admin_required",
+ "identity:delete_group": "rule:admin_required",
+ "identity:list_users_in_group": "rule:admin_required",
+ "identity:remove_user_from_group": "rule:admin_required",
+ "identity:check_user_in_group": "rule:admin_required",
+ "identity:add_user_to_group": "rule:admin_required",
+
+ "identity:get_credential": "rule:admin_required",
+ "identity:list_credentials": "rule:admin_required",
+ "identity:create_credential": "rule:admin_required",
+ "identity:update_credential": "rule:admin_required",
+ "identity:delete_credential": "rule:admin_required",
+
+ "identity:ec2_get_credential": "rule:admin_or_owner",
+ "identity:ec2_list_credentials": "rule:admin_or_owner",
+ "identity:ec2_create_credential": "rule:admin_or_owner",
+ "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",
+
+ "identity:get_role": "rule:admin_required",
+ "identity:list_roles": "rule:admin_required",
+ "identity:create_role": "rule:admin_required",
+ "identity:update_role": "rule:admin_required",
+ "identity:delete_role": "rule:admin_required",
+
+ "identity:check_grant": "rule:admin_required",
+ "identity:list_grants": "rule:admin_required",
+ "identity:create_grant": "rule:admin_required",
+ "identity:revoke_grant": "rule:admin_required",
+
+ "identity:list_role_assignments": "rule:admin_required",
+
+ "identity:get_policy": "rule:admin_required",
+ "identity:list_policies": "rule:admin_required",
+ "identity:create_policy": "rule:admin_required",
+ "identity:update_policy": "rule:admin_required",
+ "identity:delete_policy": "rule:admin_required",
+
+ "identity:check_token": "rule:admin_required",
+ "identity:validate_token": "rule:service_or_admin",
+ "identity:validate_token_head": "rule:service_or_admin",
+ "identity:revocation_list": "rule:service_or_admin",
+ "identity:revoke_token": "rule:admin_or_owner",
+
+ "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+ "identity:get_trust": "rule:admin_or_owner",
+ "identity:list_trusts": "",
+ "identity:list_roles_for_trust": "",
+ "identity:check_role_for_trust": "",
+ "identity:get_role_for_trust": "",
+ "identity:delete_trust": "",
+
+ "identity:create_consumer": "rule:admin_required",
+ "identity:get_consumer": "rule:admin_required",
+ "identity:list_consumers": "rule:admin_required",
+ "identity:delete_consumer": "rule:admin_required",
+ "identity:update_consumer": "rule:admin_required",
+
+ "identity:authorize_request_token": "rule:admin_required",
+ "identity:list_access_token_roles": "rule:admin_required",
+ "identity:get_access_token_role": "rule:admin_required",
+ "identity:list_access_tokens": "rule:admin_required",
+ "identity:get_access_token": "rule:admin_required",
+ "identity:delete_access_token": "rule:admin_required",
+
+ "identity:list_projects_for_endpoint": "rule:admin_required",
+ "identity:add_endpoint_to_project": "rule:admin_required",
+ "identity:check_endpoint_in_project": "rule:admin_required",
+ "identity:list_endpoints_for_project": "rule:admin_required",
+ "identity:remove_endpoint_from_project": "rule:admin_required",
+
+ "identity:create_identity_provider": "rule:admin_required",
+ "identity:list_identity_providers": "rule:admin_required",
+ "identity:get_identity_providers": "rule:admin_required",
+ "identity:update_identity_provider": "rule:admin_required",
+ "identity:delete_identity_provider": "rule:admin_required",
+
+ "identity:create_protocol": "rule:admin_required",
+ "identity:update_protocol": "rule:admin_required",
+ "identity:get_protocol": "rule:admin_required",
+ "identity:list_protocols": "rule:admin_required",
+ "identity:delete_protocol": "rule:admin_required",
+
+ "identity:create_mapping": "rule:admin_required",
+ "identity:get_mapping": "rule:admin_required",
+ "identity:list_mappings": "rule:admin_required",
+ "identity:delete_mapping": "rule:admin_required",
+ "identity:update_mapping": "rule:admin_required",
+
+ "identity:list_projects_for_groups": "",
+ "identity:list_domains_for_groups": "",
+
+ "identity:list_revoke_events": ""
+}
diff --git a/openstack/usr/share/openstack/modules/README b/openstack/usr/share/openstack/modules/README
new file mode 100644
index 00000000..5cabf204
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/README
@@ -0,0 +1,3 @@
+Ansible modules borrowed from:
+
+https://github.com/openstack-ansible/openstack-ansible-modules
diff --git a/openstack/usr/share/openstack/modules/cinder_manage b/openstack/usr/share/openstack/modules/cinder_manage
new file mode 100644
index 00000000..75a0b453
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/cinder_manage
@@ -0,0 +1,105 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: cinder_manage
+short_description: Initialize OpenStack Block Storage (cinder) database
+description: Create the tables for the database backend used by cinder
+options:
+ action:
+ description:
+ - action to perform. Currently only dbysnc is supported
+ required: true
+ conf:
+ description:
+ - path to cinder config file.
+ required: false
+ default: /etc/cinder/cinder.conf
+requirements: [ cinder ]
+author: Lorin Hochstein
+'''
+
+EXAMPLES = '''
+cinder_manage: action=dbsync
+'''
+
+import subprocess
+
+cinder_found = True
+try:
+ from cinder.db.sqlalchemy import migration
+ try:
+ from cinder import flags
+ FLAGS = flags.FLAGS
+ except ImportError:
+ # Starting with icehouse
+ import cinder.common.config
+ FLAGS = cinder.common.config.CONF
+except ImportError:
+ cinder_found = False
+
+
+def load_config_file(conf):
+ FLAGS(args=[], project='cinder', default_config_files=[conf])
+
+def will_db_change():
+ """ Check if the database version will change after the sync.
+
+ """
+ # Load the config file options
+ current_version = migration.db_version()
+ repository = migration._find_migrate_repo()
+ repo_version = repository.latest
+ return current_version != repo_version
+
+
+def do_dbsync():
+ """Do the dbsync. Returns (returncode, stdout, stderr)"""
+ # We call cinder-manage db_sync on the shell rather than trying to
+ # do this in Python since we have no guarantees about changes to the
+ # internals.
+ args = ['cinder-manage', 'db', 'sync']
+
+ call = subprocess.Popen(args, shell=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = call.communicate()
+ return (call.returncode, out, err)
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ action=dict(required=True),
+ conf=dict(required=False, default="/etc/cinder/cinder.conf")
+ ),
+ supports_check_mode=True
+ )
+
+ if not cinder_found:
+ module.fail_json(msg="cinder package could not be found")
+
+ action = module.params['action']
+ conf = module.params['conf']
+
+ if action not in ['dbsync', 'db_sync']:
+ module.fail_json(msg="Only supported action is 'dbsync'")
+
+ load_config_file(conf)
+
+ changed = will_db_change()
+ if module.check_mode:
+ module.exit_json(changed=changed)
+
+ (res, stdout, stderr) = do_dbsync()
+
+ if res == 0:
+ module.exit_json(changed=changed, stdout=stdout, stderr=stderr)
+ else:
+ module.fail_json(msg="cinder-manage returned non-zero value: %d" % res,
+ stdout=stdout, stderr=stderr)
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+main()
diff --git a/openstack/usr/share/openstack/modules/glance b/openstack/usr/share/openstack/modules/glance
new file mode 100644
index 00000000..f62942f9
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/glance
@@ -0,0 +1,176 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: glance
+short_description: Manage OpenStack virtual machine images
+description:
+ - Upload virtual machine images to OpenStack Image Service (glance)
+requirements: [ python-glanceclient ]
+options:
+ name:
+ description:
+ - name of the image
+ required: true
+ format:
+ description:
+ - disk format
+ choices: [ami, ari, aki, vhd, vmdk, raw, qcow2, vdi, iso]
+ required: true
+ is_public:
+ description:
+ - if true, image is public
+ choices: [true, false]
+ aliases: [public]
+ required: false
+ default: false
+ file:
+ description:
+ - path to the file that contains the image
+ required: true
+ aliases: [path]
+ auth_url:
+ description:
+ - URL to Identity service (keystone) catalog endpoint
+ required: true
+ region:
+ description:
+ - OpenStack region name
+ required: false
+ aliases: [region_name]
+ username:
+ description:
+ - user name to authenticate against Identity service
+ aliases: [user, user_name, login_user]
+ password:
+ description:
+ - password to authenticate against Identity service
+ aliases: [pass, login_password]
+ tenant_name:
+ description:
+ - name of the tenant
+ endpoint_type:
+ description:
+ - endpoint URL type
+ choices: [publicURL, internalURL]
+ required: false
+ default: publicURL
+
+examples:
+ - code: 'glance: name=cirros file=/tmp/cirros.img format=qcow2 is_public=true auth_url=http://192.168.206.130:5000/v2.0/ username=admin tenant_name=demo password=secrete region=RegionOne endpoint_type=publicURL '
+'''
+
+
+try:
+ from glanceclient import Client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ glanceclient_found = False
+else:
+ glanceclient_found = True
+
+
+def get_token_and_endpoint(auth_url, username, password, tenant_name,
+ region_name, endpoint_type):
+
+ keystone = ksclient.Client(username=username,
+ password=password,
+ tenant_name=tenant_name,
+ auth_url=auth_url,
+ region_name=region_name)
+ glance_endpoint = keystone.service_catalog.url_for(
+ service_type="image",
+ endpoint_type=endpoint_type)
+ return (keystone.auth_token, glance_endpoint)
+
+
+def authenticate(auth_url, username, password, tenant_name, region,
+ endpoint_type, version='1'):
+ """Return a keystone client object"""
+
+ (token, endpoint) = get_token_and_endpoint(auth_url, username, password,
+ tenant_name, region,
+ endpoint_type)
+
+ return Client(version, endpoint=endpoint, token=token)
+
+
+def get_images(glance, name):
+ """ Retrieve all images with a certain name """
+ images = [x for x in glance.images.list() if x.name == name]
+ return images
+
+
+def create_image(glance, name, path, disk_format, is_public, check_mode):
+ """ Create a new image from a file on the path.
+
+ Return a pair. First element indicates whether a change occurred,
+ second one is the ID of the iamge """
+
+ # If the image(s) already exists, we're done
+ images = get_images(glance, name)
+ if len(images) > 0:
+ return (False, images[0].id)
+
+ if check_mode:
+ return (True, None)
+
+ image = glance.images.create(name=name, disk_format=disk_format,
+ container_format='bare',
+ is_public=is_public)
+ image.update(data=open(path, 'rb'))
+ return (True, image.id)
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True),
+ file=dict(required=True, aliases=['path']),
+ auth_url=dict(required=True),
+ region=dict(required=False, aliases=['region_name']),
+ username=dict(required=True, aliases=['user',
+ 'user_name',
+ 'login_user']),
+ password=dict(required=True, aliases=['pass', 'login_password']),
+ tenant_name=dict(required=True, aliases=['tenant']),
+ disk_format=dict(required=True,
+ choices=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw',
+ 'qcow2', 'vdi', 'iso'],
+ aliases=['disk-format', 'format']),
+ is_public=dict(required=False,
+ default=False,
+ aliases=['public']),
+ endpoint_type=dict(required=False,
+ choices=['publicURL', 'internalURL'],
+ default='publicURL')
+ ),
+ supports_check_mode=True
+ )
+
+ name = module.params['name']
+ path = module.params['file']
+ auth_url = module.params['auth_url']
+ region = module.params['region']
+ username = module.params['username']
+ password = module.params['password']
+ tenant_name = module.params['tenant_name']
+ disk_format = module.params['disk_format']
+ is_public = module.params['is_public']
+ endpoint_type = module.params['endpoint_type']
+ check_mode = module.check_mode
+
+ glance = authenticate(auth_url, username, password, tenant_name, region,
+ endpoint_type)
+
+ (changed, id) = create_image(glance, name, path, disk_format, is_public,
+ check_mode)
+
+ module.exit_json(changed=changed, name=name, id=id)
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+if __name__ == '__main__':
+ main()
diff --git a/openstack/usr/share/openstack/modules/glance_manage b/openstack/usr/share/openstack/modules/glance_manage
new file mode 100644
index 00000000..b89e7bb0
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/glance_manage
@@ -0,0 +1,158 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: glance_manage
+short_description: Initialize OpenStack Image (glance) database
+description: Create the tables for the database backend used by glance
+options:
+ action:
+ description:
+ - action to perform. Currently only dbsync is supported.
+ required: true
+ conf:
+ description:
+ - path to glance-registry config file.
+ required: false
+ default: /etc/glance/glance-registry.conf
+requirements: [ glance ]
+author: Lorin Hochstein
+'''
+
+EXAMPLES = '''
+glance_manage: action=dbsync
+'''
+
+import os
+import subprocess
+import sys
+
+try:
+ import glance
+ import sqlalchemy
+except ImportError:
+ print("failed=True msg='glance is not installed'")
+ sys.exit(1)
+
+from glance.version import version_info
+# this is necessary starting from havana release due to bug 885529
+# https://bugs.launchpad.net/glance/+bug/885529
+from glance.openstack.common import gettextutils
+gettextutils.install('glance')
+import glance.db.sqlalchemy.api
+
+try:
+ glance_version = version_info.version_string()
+except AttributeError:
+ glance_version = version_info.version
+
+if glance_version.startswith('2014.2'):
+ from oslo.config.cfg import CONF
+ from oslo.db.sqlalchemy import migration
+ from migrate.versioning import api as versioning_api
+ from glance.db import migration as db_migration
+ from glance.db.sqlalchemy import api as db_api
+elif glance_version.startswith('2014.1'):
+ from oslo.config.cfg import CONF
+ from glance.openstack.common.db.sqlalchemy import migration
+ from migrate.versioning import api as versioning_api
+else:
+ from glance.db.sqlalchemy import migration
+ from glance.common.exception import DatabaseMigrationError
+ from migrate.versioning import api as versioning_api
+ CONF = migration.CONF
+
+def is_under_version_control(conf):
+ """ Return true if the database is under version control"""
+ CONF(project='glance', default_config_files=[conf])
+ try:
+ migration.db_version()
+ except DatabaseMigrationError:
+ return False
+ # db_version() will fail with TypeError on icehouse. Icehouse uses db
+ # migration so we're good.
+ finally:
+ return True
+
+
+def will_db_change(conf):
+ """ Check if the database version will change after the sync """
+ # Load the config file options
+ if not is_under_version_control(conf):
+ return True
+ if glance_version.startswith('2014.2'):
+ engine = db_api.get_engine()
+ repo_path = db_migration.MIGRATE_REPO_PATH
+ current_version = migration.db_version(db_api.get_engine(),
+ repo_path,
+ db_migration.INIT_VERSION)
+ elif glance_version.startswith('2014.1'):
+ repo_path = os.path.join(os.path.dirname(glance.__file__),
+ 'db', 'sqlalchemy', 'migrate_repo')
+ engine = sqlalchemy.create_engine(CONF.database.connection)
+ current_version = migration.db_version(engine, repo_path, 0)
+ else:
+ repo_path = migration.get_migrate_repo_path()
+ current_version = migration.db_version()
+
+ repo_version = versioning_api.repository.Repository(repo_path).latest
+ return current_version != repo_version
+
+
+def put_under_version_control():
+ """ Create the initial sqlalchemy migrate database tables. """
+ args = ['glance-manage', 'version_control', '0']
+
+ call = subprocess.Popen(args, shell=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = call.communicate()
+ return (call.returncode, out, err)
+
+
+def do_dbsync():
+ """ Do a database migration """
+ args = ['glance-manage', 'db_sync']
+
+ call = subprocess.Popen(args, shell=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = call.communicate()
+ return (call.returncode, out, err)
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ action=dict(required=True),
+ conf=dict(required=False,
+ default="/etc/glance/glance-registry.conf")
+ ),
+ supports_check_mode=True
+ )
+
+ action = module.params['action']
+ if action not in ['dbsync', 'db_sync']:
+ module.fail_json(msg="Only supported action is 'dbsync'")
+
+ conf = module.params['conf']
+
+ changed = will_db_change(conf)
+ if module.check_mode:
+ module.exit_json(changed=changed)
+
+ if not is_under_version_control(conf):
+ (res, stdout, stderr) = put_under_version_control()
+ if res != 0:
+ msg = "failed to put glance db under version control"
+ module.fail_json(msg=msg, stdout=stdout, stderr=stderr)
+
+ (res, stdout, stderr) = do_dbsync()
+ if res != 0:
+ msg = "failed to synchronize glance db with repository"
+ module.fail_json(msg=msg, stdout=stdout, stderr=stderr)
+
+ module.exit_json(changed=changed)
+
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+main()
diff --git a/openstack/usr/share/openstack/modules/heat_manage b/openstack/usr/share/openstack/modules/heat_manage
new file mode 100644
index 00000000..e24abbda
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/heat_manage
@@ -0,0 +1,105 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: heat_manage
+short_description: Initialize Orchestration (heat) database
+description: Create the tables for the database backend used by heat
+options:
+ action:
+ description:
+ - action to perform. Currently only dbysnc is supported
+ required: true
+ conf:
+ description:
+ - path to keystone config file.
+ required: false
+ default: /etc/heat/heat.conf
+requirements: [ python-heatclient ]
+author: Gauvain Pocentek
+'''
+
+EXAMPLES = '''
+heat_manage: action=dbsync
+'''
+
+import subprocess
+
+try:
+ import heat
+ from heat.db.sqlalchemy import migration
+ from migrate.versioning import api as versioning_api
+ from heat.db import api
+ from oslo.config import cfg
+except ImportError:
+ heat_found = False
+else:
+ heat_found = True
+
+
+def will_db_change(conf):
+ """ Check if the database version will change after the sync.
+
+ conf is the path to the heat config file
+
+ """
+ # Load the config file options
+ cfg.CONF(project='heat', default_config_files=[conf])
+ try:
+ current_version = migration.db_version()
+ except TypeError: # juno
+ current_version = api.db_version(api.get_engine())
+
+ repo_path = os.path.join(os.path.dirname(heat.__file__),
+ 'db', 'sqlalchemy', 'migrate_repo')
+ repo_version = versioning_api.repository.Repository(repo_path).latest
+ return current_version != repo_version
+
+
+def do_dbsync():
+ """Do the dbsync. Returns (returncode, stdout, stderr)"""
+ # We call heat-manage db_sync on the shell rather than trying to
+ # do this in Python since we have no guarantees about changes to the
+ # internals.
+ args = ['heat-manage', 'db_sync']
+
+ call = subprocess.Popen(args, shell=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = call.communicate()
+ return (call.returncode, out, err)
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ action=dict(required=True),
+ conf=dict(required=False, default="/etc/heat/heat.conf")
+ ),
+ supports_check_mode=True
+ )
+
+ if not heat_found:
+ module.fail_json(msg="python-heatclient could not be found")
+
+ action = module.params['action']
+ conf = module.params['conf']
+ if action not in ['dbsync', 'db_sync']:
+ module.fail_json(msg="Only supported action is 'dbsync'")
+
+ changed = will_db_change(conf)
+ if module.check_mode:
+ module.exit_json(changed=changed)
+
+ (res, stdout, stderr) = do_dbsync()
+
+ if res == 0:
+ module.exit_json(changed=changed, stdout=stdout, stderr=stderr)
+ else:
+ module.fail_json(msg="heat-manage returned non-zero value: %d" % res,
+ stdout=stdout, stderr=stderr)
+
+
+from ansible.module_utils.basic import *
+main()
diff --git a/openstack/usr/share/openstack/modules/keystone_manage b/openstack/usr/share/openstack/modules/keystone_manage
new file mode 100644
index 00000000..780f7c9a
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/keystone_manage
@@ -0,0 +1,123 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: keystone_manage
+short_description: Initialize OpenStack Identity (keystone) database
+description: Create the tables for the database backend used by keystone
+options:
+ action:
+ description:
+ - action to perform. Currently only dbysnc is supported
+ required: true
+ conf:
+ description:
+ - path to keystone config file.
+ required: false
+ default: /etc/keystone/keystone.conf
+requirements: [ keystone ]
+author: Lorin Hochstein
+'''
+
+EXAMPLES = '''
+keystone_manage: action=dbsync
+'''
+
+import subprocess
+
+try:
+ # this is necessary starting from havana release due to bug 885529
+ # https://bugs.launchpad.net/glance/+bug/885529
+ from keystone.openstack.common import gettextutils
+ gettextutils.install('keystone')
+except AttributeError:
+ # this is not havana
+ pass
+
+try:
+ from keystone.common import sql
+ from migrate.versioning import api as versioning_api
+except ImportError:
+ keystone_found = False
+else:
+ keystone_found = True
+
+try:
+ # for icehouse
+ from keystone.common.sql import migration_helpers as migration
+except ImportError:
+ pass
+
+
+def will_db_change(conf):
+ """ Check if the database version will change after the sync.
+
+ conf is the path to the keystone config file
+
+ """
+ # Load the config file options
+ try:
+ # before icehouse
+ sql.migration.CONF(project='keystone', default_config_files=[conf])
+ current_version = sql.migration.db_version()
+ except AttributeError:
+ # starting with icehouse
+ sql.core.CONF(project='keystone', default_config_files=[conf])
+ current_version = migration.get_db_version()
+
+ # in havana the method _find_migrate_repo has been renamed to find_migrate_repo
+ try:
+ repo_path = migration.find_migrate_repo()
+ except AttributeError:
+ repo_path = migration._find_migrate_repo()
+ repo_version = versioning_api.repository.Repository(repo_path).latest
+ return current_version != repo_version
+
+
+def do_dbsync():
+ """Do the dbsync. Returns (returncode, stdout, stderr)"""
+ # We call keystone-manage db_sync on the shell rather than trying to
+ # do this in Python since we have no guarantees about changes to the
+ # internals.
+ args = ['keystone-manage', 'db_sync']
+
+ call = subprocess.Popen(args, shell=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = call.communicate()
+ return (call.returncode, out, err)
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ action=dict(required=True),
+ conf=dict(required=False, default="/etc/keystone/keystone.conf")
+ ),
+ supports_check_mode=True
+ )
+
+ if not keystone_found:
+ module.fail_json(msg="keystone package could not be found")
+
+ action = module.params['action']
+ conf = module.params['conf']
+ if action not in ['dbsync', 'db_sync']:
+ module.fail_json(msg="Only supported action is 'dbsync'")
+
+ changed = will_db_change(conf)
+ if module.check_mode:
+ module.exit_json(changed=changed)
+
+ (res, stdout, stderr) = do_dbsync()
+
+ if res == 0:
+ module.exit_json(changed=changed, stdout=stdout, stderr=stderr)
+ else:
+ module.fail_json(msg="keystone-manage returned non-zero value: %d" % res,
+ stdout=stdout, stderr=stderr)
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+main()
diff --git a/openstack/usr/share/openstack/modules/keystone_service b/openstack/usr/share/openstack/modules/keystone_service
new file mode 100644
index 00000000..aa4302d1
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/keystone_service
@@ -0,0 +1,309 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: keystone_service
+short_description: Manage OpenStack Identity (keystone) service endpoints
+options:
+ name:
+ description:
+ - name of service (e.g., keystone)
+ required: yes
+ type:
+ description:
+ - type of service (e.g., identity)
+ required: yes
+ description:
+ description:
+ - description of service (e.g., Identity Service)
+ required: yes
+ public_url:
+ description:
+ - public url of service.
+ - 'Alias: I(url)'
+ - 'Alias: I(publicurl)'
+ required: yes
+ internal_url:
+ description:
+ - internal url of service.
+ - 'Alias: I(internalurl)'
+ required: no
+ default: value of public_url
+ admin_url:
+ description:
+ - admin url of service.
+ - 'Alias: I(adminurl)'
+ required: no
+ default: value of public_url
+ insecure:
+ description:
+ - allow use of self-signed SSL certificates
+ required: no
+ choices: [ "yes", "no" ]
+ region:
+ description:
+ - region of service
+ required: yes
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+
+
+
+requirements: [ python-keystoneclient ]
+author: Lorin Hochstein
+'''
+
+EXAMPLES = '''
+examples:
+keystone_service: >
+ name=keystone
+ type=identity
+ description="Keystone Identity Service"
+ publicurl=http://192.168.206.130:5000/v2.0
+ internalurl=http://192.168.206.130:5000/v2.0
+ adminurl=http://192.168.206.130:35357/v2.0
+
+keystone_service: >
+ name=glance
+ type=image
+ description="Glance Identity Service"
+ url=http://192.168.206.130:9292
+
+'''
+
+try:
+ from keystoneclient.v2_0 import client
+except ImportError:
+ keystoneclient_found = False
+else:
+ keystoneclient_found = True
+
+import traceback
+
+
+def authenticate(endpoint, token, login_user, login_password, tenant_name,
+ insecure):
+ """Return a keystone client object"""
+
+ if token:
+ return client.Client(endpoint=endpoint, token=token, insecure=insecure)
+ else:
+ return client.Client(auth_url=endpoint, username=login_user,
+ password=login_password, tenant_name=tenant_name,
+ insecure=insecure)
+
+def get_service(keystone, name):
+ """ Retrieve a service by name """
+ services = [x for x in keystone.services.list() if x.name == name]
+ count = len(services)
+ if count == 0:
+ raise KeyError("No keystone services with name %s" % name)
+ elif count > 1:
+ raise ValueError("%d services with name %s" % (count, name))
+ else:
+ return services[0]
+
+
+def get_endpoint(keystone, name):
+ """ Retrieve a service endpoint by name """
+ service = get_service(keystone, name)
+ endpoints = [x for x in keystone.endpoints.list()
+ if x.service_id == service.id]
+ count = len(endpoints)
+ if count == 0:
+ raise KeyError("No keystone endpoints with service name %s" % name)
+ elif count > 1:
+ raise ValueError("%d endpoints with service name %s" % (count, name))
+ else:
+ return endpoints[0]
+
+
+def ensure_service_present(keystone, name, service_type, description,
+ check_mode):
+ """ Ensure the service is present and has the right values
+
+ Returns a pair, where the first element is a boolean that indicates
+ a state change, and the second element is the service uuid, or None
+ if running in check mode"""
+ service = None
+ try:
+ service = get_service(keystone, name)
+ except:
+ # Service doesn't exist yet, we'll need to create one
+ pass
+ else:
+ # See if it matches exactly
+ if service.name == name and \
+ service.type == service_type and \
+ service.description == description:
+
+ # Same, no changes needed
+ return (False, service.id)
+
+ # At this point, we know we will need to make a change
+ if check_mode:
+ return (True, None)
+
+ if service is None:
+ service = keystone.services.create(name=name,
+ service_type=service_type,
+ description=description)
+ return (True, service.id)
+ else:
+ msg = "keystone v2 API doesn't support updating services"
+ raise ValueError(msg)
+
+
+def ensure_endpoint_present(keystone, name, public_url, internal_url,
+ admin_url, region, check_mode):
+ """ Ensure the service endpoint is present and have the right values
+
+ Assumes the service object has already been created at this point"""
+
+ service = get_service(keystone, name)
+ endpoint = None
+ try:
+ endpoint = get_endpoint(keystone, name)
+ except:
+ # Endpoint doesn't exist yet, we'll need to create one
+ pass
+ else:
+ # See if it matches
+ if endpoint.publicurl == public_url and \
+ endpoint.adminurl == admin_url and \
+ endpoint.internalurl == internal_url and \
+ endpoint.region == region:
+
+ # Same, no changes needed
+ return (False, endpoint.id)
+
+ # At this point, we know we will need to make a change
+ if check_mode:
+ return (True, None)
+
+ if endpoint is None:
+ endpoint = keystone.endpoints.create(region=region,
+ service_id=service.id,
+ publicurl=public_url,
+ adminurl=admin_url,
+ internalurl=internal_url)
+ return (True, endpoint.id)
+ else:
+ msg = "keystone v2 API doesn't support updating endpoints"
+ raise ValueError(msg)
+
+
+def ensure_service_absent(keystone, name, check_mode):
+ """ Ensure the service is absent"""
+
+ raise NotImplementedError()
+
+def ensure_endpoint_absent(keystone, name, check_mode):
+ """ Ensure the service endpoint """
+ raise NotImplementedError()
+
+
+def dispatch(keystone, name, service_type, description, public_url,
+ internal_url, admin_url, region, state, check_mode):
+
+ if state == 'present':
+ (service_changed, service_id) = ensure_service_present(keystone,
+ name,
+ service_type,
+ description,
+ check_mode)
+
+ (endpoint_changed, endpoint_id) = ensure_endpoint_present(
+ keystone,
+ name,
+ public_url,
+ internal_url,
+ admin_url,
+ region,
+ check_mode)
+ return dict(changed=service_changed or endpoint_changed,
+ service_id=service_id,
+ endpoint_id=endpoint_id)
+ elif state == 'absent':
+ endpoint_changed = ensure_endpoint_absent(keystone, name, check_mode)
+ service_changed = ensure_service_absent(keystone, name, check_mode)
+ return dict(changed=service_changed or endpoint_changed)
+ else:
+ raise ValueError("Code should never reach here")
+
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ name=dict(required=True),
+ type=dict(required=True),
+ description=dict(required=False),
+ public_url=dict(required=True, aliases=['url', 'publicurl']),
+ internal_url=dict(required=False, aliases=['internalurl']),
+ admin_url=dict(required=False, aliases=['adminurl']),
+ region=dict(required=True),
+ state=dict(default='present', choices=['present', 'absent']),
+ endpoint=dict(required=False,
+ default="http://127.0.0.1:35357/v2.0",
+ aliases=['auth_url']),
+ token=dict(required=False),
+ insecure=dict(required=False, default=False, choices=BOOLEANS),
+
+ login_user=dict(required=False),
+ login_password=dict(required=False),
+ tenant_name=dict(required=False, aliases=['tenant'])
+ ),
+ supports_check_mode=True,
+ mutually_exclusive=[['token', 'login_user'],
+ ['token', 'login_password'],
+ ['token', 'tenant_name']]
+ )
+
+ endpoint = module.params['endpoint']
+ token = module.params['token']
+ login_user = module.params['login_user']
+ login_password = module.params['login_password']
+ tenant_name = module.params['tenant_name']
+ insecure = module.boolean(module.params['insecure'])
+ name = module.params['name']
+ service_type = module.params['type']
+ description = module.params['description']
+ public_url = module.params['public_url']
+ internal_url = module.params['internal_url']
+ if internal_url is None:
+ internal_url = public_url
+ admin_url = module.params['admin_url']
+ if admin_url is None:
+ admin_url = public_url
+ region = module.params['region']
+ state = module.params['state']
+
+ keystone = authenticate(endpoint, token, login_user, login_password,
+ tenant_name, insecure)
+ check_mode = module.check_mode
+
+ try:
+ d = dispatch(keystone, name, service_type, description,
+ public_url, internal_url, admin_url, region, state,
+ check_mode)
+ except Exception:
+ if check_mode:
+ # If we have a failure in check mode
+ module.exit_json(changed=True,
+ msg="exception: %s" % traceback.format_exc())
+ else:
+ module.fail_json(msg=traceback.format_exc())
+ else:
+ module.exit_json(**d)
+
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+if __name__ == '__main__':
+ main()
diff --git a/openstack/usr/share/openstack/modules/neutron_floating_ip b/openstack/usr/share/openstack/modules/neutron_floating_ip
new file mode 100644
index 00000000..4c141025
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_floating_ip
@@ -0,0 +1,274 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2013, Benno Joy <benno@ansibleworks.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from novaclient.v1_1 import client as nova_client
+ from neutronclient.neutron import client
+ from keystoneclient.v2_0 import client as ksclient
+ import time
+except ImportError:
+ print("failed=True msg='glanceclient,keystoneclient and neutronclient client are required'")
+
+DOCUMENTATION = '''
+---
+module: neutron_floating_ip
+version_added: "1.2"
+short_description: Add/Remove floating IP from an instance
+description:
+ - Add or Remove a floating IP to an instance
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ default: admin
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ default: 'yes'
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ default: 'yes'
+ auth_url:
+ description:
+ - The keystone url for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+ network_name:
+ description:
+ - Name of the network from which IP has to be assigned to VM. Please make sure the network is an external network
+ required: true
+ default: None
+ port_network_name:
+ description:
+ - Name of the network where the VM port lives. Useful when the VM has more than one port
+ required: false
+ default: None
+ instance_name:
+ description:
+ - The name of the instance to which the IP address should be assigned
+ required: true
+ default: None
+requirements: ["novaclient", "neutronclient", "keystoneclient"]
+'''
+
+EXAMPLES = '''
+# Assign a floating ip to the instance from an external network
+- neutron_floating_ip: state=present login_username=admin login_password=admin
+ login_tenant_name=admin network_name=external_network
+ instance_name=vm1
+'''
+
+def _get_ksclient(module, kwargs):
+ try:
+ kclient = ksclient.Client(username=kwargs.get('login_username'),
+ password=kwargs.get('login_password'),
+ tenant_name=kwargs.get('login_tenant_name'),
+ auth_url=kwargs.get('auth_url'))
+ except Exception as e:
+ module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
+ global _os_keystone
+ _os_keystone = kclient
+ return kclient
+
+
+def _get_endpoint(module, ksclient):
+ try:
+ endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+ except Exception as e:
+ module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
+ return endpoint
+
+def _get_neutron_client(module, kwargs):
+ _ksclient = _get_ksclient(module, kwargs)
+ token = _ksclient.auth_token
+ endpoint = _get_endpoint(module, _ksclient)
+ kwargs = {
+ 'token': token,
+ 'endpoint_url': endpoint
+ }
+ try:
+ neutron = client.Client('2.0', **kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
+ return neutron
+
+def _get_server_state(module, nova):
+ server_info = None
+ server = None
+ try:
+ for server in nova.servers.list():
+ if server:
+ info = server._info
+ if info['name'] == module.params['instance_name']:
+ if info['status'] != 'ACTIVE' and module.params['state'] == 'present':
+ module.fail_json( msg="The VM is available but not Active. state:" + info['status'])
+ server_info = info
+ break
+ except Exception as e:
+ module.fail_json(msg = "Error in getting the server list: %s" % e.message)
+ return server_info, server
+
+def _get_port_info(neutron, module, instance_id):
+ if module.params['port_network_name'] is None:
+ kwargs = {
+ 'device_id': instance_id
+ }
+ else:
+ network_id = _get_net_id(neutron, module.params['port_network_name'])
+ if not network_id:
+ module.fail_json(msg = "cannot find the network specified, please check")
+
+ kwargs = {
+ 'device_id': instance_id,
+ 'network_id': network_id
+ }
+ try:
+ ports = neutron.list_ports(**kwargs)
+ except Exception as e:
+ module.fail_json( msg = "Error in listing ports: %s" % e.message)
+ if not ports['ports']:
+ return None, None
+ return ports['ports'][0]['fixed_ips'][0]['ip_address'], ports['ports'][0]['id']
+
+def _get_floating_ip(module, neutron, fixed_ip_address):
+ kwargs = {
+ 'fixed_ip_address': fixed_ip_address
+ }
+ try:
+ ips = neutron.list_floatingips(**kwargs)
+ except Exception as e:
+ module.fail_json(msg = "error in fetching the floatingips's %s" % e.message)
+ if not ips['floatingips']:
+ return None, None
+ return ips['floatingips'][0]['id'], ips['floatingips'][0]['floating_ip_address']
+
+def _assign_floating_ip(neutron, module, port_id, net_id):
+ kwargs = {
+ 'floating_network_id': net_id
+ }
+ try:
+ ips = neutron.list_floatingips(**kwargs)
+ except Exception as e:
+ module.fail_json(msg = "error in fetching the floatingips's %s" % e.message)
+
+ fip = next((fip for fip in ips['floatingips'] if fip['port_id'] is None), None)
+
+ if fip is None:
+ _create_floating_ip(neutron, module, port_id, net_id)
+ else:
+ _update_floating_ip(neutron, module, port_id, fip['id'])
+
+def _create_floating_ip(neutron, module, port_id, net_id):
+ kwargs = {
+ 'port_id': port_id,
+ 'floating_network_id': net_id
+ }
+ try:
+ result = neutron.create_floatingip({'floatingip': kwargs})
+ except Exception as e:
+ module.fail_json(msg="There was an error in updating the floating ip address: %s" % e.message)
+ module.exit_json(changed=True, result=result, public_ip=result['floatingip']['floating_ip_address'])
+
+def _get_net_id(neutron, network_name):
+ kwargs = {
+ 'name': network_name,
+ }
+ try:
+ networks = neutron.list_networks(**kwargs)
+ except Exception as e:
+ module.fail_json("Error in listing neutron networks: %s" % e.message)
+ if not networks['networks']:
+ return None
+ return networks['networks'][0]['id']
+
+def _update_floating_ip(neutron, module, port_id, floating_ip_id):
+ kwargs = {
+ 'port_id': port_id
+ }
+ try:
+ result = neutron.update_floatingip(floating_ip_id, {'floatingip': kwargs})
+ except Exception as e:
+ module.fail_json(msg="There was an error in updating the floating ip address: %s" % e.message)
+ module.exit_json(changed=True, result=result, public_ip=result['floatingip']['floating_ip_address'])
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin'),
+ login_password = dict(required=True),
+ login_tenant_name = dict(required='True'),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ network_name = dict(required=True),
+ instance_name = dict(required=True),
+ port_network_name = dict(default=None),
+ state = dict(default='present', choices=['absent', 'present'])
+ ),
+ )
+
+ try:
+ nova = nova_client.Client(module.params['login_username'], module.params['login_password'],
+ module.params['login_tenant_name'], module.params['auth_url'], service_type='compute')
+ neutron = _get_neutron_client(module, module.params)
+ except Exception as e:
+ module.fail_json(msg="Error in authenticating to nova: %s" % e.message)
+
+ server_info, server_obj = _get_server_state(module, nova)
+ if not server_info:
+ module.fail_json(msg="The instance name provided cannot be found")
+
+ fixed_ip, port_id = _get_port_info(neutron, module, server_info['id'])
+ if not port_id:
+ module.fail_json(msg="Cannot find a port for this instance, maybe fixed ip is not assigned")
+
+ floating_id, floating_ip = _get_floating_ip(module, neutron, fixed_ip)
+
+ if module.params['state'] == 'present':
+ if floating_ip:
+ module.exit_json(changed = False, public_ip=floating_ip)
+ net_id = _get_net_id(neutron, module.params['network_name'])
+ if not net_id:
+ module.fail_json(msg = "cannot find the network specified, please check")
+ _assign_floating_ip(neutron, module, port_id, net_id)
+
+ if module.params['state'] == 'absent':
+ if floating_ip:
+ _update_floating_ip(neutron, module, None, floating_id)
+ module.exit_json(changed=False)
+
+# this is magic, see lib/ansible/module.params['common.py
+from ansible.module_utils.basic import *
+main()
+
+
diff --git a/openstack/usr/share/openstack/modules/neutron_network b/openstack/usr/share/openstack/modules/neutron_network
new file mode 100644
index 00000000..6dee0450
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_network
@@ -0,0 +1,282 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2013, Benno Joy <benno@ansibleworks.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from neutronclient.neutron import client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ print("failed=True msg='neutronclient and keystone client are required'")
+
+DOCUMENTATION = '''
+---
+module: neutron_network
+version_added: "1.4"
+short_description: Creates/Removes networks from OpenStack
+description:
+ - Add or Remove network from OpenStack.
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ default: admin
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ default: 'yes'
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ default: 'yes'
+ tenant_name:
+ description:
+ - The name of the tenant for whom the network is created
+ required: false
+ default: None
+ auth_url:
+ description:
+ - The keystone url for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+ name:
+ description:
+ - Name to be assigned to the nework
+ required: true
+ default: None
+ provider_network_type:
+ description:
+ - The type of the network to be created, gre, vxlan, vlan, local. Available types depend on the plugin. The Neutron service decides if not specified.
+ required: false
+ default: None
+ provider_physical_network:
+ description:
+ - The physical network which would realize the virtual network for flat and vlan networks.
+ required: false
+ default: None
+ provider_segmentation_id:
+ description:
+ - The id that has to be assigned to the network, in case of vlan networks that would be vlan id, for gre the tunnel id and for vxlan the VNI.
+ required: false
+ default: None
+ router_external:
+ description:
+ - If 'yes', specifies that the virtual network is a external network (public).
+ required: false
+ default: false
+ shared:
+ description:
+ - Whether this network is shared or not
+ required: false
+ default: false
+ admin_state_up:
+ description:
+ - Whether the state should be marked as up or down
+ required: false
+ default: true
+requirements: ["neutronclient", "keystoneclient"]
+
+'''
+
+EXAMPLES = '''
+# Create a GRE backed Neutron network with tunnel id 1 for tenant1
+- neutron_network: name=t1network tenant_name=tenant1 state=present
+ provider_network_type=gre provider_segmentation_id=1
+ login_username=admin login_password=admin login_tenant_name=admin
+
+# Create an external network
+- neutron_network: name=external_network state=present
+ provider_network_type=local router_external=yes
+ login_username=admin login_password=admin login_tenant_name=admin
+'''
+
+_os_keystone = None
+_os_tenant_id = None
+
+def _get_ksclient(module, kwargs):
+ try:
+ kclient = ksclient.Client(username=kwargs.get('login_username'),
+ password=kwargs.get('login_password'),
+ tenant_name=kwargs.get('login_tenant_name'),
+ auth_url=kwargs.get('auth_url'))
+ except Exception as e:
+ module.fail_json(msg = "Error authenticating to the keystone: %s" %e.message)
+ global _os_keystone
+ _os_keystone = kclient
+ return kclient
+
+
+def _get_endpoint(module, ksclient):
+ try:
+ endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+ except Exception as e:
+ module.fail_json(msg = "Error getting endpoint for Neutron: %s " %e.message)
+ return endpoint
+
+def _get_neutron_client(module, kwargs):
+ _ksclient = _get_ksclient(module, kwargs)
+ token = _ksclient.auth_token
+ endpoint = _get_endpoint(module, _ksclient)
+ kwargs = {
+ 'token': token,
+ 'endpoint_url': endpoint
+ }
+ try:
+ neutron = client.Client('2.0', **kwargs)
+ except Exception as e:
+ module.fail_json(msg = " Error in connecting to Neutron: %s " %e.message)
+ return neutron
+
+def _set_tenant_id(module):
+ global _os_tenant_id
+ if not module.params['tenant_name']:
+ tenant_name = module.params['login_tenant_name']
+ else:
+ tenant_name = module.params['tenant_name']
+
+ for tenant in _os_keystone.tenants.list():
+ if tenant.name == tenant_name:
+ _os_tenant_id = tenant.id
+ break
+ if not _os_tenant_id:
+ module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
+
+
+def _get_net_id(neutron, module):
+ kwargs = {
+ 'tenant_id': _os_tenant_id,
+ 'name': module.params['name'],
+ }
+ try:
+ networks = neutron.list_networks(**kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in listing Neutron networks: %s" % e.message)
+ if not networks['networks']:
+ return None
+ return networks['networks'][0]['id']
+
+def _create_network(module, neutron):
+
+ neutron.format = 'json'
+
+ network = {
+ 'name': module.params.get('name'),
+ 'tenant_id': _os_tenant_id,
+ 'provider:network_type': module.params.get('provider_network_type'),
+ 'provider:physical_network': module.params.get('provider_physical_network'),
+ 'provider:segmentation_id': module.params.get('provider_segmentation_id'),
+ 'router:external': module.params.get('router_external'),
+ 'shared': module.params.get('shared'),
+ 'admin_state_up': module.params.get('admin_state_up'),
+ }
+
+ if module.params['provider_network_type'] == 'local':
+ network.pop('provider:physical_network', None)
+ network.pop('provider:segmentation_id', None)
+
+ if module.params['provider_network_type'] == 'flat':
+ network.pop('provider:segmentation_id', None)
+
+ if module.params['provider_network_type'] == 'gre':
+ network.pop('provider:physical_network', None)
+
+ if module.params['provider_network_type'] == 'vxlan':
+ network.pop('provider:physical_network', None)
+
+ if module.params['provider_network_type'] is None:
+ network.pop('provider:network_type', None)
+ network.pop('provider:physical_network', None)
+ network.pop('provider:segmentation_id', None)
+
+ try:
+ net = neutron.create_network({'network':network})
+ except Exception as e:
+ module.fail_json(msg = "Error in creating network: %s" % e.message)
+ return net['network']['id']
+
+def _delete_network(module, net_id, neutron):
+
+ try:
+ id = neutron.delete_network(net_id)
+ except Exception as e:
+ module.fail_json(msg = "Error in deleting the network: %s" % e.message)
+ return True
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin'),
+ login_password = dict(required=True),
+ login_tenant_name = dict(required='True'),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ name = dict(required=True),
+ tenant_name = dict(default=None),
+ provider_network_type = dict(default=None, choices=['local', 'vlan', 'flat', 'gre', 'vxlan']),
+ provider_physical_network = dict(default=None),
+ provider_segmentation_id = dict(default=None),
+ router_external = dict(default=False, type='bool'),
+ shared = dict(default=False, type='bool'),
+ admin_state_up = dict(default=True, type='bool'),
+ state = dict(default='present', choices=['absent', 'present'])
+ ),
+ )
+
+ if module.params['provider_network_type'] in ['vlan' , 'flat']:
+ if not module.params['provider_physical_network']:
+ module.fail_json(msg = " for vlan and flat networks, variable provider_physical_network should be set.")
+
+ if module.params['provider_network_type'] in ['vlan', 'gre', 'vxlan']:
+ if not module.params['provider_segmentation_id']:
+ module.fail_json(msg = " for vlan, gre & vxlan networks, variable provider_segmentation_id should be set.")
+
+ neutron = _get_neutron_client(module, module.params)
+
+ _set_tenant_id(module)
+
+ if module.params['state'] == 'present':
+ network_id = _get_net_id(neutron, module)
+ if not network_id:
+ network_id = _create_network(module, neutron)
+ module.exit_json(changed = True, result = "Created", id = network_id)
+ else:
+ module.exit_json(changed = False, result = "Success", id = network_id)
+
+ if module.params['state'] == 'absent':
+ network_id = _get_net_id(neutron, module)
+ if not network_id:
+ module.exit_json(changed = False, result = "Success")
+ else:
+ _delete_network(module, network_id, neutron)
+ module.exit_json(changed = True, result = "Deleted")
+
+# this is magic, see lib/ansible/module.params['common.py
+from ansible.module_utils.basic import *
+main()
diff --git a/openstack/usr/share/openstack/modules/neutron_router b/openstack/usr/share/openstack/modules/neutron_router
new file mode 100644
index 00000000..56d384d0
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_router
@@ -0,0 +1,210 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2013, Benno Joy <benno@ansibleworks.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from neutronclient.neutron import client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ print("failed=True msg='neutronclient and keystone client are required'")
+
+DOCUMENTATION = '''
+---
+module: neutron_router
+version_added: "1.2"
+short_description: Create or Remove router from openstack
+description:
+ - Create or Delete routers from OpenStack
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ default: admin
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ default: 'yes'
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ default: 'yes'
+ auth_url:
+ description:
+ - The keystone url for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+ name:
+ description:
+ - Name to be give to the router
+ required: true
+ default: None
+ tenant_name:
+ description:
+ - Name of the tenant for which the router has to be created, if none router would be created for the login tenant.
+ required: false
+ default: None
+ admin_state_up:
+ description:
+ - desired admin state of the created router .
+ required: false
+ default: true
+requirements: ["neutronclient", "keystoneclient"]
+'''
+
+EXAMPLES = '''
+# Creates a router for tenant admin
+- neutron_router: state=present
+ login_username=admin
+ login_password=admin
+ login_tenant_name=admin
+ name=router1"
+'''
+
+_os_keystone = None
+_os_tenant_id = None
+
+def _get_ksclient(module, kwargs):
+ try:
+ kclient = ksclient.Client(username=kwargs.get('login_username'),
+ password=kwargs.get('login_password'),
+ tenant_name=kwargs.get('login_tenant_name'),
+ auth_url=kwargs.get('auth_url'))
+ except Exception as e:
+ module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
+ global _os_keystone
+ _os_keystone = kclient
+ return kclient
+
+
+def _get_endpoint(module, ksclient):
+ try:
+ endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+ except Exception as e:
+ module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
+ return endpoint
+
+def _get_neutron_client(module, kwargs):
+ _ksclient = _get_ksclient(module, kwargs)
+ token = _ksclient.auth_token
+ endpoint = _get_endpoint(module, _ksclient)
+ kwargs = {
+ 'token': token,
+ 'endpoint_url': endpoint
+ }
+ try:
+ neutron = client.Client('2.0', **kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in connecting to Neutron: %s " % e.message)
+ return neutron
+
+def _set_tenant_id(module):
+ global _os_tenant_id
+ if not module.params['tenant_name']:
+ login_tenant_name = module.params['login_tenant_name']
+ else:
+ login_tenant_name = module.params['tenant_name']
+
+ for tenant in _os_keystone.tenants.list():
+ if tenant.name == login_tenant_name:
+ _os_tenant_id = tenant.id
+ break
+ if not _os_tenant_id:
+ module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
+
+
+def _get_router_id(module, neutron):
+ kwargs = {
+ 'name': module.params['name'],
+ 'tenant_id': _os_tenant_id,
+ }
+ try:
+ routers = neutron.list_routers(**kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in getting the router list: %s " % e.message)
+ if not routers['routers']:
+ return None
+ return routers['routers'][0]['id']
+
+def _create_router(module, neutron):
+ router = {
+ 'name': module.params['name'],
+ 'tenant_id': _os_tenant_id,
+ 'admin_state_up': module.params['admin_state_up'],
+ }
+ try:
+ new_router = neutron.create_router(dict(router=router))
+ except Exception as e:
+ module.fail_json( msg = "Error in creating router: %s" % e.message)
+ return new_router['router']['id']
+
+def _delete_router(module, neutron, router_id):
+ try:
+ neutron.delete_router(router_id)
+ except:
+ module.fail_json("Error in deleting the router")
+ return True
+
+def main():
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin'),
+ login_password = dict(required=True),
+ login_tenant_name = dict(required='True'),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ name = dict(required=True),
+ tenant_name = dict(default=None),
+ state = dict(default='present', choices=['absent', 'present']),
+ admin_state_up = dict(type='bool', default=True),
+ ),
+ )
+
+ neutron = _get_neutron_client(module, module.params)
+ _set_tenant_id(module)
+
+ if module.params['state'] == 'present':
+ router_id = _get_router_id(module, neutron)
+ if not router_id:
+ router_id = _create_router(module, neutron)
+ module.exit_json(changed=True, result="Created", id=router_id)
+ else:
+ module.exit_json(changed=False, result="success" , id=router_id)
+
+ else:
+ router_id = _get_router_id(module, neutron)
+ if not router_id:
+ module.exit_json(changed=False, result="success")
+ else:
+ _delete_router(module, neutron, router_id)
+ module.exit_json(changed=True, result="deleted")
+
+# this is magic, see lib/ansible/module.params['common.py
+from ansible.module_utils.basic import *
+main()
diff --git a/openstack/usr/share/openstack/modules/neutron_router_gateway b/openstack/usr/share/openstack/modules/neutron_router_gateway
new file mode 100644
index 00000000..93235b85
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_router_gateway
@@ -0,0 +1,215 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2013, Benno Joy <benno@ansibleworks.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from neutronclient.neutron import client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ print("failed=True msg='neutronclient and keystone client are required'")
+DOCUMENTATION = '''
+---
+module: neutron_router_gateway
+version_added: "1.2"
+short_description: set/unset a gateway interface for the router with the specified external network
+description:
+ - Creates/Removes a gateway interface from the router, used to associate a external network with a router to route external traffic.
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ default: admin
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ default: 'yes'
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ default: 'yes'
+ auth_url:
+ description:
+ - The keystone URL for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+ router_name:
+ description:
+ - Name of the router to which the gateway should be attached.
+ required: true
+ default: None
+ network_name:
+ description:
+ - Name of the external network which should be attached to the router.
+ required: true
+ default: None
+requirements: ["neutronclient", "keystoneclient"]
+'''
+
+EXAMPLES = '''
+# Attach an external network with a router to allow flow of external traffic
+- neutron_router_gateway: state=present login_username=admin login_password=admin
+ login_tenant_name=admin router_name=external_router
+ network_name=external_network
+'''
+
+_os_keystone = None
+def _get_ksclient(module, kwargs):
+ try:
+ kclient = ksclient.Client(username=kwargs.get('login_username'),
+ password=kwargs.get('login_password'),
+ tenant_name=kwargs.get('login_tenant_name'),
+ auth_url=kwargs.get('auth_url'))
+ except Exception as e:
+ module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
+ global _os_keystone
+ _os_keystone = kclient
+ return kclient
+
+
+def _get_endpoint(module, ksclient):
+ try:
+ endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+ except Exception as e:
+ module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
+ return endpoint
+
+def _get_neutron_client(module, kwargs):
+ _ksclient = _get_ksclient(module, kwargs)
+ token = _ksclient.auth_token
+ endpoint = _get_endpoint(module, _ksclient)
+ kwargs = {
+ 'token': token,
+ 'endpoint_url': endpoint
+ }
+ try:
+ neutron = client.Client('2.0', **kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
+ return neutron
+
+def _get_router_id(module, neutron):
+ kwargs = {
+ 'name': module.params['router_name'],
+ }
+ try:
+ routers = neutron.list_routers(**kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in getting the router list: %s " % e.message)
+ if not routers['routers']:
+ return None
+ return routers['routers'][0]['id']
+
+def _get_net_id(neutron, module):
+ kwargs = {
+ 'name': module.params['network_name'],
+ 'router:external': True
+ }
+ try:
+ networks = neutron.list_networks(**kwargs)
+ except Exception as e:
+ module.fail_json("Error in listing neutron networks: %s" % e.message)
+ if not networks['networks']:
+ return None
+ return networks['networks'][0]['id']
+
+def _get_port_id(neutron, module, router_id, network_id):
+ kwargs = {
+ 'device_id': router_id,
+ 'network_id': network_id,
+ }
+ try:
+ ports = neutron.list_ports(**kwargs)
+ except Exception as e:
+ module.fail_json( msg = "Error in listing ports: %s" % e.message)
+ if not ports['ports']:
+ return None
+ return ports['ports'][0]['id']
+
+def _add_gateway_router(neutron, module, router_id, network_id):
+ kwargs = {
+ 'network_id': network_id
+ }
+ try:
+ neutron.add_gateway_router(router_id, kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in adding gateway to router: %s" % e.message)
+ return True
+
+def _remove_gateway_router(neutron, module, router_id):
+ try:
+ neutron.remove_gateway_router(router_id)
+ except Exception as e:
+ module.fail_json(msg = "Error in removing gateway to router: %s" % e.message)
+ return True
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin'),
+ login_password = dict(required=True),
+ login_tenant_name = dict(required='True'),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ router_name = dict(required=True),
+ network_name = dict(required=True),
+ state = dict(default='present', choices=['absent', 'present']),
+ ),
+ )
+
+ neutron = _get_neutron_client(module, module.params)
+ router_id = _get_router_id(module, neutron)
+
+ if not router_id:
+ module.fail_json(msg="failed to get the router id, please check the router name")
+
+ network_id = _get_net_id(neutron, module)
+ if not network_id:
+ module.fail_json(msg="failed to get the network id, please check the network name and make sure it is external")
+
+ if module.params['state'] == 'present':
+ port_id = _get_port_id(neutron, module, router_id, network_id)
+ if not port_id:
+ _add_gateway_router(neutron, module, router_id, network_id)
+ module.exit_json(changed=True, result="created")
+ module.exit_json(changed=False, result="success")
+
+ if module.params['state'] == 'absent':
+ port_id = _get_port_id(neutron, module, router_id, network_id)
+ if not port_id:
+ module.exit_json(changed=False, result="Success")
+ _remove_gateway_router(neutron, module, router_id)
+ module.exit_json(changed=True, result="Deleted")
+
+# this is magic, see lib/ansible/module.params['common.py
+from ansible.module_utils.basic import *
+main()
+
+
diff --git a/openstack/usr/share/openstack/modules/neutron_router_interface b/openstack/usr/share/openstack/modules/neutron_router_interface
new file mode 100644
index 00000000..8d57725c
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_router_interface
@@ -0,0 +1,249 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2013, Benno Joy <benno@ansibleworks.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from neutronclient.neutron import client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ print("failed=True msg='neutronclient and keystone client are required'")
+DOCUMENTATION = '''
+---
+module: neutron_router_interface
+version_added: "1.2"
+short_description: Attach/Dettach a subnet's interface to a router
+description:
+ - Attach/Dettach a subnet interface to a router, to provide a gateway for the subnet.
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ default: admin
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ default: 'yes'
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ default: 'yes'
+ auth_url:
+ description:
+ - The keystone URL for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+ router_name:
+ description:
+ - Name of the router to which the subnet's interface should be attached.
+ required: true
+ default: None
+ subnet_name:
+ description:
+ - Name of the subnet to whose interface should be attached to the router.
+ required: true
+ default: None
+ tenant_name:
+ description:
+ - Name of the tenant whose subnet has to be attached.
+ required: false
+ default: None
+requirements: ["neutronclient", "keystoneclient"]
+'''
+
+EXAMPLES = '''
+# Attach tenant1's subnet to the external router
+- neutron_router_interface: state=present login_username=admin
+ login_password=admin
+ login_tenant_name=admin
+ tenant_name=tenant1
+ router_name=external_route
+ subnet_name=t1subnet
+'''
+
+
+_os_keystone = None
+_os_tenant_id = None
+
+def _get_ksclient(module, kwargs):
+ try:
+ kclient = ksclient.Client(username=kwargs.get('login_username'),
+ password=kwargs.get('login_password'),
+ tenant_name=kwargs.get('login_tenant_name'),
+ auth_url=kwargs.get('auth_url'))
+ except Exception as e:
+ module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
+ global _os_keystone
+ _os_keystone = kclient
+ return kclient
+
+
+def _get_endpoint(module, ksclient):
+ try:
+ endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+ except Exception as e:
+ module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
+ return endpoint
+
+def _get_neutron_client(module, kwargs):
+ _ksclient = _get_ksclient(module, kwargs)
+ token = _ksclient.auth_token
+ endpoint = _get_endpoint(module, _ksclient)
+ kwargs = {
+ 'token': token,
+ 'endpoint_url': endpoint
+ }
+ try:
+ neutron = client.Client('2.0', **kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
+ return neutron
+
+def _set_tenant_id(module):
+ global _os_tenant_id
+ if not module.params['tenant_name']:
+ login_tenant_name = module.params['login_tenant_name']
+ else:
+ login_tenant_name = module.params['tenant_name']
+
+ for tenant in _os_keystone.tenants.list():
+ if tenant.name == login_tenant_name:
+ _os_tenant_id = tenant.id
+ break
+ if not _os_tenant_id:
+ module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
+
+
+def _get_router_id(module, neutron):
+ kwargs = {
+ 'name': module.params['router_name'],
+ }
+ try:
+ routers = neutron.list_routers(**kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in getting the router list: %s " % e.message)
+ if not routers['routers']:
+ return None
+ return routers['routers'][0]['id']
+
+
+def _get_subnet_id(module, neutron):
+ subnet_id = None
+ kwargs = {
+ 'tenant_id': _os_tenant_id,
+ 'name': module.params['subnet_name'],
+ }
+ try:
+ subnets = neutron.list_subnets(**kwargs)
+ except Exception as e:
+ module.fail_json( msg = " Error in getting the subnet list:%s " % e.message)
+ if not subnets['subnets']:
+ return None
+ return subnets['subnets'][0]['id']
+
+def _get_port_id(neutron, module, router_id, subnet_id):
+ kwargs = {
+ 'tenant_id': _os_tenant_id,
+ 'device_id': router_id,
+ }
+ try:
+ ports = neutron.list_ports(**kwargs)
+ except Exception as e:
+ module.fail_json( msg = "Error in listing ports: %s" % e.message)
+ if not ports['ports']:
+ return None
+ for port in ports['ports']:
+ for subnet in port['fixed_ips']:
+ if subnet['subnet_id'] == subnet_id:
+ return port['id']
+ return None
+
+def _add_interface_router(neutron, module, router_id, subnet_id):
+ kwargs = {
+ 'subnet_id': subnet_id
+ }
+ try:
+ neutron.add_interface_router(router_id, kwargs)
+ except Exception as e:
+ module.fail_json(msg = "Error in adding interface to router: %s" % e.message)
+ return True
+
+def _remove_interface_router(neutron, module, router_id, subnet_id):
+ kwargs = {
+ 'subnet_id': subnet_id
+ }
+ try:
+ neutron.remove_interface_router(router_id, kwargs)
+ except Exception as e:
+ module.fail_json(msg="Error in removing interface from router: %s" % e.message)
+ return True
+
+def main():
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin'),
+ login_password = dict(required=True),
+ login_tenant_name = dict(required='True'),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ router_name = dict(required=True),
+ subnet_name = dict(required=True),
+ tenant_name = dict(default=None),
+ state = dict(default='present', choices=['absent', 'present']),
+ ),
+ )
+
+ neutron = _get_neutron_client(module, module.params)
+ _set_tenant_id(module)
+
+ router_id = _get_router_id(module, neutron)
+ if not router_id:
+ module.fail_json(msg="failed to get the router id, please check the router name")
+
+ subnet_id = _get_subnet_id(module, neutron)
+ if not subnet_id:
+ module.fail_json(msg="failed to get the subnet id, please check the subnet name")
+
+ if module.params['state'] == 'present':
+ port_id = _get_port_id(neutron, module, router_id, subnet_id)
+ if not port_id:
+ _add_interface_router(neutron, module, router_id, subnet_id)
+ module.exit_json(changed=True, result="created", id=port_id)
+ module.exit_json(changed=False, result="success", id=port_id)
+
+ if module.params['state'] == 'absent':
+ port_id = _get_port_id(neutron, module, router_id, subnet_id)
+ if not port_id:
+ module.exit_json(changed = False, result = "Success")
+ _remove_interface_router(neutron, module, router_id, subnet_id)
+ module.exit_json(changed=True, result="Deleted")
+
+# this is magic, see lib/ansible/module.params['common.py
+from ansible.module_utils.basic import *
+main()
diff --git a/openstack/usr/share/openstack/modules/neutron_sec_group b/openstack/usr/share/openstack/modules/neutron_sec_group
new file mode 100644
index 00000000..518c50e7
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_sec_group
@@ -0,0 +1,382 @@
+#!/usr/bin/python
+#
+# (c) Cisco Systems, 2014
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+DOCUMENTATION = '''
+---
+module: neutron_sec_group
+short_description: Create, Remove or Update Openstack security groups
+description:
+ - Create, Remove or Update Openstack security groups
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ auth_url:
+ description:
+ - The keystone url for authentication
+ required: false
+ default: 'http://127.0.0.1:5000/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the security group
+ choices: ['present', 'absent']
+ default: present
+ name:
+ description:
+ - Name to be given to the security group
+ required: true
+ default: None
+ tenant_name:
+ description:
+ - Name of the tenant for which the security group has to be created,
+ if none, the security group would be created for the login tenant.
+ required: false
+ default: None
+ rules:
+ description:
+ - "List of security group rules. Available parameters of a rule:
+ direction, port_range_min, port_range_max, ethertype, protocol,
+ remote_ip_prefix/remote_ip_group"
+ required: false
+ default: none
+requirements: ["neutronclient", "keystoneclient"]
+'''
+
+EXAMPLES = '''
+# Creates a security group with a number of rules
+neutron_sec_group:
+ login_username: "demo"
+ login_password: "password"
+ login_tenant_name: "demo"
+ auth_url: "http://127.0.0.1:5000/v2.0"
+ name: "sg-test"
+ description: "Description of the security group"
+ state: "present"
+ rules:
+ - direction: "ingress"
+ port_range_min: "80"
+ port_range_max: "80"
+ ethertype: "IPv4"
+ protocol: "tcp"
+ remote_ip_prefix: "10.0.0.1/24"
+ - direction: "ingress"
+ port_range_min: "22"
+ port_range_max: "22"
+ ethertype: "IPv4"
+ protocol: "tcp"
+ remote_ip_prefix: "10.0.0.1/24"
+'''
+
+try:
+ import neutronclient.v2_0.client
+ import keystoneclient.v2_0.client
+ from neutronclient.common import exceptions
+except ImportError:
+ print "failed=True msg='neutronclient and keystoneclient are required'"
+
+def main():
+ """
+ Main function - entry point. The magic starts here ;-)
+ """
+ module = AnsibleModule(
+ argument_spec=dict(
+ auth_url=dict(default="http://127.0.0.1:5000/v2.0/"),
+ login_username=dict(required=True),
+ login_password=dict(required=True),
+ login_tenant_name=dict(required=True),
+ name=dict(required=True),
+ description=dict(default=None),
+ region_name=dict(default=None),
+ rules=dict(default=None),
+ tenant_name=dict(required=False),
+ state=dict(default="present", choices=['present', 'absent'])
+ ),
+ supports_check_mode=True
+ )
+ network_client = _get_network_client(module.params)
+ identity_client = _get_identity_client(module.params)
+
+ try:
+ # Get id of security group (as a result check whether it exists)
+ params = {
+ 'name': module.params['name'],
+ 'tenant_id': _get_tenant_id(module, identity_client),
+ 'fields': 'id'
+ }
+ sec_groups = network_client.list_security_groups(**params)["security_groups"]
+ if len(sec_groups) > 1:
+ raise exceptions.NeutronClientNoUniqueMatch(resource='security_group',name=name)
+ elif len(sec_groups) == 0:
+ sec_group_exists = False
+ else:
+ sec_group = sec_groups[0]
+ sec_group_exists = True
+
+ # state=present -> create or update depending on whether sg exists.
+ if module.params['state'] == "present":
+ # UPDATE
+ if sec_group_exists:
+ changed, sg = _update_sg(module, network_client, sec_group)
+ if changed:
+ module.exit_json(sec_group=sg, updated=True, changed=changed)
+ else:
+ module.exit_json(sec_group=sg, changed=changed)
+ # CREATE
+ else:
+ sg = _create_sg(module, network_client, identity_client)
+ module.exit_json(sec_group=sg, created=True, changed=True)
+ # DELETE
+ elif module.params['state'] == "absent" and sec_group_exists:
+ _delete_sg(module, network_client, sec_group)
+ module.exit_json(changed=True)
+
+ module.exit_json(changed=False)
+
+ except exceptions.Unauthorized as exc:
+ module.fail_json(msg="Authentication error: %s" % str(exc))
+ except Exception as exc:
+ module.fail_json(msg="Error: %s" % str(exc))
+
+def _delete_sg(module, network_client, sec_group):
+ """
+ Deletes a security group.
+ :param module: module to get security group params from.
+ :param network_client: network client to use.
+ :param sec_group: security group to delete.
+ """
+ if module.check_mode:
+ return
+ network_client.delete_security_group(sec_group['id'])
+
+
+def _create_sg(module, network_client, identity_client):
+ """
+ Creates a security group.
+ :param module: module to get security group params from.
+ :param network_client: network client to use.
+ :param: identity_client: identity_client used if an admin performs the
+ operation for a different tenant.
+ :return: newly created security group.
+ """
+ if module.check_mode:
+ return None
+ # NOTE: we don't do explicit rule validation, the API server will take
+ # care of that for us :-)
+ rules = module.params['rules']
+
+ data = {
+ "security_group": {
+ "name": module.params['name'],
+ "description": module.params['description'],
+ 'tenant_id': _get_tenant_id(module, identity_client)
+ }
+ }
+
+ sg = network_client.create_security_group(data)
+ sg = sg["security_group"]
+
+ changed, sg = _update_sg(module, network_client, sg)
+ return sg
+
+
+def _update_sg(module, network_client, sg):
+ """
+ Updates a security group.
+ :param module: module to get updated security group param from.
+ :param network_client: network client to use.
+ :param sg: security group that needs to be updated.
+ :return: True/False, the updated security group.
+ """
+ changed = False
+ sg = network_client.show_security_group(sg['id'])
+ sg = sg['security_group']
+
+ # We only allow description updating, no name updating
+ if module.params["description"] \
+ and not module.params['description'] == sg['description'] \
+ and module.check_mode:
+
+ changed = True
+ elif module.params["description"] \
+ and not module.params['description'] == sg['description'] \
+ and not module.check_mode:
+ body = {
+ "security_group": {
+ "description": module.params["description"]
+ }
+ }
+ sg = network_client.update_security_group(sg['id'], body)
+ sg = sg['security_group']
+ changed = True
+
+ # Security rules group update
+ existing_rules = sg['security_group_rules']
+ wanted_rules = module.params['rules']
+
+ #check ok
+ ok_rules = []
+ for new_rule in wanted_rules:
+ # Ugly: define tenant also here so that matches
+ new_rule['tenant_id'] = sg['tenant_id']
+ # protocol is in lowercase
+ if 'protocol' in new_rule:
+ new_rule['protocol'] = new_rule['protocol'].lower()
+
+ matched_id = None
+ for old_rule in existing_rules:
+ clean_new_rule = new_rule.copy()
+ clean_old_rule = old_rule.copy()
+ old_id = clean_old_rule.pop('id')
+ clean_old_rule.pop('security_group_id')
+ for key in clean_old_rule.keys():
+ if key not in clean_new_rule:
+ clean_new_rule[key] = None
+ continue
+ value = clean_new_rule[key]
+ if isinstance(value, (str, unicode)) and value.isdigit():
+ clean_new_rule[key] = int(value)
+ if cmp(clean_old_rule, clean_new_rule) == 0:
+ matched_id = old_id
+ break
+
+ if matched_id:
+ new_rule['done'] = True
+ ok_rules.append(matched_id)
+
+ #apply new first
+ new_rules = [rule for rule in wanted_rules if 'done' not in rule]
+ if len(new_rules):
+ if not module.check_mode:
+ sg = _create_sg_rules(network_client, sg, new_rules)
+ changed = True
+
+ #then delete not ok
+ for rule in existing_rules:
+ if rule['id'] in ok_rules:
+ continue
+ if not module.check_mode:
+ sg = network_client.delete_security_group_rule(rule['id'])
+ changed = True
+
+ return changed, sg
+
+def _create_sg_rules(network_client, sg, rules):
+ """
+ Creates a set of security group rules in a given security group.
+ :param network_client: network client to use to create rules.
+ :param sg: security group to create rules in.
+ :param rules: rules to create.
+ :return: the updated security group.
+ """
+ if rules:
+ for rule in rules:
+ rule['tenant_id'] = sg['tenant_id']
+ rule['security_group_id'] = sg['id']
+ data = {
+ "security_group_rule": rule
+ }
+ network_client.create_security_group_rule(data)
+
+ # fetch security group again to show end result
+ return network_client.show_security_group(sg['id'])['security_group']
+ return sg
+
+
+def _get_tenant_id(module, identity_client):
+ """
+ Returns the tenant_id, given tenant_name.
+ if tenant_name is not specified in the module params uses tenant_id
+ from Keystone session
+ :param identity_client: identity_client used to get the tenant_id from its
+ name.
+ :param module_params: module parameters.
+ """
+ if not module.params['tenant_name']:
+ tenant_id = identity_client.tenant_id
+ else:
+ tenant_name = module.params['tenant_name']
+ tenant = _get_tenant(identity_client, tenant_name)
+ tenant_id = tenant.id
+
+ return tenant_id
+
+
+def _get_tenant(identity_client, tenant_name):
+ """
+ Returns the tenant, given the tenant_name.
+ :param identity_client: identity client to use to do the required requests.
+ :param tenant_name: name of the tenant.
+ :return: tenant for which the name was given.
+ """
+ tenants = identity_client.tenants.list()
+ tenant = next((t for t in tenants if t.name == tenant_name), None)
+ if not tenant:
+ raise Exception("Tenant with name '%s' not found." % tenant_name)
+
+ return tenant
+
+
+def _get_network_client(module_params):
+ """
+ :param module_params: module params containing the openstack credentials
+ used to authenticate.
+ :return: a neutron client.
+ """
+ client = neutronclient.v2_0.client.Client(
+ username=module_params.get('login_username'),
+ password=module_params.get('login_password'),
+ tenant_name=module_params.get('login_tenant_name'),
+ auth_url=module_params.get('auth_url'),
+ region_name=module_params.get('region_name'))
+
+ return client
+
+
+def _get_identity_client(module_params):
+ """
+ :param module_params: module params containing the openstack credentials
+ used to authenticate.
+ :return: a keystone client.
+ """
+ client = keystoneclient.v2_0.client.Client(
+ username=module_params.get('login_username'),
+ password=module_params.get('login_password'),
+ tenant_name=module_params.get('login_tenant_name'),
+ auth_url=module_params.get('auth_url'),
+ region_name=module_params.get('region_name'))
+
+ return client
+
+
+# Let's get the party started!
+from ansible.module_utils.basic import *
+
+main()
diff --git a/openstack/usr/share/openstack/modules/neutron_subnet b/openstack/usr/share/openstack/modules/neutron_subnet
new file mode 100644
index 00000000..8cb622b5
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/neutron_subnet
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2013, Benno Joy <benno@ansibleworks.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from neutronclient.neutron import client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ print("failed=True msg='neutron and keystone client are required'")
+
+DOCUMENTATION = '''
+---
+module: neutron_subnet
+version_added: "1.2"
+short_description: Add/Remove floating IP from an instance
+description:
+ - Add or Remove a floating IP to an instance
+options:
+ login_username:
+ description:
+ - login username to authenticate to keystone
+ required: true
+ default: admin
+ login_password:
+ description:
+ - Password of login user
+ required: true
+ default: True
+ login_tenant_name:
+ description:
+ - The tenant name of the login user
+ required: true
+ default: True
+ auth_url:
+ description:
+ - The keystone URL for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: false
+ default: None
+ state:
+ description:
+ - Indicate desired state of the resource
+ choices: ['present', 'absent']
+ default: present
+ network_name:
+ description:
+ - Name of the network to which the subnet should be attached
+ required: true
+ default: None
+ cidr:
+ description:
+ - The CIDR representation of the subnet that should be assigned to the subnet
+ required: true
+ default: None
+ tenant_name:
+ description:
+ - The name of the tenant for whom the subnet should be created
+ required: false
+ default: None
+ ip_version:
+ description:
+ - The IP version of the subnet 4 or 6
+ required: false
+ default: 4
+ enable_dhcp:
+ description:
+ - Whether DHCP should be enabled for this subnet.
+ required: false
+ default: true
+ gateway_ip:
+ description:
+ - The ip that would be assigned to the gateway for this subnet
+ required: false
+ default: None
+ dns_nameservers:
+ description:
+ - DNS nameservers for this subnet, comma-separated
+ required: false
+ default: None
+ allocation_pool_start:
+ description:
+ - From the subnet pool the starting address from which the IP should be allocated
+ required: false
+ default: None
+ allocation_pool_end:
+ description:
+ - From the subnet pool the last IP that should be assigned to the virtual machines
+ required: false
+ default: None
+ host_routes:
+ description:
+ - Host routes for this subnet, list of dictionaries, e.g. [{destination: 0.0.0.0/0, nexthop: 123.456.78.9}, {destination: 192.168.0.0/24, nexthop: 192.168.0.1}]
+ required: false
+ default: None
+requirements: ["neutron", "keystoneclient"]
+'''
+
+EXAMPLES = '''
+# Create a subnet for a tenant with the specified subnet
+- neutron_subnet: state=present login_username=admin login_password=admin
+ login_tenant_name=admin tenant_name=tenant1
+ network_name=network1 name=net1subnet cidr=192.168.0.0/24"
+'''
+
+_os_keystone = None
+_os_tenant_id = None
+_os_network_id = None
+
+def _get_ksclient(module, kwargs):
+ try:
+ kclient = ksclient.Client(username=kwargs.get('login_username'),
+ password=kwargs.get('login_password'),
+ tenant_name=kwargs.get('login_tenant_name'),
+ auth_url=kwargs.get('auth_url'))
+ except Exception as e:
+ module.fail_json(msg = "Error authenticating to the keystone: %s" %e.message)
+ global _os_keystone
+ _os_keystone = kclient
+ return kclient
+
+
+def _get_endpoint(module, ksclient):
+ try:
+ endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
+ except Exception as e:
+ module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
+ return endpoint
+
+def _get_neutron_client(module, kwargs):
+ _ksclient = _get_ksclient(module, kwargs)
+ token = _ksclient.auth_token
+ endpoint = _get_endpoint(module, _ksclient)
+ kwargs = {
+ 'token': token,
+ 'endpoint_url': endpoint
+ }
+ try:
+ neutron = client.Client('2.0', **kwargs)
+ except Exception as e:
+ module.fail_json(msg = " Error in connecting to Neutron: %s" % e.message)
+ return neutron
+
+def _set_tenant_id(module):
+ global _os_tenant_id
+ if not module.params['tenant_name']:
+ tenant_name = module.params['login_tenant_name']
+ else:
+ tenant_name = module.params['tenant_name']
+
+ for tenant in _os_keystone.tenants.list():
+ if tenant.name == tenant_name:
+ _os_tenant_id = tenant.id
+ break
+ if not _os_tenant_id:
+ module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
+
+def _get_net_id(neutron, module):
+ kwargs = {
+ 'tenant_id': _os_tenant_id,
+ 'name': module.params['network_name'],
+ }
+ try:
+ networks = neutron.list_networks(**kwargs)
+ except Exception as e:
+ module.fail_json("Error in listing Neutron networks: %s" % e.message)
+ if not networks['networks']:
+ return None
+ return networks['networks'][0]['id']
+
+
+def _get_subnet_id(module, neutron):
+ global _os_network_id
+ subnet_id = None
+ _os_network_id = _get_net_id(neutron, module)
+ if not _os_network_id:
+ module.fail_json(msg = "network id of network not found.")
+ else:
+ kwargs = {
+ 'tenant_id': _os_tenant_id,
+ 'name': module.params['name'],
+ }
+ try:
+ subnets = neutron.list_subnets(**kwargs)
+ except Exception as e:
+ module.fail_json( msg = " Error in getting the subnet list:%s " % e.message)
+ if not subnets['subnets']:
+ return None
+ return subnets['subnets'][0]['id']
+
+def _create_subnet(module, neutron):
+ neutron.format = 'json'
+ subnet = {
+ 'name': module.params['name'],
+ 'ip_version': module.params['ip_version'],
+ 'enable_dhcp': module.params['enable_dhcp'],
+ 'tenant_id': _os_tenant_id,
+ 'gateway_ip': module.params['gateway_ip'],
+ 'dns_nameservers': module.params['dns_nameservers'],
+ 'network_id': _os_network_id,
+ 'cidr': module.params['cidr'],
+ 'host_routes': module.params['host_routes'],
+ }
+ if module.params['allocation_pool_start'] and module.params['allocation_pool_end']:
+ allocation_pools = [
+ {
+ 'start' : module.params['allocation_pool_start'],
+ 'end' : module.params['allocation_pool_end']
+ }
+ ]
+ subnet.update({'allocation_pools': allocation_pools})
+ if not module.params['gateway_ip']:
+ subnet.pop('gateway_ip')
+ if module.params['dns_nameservers']:
+ subnet['dns_nameservers'] = module.params['dns_nameservers'].split(',')
+ else:
+ subnet.pop('dns_nameservers')
+ if not module.params['host_routes']:
+ subnet.pop('host_routes')
+ try:
+ new_subnet = neutron.create_subnet(dict(subnet=subnet))
+ except Exception, e:
+ module.fail_json(msg = "Failure in creating subnet: %s" % e.message)
+ return new_subnet['subnet']['id']
+
+
+def _delete_subnet(module, neutron, subnet_id):
+ try:
+ neutron.delete_subnet(subnet_id)
+ except Exception as e:
+ module.fail_json( msg = "Error in deleting subnet: %s" % e.message)
+ return True
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin'),
+ login_password = dict(required=True),
+ login_tenant_name = dict(required='True'),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ name = dict(required=True),
+ network_name = dict(required=True),
+ cidr = dict(required=True),
+ tenant_name = dict(default=None),
+ state = dict(default='present', choices=['absent', 'present']),
+ ip_version = dict(default='4', choices=['4', '6']),
+ enable_dhcp = dict(default='true', choices=BOOLEANS),
+ gateway_ip = dict(default=None),
+ dns_nameservers = dict(default=None),
+ allocation_pool_start = dict(default=None),
+ allocation_pool_end = dict(default=None),
+ host_routes = dict(default=None),
+ ),
+ )
+ neutron = _get_neutron_client(module, module.params)
+ _set_tenant_id(module)
+ if module.params['state'] == 'present':
+ subnet_id = _get_subnet_id(module, neutron)
+ if not subnet_id:
+ subnet_id = _create_subnet(module, neutron)
+ module.exit_json(changed = True, result = "Created" , id = subnet_id)
+ else:
+ module.exit_json(changed = False, result = "success" , id = subnet_id)
+ else:
+ subnet_id = _get_subnet_id(module, neutron)
+ if not subnet_id:
+ module.exit_json(changed = False, result = "success")
+ else:
+ _delete_subnet(module, neutron, subnet_id)
+ module.exit_json(changed = True, result = "deleted")
+
+# this is magic, see lib/ansible/module.params['common.py
+from ansible.module_utils.basic import *
+main()
diff --git a/openstack/usr/share/openstack/modules/nova_flavor b/openstack/usr/share/openstack/modules/nova_flavor
new file mode 100644
index 00000000..b71d648f
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/nova_flavor
@@ -0,0 +1,188 @@
+#!/usr/bin/python
+#coding: utf-8 -*-
+
+# (c) 2014, Adam Samalik <asamalik@redhat.com>
+#
+# This module is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This software is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this software. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ from novaclient import client
+ from keystoneclient.v2_0 import client as ksclient
+except ImportError:
+ print("failed=True msg='novaclient and keystone client are required'")
+
+DOCUMENTATION = '''
+---
+module: nova_flavor
+short_description: Manage OpenStack flavours
+description:
+ - Create VM flavours with OpenStack Nova service
+requirements: [ python-novaclient ]
+options:
+ login_username:
+ description:
+ - user name to authenticate against Identity service
+ required: True
+ aliases: [username]
+ login_password:
+ description:
+ - password to authenticate against Identity service
+ aliases: [password]
+ required: True
+ login_tenant_name:
+ description:
+ - tenant name of the login user
+ aliases: [tenant_name]
+ required: True
+ auth_url:
+ description:
+ - The keystone URL for authentication
+ required: false
+ default: 'http://127.0.0.1:35357/v2.0/'
+ region_name:
+ description:
+ - Name of the region
+ required: False
+ default: None
+ name:
+ description:
+ - Descriptive name of the flavor
+ required: True
+ ram:
+ description:
+ - Memory in MB for the flavor
+ required: True
+ vcpus:
+ description:
+ - Number of VCPUs for the flavor
+ required: True
+ disk:
+ description:
+ - Size of local disk in GB
+ required: True
+ swap:
+ description:
+ - Swap space in MB
+ required: False
+ default: 0
+ id:
+ description:
+ - ID for the flavor (optional).
+ required: False
+ default: ID will be automatically generated
+ is_public:
+ description:
+ - Decide if the flavour is public
+'''
+
+EXAMPLES = '''
+ - nova_flavor:
+ login_username: admin
+ login_password: 1234
+ login_tenant_name: admin
+ name: medium
+ ram: 2048
+ vcpus: 2
+ disk: 20
+'''
+
+
+def authenticate(module, auth_url, username, password, tenant_name, region):
+ """
+ Return a Nova client object.
+ """
+ try:
+ keystone = ksclient.Client(auth_url=auth_url,
+ username=username,
+ password=password,
+ tenant_name=tenant_name,
+ region=region)
+ except Exception as e:
+ module.fail_json(
+ msg = "Could not authenticate with Keystone: {}".format(
+ e.message))
+
+ try:
+ nova = client.Client('2', keystone.username,
+ keystone.password,
+ keystone.tenant_name,
+ keystone.auth_url)
+ except Exception as e:
+ module.fail_json(msg = "Could not get Nova client: {}".format(
+ e.message))
+
+ return nova
+
+def get_flavors(nova, name, id=None):
+ if not id:
+ flavors = [x for x in nova.flavors.list() if x.name == name]
+ else:
+ flavors = [x for x in nova.flavors.list() if x.name == name and x.id == str(id)]
+ return flavors
+
+def create_flavor(module, nova, name, ram, vcpus, disk, swap, id, is_public):
+ flavors = get_flavors(nova, name, id)
+ if len(flavors) >0:
+ return False, flavors[0].id
+
+ try:
+ flavor = nova.flavors.create(name, ram, vcpus, disk, swap=swap,
+ flavorid=id, is_public=is_public)
+ except Exception as e:
+ module.fail_json(msg = "Could not create a flavour: {}".format(
+ e.message))
+
+ return True, flavor.id
+
+def main():
+ module = AnsibleModule(
+ argument_spec = dict(
+ login_username = dict(default='admin', aliases=["username"]),
+ login_password = dict(required=True, aliases=["password"]),
+ login_tenant_name = dict(required='True', aliases=["tenant_name"]),
+ auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
+ region_name = dict(default=None),
+ name = dict(required=True),
+ ram = dict(required=True),
+ vcpus = dict(required=True),
+ disk = dict(required=True),
+ swap = dict(default=0),
+ id = dict(default=None),
+ is_public = dict(default=True, choices=BOOLEANS),
+ )
+ )
+ auth_url = module.params['auth_url']
+ region = module.params['region_name']
+ username = module.params['login_username']
+ password = module.params['login_password']
+ tenant_name = module.params['login_tenant_name']
+ name = module.params['name']
+ ram = module.params['ram']
+ vcpus = module.params['vcpus']
+ disk = module.params['disk']
+ swap = module.params['swap']
+ id = module.params['id']
+ is_public = module.params['is_public']
+
+ nova = authenticate(module, auth_url, username, password, tenant_name, region)
+
+ changed, id = create_flavor(module, nova, name, ram, vcpus, disk, swap, id,
+ is_public)
+
+ module.exit_json(changed=changed, name=name, id=id)
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+if __name__ == '__main__':
+ main()
diff --git a/openstack/usr/share/openstack/modules/nova_manage b/openstack/usr/share/openstack/modules/nova_manage
new file mode 100644
index 00000000..6b1a297e
--- /dev/null
+++ b/openstack/usr/share/openstack/modules/nova_manage
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+DOCUMENTATION = '''
+---
+module: nova_manage
+short_description: Initialize OpenStack Compute (nova) database
+description: Create the tables for the database backend used by nova
+options:
+ action:
+ description:
+ - action to perform. Currently only dbsync is supported
+ required: true
+requirements: [ nova ]
+'''
+
+EXAMPLES = '''
+nova_manage: action=dbsync
+'''
+
+import subprocess
+
+try:
+ from nova.db.sqlalchemy import migration
+ from nova import config
+except ImportError:
+ nova_found = False
+else:
+ nova_found = True
+
+
+def load_config_file():
+ config.parse_args([])
+
+
+def will_db_change():
+ """ Check if the database version will change after the sync.
+
+ """
+ # Load the config file options
+ current_version = migration.db_version()
+ repository = migration._find_migrate_repo()
+ repo_version = repository.latest
+ return current_version != repo_version
+
+
+def do_dbsync():
+ """Do the dbsync. Returns (returncode, stdout, stderr)"""
+ # We call nova-manage db_sync on the shell rather than trying to
+ # do this in Python since we have no guarantees about changes to the
+ # internals.
+ args = ['nova-manage', 'db', 'sync']
+
+ call = subprocess.Popen(args, shell=False,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ out, err = call.communicate()
+ return (call.returncode, out, err)
+
+
+def main():
+
+ module = AnsibleModule(
+ argument_spec=dict(
+ action=dict(required=True),
+ ),
+ supports_check_mode=True
+ )
+
+ if not nova_found:
+ module.fail_json(msg="nova package could not be found")
+
+ action = module.params['action']
+
+ if action not in ['dbsync', 'db_sync']:
+ module.fail_json(msg="Only supported action is 'dbsync'")
+
+ load_config_file()
+
+ changed = will_db_change()
+ if module.check_mode:
+ module.exit_json(changed=changed)
+
+ (res, stdout, stderr) = do_dbsync()
+
+ if res == 0:
+ module.exit_json(changed=changed, stdout=stdout, stderr=stderr)
+ else:
+ module.fail_json(msg="nova-manage returned non-zero value: %d" % res,
+ stdout=stdout, stderr=stderr)
+
+# this is magic, see lib/ansible/module_common.py
+#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
+main()
diff --git a/openstack/usr/share/openstack/openstack-keystone-setup b/openstack/usr/share/openstack/openstack-keystone-setup
deleted file mode 100644
index 9c034c5b..00000000
--- a/openstack/usr/share/openstack/openstack-keystone-setup
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/bin/sh
-#
-# Copyright (C) 2014 Codethink Limited
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-set -e
-
-# Create required system users and groups
-
-getent group keystone >/dev/null || groupadd -r --gid 163 keystone
-getent passwd keystone >/dev/null || \
- useradd --uid 163 -r -g keystone -d /var/lib/keystone -s /sbin/nologin \
- -c "OpenStack Keystone Daemons" keystone
-
-# Keystone compute configuration
-if [ ! -d /var/run/keystone ]; then
- mkdir -p /var/run/keystone
- chown -R keystone:keystone /var/run/keystone
-fi
-
-if [ ! -d /var/lock/keystone ]; then
- mkdir -p /var/lock/keystone
- chown -R keystone:keystone /var/lock/keystone
-fi
-
-if [ ! -d /var/log/keystone ]; then
- mkdir -p /var/log/keystone
- chown -R keystone:keystone /var/log/keystone
-fi
-
-# Setup the keystone database
-if ! sudo -u postgres psql -lqt | grep -q keystone; then
- # Create posgreSQL user
- sudo -u postgres createuser \
- --pwprompt --encrypted \
- --no-adduser --no-createdb \
- --no-password \
- ##KEYSTONE_DB_USER##
-
- sudo -u postgres createdb \
- --owner=##KEYSTONE_DB_USER## \
- keystone
-
- sudo -u keystone keystone-manage db_sync
-fi
-
-chown -R keystone:keystone /var/lib/keystone
-
-systemctl start openstack-keystone
-
-export OS_SERVICE_TOKEN=##KEYSTONE_TEMPORARY_ADMIN_TOKEN##
-export OS_SERVICE_ENDPOINT='http://onenode:35357/v2.0'
-
-# This script creates a TEMPORARY admin user, with a password that may
-# float arount on the system. Please delete this user once you have set up
-# the real admin user with a real secure password.
-
-keystone tenant-create --name admin --description "Admin Tenant"
-keystone role-create --name admin
-
-keystone user-create --name temporary_admin --pass ##KEYSTONE_TEMPORARY_ADMIN_PASSWORD##
-keystone user-role-add --tenant admin --user temporary_admin --role admin
-
-keystone tenant-create --name service --description "Service Tenant"
-
-# Define a service for the Identity Service
-keystone service-create --name keystone --type identity --description "Openstack Identity"
-
-# Specify an API endpoint for the Identity Service by using the returned service ID.
-keystone endpoint-create --service-id $(keystone service-list | awk '/ identity / {print $2}') \
- --publicurl ##KEYSTONE_PUBLIC_URL## \
- --internalurl ##KEYSTONE_INTERNAL_URL## \
- --adminurl ##KEYSTONE_ADMIN_URL##
-
-rm /etc/systemd/system/multi-user.target.wants/openstack-keystone-setup.service
-
-ln -s "/etc/systemd/system/openstack-keystone.service" \
- "/etc/systemd/system/multi-user.target.wants/openstack-keystone.service"
-
-exit 0