Merge "Pin API version during rolling upgrade"

This commit is contained in:
Zuul 2017-12-07 07:13:53 +00:00 committed by Gerrit Code Review
commit 39a63602c7
19 changed files with 262 additions and 154 deletions

View File

@ -365,13 +365,12 @@
#host = localhost #host = localhost
# Used for rolling upgrades. Setting this option downgrades # Used for rolling upgrades. Setting this option downgrades
# (or pins) the internal ironic RPC communication and database # (or pins) the Bare Metal API, the internal ironic RPC
# objects to their respective versions, so they are compatible # communication, and the database objects to their respective
# with older services. When doing a rolling upgrade from # versions, so they are compatible with older services. When
# version N to version N+1, set (to pin) this to N. To unpin # doing a rolling upgrade from version N to version N+1, set
# (default), leave it unset and the latest versions of RPC # (to pin) this to N. To unpin (default), leave it unset and
# communication and database objects will be used. (string # the latest versions will be used. (string value)
# value)
# Allowed values: pike, 9.2, 9.1, 9.0, 8.0 # Allowed values: pike, 9.2, 9.1, 9.0, 8.0
#pin_release_version = <None> #pin_release_version = <None>
@ -1025,7 +1024,9 @@
#domain_name = <None> #domain_name = <None>
# Always use this endpoint URL for requests for this client. # Always use this endpoint URL for requests for this client.
# (string value) # NOTE: The unversioned endpoint should be specified here; to
# request a particular API version, use the `version`, `min-
# version`, and/or `max-version` options. (string value)
#endpoint_override = <None> #endpoint_override = <None>
# Verify HTTPS connections. (boolean value) # Verify HTTPS connections. (boolean value)
@ -1662,7 +1663,9 @@
#domain_name = <None> #domain_name = <None>
# Always use this endpoint URL for requests for this client. # Always use this endpoint URL for requests for this client.
# (string value) # NOTE: The unversioned endpoint should be specified here; to
# request a particular API version, use the `version`, `min-
# version`, and/or `max-version` options. (string value)
#endpoint_override = <None> #endpoint_override = <None>
# DEPRECATED: Allow to perform insecure SSL (https) requests # DEPRECATED: Allow to perform insecure SSL (https) requests
@ -1972,7 +1975,9 @@
#enabled = false #enabled = false
# Always use this endpoint URL for requests for this client. # Always use this endpoint URL for requests for this client.
# (string value) # NOTE: The unversioned endpoint should be specified here; to
# request a particular API version, use the `version`, `min-
# version`, and/or `max-version` options. (string value)
#endpoint_override = <None> #endpoint_override = <None>
# Verify HTTPS connections. (boolean value) # Verify HTTPS connections. (boolean value)
@ -2234,6 +2239,24 @@
# service user utilizes for validating tokens, because normal # service user utilizes for validating tokens, because normal
# end users may not be able to reach that endpoint. (string # end users may not be able to reach that endpoint. (string
# value) # value)
# Deprecated group/name - [keystone_authtoken]/auth_uri
#www_authenticate_uri = <None>
# DEPRECATED: Complete "public" Identity API endpoint. This
# endpoint should not be an "admin" endpoint, as it should be
# accessible by all end users. Unauthenticated clients are
# redirected to this endpoint to authenticate. Although this
# endpoint should ideally be unversioned, client support in
# the wild varies. If you're using a versioned v2 endpoint
# here, then this should *not* be the same endpoint the
# service user utilizes for validating tokens, because normal
# end users may not be able to reach that endpoint. This
# option is deprecated in favor of www_authenticate_uri and
# will be removed in the S release. (string value)
# This option is deprecated for removal since Queens.
# Its value may be silently ignored in the future.
# Reason: The auth_uri option is deprecated in favor of
# www_authenticate_uri and will be removed in the S release.
#auth_uri = <None> #auth_uri = <None>
# API version of the admin Identity API endpoint. (string # API version of the admin Identity API endpoint. (string
@ -3800,7 +3823,9 @@
#domain_name = <None> #domain_name = <None>
# Always use this endpoint URL for requests for this client. # Always use this endpoint URL for requests for this client.
# (string value) # NOTE: The unversioned endpoint should be specified here; to
# request a particular API version, use the `version`, `min-
# version`, and/or `max-version` options. (string value)
#endpoint_override = <None> #endpoint_override = <None>
# Verify HTTPS connections. (boolean value) # Verify HTTPS connections. (boolean value)

View File

@ -85,8 +85,8 @@ class Root(base.APIBase):
root.description = ("Ironic is an OpenStack project which aims to " root.description = ("Ironic is an OpenStack project which aims to "
"provision baremetal machines.") "provision baremetal machines.")
root.default_version = Version(ID_VERSION1, root.default_version = Version(ID_VERSION1,
versions.MIN_VERSION_STRING, versions.min_version_string(),
versions.MAX_VERSION_STRING) versions.max_version_string())
root.versions = [root.default_version] root.versions = [root.default_version]
return root return root

View File

@ -39,12 +39,17 @@ from ironic.common.i18n import _
BASE_VERSION = versions.BASE_VERSION BASE_VERSION = versions.BASE_VERSION
MIN_VER = base.Version(
{base.Version.string: versions.MIN_VERSION_STRING}, def min_version():
versions.MIN_VERSION_STRING, versions.MAX_VERSION_STRING) return base.Version(
MAX_VER = base.Version( {base.Version.string: versions.min_version_string()},
{base.Version.string: versions.MAX_VERSION_STRING}, versions.min_version_string(), versions.max_version_string())
versions.MIN_VERSION_STRING, versions.MAX_VERSION_STRING)
def max_version():
return base.Version(
{base.Version.string: versions.max_version_string()},
versions.min_version_string(), versions.max_version_string())
class MediaType(base.APIBase): class MediaType(base.APIBase):
@ -200,29 +205,29 @@ class Controller(rest.RestController):
"Mutually exclusive versions requested. Version %(ver)s " "Mutually exclusive versions requested. Version %(ver)s "
"requested but not supported by this service. The supported " "requested but not supported by this service. The supported "
"version range is: [%(min)s, %(max)s].") % "version range is: [%(min)s, %(max)s].") %
{'ver': version, 'min': versions.MIN_VERSION_STRING, {'ver': version, 'min': versions.min_version_string(),
'max': versions.MAX_VERSION_STRING}, 'max': versions.max_version_string()},
headers=headers) headers=headers)
# ensure the minor version is within the supported range # ensure the minor version is within the supported range
if version < MIN_VER or version > MAX_VER: if version < min_version() or version > max_version():
raise exc.HTTPNotAcceptable(_( raise exc.HTTPNotAcceptable(_(
"Version %(ver)s was requested but the minor version is not " "Version %(ver)s was requested but the minor version is not "
"supported by this service. The supported version range is: " "supported by this service. The supported version range is: "
"[%(min)s, %(max)s].") % "[%(min)s, %(max)s].") %
{'ver': version, 'min': versions.MIN_VERSION_STRING, {'ver': version, 'min': versions.min_version_string(),
'max': versions.MAX_VERSION_STRING}, 'max': versions.max_version_string()},
headers=headers) headers=headers)
@pecan.expose() @pecan.expose()
def _route(self, args, request=None): def _route(self, args, request=None):
v = base.Version(pecan.request.headers, versions.MIN_VERSION_STRING, v = base.Version(pecan.request.headers, versions.min_version_string(),
versions.MAX_VERSION_STRING) versions.max_version_string())
# Always set the min and max headers # Always set the min and max headers
pecan.response.headers[base.Version.min_string] = ( pecan.response.headers[base.Version.min_string] = (
versions.MIN_VERSION_STRING) versions.min_version_string())
pecan.response.headers[base.Version.max_string] = ( pecan.response.headers[base.Version.max_string] = (
versions.MAX_VERSION_STRING) versions.max_version_string())
# assert that requested version is supported # assert that requested version is supported
self._check_version(v, pecan.response.headers) self._check_version(v, pecan.response.headers)

