Add flaovr API

Change-Id: I467042648cb13e857e149c396af92552243c5d2a
This commit is contained in:
Zhenguo Niu 2016-08-18 11:09:20 +08:00
parent 04d7a6d618
commit b11452b68a
18 changed files with 1140 additions and 9 deletions

View File

@ -136,6 +136,132 @@
# value)
#fatal_deprecations = false
#
# From oslo.messaging
#
# Size of RPC connection pool. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_conn_pool_size
#rpc_conn_pool_size = 30
# The pool size limit for connections expiration policy
# (integer value)
#conn_pool_min_size = 2
# The time-to-live in sec of idle connections in the pool
# (integer value)
#conn_pool_ttl = 1200
# ZeroMQ bind address. Should be a wildcard (*), an ethernet
# interface, or IP. The "host" option should point or resolve
# to this address. (string value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_address
#rpc_zmq_bind_address = *
# MatchMaker driver. (string value)
# Allowed values: redis, dummy
# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
#rpc_zmq_matchmaker = redis
# Number of ZeroMQ contexts, defaults to 1. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_contexts
#rpc_zmq_contexts = 1
# Maximum number of ingress messages to locally buffer per
# topic. Default is unlimited. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_topic_backlog
#rpc_zmq_topic_backlog = <None>
# Directory for holding IPC sockets. (string value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_ipc_dir
#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)
# Deprecated group/name - [DEFAULT]/rpc_zmq_host
#rpc_zmq_host = localhost
# Seconds to wait before a cast expires (TTL). The default
# value of -1 specifies an infinite linger period. The value
# of 0 specifies no linger period. Pending messages shall be
# discarded immediately when the socket is closed. Only
# supported by impl_zmq. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_cast_timeout
#rpc_cast_timeout = -1
# The default number of seconds that poll should wait. Poll
# raises timeout exception when timeout expired. (integer
# value)
# Deprecated group/name - [DEFAULT]/rpc_poll_timeout
#rpc_poll_timeout = 1
# Expiration timeout in seconds of a name service record about
# existing target ( < 0 means no timeout). (integer value)
# Deprecated group/name - [DEFAULT]/zmq_target_expire
#zmq_target_expire = 300
# Update period in seconds of a name service record about
# existing target. (integer value)
# Deprecated group/name - [DEFAULT]/zmq_target_update
#zmq_target_update = 180
# Use PUB/SUB pattern for fanout methods. PUB/SUB always uses
# proxy. (boolean value)
# Deprecated group/name - [DEFAULT]/use_pub_sub
#use_pub_sub = true
# Use ROUTER remote proxy. (boolean value)
# Deprecated group/name - [DEFAULT]/use_router_proxy
#use_router_proxy = true
# Minimal port number for random ports range. (port value)
# Minimum value: 0
# Maximum value: 65535
# Deprecated group/name - [DEFAULT]/rpc_zmq_min_port
#rpc_zmq_min_port = 49153
# Maximal port number for random ports range. (integer value)
# Minimum value: 1
# Maximum value: 65536
# Deprecated group/name - [DEFAULT]/rpc_zmq_max_port
#rpc_zmq_max_port = 65536
# Number of retries to find free port number before fail with
# ZMQBindError. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_port_retries
#rpc_zmq_bind_port_retries = 100
# Default serialization mechanism for
# serializing/deserializing outgoing/incoming messages (string
# value)
# Allowed values: json, msgpack
# Deprecated group/name - [DEFAULT]/rpc_zmq_serialization
#rpc_zmq_serialization = json
# Size of executor thread pool. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_thread_pool_size
#executor_thread_pool_size = 64
# 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. (string value)
#transport_url = <None>
# DEPRECATED: The messaging driver to use, defaults to rabbit.
# Other drivers include amqp and zmq. (string value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#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
#
# From oslo.service.periodic_task
#
@ -406,6 +532,57 @@
#db_max_retries = 20
[matchmaker_redis]
#
# From oslo.messaging
#
# DEPRECATED: Host to locate redis. (string value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#host = 127.0.0.1
# DEPRECATED: Use this port to connect to redis host. (port
# value)
# Minimum value: 0
# Maximum value: 65535
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#port = 6379
# DEPRECATED: Password for Redis server (optional). (string
# value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#password =
# DEPRECATED: List of Redis Sentinel hosts (fault tolerance
# mode) e.g. [host:port, host1:port ... ] (list
# value)
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#sentinel_hosts =
# Redis replica set name. (string value)
#sentinel_group_name = oslo-messaging-zeromq
# Time in ms to wait between connection attempts. (integer
# value)
#wait_timeout = 5000
# Time in ms to wait before the transaction is killed.
# (integer value)
#check_timeout = 60000
# Timeout in ms on blocking socket operations (integer value)
#socket_timeout = 10000
[oslo_concurrency]
#
@ -425,6 +602,485 @@
#lock_path = <None>
[oslo_messaging_amqp]
#
# From oslo.messaging
#
# address prefix used when sending to a specific server
# (string value)
# Deprecated group/name - [amqp1]/server_request_prefix
#server_request_prefix = exclusive
# address prefix used when broadcasting to all servers (string
# value)
# Deprecated group/name - [amqp1]/broadcast_prefix
#broadcast_prefix = broadcast
# address prefix when sending to any server in group (string
# value)
# Deprecated group/name - [amqp1]/group_request_prefix
#group_request_prefix = unicast
# Name for the AMQP container (string value)
# Deprecated group/name - [amqp1]/container_name
#container_name = <None>
# Timeout for inactive connections (in seconds) (integer
# value)
# Deprecated group/name - [amqp1]/idle_timeout
#idle_timeout = 0
# Debug: dump AMQP frames to stdout (boolean value)
# Deprecated group/name - [amqp1]/trace
#trace = false
# CA certificate PEM file to verify server certificate (string
# value)
# Deprecated group/name - [amqp1]/ssl_ca_file
#ssl_ca_file =
# Identifying certificate PEM file to present to clients
# (string value)
# Deprecated group/name - [amqp1]/ssl_cert_file
#ssl_cert_file =
# Private key PEM file used to sign cert_file certificate
# (string value)
# Deprecated group/name - [amqp1]/ssl_key_file
#ssl_key_file =
# Password for decrypting ssl_key_file (if encrypted) (string
# value)
# Deprecated group/name - [amqp1]/ssl_key_password
#ssl_key_password = <None>
# Accept clients using either SSL or plain TCP (boolean value)
# Deprecated group/name - [amqp1]/allow_insecure_clients
#allow_insecure_clients = false
# Space separated list of acceptable SASL mechanisms (string
# value)
# Deprecated group/name - [amqp1]/sasl_mechanisms
#sasl_mechanisms =
# Path to directory that contains the SASL configuration
# (string value)
# Deprecated group/name - [amqp1]/sasl_config_dir
#sasl_config_dir =
# Name of configuration file (without .conf suffix) (string
# value)
# Deprecated group/name - [amqp1]/sasl_config_name
#sasl_config_name =
# User name for message broker authentication (string value)
# Deprecated group/name - [amqp1]/username
#username =
# Password for message broker authentication (string value)
# Deprecated group/name - [amqp1]/password
#password =
[oslo_messaging_notifications]
#
# From oslo.messaging
#
# The Drivers(s) to handle sending notifications. Possible
# values are messaging, messagingv2, routing, log, test, noop
# (multi valued)
# Deprecated group/name - [DEFAULT]/notification_driver
#driver =
# A URL representing the messaging driver to use for
# notifications. If not set, we fall back to the same
# configuration used for RPC. (string value)
# Deprecated group/name - [DEFAULT]/notification_transport_url
#transport_url = <None>
# AMQP topic used for OpenStack notifications. (list value)
# Deprecated group/name - [rpc_notifier2]/topics
# Deprecated group/name - [DEFAULT]/notification_topics
#topics = notifications
[oslo_messaging_rabbit]
#
# From oslo.messaging
#
# Use durable queues in AMQP. (boolean value)
# Deprecated group/name - [DEFAULT]/amqp_durable_queues
# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
#amqp_durable_queues = false
# Auto-delete queues in AMQP. (boolean value)
# Deprecated group/name - [DEFAULT]/amqp_auto_delete
#amqp_auto_delete = false
# SSL version to use (valid only if SSL enabled). Valid values
# are TLSv1 and SSLv23. SSLv2, SSLv3, TLSv1_1, and TLSv1_2 may
# be available on some distributions. (string value)
# Deprecated group/name - [DEFAULT]/kombu_ssl_version
#kombu_ssl_version =
# SSL key file (valid only if SSL enabled). (string value)
# Deprecated group/name - [DEFAULT]/kombu_ssl_keyfile
#kombu_ssl_keyfile =
# SSL cert file (valid only if SSL enabled). (string value)
# Deprecated group/name - [DEFAULT]/kombu_ssl_certfile
#kombu_ssl_certfile =
# SSL certification authority file (valid only if SSL
# enabled). (string value)
# Deprecated group/name - [DEFAULT]/kombu_ssl_ca_certs
#kombu_ssl_ca_certs =
# How long to wait before reconnecting in response to an AMQP
# consumer cancel notification. (floating point value)
# Deprecated group/name - [DEFAULT]/kombu_reconnect_delay
#kombu_reconnect_delay = 1.0
# EXPERIMENTAL: Possible values are: gzip, bz2. If not set
# compression will not be used. This option may notbe
# available in future versions. (string value)
#kombu_compression = <None>
# How long to wait a missing client before abandoning to send
# it its replies. This value should not be longer than
# rpc_response_timeout. (integer value)
# Deprecated group/name - [oslo_messaging_rabbit]/kombu_reconnect_timeout
#kombu_missing_consumer_retry_timeout = 60
# Determines how the next RabbitMQ node is chosen in case the
# one we are currently connected to becomes unavailable. Takes
# effect only if more than one RabbitMQ node is provided in
# config. (string value)
# Allowed values: round-robin, shuffle
#kombu_failover_strategy = round-robin
# DEPRECATED: The RabbitMQ broker address where a single node
# is used. (string value)
# Deprecated group/name - [DEFAULT]/rabbit_host
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rabbit_host = localhost
# DEPRECATED: The RabbitMQ broker port where a single node is
# used. (port value)
# Minimum value: 0
# Maximum value: 65535
# Deprecated group/name - [DEFAULT]/rabbit_port
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rabbit_port = 5672
# DEPRECATED: RabbitMQ HA cluster host:port pairs. (list
# value)
# Deprecated group/name - [DEFAULT]/rabbit_hosts
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rabbit_hosts = $rabbit_host:$rabbit_port
# Connect over SSL for RabbitMQ. (boolean value)
# Deprecated group/name - [DEFAULT]/rabbit_use_ssl
#rabbit_use_ssl = false
# DEPRECATED: The RabbitMQ userid. (string value)
# Deprecated group/name - [DEFAULT]/rabbit_userid
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rabbit_userid = guest
# DEPRECATED: The RabbitMQ password. (string value)
# Deprecated group/name - [DEFAULT]/rabbit_password
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rabbit_password = guest
# The RabbitMQ login method. (string value)
# Deprecated group/name - [DEFAULT]/rabbit_login_method
#rabbit_login_method = AMQPLAIN
# DEPRECATED: The RabbitMQ virtual host. (string value)
# Deprecated group/name - [DEFAULT]/rabbit_virtual_host
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#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)
# Deprecated group/name - [DEFAULT]/rabbit_retry_backoff
#rabbit_retry_backoff = 2
# Maximum interval of RabbitMQ connection retries. Default is
# 30 seconds. (integer value)
#rabbit_interval_max = 30
# DEPRECATED: Maximum number of RabbitMQ connection retries.
# Default is 0 (infinite retry count). (integer value)
# Deprecated group/name - [DEFAULT]/rabbit_max_retries
# This option is deprecated for removal.
# Its value may be silently ignored in the future.
#rabbit_max_retries = 0
# Try to use HA queues in RabbitMQ (x-ha-policy: all). If you
# change this option, you must wipe the RabbitMQ database. In
# RabbitMQ 3.0, queue mirroring is no longer controlled by the
# x-ha-policy argument when declaring a queue. If you just
# want to make sure that all queues (except those with auto-
# generated names) are mirrored across all nodes, run:
# "rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode":
# "all"}' " (boolean value)
# Deprecated group/name - [DEFAULT]/rabbit_ha_queues
#rabbit_ha_queues = false
# Positive integer representing duration in seconds for queue
# TTL (x-expires). Queues which are unused for the duration of
# the TTL are automatically deleted. The parameter affects
# only reply and fanout queues. (integer value)
# Minimum value: 1
#rabbit_transient_queues_ttl = 1800
# Specifies the number of messages to prefetch. Setting to
# zero allows unlimited messages. (integer value)
#rabbit_qos_prefetch_count = 0
# Number of seconds after which the Rabbit broker is
# considered down if heartbeat's keep-alive fails (0 disable
# the heartbeat). EXPERIMENTAL (integer value)
#heartbeat_timeout_threshold = 60
# How often times during the heartbeat_timeout_threshold we
# check the heartbeat. (integer value)
#heartbeat_rate = 2
# Deprecated, use rpc_backend=kombu+memory or rpc_backend=fake
# (boolean value)
# Deprecated group/name - [DEFAULT]/fake_rabbit
#fake_rabbit = false
# Maximum number of channels to allow (integer value)
#channel_max = <None>
# The maximum byte size for an AMQP frame (integer value)
#frame_max = <None>
# How often to send heartbeats for consumer's connections
# (integer value)
#heartbeat_interval = 3
# Enable SSL (boolean value)
#ssl = <None>
# Arguments passed to ssl.wrap_socket (dict value)
#ssl_options = <None>
# Set socket timeout in seconds for connection's socket
# (floating point value)
#socket_timeout = 0.25
# Set TCP_USER_TIMEOUT in seconds for connection's socket
# (floating point value)
#tcp_user_timeout = 0.25
# Set delay for reconnection to some host which has connection
# error (floating point value)
#host_connection_reconnect_delay = 0.25
# Connection factory implementation (string value)
# Allowed values: new, single, read_write
#connection_factory = single
# Maximum number of connections to keep queued. (integer
# value)
#pool_max_size = 30
# Maximum number of connections to create above
# `pool_max_size`. (integer value)
#pool_max_overflow = 0
# Default number of seconds to wait for a connections to
# available (integer value)
#pool_timeout = 30
# Lifetime of a connection (since creation) in seconds or None
# for no recycling. Expired connections are closed on acquire.
# (integer value)
#pool_recycle = 600
# Threshold at which inactive (since release) connections are
# considered stale in seconds or None for no staleness. Stale
# connections are closed on acquire. (integer value)
#pool_stale = 60
# Persist notification messages. (boolean value)
#notification_persistence = false
# Exchange name for sending notifications (string value)
#default_notification_exchange = ${control_exchange}_notification
# Max number of not acknowledged message which RabbitMQ can
# send to notification listener. (integer value)
#notification_listener_prefetch_count = 100
# Reconnecting retry count in case of connectivity problem
# during sending notification, -1 means infinite retry.
# (integer value)
#default_notification_retry_attempts = -1
# Reconnecting retry delay in case of connectivity problem
# during sending notification message (floating point value)
#notification_retry_delay = 0.25
# Time to live for rpc queues without consumers in seconds.
# (integer value)
#rpc_queue_expiration = 60
# Exchange name for sending RPC messages (string value)
#default_rpc_exchange = ${control_exchange}_rpc
# Exchange name for receiving RPC replies (string value)
#rpc_reply_exchange = ${control_exchange}_rpc_reply
# Max number of not acknowledged message which RabbitMQ can
# send to rpc listener. (integer value)
#rpc_listener_prefetch_count = 100
# Max number of not acknowledged message which RabbitMQ can
# send to rpc reply listener. (integer value)
#rpc_reply_listener_prefetch_count = 100
# Reconnecting retry count in case of connectivity problem
# during sending reply. -1 means infinite retry during
# rpc_timeout (integer value)
#rpc_reply_retry_attempts = -1
# Reconnecting retry delay in case of connectivity problem
# during sending reply. (floating point value)
#rpc_reply_retry_delay = 0.25
# Reconnecting retry count in case of connectivity problem
# during sending RPC message, -1 means infinite retry. If
# actual retry attempts in not 0 the rpc request could be
# processed more then one time (integer value)
#default_rpc_retry_attempts = -1
# Reconnecting retry delay in case of connectivity problem
# during sending RPC message (floating point value)
#rpc_retry_delay = 0.25
[oslo_messaging_zmq]
#
# From oslo.messaging
#
# ZeroMQ bind address. Should be a wildcard (*), an ethernet
# interface, or IP. The "host" option should point or resolve
# to this address. (string value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_address
#rpc_zmq_bind_address = *
# MatchMaker driver. (string value)
# Allowed values: redis, dummy
# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
#rpc_zmq_matchmaker = redis
# Number of ZeroMQ contexts, defaults to 1. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_contexts
#rpc_zmq_contexts = 1
# Maximum number of ingress messages to locally buffer per
# topic. Default is unlimited. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_topic_backlog
#rpc_zmq_topic_backlog = <None>
# Directory for holding IPC sockets. (string value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_ipc_dir
#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)
# Deprecated group/name - [DEFAULT]/rpc_zmq_host
#rpc_zmq_host = localhost
# Seconds to wait before a cast expires (TTL). The default
# value of -1 specifies an infinite linger period. The value
# of 0 specifies no linger period. Pending messages shall be
# discarded immediately when the socket is closed. Only
# supported by impl_zmq. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_cast_timeout
#rpc_cast_timeout = -1
# The default number of seconds that poll should wait. Poll
# raises timeout exception when timeout expired. (integer
# value)
# Deprecated group/name - [DEFAULT]/rpc_poll_timeout
#rpc_poll_timeout = 1
# Expiration timeout in seconds of a name service record about
# existing target ( < 0 means no timeout). (integer value)
# Deprecated group/name - [DEFAULT]/zmq_target_expire
#zmq_target_expire = 300
# Update period in seconds of a name service record about
# existing target. (integer value)
# Deprecated group/name - [DEFAULT]/zmq_target_update
#zmq_target_update = 180
# Use PUB/SUB pattern for fanout methods. PUB/SUB always uses
# proxy. (boolean value)
# Deprecated group/name - [DEFAULT]/use_pub_sub
#use_pub_sub = true
# Use ROUTER remote proxy. (boolean value)
# Deprecated group/name - [DEFAULT]/use_router_proxy
#use_router_proxy = true
# Minimal port number for random ports range. (port value)
# Minimum value: 0
# Maximum value: 65535
# Deprecated group/name - [DEFAULT]/rpc_zmq_min_port
#rpc_zmq_min_port = 49153
# Maximal port number for random ports range. (integer value)
# Minimum value: 1
# Maximum value: 65536
# Deprecated group/name - [DEFAULT]/rpc_zmq_max_port
#rpc_zmq_max_port = 65536
# Number of retries to find free port number before fail with
# ZMQBindError. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_zmq_bind_port_retries
#rpc_zmq_bind_port_retries = 100
# Default serialization mechanism for
# serializing/deserializing outgoing/incoming messages (string
# value)
# Allowed values: json, msgpack
# Deprecated group/name - [DEFAULT]/rpc_zmq_serialization
#rpc_zmq_serialization = json
[oslo_policy]
#

