Expose floatingip APIs and virtual:floatingip resources

Partially Implements: blueprint floatingip-reservation
Change-Id: Idc2571027ebd24ca1af73941203411990172eb45
This commit is contained in:
Masahito Muroi 2019-01-28 11:43:35 +09:00
parent 9e963f838f
commit 59b0968ea1
20 changed files with 545 additions and 12 deletions

View File

@ -0,0 +1,162 @@
.. -*- rst -*-
============
Floating IPs
============
List FloatingIPs
================
.. rest_method:: GET v1/floatingips
List floating IPs.
**Response codes**
Normal response code: 200
Error response codes: Bad Request(400), Unauthorized(401), Forbidden(403),
Internal Server Error(500)
Request
-------
No body content, path, nor query option.
Response
--------
.. rest_parameters:: parameters.yaml
- floatingips: floatingips
- id: floatingip_id
- floating_network_id: floating_network_id
- subnet_id: floating_subnet_id
- floating_ip_address: floating_ip_address
- reservable: floatingip_reservable
- created_at: created_at
- updated_at: updated_at
**Example of List Hosts Response**
.. literalinclude:: ../../../doc/api_samples/floatingips/floatingip-list-resp.json
:language: javascript
Create Floating IP
==================
.. rest_method:: POST v1/floatingips
Create a floating IP.
**Response codes**
Normal response code: 201
Error response codes: Bad Request(400), Unauthorized(401), Forbidden(403),
Conflict(409), Internal Server Error(500)
Request
-------
.. rest_parameters:: parameters.yaml
- floating_network_id: floating_network_id
- floating_ip_address: floating_ip_address_create
**Example of Create Host Request**
.. literalinclude:: ../../../doc/api_samples/floatingips/floatingip-create-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- floatingip: floatingip
- id: floatingip_id
- floating_ip_address: floating_ip_address
- network_id: floating_network_id
- subnet_id: floating_subnet_id
- reservable: floatingip_reservable
- created_at: created_at
- updated_at: updated_at
**Example of Create Host Response**
.. literalinclude:: ../../../doc/api_samples/floatingips/floatingip-create-resp.json
:language: javascript
Show Floating IP Details
========================
.. rest_method:: GET v1/floatingips/{floatingip_id}
Show details of a floating IP.
**Preconditions**
The floating IP must exist.
**Response codes**
Normal response code: 200
Error response codes: Bad Request(400), Unauthorized(401), Forbidden(403),
Not Found(404), Internal Server Error(500)
Request
-------
.. rest_parameters:: parameters.yaml
- floatingip_id: floatingip_id_path
Response
--------
.. rest_parameters:: parameters.yaml
- floatingip: floatingip
- id: floatingip_id
- floating_network_id: floating_network_id
- floating_ip_address: floating_ip_address
- reservable: floatingip_reservable
- created_at: created_at
- updated_at: updated_at
**Example of Show Floating IP Details Response**
.. literalinclude:: ../../../doc/api_samples/floatingips/floatingip-details-resp.json
:language: javascript
Delete Floating IP
==================
.. rest_method:: DELETE v1/floatingips/{floatingip_id}
Delete a floating IP.
**Preconditions**
The floating IP must exist.
**Response codes**
Normal response code: 204
Error response codes: Bad Request(400), Unauthorized(401), Forbidden(403),
Not Found(404), Conflict(409), Internal Server Error(500)
Request
-------
.. rest_parameters:: parameters.yaml
- floatingip_id: floatingip_id_path
Repsponse
---------
No body content is returned on a successful DELETE.

View File

@ -9,3 +9,4 @@ Blazar project.
.. include:: leases.inc
.. include:: hosts.inc
.. include:: floatingips.inc

View File