View File

@ -13,6 +13,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_config import cfg
from ironic.common import release_mappings
CONF = cfg.CONF
# This is the version 1 API # This is the version 1 API
BASE_VERSION = 1 BASE_VERSION = 1
@ -104,11 +110,33 @@ MINOR_33_STORAGE_INTERFACE = 33
MINOR_34_PORT_PHYSICAL_NETWORK = 34 MINOR_34_PORT_PHYSICAL_NETWORK = 34
MINOR_35_REBUILD_CONFIG_DRIVE = 35 MINOR_35_REBUILD_CONFIG_DRIVE = 35
# When adding another version, update MINOR_MAX_VERSION and also update # When adding another version, update:
# doc/source/dev/webapi-version-history.rst with a detailed explanation of # - MINOR_MAX_VERSION
# what the version has changed. # - doc/source/dev/webapi-version-history.rst with a detailed explanation of
# what changed in the new version
# - common/release_mappings.py, RELEASE_MAPPING['master']['api']
MINOR_MAX_VERSION = MINOR_35_REBUILD_CONFIG_DRIVE MINOR_MAX_VERSION = MINOR_35_REBUILD_CONFIG_DRIVE
# String representations of the minor and maximum versions # String representations of the minor and maximum versions
MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION) _MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
MAX_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_MAX_VERSION) _MAX_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_MAX_VERSION)
def min_version_string():
"""Returns the minimum supported API version (as a string)"""
return _MIN_VERSION_STRING
def max_version_string():
"""Returns the maximum supported API version (as a string).
If the service is pinned, the maximum API version is the pinned
version. Otherwise, it is the maximum supported API version.
"""
release_ver = release_mappings.RELEASE_MAPPING.get(
CONF.pin_release_version)
if release_ver:
return release_ver['api']
else:
return _MAX_VERSION_STRING

View File

