Add check for specified image in create request

We should make sure the image exists before sending it to
Ironic.

Change-Id: I8ff6aec53186c3ecbb9b7bd06e3bcd3fe35ef913
This commit is contained in:
Zhenguo Niu 2016-11-23 16:27:05 +08:00
parent 80983ab56b
commit 948e0f5758
7 changed files with 266 additions and 22 deletions

View File

@ -88,7 +88,10 @@ function configure_nimble {
iniset ${NIMBLE_CONF_FILE} ironic api_endpoint "${KEYSTONE_AUTH_PROTOCOL}://${SERVICE_HOST}:${IRONIC_SERVICE_PORT}" iniset ${NIMBLE_CONF_FILE} ironic api_endpoint "${KEYSTONE_AUTH_PROTOCOL}://${SERVICE_HOST}:${IRONIC_SERVICE_PORT}"
# Setup neutron section # Setup neutron section
iniset ${NIMBLE_CONF_FILE} neutron url "${NIMBLE_SERVICE_PROTOCOL}://${SERVICE_HOST}:${NEUTRON_SERVICE_PORT}" iniset ${NIMBLE_CONF_FILE} neutron url "${NEUTRON_SERVICE_PROTOCOL}://${SERVICE_HOST}:${NEUTRON_SERVICE_PORT}"
# Setup glance section
iniset ${NIMBLE_CONF_FILE} glance glance_api_servers "${GLANCE_SERVICE_PROTOCOL}://${SERVICE_HOST}:${GLANCE_SERVICE_PORT}"
# Setup keystone section # Setup keystone section
iniset ${NIMBLE_CONF_FILE} keystone region_name ${REGION_NAME} iniset ${NIMBLE_CONF_FILE} keystone region_name ${REGION_NAME}

View File

@ -168,7 +168,7 @@
#rpc_zmq_bind_address = * #rpc_zmq_bind_address = *
# MatchMaker driver. (string value) # MatchMaker driver. (string value)
# Allowed values: redis, dummy # Allowed values: redis, sentinel, dummy
# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker # Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
#rpc_zmq_matchmaker = redis #rpc_zmq_matchmaker = redis
@ -191,13 +191,15 @@
# Deprecated group/name - [DEFAULT]/rpc_zmq_host # Deprecated group/name - [DEFAULT]/rpc_zmq_host
#rpc_zmq_host = localhost #rpc_zmq_host = localhost
# Seconds to wait before a cast expires (TTL). The default # Number of seconds to wait before all pending messages will
# value of -1 specifies an infinite linger period. The value # be sent after closing a socket. The default value of -1
# of 0 specifies no linger period. Pending messages shall be # specifies an infinite linger period. The value of 0
# discarded immediately when the socket is closed. Only # specifies no linger period. Pending messages shall be
# supported by impl_zmq. (integer value) # discarded immediately when the socket is closed. Positive
# values specify an upper bound for the linger period.
# (integer value)
# Deprecated group/name - [DEFAULT]/rpc_cast_timeout # Deprecated group/name - [DEFAULT]/rpc_cast_timeout
#rpc_cast_timeout = -1 #zmq_linger = -1
# The default number of seconds that poll should wait. Poll # The default number of seconds that poll should wait. Poll
# raises timeout exception when timeout expired. (integer # raises timeout exception when timeout expired. (integer
@ -253,7 +255,73 @@
# False means to keep queue and messages even if server is # False means to keep queue and messages even if server is
# disconnected, when the server appears we send all # disconnected, when the server appears we send all
# accumulated messages to it. (boolean value) # accumulated messages to it. (boolean value)
#zmq_immediate = false #zmq_immediate = true
# Enable/disable TCP keepalive (KA) mechanism. The default
# value of -1 (or any other negative value) means to skip any
# overrides and leave it to OS default; 0 and 1 (or any other
# positive value) mean to disable and enable the option
# respectively. (integer value)
#zmq_tcp_keepalive = -1
# The duration between two keepalive transmissions in idle
# condition. The unit is platform dependent, for example,
# seconds in Linux, milliseconds in Windows etc. The default
# value of -1 (or any other negative value and 0) means to
# skip any overrides and leave it to OS default. (integer
# value)
#zmq_tcp_keepalive_idle = -1
# The number of retransmissions to be carried out before
# declaring that remote end is not available. The default
# value of -1 (or any other negative value and 0) means to
# skip any overrides and leave it to OS default. (integer
# value)
#zmq_tcp_keepalive_cnt = -1
# The duration between two successive keepalive
# retransmissions, if acknowledgement to the previous
# keepalive transmission is not received. The unit is platform
# dependent, for example, seconds in Linux, milliseconds in
# Windows etc. The default value of -1 (or any other negative
# value and 0) means to skip any overrides and leave it to OS
# default. (integer value)
#zmq_tcp_keepalive_intvl = -1
# Maximum number of (green) threads to work concurrently.
# (integer value)
#rpc_thread_pool_size = 100
# Expiration timeout in seconds of a sent/received message
# after which it is not tracked anymore by a client/server.
# (integer value)
#rpc_message_ttl = 300
# Wait for message acknowledgements from receivers. This
# mechanism works only via proxy without PUB/SUB. (boolean
# value)
#rpc_use_acks = false
# Number of seconds to wait for an ack from a cast/call. After
# each retry attempt this timeout is multiplied by some
# specified multiplier. (integer value)
#rpc_ack_timeout_base = 15
# Number to multiply base ack timeout by after each retry
# attempt. (integer value)
#rpc_ack_timeout_multiplier = 2
# Default number of message sending attempts in case of any
# problems occurred: positive value N means at most N retries,
# 0 means no retries, None or -1 (or any other negative
# values) mean to retry forever. This option is used only if
# acknowledgments are enabled. (integer value)
#rpc_retry_attempts = 3
# List of publisher hosts SubConsumer can subscribe on. This
# option has higher priority then the default publishers list
# taken from the matchmaker. (list value)
#subscribe_on =
# Size of executor thread pool. (integer value) # Size of executor thread pool. (integer value)
# Deprecated group/name - [DEFAULT]/rpc_thread_pool_size # Deprecated group/name - [DEFAULT]/rpc_thread_pool_size
@ -571,6 +639,34 @@
# seconds. (integer value) # seconds. (integer value)
#sync_node_resource_interval = 60 #sync_node_resource_interval = 60
# Default scheduler driver to use (string value)
#scheduler_driver = nimble.engine.scheduler.filter_scheduler.FilterScheduler
[glance]
#
# From nimble
#
# A list of the glance api servers available to nimble. Prefix
# with https:// for SSL-based glance API servers. Format is
# [hostname|IP]:port. (list value)
#glance_api_servers = <None>
# Allow to perform insecure SSL (https) requests to glance.
# (boolean value)
#glance_api_insecure = false
# Number of retries when downloading an image from glance.
# (integer value)
#glance_num_retries = 0
# Optional path to a CA certificate bundle to be used to
# validate the SSL certificate served by glance. It is used
# when glance_api_insecure is set to False. (string value)
#glance_cafile = <None>
[ironic] [ironic]
@ -919,6 +1015,19 @@
# Minimum value: 1 # Minimum value: 1
#notify_server_credit = 100 #notify_server_credit = 100
# Send messages of this type pre-settled.
# Pre-settled messages will not receive acknowledgement
# from the peer. Note well: pre-settled messages may be
# silently discarded if the delivery fails.
# Permitted values:
# 'rpc-call' - send RPC Calls pre-settled
# 'rpc-reply'- send RPC Replies pre-settled
# 'rpc-cast' - Send RPC Casts pre-settled
# 'notify' - Send Notifications pre-settled
# (multi valued)
#pre_settled = rpc-cast
#pre_settled = rpc-reply
[oslo_messaging_notifications] [oslo_messaging_notifications]
@ -1046,6 +1155,7 @@
#rabbit_password = guest #rabbit_password = guest
# The RabbitMQ login method. (string value) # The RabbitMQ login method. (string value)
# Allowed values: PLAIN, AMQPLAIN, RABBIT-CR-DEMO
# Deprecated group/name - [DEFAULT]/rabbit_login_method # Deprecated group/name - [DEFAULT]/rabbit_login_method
#rabbit_login_method = AMQPLAIN #rabbit_login_method = AMQPLAIN
@ -1080,7 +1190,7 @@
# change this option, you must wipe the RabbitMQ database. In # change this option, you must wipe the RabbitMQ database. In
# RabbitMQ 3.0, queue mirroring is no longer controlled by the # RabbitMQ 3.0, queue mirroring is no longer controlled by the
# x-ha-policy argument when declaring a queue. If you just # x-ha-policy argument when declaring a queue. If you just
# want to make sure that all queues (except those with auto- # want to make sure that all queues (except those with auto-
# generated names) are mirrored across all nodes, run: # generated names) are mirrored across all nodes, run:
# "rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode": # "rabbitmqctl set_policy HA '^(?!amq\.).*' '{"ha-mode":
# "all"}' " (boolean value) # "all"}' " (boolean value)
@ -1166,6 +1276,12 @@
# connections are closed on acquire. (integer value) # connections are closed on acquire. (integer value)
#pool_stale = 60 #pool_stale = 60
# Default serialization mechanism for
# serializing/deserializing outgoing/incoming messages (string
# value)
# Allowed values: json, msgpack
#default_serializer_type = json
# Persist notification messages. (boolean value) # Persist notification messages. (boolean value)
#notification_persistence = false #notification_persistence = false
@ -1236,7 +1352,7 @@
#rpc_zmq_bind_address = * #rpc_zmq_bind_address = *
# MatchMaker driver. (string value) # MatchMaker driver. (string value)
# Allowed values: redis, dummy # Allowed values: redis, sentinel, dummy
# Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker # Deprecated group/name - [DEFAULT]/rpc_zmq_matchmaker
#rpc_zmq_matchmaker = redis #rpc_zmq_matchmaker = redis
@ -1259,13 +1375,15 @@
# Deprecated group/name - [DEFAULT]/rpc_zmq_host # Deprecated group/name - [DEFAULT]/rpc_zmq_host
#rpc_zmq_host = localhost #rpc_zmq_host = localhost
# Seconds to wait before a cast expires (TTL). The default # Number of seconds to wait before all pending messages will
# value of -1 specifies an infinite linger period. The value # be sent after closing a socket. The default value of -1
# of 0 specifies no linger period. Pending messages shall be # specifies an infinite linger period. The value of 0
# discarded immediately when the socket is closed. Only # specifies no linger period. Pending messages shall be
# supported by impl_zmq. (integer value) # discarded immediately when the socket is closed. Positive
# values specify an upper bound for the linger period.
# (integer value)
# Deprecated group/name - [DEFAULT]/rpc_cast_timeout # Deprecated group/name - [DEFAULT]/rpc_cast_timeout
#rpc_cast_timeout = -1 #zmq_linger = -1
# The default number of seconds that poll should wait. Poll # The default number of seconds that poll should wait. Poll
# raises timeout exception when timeout expired. (integer # raises timeout exception when timeout expired. (integer
@ -1321,7 +1439,73 @@
# False means to keep queue and messages even if server is # False means to keep queue and messages even if server is
# disconnected, when the server appears we send all # disconnected, when the server appears we send all
# accumulated messages to it. (boolean value) # accumulated messages to it. (boolean value)
#zmq_immediate = false #zmq_immediate = true
# Enable/disable TCP keepalive (KA) mechanism. The default
# value of -1 (or any other negative value) means to skip any
# overrides and leave it to OS default; 0 and 1 (or any other
# positive value) mean to disable and enable the option
# respectively. (integer value)
#zmq_tcp_keepalive = -1
# The duration between two keepalive transmissions in idle
# condition. The unit is platform dependent, for example,
# seconds in Linux, milliseconds in Windows etc. The default
# value of -1 (or any other negative value and 0) means to
# skip any overrides and leave it to OS default. (integer
# value)
#zmq_tcp_keepalive_idle = -1
# The number of retransmissions to be carried out before
# declaring that remote end is not available. The default
# value of -1 (or any other negative value and 0) means to
# skip any overrides and leave it to OS default. (integer
# value)
#zmq_tcp_keepalive_cnt = -1
# The duration between two successive keepalive
# retransmissions, if acknowledgement to the previous
# keepalive transmission is not received. The unit is platform
# dependent, for example, seconds in Linux, milliseconds in
# Windows etc. The default value of -1 (or any other negative
# value and 0) means to skip any overrides and leave it to OS
# default. (integer value)
#zmq_tcp_keepalive_intvl = -1
# Maximum number of (green) threads to work concurrently.
# (integer value)
#rpc_thread_pool_size = 100
# Expiration timeout in seconds of a sent/received message
# after which it is not tracked anymore by a client/server.
# (integer value)
#rpc_message_ttl = 300
# Wait for message acknowledgements from receivers. This
# mechanism works only via proxy without PUB/SUB. (boolean
# value)
#rpc_use_acks = false
# Number of seconds to wait for an ack from a cast/call. After
# each retry attempt this timeout is multiplied by some
# specified multiplier. (integer value)
#rpc_ack_timeout_base = 15
# Number to multiply base ack timeout by after each retry
# attempt. (integer value)
#rpc_ack_timeout_multiplier = 2
# Default number of message sending attempts in case of any
# problems occurred: positive value N means at most N retries,
# 0 means no retries, None or -1 (or any other negative
# values) mean to retry forever. This option is used only if
# acknowledgments are enabled. (integer value)
#rpc_retry_attempts = 3
# List of publisher hosts SubConsumer can subscribe on. This
# option has higher priority then the default publishers list
# taken from the matchmaker. (list value)
#subscribe_on =
[oslo_policy] [oslo_policy]
@ -1330,7 +1514,7 @@
# From oslo.policy # From oslo.policy
# #
# The JSON file that defines policies. (string value) # The file that defines policies. (string value)
# Deprecated group/name - [DEFAULT]/policy_file # Deprecated group/name - [DEFAULT]/policy_file
#policy_file = policy.json #policy_file = policy.json
@ -1349,6 +1533,39 @@
#policy_dirs = policy.d #policy_dirs = policy.d
[scheduler]
#
# From nimble
#
# Default scheduler driver to use (string value)
#scheduler_driver = nimble.engine.scheduler.filter_scheduler.FilterScheduler
# The scheduler node manager class to use (string value)
#scheduler_node_manager = nimble.engine.scheduler.node_manager.NodeManager
# Maximum number of attempts to schedule a node (integer
# value)
#scheduler_max_attempts = 3
# Absolute path to scheduler configuration JSON file. (string
# value)
#scheduler_json_config_location =
# Which filter class names to use for filtering nodes when not
# specified in the request. (list value)
#scheduler_default_filters = AvailabilityZoneFilter,InstanceTypeFilter,CapabilitiesFilter
# Which weigher class names to use for weighing nodes. (list
# value)
#scheduler_default_weighers =
# Which handler to use for selecting the node after weighing
# (string value)
#scheduler_weight_handler = nimble.engine.scheduler.weights.OrderedNodeWeightHandler
[ssl] [ssl]
# #

View File

@ -369,6 +369,7 @@ class InstanceController(rest.RestController):
requested_networks = instance.pop('networks', None) requested_networks = instance.pop('networks', None)
instance_type_uuid = instance.get('instance_type_uuid') instance_type_uuid = instance.get('instance_type_uuid')
image_uuid = instance.get('image_uuid')
try: try:
instance_type = objects.InstanceType.get(pecan.request.context, instance_type = objects.InstanceType.get(pecan.request.context,
@ -377,7 +378,7 @@ class InstanceController(rest.RestController):
instance = self.engine_api.create( instance = self.engine_api.create(
pecan.request.context, pecan.request.context,
instance_type, instance_type,
image_uuid=instance.get('image_uuid'), image_uuid=image_uuid,
name=instance.get('name'), name=instance.get('name'),
description=instance.get('description'), description=instance.get('description'),
availability_zone=instance.get('availability_zone'), availability_zone=instance.get('availability_zone'),
@ -388,6 +389,14 @@ class InstanceController(rest.RestController):
instance_type_uuid) instance_type_uuid)
raise wsme.exc.ClientSideError( raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST) msg, status_code=http_client.BAD_REQUEST)
except exception.ImageNotFound:
msg = (_("Requested image %s could not be found") % image_uuid)
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
except exception.GlanceConnectionFailed:
msg = _("Error contacting with glance server")
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
# Set the HTTP Location Header # Set the HTTP Location Header
pecan.response.location = link.build_url('instance', instance.uuid) pecan.response.location = link.build_url('instance', instance.uuid)

View File

@ -21,6 +21,7 @@ from nimble.common.i18n import _
opts = [ opts = [
cfg.ListOpt('glance_api_servers', cfg.ListOpt('glance_api_servers',
required=True,
help=_('A list of the glance api servers available to nimble. ' help=_('A list of the glance api servers available to nimble. '
'Prefix with https:// for SSL-based glance API ' 'Prefix with https:// for SSL-based glance API '
'servers. Format is [hostname|IP]:port.')), 'servers. Format is [hostname|IP]:port.')),

View File

@ -19,6 +19,7 @@ from oslo_log import log
from nimble.engine import rpcapi from nimble.engine import rpcapi
from nimble.engine import status from nimble.engine import status
from nimble import image
from nimble import objects from nimble import objects
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
@ -27,10 +28,14 @@ LOG = log.getLogger(__name__)
class API(object): class API(object):
"""API for interacting with the engine manager.""" """API for interacting with the engine manager."""
def __init__(self, **kwargs): def __init__(self, image_api=None, **kwargs):
super(API, self).__init__(**kwargs) super(API, self).__init__(**kwargs)
self.image_api = image_api or image.API()
self.engine_rpcapi = rpcapi.EngineAPI() self.engine_rpcapi = rpcapi.EngineAPI()
def _get_image(self, context, image_uuid):
return self.image_api.get(context, image_uuid)
def _validate_and_build_base_options(self, context, instance_type, def _validate_and_build_base_options(self, context, instance_type,
image_uuid, name, description, image_uuid, name, description,
availability_zone, extra): availability_zone, extra):
@ -65,6 +70,10 @@ class API(object):
requested_networks): requested_networks):
"""Verify all the input parameters""" """Verify all the input parameters"""
# Verify the specified image exists
if image_uuid:
self._get_image(context, image_uuid)
base_options = self._validate_and_build_base_options( base_options = self._validate_and_build_base_options(
context, instance_type, image_uuid, name, description, context, instance_type, image_uuid, name, description,
availability_zone, extra) availability_zone, extra)

View File

@ -69,6 +69,7 @@ class TestCase(base.BaseTestCase):
self.set_defaults(connection="sqlite://", self.set_defaults(connection="sqlite://",
sqlite_synchronous=False, sqlite_synchronous=False,
group='database') group='database')
CONF.set_override('glance_api_servers', 'fake-glance', 'glance')
nimble_config.parse_args([], default_config_files=[]) nimble_config.parse_args([], default_config_files=[])
def config(self, **kw): def config(self, **kw):

View File

@ -80,8 +80,10 @@ class ComputeAPIUnitTest(base.DbTestCase):
@mock.patch.object(engine_rpcapi.EngineAPI, 'create_instance') @mock.patch.object(engine_rpcapi.EngineAPI, 'create_instance')
@mock.patch('nimble.engine.api.API._provision_instances') @mock.patch('nimble.engine.api.API._provision_instances')
@mock.patch('nimble.engine.api.API._get_image')
@mock.patch('nimble.engine.api.API._validate_and_build_base_options') @mock.patch('nimble.engine.api.API._validate_and_build_base_options')
def test_create(self, mock_validate, mock_provision, mock_create): def test_create(self, mock_validate, mock_get_image,
mock_provision, mock_create):
instance_type = self._create_instance_type() instance_type = self._create_instance_type()
base_options = {'image_uuid': 'fake-uuid', base_options = {'image_uuid': 'fake-uuid',
@ -94,6 +96,7 @@ class ComputeAPIUnitTest(base.DbTestCase):
'extra': {'k1', 'v1'}, 'extra': {'k1', 'v1'},
'availability_zone': None} 'availability_zone': None}
mock_validate.return_value = base_options mock_validate.return_value = base_options
mock_get_image.side_effect = None
mock_create.return_value = mock.MagicMock() mock_create.return_value = mock.MagicMock()
self.engine_api.create( self.engine_api.create(
@ -111,3 +114,4 @@ class ComputeAPIUnitTest(base.DbTestCase):
'fake-descritpion', 'test_az', {'k1', 'v1'}) 'fake-descritpion', 'test_az', {'k1', 'v1'})
mock_provision.assert_called_once_with(self.context, base_options) mock_provision.assert_called_once_with(self.context, base_options)
self.assertTrue(mock_create.called) self.assertTrue(mock_create.called)
self.assertTrue(mock_get_image.called)