@ -1,4 +1,10 @@
# variables in path
floatingip_id_path:
description: |
The ID of the floating IP.
in: path
required: true
type: string
host_id_path:
description: |
The ID of the host.
@ -96,6 +102,61 @@ events_optional:
in: body
required: false
type: array
## parameters for floating IP
floating_ip_address:
description:
The floating IP address.
in: body
required: true
type: string
floating_ip_address_create:
description:
The floating IP address. The IP must be the out side of allocation_pools
and within its subnet's CIDR network.
in: body
required: true
type: string
floating_network_id:
description:
An external network ID the floating IP belongs to.
in: body
required: true
type: string
floating_subnet_id:
description: |
An external subnet ID the floating IP belongs to.
in: body
required: true
type: boolean
floatingip:
description: |
A ``floatingip`` object.
in: body
required: true
type: object
floatingip_id:
description:
The ID of the floating ip resources.
in: body
required: true
type: string
floatingip_reservable:
description: |
The flag which represents whether the floating IP is reservable or not.
in: body
required: true
type: boolean
floatingips:
description: |
A list of ``floatingip`` objects.
in: body
required: true
type: array
## parameters for host
host:
description: |
A ``host`` object.
@ -197,6 +258,9 @@ hosts:
in: body
required: true
type: array
## parameters for leases
lease:
description: |
A ``lease`` object.

View File