View File

@ -29,6 +29,7 @@ app = {
'debug': False,
'acl_public_routes': [
'/',
'/v1',
],
}

View File

@ -0,0 +1,58 @@
# Copyright 2013 Red Hat, Inc.
# 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.
import pecan
from wsme import types as wtypes
from nimble.api.controllers import base
def build_url(resource, resource_args, bookmark=False, base_url=None):
if base_url is None:
base_url = pecan.request.public_url
template = '%(url)s/%(res)s' if bookmark else '%(url)s/v1/%(res)s'
# FIXME(lucasagomes): I'm getting a 404 when doing a GET on
# a nested resource that the URL ends with a '/'.
# https://groups.google.com/forum/#!topic/pecan-dev/QfSeviLg5qs
template += '%(args)s' if resource_args.startswith('?') else '/%(args)s'
return template % {'url': base_url, 'res': resource, 'args': resource_args}
class Link(base.APIBase):
"""A link representation."""
href = wtypes.text
"""The url of a link."""
rel = wtypes.text
"""The name of a link."""
type = wtypes.text
"""Indicates the type of document/link."""
@staticmethod
def make_link(rel_name, url, resource, resource_args,
bookmark=False, type=wtypes.Unset):
href = build_url(resource, resource_args,
bookmark=bookmark, base_url=url)
return Link(href=href, rel=rel_name, type=type)
@classmethod
def sample(cls):
sample = cls(href="http://localhost:6688/chassis/"
"eaaca217-e7d8-47b4-bb41-3f99f20eed89",
rel="bookmark")
return sample

