Move Glance Artifact Repository API to separate endpoint

EXPERIMENTAL Glance v3 API has been removed in favor of standalone API
(EXPERIMENTAL Artifacts API of v0.1).
This patch introduces a new process entry point to run on a different
port (9494 by default), with its own configuration file and a paste
config.

A controller stub for old /v3 api remains in the glnace.api package for
the compatibility with existing paste configuration which may reference
it. This stub returns a 301 redirects to glare endpoint if it is present
or 410 errors otherwise.

To reuse  the existing version_negotiation middleware some refactoring
has been made.

Implements blueprint: move-v3-to-glare

Change-Id: I5b7bd4cdcc5f2a40fc4a5f74bcc422fd700c4fb0
This commit is contained in:
Alexander Tivelkov 2015-12-09 17:06:57 +03:00 committed by Darja Shakhray
parent d64fd960d6
commit b974a63660
59 changed files with 1396 additions and 276 deletions

View File

@ -1461,7 +1461,7 @@ Optional. Default: ``True``
Defines which version(s) of the Registry API will be enabled.
If the Glance API server parameter ``enable_v1_api`` has been set to ``True`` the
``enable_v1_registry`` has to be ``True`` as well.
If the Glance API server parameter ``enable_v2_api`` or ``enable_v3_api`` has been
If the Glance API server parameter ``enable_v2_api`` has been
set to ``True`` and the parameter ``data_api`` has been set to
``glance.db.registry.api`` the ``enable_v2_registry`` has to be set to ``True``
@ -1518,7 +1518,7 @@ Optional. Default: ``roles``.
Configuring Glance APIs
-----------------------
The glance-api service implements versions 1, 2 and 3 of
The glance-api service implements versions 1 and 2 of
the OpenStack Images API. Disable any version of
the Images API using the following options:
@ -1530,11 +1530,7 @@ Optional. Default: ``True``
Optional. Default: ``True``
* ``enable_v3_api=<True|False>``
Optional. Default: ``False``
**IMPORTANT NOTE**: To use v2 registry in v2 or v3 API, you must set
**IMPORTANT NOTE**: To use v2 registry in v2 API, you must set
``data_api`` to glance.db.registry.api in glance-api.conf.
Configuring Glance Tasks

View File

@ -39,7 +39,6 @@ paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app
/v3: apiv3app
[app:apiversions]
paste.app_factory = glance.api.versions:create_resource
@ -50,9 +49,6 @@ paste.app_factory = glance.api.v1.router:API.factory
[app:apiv2app]
paste.app_factory = glance.api.v2.router:API.factory
[app:apiv3app]
paste.app_factory = glance.api.v3.router:API.factory
[filter:healthcheck]
paste.filter_factory = oslo_middleware:Healthcheck.factory
backends = disable_by_file

View File

@ -94,9 +94,6 @@
# Deploy the v2 OpenStack Images API. (boolean value)
#enable_v2_api = true
# Deploy the v3 OpenStack Objects API. (boolean value)
#enable_v3_api = false
# Deploy the v1 OpenStack Registry API. (boolean value)
#enable_v1_registry = true

View File

@ -71,9 +71,6 @@
# Deploy the v2 OpenStack Images API. (boolean value)
#enable_v2_api = true
# Deploy the v3 OpenStack Objects API. (boolean value)
#enable_v3_api = false
# Deploy the v1 OpenStack Registry API. (boolean value)
#enable_v1_registry = true

View File

@ -0,0 +1,60 @@
# Use this pipeline for no auth - DEFAULT
[pipeline:glare-api]
pipeline = cors healthcheck versionnegotiation osprofiler unauthenticated-context rootapp
# Use this pipeline for keystone auth
[pipeline:glare-api-keystone]
pipeline = cors healthcheck versionnegotiation osprofiler authtoken context rootapp
[composite:rootapp]
paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v0.1: glareapi
[app:apiversions]
paste.app_factory = glance.api.glare.versions:create_resource
[app:glareapi]
paste.app_factory = glance.api.glare.router:API.factory
[filter:healthcheck]
paste.filter_factory = oslo_middleware:Healthcheck.factory
backends = disable_by_file
disable_by_file_path = /etc/glance/healthcheck_disable
[filter:versionnegotiation]
paste.filter_factory = glance.api.middleware.version_negotiation:GlareVersionNegotiationFilter.factory
[filter:context]
paste.filter_factory = glance.api.middleware.context:ContextMiddleware.factory
[filter:unauthenticated-context]
paste.filter_factory = glance.api.middleware.context:UnauthenticatedContextMiddleware.factory
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
delay_auth_decision = true
[filter:osprofiler]
paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = glance
oslo_config_program = glance-glare
# Basic Headers (Automatic)
# Accept = Origin, Accept, Accept-Language, Content-Type, Cache-Control, Content-Language, Expires, Last-Modified, Pragma
# Expose = Origin, Accept, Accept-Language, Content-Type, Cache-Control, Content-Language, Expires, Last-Modified, Pragma
# Glance Headers
# Accept = Content-MD5, Accept-Encoding
# Keystone Headers
# Accept = X-Auth-Token, X-Identity-Status, X-Roles, X-Service-Catalog, X-User-Id, X-Tenant-Id
# Expose = X-Auth-Token, X-Subject-Token, X-Service-Token
# Request ID Middleware Headers
# Accept = X-OpenStack-Request-ID
# Expose = X-OpenStack-Request-ID
latent_allow_headers = Content-MD5, Accept-Encoding, X-Auth-Token, X-Identity-Status, X-Roles, X-Service-Catalog, X-User-Id, X-Tenant-Id, X-OpenStack-Request-ID
latent_expose_headers = X-Auth-Token, X-Subject-Token, X-Service-Token, X-OpenStack-Request-ID

849
etc/glance-glare.conf Normal file
View File