@ -22,10 +22,9 @@ from keystonemiddleware import auth_token
from oslo_config import cfg
from oslo_log import log as logging
from oslo_middleware import debug
from stevedore import enabled
from werkzeug import exceptions as werkzeug_exceptions
from blazar.api.v1.leases import v1_0 as leases_api_v1_0
from blazar.api.v1.oshosts import v1_0 as host_api_v1_0
from blazar.api.v1 import utils as api_utils
@ -69,14 +68,19 @@ def make_app():
app.route('/', methods=['GET'])(version_list)
app.route('/versions', methods=['GET'])(version_list)
app.register_blueprint(leases_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')
plugins = cfg.CONF.manager.plugins + ['leases']
extension_manager = enabled.EnabledExtensionManager(
check_func=lambda ext: ext.name in plugins,
namespace='blazar.api.v1.extensions',
invoke_on_load=False
)
for ext in extension_manager.extensions:
bp = ext.plugin()
app.register_blueprint(bp, url_prefix=bp.url_prefix)
for code in werkzeug_exceptions.default_exceptions:
app.register_error_handler(code, make_json_error)

View File

View File

@ -0,0 +1,57 @@
# Copyright (c) 2019 NTT
#
# 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 blazar.manager.floatingips import rpcapi as manager_rpcapi
from blazar import policy
from blazar.utils import trusts
class API(object):
def __init__(self):
self.manager_rpcapi = manager_rpcapi.ManagerRPCAPI()
@policy.authorize('floatingips', 'get')
def get_floatingips(self):
"""List all existing floatingip."""
return self.manager_rpcapi.list_floatingips()
@policy.authorize('floatingips', 'post')
@trusts.use_trust_auth()
def create_floatingip(self, data):
"""Create new floatingip.
:param data: New floatingip characteristics.
:type data: dict
"""
return self.manager_rpcapi.create_floatingip(data)
@policy.authorize('floatingips', 'get')
def get_floatingip(self, floatingip_id):
"""Get floatingip by its ID.
:param floatingip_id: ID of the floatingip in Blazar DB.
:type floatingip_id: str
"""
return self.manager_rpcapi.get_floatingip(floatingip_id)
@policy.authorize('floatingips', 'delete')
def delete_floatingip(self, floatingip_id):
"""Delete specified floatingip.
:param floatingip_id: ID of the floatingip in Blazar DB.
:type floatingip_id: str
"""
self.manager_rpcapi.delete_floatingip(floatingip_id)

View File

@ -0,0 +1,58 @@
# Copyright (c) 2019 NTT.
#
# 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 blazar.api.v1.floatingips import service
from blazar.api.v1 import utils as api_utils
from blazar.api.v1 import validation
from blazar import utils
def get_rest():
"""Return Rest app"""
return rest
rest = api_utils.Rest('floatingip_v1_0', __name__,
url_prefix='/v1/floatingips')
_api = utils.LazyProxy(service.API)
# Floatingips operations
@rest.get('')
def floatingips_list():
"""List all existing floatingips."""
return api_utils.render(floatingips=_api.get_floatingips())
@rest.post('')
def floatingips_create(data):
"""Create new floatingip."""
return api_utils.render(floatingip=_api.create_floatingip(data))
@rest.get('/<floatingip_id>')
@validation.check_exists(_api.get_floatingip, floatingip_id='floatingip_id')
def floatingips_get(floatingip_id):
"""Get floatingip by its ID."""
return api_utils.render(floatingip=_api.get_floatingip(floatingip_id))
@rest.delete('/<floatingip_id>')
@validation.check_exists(_api.get_floatingip, floatingip_id='floatingip_id')
def floatingips_delete(floatingip_id):
"""Delete specified floatingip."""
_api.delete_floatingip(floatingip_id)
return api_utils.render()

View File

@ -22,7 +22,13 @@ from blazar import utils
LOG = logging.getLogger(__name__)
rest = api_utils.Rest('v1_0', __name__)
def get_rest():
"""Return Rest app"""
return rest
rest = api_utils.Rest('v1_0', __name__, url_prefix='/v1')
_api = utils.LazyProxy(service.API)

View File

@ -19,7 +19,12 @@ from blazar.api.v1 import validation
from blazar import utils
rest = api_utils.Rest('host_v1_0', __name__)
def get_rest():
"""Return Rest app"""
return rest
rest = api_utils.Rest('host_v1_0', __name__, url_prefix='/v1/os-hosts')
_api = utils.LazyProxy(service.API)

View File

@ -35,6 +35,7 @@ class Rest(flask.Blueprint):
def __init__(self, *args, **kwargs):
super(Rest, self).__init__(*args, **kwargs)
self.url_prefix = kwargs.get('url_prefix', None)
self.routes_with_query_support = []
def get(self, rule, status_code=200, query=False):

View File

View File

@ -0,0 +1,53 @@
# Copyright (c) 2019 NTT.
#
# 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 blazar import manager
from blazar.utils import service
CONF = cfg.CONF
CONF.import_opt('rpc_topic', 'blazar.manager.service', 'manager')
class ManagerRPCAPI(service.RPCClient):
"""Client side for the Manager RPC API.
Used from other services to communicate with blazar-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__(manager.get_target())
def get_floatingip(self, floatingip_id):
"""Get detailed info about a floatingip."""
return self.call('virtual:floatingip:get_floatingip',
fip_id=floatingip_id)
def list_floatingips(self):
"""List all floatingips."""
return self.call('virtual:floatingip:list_floatingip')
def create_floatingip(self, floatingip_values):
"""Create floatingip with specified parameters."""
return self.call('virtual:floatingip:create_floatingip',
values=floatingip_values)
def delete_floatingip(self, floatingip_id):
"""Delete specified floatingip."""
return self.call('virtual:floatingip:delete_floatingip',
fip_id=floatingip_id)

View File

@ -13,6 +13,7 @@
import itertools
from blazar.policies import base
from blazar.policies import floatingips
from blazar.policies import leases
from blazar.policies import oshosts
@ -22,4 +23,5 @@ def list_rules():
base.list_rules(),
leases.list_rules(),
oshosts.list_rules(),
floatingips.list_rules()
)

View File

@ -0,0 +1,61 @@
# 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_policy import policy
from blazar.policies import base
POLICY_ROOT = 'blazar:floatingips:%s'
floatingips_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'get',
check_str=base.RULE_ADMIN,
description='Policy rule for List/Show FloatingIP(s) API.',
operations=[
{
'path': '/{api_version}/floatingips',
'method': 'GET'
},
{
'path': '/{api_version}/floatingips/{floatingip_id}',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'post',
check_str=base.RULE_ADMIN,
description='Policy rule for Create Floating IP API.',
operations=[
{
'path': '/{api_version}/floatingips',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str=base.RULE_ADMIN,
description='Policy rule for Delete Floating IP API.',
operations=[
{
'path': '/{api_version}/floatingips/{floatingip_id}',
'method': 'DELETE'
}
]
)
]
def list_rules():
return floatingips_policies

View File

@ -19,6 +19,7 @@ from oslo_config import cfg
from werkzeug import exceptions as werkzeug_exceptions
from blazar.api.v1 import app
from blazar.api.v1.leases import v1_0 as lease_api_v1_0
from blazar.api.v1.oshosts import v1_0 as host_api_v1_0
from blazar.api.v1 import utils as api_utils
from blazar import tests
@ -81,11 +82,14 @@ class AppTestCaseForHostsPlugin(tests.TestCase):
cfg.CONF.set_override('plugins', ['physical.host.plugin'], 'manager')
self.app = app
self.host_api_v1_0 = host_api_v1_0
self.lease_api_v1_0 = lease_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')
self.fake_blueprint.assert_any_call(self.lease_api_v1_0.rest,
url_prefix='/v1')
self.fake_blueprint.assert_any_call(self.host_api_v1_0.rest,
url_prefix='/v1/os-hosts')

View File

@ -0,0 +1,4 @@
{
"floating_network_id": "1e17587e-a7ed-4b82-a17b-4beb32523e28",
"floating_ip_address": "172.24.4.101"
}

View File

@ -0,0 +1,11 @@
{
"floatingip": {
"id": "84c4d37e-1f8b-45ce-897b-16ad7f49b0e9",
"floating_network_id": "1e17587e-a7ed-4b82-a17b-4beb32523e28",
"floating_ip_address": "172.24.4.101",
"subnet_id": "a2fa9b7e-8451-4868-85f4-92ee7c77eed6",
"reservable": true,
"created_at": "2019-01-28T08:01:46.000000",
"updated_at": null
}
}

View File

@ -0,0 +1,11 @@
{
"floatingip": {
"id": "84c4d37e-1f8b-45ce-897b-16ad7f49b0e9",
"floating_network_id": "1e17587e-a7ed-4b82-a17b-4beb32523e28",
"floating_ip_address": "172.24.4.101",
"subnet_id": "a2fa9b7e-8451-4868-85f4-92ee7c77eed6",
"reservable": true,
"created_at": "2019-01-28T08:01:46.000000",
"updated_at": null
}
}

View File

@ -0,0 +1,23 @@
{
"floatingips": [
{
"id": "84c4d37e-1f8b-45ce-897b-16ad7f49b0e9",
"floating_network_id": "1e17587e-a7ed-4b82-a17b-4beb32523e28",
"subnet_id": "a2fa9b7e-8451-4868-85f4-92ee7c77eed6",
"floating_ip_address": "172.24.4.101",
"reservable": true,
"created_at": "2019-01-28 08:01:46",
"updated_at": null
},
{
"id": "f180cf4c-f886-4dd1-8c36-854d17fbefb5",
"floating_network_id": "1e17587e-a7ed-4b82-a17b-4beb32523e28",
"subnet_id": "a2fa9b7e-8451-4868-85f4-92ee7c77eed6",
"floating_ip_address": "172.24.4.102",
"reservable": true,
"created_at": "2019-01-28 08:08:22",
"updated_at": null,
}
]
}

View File

@ -39,6 +39,12 @@ blazar.resource.plugins =
dummy.vm.plugin=blazar.plugins.dummy_vm_plugin:DummyVMPlugin
physical.host.plugin=blazar.plugins.oshosts.host_plugin:PhysicalHostPlugin
virtual.instance.plugin=blazar.plugins.instances.instance_plugin:VirtualInstancePlugin
virtual.floatingip.plugin=blazar.plugins.floatingips.floatingip_plugin:FloatingIpPlugin
blazar.api.v1.extensions =
leases=blazar.api.v1.leases.v1_0:get_rest
physical.host.plugin=blazar.api.v1.oshosts.v1_0:get_rest
virtual.floatingip.plugin=blazar.api.v1.floatingips.v1_0:get_rest
blazar.api.v2.controllers.extensions =
oshosts=blazar.api.v2.controllers.extensions.host:HostsController