Add Host Reservation Admin API
Initial release of Host Reservation Admin API by adding new classes to the current Lease API mapped to /os-hosts/ context. The goal of this API is to be admin-only, defining CRUD methods for adding a host to Compute, aiming to dedicate it for lease management. As a result, the added host won't be available for booting VMs on it unless Climate specifically picks it from a specific freepool to the user' pcloud associated with the host reservation. For testing, please patch RPC methods like this : call = lambda *args, **kwargs: True cast = lambda *args, **kwargs: True TODO : - Add @policy.authorize() to climate.api.oshosts.service controllers once review 57200 (Policy mgmt) is merged Implements bp:host-provisioning-api Change-Id: I58d986fe8344b9578b2f15399ec19f7649cc3035
This commit is contained in:
parent
9f63fe76ae
commit
8624ca116f
@ -19,6 +19,7 @@ from keystoneclient.middleware import auth_token
|
||||
from oslo.config import cfg
|
||||
from werkzeug import exceptions as werkzeug_exceptions
|
||||
|
||||
from climate.api.oshosts import v1_0 as host_api_v1_0
|
||||
from climate.api import utils as api_utils
|
||||
from climate.api import v1_0 as api_v1_0
|
||||
from climate.openstack.common import log
|
||||
@ -70,6 +71,13 @@ def make_app():
|
||||
app.route('/', methods=['GET'])(version_list)
|
||||
app.register_blueprint(api_v1_0.rest, url_prefix='/v1')
|
||||
|
||||
LOG.debug("List of plugins: %s", cfg.CONF.manager.plugins)
|
||||
# TODO(sbauza) : Change this whole crap by removing hardcoded values and
|
||||
# maybe using stevedore for achieving this
|
||||
if cfg.CONF.manager.plugins \
|
||||
and 'physical.host.plugin' in cfg.CONF.manager.plugins:
|
||||
app.register_blueprint(host_api_v1_0.rest, url_prefix='/v1/os-hosts')
|
||||
|
||||
for code in werkzeug_exceptions.default_exceptions.iterkeys():
|
||||
app.error_handler_spec[None][code] = make_json_error
|
||||
|
||||
|
0
climate/api/oshosts/__init__.py
Normal file
0
climate/api/oshosts/__init__.py
Normal file
75
climate/api/oshosts/service.py
Normal file
75
climate/api/oshosts/service.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Copyright (c) 2013 Bull.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from climate import exceptions
|
||||
from climate.manager.oshosts import rpcapi as manager_rpcapi
|
||||
from climate.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class API(object):
|
||||
def __init__(self):
|
||||
self.manager_rpcapi = manager_rpcapi.ManagerRPCAPI()
|
||||
|
||||
def get_computehosts(self):
|
||||
"""List all existing computehosts."""
|
||||
return self.manager_rpcapi.list_computehosts()
|
||||
|
||||
def create_computehost(self, data):
|
||||
"""Create new computehost.
|
||||
|
||||
:param data: New computehost characteristics.
|
||||
:type data: dict
|
||||
"""
|
||||
# here API should go to Keystone API v3 and create trust
|
||||
trust = 'trust'
|
||||
data.update({'trust': trust})
|
||||
|
||||
return self.manager_rpcapi.create_computehost(data)
|
||||
|
||||
def get_computehost(self, host_id):
|
||||
"""Get computehost by its ID.
|
||||
|
||||
:param host_id: ID of the computehost in Climate DB.
|
||||
:type host_id: str
|
||||
"""
|
||||
return self.manager_rpcapi.get_computehost(host_id)
|
||||
|
||||
def update_computehost(self, host_id, data):
|
||||
"""Update computehost. Only name changing may be proceeded.
|
||||
|
||||
:param host_id: ID of the computehost in Climate DB.
|
||||
:type host_id: str
|
||||
:param data: New computehost characteristics.
|
||||
:type data: dict
|
||||
"""
|
||||
new_name = data.pop('name', None)
|
||||
if len(data) > 0:
|
||||
raise exceptions.ClimateException('Only name changing may be '
|
||||
'proceeded.')
|
||||
data = {}
|
||||
if new_name:
|
||||
data['name'] = new_name
|
||||
return self.manager_rpcapi.update_computehost(host_id, data)
|
||||
|
||||
def delete_computehost(self, host_id):
|
||||
"""Delete specified computehost.
|
||||
|
||||
:param host_id: ID of the computehost in Climate DB.
|
||||
:type host_id: str
|
||||
"""
|
||||
self.manager_rpcapi.delete_computehost(host_id)
|
64
climate/api/oshosts/v1_0.py
Normal file
64
climate/api/oshosts/v1_0.py
Normal file
@ -0,0 +1,64 @@
|
||||
# Copyright (c) 2013 Bull.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from climate.api.oshosts import service
|
||||
from climate.api import utils as api_utils
|
||||
from climate.api import validation
|
||||
from climate import utils
|
||||
|
||||
|
||||
rest = api_utils.Rest('host_v1_0', __name__)
|
||||
_api = utils.LazyProxy(service.API)
|
||||
|
||||
|
||||
## Computehosts operations
|
||||
|
||||
@rest.get('')
|
||||
def computehosts_list():
|
||||
"""List all existing computehosts."""
|
||||
return api_utils.render(hosts=_api.get_computehosts())
|
||||
|
||||
|
||||
@rest.post('')
|
||||
def computehosts_create(data):
|
||||
"""Create new computehost."""
|
||||
return api_utils.render(host=_api.create_computehost(data))
|
||||
|
||||
|
||||
@rest.get('/<host_id>')
|
||||
@validation.check_exists(_api.get_computehost, host_id='host_id')
|
||||
def computehosts_get(host_id):
|
||||
"""Get computehost by its ID."""
|
||||
return api_utils.render(host=_api.get_computehost(host_id))
|
||||
|
||||
|
||||
@rest.put('/<host_id>')
|
||||
@validation.check_exists(_api.get_computehost, host_id='host_id')
|
||||
def computehosts_update(host_id, data):
|
||||
"""Update computehost. Only name changing may be proceeded.
|
||||
"""
|
||||
if len(data) == 0:
|
||||
return api_utils.internal_error(status_code=400,
|
||||
descr="No data to update")
|
||||
else:
|
||||
return api_utils.render(host=_api.update_computehost(host_id, data))
|
||||
|
||||
|
||||
@rest.delete('/<host_id>')
|
||||
@validation.check_exists(_api.get_computehost, host_id='host_id')
|
||||
def computehosts_delete(host_id):
|
||||
"""Delete specified computehost."""
|
||||
_api.delete_computehost(host_id)
|
||||
return api_utils.render()
|
0
climate/manager/oshosts/__init__.py
Normal file
0
climate/manager/oshosts/__init__.py
Normal file
56
climate/manager/oshosts/rpcapi.py
Normal file
56
climate/manager/oshosts/rpcapi.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2013 Bull.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from climate.utils import service
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_opt('rpc_topic', 'climate.manager.service', 'manager')
|
||||
|
||||
|
||||
class ManagerRPCAPI(service.RpcProxy):
|
||||
"""Client side for the Manager RPC API.
|
||||
|
||||
Used from other services to communicate with climate-manager service.
|
||||
"""
|
||||
BASE_RPC_API_VERSION = '1.0'
|
||||
|
||||
def __init__(self):
|
||||
"""Initiate RPC API client with needed topic and RPC version."""
|
||||
super(ManagerRPCAPI, self).__init__(
|
||||
topic=CONF.manager.rpc_topic,
|
||||
default_version=self.BASE_RPC_API_VERSION,
|
||||
)
|
||||
|
||||
def get_computehost(self, host_id):
|
||||
"""Get detailed info about some computehost."""
|
||||
return self.call('get_computehost', host_id=host_id)
|
||||
|
||||
def list_computehosts(self):
|
||||
"""List all computehosts."""
|
||||
return self.call('list_computehosts')
|
||||
|
||||
def create_computehost(self, host_values):
|
||||
"""Create computehost with specified parameters."""
|
||||
return self.call('create_computehost', host_values=host_values)
|
||||
|
||||
def update_computehost(self, host_id, values):
|
||||
"""Update computehost with passes values dictionary."""
|
||||
return self.call('update_computehost', host_id=host_id, values=values)
|
||||
|
||||
def delete_computehost(self, host_id):
|
||||
"""Delete specified computehost."""
|
||||
return self.cast('delete_computehost', host_id=host_id)
|
0
climate/tests/api/oshosts/__init__.py
Normal file
0
climate/tests/api/oshosts/__init__.py
Normal file
46
climate/tests/api/oshosts/test_service.py
Normal file
46
climate/tests/api/oshosts/test_service.py
Normal file
@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2013 Bull.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from climate.api.oshosts import service as service_api
|
||||
from climate import tests
|
||||
|
||||
|
||||
class RPCApiTestCase(tests.TestCase):
|
||||
def setUp(self):
|
||||
super(RPCApiTestCase, self).setUp()
|
||||
self.s_api = service_api
|
||||
|
||||
self.fake_list = []
|
||||
self.fake_computehost = {}
|
||||
|
||||
self.patch(self.s_api.API, "get_computehosts").\
|
||||
return_value = self.fake_list
|
||||
self.patch(self.s_api.API, "create_computehost").return_value = True
|
||||
self.patch(self.s_api.API, "get_computehost").\
|
||||
return_value = self.fake_computehost
|
||||
self.patch(self.s_api.API, "update_computehost").return_value = True
|
||||
self.patch(self.s_api.API, "delete_computehost").return_value = True
|
||||
|
||||
def test_get_computehost(self):
|
||||
pass
|
||||
|
||||
def test_create_computehost(self):
|
||||
pass
|
||||
|
||||
def test_update_computehost(self):
|
||||
pass
|
||||
|
||||
def test_delete_computehost(self):
|
||||
pass
|
60
climate/tests/api/oshosts/test_v1_0.py
Normal file
60
climate/tests/api/oshosts/test_v1_0.py
Normal file
@ -0,0 +1,60 @@
|
||||
# Copyright (c) 2013 Bull.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from climate.api.oshosts import service as service_api
|
||||
from climate.api.oshosts import v1_0 as api
|
||||
from climate.api import utils as utils_api
|
||||
from climate import tests
|
||||
|
||||
|
||||
class RESTApiTestCase(tests.TestCase):
|
||||
def setUp(self):
|
||||
super(RESTApiTestCase, self).setUp()
|
||||
self.api = api
|
||||
self.u_api = utils_api
|
||||
self.s_api = service_api
|
||||
|
||||
self.render = self.patch(self.u_api, "render")
|
||||
self.get_computehosts = self.patch(self.s_api.API,
|
||||
'get_computehosts')
|
||||
self.create_computehost = self.patch(self.s_api.API,
|
||||
'create_computehost')
|
||||
self.get_computehost = self.patch(self.s_api.API, 'get_computehost')
|
||||
self.update_computehost = self.patch(self.s_api.API,
|
||||
'update_computehost')
|
||||
self.delete_computehost = self.patch(self.s_api.API,
|
||||
'delete_computehost')
|
||||
|
||||
self.fake_id = '1'
|
||||
|
||||
def test_computehost_list(self):
|
||||
self.api.computehosts_list()
|
||||
self.render.assert_called_once_with(hosts=self.get_computehosts())
|
||||
|
||||
def test_computehosts_create(self):
|
||||
self.api.computehosts_create(data=None)
|
||||
self.render.assert_called_once_with(host=self.create_computehost())
|
||||
|
||||
def test_computehosts_get(self):
|
||||
self.api.computehosts_get(host_id=self.fake_id)
|
||||
self.render.assert_called_once_with(host=self.get_computehost())
|
||||
|
||||
def test_computehosts_update(self):
|
||||
self.api.computehosts_update(host_id=self.fake_id, data=self.fake_id)
|
||||
self.render.assert_called_once_with(host=self.update_computehost())
|
||||
|
||||
def test_computehosts_delete(self):
|
||||
self.api.computehosts_delete(host_id=self.fake_id)
|
||||
self.render.assert_called_once()
|
@ -15,9 +15,11 @@
|
||||
|
||||
import flask
|
||||
from keystoneclient.middleware import auth_token
|
||||
from oslo.config import cfg
|
||||
from werkzeug import exceptions as werkzeug_exceptions
|
||||
|
||||
from climate.api import app
|
||||
from climate.api.oshosts import v1_0 as host_api_v1_0
|
||||
from climate.api import utils as api_utils
|
||||
from climate import tests
|
||||
|
||||
@ -69,3 +71,21 @@ class AppTestCase(tests.TestCase):
|
||||
auth_version='v2.0',
|
||||
admin_password='climate',
|
||||
auth_host='127.0.0.1')
|
||||
|
||||
|
||||
class AppTestCaseForHostsPlugin(tests.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(AppTestCaseForHostsPlugin, self).setUp()
|
||||
|
||||
cfg.CONF.set_override('plugins', ['physical.host.plugin'], 'manager')
|
||||
self.app = app
|
||||
self.host_api_v1_0 = host_api_v1_0
|
||||
self.flask = flask
|
||||
self.fake_blueprint = self.patch(self.flask.Flask,
|
||||
'register_blueprint')
|
||||
|
||||
def test_make_app_with_host_plugin(self):
|
||||
self.app.make_app()
|
||||
self.fake_blueprint.assert_called_with(self.host_api_v1_0.rest,
|
||||
url_prefix='/v1/os-hosts')
|
||||
|
Loading…
x
Reference in New Issue
Block a user