View File

@ -13,12 +13,16 @@
# License for the specific language governing permissions and limitations
# under the License.
import pecan
from pecan import rest
from wsme import types as wtypes
from nimble.api.controllers import base
from nimble.api.controllers import v1
from nimble.api import expose
ID_VERSION1 = 'v1'
class Root(base.APIBase):
@ -39,6 +43,26 @@ class Root(base.APIBase):
class RootController(rest.RestController):
_versions = [ID_VERSION1]
"""All supported API versions"""
_default_version = ID_VERSION1
"""The default API version"""
v1 = v1.Controller()
@expose.expose(Root)
def get(self):
return Root.convert()
@pecan.expose()
def _route(self, args):
"""Overrides the default routing behavior.
It redirects the request to the default version of the nimble API
if the version number is not specified in the url.
"""
if args[0] and args[0] not in self._versions:
args = [self._default_version] + args
return super(RootController, self)._route(args)

View File

@ -0,0 +1,33 @@
# Copyright 2016 Huawei Technologies Co.,LTD.
# 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.
"""
Version 1 of the Nimble API
Specification can be found at doc/source/webapi/v1.rst
"""
from pecan import rest
from nimble.api.controllers.v1 import flavor
class Controller(rest.RestController):
"""Version 1 API controller root."""
flavor = flavor.FlavorController()
__all__ = ('Controller',)