@ -26,6 +26,7 @@
# NOTE(xek): The format of this dict is: # NOTE(xek): The format of this dict is:
# { '<release version>': { # { '<release version>': {
# 'api': '<Bare Metal API version>',
# 'rpc': '<RPC API version>', # 'rpc': '<RPC API version>',
# 'objects': { # 'objects': {
# '<object class name>': ['<object version>'], # '<object class name>': ['<object version>'],
@ -55,6 +56,7 @@
RELEASE_MAPPING = { RELEASE_MAPPING = {
'8.0': { '8.0': {
'api': '1.31',
'rpc': '1.40', 'rpc': '1.40',
'objects': { 'objects': {
'Node': ['1.21'], 'Node': ['1.21'],
@ -67,6 +69,7 @@ RELEASE_MAPPING = {
} }
}, },
'9.0': { '9.0': {
'api': '1.34',
'rpc': '1.41', 'rpc': '1.41',
'objects': { 'objects': {
'Node': ['1.21'], 'Node': ['1.21'],
@ -79,6 +82,7 @@ RELEASE_MAPPING = {
} }
}, },
'9.1': { '9.1': {
'api': '1.34',
'rpc': '1.41', 'rpc': '1.41',
'objects': { 'objects': {
'Node': ['1.21'], 'Node': ['1.21'],
@ -92,6 +96,7 @@ RELEASE_MAPPING = {
}, },
'9.2': { '9.2': {
'rpc': '1.41', 'rpc': '1.41',
'api': '1.35',
'objects': { 'objects': {
'Node': ['1.21'], 'Node': ['1.21'],
'Conductor': ['1.2'], 'Conductor': ['1.2'],
@ -103,6 +108,7 @@ RELEASE_MAPPING = {
} }
}, },
'master': { 'master': {
'api': '1.35',
'rpc': '1.41', 'rpc': '1.41',
'objects': { 'objects': {
'Node': ['1.21'], 'Node': ['1.21'],

View File

@ -275,13 +275,13 @@ service_opts = [
choices=versions.RELEASE_VERSIONS, choices=versions.RELEASE_VERSIONS,
# TODO(xek): mutable=True, # TODO(xek): mutable=True,
help=_('Used for rolling upgrades. Setting this option ' help=_('Used for rolling upgrades. Setting this option '
'downgrades (or pins) the internal ironic RPC ' 'downgrades (or pins) the Bare Metal API, '
'communication and database objects to their respective ' 'the internal ironic RPC communication, and '
'the database objects to their respective '
'versions, so they are compatible with older services. ' 'versions, so they are compatible with older services. '
'When doing a rolling upgrade from version N to version ' 'When doing a rolling upgrade from version N to version '
'N+1, set (to pin) this to N. To unpin (default), leave ' 'N+1, set (to pin) this to N. To unpin (default), leave '
'it unset and the latest versions of RPC communication ' 'it unset and the latest versions will be used.')),
'and database objects will be used.')),
] ]
utils_opts = [ utils_opts = [

View File

@ -77,7 +77,7 @@ class TestListChassis(test_api_base.BaseApiTest):
fields = 'extra,description' fields = 'extra,description'
data = self.get_json( data = self.get_json(
'/chassis/%s?fields=%s' % (chassis.uuid, fields), '/chassis/%s?fields=%s' % (chassis.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
# We always append "links" # We always append "links"
self.assertItemsEqual(['description', 'extra', 'links'], data) self.assertItemsEqual(['description', 'extra', 'links'], data)
@ -89,7 +89,7 @@ class TestListChassis(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/chassis?fields=%s' % fields, '/chassis?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['chassis'])) self.assertEqual(3, len(data['chassis']))
for ch in data['chassis']: for ch in data['chassis']:
@ -101,7 +101,7 @@ class TestListChassis(test_api_base.BaseApiTest):
fields = 'uuid,spongebob' fields = 'uuid,spongebob'
response = self.get_json( response = self.get_json(
'/chassis/%s?fields=%s' % (chassis.uuid, fields), '/chassis/%s?fields=%s' % (chassis.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@ -112,7 +112,7 @@ class TestListChassis(test_api_base.BaseApiTest):
fields = 'uuid,extra' fields = 'uuid,extra'
response = self.get_json( response = self.get_json(
'/chassis/%s?fields=%s' % (chassis.uuid, fields), '/chassis/%s?fields=%s' % (chassis.uuid, fields),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int) self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int)

View File

@ -90,7 +90,8 @@ class TestListNodes(test_api_base.BaseApiTest):
node = obj_utils.create_test_node(self.context, node = obj_utils.create_test_node(self.context,
chassis_id=self.chassis.id) chassis_id=self.chassis.id)
data = self.get_json( data = self.get_json(
'/nodes', headers={api_base.Version.string: str(api_v1.MAX_VER)}) '/nodes',
headers={api_base.Version.string: str(api_v1.max_version())})
self.assertIn('instance_uuid', data['nodes'][0]) self.assertIn('instance_uuid', data['nodes'][0])
self.assertIn('maintenance', data['nodes'][0]) self.assertIn('maintenance', data['nodes'][0])
self.assertIn('power_state', data['nodes'][0]) self.assertIn('power_state', data['nodes'][0])
@ -125,7 +126,7 @@ class TestListNodes(test_api_base.BaseApiTest):
chassis_id=self.chassis.id) chassis_id=self.chassis.id)
data = self.get_json( data = self.get_json(
'/nodes/%s' % node.uuid, '/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(node.uuid, data['uuid']) self.assertEqual(node.uuid, data['uuid'])
self.assertIn('driver', data) self.assertIn('driver', data)
self.assertIn('driver_info', data) self.assertIn('driver_info', data)
@ -184,7 +185,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields = 'extra,instance_info' fields = 'extra,instance_info'
data = self.get_json( data = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields), '/nodes/%s?fields=%s' % (node.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
# We always append "links" # We always append "links"
self.assertItemsEqual(['extra', 'instance_info', 'links'], data) self.assertItemsEqual(['extra', 'instance_info', 'links'], data)
@ -197,7 +198,7 @@ class TestListNodes(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/nodes?fields=%s' % fields, '/nodes?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['nodes'])) self.assertEqual(3, len(data['nodes']))
for node in data['nodes']: for node in data['nodes']:
@ -210,7 +211,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields = 'uuid,spongebob' fields = 'uuid,spongebob'
response = self.get_json( response = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields), '/nodes/%s?fields=%s' % (node.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@ -222,7 +223,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields = 'uuid,extra' fields = 'uuid,extra'
response = self.get_json( response = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields), '/nodes/%s?fields=%s' % (node.uuid, fields),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int) self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int)
@ -233,7 +234,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields = 'driver_info' fields = 'driver_info'
data = self.get_json( data = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields), '/nodes/%s?fields=%s' % (node.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
# We always append "links" # We always append "links"
self.assertItemsEqual(['driver_info', 'links'], data) self.assertItemsEqual(['driver_info', 'links'], data)
self.assertEqual('******', data['driver_info']['fake_password']) self.assertEqual('******', data['driver_info']['fake_password'])
@ -254,7 +255,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields = 'network_interface' fields = 'network_interface'
response = self.get_json( response = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields), '/nodes/%s?fields=%s' % (node.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertIn('network_interface', response) self.assertIn('network_interface', response)
def test_get_all_interface_fields_invalid_api_version(self): def test_get_all_interface_fields_invalid_api_version(self):
@ -273,7 +274,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields_arg = ','.join(api_utils.V31_FIELDS) fields_arg = ','.join(api_utils.V31_FIELDS)
response = self.get_json( response = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields_arg), '/nodes/%s?fields=%s' % (node.uuid, fields_arg),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
for field in api_utils.V31_FIELDS: for field in api_utils.V31_FIELDS:
self.assertIn(field, response) self.assertIn(field, response)
@ -293,7 +294,7 @@ class TestListNodes(test_api_base.BaseApiTest):
fields = 'storage_interface' fields = 'storage_interface'
response = self.get_json( response = self.get_json(
'/nodes/%s?fields=%s' % (node.uuid, fields), '/nodes/%s?fields=%s' % (node.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertIn('storage_interface', response) self.assertIn('storage_interface', response)
def test_detail(self): def test_detail(self):
@ -301,7 +302,7 @@ class TestListNodes(test_api_base.BaseApiTest):
chassis_id=self.chassis.id) chassis_id=self.chassis.id)
data = self.get_json( data = self.get_json(
'/nodes/detail', '/nodes/detail',
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(node.uuid, data['nodes'][0]["uuid"]) self.assertEqual(node.uuid, data['nodes'][0]["uuid"])
self.assertIn('name', data['nodes'][0]) self.assertIn('name', data['nodes'][0])
self.assertIn('driver', data['nodes'][0]) self.assertIn('driver', data['nodes'][0])
@ -339,7 +340,7 @@ class TestListNodes(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/nodes/%s' % node.uuid, '/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}) headers={api_base.Version.string: str(api_v1.min_version())})
self.assertEqual(states.NOSTATE, data['provision_state']) self.assertEqual(states.NOSTATE, data['provision_state'])
data = self.get_json('/nodes/%s' % node.uuid, data = self.get_json('/nodes/%s' % node.uuid,
@ -351,7 +352,7 @@ class TestListNodes(test_api_base.BaseApiTest):
driver_internal_info={"foo": "bar"}) driver_internal_info={"foo": "bar"})
data = self.get_json( data = self.get_json(
'/nodes/%s' % node.uuid, '/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}) headers={api_base.Version.string: str(api_v1.min_version())})
self.assertNotIn('driver_internal_info', data) self.assertNotIn('driver_internal_info', data)
data = self.get_json('/nodes/%s' % node.uuid, data = self.get_json('/nodes/%s' % node.uuid,
@ -375,7 +376,7 @@ class TestListNodes(test_api_base.BaseApiTest):
inspection_started_at=some_time) inspection_started_at=some_time)
data = self.get_json( data = self.get_json(
'/nodes/%s' % node.uuid, '/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}) headers={api_base.Version.string: str(api_v1.min_version())})
self.assertNotIn('inspection_finished_at', data) self.assertNotIn('inspection_finished_at', data)
self.assertNotIn('inspection_started_at', data) self.assertNotIn('inspection_started_at', data)
@ -391,7 +392,7 @@ class TestListNodes(test_api_base.BaseApiTest):
clean_step={"foo": "bar"}) clean_step={"foo": "bar"})
data = self.get_json( data = self.get_json(
'/nodes/%s' % node.uuid, '/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}) headers={api_base.Version.string: str(api_v1.min_version())})
self.assertNotIn('clean_step', data) self.assertNotIn('clean_step', data)
data = self.get_json('/nodes/%s' % node.uuid, data = self.get_json('/nodes/%s' % node.uuid,
@ -737,14 +738,14 @@ class TestListNodes(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/nodes/%s/volume/connectors' % node.uuid, '/nodes/%s/volume/connectors' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(2, len(data['connectors'])) self.assertEqual(2, len(data['connectors']))
self.assertNotIn('next', data) self.assertNotIn('next', data)
# Test collection pagination # Test collection pagination
data = self.get_json( data = self.get_json(
'/nodes/%s/volume/connectors?limit=1' % node.uuid, '/nodes/%s/volume/connectors?limit=1' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(1, len(data['connectors'])) self.assertEqual(1, len(data['connectors']))
self.assertIn('next', data) self.assertIn('next', data)
@ -755,7 +756,7 @@ class TestListNodes(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
'/nodes/volume/connectors', '/nodes/volume/connectors',
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
def test_volume_connectors_subresource_node_not_found(self): def test_volume_connectors_subresource_node_not_found(self):
@ -763,7 +764,7 @@ class TestListNodes(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
'/nodes/%s/volume/connectors' % non_existent_uuid, '/nodes/%s/volume/connectors' % non_existent_uuid,
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
def test_volume_targets_subresource(self): def test_volume_targets_subresource(self):
@ -776,14 +777,14 @@ class TestListNodes(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/nodes/%s/volume/targets' % node.uuid, '/nodes/%s/volume/targets' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(2, len(data['targets'])) self.assertEqual(2, len(data['targets']))
self.assertNotIn('next', data) self.assertNotIn('next', data)
# Test collection pagination # Test collection pagination
data = self.get_json( data = self.get_json(
'/nodes/%s/volume/targets?limit=1' % node.uuid, '/nodes/%s/volume/targets?limit=1' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(1, len(data['targets'])) self.assertEqual(1, len(data['targets']))
self.assertIn('next', data) self.assertIn('next', data)
@ -794,7 +795,7 @@ class TestListNodes(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
'/nodes/volume/targets', '/nodes/volume/targets',
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
def test_volume_targets_subresource_node_not_found(self): def test_volume_targets_subresource_node_not_found(self):
@ -802,7 +803,7 @@ class TestListNodes(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
'/nodes/%s/volume/targets' % non_existent_uuid, '/nodes/%s/volume/targets' % non_existent_uuid,
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@mock.patch.object(timeutils, 'utcnow') @mock.patch.object(timeutils, 'utcnow')
@ -1085,7 +1086,7 @@ class TestListNodes(test_api_base.BaseApiTest):
def test_get_nodes_by_driver_invalid_api_version(self): def test_get_nodes_by_driver_invalid_api_version(self):
response = self.get_json( response = self.get_json(
'/nodes?driver=fake', '/nodes?driver=fake',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code) self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
@ -1147,7 +1148,7 @@ class TestListNodes(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
base_url % 'fake', base_url % 'fake',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code) self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_code)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
@ -1307,7 +1308,7 @@ class TestListNodes(test_api_base.BaseApiTest):
driver_info=driver_info) driver_info=driver_info)
data = self.get_json( data = self.get_json(
'/nodes/%s' % node.uuid, '/nodes/%s' % node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual("******", data["driver_info"]["ssh_password"]) self.assertEqual("******", data["driver_info"]["ssh_password"])
self.assertEqual("******", data["driver_info"]["ssh_key_contents"]) self.assertEqual("******", data["driver_info"]["ssh_key_contents"])
@ -1562,7 +1563,7 @@ class TestPatch(test_api_base.BaseApiTest):
'/nodes/%s/volume/connectors' % self.node.uuid, '/nodes/%s/volume/connectors' % self.node.uuid,
[{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}], [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}],
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
def test_patch_volume_connectors_subresource(self): def test_patch_volume_connectors_subresource(self):
@ -1574,7 +1575,7 @@ class TestPatch(test_api_base.BaseApiTest):
connector.uuid), connector.uuid),
[{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}], [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}],
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
def test_patch_volume_targets_subresource(self): def test_patch_volume_targets_subresource(self):
@ -1585,7 +1586,7 @@ class TestPatch(test_api_base.BaseApiTest):
target.uuid), target.uuid),
[{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}], [{'path': '/extra/foo', 'value': 'bar', 'op': 'add'}],
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
def test_remove_uuid(self): def test_remove_uuid(self):
@ -1943,7 +1944,7 @@ class TestPatch(test_api_base.BaseApiTest):
uuid=uuidutils.generate_uuid()) uuid=uuidutils.generate_uuid())
self.mock_update_node.return_value = node self.mock_update_node.return_value = node
network_interface = 'flat' network_interface = 'flat'
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
response = self.patch_json('/nodes/%s' % node.uuid, response = self.patch_json('/nodes/%s' % node.uuid,
[{'path': '/network_interface', [{'path': '/network_interface',
'value': network_interface, 'value': network_interface,
@ -2029,7 +2030,7 @@ class TestPatch(test_api_base.BaseApiTest):
node = obj_utils.create_test_node(self.context, node = obj_utils.create_test_node(self.context,
uuid=uuidutils.generate_uuid()) uuid=uuidutils.generate_uuid())
self.mock_update_node.return_value = node self.mock_update_node.return_value = node
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
for field in api_utils.V31_FIELDS: for field in api_utils.V31_FIELDS:
response = self.patch_json('/nodes/%s' % node.uuid, response = self.patch_json('/nodes/%s' % node.uuid,
[{'path': '/%s' % field, [{'path': '/%s' % field,
@ -2075,7 +2076,7 @@ class TestPatch(test_api_base.BaseApiTest):
uuid=uuidutils.generate_uuid()) uuid=uuidutils.generate_uuid())
self.mock_update_node.return_value = node self.mock_update_node.return_value = node
storage_interface = 'cinder' storage_interface = 'cinder'
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
response = self.patch_json('/nodes/%s' % node.uuid, response = self.patch_json('/nodes/%s' % node.uuid,
[{'path': '/storage_interface', [{'path': '/storage_interface',
'value': storage_interface, 'value': storage_interface,
@ -2473,7 +2474,7 @@ class TestPost(test_api_base.BaseApiTest):
response = self.post_json( response = self.post_json(
'/nodes/volume/connectors', pdict, '/nodes/volume/connectors', pdict,
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
def test_post_volume_connectors_subresource(self): def test_post_volume_connectors_subresource(self):
@ -2483,7 +2484,7 @@ class TestPost(test_api_base.BaseApiTest):
response = self.post_json( response = self.post_json(
'/nodes/%s/volume/connectors' % node.uuid, pdict, '/nodes/%s/volume/connectors' % node.uuid, pdict,
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
def test_post_volume_targets_subresource(self): def test_post_volume_targets_subresource(self):
@ -2493,7 +2494,7 @@ class TestPost(test_api_base.BaseApiTest):
response = self.post_json( response = self.post_json(
'/nodes/%s/volume/targets' % node.uuid, pdict, '/nodes/%s/volume/targets' % node.uuid, pdict,
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
def test_create_node_no_mandatory_field_driver(self): def test_create_node_no_mandatory_field_driver(self):
@ -2589,11 +2590,11 @@ class TestPost(test_api_base.BaseApiTest):
network_interface='flat') network_interface='flat')
response = self.post_json('/nodes', ndict, response = self.post_json('/nodes', ndict,
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MAX_VER)}) str(api_v1.max_version())})
self.assertEqual(http_client.CREATED, response.status_int) self.assertEqual(http_client.CREATED, response.status_int)
result = self.get_json('/nodes/%s' % ndict['uuid'], result = self.get_json('/nodes/%s' % ndict['uuid'],
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MAX_VER)}) str(api_v1.max_version())})
self.assertEqual('flat', result['network_interface']) self.assertEqual('flat', result['network_interface'])
def test_create_node_network_interface_old_api_version(self): def test_create_node_network_interface_old_api_version(self):
@ -2608,7 +2609,7 @@ class TestPost(test_api_base.BaseApiTest):
network_interface='foo') network_interface='foo')
response = self.post_json('/nodes', ndict, expect_errors=True, response = self.post_json('/nodes', ndict, expect_errors=True,
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MAX_VER)}) str(api_v1.max_version())})
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
@ -2617,11 +2618,11 @@ class TestPost(test_api_base.BaseApiTest):
resource_class='foo') resource_class='foo')
response = self.post_json('/nodes', ndict, response = self.post_json('/nodes', ndict,
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MAX_VER)}) str(api_v1.max_version())})
self.assertEqual(http_client.CREATED, response.status_int) self.assertEqual(http_client.CREATED, response.status_int)
result = self.get_json('/nodes/%s' % ndict['uuid'], result = self.get_json('/nodes/%s' % ndict['uuid'],
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MAX_VER)}) str(api_v1.max_version())})
self.assertEqual('foo', result['resource_class']) self.assertEqual('foo', result['resource_class'])
def test_create_node_resource_class_old_api_version(self): def test_create_node_resource_class_old_api_version(self):
@ -2643,7 +2644,7 @@ class TestPost(test_api_base.BaseApiTest):
ndict = test_api_utils.post_get_test_node(storage_interface='foo') ndict = test_api_utils.post_get_test_node(storage_interface='foo')
response = self.post_json('/nodes', ndict, expect_errors=True, response = self.post_json('/nodes', ndict, expect_errors=True,
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MAX_VER)}) str(api_v1.max_version())})
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
@ -2750,7 +2751,7 @@ class TestDelete(test_api_base.BaseApiTest):
response = self.delete( response = self.delete(
'/nodes/%s/volume/connectors' % node.uuid, '/nodes/%s/volume/connectors' % node.uuid,
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
def test_delete_volume_connectors_subresource(self): def test_delete_volume_connectors_subresource(self):
@ -2760,7 +2761,7 @@ class TestDelete(test_api_base.BaseApiTest):
response = self.delete( response = self.delete(
'/nodes/%s/volume/connectors/%s' % (node.uuid, connector.uuid), '/nodes/%s/volume/connectors/%s' % (node.uuid, connector.uuid),
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
def test_delete_volume_targets_subresource(self): def test_delete_volume_targets_subresource(self):
@ -2770,7 +2771,7 @@ class TestDelete(test_api_base.BaseApiTest):
response = self.delete( response = self.delete(
'/nodes/%s/volume/targets/%s' % (node.uuid, target.uuid), '/nodes/%s/volume/targets/%s' % (node.uuid, target.uuid),
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
@mock.patch.object(notification_utils, '_emit_api_notification') @mock.patch.object(notification_utils, '_emit_api_notification')

View File

@ -233,7 +233,7 @@ class TestListPorts(test_api_base.BaseApiTest):
fields = 'address,extra' fields = 'address,extra'
data = self.get_json( data = self.get_json(
'/ports/%s?fields=%s' % (port.uuid, fields), '/ports/%s?fields=%s' % (port.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
# We always append "links" # We always append "links"
self.assertItemsEqual(['address', 'extra', 'links'], data) self.assertItemsEqual(['address', 'extra', 'links'], data)
@ -242,7 +242,7 @@ class TestListPorts(test_api_base.BaseApiTest):
internal_info={"foo": "bar"}) internal_info={"foo": "bar"})
data = self.get_json( data = self.get_json(
'/ports/%s' % port.uuid, '/ports/%s' % port.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}) headers={api_base.Version.string: str(api_v1.min_version())})
self.assertNotIn('internal_info', data) self.assertNotIn('internal_info', data)
data = self.get_json('/ports/%s' % port.uuid, data = self.get_json('/ports/%s' % port.uuid,
@ -313,7 +313,7 @@ class TestListPorts(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/ports?fields=%s' % fields, '/ports?fields=%s' % fields,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(3, len(data['ports'])) self.assertEqual(3, len(data['ports']))
for port in data['ports']: for port in data['ports']:
@ -325,7 +325,7 @@ class TestListPorts(test_api_base.BaseApiTest):
fields = 'uuid,spongebob' fields = 'uuid,spongebob'
response = self.get_json( response = self.get_json(
'/ports/%s?fields=%s' % (port.uuid, fields), '/ports/%s?fields=%s' % (port.uuid, fields),
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@ -336,7 +336,7 @@ class TestListPorts(test_api_base.BaseApiTest):
fields = 'uuid,extra' fields = 'uuid,extra'
response = self.get_json( response = self.get_json(
'/ports/%s?fields=%s' % (port.uuid, fields), '/ports/%s?fields=%s' % (port.uuid, fields),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int) self.assertEqual(http_client.NOT_ACCEPTABLE, response.status_int)
@ -380,7 +380,7 @@ class TestListPorts(test_api_base.BaseApiTest):
physical_network='physnet1') physical_network='physnet1')
data = self.get_json( data = self.get_json(
'/ports/detail', '/ports/detail',
headers={api_base.Version.string: str(api_v1.MAX_VER)} headers={api_base.Version.string: str(api_v1.max_version())}
) )
self.assertEqual(port.uuid, data['ports'][0]["uuid"]) self.assertEqual(port.uuid, data['ports'][0]["uuid"])
self.assertIn('extra', data['ports'][0]) self.assertIn('extra', data['ports'][0])
@ -519,7 +519,7 @@ class TestListPorts(test_api_base.BaseApiTest):
for invalid_key in invalid_keys_list: for invalid_key in invalid_keys_list:
response = self.get_json( response = self.get_json(
'/ports?sort_key=%s' % invalid_key, expect_errors=True, '/ports?sort_key=%s' % invalid_key, expect_errors=True,
headers={api_base.Version.string: str(api_v1.MAX_VER)} headers={api_base.Version.string: str(api_v1.max_version())}
) )
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
@ -535,7 +535,7 @@ class TestListPorts(test_api_base.BaseApiTest):
address='52:54:00:cf:2d:3%s' % id_, address='52:54:00:cf:2d:3%s' % id_,
pxe_enabled=id_ % 2) pxe_enabled=id_ % 2)
port_uuids.append(port.uuid) port_uuids.append(port.uuid)
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
detail_str = '/detail' if detail else '' detail_str = '/detail' if detail else ''
data = self.get_json('/ports%s?sort_key=pxe_enabled' % detail_str, data = self.get_json('/ports%s?sort_key=pxe_enabled' % detail_str,
headers=headers) headers=headers)
@ -1268,7 +1268,7 @@ class TestPatch(test_api_base.BaseApiTest):
def test_invalid_physnet_non_text(self, mock_upd): def test_invalid_physnet_non_text(self, mock_upd):
physnet = 1234 physnet = 1234
headers = {api_base.Version.string: versions.MAX_VERSION_STRING} headers = {api_base.Version.string: versions.max_version_string()}
response = self.patch_json('/ports/%s' % self.port.uuid, response = self.patch_json('/ports/%s' % self.port.uuid,
[{'path': '/physical_network', [{'path': '/physical_network',
'value': physnet, 'value': physnet,
@ -1281,7 +1281,7 @@ class TestPatch(test_api_base.BaseApiTest):
def test_invalid_physnet_too_long(self, mock_upd): def test_invalid_physnet_too_long(self, mock_upd):
physnet = 'p' * 65 physnet = 'p' * 65
headers = {api_base.Version.string: versions.MAX_VERSION_STRING} headers = {api_base.Version.string: versions.max_version_string()}
response = self.patch_json('/ports/%s' % self.port.uuid, response = self.patch_json('/ports/%s' % self.port.uuid,
[{'path': '/physical_network', [{'path': '/physical_network',
'value': physnet, 'value': physnet,
@ -1319,7 +1319,7 @@ class TestPost(test_api_base.BaseApiTest):
self.portgroup = obj_utils.create_test_portgroup(self.context, self.portgroup = obj_utils.create_test_portgroup(self.context,
node_id=self.node.id) node_id=self.node.id)
self.headers = {api_base.Version.string: str( self.headers = {api_base.Version.string: str(
versions.MAX_VERSION_STRING)} versions.max_version_string())}
p = mock.patch.object(rpcapi.ConductorAPI, 'get_topic_for') p = mock.patch.object(rpcapi.ConductorAPI, 'get_topic_for')
self.mock_gtf = p.start() self.mock_gtf = p.start()
@ -1370,7 +1370,7 @@ class TestPost(test_api_base.BaseApiTest):
pdict.pop('pxe_enabled') pdict.pop('pxe_enabled')
pdict.pop('extra') pdict.pop('extra')
pdict.pop('physical_network') pdict.pop('physical_network')
headers = {api_base.Version.string: str(api_v1.MIN_VER)} headers = {api_base.Version.string: str(api_v1.min_version())}
response = self.post_json('/ports', pdict, headers=headers) response = self.post_json('/ports', pdict, headers=headers)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(http_client.CREATED, response.status_int) self.assertEqual(http_client.CREATED, response.status_int)

View File

@ -51,7 +51,7 @@ class TestPortgroupObject(base.TestCase):
class TestListPortgroups(test_api_base.BaseApiTest): class TestListPortgroups(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestListPortgroups, self).setUp() super(TestListPortgroups, self).setUp()
@ -152,7 +152,7 @@ class TestListPortgroups(test_api_base.BaseApiTest):
node_id=self.node.id) node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/portgroups/%s' % (portgroup.uuid), '/portgroups/%s' % (portgroup.uuid),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -170,7 +170,7 @@ class TestListPortgroups(test_api_base.BaseApiTest):
def test_detail_invalid_api_version(self): def test_detail_invalid_api_version(self):
response = self.get_json( response = self.get_json(
'/portgroups/detail', '/portgroups/detail',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -274,14 +274,14 @@ class TestListPortgroups(test_api_base.BaseApiTest):
# Test get one old api version, /portgroups controller not allowed # Test get one old api version, /portgroups controller not allowed
response = self.get_json('/portgroups/%s/ports/%s' % ( response = self.get_json('/portgroups/%s/ports/%s' % (
pg.uuid, uuidutils.generate_uuid()), pg.uuid, uuidutils.generate_uuid()),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
# Test get one not allowed to access to /portgroups/<uuid>/ports/<uuid> # Test get one not allowed to access to /portgroups/<uuid>/ports/<uuid>
response = self.get_json( response = self.get_json(
'/portgroups/%s/ports/%s' % (pg.uuid, uuidutils.generate_uuid()), '/portgroups/%s/ports/%s' % (pg.uuid, uuidutils.generate_uuid()),
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.FORBIDDEN, response.status_int) self.assertEqual(http_client.FORBIDDEN, response.status_int)
@ -471,7 +471,7 @@ class TestListPortgroups(test_api_base.BaseApiTest):
@mock.patch.object(rpcapi.ConductorAPI, 'update_portgroup') @mock.patch.object(rpcapi.ConductorAPI, 'update_portgroup')
class TestPatch(test_api_base.BaseApiTest): class TestPatch(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestPatch, self).setUp() super(TestPatch, self).setUp()
@ -865,7 +865,7 @@ class TestPatch(test_api_base.BaseApiTest):
'op': 'replace'}], 'op': 'replace'}],
expect_errors=True, expect_errors=True,
headers={api_base.Version.string: headers={api_base.Version.string:
str(api_v1.MIN_VER)}) str(api_v1.min_version())})
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
self.assertTrue(response.json['error_message']) self.assertTrue(response.json['error_message'])
@ -929,7 +929,7 @@ class TestPatch(test_api_base.BaseApiTest):
class TestPost(test_api_base.BaseApiTest): class TestPost(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestPost, self).setUp() super(TestPost, self).setUp()
@ -1205,7 +1205,7 @@ class TestPost(test_api_base.BaseApiTest):
@mock.patch.object(rpcapi.ConductorAPI, 'destroy_portgroup') @mock.patch.object(rpcapi.ConductorAPI, 'destroy_portgroup')
class TestDelete(test_api_base.BaseApiTest): class TestDelete(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestDelete, self).setUp() super(TestDelete, self).setUp()

View File

@ -65,14 +65,14 @@ class TestLookup(test_api_base.BaseApiTest):
def test_nothing_provided(self): def test_nothing_provided(self):
response = self.get_json( response = self.get_json(
'/lookup', '/lookup',
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.BAD_REQUEST, response.status_int) self.assertEqual(http_client.BAD_REQUEST, response.status_int)
def test_not_found(self): def test_not_found(self):
response = self.get_json( response = self.get_json(
'/lookup?addresses=%s' % ','.join(self.addresses), '/lookup?addresses=%s' % ','.join(self.addresses),
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -83,7 +83,7 @@ class TestLookup(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
'/lookup?addresses=%s' % ','.join(self.addresses), '/lookup?addresses=%s' % ','.join(self.addresses),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -94,7 +94,7 @@ class TestLookup(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/lookup?addresses=%s' % ','.join(self.addresses), '/lookup?addresses=%s' % ','.join(self.addresses),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid']) self.assertEqual(self.node.uuid, data['node']['uuid'])
self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'}, self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'},
set(data['node'])) set(data['node']))
@ -110,7 +110,7 @@ class TestLookup(test_api_base.BaseApiTest):
':f4:52:14:03:00:54:06:c2,' + ','.join(self.addresses)) ':f4:52:14:03:00:54:06:c2,' + ','.join(self.addresses))
data = self.get_json( data = self.get_json(
'/lookup?addresses=%s' % addresses, '/lookup?addresses=%s' % addresses,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid']) self.assertEqual(self.node.uuid, data['node']['uuid'])
self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'}, self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'},
set(data['node'])) set(data['node']))
@ -121,7 +121,7 @@ class TestLookup(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/lookup?addresses=%s&node_uuid=%s' % '/lookup?addresses=%s&node_uuid=%s' %
(','.join(self.addresses), self.node.uuid), (','.join(self.addresses), self.node.uuid),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid']) self.assertEqual(self.node.uuid, data['node']['uuid'])
self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'}, self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'},
set(data['node'])) set(data['node']))
@ -130,7 +130,7 @@ class TestLookup(test_api_base.BaseApiTest):
def test_found_by_only_uuid(self): def test_found_by_only_uuid(self):
data = self.get_json( data = self.get_json(
'/lookup?node_uuid=%s' % self.node.uuid, '/lookup?node_uuid=%s' % self.node.uuid,
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node.uuid, data['node']['uuid']) self.assertEqual(self.node.uuid, data['node']['uuid'])
self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'}, self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'},
set(data['node'])) set(data['node']))
@ -140,7 +140,7 @@ class TestLookup(test_api_base.BaseApiTest):
response = self.get_json( response = self.get_json(
'/lookup?addresses=%s&node_uuid=%s' % '/lookup?addresses=%s&node_uuid=%s' %
(','.join(self.addresses), self.node2.uuid), (','.join(self.addresses), self.node2.uuid),
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -149,7 +149,7 @@ class TestLookup(test_api_base.BaseApiTest):
data = self.get_json( data = self.get_json(
'/lookup?addresses=%s&node_uuid=%s' % '/lookup?addresses=%s&node_uuid=%s' %
(','.join(self.addresses), self.node2.uuid), (','.join(self.addresses), self.node2.uuid),
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(self.node2.uuid, data['node']['uuid']) self.assertEqual(self.node2.uuid, data['node']['uuid'])
self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'}, self.assertEqual(set(ramdisk._LOOKUP_RETURN_FIELDS) | {'links'},
set(data['node'])) set(data['node']))
@ -163,7 +163,7 @@ class TestHeartbeat(test_api_base.BaseApiTest):
response = self.post_json( response = self.post_json(
'/heartbeat/%s' % uuidutils.generate_uuid(), '/heartbeat/%s' % uuidutils.generate_uuid(),
{'callback_url': 'url'}, {'callback_url': 'url'},
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -171,7 +171,7 @@ class TestHeartbeat(test_api_base.BaseApiTest):
response = self.post_json( response = self.post_json(
'/heartbeat/%s' % uuidutils.generate_uuid(), '/heartbeat/%s' % uuidutils.generate_uuid(),
{'callback_url': 'url'}, {'callback_url': 'url'},
headers={api_base.Version.string: str(api_v1.MAX_VER)}, headers={api_base.Version.string: str(api_v1.max_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -181,7 +181,7 @@ class TestHeartbeat(test_api_base.BaseApiTest):
response = self.post_json( response = self.post_json(
'/heartbeat/%s' % node.uuid, '/heartbeat/%s' % node.uuid,
{'callback_url': 'url'}, {'callback_url': 'url'},
headers={api_base.Version.string: str(api_v1.MAX_VER)}) headers={api_base.Version.string: str(api_v1.max_version())})
self.assertEqual(http_client.ACCEPTED, response.status_int) self.assertEqual(http_client.ACCEPTED, response.status_int)
self.assertEqual(b'', response.body) self.assertEqual(b'', response.body)
mock_heartbeat.assert_called_once_with(mock.ANY, mock.ANY, mock_heartbeat.assert_called_once_with(mock.ANY, mock.ANY,

View File

@ -40,7 +40,7 @@ class TestCheckVersions(test_base.TestCase):
def test_check_version_invalid_major_version(self): def test_check_version_invalid_major_version(self):
self.version.major = v1_api.BASE_VERSION + 1 self.version.major = v1_api.BASE_VERSION + 1
self.version.minor = v1_api.MIN_VER.minor self.version.minor = v1_api.min_version().minor
self.assertRaises( self.assertRaises(
webob_exc.HTTPNotAcceptable, webob_exc.HTTPNotAcceptable,
v1_api.Controller()._check_version, v1_api.Controller()._check_version,
@ -48,7 +48,7 @@ class TestCheckVersions(test_base.TestCase):
def test_check_version_too_low(self): def test_check_version_too_low(self):
self.version.major = v1_api.BASE_VERSION self.version.major = v1_api.BASE_VERSION
self.version.minor = v1_api.MIN_VER.minor - 1 self.version.minor = v1_api.min_version().minor - 1
self.assertRaises( self.assertRaises(
webob_exc.HTTPNotAcceptable, webob_exc.HTTPNotAcceptable,
v1_api.Controller()._check_version, v1_api.Controller()._check_version,
@ -56,14 +56,14 @@ class TestCheckVersions(test_base.TestCase):
def test_check_version_too_high(self): def test_check_version_too_high(self):
self.version.major = v1_api.BASE_VERSION self.version.major = v1_api.BASE_VERSION
self.version.minor = v1_api.MAX_VER.minor + 1 self.version.minor = v1_api.max_version().minor + 1
e = self.assertRaises( e = self.assertRaises(
webob_exc.HTTPNotAcceptable, webob_exc.HTTPNotAcceptable,
v1_api.Controller()._check_version, v1_api.Controller()._check_version,
self.version, {'fake-headers': v1_api.MAX_VER.minor}) self.version, {'fake-headers': v1_api.max_version().minor})
self.assertEqual(v1_api.MAX_VER.minor, e.headers['fake-headers']) self.assertEqual(v1_api.max_version().minor, e.headers['fake-headers'])
def test_check_version_ok(self): def test_check_version_ok(self):
self.version.major = v1_api.BASE_VERSION self.version.major = v1_api.BASE_VERSION
self.version.minor = v1_api.MIN_VER.minor self.version.minor = v1_api.min_version().minor
v1_api.Controller()._check_version(self.version) v1_api.Controller()._check_version(self.version)

View File

@ -17,7 +17,11 @@ Tests for the versions constants and methods.
import re import re
import mock
from ironic.api.controllers.v1 import versions from ironic.api.controllers.v1 import versions
from ironic.common import release_mappings
from ironic.conf import CONF
from ironic.tests import base from ironic.tests import base
@ -36,16 +40,16 @@ class TestVersionConstants(base.TestCase):
self.minor_consts.sort(key=minor_key) self.minor_consts.sort(key=minor_key)
def test_max_ver_str(self): def test_max_ver_str(self):
# Test to make sure MAX_VERSION_STRING corresponds with the largest # Test to make sure _MAX_VERSION_STRING corresponds with the largest
# MINOR_ constant # MINOR_ constant
max_ver = '1.{}'.format(getattr(versions, self.minor_consts[-1])) max_ver = '1.{}'.format(getattr(versions, self.minor_consts[-1]))
self.assertEqual(max_ver, versions.MAX_VERSION_STRING) self.assertEqual(max_ver, versions._MAX_VERSION_STRING)
def test_min_ver_str(self): def test_min_ver_str(self):
# Try to make sure someone doesn't change the MIN_VERSION_STRING by # Try to make sure someone doesn't change the _MIN_VERSION_STRING by
# accident and make sure it exists # accident and make sure it exists
self.assertEqual('1.1', versions.MIN_VERSION_STRING) self.assertEqual('1.1', versions._MIN_VERSION_STRING)
def test_name_value_match(self): def test_name_value_match(self):
# Test to make sure variable name matches the value. For example # Test to make sure variable name matches the value. For example
@ -67,3 +71,25 @@ class TestVersionConstants(base.TestCase):
value, seen_values, value, seen_values,
'The value {} has been used more than once'.format(value)) 'The value {} has been used more than once'.format(value))
seen_values.add(value) seen_values.add(value)
class TestMaxVersionString(base.TestCase):
def test_max_version_not_pinned(self):
CONF.set_override('pin_release_version', None)
self.assertEqual(versions._MAX_VERSION_STRING,
versions.max_version_string())
@mock.patch('ironic.common.release_mappings.RELEASE_MAPPING',
autospec=True)
def test_max_version_pinned(self, mock_release_mapping):
CONF.set_override('pin_release_version',
release_mappings.RELEASE_VERSIONS[-1])
mock_release_mapping.get.return_value = {
'api': '1.5',
'rpc': '1.4',
'objects': {
'MyObj': ['1.4'],
}
}
self.assertEqual('1.5', versions.max_version_string())

View File

@ -32,7 +32,7 @@ class TestGetVolume(test_api_base.BaseApiTest):
headers=headers)) headers=headers))
def test_get_volume(self): def test_get_volume(self):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
data = self.get_json('/volume/', headers=headers) data = self.get_json('/volume/', headers=headers)
for key in ['links', 'connectors', 'targets']: for key in ['links', 'connectors', 'targets']:
self._test_links(data, key, headers) self._test_links(data, key, headers)
@ -46,7 +46,7 @@ class TestGetVolume(test_api_base.BaseApiTest):
data['targets'][1]['href']) data['targets'][1]['href'])
def test_get_volume_invalid_api_version(self): def test_get_volume_invalid_api_version(self):
headers = {api_base.Version.string: str(api_v1.MIN_VER)} headers = {api_base.Version.string: str(api_v1.min_version())}
response = self.get_json('/volume/', headers=headers, response = self.get_json('/volume/', headers=headers,
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)

View File

@ -59,7 +59,7 @@ class TestVolumeConnectorObject(base.TestCase):
class TestListVolumeConnectors(test_api_base.BaseApiTest): class TestListVolumeConnectors(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestListVolumeConnectors, self).setUp() super(TestListVolumeConnectors, self).setUp()
@ -83,7 +83,7 @@ class TestListVolumeConnectors(test_api_base.BaseApiTest):
node_id=self.node.id) node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/volume/connectors', '/volume/connectors',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -103,7 +103,7 @@ class TestListVolumeConnectors(test_api_base.BaseApiTest):
self.context, node_id=self.node.id) self.context, node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/volume/connectors/%s' % connector.uuid, '/volume/connectors/%s' % connector.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -151,7 +151,7 @@ class TestListVolumeConnectors(test_api_base.BaseApiTest):
fields = 'uuid,extra' fields = 'uuid,extra'
response = self.get_json( response = self.get_json(
'/volume/connectors/%s?fields=%s' % (connector.uuid, fields), '/volume/connectors/%s?fields=%s' % (connector.uuid, fields),
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -181,7 +181,7 @@ class TestListVolumeConnectors(test_api_base.BaseApiTest):
node_id=self.node.id) node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/volume/connectors?detail=True', '/volume/connectors?detail=True',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -348,7 +348,7 @@ class TestListVolumeConnectors(test_api_base.BaseApiTest):
@mock.patch.object(rpcapi.ConductorAPI, 'update_volume_connector') @mock.patch.object(rpcapi.ConductorAPI, 'update_volume_connector')
class TestPatch(test_api_base.BaseApiTest): class TestPatch(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestPatch, self).setUp() super(TestPatch, self).setUp()
@ -388,7 +388,7 @@ class TestPatch(test_api_base.BaseApiTest):
node_uuid=self.node.uuid)]) node_uuid=self.node.uuid)])
def test_update_invalid_api_version(self, mock_upd): def test_update_invalid_api_version(self, mock_upd):
headers = {api_base.Version.string: str(api_v1.MIN_VER)} headers = {api_base.Version.string: str(api_v1.min_version())}
response = self.patch_json('/volume/connectors/%s' response = self.patch_json('/volume/connectors/%s'
% self.connector.uuid, % self.connector.uuid,
[{'path': '/extra/foo', [{'path': '/extra/foo',
@ -714,7 +714,7 @@ class TestPatch(test_api_base.BaseApiTest):
class TestPost(test_api_base.BaseApiTest): class TestPost(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestPost, self).setUp() super(TestPost, self).setUp()
@ -754,7 +754,7 @@ class TestPost(test_api_base.BaseApiTest):
pdict = post_get_test_volume_connector() pdict = post_get_test_volume_connector()
response = self.post_json( response = self.post_json(
'/volume/connectors', pdict, '/volume/connectors', pdict,
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -879,7 +879,7 @@ class TestPost(test_api_base.BaseApiTest):
@mock.patch.object(rpcapi.ConductorAPI, 'destroy_volume_connector') @mock.patch.object(rpcapi.ConductorAPI, 'destroy_volume_connector')
class TestDelete(test_api_base.BaseApiTest): class TestDelete(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestDelete, self).setUp() super(TestDelete, self).setUp()
@ -907,7 +907,7 @@ class TestDelete(test_api_base.BaseApiTest):
node_uuid=self.node.uuid)]) node_uuid=self.node.uuid)])
def test_delete_volume_connector_byid_invalid_api_version(self, mock_dvc): def test_delete_volume_connector_byid_invalid_api_version(self, mock_dvc):
headers = {api_base.Version.string: str(api_v1.MIN_VER)} headers = {api_base.Version.string: str(api_v1.min_version())}
response = self.delete('/volume/connectors/%s' % self.connector.uuid, response = self.delete('/volume/connectors/%s' % self.connector.uuid,
expect_errors=True, headers=headers) expect_errors=True, headers=headers)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)

View File

@ -59,7 +59,7 @@ class TestVolumeTargetObject(base.TestCase):
class TestListVolumeTargets(test_api_base.BaseApiTest): class TestListVolumeTargets(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestListVolumeTargets, self).setUp() super(TestListVolumeTargets, self).setUp()
@ -83,7 +83,7 @@ class TestListVolumeTargets(test_api_base.BaseApiTest):
self.context, node_id=self.node.id) self.context, node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/volume/targets', '/volume/targets',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -103,7 +103,7 @@ class TestListVolumeTargets(test_api_base.BaseApiTest):
node_id=self.node.id) node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/volume/targets/%s' % target.uuid, '/volume/targets/%s' % target.uuid,
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -170,7 +170,7 @@ class TestListVolumeTargets(test_api_base.BaseApiTest):
node_id=self.node.id) node_id=self.node.id)
response = self.get_json( response = self.get_json(
'/volume/targets?detail=True', '/volume/targets?detail=True',
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -328,7 +328,7 @@ class TestListVolumeTargets(test_api_base.BaseApiTest):
@mock.patch.object(rpcapi.ConductorAPI, 'update_volume_target') @mock.patch.object(rpcapi.ConductorAPI, 'update_volume_target')
class TestPatch(test_api_base.BaseApiTest): class TestPatch(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestPatch, self).setUp() super(TestPatch, self).setUp()
@ -368,7 +368,7 @@ class TestPatch(test_api_base.BaseApiTest):
node_uuid=self.node.uuid)]) node_uuid=self.node.uuid)])
def test_update_byid_invalid_api_version(self, mock_upd): def test_update_byid_invalid_api_version(self, mock_upd):
headers = {api_base.Version.string: str(api_v1.MIN_VER)} headers = {api_base.Version.string: str(api_v1.min_version())}
response = self.patch_json('/volume/targets/%s' response = self.patch_json('/volume/targets/%s'
% self.target.uuid, % self.target.uuid,
[{'path': '/extra/foo', [{'path': '/extra/foo',
@ -702,7 +702,7 @@ class TestPatch(test_api_base.BaseApiTest):
class TestPost(test_api_base.BaseApiTest): class TestPost(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestPost, self).setUp() super(TestPost, self).setUp()
@ -742,7 +742,7 @@ class TestPost(test_api_base.BaseApiTest):
pdict = post_get_test_volume_target() pdict = post_get_test_volume_target()
response = self.post_json( response = self.post_json(
'/volume/targets', pdict, '/volume/targets', pdict,
headers={api_base.Version.string: str(api_v1.MIN_VER)}, headers={api_base.Version.string: str(api_v1.min_version())},
expect_errors=True) expect_errors=True)
self.assertEqual(http_client.NOT_FOUND, response.status_int) self.assertEqual(http_client.NOT_FOUND, response.status_int)
@ -860,7 +860,7 @@ class TestPost(test_api_base.BaseApiTest):
@mock.patch.object(rpcapi.ConductorAPI, 'destroy_volume_target') @mock.patch.object(rpcapi.ConductorAPI, 'destroy_volume_target')
class TestDelete(test_api_base.BaseApiTest): class TestDelete(test_api_base.BaseApiTest):
headers = {api_base.Version.string: str(api_v1.MAX_VER)} headers = {api_base.Version.string: str(api_v1.max_version())}
def setUp(self): def setUp(self):
super(TestDelete, self).setUp() super(TestDelete, self).setUp()
@ -889,7 +889,7 @@ class TestDelete(test_api_base.BaseApiTest):
node_uuid=self.node.uuid)]) node_uuid=self.node.uuid)])
def test_delete_volume_target_byid_invalid_api_version(self, mock_dvc): def test_delete_volume_target_byid_invalid_api_version(self, mock_dvc):
headers = {api_base.Version.string: str(api_v1.MIN_VER)} headers = {api_base.Version.string: str(api_v1.min_version())}
response = self.delete('/volume/targets/%s' % self.target.uuid, response = self.delete('/volume/targets/%s' % self.target.uuid,
headers=headers, headers=headers,
expect_errors=True) expect_errors=True)

View File

@ -31,8 +31,9 @@ class TestRoot(base.BaseApiTest):
version1 = response['default_version'] version1 = response['default_version']
self.assertEqual('v1', version1['id']) self.assertEqual('v1', version1['id'])
self.assertEqual('CURRENT', version1['status']) self.assertEqual('CURRENT', version1['status'])
self.assertEqual(versions.MIN_VERSION_STRING, version1['min_version']) self.assertEqual(versions.min_version_string(),
self.assertEqual(versions.MAX_VERSION_STRING, version1['version']) version1['min_version'])
self.assertEqual(versions.max_version_string(), version1['version'])
class TestV1Root(base.BaseApiTest): class TestV1Root(base.BaseApiTest):

View File

@ -16,6 +16,7 @@ import mock
from oslo_utils import versionutils from oslo_utils import versionutils
import six import six
from ironic.api.controllers.v1 import versions as api_versions
from ironic.common import release_mappings from ironic.common import release_mappings
from ironic.conductor import rpcapi from ironic.conductor import rpcapi
from ironic.db.sqlalchemy import models from ironic.db.sqlalchemy import models
@ -49,7 +50,11 @@ class ReleaseMappingsTestCase(base.TestCase):
def test_structure(self): def test_structure(self):
for value in release_mappings.RELEASE_MAPPING.values(): for value in release_mappings.RELEASE_MAPPING.values():
self.assertIsInstance(value, dict) self.assertIsInstance(value, dict)
self.assertEqual({'rpc', 'objects'}, set(value)) self.assertEqual({'api', 'rpc', 'objects'}, set(value))
self.assertIsInstance(value['api'], six.string_types)
(major, minor) = value['api'].split('.')
self.assertEqual(1, int(major))
self.assertLessEqual(int(minor), api_versions.MINOR_MAX_VERSION)
self.assertIsInstance(value['rpc'], six.string_types) self.assertIsInstance(value['rpc'], six.string_types)
self.assertIsInstance(value['objects'], dict) self.assertIsInstance(value['objects'], dict)
for obj_value in value['objects'].values(): for obj_value in value['objects'].values():
@ -110,6 +115,7 @@ class GetObjectVersionsTestCase(base.TestCase):
TEST_MAPPING = { TEST_MAPPING = {
'7.0': { '7.0': {
'api': '1.30',
'rpc': '1.40', 'rpc': '1.40',
'objects': { 'objects': {
'Node': ['1.21'], 'Node': ['1.21'],
@ -119,6 +125,7 @@ class GetObjectVersionsTestCase(base.TestCase):
} }
}, },
'8.0': { '8.0': {
'api': '1.30',
'rpc': '1.40', 'rpc': '1.40',
'objects': { 'objects': {
'Node': ['1.22'], 'Node': ['1.22'],
@ -129,6 +136,7 @@ class GetObjectVersionsTestCase(base.TestCase):
} }
}, },
'master': { 'master': {
'api': '1.34',
'rpc': '1.40', 'rpc': '1.40',
'objects': { 'objects': {
'Node': ['1.23'], 'Node': ['1.23'],

View File

@ -0,0 +1,8 @@
---
upgrade:
- |
During a `rolling upgrade
<https://docs.openstack.org/ironic/latest/admin/upgrade-guide.html#during-maintenance-window>`_
when the new services are pinned to the old release,
the Bare Metal API version will also be pinned to the old release. This will
prevent new features from being accessed until after the upgrade is done.