@ -0,0 +1,849 @@
[DEFAULT]
#
# From glance.glare
#
# When true, this option sets the owner of an image to be the tenant.
# Otherwise, the owner of the image will be the authenticated user
# issuing the request. (boolean value)
#owner_is_tenant = true
# Role used to identify an authenticated user as administrator.
# (string value)
#admin_role = admin
# Allow unauthenticated users to access the API with read-only
# privileges. This only applies when using ContextMiddleware. (boolean
# value)
#allow_anonymous_access = false
# Limits request ID length. (integer value)
#max_request_id_length = 64
# Public url to use for versions endpoint. The default is None, which
# will use the request's host_url attribute to populate the URL base.
# If Glance is operating behind a proxy, you will want to change this
# to represent the proxy's URL. (string value)
#public_endpoint = <None>
# Address to bind the server. Useful when selecting a particular
# network interface. (string value)
#bind_host = 0.0.0.0
# The port on which the server will listen. (port value)
# Minimum value: 1
# Maximum value: 65535
#bind_port = <None>
# The number of child process workers that will be created to service
# requests. The default will be equal to the number of CPUs available.
# (integer value)
#workers = 8
# Maximum line size of message headers to be accepted. max_header_line
# may need to be increased when using large tokens (typically those
# generated by the Keystone v3 API with big service catalogs (integer
# value)
#max_header_line = 16384
# If False, server will return the header "Connection: close", If
# True, server will return "Connection: Keep-Alive" in its responses.
# In order to close the client socket connection explicitly after the
# response is sent and read successfully by the client, you simply
# have to set this option to False when you create a wsgi server.
# (boolean value)
#http_keepalive = true
# Timeout for client connections' socket operations. If an incoming
# connection is idle for this number of seconds it will be closed. A
# value of '0' means wait forever. (integer value)
#client_socket_timeout = 900
# The backlog value that will be used when creating the TCP listener
# socket. (integer value)
#backlog = 4096
# The value for the socket option TCP_KEEPIDLE. This is the time in
# seconds that the connection must be idle before TCP starts sending
# keepalive probes. (integer value)
#tcp_keepidle = 600
# CA certificate file to use to verify connecting clients. (string
# value)
#ca_file = <None>
# Certificate file to use when starting API server securely. (string
# value)
#cert_file = <None>
# Private key file to use when starting API server securely. (string
# value)
#key_file = <None>
# If False fully disable profiling feature. (boolean value)
#enabled = false
# If False doesn't trace SQL requests. (boolean value)
#trace_sqlalchemy = false
# Default publisher_id for outgoing notifications. (string value)
#default_publisher_id = image.localhost
# List of disabled notifications. A notification can be given either
# as a notification type to disable a single event, or as a
# notification group prefix to disable all events within a group.
# Example: if this config option is set to ["image.create",
# "metadef_namespace"], then "image.create" notification will not be
# sent after image is created and none of the notifications for
# metadefinition namespaces will be sent. (list value)
#disabled_notifications =
#
# From oslo.log
#
# Print debugging output (set logging level to DEBUG instead of
# default INFO level). (boolean value)
#debug = false
# If set to false, will disable INFO logging level, making WARNING the
# default. (boolean value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
#verbose = true
# 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.
# Note that when logging configuration files are used then all logging
# configuration is set in the configuration file and other logging
# configuration options are ignored (for example, log_format). (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. This option is ignored if
# log_config_append is set. (string value)
#log_format = <None>
# Format string for %%(asctime)s in log records. Default: %(default)s
# . This option is ignored if log_config_append is set. (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. This option is ignored if
# log_config_append is set. (string value)
# Deprecated group/name - [DEFAULT]/logfile
#log_file = <None>
# (Optional) The base directory used for relative --log-file paths.
# This option is ignored if log_config_append is set. (string value)
# Deprecated group/name - [DEFAULT]/logdir
#log_dir = <None>
# (Optional) Uses logging handler designed to watch file system. When
# log file is moved or removed this handler will open a new log file
# with specified path instantaneously. It makes sense only if log-file
# option is specified and Linux platform is used. This option is
# ignored if log_config_append is set. (boolean value)
#watch_log_file = false
# Use syslog for logging. Existing syslog format is DEPRECATED and
# will be changed later to honor RFC5424. This option is ignored if
# log_config_append is set. (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 Kilo,
# and will be removed in Mitaka, along with this option. This option
# is ignored if log_config_append is set. (boolean value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
#use_syslog_rfc_format = true
# Syslog facility to receive log lines. This option is ignored if
# log_config_append is set. (string value)
#syslog_log_facility = LOG_USER
# Log output to standard error. This option is ignored if
# log_config_append is set. (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 ERROR %(name)s %(instance)s
# List of logger=LEVEL pairs. This option is ignored if
# log_config_append is set. (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,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN
# Enables or disables publication of error events. (boolean value)
#publish_errors = 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] "
# Format string for user_identity field of the
# logging_context_format_string (string value)
#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s
# Enables or disables fatal status of deprecations. (boolean value)
#fatal_deprecations = false
[database]
#
# From oslo.db
#
# The file name to use with SQLite. (string value)
# Deprecated group/name - [DEFAULT]/sqlite_db
#sqlite_db = oslo.sqlite
# If True, SQLite uses synchronous mode. (boolean value)
# Deprecated group/name - [DEFAULT]/sqlite_synchronous
#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>
# 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 number of database 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 retries of a database transaction. (integer value)
#db_retry_interval = 1
# If True, increases the interval between retries of a database
# operation up to db_max_retry_interval. (boolean value)
#db_inc_retry_interval = true
# If db_inc_retry_interval is set, the maximum seconds between retries
# of a database operation. (integer value)
#db_max_retry_interval = 10
# Maximum retries in case of connection error or deadlock error before
# error is raised. Set to -1 to specify an infinite retry count.
# (integer value)
#db_max_retries = 20
#
# From oslo.db.concurrency
#
# Enable the experimental use of thread pooling for all DB API calls
# (boolean value)
# Deprecated group/name - [DEFAULT]/dbapi_use_tpool
#use_tpool = false
[glance_store]
#
# From glance.store
#
# List of stores enabled (list value)
#stores = file,http
# Default scheme to use to store image data. The scheme must be
# registered by one of the stores defined by the 'stores' config
# option. (string value)
#default_store = file
# Minimum interval seconds to execute updating dynamic storage
# capabilities based on backend status then. It's not a periodic
# routine, the update logic will be executed only when interval
# seconds elapsed and an operation of store has triggered. The feature
# will be enabled only when the option value greater then zero.
# (integer value)
#store_capabilities_update_min_interval = 0
#
# From glance.store
#
# If True, swiftclient won't check for a valid SSL certificate when
# authenticating. (boolean value)
#swift_store_auth_insecure = false
# A string giving the CA certificate file to use in SSL connections
# for verifying certs. (string value)
#swift_store_cacert = <None>
# The region of the swift endpoint to be used for single tenant. This
# setting is only necessary if the tenant has multiple swift
# endpoints. (string value)
#swift_store_region = <None>
# If set, the configured endpoint will be used. If None, the storage
# url from the auth response will be used. (string value)
#swift_store_endpoint = <None>
# A string giving the endpoint type of the swift service to use
# (publicURL, adminURL or internalURL). This setting is only used if
# swift_store_auth_version is 2. (string value)
#swift_store_endpoint_type = publicURL
# A string giving the service type of the swift service to use. This
# setting is only used if swift_store_auth_version is 2. (string
# value)
#swift_store_service_type = object-store
# Container within the account that the account should use for storing
# images in Swift when using single container mode. In multiple
# container mode, this will be the prefix for all containers. (string
# value)
#swift_store_container = glance
# The size, in MB, that Glance will start chunking image files and do
# a large object manifest in Swift. (integer value)
#swift_store_large_object_size = 5120
# The amount of data written to a temporary disk buffer during the
# process of chunking the image file. (integer value)
#swift_store_large_object_chunk_size = 200
# A boolean value that determines if we create the container if it
# does not exist. (boolean value)
#swift_store_create_container_on_put = false
# If set to True, enables multi-tenant storage mode which causes
# Glance images to be stored in tenant specific Swift accounts.
# (boolean value)
#swift_store_multi_tenant = false
# When set to 0, a single-tenant store will only use one container to
# store all images. When set to an integer value between 1 and 32, a
# single-tenant store will use multiple containers to store images,
# and this value will determine how many containers are created.Used
# only when swift_store_multi_tenant is disabled. The total number of
# containers that will be used is equal to 16^N, so if this config
# option is set to 2, then 16^2=256 containers will be used to store
# images. (integer value)
#swift_store_multiple_containers_seed = 0
# A list of tenants that will be granted read/write access on all
# Swift containers created by Glance in multi-tenant mode. (list
# value)
#swift_store_admin_tenants =
# If set to False, disables SSL layer compression of https swift
# requests. Setting to False may improve performance for images which
# are already in a compressed format, eg qcow2. (boolean value)
#swift_store_ssl_compression = true
# The number of times a Swift download will be retried before the
# request fails. (integer value)
#swift_store_retry_get_count = 0
# The reference to the default swift account/backing store parameters
# to use for adding new images. (string value)
#default_swift_reference = ref1
# Version of the authentication service to use. Valid versions are 2
# and 3 for keystone and 1 (deprecated) for swauth and rackspace.
# (deprecated - use "auth_version" in swift_store_config_file) (string
# value)
#swift_store_auth_version = 2
# The address where the Swift authentication service is listening.
# (deprecated - use "auth_address" in swift_store_config_file) (string
# value)
#swift_store_auth_address = <None>
# The user to authenticate against the Swift authentication service
# (deprecated - use "user" in swift_store_config_file) (string value)
#swift_store_user = <None>
# Auth key for the user authenticating against the Swift
# authentication service. (deprecated - use "key" in
# swift_store_config_file) (string value)
#swift_store_key = <None>
# The config file that has the swift account(s)configs. (string value)
#swift_store_config_file = <None>
# Info to match when looking for cinder in the service catalog. Format
# is : separated values of the form:
# <service_type>:<service_name>:<endpoint_type> (string value)
#cinder_catalog_info = volume:cinder:publicURL
# Override service catalog lookup with template for cinder endpoint
# e.g. http://localhost:8776/v1/%(project_id)s (string value)
#cinder_endpoint_template = <None>
# Region name of this node (string value)
#os_region_name = <None>
# Location of ca certicates file to use for cinder client requests.
# (string value)
#cinder_ca_certificates_file = <None>
# Number of cinderclient retries on failed http calls (integer value)
#cinder_http_retries = 3
# Allow to perform insecure SSL requests to cinder (boolean value)
#cinder_api_insecure = false
# Hostname or IP address of the instance to connect to, or a mongodb
# URI, or a list of hostnames / mongodb URIs. If host is an IPv6
# literal it must be enclosed in '[' and ']' characters following the
# RFC2732 URL syntax (e.g. '[::1]' for localhost) (string value)
#mongodb_store_uri = <None>
# Database to use (string value)
#mongodb_store_db = <None>
# Images will be chunked into objects of this size (in megabytes). For
# best performance, this should be a power of two. (integer value)
#sheepdog_store_chunk_size = 64
# Port of sheep daemon. (integer value)
#sheepdog_store_port = 7000
# IP address of sheep daemon. (string value)
#sheepdog_store_address = localhost
# RADOS images will be chunked into objects of this size (in
# megabytes). For best performance, this should be a power of two.
# (integer value)
#rbd_store_chunk_size = 8
# RADOS pool in which images are stored. (string value)
#rbd_store_pool = images
# RADOS user to authenticate as (only applicable if using Cephx. If
# <None>, a default will be chosen based on the client. section in
# rbd_store_ceph_conf) (string value)
#rbd_store_user = <None>
# Ceph configuration file path. If <None>, librados will locate the
# default config. If using cephx authentication, this file should
# include a reference to the right keyring in a client.<USER> section
# (string value)
#rbd_store_ceph_conf = /etc/ceph/ceph.conf
# Timeout value (in seconds) used when connecting to ceph cluster. If
# value <= 0, no timeout is set and default librados value is used.
# (integer value)
#rados_connect_timeout = 0
# ESX/ESXi or vCenter Server target system. The server value can be an
# IP address or a DNS name. (string value)
#vmware_server_host = <None>
# Username for authenticating with VMware ESX/VC server. (string
# value)
#vmware_server_username = <None>
# Password for authenticating with VMware ESX/VC server. (string
# value)
#vmware_server_password = <None>
# DEPRECATED. Inventory path to a datacenter. If the
# vmware_server_host specified is an ESX/ESXi, the
# vmware_datacenter_path is optional. If specified, it should be "ha-
# datacenter". This option is deprecated in favor of vmware_datastores
# and will be removed in the Liberty release. (string value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
#vmware_datacenter_path = ha-datacenter
# DEPRECATED. Datastore associated with the datacenter. This option is
# deprecated in favor of vmware_datastores and will be removed in the
# Liberty release. (string value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
#vmware_datastore_name = <None>
# Number of times VMware ESX/VC server API must be retried upon
# connection related issues. (integer value)
#vmware_api_retry_count = 10
# The interval used for polling remote tasks invoked on VMware ESX/VC
# server. (integer value)
#vmware_task_poll_interval = 5
# The name of the directory where the glance images will be stored in
# the VMware datastore. (string value)
#vmware_store_image_dir = /openstack_glance
# Allow to perform insecure SSL requests to ESX/VC. (boolean value)
#vmware_api_insecure = false
# A list of datastores where the image can be stored. This option may
# be specified multiple times for specifying multiple datastores.
# Either one of vmware_datastore_name or vmware_datastores is
# required. The datastore name should be specified after its
# datacenter path, seperated by ":". An optional weight may be given
# after the datastore name, seperated again by ":". Thus, the required
# format becomes <datacenter_path>:<datastore_name>:<optional_weight>.
# When adding an image, the datastore with highest weight will be
# selected, unless there is not enough free space available in cases
# where the image size is already known. If no weight is given, it is
# assumed to be zero and the directory will be considered for
# selection last. If multiple datastores have the same weight, then
# the one with the most free space available is selected. (multi
# valued)
#vmware_datastores =
# Directory to which the Filesystem backend store writes images.
# (string value)
#filesystem_store_datadir = <None>
# List of directories and its priorities to which the Filesystem
# backend store writes images. (multi valued)
#filesystem_store_datadirs =
# The path to a file which contains the metadata to be returned with
# any location associated with this store. The file must contain a
# valid JSON object. The object should contain the keys 'id' and
# 'mountpoint'. The value for both keys should be 'string'. (string
# value)
#filesystem_store_metadata_file = <None>
# The required permission for created image file. In this way the user
# other service used, e.g. Nova, who consumes the image could be the
# exclusive member of the group that owns the files created. Assigning
# it less then or equal to zero means don't change the default
# permission of the file. This value will be decoded as an octal
# digit. (integer value)
#filesystem_store_file_perm = 0
# The host where the S3 server is listening. (string value)
#s3_store_host = <None>
# The S3 query token access key. (string value)
#s3_store_access_key = <None>
# The S3 query token secret key. (string value)
#s3_store_secret_key = <None>
# The S3 bucket to be used to store the Glance data. (string value)
#s3_store_bucket = <None>
# The local directory where uploads will be staged before they are
# transferred into S3. (string value)
#s3_store_object_buffer_dir = <None>
# A boolean to determine if the S3 bucket should be created on upload
# if it does not exist or if an error should be returned to the user.
# (boolean value)
#s3_store_create_bucket_on_put = false
# The S3 calling format used to determine the bucket. Either subdomain
# or path can be used. (string value)
#s3_store_bucket_url_format = subdomain
# What size, in MB, should S3 start chunking image files and do a
# multipart upload in S3. (integer value)
#s3_store_large_object_size = 100
# What multipart upload part size, in MB, should S3 use when uploading
# parts. The size must be greater than or equal to 5M. (integer value)
#s3_store_large_object_chunk_size = 10
# The number of thread pools to perform a multipart upload in S3.
# (integer value)
#s3_store_thread_pools = 10
# Enable the use of a proxy. (boolean value)
#s3_store_enable_proxy = false
# Address or hostname for the proxy server. (string value)
#s3_store_proxy_host = <None>
# The port to use when connecting over a proxy. (integer value)
#s3_store_proxy_port = 8080
# The username to connect to the proxy. (string value)
#s3_store_proxy_user = <None>
# The password to use when connecting over a proxy. (string value)
#s3_store_proxy_password = <None>
[keystone_authtoken]
#
# From keystonemiddleware.auth_token
#
# Complete public Identity API endpoint. (string value)
#auth_uri = <None>
# API version of the admin Identity API endpoint. (string value)
#auth_version = <None>
# Do not handle authorization requests within the middleware, but
# delegate the authorization decision to downstream WSGI components.
# (boolean value)
#delay_auth_decision = false
# Request timeout value for communicating with Identity API server.
# (integer value)
#http_connect_timeout = <None>
# How many times are we trying to reconnect when communicating with
# Identity API Server. (integer value)
#http_request_max_retries = 3
# Env key for the swift cache. (string value)
#cache = <None>
# Required if identity server requires client certificate (string
# value)
#certfile = <None>
# Required if identity server requires client certificate (string
# value)
#keyfile = <None>
# A PEM encoded Certificate Authority to use when verifying HTTPs
# connections. Defaults to system CAs. (string value)
#cafile = <None>
# Verify HTTPS connections. (boolean value)
#insecure = false
# The region in which the identity server can be found. (string value)
#region_name = <None>
# Directory used to cache files related to PKI tokens. (string value)
#signing_dir = <None>
# Optionally specify a list of memcached server(s) to use for caching.
# If left undefined, tokens will instead be cached in-process. (list
# value)
# Deprecated group/name - [DEFAULT]/memcache_servers
#memcached_servers = <None>
# In order to prevent excessive effort spent validating tokens, the
# middleware caches previously-seen tokens for a configurable duration
# (in seconds). Set to -1 to disable caching completely. (integer
# value)
#token_cache_time = 300
# Determines the frequency at which the list of revoked tokens is
# retrieved from the Identity service (in seconds). A high number of
# revocation events combined with a low cache duration may
# significantly reduce performance. (integer value)
#revocation_cache_time = 10
# (Optional) If defined, indicate whether token data should be
# authenticated or authenticated and encrypted. Acceptable values are
# MAC or ENCRYPT. If MAC, token data is authenticated (with HMAC) in
# the cache. If ENCRYPT, token data is encrypted and authenticated in
# the cache. If the value is not one of these options or empty,
# auth_token will raise an exception on initialization. (string value)
#memcache_security_strategy = <None>
# (Optional, mandatory if memcache_security_strategy is defined) This
# string is used for key derivation. (string value)
#memcache_secret_key = <None>
# (Optional) Number of seconds memcached server is considered dead
# before it is tried again. (integer value)
#memcache_pool_dead_retry = 300
# (Optional) Maximum total number of open connections to every
# memcached server. (integer value)
#memcache_pool_maxsize = 10
# (Optional) Socket timeout in seconds for communicating with a
# memcached server. (integer value)
#memcache_pool_socket_timeout = 3
# (Optional) Number of seconds a connection to memcached is held
# unused in the pool before it is closed. (integer value)
#memcache_pool_unused_timeout = 60
# (Optional) Number of seconds that an operation will wait to get a
# memcached client connection from the pool. (integer value)
#memcache_pool_conn_get_timeout = 10
# (Optional) Use the advanced (eventlet safe) memcached client pool.
# The advanced pool will only work under python 2.x. (boolean value)
#memcache_use_advanced_pool = false
# (Optional) Indicate whether to set the X-Service-Catalog header. If
# False, middleware will not ask for service catalog on token
# validation and will not set the X-Service-Catalog header. (boolean
# value)
#include_service_catalog = true
# Used to control the use and type of token binding. Can be set to:
# "disabled" to not check token binding. "permissive" (default) to
# validate binding information if the bind type is of a form known to
# the server and ignore it if not. "strict" like "permissive" but if
# the bind type is unknown the token will be rejected. "required" any
# form of token binding is needed to be allowed. Finally the name of a
# binding method that must be present in tokens. (string value)
#enforce_token_bind = permissive
# If true, the revocation list will be checked for cached tokens. This
# requires that PKI tokens are configured on the identity server.
# (boolean value)
#check_revocations_for_cached = false
# Hash algorithms to use for hashing PKI tokens. This may be a single
# algorithm or multiple. The algorithms are those supported by Python
# standard hashlib.new(). The hashes will be tried in the order given,
# so put the preferred one first for performance. The result of the
# first hash will be stored in the cache. This will typically be set
# to multiple values only while migrating from a less secure algorithm
# to a more secure one. Once all the old tokens are expired this
# option should be set to a single value for better performance. (list
# value)
#hash_algorithms = md5
# Prefix to prepend at the beginning of the path. Deprecated, use
# identity_uri. (string value)
#auth_admin_prefix =
# Host providing the admin Identity API endpoint. Deprecated, use
# identity_uri. (string value)
#auth_host = 127.0.0.1
# Port of the admin Identity API endpoint. Deprecated, use
# identity_uri. (integer value)
#auth_port = 35357
# Protocol of the admin Identity API endpoint (http or https).
# Deprecated, use identity_uri. (string value)
#auth_protocol = https
# Complete admin Identity API endpoint. This should specify the
# unversioned root endpoint e.g. https://localhost:35357/ (string
# value)
#identity_uri = <None>
# This option is deprecated and may be removed in a future release.
# Single shared secret with the Keystone configuration used for
# bootstrapping a Keystone installation, or otherwise bypassing the
# normal authentication process. This option should not be used, use
# `admin_user` and `admin_password` instead. (string value)
#admin_token = <None>
# Service username. (string value)
#admin_user = <None>
# Service user password. (string value)
#admin_password = <None>
# Service tenant name. (string value)
#admin_tenant_name = admin
# Authentication type to load (unknown value)
# Deprecated group/name - [DEFAULT]/auth_plugin
#auth_type = <None>
# Config Section from which to load plugin specific options (unknown
# value)
#auth_section = <None>
[paste_deploy]
#
# From glance.glare
#
# Partial name of a pipeline in your paste configuration file with the
# service name removed. For example, if your paste section name is
# [pipeline:glance-api-keystone] use the value "keystone" (string
# value)
#flavor = <None>
# Name of the paste configuration file. (string value)
#config_file = <None>