View File

@ -0,0 +1,131 @@
# Copyright 2016 Huawei Technologies Co.,LTD.
# 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.
import pecan
from pecan import rest
from six.moves import http_client
import wsme
from wsme import types as wtypes
from nimble.api.controllers import base
from nimble.api.controllers import link
from nimble.api.controllers.v1 import types
from nimble.api import expose
from nimble import objects
class Flavor(base.APIBase):
"""API representation of a flavor.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
a flavor.
"""
uuid = types.uuid
"""The UUID of the flavor"""
name = wtypes.text
"""The name of the flavor"""
description = wtypes.text
"""The description of the flavor"""
is_public = types.boolean
"""Indicates whether the flavor is public."""
links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link"""
def __init__(self, **kwargs):
self.fields = []
for field in objects.Flavor.fields:
# Skip fields we do not expose.
if not hasattr(self, field):
continue
self.fields.append(field)
setattr(self, field, kwargs.get(field, wtypes.Unset))
@classmethod
def convert_with_links(cls, rpc_flavor):
flavor = Flavor(**rpc_flavor.as_dict())
url = pecan.request.public_url
flavor.links = [link.Link.make_link('self',
url,
'flavor', flavor.uuid),
link.Link.make_link('bookmark',
url,
'flavor', flavor.uuid,
bookmark=True)
]
return flavor
class FlavorCollection(base.APIBase):
"""API representation of a collection of flavor."""
flavor = [Flavor]
"""A list containing flavor objects"""
@staticmethod
def convert_with_links(flavor, url=None, **kwargs):
collection = FlavorCollection()
collection.flavor = [Flavor.convert_with_links(fl)
for fl in flavor]
return collection
class FlavorController(rest.RestController):
"""REST controller for Chassis."""
@expose.expose(FlavorCollection)
def get_all(self):
"""Retrieve a list of flavor."""
flavor = objects.Flavor.list(pecan.request.context)
return FlavorCollection.convert_with_links(flavor)
@expose.expose(Flavor, types.uuid)
def get_one(self, flavor_uuid):
"""Retrieve information about the given flavor.
:param flavor_uuid: UUID of a flavor.
"""
rpc_flavor = objects.Flavor.get(pecan.request.context,
flavor_uuid)
return Flavor.convert_with_links(rpc_flavor)
@expose.expose(Flavor, body=Flavor, status_code=http_client.CREATED)
def post(self, flavor):
"""Create a new flavor.
:param flavor: a flavor within the request body.
"""
new_flavor = objects.Flavor(pecan.request.context,
**flavor.as_dict())
new_flavor.create()
# Set the HTTP Location Header
pecan.response.location = link.build_url('flavor', new_flavor.uuid)
return Flavor.convert_with_links(new_flavor)
@expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
def delete(self, flavor_uuid):
"""Delete a flavor.
:param flavor_uuid: UUID of a flavor.
"""
rpc_flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
rpc_flavor.destroy()

View File

@ -0,0 +1,66 @@
# coding: utf-8
#
# Copyright 2013 Red Hat, Inc.
# 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_utils import strutils
from oslo_utils import uuidutils
from wsme import types as wtypes
from nimble.common import exception
class UuidType(wtypes.UserType):
"""A simple UUID type."""
basetype = wtypes.text
name = 'uuid'
@staticmethod
def validate(value):
if not uuidutils.is_uuid_like(value):
raise exception.InvalidUUID(uuid=value)
return value
@staticmethod
def frombasetype(value):
if value is None:
return None
return UuidType.validate(value)
class BooleanType(wtypes.UserType):
"""A simple boolean type."""
basetype = wtypes.text
name = 'boolean'
@staticmethod
def validate(value):
try:
return strutils.bool_from_string(value, strict=True)
except ValueError as e:
# raise Invalid to return 400 (BadRequest) in the API
raise exception.Invalid(e)
@staticmethod
def frombasetype(value):
if value is None:
return None
return BooleanType.validate(value)
boolean = BooleanType()
uuid = UuidType()

View File

@ -62,11 +62,13 @@ class ParsableErrorMiddleware(object):
app_iter = self.app(environ, replacement_start_response)
if (state['status_code'] // 100) not in (2, 3):
errs = self._update_errors(app_iter, state['status_code'])
body = [six.b(json.dumps({'errors': errs}))]
if six.PY3:
app_iter = [i.decode('utf-8') for i in app_iter]
body = [json.dumps({'error_message': '\n'.join(app_iter)})]
if six.PY3:
body = [item.encode('utf-8') for item in body]
state['headers'].append(('Content-Type', 'application/json'))
state['headers'].append(('Content-Length', str(len(body[0]))))
else:
body = app_iter
return body

View File

@ -96,6 +96,11 @@ class OperationNotPermitted(NotAuthorized):
_msg_fmt = _("Operation not permitted.")
class NotFound(NimbleException):
_msg_fmt = _("Resource could not be found.")
code = http_client.NOT_FOUND
class Invalid(NimbleException):
_msg_fmt = _("Unacceptable parameters.")
code = http_client.BAD_REQUEST
@ -124,5 +129,13 @@ class InvalidMAC(Invalid):
_msg_fmt = _("Expected a MAC address but received %(mac)s.")
class InvalidUUID(Invalid):
msg_fmt = _("Expected a uuid but received %(uuid)s.")
class FlavorAlreadyExists(NimbleException):
_msg_fmt = _("Flavor with name %(name)s already exists.")
class FlavorNotFound(NotFound):
msg_fmt = _("Flavor %(flavor)s could not be found.")

View File

@ -22,6 +22,7 @@ from nimble.common import config
from nimble.common import exception
from nimble.common.i18n import _
from nimble.conf import CONF
from nimble import objects
LOG = log.getLogger(__name__)
@ -47,6 +48,7 @@ def prepare_service(argv=None):
])
config.parse_args(argv)
log.setup(CONF, 'nimble')
objects.register_all()
def process_launcher():

79
nimble/conf/auth.py Normal file
View File

@ -0,0 +1,79 @@
# Copyright 2016 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.
import copy
from keystoneauth1 import exceptions as kaexception
from keystoneauth1 import loading as kaloading
from oslo_config import cfg
LEGACY_SECTION = 'keystone_authtoken'
OLD_SESSION_OPTS = {
'certfile': [cfg.DeprecatedOpt('certfile', LEGACY_SECTION)],
'keyfile': [cfg.DeprecatedOpt('keyfile', LEGACY_SECTION)],
'cafile': [cfg.DeprecatedOpt('cafile', LEGACY_SECTION)],
'insecure': [cfg.DeprecatedOpt('insecure', LEGACY_SECTION)],
'timeout': [cfg.DeprecatedOpt('timeout', LEGACY_SECTION)],
}
# FIXME(pas-ha) remove import of auth_token section after deprecation period
cfg.CONF.import_group(LEGACY_SECTION, 'keystonemiddleware.auth_token')
def load_auth(conf, group):
try:
auth = kaloading.load_auth_from_conf_options(conf, group)
except kaexception.MissingRequiredOptions:
auth = None
return auth
def register_auth_opts(conf, group):
"""Register session- and auth-related options
Registers only basic auth options shared by all auth plugins.
The rest are registered at runtime depending on auth plugin used.
"""
kaloading.register_session_conf_options(
conf, group, deprecated_opts=OLD_SESSION_OPTS)
kaloading.register_auth_conf_options(conf, group)
def add_auth_opts(options):
"""Add auth options to sample config
As these are dynamically registered at runtime,
this adds options for most used auth_plugins
when generating sample config.
"""
def add_options(opts, opts_to_add):
for new_opt in opts_to_add:
for opt in opts:
if opt.name == new_opt.name:
break
else:
opts.append(new_opt)
opts = copy.deepcopy(options)
opts.insert(0, kaloading.get_auth_common_conf_options()[0])
# NOTE(dims): There are a lot of auth plugins, we just generate
# the config options for a few common ones
plugins = ['password', 'v2password', 'v3password']
for name in plugins:
plugin = kaloading.get_plugin_loader(name)
add_options(opts, kaloading.get_auth_plugin_conf_options(plugin))
add_options(opts, kaloading.get_session_conf_options())
opts.sort(key=lambda x: x.name)
return opts

View File

@ -20,6 +20,14 @@ from oslo_config import cfg
from nimble.common.i18n import _
api_opts = [
cfg.BoolOpt('debug_tracebacks_in_api',
default=False,
help=_('Return server tracebacks in the API response for any '
'error responses. WARNING: this is insecure '
'and should not be used in a production environment.')),
]
exc_log_opts = [
cfg.BoolOpt('fatal_exception_format_errors',
default=False,
@ -57,6 +65,7 @@ service_opts = [
def register_opts(conf):
conf.register_opts(api_opts)
conf.register_opts(exc_log_opts)
conf.register_opts(service_opts)
conf.register_opts(path_opts)

View File

@ -17,6 +17,7 @@ import nimble.conf.database
import nimble.conf.default
_default_opt_lists = [
nimble.conf.default.api_opts,
nimble.conf.default.exc_log_opts,
nimble.conf.default.path_opts,
nimble.conf.default.service_opts,

View File

@ -46,11 +46,11 @@ class Connection(object):
"""Create a new instance type."""
@abc.abstractmethod
def flavor_get_by_name(name):
def flavor_get(uuid):
"""Get instance type by name."""
def flavor_get_all():
"""Get all instance flavors."""
"""Get all instance types."""
@abc.abstractmethod
def flavor_destroy(name):

View File

@ -33,10 +33,12 @@ def upgrade():
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(length=255), nullable=True),
sa.Column('description', sa.String(length=255), nullable=True),
sa.Column('uuid', sa.String(length=36), nullable=True),
sa.Column('name', sa.String(length=255), nullable=False),
sa.Column('description', sa.String(length=255), nullable=False),
sa.Column('is_public', sa.Boolean(), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name', name='uniq_instance_types0name'),
mysql_ENGINE='InnoDB',
mysql_DEFAULT_CHARSET='UTF8'
)

View File

@ -20,6 +20,9 @@ import threading
from oslo_db import exception as db_exc
from oslo_db.sqlalchemy import enginefacade
from oslo_log import log
from oslo_utils import strutils
from oslo_utils import uuidutils
from sqlalchemy.orm.exc import NoResultFound
from nimble.common import exception
from nimble.db import api
@ -55,6 +58,24 @@ def model_query(model, *args, **kwargs):
return query
def add_identity_filter(query, value):
"""Adds an identity filter to a query.
Filters results by ID, if supplied value is a valid integer.
Otherwise attempts to filter results by UUID.
:param query: Initial query to add filter to.
:param value: Value for filtering results by.
:return: Modified query.
"""
if strutils.is_int_like(value):
return query.filter_by(id=value)
elif uuidutils.is_uuid_like(value):
return query.filter_by(uuid=value)
else:
raise exception.InvalidIdentity(identity=value)
class Connection(api.Connection):
"""SqlAlchemy connection."""
@ -62,6 +83,9 @@ class Connection(api.Connection):
pass
def flavor_create(self, values):
if not values.get('uuid'):
values['uuid'] = uuidutils.generate_uuid()
instance_type = models.InstanceTypes()
instance_type.update(values)
@ -73,5 +97,21 @@ class Connection(api.Connection):
raise exception.FlavorAlreadyExists(name=values['name'])
return instance_type
def flavor_get(self, flavor_id):
query = model_query(models.InstanceTypes).filter_by(uuid=flavor_id)
try:
return query.one()
except NoResultFound:
raise exception.FlavorNotFound(flavor=flavor_id)
def flavor_get_all(self):
return model_query(models.InstanceTypes)
def flavor_destroy(self, flavor_id):
with _session_for_write():
query = model_query(models.InstanceTypes)
query = add_identity_filter(query, flavor_id)
count = query.delete()
if count != 1:
raise exception.FlavorNotFound(flavor=flavor_id)

View File

@ -65,8 +65,9 @@ class InstanceTypes(Base):
table_args()
)
id = Column(Integer, primary_key=True)
name = Column(String(255), nullable=True)
description = Column(String(255), nullable=True)
uuid = Column(String(36), nullable=True)
name = Column(String(255), nullable=False)
description = Column(String(255), nullable=False)
is_public = Column(Boolean, default=True)

View File

@ -30,6 +30,7 @@ class Flavor(base.NimbleObject, object_base.VersionedObjectDictCompat):
fields = {
'id': object_fields.IntegerField(),
'uuid': object_fields.UUIDField(nullable=True),
'name': object_fields.StringField(nullable=True),
'description': object_fields.StringField(nullable=True),
'is_public': object_fields.BooleanField(),
@ -47,8 +48,20 @@ class Flavor(base.NimbleObject, object_base.VersionedObjectDictCompat):
db_flavors = cls.dbapi.flavor_get_all()
return Flavor._from_db_object_list(db_flavors, cls, context)
@classmethod
def get(cls, context, flavor_id):
"""Find a flavor and return a Flavor object."""
db_flavor = cls.dbapi.flavor_get(flavor_id)
flavor = Flavor._from_db_object(cls(context), db_flavor)
return flavor
def create(self, context=None):
"""Create a Flavor record in the DB."""
values = self.obj_get_changes()
db_flavor = self.dbapi.flavor_create(values)
self._from_db_object(self, db_flavor)
def destroy(self, context=None):
"""Delete the Flavor from the DB."""
self.dbapi.flavor_destroy(self.uuid)
self.obj_reset_changes()