Create a versions.py file
Create constants for the versions and put them into versions.py. Use these constants instead of unnamed numerical constants. In the future, versions.py, could possibly contain more than constants. Possibly helper functions related to versioning could be placed in it. Change-Id: I8c68133e68d77ac451506b3a5bae038b641ed31f
This commit is contained in:
parent
16c5e5aecc
commit
3c5dde4ea5
|
@ -33,44 +33,18 @@ from ironic.api.controllers.v1 import chassis
|
|||
from ironic.api.controllers.v1 import driver
|
||||
from ironic.api.controllers.v1 import node
|
||||
from ironic.api.controllers.v1 import port
|
||||
from ironic.api.controllers.v1 import versions
|
||||
from ironic.api import expose
|
||||
from ironic.common.i18n import _
|
||||
|
||||
BASE_VERSION = 1
|
||||
BASE_VERSION = versions.BASE_VERSION
|
||||
|
||||
# Here goes a short log of changes in every version.
|
||||
# Refer to doc/source/webapi/v1.rst for a detailed explanation of what
|
||||
# each version contains, and don't forget to update it when introducing
|
||||
# a new version.
|
||||
#
|
||||
# v1.0: corresponds to Juno API, not supported since Kilo
|
||||
# v1.1: API at the point in time when versioning support was added,
|
||||
# covers the following commits from Kilo cycle:
|
||||
# 827db7fe: Add Node.maintenance_reason
|
||||
# 68eed82b: Add API endpoint to set/unset the node maintenance mode
|
||||
# bc973889: Add sync and async support for passthru methods
|
||||
# e03f443b: Vendor endpoints to support different HTTP methods
|
||||
# e69e5309: Make vendor methods discoverable via the Ironic API
|
||||
# edf532db: Add logic to store the config drive passed by Nova
|
||||
# v1.2: Renamed NOSTATE ("None") to AVAILABLE ("available")
|
||||
# v1.3: Add node.driver_internal_info
|
||||
# v1.4: Add MANAGEABLE state
|
||||
# v1.5: Add logical node names
|
||||
# v1.6: Add INSPECT* states
|
||||
# v1.7: Add node.clean_step
|
||||
# v1.8: Add ability to return a subset of resource fields
|
||||
# v1.9: Add ability to filter nodes by provision state
|
||||
# v1.10: Logical node names support RFC 3986 unreserved characters
|
||||
# v1.11: Nodes appear in ENROLL state by default
|
||||
|
||||
MIN_VER_STR = '1.1'
|
||||
MAX_VER_STR = '1.11'
|
||||
|
||||
|
||||
MIN_VER = base.Version({base.Version.string: MIN_VER_STR},
|
||||
MIN_VER_STR, MAX_VER_STR)
|
||||
MAX_VER = base.Version({base.Version.string: MAX_VER_STR},
|
||||
MIN_VER_STR, MAX_VER_STR)
|
||||
MIN_VER = base.Version(
|
||||
{base.Version.string: versions.MIN_VERSION_STRING},
|
||||
versions.MIN_VERSION_STRING, versions.MAX_VERSION_STRING)
|
||||
MAX_VER = base.Version(
|
||||
{base.Version.string: versions.MAX_VERSION_STRING},
|
||||
versions.MIN_VERSION_STRING, versions.MAX_VERSION_STRING)
|
||||
|
||||
|
||||
class MediaType(base.APIBase):
|
||||
|
@ -177,7 +151,8 @@ class Controller(rest.RestController):
|
|||
"Mutually exclusive versions requested. Version %(ver)s "
|
||||
"requested but not supported by this service. The supported "
|
||||
"version range is: [%(min)s, %(max)s].") %
|
||||
{'ver': version, 'min': MIN_VER_STR, 'max': MAX_VER_STR},
|
||||
{'ver': version, 'min': versions.MIN_VERSION_STRING,
|
||||
'max': versions.MAX_VERSION_STRING},
|
||||
headers=headers)
|
||||
# ensure the minor version is within the supported range
|
||||
if version < MIN_VER or version > MAX_VER:
|
||||
|
@ -185,16 +160,20 @@ class Controller(rest.RestController):
|
|||
"Version %(ver)s was requested but the minor version is not "
|
||||
"supported by this service. The supported version range is: "
|
||||
"[%(min)s, %(max)s].") %
|
||||
{'ver': version, 'min': MIN_VER_STR, 'max': MAX_VER_STR},
|
||||
{'ver': version, 'min': versions.MIN_VERSION_STRING,
|
||||
'max': versions.MAX_VERSION_STRING},
|
||||
headers=headers)
|
||||
|
||||
@pecan.expose()
|
||||
def _route(self, args):
|
||||
v = base.Version(pecan.request.headers, MIN_VER_STR, MAX_VER_STR)
|
||||
v = base.Version(pecan.request.headers, versions.MIN_VERSION_STRING,
|
||||
versions.MAX_VERSION_STRING)
|
||||
|
||||
# Always set the min and max headers
|
||||
pecan.response.headers[base.Version.min_string] = MIN_VER_STR
|
||||
pecan.response.headers[base.Version.max_string] = MAX_VER_STR
|
||||
pecan.response.headers[base.Version.min_string] = (
|
||||
versions.MIN_VERSION_STRING)
|
||||
pecan.response.headers[base.Version.max_string] = (
|
||||
versions.MAX_VERSION_STRING)
|
||||
|
||||
# assert that requested version is supported
|
||||
self._check_version(v, pecan.response.headers)
|
||||
|
|
|
@ -31,6 +31,7 @@ from ironic.api.controllers.v1 import collection
|
|||
from ironic.api.controllers.v1 import port
|
||||
from ironic.api.controllers.v1 import types
|
||||
from ironic.api.controllers.v1 import utils as api_utils
|
||||
from ironic.api.controllers.v1 import versions
|
||||
from ironic.api import expose
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
|
@ -61,33 +62,33 @@ _DEFAULT_RETURN_FIELDS = ('instance_uuid', 'maintenance', 'power_state',
|
|||
MIN_VERB_VERSIONS = {
|
||||
# v1.4 added the MANAGEABLE state and two verbs to move nodes into
|
||||
# and out of that state. Reject requests to do this in older versions
|
||||
ir_states.VERBS['manage']: 4,
|
||||
ir_states.VERBS['provide']: 4,
|
||||
ir_states.VERBS['manage']: versions.MINOR_4_MANAGEABLE_STATE,
|
||||
ir_states.VERBS['provide']: versions.MINOR_4_MANAGEABLE_STATE,
|
||||
|
||||
ir_states.VERBS['inspect']: 6,
|
||||
ir_states.VERBS['inspect']: versions.MINOR_6_INSPECT_STATE,
|
||||
}
|
||||
|
||||
|
||||
def hide_fields_in_newer_versions(obj):
|
||||
# if requested version is < 1.3, hide driver_internal_info
|
||||
if pecan.request.version.minor < 3:
|
||||
if pecan.request.version.minor < versions.MINOR_3_DRIVER_INTERNAL_INFO:
|
||||
obj.driver_internal_info = wsme.Unset
|
||||
|
||||
if not api_utils.allow_node_logical_names():
|
||||
obj.name = wsme.Unset
|
||||
|
||||
# if requested version is < 1.6, hide inspection_*_at fields
|
||||
if pecan.request.version.minor < 6:
|
||||
if pecan.request.version.minor < versions.MINOR_6_INSPECT_STATE:
|
||||
obj.inspection_finished_at = wsme.Unset
|
||||
obj.inspection_started_at = wsme.Unset
|
||||
|
||||
if pecan.request.version.minor < 7:
|
||||
if pecan.request.version.minor < versions.MINOR_7_NODE_CLEAN:
|
||||
obj.clean_step = wsme.Unset
|
||||
|
||||
|
||||
def assert_juno_provision_state_name(obj):
|
||||
# if requested version is < 1.2, convert AVAILABLE to the old NOSTATE
|
||||
if (pecan.request.version.minor < 2 and
|
||||
if (pecan.request.version.minor < versions.MINOR_2_AVAILABLE_STATE and
|
||||
obj.provision_state == ir_states.AVAILABLE):
|
||||
obj.provision_state = ir_states.NOSTATE
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import six
|
|||
from webob.static import FileIter
|
||||
import wsme
|
||||
|
||||
from ironic.api.controllers.v1 import versions
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import states
|
||||
|
@ -72,7 +73,7 @@ def get_patch_value(patch, path):
|
|||
|
||||
def allow_node_logical_names():
|
||||
# v1.5 added logical name aliases
|
||||
return pecan.request.version.minor >= 5
|
||||
return pecan.request.version.minor >= versions.MINOR_5_NODE_NAME
|
||||
|
||||
|
||||
def get_rpc_node(node_ident):
|
||||
|
@ -112,7 +113,7 @@ def is_valid_node_name(name):
|
|||
|
||||
def is_valid_logical_name(name):
|
||||
"""Determine if the provided name is a valid hostname."""
|
||||
if pecan.request.version.minor < 10:
|
||||
if pecan.request.version.minor < versions.MINOR_10_UNRESTRICTED_NODE_NAME:
|
||||
return utils.is_hostname_safe(name)
|
||||
else:
|
||||
return utils.is_valid_logical_name(name)
|
||||
|
@ -192,7 +193,8 @@ def check_allow_specify_fields(fields):
|
|||
attributes, this method checks if the required version is being
|
||||
requested.
|
||||
"""
|
||||
if fields is not None and pecan.request.version.minor < 8:
|
||||
if (fields is not None and pecan.request.version.minor <
|
||||
versions.MINOR_8_FETCHING_SUBSET_OF_FIELDS):
|
||||
raise exception.NotAcceptable()
|
||||
|
||||
|
||||
|
@ -202,7 +204,8 @@ def check_for_invalid_state_and_allow_filter(provision_state):
|
|||
Version 1.9 of the API allows filter nodes by provision state.
|
||||
"""
|
||||
if provision_state is not None:
|
||||
if pecan.request.version.minor < 9:
|
||||
if (pecan.request.version.minor <
|
||||
versions.MINOR_9_PROVISION_STATE_FILTER):
|
||||
raise exception.NotAcceptable()
|
||||
valid_states = states.machine.states
|
||||
if provision_state not in valid_states:
|
||||
|
@ -216,5 +219,6 @@ def initial_node_provision_state():
|
|||
Previously the default state for new nodes was AVAILABLE.
|
||||
Starting with API 1.11 it is ENROLL.
|
||||
"""
|
||||
return (states.AVAILABLE if pecan.request.version.minor < 11
|
||||
return (states.AVAILABLE
|
||||
if pecan.request.version.minor < versions.MINOR_11_ENROLL_STATE
|
||||
else states.ENROLL)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (c) 2015 Intel Corporation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This is the version 1 API
|
||||
BASE_VERSION = 1
|
||||
|
||||
# Here goes a short log of changes in every version.
|
||||
# Refer to doc/source/webapi/v1.rst for a detailed explanation of what
|
||||
# each version contains, and don't forget to update it when introducing
|
||||
# a new version.
|
||||
#
|
||||
# v1.0: corresponds to Juno API, not supported since Kilo
|
||||
# v1.1: API at the point in time when versioning support was added,
|
||||
# covers the following commits from Kilo cycle:
|
||||
# 827db7fe: Add Node.maintenance_reason
|
||||
# 68eed82b: Add API endpoint to set/unset the node maintenance mode
|
||||
# bc973889: Add sync and async support for passthru methods
|
||||
# e03f443b: Vendor endpoints to support different HTTP methods
|
||||
# e69e5309: Make vendor methods discoverable via the Ironic API
|
||||
# edf532db: Add logic to store the config drive passed by Nova
|
||||
# v1.2: Renamed NOSTATE ("None") to AVAILABLE ("available")
|
||||
# v1.3: Add node.driver_internal_info
|
||||
# v1.4: Add MANAGEABLE state
|
||||
# v1.5: Add logical node names
|
||||
# v1.6: Add INSPECT* states
|
||||
# v1.7: Add node.clean_step
|
||||
# v1.8: Add ability to return a subset of resource fields
|
||||
# v1.9: Add ability to filter nodes by provision state
|
||||
# v1.10: Logical node names support RFC 3986 unreserved characters
|
||||
# v1.11: Nodes appear in ENROLL state by default
|
||||
|
||||
MINOR_0_JUNO = 0
|
||||
MINOR_1_INITIAL_VERSION = 1
|
||||
MINOR_2_AVAILABLE_STATE = 2
|
||||
MINOR_3_DRIVER_INTERNAL_INFO = 3
|
||||
MINOR_4_MANAGEABLE_STATE = 4
|
||||
MINOR_5_NODE_NAME = 5
|
||||
MINOR_6_INSPECT_STATE = 6
|
||||
MINOR_7_NODE_CLEAN = 7
|
||||
MINOR_8_FETCHING_SUBSET_OF_FIELDS = 8
|
||||
MINOR_9_PROVISION_STATE_FILTER = 9
|
||||
MINOR_10_UNRESTRICTED_NODE_NAME = 10
|
||||
MINOR_11_ENROLL_STATE = 11
|
||||
|
||||
# When adding another version, update MINOR_MAX_VERSION
|
||||
MINOR_MAX_VERSION = MINOR_11_ENROLL_STATE
|
||||
|
||||
# String representations of the minor and maximum versions
|
||||
MIN_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_1_INITIAL_VERSION)
|
||||
MAX_VERSION_STRING = '{}.{}'.format(BASE_VERSION, MINOR_MAX_VERSION)
|
|
@ -0,0 +1,69 @@
|
|||
# Copyright (c) 2015 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Tests for the versions constants and methods.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from ironic.api.controllers.v1 import versions
|
||||
from ironic.tests import base
|
||||
|
||||
|
||||
class TestVersionConstants(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestVersionConstants, self).setUp()
|
||||
|
||||
# Get all of our named constants. They all begin with r'MINOR_[0-9]'
|
||||
self.minor_consts = [x for x in dir(versions)
|
||||
if re.search(r'^MINOR_[0-9]', x)]
|
||||
|
||||
# Sort key needs to be an integer
|
||||
def minor_key(x):
|
||||
return int(x.split('_', 2)[1])
|
||||
self.minor_consts.sort(key=minor_key)
|
||||
|
||||
def test_max_ver_str(self):
|
||||
# Test to make sure MAX_VERSION_STRING corresponds with the largest
|
||||
# MINOR_ constant
|
||||
|
||||
max_ver = '1.{}'.format(getattr(versions, self.minor_consts[-1]))
|
||||
self.assertEqual(max_ver, versions.MAX_VERSION_STRING)
|
||||
|
||||
def test_min_ver_str(self):
|
||||
# Try to make sure someone doesn't change the MIN_VERSION_STRING by
|
||||
# accident and make sure it exists
|
||||
self.assertEqual('1.1', versions.MIN_VERSION_STRING)
|
||||
|
||||
def test_name_value_match(self):
|
||||
# Test to make sure variable name matches the value. For example
|
||||
# MINOR_99_FOO should equal 99
|
||||
|
||||
for var_name in self.minor_consts:
|
||||
version = int(var_name.split('_', 2)[1])
|
||||
self.assertEqual(
|
||||
version, getattr(versions, var_name),
|
||||
'Constant "{}" does not equal {}'.format(var_name, version))
|
||||
|
||||
def test_duplicates(self):
|
||||
# Test to make sure no duplicates values
|
||||
|
||||
seen_values = set()
|
||||
for var_name in self.minor_consts:
|
||||
value = getattr(versions, var_name)
|
||||
self.assertNotIn(
|
||||
value, seen_values,
|
||||
'The value {} has been used more than once'.format(value))
|
||||
seen_values.add(value)
|
Loading…
Reference in New Issue