View File

@ -88,9 +88,6 @@
# Deploy the v2 OpenStack Images API. (boolean value)
#enable_v2_api = true
# Deploy the v3 OpenStack Objects API. (boolean value)
#enable_v3_api = false
# Deploy the v1 OpenStack Registry API. (boolean value)
#enable_v1_registry = true

View File

@ -71,9 +71,6 @@
# Deploy the v2 OpenStack Images API. (boolean value)
#enable_v2_api = true
# Deploy the v3 OpenStack Objects API. (boolean value)
#enable_v3_api = false
# Deploy the v1 OpenStack Registry API. (boolean value)
#enable_v1_registry = true

View File

@ -0,0 +1,9 @@
[DEFAULT]
output_file = etc/glance-glare.conf.sample
namespace = glance.glare
namespace = glance.store
namespace = oslo.db
namespace = oslo.db.concurrency
namespace = keystonemiddleware.auth_token
namespace = oslo.log
namespace = oslo.middleware.cors

View File

@ -24,6 +24,4 @@ def root_app_factory(loader, global_conf, **local_conf):
del local_conf['/v1']
if not CONF.enable_v2_api and '/v2' in local_conf:
del local_conf['/v2']
if not CONF.enable_v3_api and '/v3' in local_conf:
del local_conf['/v3']
return paste.urlmap.urlmap_factory(loader, global_conf, **local_conf)

View File

@ -26,15 +26,15 @@ import six
import six.moves.urllib.parse as urlparse
import webob.exc
from glance.artifacts import gateway
from glance.artifacts import Showlevel
from glance.common.artifacts import loader
from glance.common.artifacts import serialization
from glance.common import exception
from glance.common.glare import loader
from glance.common.glare import serialization
from glance.common import jsonpatchvalidator
from glance.common import utils
from glance.common import wsgi
import glance.db
from glance.glare import gateway
from glance.glare import Showlevel
from glance.i18n import _, _LE
from oslo_log import log as logging
@ -455,7 +455,8 @@ class ArtifactsController(object):
def list_artifact_types(self, req):
plugins = self.plugins.plugin_map
response = []
base_link = "%s/v3/artifacts" % (CONF.public_endpoint or req.host_url)
base_link = "%s/v0.1/artifacts" % (CONF.public_endpoint or
req.host_url)
for type_name, plugin in six.iteritems(plugins.get("by_typename")):
@ -830,7 +831,7 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer,
class ResponseSerializer(wsgi.JSONResponseSerializer):
# TODO(ivasilevskaya): ideally this should be autogenerated/loaded
ARTIFACTS_ENDPOINT = '/v3/artifacts'
ARTIFACTS_ENDPOINT = '/v0.1/artifacts'
fields = ['id', 'name', 'version', 'type_name', 'type_version',
'visibility', 'state', 'owner', 'scope', 'created_at',
'updated_at', 'tags', 'dependencies', 'blobs', 'properties']
@ -869,7 +870,7 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
artifacts_list = [
serialization.serialize_for_client(a, show_level=Showlevel.NONE)
for a in res['artifacts']]
url = "/v3/artifacts"
url = "/v0.1/artifacts"
if type_name:
url += "/" + type_name
if type_version:

View File

@ -0,0 +1,98 @@
# Copyright (c) 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from glance.api.glare.v0_1 import glare
from glance.common import wsgi
UUID_REGEX = (
R'[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}')
class API(wsgi.Router):
def _get_artifacts_resource(self):
if not self.artifacts_resource:
self.artifacts_resource = glare.create_resource()
return self.artifacts_resource
def __init__(self, mapper):
self.artifacts_resource = None
artifacts_resource = self._get_artifacts_resource()
reject_method_resource = wsgi.Resource(wsgi.RejectMethodController())
def _check_json_content_type(environ, result):
return "application/json" in environ["CONTENT_TYPE"]
def _check_octet_stream_content_type(environ, result):
return "application/octet-stream" in environ["CONTENT_TYPE"]
def connect_routes(m, read_only):
with m.submapper(resource_name="artifact_operations",
path_prefix="/{id}",
requirements={'id': UUID_REGEX}) as art:
art.show()
if not read_only:
art.delete()
art.action('update', method='PATCH')
art.link('publish', method='POST')
def connect_attr_action(attr):
if not read_only:
attr.action("upload", conditions={
'method': ["POST", "PUT"],
'function': _check_octet_stream_content_type})
attr.action("update_property",
conditions={
'method': ["POST", "PUT"],
'function': _check_json_content_type})
attr.link("download", method="GET")
attr_map = art.submapper(resource_name="attr_operations",
path_prefix="/{attr}", path_left=None)
attr_items = art.submapper(
resource_name="attr_item_ops",
path_prefix="/{attr}/{path_left:.*}")
connect_attr_action(attr_map)
connect_attr_action(attr_items)
m.connect("", action='list', conditions={'method': 'GET'},
state='active')
m.connect("/drafts", action='list', conditions={'method': 'GET'},
state='creating')
if not read_only:
m.connect("/drafts", action='create',
conditions={'method': 'POST'})
mapper.connect('/artifacts',
controller=artifacts_resource,
action='list_artifact_types',
conditions={'method': ['GET']})
versioned = mapper.submapper(path_prefix='/artifacts/{type_name}/'
'v{type_version}',
controller=artifacts_resource)
non_versioned = mapper.submapper(path_prefix='/artifacts/{type_name}',
type_version=None,
controller=artifacts_resource)
connect_routes(versioned, False)
connect_routes(non_versioned, True)
mapper.connect('/artifacts',
controller=reject_method_resource,
action='reject',
allowed_methods='GET')
super(API, self).__init__(mapper)

View File

@ -0,0 +1,76 @@
# Copyright 2012 OpenStack Foundation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_serialization import jsonutils
import six
from six.moves import http_client
import webob.dec
from glance.common import wsgi
from glance import i18n
_ = i18n._
versions_opts = [
cfg.StrOpt('public_endpoint',
help=_('Public url to use for versions endpoint. The default '
'is None, which will use the request\'s host_url '
'attribute to populate the URL base. If Glance is '
'operating behind a proxy, you will want to change '
'this to represent the proxy\'s URL.')),
]
CONF = cfg.CONF
CONF.register_opts(versions_opts)
class Controller(object):
"""A wsgi controller that reports which API versions are supported."""
def index(self, req, explicit=False):
"""Respond to a request for all OpenStack API versions."""
def build_version_object(version, path, status):
url = CONF.public_endpoint or req.host_url
return {
'id': 'v%s' % version,
'status': status,
'links': [
{
'rel': 'self',
'href': '%s/%s/' % (url, path),
},
],
}
version_objs = [build_version_object(0.1, 'v0.1', 'EXPERIMENTAL')]
status = explicit and http_client.OK or http_client.MULTIPLE_CHOICES
response = webob.Response(request=req,
status=status,
content_type='application/json')
json = jsonutils.dumps(dict(versions=version_objs))
if six.PY3:
json = json.encode('utf-8')
response.body = json
return response
@webob.dec.wsgify(RequestClass=wsgi.Request)
def __call__(self, req):
return self.index(req)
def create_resource(conf):
return wsgi.Resource(Controller())

View File

@ -22,6 +22,7 @@ return
from oslo_config import cfg
from oslo_log import log as logging
from glance.api.glare import versions as artifacts_versions
from glance.api import versions
from glance.common import wsgi
@ -34,6 +35,8 @@ class VersionNegotiationFilter(wsgi.Middleware):
def __init__(self, app):
self.versions_app = versions.Controller()
self.allowed_versions = None
self.vnd_mime_type = 'application/vnd.openstack.images-'
super(VersionNegotiationFilter, self).__init__(app)
def process_request(self, req):
@ -47,9 +50,9 @@ class VersionNegotiationFilter(wsgi.Middleware):
return self.versions_app.index(req, explicit=True)
accept = str(req.accept)
if accept.startswith('application/vnd.openstack.images-'):
if accept.startswith(self.vnd_mime_type):
LOG.debug("Using media-type versioning")
token_loc = len('application/vnd.openstack.images-')
token_loc = len(self.vnd_mime_type)
req_version = accept[token_loc:]
else:
LOG.debug("Using url versioning")
@ -68,6 +71,22 @@ class VersionNegotiationFilter(wsgi.Middleware):
LOG.debug('new path %s', req.path_info)
return None
def _get_allowed_versions(self):
allowed_versions = {}
if CONF.enable_v1_api:
allowed_versions['v1'] = 1
allowed_versions['v1.0'] = 1
allowed_versions['v1.1'] = 1
if CONF.enable_v2_api:
allowed_versions['v2'] = 2
allowed_versions['v2.0'] = 2
allowed_versions['v2.1'] = 2
allowed_versions['v2.2'] = 2
if CONF.enable_v3_api:
allowed_versions['v3'] = 3
allowed_versions['v3.0'] = 3
return allowed_versions
def _match_version_string(self, subject):
"""
Given a string, tries to match a major and/or
@ -77,17 +96,13 @@ class VersionNegotiationFilter(wsgi.Middleware):
:returns: version found in the subject
:raises: ValueError if no acceptable version could be found
"""
if subject in ('v1', 'v1.0', 'v1.1') and CONF.enable_v1_api:
major_version = 1
elif subject in ('v2', 'v2.0', 'v2.1', 'v2.2') and CONF.enable_v2_api:
major_version = 2
elif subject in ('v3', 'v3.0') and CONF.enable_v3_api:
major_version = 3
if self.allowed_versions is None:
self.allowed_versions = self._get_allowed_versions()
if subject in self.allowed_versions:
return self.allowed_versions[subject]
else:
raise ValueError()
return major_version
def _pop_path_info(self, req):
"""
'Pops' off the next segment of PATH_INFO, returns the popped
@ -104,3 +119,15 @@ class VersionNegotiationFilter(wsgi.Middleware):
r = path[:idx]
req.path_info = path[idx:]
return r
class GlareVersionNegotiationFilter(VersionNegotiationFilter):
def __init__(self, app):
super(GlareVersionNegotiationFilter, self).__init__(app)
self.versions_app = artifacts_versions.Controller()
self.vnd_mime_type = 'application/vnd.openstack.artifacts-'
def _get_allowed_versions(self):
return {
'v0.1': 0.1
}

View File

@ -12,87 +12,68 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.api.v3 import artifacts
from oslo_config import cfg
from oslo_log import log as logging
from oslo_log import versionutils
from glance.common import wsgi
from glance.i18n import _LW
CONF = cfg.CONF
UUID_REGEX = (
R'[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}')
LOG = logging.getLogger(__name__)
"""v3 controller stub
Since Glance Artifact Service was released in Liberty as experimental Glance v3
API, its router was referenced in paste configuration as glance.api.v3.router
In Mitaka the Artifacts Service was moved into a standalone process and its
router was renamed to glance.api.artifacts.router.
However, in existing deployments the glance-api-paste.ini may still reference
the glance.api.v3.router. To not break these deployments this stub is included
to redirect the v3 request to glare service (if it is present) or return a 410
otherwise.
This stub controller should be removed in future releases.
"""
class API(wsgi.Router):
def _get_artifacts_resource(self):
if not self.artifacts_resource:
self.artifacts_resource = artifacts.create_resource()
return self.artifacts_resource
def __init__(self, mapper):
self.artifacts_resource = None
artifacts_resource = self._get_artifacts_resource()
reject_method_resource = wsgi.Resource(wsgi.RejectMethodController())
def _check_json_content_type(environ, result):
return "application/json" in environ["CONTENT_TYPE"]
def _check_octet_stream_content_type(environ, result):
return "application/octet-stream" in environ["CONTENT_TYPE"]
def connect_routes(m, read_only):
with m.submapper(resource_name="artifact_operations",
path_prefix="/{id}",
requirements={'id': UUID_REGEX}) as art:
art.show()
if not read_only:
art.delete()
art.action('update', method='PATCH')
art.link('publish', method='POST')
def connect_attr_action(attr):
if not read_only:
attr.action("upload", conditions={
'method': ["POST", "PUT"],
'function': _check_octet_stream_content_type})
attr.action("update_property",
conditions={
'method': ["POST", "PUT"],
'function': _check_json_content_type})
attr.link("download", method="GET")
attr_map = art.submapper(resource_name="attr_operations",
path_prefix="/{attr}", path_left=None)
attr_items = art.submapper(
resource_name="attr_item_ops",
path_prefix="/{attr}/{path_left:.*}")
connect_attr_action(attr_map)
connect_attr_action(attr_items)
m.connect("", action='list', conditions={'method': 'GET'},
state='active')
m.connect("/drafts", action='list', conditions={'method': 'GET'},
state='creating')
if not read_only:
m.connect("/drafts", action='create',
conditions={'method': 'POST'})
mapper.connect('/artifacts',
controller=artifacts_resource,
action='list_artifact_types',
conditions={'method': ['GET']})
versioned = mapper.submapper(path_prefix='/artifacts/{type_name}/'
'v{type_version}',
controller=artifacts_resource)
non_versioned = mapper.submapper(path_prefix='/artifacts/{type_name}',
type_version=None,
controller=artifacts_resource)
connect_routes(versioned, False)
connect_routes(non_versioned, True)
mapper.connect('/artifacts',
controller=reject_method_resource,
action='reject',
allowed_methods='GET')
versionutils.report_deprecated_feature(
LOG,
_LW('/v3 controller is deprecated and will be removed from '
'glance-api soon. Remove the reference to it from '
'glance-api-paste.ini configuration file and use Glance '
'Artifact Service API instead'))
redirector = self._get_redirector()
mapper.connect(None, "/artifacts",
controller=redirector, action='redirect')
mapper.connect(None, "/artifacts/{path:.*}",
controller=redirector, action='redirect')
super(API, self).__init__(mapper)
def _get_redirector(self):
return wsgi.Resource(RedirectController(),
serializer=RedirectResponseSerializer())
class RedirectController(object):
def redirect(self, req, path=None):
try:
glare_endpoint = next((s['endpoints']
for s in req.context.service_catalog
if s['type'] == 'artifact'))[0]['publicURL']
if path:
path = '/' + path
return '{0}/v0.1/artifacts{1}'.format(glare_endpoint, path or "")
except StopIteration:
return None
class RedirectResponseSerializer(wsgi.JSONResponseSerializer):
def default(self, response, res):
if res:
response.location = res
response.status_int = 301
else:
response.status_int = 410

View File

@ -56,9 +56,6 @@ class Controller(object):
}
version_objs = []
if CONF.enable_v3_api:
version_objs.append(
build_version_object(3.0, 'v3', 'EXPERIMENTAL'))
if CONF.enable_v2_api:
version_objs.extend([
build_version_object(2.3, 'v2', 'CURRENT'),

87
glance/cmd/glare.py Executable file
View File

@ -0,0 +1,87 @@
#!/usr/bin/env python
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Glare (Glance Artifact Repository) API service
"""
import sys
import eventlet
from oslo_utils import encodeutils
eventlet.patcher.monkey_patch(all=False, socket=True, time=True,
select=True, thread=True, os=True)
import glance_store
from oslo_config import cfg
from oslo_log import log as logging
import oslo_messaging
import osprofiler.notifier
import osprofiler.web
from glance.common import config
from glance.common import exception
from glance.common import wsgi
from glance import notifier
CONF = cfg.CONF
CONF.import_group("profiler", "glance.common.wsgi")
logging.register_options(CONF)
KNOWN_EXCEPTIONS = (RuntimeError,
exception.WorkerCreationFailure,
glance_store.exceptions.BadStoreConfiguration)
def fail(e):
global KNOWN_EXCEPTIONS
return_code = KNOWN_EXCEPTIONS.index(type(e)) + 1
sys.stderr.write("ERROR: %s\n" % encodeutils.exception_to_unicode(e))
sys.exit(return_code)
def main():
try:
config.parse_args()
wsgi.set_eventlet_hub()
logging.setup(CONF, 'glare')
if cfg.CONF.profiler.enabled:
_notifier = osprofiler.notifier.create("Messaging",
oslo_messaging, {},
notifier.get_transport(),
"glance", "artifacts",
cfg.CONF.bind_host)
osprofiler.notifier.set(_notifier)
else:
osprofiler.web.disable()
server = wsgi.Server(initialize_glance_store=True)
server.start(config.load_paste_app('glare-api'), default_port=9494)
server.wait()
except KNOWN_EXCEPTIONS as e:
fail(e)
if __name__ == '__main__':
main()

View File

@ -149,7 +149,8 @@ common_opts = [
cfg.BoolOpt('enable_v2_api', default=True,
help=_("Deploy the v2 OpenStack Images API.")),
cfg.BoolOpt('enable_v3_api', default=False,
help=_("Deploy the v3 OpenStack Objects API.")),
help=_("Deploy the v3 OpenStack Objects API."),
deprecated_for_removal=True),
cfg.BoolOpt('enable_v1_registry', default=True,
help=_("Deploy the v1 OpenStack Registry API.")),
cfg.BoolOpt('enable_v2_registry', default=True,

View File

View File

@ -19,8 +19,8 @@ import re
import semantic_version
import six
from glance.common.artifacts import declarative
import glance.common.exception as exc
from glance.common.glare import declarative
from glance.i18n import _

View File

@ -19,8 +19,8 @@ from oslo_config import cfg
import semantic_version
from stevedore import enabled
from glance.common.artifacts import definitions
from glance.common import exception
from glance.common.glare import definitions
from glance.i18n import _, _LE, _LI, _LW
from oslo_log import log as logging

View File

@ -16,10 +16,10 @@ import collections
import six
from glance import artifacts as ga
from glance.common.artifacts import declarative
from glance.common.artifacts import definitions
from glance.common import exception
from glance.common.glare import declarative
from glance.common.glare import definitions
from glance import glare as ga
from glance.i18n import _

View File

@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.common.artifacts import definitions
from glance.common.glare import definitions
class BaseArtifact(definitions.ArtifactType):

View File

@ -14,7 +14,7 @@
# under the License.
from glance.common.artifacts import definitions
from glance.common.glare import definitions
from glance.contrib.plugins.artifacts_sample import base

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.common.artifacts import definitions
from glance.common.glare import definitions
class ImageAsAnArtifact(definitions.ArtifactType):

View File

@ -13,7 +13,7 @@
# under the License.
from glance.common.artifacts import definitions
from glance.common.glare import definitions
import glance.contrib.plugins.image_artifact.v1.image as v1

View File

@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.common.artifacts import definitions
from glance.common import exception
from glance.common.glare import definitions
import glance.contrib.plugins.image_artifact.v1_1.image as v1_1
import glanceclient

View File

@ -22,13 +22,13 @@ from oslo_utils import importutils
from wsme.rest import json
from glance.api.v2.model.metadef_property_type import PropertyType
from glance import artifacts as ga
from glance.common.artifacts import serialization
from glance.common import crypt
from glance.common import exception
from glance.common.glare import serialization
from glance.common import location_strategy
import glance.domain
import glance.domain.proxy
from glance import glare as ga
from glance.i18n import _
CONF = cfg.CONF

View File

@ -31,7 +31,7 @@ database back-end.
import functools
from glance import artifacts
from glance import glare
from glance.registry.client.v2 import api
@ -600,7 +600,7 @@ def artifact_get(client, artifact_id,
@_get_client
def artifact_get_all(client, marker=None, limit=None, sort_key=None,
sort_dir=None, filters=None,
show_level=artifacts.Showlevel.NONE, session=None):
show_level=glare.Showlevel.NONE, session=None):
if filters is None:
filters = {}
return client.artifact_create(marker, limit, sort_key,

View File

@ -38,11 +38,10 @@ from sqlalchemy import MetaData, Table, select
import sqlalchemy.orm as sa_orm
import sqlalchemy.sql as sa_sql
from glance import artifacts as ga
from glance.common import exception
from glance.common import timeutils
from glance.common import utils
from glance.db.sqlalchemy import artifacts
from glance.db.sqlalchemy import glare
from glance.db.sqlalchemy.metadef_api import (resource_type
as metadef_resource_type_api)
from glance.db.sqlalchemy.metadef_api import (resource_type_association
@ -52,6 +51,7 @@ from glance.db.sqlalchemy.metadef_api import object as metadef_object_api
from glance.db.sqlalchemy.metadef_api import property as metadef_property_api
from glance.db.sqlalchemy.metadef_api import tag as metadef_tag_api
from glance.db.sqlalchemy import models
from glance import glare as ga
from glance.i18n import _, _LW, _LE, _LI
BASE = models.BASE
@ -1816,24 +1816,24 @@ def metadef_tag_count(context, namespace_name, session=None):
def artifact_create(context, values, type_name,
type_version=None, session=None):
session = session or get_session()
artifact = artifacts.create(context, values, session, type_name,
type_version)
artifact = glare.create(context, values, session, type_name,
type_version)
return artifact
def artifact_delete(context, artifact_id, type_name,
type_version=None, session=None):
session = session or get_session()
artifact = artifacts.delete(context, artifact_id, session, type_name,
type_version)
artifact = glare.delete(context, artifact_id, session, type_name,
type_version)
return artifact
def artifact_update(context, values, artifact_id, type_name,
type_version=None, session=None):
session = session or get_session()
artifact = artifacts.update(context, values, artifact_id, session,
type_name, type_version)
artifact = glare.update(context, values, artifact_id, session,
type_name, type_version)
return artifact
@ -1843,8 +1843,8 @@ def artifact_get(context, artifact_id,
show_level=ga.Showlevel.BASIC,
session=None):
session = session or get_session()
return artifacts.get(context, artifact_id, session, type_name,
type_version, show_level)
return glare.get(context, artifact_id, session, type_name,
type_version, show_level)
def artifact_publish(context,
@ -1853,16 +1853,16 @@ def artifact_publish(context,
type_version=None,
session=None):
session = session or get_session()
return artifacts.publish(context,
artifact_id,
session,
type_name,
type_version)
return glare.publish(context,
artifact_id,
session,
type_name,
type_version)
def artifact_get_all(context, marker=None, limit=None, sort_keys=None,
sort_dirs=None, filters=None,
show_level=ga.Showlevel.NONE, session=None):
session = session or get_session()
return artifacts.get_all(context, session, marker, limit, sort_keys,
sort_dirs, filters, show_level)
return glare.get_all(context, session, marker, limit, sort_keys,
sort_dirs, filters, show_level)

View File

@ -26,11 +26,11 @@ from sqlalchemy import or_
import sqlalchemy.orm as orm
from sqlalchemy.orm import joinedload
import glance.artifacts as ga
from glance.common import exception
from glance.common import semver_db
from glance.common import timeutils
from glance.db.sqlalchemy import models_artifacts as models
from glance.db.sqlalchemy import models_glare as models
import glance.glare as ga
from glance.i18n import _LE, _LW
from oslo_log import log as os_logging

View File

@ -30,9 +30,9 @@ from sqlalchemy.orm import relationship
from sqlalchemy import String
from sqlalchemy import Text
import glance.artifacts as ga
from glance.common import semver_db
from glance.common import timeutils
import glance.glare as ga
BASE = declarative.declarative_base()

View File

@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.artifacts.domain import proxy
import glance.common.artifacts.definitions as definitions
import glance.common.exception as exc
import glance.common.glare.definitions as definitions
from glance.glare.domain import proxy
from glance.i18n import _

View File

@ -13,12 +13,12 @@
# under the License.
import glance_store
from glance.artifacts import dependency
from glance.artifacts import domain
from glance.artifacts import location
from glance.artifacts import updater
from glance.common import store_utils
import glance.db
from glance.glare import dependency
from glance.glare import domain
from glance.glare import location
from glance.glare import updater
class Gateway(object):

View File

@ -19,9 +19,9 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import encodeutils
from glance.artifacts.domain import proxy
from glance.common.artifacts import definitions
from glance.common.glare import definitions
from glance.common import utils
from glance.glare.domain import proxy
from glance.i18n import _, _LE, _LW
CONF = cfg.CONF

View File

@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
from glance.artifacts.domain import proxy
from glance.common import exception as exc
from glance.glare.domain import proxy
from glance.i18n import _

View File

@ -17,7 +17,8 @@ __all__ = [
'list_registry_opts',
'list_scrubber_opts',
'list_cache_opts',
'list_manage_opts'
'list_manage_opts',
'list_artifacts_opts'
]
import copy
@ -99,6 +100,17 @@ _cache_opts = [
_manage_opts = [
(None, [])
]
_artifacts_opts = [
(None, list(itertools.chain(
glance.api.middleware.context.context_opts,
glance.api.versions.versions_opts,
glance.common.wsgi.bind_opts,
glance.common.wsgi.eventlet_opts,
glance.common.wsgi.socket_opts,
glance.common.wsgi.profiler_opts,
glance.notifier.notifier_opts))),
('paste_deploy', glance.common.config.paste_deploy_opts)
]
def list_api_opts():
@ -145,3 +157,8 @@ def list_cache_opts():
def list_manage_opts():
"""Return a list of oslo_config options available in Glance manage."""
return [(g, copy.deepcopy(o)) for g, o in _manage_opts]
def list_artifacts_opts():
"""Return a list of oslo_config options available in Glance artifacts"""
return [(g, copy.deepcopy(o)) for g, o in _artifacts_opts]

View File

@ -77,7 +77,6 @@ class Server(object):
self.property_protection_file = ''
self.enable_v1_api = True
self.enable_v2_api = True
self.enable_v3_api = True
self.enable_v1_registry = True
self.enable_v2_registry = True
self.needs_database = False
@ -348,7 +347,6 @@ show_multiple_locations = %(show_multiple_locations)s
user_storage_quota = %(user_storage_quota)s
enable_v1_api = %(enable_v1_api)s
enable_v2_api = %(enable_v2_api)s
enable_v3_api = %(enable_v3_api)s
lock_path = %(lock_path)s
property_protection_file = %(property_protection_file)s
property_protection_rule_format = %(property_protection_rule_format)s
@ -404,7 +402,6 @@ paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app
/v3: apiv3app
[app:apiversions]
paste.app_factory = glance.api.versions:create_resource
@ -415,9 +412,6 @@ paste.app_factory = glance.api.v1.router:API.factory
[app:apiv2app]
paste.app_factory = glance.api.v2.router:API.factory
[app:apiv3app]
paste.app_factory = glance.api.v3.router:API.factory
[filter:healthcheck]
paste.filter_factory = oslo_middleware:Healthcheck.factory
backends = disable_by_file

View File

@ -17,9 +17,9 @@ import uuid
import six
from six.moves import range
import glance.artifacts as ga
from glance.common import exception as exc
from glance import context
import glance.glare as ga
import glance.tests.functional.db as db_tests
from glance.tests import utils as test_utils

View File

@ -20,11 +20,11 @@ from oslo_db import options
from glance.common import exception
import glance.db.sqlalchemy.api
from glance.db.sqlalchemy import models as db_models
from glance.db.sqlalchemy import models_artifacts as artifact_models
from glance.db.sqlalchemy import models_glare as artifact_models
from glance.db.sqlalchemy import models_metadef as metadef_models
import glance.tests.functional.db as db_tests
from glance.tests.functional.db import base
from glance.tests.functional.db import base_artifacts
from glance.tests.functional.db import base_glare
from glance.tests.functional.db import base_metadef
CONF = cfg.CONF
@ -169,8 +169,8 @@ class TestDBPurge(base.DBPurgeTests,
self.addCleanup(db_tests.reset)
class TestArtifacts(base_artifacts.ArtifactsTestDriver,
base_artifacts.ArtifactTests):
class TestArtifacts(base_glare.ArtifactsTestDriver,
base_glare.ArtifactTests):
def setUp(self):
db_tests.load(get_db, reset_db_artifacts)
super(TestArtifacts, self).setUp()

View File

@ -20,10 +20,10 @@ from oslo_serialization import jsonutils
import pkg_resources
import requests
from glance.api.v3 import artifacts
from glance.api.v3 import router
from glance.common.artifacts import definitions
from glance.common.artifacts import loader
from glance.api.glare.v0_1 import glare
from glance.api.glare.v0_1 import router
from glance.common.glare import definitions
from glance.common.glare import loader
from glance.common import wsgi
from glance.tests import functional
@ -62,7 +62,7 @@ def _create_resource():
plugins = None
mock_this = 'stevedore.extension.ExtensionManager._find_entry_points'
with mock.patch(mock_this) as fep:
path = 'glance.tests.functional.artifacts.test_artifacts'
path = 'glance.tests.functional.glare.test_glare'
fep.return_value = [
pkg_resources.EntryPoint.parse('WithProps=%s:Artifact' % path),
pkg_resources.EntryPoint.parse(
@ -73,9 +73,9 @@ def _create_resource():
'WithBlob=%s:ArtifactWithBlob' % path)
]
plugins = loader.ArtifactsPluginLoader('glance.artifacts.types')
deserializer = artifacts.RequestDeserializer(plugins=plugins)
serializer = artifacts.ResponseSerializer()
controller = artifacts.ArtifactsController(plugins=plugins)
deserializer = glare.RequestDeserializer(plugins=plugins)
serializer = glare.ResponseSerializer()
controller = glare.ArtifactsController(plugins=plugins)
return wsgi.Resource(controller, deserializer, serializer)
@ -110,6 +110,8 @@ class TestArtifacts(functional.FunctionalTest):
def setUp(self):
super(TestArtifacts, self).setUp()
self._set_user('user1')
self.api_server.server_name = 'glare'
self.api_server.server_module = 'glance.cmd.glare'
self.api_server.deployment_flavor = 'noauth'
self.start_servers(**self.__dict__.copy())
@ -119,7 +121,7 @@ class TestArtifacts(functional.FunctionalTest):
super(TestArtifacts, self).tearDown()
def _url(self, path):
return 'http://127.0.0.1:%d/v3/artifacts%s' % (self.api_port, path)
return 'http://127.0.0.1:%d/v0.1/artifacts%s' % (self.api_port, path)
def _set_user(self, username):
if username not in self.users:
@ -138,60 +140,32 @@ class TestArtifacts(functional.FunctionalTest):
return base_headers
def start_servers(self, **kwargs):
new_paste_conf_base = """[pipeline:glance-api]
pipeline = versionnegotiation gzip unauthenticated-context rootapp
# noqa
new_paste_conf_base = """[pipeline:glare-api]
pipeline = versionnegotiation unauthenticated-context rootapp
[pipeline:glance-api-caching]
pipeline = versionnegotiation gzip unauthenticated-context cache rootapp
[pipeline:glare-api-fakeauth]
pipeline = versionnegotiation fakeauth context rootapp
[pipeline:glance-api-cachemanagement]
pipeline =
versionnegotiation
gzip
unauthenticated-context
cache
cache_manage
rootapp
[pipeline:glance-api-fakeauth]
pipeline = versionnegotiation gzip fakeauth context rootapp
[pipeline:glance-api-noauth]
pipeline = versionnegotiation gzip context rootapp
[pipeline:glare-api-noauth]
pipeline = versionnegotiation context rootapp
[composite:rootapp]
paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app
/v3: apiv3app
/v0.1: glareapi
[app:apiversions]
paste.app_factory = glance.api.versions:create_resource
paste.app_factory = glance.api.glare.versions:create_resource
[app:apiv1app]
paste.app_factory = glance.api.v1.router:API.factory
[app:apiv2app]
paste.app_factory = glance.api.v2.router:API.factory
[app:apiv3app]
[app:glareapi]
paste.app_factory =
glance.tests.functional.artifacts.test_artifacts:TestRouter.factory
glance.tests.functional.glare.test_glare:TestRouter.factory
[filter:versionnegotiation]
paste.filter_factory =
glance.api.middleware.version_negotiation:VersionNegotiationFilter.factory
[filter:gzip]
paste.filter_factory = glance.api.middleware.gzip:GzipMiddleware.factory
[filter:cache]
paste.filter_factory = glance.api.middleware.cache:CacheFilter.factory
[filter:cache_manage]
paste.filter_factory =
glance.api.middleware.cache_manage:CacheManageFilter.factory
glance.api.middleware.version_negotiation:
GlareVersionNegotiationFilter.factory
[filter:context]
paste.filter_factory = glance.api.middleware.context:ContextMiddleware.factory
@ -1329,24 +1303,26 @@ paste.filter_factory = glance.tests.utils:FakeAuthMiddleware.factory
u'type_name': u'NoProp',
u'versions':
[{u'id': u'v0.5',
u'link': u'http://127.0.0.1:%d/v3/artifacts/noprop/v0.5'
u'link': u'http://127.0.0.1:%d/v0.1/'
u'artifacts/noprop/v0.5'
% self.api_port},
{u'id': u'v1.0',
u'link': u'http://127.0.0.1:%d/v3/artifacts/noprop/v1.0'
u'link': u'http://127.0.0.1:%d/v0.1/'
u'artifacts/noprop/v1.0'
% self.api_port}]},
{u'displayed_name': u'WithBlob',
u'type_name': u'WithBlob',
u'versions':
[{u'id': u'v1.0',
u'link':
u'http://127.0.0.1:%d/v3/artifacts/withblob/v1.0'
u'http://127.0.0.1:%d/v0.1/artifacts/withblob/v1.0'
% self.api_port}]},
{u'displayed_name': u'WithProps',
u'type_name': u'WithProps',
u'versions':
[{u'id': u'v1.0',
u'link':
u'http://127.0.0.1:%d/v3/artifacts/withprops/v1.0'
u'http://127.0.0.1:%d/v0.1/artifacts/withprops/v1.0'
% self.api_port}]}]}
response = self._check_artifact_get("", status=200)

View File

@ -31,11 +31,6 @@ class TestApiVersions(functional.FunctionalTest):
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
versions = {'versions': [
{
'status': 'EXPERIMENTAL',
'id': 'v3.0',
'links': [{'href': url % '3', "rel": "self"}],
},
{
'id': 'v2.3',
'status': 'CURRENT',
@ -83,11 +78,6 @@ class TestApiVersions(functional.FunctionalTest):
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
versions = {'versions': [
{
'status': 'EXPERIMENTAL',
'id': 'v3.0',
'links': [{'href': url % '3', "rel": "self"}],
},
{
'id': 'v2.3',
'status': 'CURRENT',
@ -121,7 +111,6 @@ class TestApiVersions(functional.FunctionalTest):
def test_v1_api_configuration(self):
self.api_server.enable_v1_api = True
self.api_server.enable_v2_api = False
self.api_server.enable_v3_api = False
self.start_servers(**self.__dict__.copy())
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
@ -154,11 +143,6 @@ class TestApiPaths(functional.FunctionalTest):
url = 'http://127.0.0.1:%d/v%%s/' % self.api_port
versions = {'versions': [
{
'status': 'EXPERIMENTAL',
'id': 'v3.0',
'links': [{'href': url % '3', "rel": "self"}],
},
{
'id': 'v2.3',
'status': 'CURRENT',

View File

@ -55,7 +55,6 @@ paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app
/v3: apiv3app
[app:apiversions]
paste.app_factory = glance.api.versions:create_resource
@ -66,9 +65,6 @@ paste.app_factory = glance.api.v1.router:API.factory
[app:apiv2app]
paste.app_factory = glance.api.v2.router:API.factory
[app:apiv3app]
paste.app_factory = glance.api.v3.router:API.factory
[filter:versionnegotiation]
paste.filter_factory =
glance.api.middleware.version_negotiation:VersionNegotiationFilter.factory

View File

@ -58,7 +58,6 @@ paste.composite_factory = glance.api:root_app_factory
/: apiversions
/v1: apiv1app
/v2: apiv2app
/v3: apiv3app
[app:apiversions]
paste.app_factory = glance.api.versions:create_resource
@ -69,9 +68,6 @@ paste.app_factory = glance.api.v1.router:API.factory
[app:apiv2app]
paste.app_factory = glance.api.v2.router:API.factory
[app:apiv3app]
paste.app_factory = glance.api.v3.router:API.factory
[filter:versionnegotiation]
paste.filter_factory =
glance.api.middleware.version_negotiation:VersionNegotiationFilter.factory

View File

@ -21,13 +21,13 @@ import mock
from oslo_config import cfg
import oslo_utils.importutils
from glance.artifacts import domain as artifacts_domain
import glance.async
from glance.async import taskflow_executor
from glance.common.artifacts import definitions
from glance.common import exception
from glance.common.glare import definitions
from glance.common import timeutils
from glance import domain
from glance.glare import domain as artifacts_domain
import glance.tests.utils as test_utils

View File

@ -17,8 +17,8 @@ import os
import mock
import pkg_resources
from glance.common.artifacts import loader
from glance.common import exception
from glance.common.glare import loader
from glance.contrib.plugins.artifacts_sample.v1 import artifact as art1
from glance.contrib.plugins.artifacts_sample.v2 import artifact as art2
from glance.tests import utils

View File

@ -17,10 +17,10 @@ import datetime
import mock
import six
from glance.common.artifacts import declarative
import glance.common.artifacts.definitions as defs
from glance.common.artifacts import serialization
import glance.common.exception as exc
from glance.common.glare import declarative
import glance.common.glare.definitions as defs
from glance.common.glare import serialization
import glance.tests.utils as test_utils

View File

@ -51,7 +51,7 @@ from glance.db import migration
from glance.db.sqlalchemy import migrate_repo
from glance.db.sqlalchemy.migrate_repo.schema import from_migration_import
from glance.db.sqlalchemy import models
from glance.db.sqlalchemy import models_artifacts
from glance.db.sqlalchemy import models_glare
from glance.db.sqlalchemy import models_metadef
from glance.i18n import _
@ -1878,7 +1878,7 @@ class ModelsMigrationSyncMixin(object):
def get_metadata(self):
for table in models_metadef.BASE_DICT.metadata.sorted_tables:
models.BASE.metadata._add_table(table.name, table.schema, table)
for table in models_artifacts.BASE.metadata.sorted_tables:
for table in models_glare.BASE.metadata.sorted_tables:
models.BASE.metadata._add_table(table.name, table.schema, table)
return models.BASE.metadata

View File

@ -13,10 +13,10 @@
# under the License.
from datetime import datetime
from glance.artifacts.domain import proxy
from glance.artifacts import location
from glance.common.artifacts import definitions
from glance.common.glare import definitions
import glance.context
from glance.glare.domain import proxy
from glance.glare import location
from glance.tests.unit import utils as unit_test_utils
from glance.tests import utils

View File

@ -170,16 +170,6 @@ class VersionNegotiationTest(base.IsolatedUnitTest):
self.middleware.process_request(request)
self.assertEqual('/v2/images', request.path_info)
def test_request_url_v3(self):
request = webob.Request.blank('/v3/artifacts')
resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller)
def test_request_url_v3_0(self):
request = webob.Request.blank('/v3.0/artifacts')
resp = self.middleware.process_request(request)
self.assertIsInstance(resp, versions.Controller)
def test_request_url_v2_3_unsupported(self):
request = webob.Request.blank('/v2.3/images')
resp = self.middleware.process_request(request)

View File

@ -34,6 +34,7 @@ console_scripts =
glance-registry = glance.cmd.registry:main
glance-replicator = glance.cmd.replicator:main
glance-scrubber = glance.cmd.scrubber:main
glance-glare = glance.cmd.glare:main
glance.common.image_location_strategy.modules =
location_order_strategy = glance.common.location_strategy.location_order
store_type_strategy = glance.common.location_strategy.store_type
@ -43,6 +44,7 @@ oslo.config.opts =
glance.scrubber = glance.opts:list_scrubber_opts
glance.cache= glance.opts:list_cache_opts
glance.manage = glance.opts:list_manage_opts
glance.glare = glance.opts:list_artifacts_opts
glance.database.migration_backend =
sqlalchemy = oslo_db.sqlalchemy.migration
glance.database.metadata_backend =

View File

@ -62,6 +62,7 @@ commands =
oslo-config-generator --config-file etc/oslo-config-generator/glance-scrubber.conf
oslo-config-generator --config-file etc/oslo-config-generator/glance-cache.conf
oslo-config-generator --config-file etc/oslo-config-generator/glance-manage.conf
oslo-config-generator --config-file etc/oslo-config-generator/glance-glare.conf
[testenv:docs]
commands = python setup.py build_sphinx