Browse Source

Add some commands for octavia flavor and flavor_profile

Depends-On: I99a673438458757d0acdaa46dd8ee041edb3be9c
Change-Id: Ib9867583545b48be828c9f5c3705e3a6a16f879c
changes/86/624686/7
yangjianfeng 3 years ago
committed by Adam Harwell
parent
commit
7a9f6f2f32
  1. 14
      doc/source/cli/index.rst
  2. 5
      octaviaclient/api/constants.py
  3. 139
      octaviaclient/api/v2/octavia.py
  4. 28
      octaviaclient/osc/v2/constants.py
  5. 215
      octaviaclient/osc/v2/flavor.py
  6. 183
      octaviaclient/osc/v2/flavorprofile.py
  7. 42
      octaviaclient/osc/v2/utils.py
  8. 189
      octaviaclient/tests/unit/api/test_octavia.py
  9. 14
      octaviaclient/tests/unit/osc/v2/constants.py
  10. 172
      octaviaclient/tests/unit/osc/v2/test_flavor.py
  11. 174
      octaviaclient/tests/unit/osc/v2/test_flavorprofile.py
  12. 4
      releasenotes/notes/add-flavor-support-75c6d5bec48b1d18.yaml
  13. 10
      setup.cfg

14
doc/source/cli/index.rst

@ -94,3 +94,17 @@ provider
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer provider *
======
flavor
======
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer flavor *
=============
flavorprofile
=============
.. autoprogram-cliff:: openstack.load_balancer.v2
:command: loadbalancer flavorprofile *

5
octaviaclient/api/constants.py

@ -50,3 +50,8 @@ BASE_PROVIDER_URL = BASE_LBAAS_ENDPOINT + "/providers"
BASE_PROVIDER_FLAVOR_CAPABILITY_URL = (BASE_LBAAS_ENDPOINT +
"/providers/{provider}/"
"flavor_capabilities")
BASE_FLAVOR_URL = BASE_LBAAS_ENDPOINT + "/flavors"
BASE_SINGLE_FLAVOR_URL = BASE_FLAVOR_URL + "/{uuid}"
BASE_FLAVORPROFILE_URL = BASE_LBAAS_ENDPOINT + "/flavorprofiles"
BASE_SINGLE_FLAVORPROFILE_URL = BASE_FLAVORPROFILE_URL + "/{uuid}"

139
octaviaclient/api/v2/octavia.py

@ -752,6 +752,145 @@ class OctaviaAPI(api.BaseAPI):
return response
def flavor_list(self, **kwargs):
"""List all flavors
:param kwargs:
Parameters to filter on
:return:
A ``dict`` containing a list of flavor
"""
url = const.BASE_FLAVOR_URL
response = self.list(path=url, **kwargs)
return response
@correct_return_codes
def flavor_delete(self, flavor_id):
"""Delete a flavor
:param string flavor_id:
ID of the flavor to delete
:return:
Response Code from the API
"""
url = const.BASE_SINGLE_FLAVOR_URL.format(uuid=flavor_id)
response = self.delete(url)
return response
@correct_return_codes
def flavor_create(self, **kwargs):
"""Create a flavor
:param kwargs:
Parameters to create a flavor with (expects json=)
:return:
A dict of the created flavor's settings
"""
url = const.BASE_FLAVOR_URL
response = self.create(url, **kwargs)
return response
@correct_return_codes
def flavor_set(self, flavor_id, **kwargs):
"""Update a flavor's settings
:param string flavor_id:
ID of the flavor to update
:param kwargs:
A dict of arguments to update a flavor
:return:
Response Code from the API
"""
url = const.BASE_SINGLE_FLAVOR_URL.format(uuid=flavor_id)
response = self.create(url, method='PUT', **kwargs)
return response
def flavor_show(self, flavor_id):
"""Show a flavor
:param string flavor_id:
ID of the flavor to show
:return:
A dict of the specified flavor's settings
"""
response = self.find(path=const.BASE_FLAVOR_URL, value=flavor_id)
return response
@correct_return_codes
def flavorprofile_create(self, **kwargs):
"""Create a flavor profile
:param kwargs:
Parameters to create a flavor profile with (expects json=)
:return:
A dict of the created flavor profile's settings
"""
url = const.BASE_FLAVORPROFILE_URL
response = self.create(url, **kwargs)
return response
def flavorprofile_list(self, **kwargs):
"""List all flavor profiles
:param kwargs:
Parameters to filter on
:return:
List of flavor profile
"""
url = const.BASE_FLAVORPROFILE_URL
response = self.list(url, **kwargs)
return response
def flavorprofile_show(self, flavorprofile_id):
"""Show a flavor profile
:param string flavorprofile_id:
ID of the flavor profile to show
:return:
A dict of the specified flavor profile's settings
"""
response = self.find(path=const.BASE_FLAVORPROFILE_URL,
value=flavorprofile_id)
return response
@correct_return_codes
def flavorprofile_set(self, flavorprofile_id, **kwargs):
"""Update a flavor profile's settings
:param string flavorprofile_id:
ID of the flavor profile to update
:kwargs:
A dict of arguments to update the flavor profile
:return:
Response Code from the API
"""
url = const.BASE_SINGLE_FLAVORPROFILE_URL.format(uuid=flavorprofile_id)
response = self.create(url, method='PUT', **kwargs)
return response
@correct_return_codes
def flavorprofile_delete(self, flavorprofile_id):
"""Delete a flavor profile
:param string flavorprofile_id:
ID of the flavor profile to delete
:return:
Response Code from the API
"""
url = const.BASE_SINGLE_FLAVORPROFILE_URL.format(uuid=flavorprofile_id)
response = self.delete(url)
return response
class OctaviaClientException(Exception):
"""The base exception class for all exceptions this library raises."""

28
octaviaclient/osc/v2/constants.py

@ -274,3 +274,31 @@ PROVIDER_CAPABILICY_COLUMNS = (
'name',
'description',
)
FLAVOR_ROWS = (
'id',
'name',
'flavor_profile_id',
'enabled',
'description',
)
FLAVOR_COLUMNS = (
'id',
'name',
'flavor_profile_id',
'enabled',
)
FLAVORPROFILE_ROWS = (
'id',
'name',
'provider_name',
'flavor_data'
)
FLAVORPROFILE_COLUMNS = (
'id',
'name',
'provider_name',
)

215
octaviaclient/osc/v2/flavor.py

@ -0,0 +1,215 @@
# Copyright (c) 2018 China Telecom 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.
"""Flavor action implementation"""
from cliff import lister
from osc_lib.command import command
from osc_lib import utils
from octaviaclient.osc.v2 import constants as const
from octaviaclient.osc.v2 import utils as v2_utils
class CreateFlavor(command.ShowOne):
"""Create a octavia flavor"""
def get_parser(self, prog_name):
parser = super(CreateFlavor, self).get_parser(prog_name)
parser.add_argument(
'--name',
metavar='<name>',
required=True,
help="New flavor name."
)
parser.add_argument(
'--flavorprofile',
metavar='<flavor_profile>',
required=True,
help="Flavor profile to add the flavor to (name or ID)."
)
parser.add_argument(
'--description',
metavar='<description>',
help="Set flavor description."
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
'--enable',
action='store_true',
default=None,
help="Enable flavor."
)
admin_group.add_argument(
'--disable',
action='store_true',
default=None,
help="Disable flavor."
)
return parser
def take_action(self, parsed_args):
rows = const.FLAVOR_ROWS
attrs = v2_utils.get_flavor_attrs(self.app.client_manager,
parsed_args)
body = {"flavor": attrs}
data = self.app.client_manager.load_balancer.flavor_create(
json=body)
formatters = {'flavorprofiles': v2_utils.format_list}
return (rows,
(utils.get_dict_properties(
data['flavor'], rows, formatters=formatters)))
class DeleteFlavor(command.Command):
"""Delete a flavor"""
def get_parser(self, prog_name):
parser = super(DeleteFlavor, self).get_parser(prog_name)
parser.add_argument(
'flavor',
metavar='<flavor>',
help="Flavor to delete (name or ID)"
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_flavor_attrs(self.app.client_manager,
parsed_args)
flavor_id = attrs.pop('flavor_id')
self.app.client_manager.load_balancer.flavor_delete(
flavor_id=flavor_id)
class ListFlavor(lister.Lister):
"""List flavor"""
def get_parser(self, prog_name):
parser = super(ListFlavor, self).get_parser(prog_name)
parser.add_argument(
'--name',
metavar='<name>',
help="List flavors according to their name."
)
parser.add_argument(
'--flavorprofile',
metavar='<flavor_profile>',
help="List flavors according to their flavor profile.",
)
admin_state_group = parser.add_mutually_exclusive_group()
admin_state_group.add_argument(
'--enable',
action='store_true',
default=None,
help="List enabled flavors."
)
admin_state_group.add_argument(
'--disable',
action='store_true',
default=None,
help="List disabled flavors."
)
return parser
def take_action(self, parsed_args):
columns = const.FLAVOR_COLUMNS
attrs = v2_utils.get_flavor_attrs(self.app.client_manager,
parsed_args)
data = self.app.client_manager.load_balancer.flavor_list(
**attrs)
formatters = {'flavorprofiles': v2_utils.format_list}
return (columns,
(utils.get_dict_properties(s, columns, formatters=formatters)
for s in data['flavors']))
class ShowFlavor(command.ShowOne):
"""Show the details for a single flavor"""
def get_parser(self, prog_name):
parser = super(ShowFlavor, self).get_parser(prog_name)
parser.add_argument(
'flavor',
metavar='<flavor>',
help="Name or UUID of the flavor."
)
return parser
def take_action(self, parsed_args):
rows = const.FLAVOR_ROWS
attrs = v2_utils.get_flavor_attrs(self.app.client_manager,
parsed_args)
flavor_id = attrs.pop('flavor_id')
data = self.app.client_manager.load_balancer.flavor_show(
flavor_id=flavor_id
)
formatters = {'flavorprofiles': v2_utils.format_list}
return (rows, (utils.get_dict_properties(
data, rows, formatters=formatters)))
class SetFlavor(command.Command):
"""Update a flavor"""
def get_parser(self, prog_name):
parser = super(SetFlavor, self).get_parser(prog_name)
parser.add_argument(
'flavor',
metavar='<flavor>',
help='Name or UUID of the flavor to update.'
)
parser.add_argument(
'--name',
metavar='<name>',
help="Set the name of the flavor."
)
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
'--enable',
action='store_true',
default=None,
help="Enable flavor."
)
admin_group.add_argument(
'--disable',
action='store_true',
default=None,
help="Disable flavor."
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_flavor_attrs(self.app.client_manager,
parsed_args)
flavor_id = attrs.pop('flavor_id')
body = {'flavor': attrs}
self.app.client_manager.load_balancer.flavor_set(
flavor_id, json=body)

183
octaviaclient/osc/v2/flavorprofile.py

@ -0,0 +1,183 @@
# Copyright (c) 2018 China Telecom 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.
"""Flavor profile action implementation"""
from cliff import lister
from osc_lib.command import command
from osc_lib import utils
from octaviaclient.osc.v2 import constants as const
from octaviaclient.osc.v2 import utils as v2_utils
class CreateFlavorProfile(command.ShowOne):
"""Create a octavia flavor profile"""
def get_parser(self, prog_name):
parser = super(CreateFlavorProfile, self).get_parser(prog_name)
parser.add_argument(
'--name',
metavar='<name>',
required=True,
help="New octavia flavor profile name."
)
parser.add_argument(
'--provider',
metavar='<provider name>',
required=True,
help="Provider name for the flavor profile."
)
parser.add_argument(
'--flavor-data',
metavar='<flavor_data>',
required=True,
help="The JSON string containing the flavor metadata."
)
return parser
def take_action(self, parsed_args):
rows = const.FLAVORPROFILE_ROWS
attrs = v2_utils.get_flavorprofile_attrs(self.app.client_manager,
parsed_args)
body = {"flavorprofile": attrs}
data = self.app.client_manager.load_balancer.flavorprofile_create(
json=body)
return (rows,
(utils.get_dict_properties(
data['flavorprofile'], rows, formatters={})))
class DeleteFlavorProfile(command.Command):
"""Delete a flavor profile"""
def get_parser(self, prog_name):
parser = super(DeleteFlavorProfile, self).get_parser(prog_name)
parser.add_argument(
'flavorprofile',
metavar='<flavor_profile>',
help="Flavor profiles to delete (name or ID)"
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_flavorprofile_attrs(self.app.client_manager,
parsed_args)
flavorprofile_id = attrs.pop('flavorprofile_id')
self.app.client_manager.load_balancer.flavorprofile_delete(
flavorprofile_id=flavorprofile_id)
class ListFlavorProfile(lister.Lister):
"""List flavor profile"""
def get_parser(self, prog_name):
parser = super(ListFlavorProfile, self).get_parser(prog_name)
parser.add_argument(
'--name',
metavar='<name>',
help="List flavor profiles by flavor profile name."
)
parser.add_argument(
'--provider',
metavar='<provider_name>',
help="List flavor profiles according to their provider.",
)
return parser
def take_action(self, parsed_args):
columns = const.FLAVORPROFILE_COLUMNS
attrs = v2_utils.get_flavorprofile_attrs(self.app.client_manager,
parsed_args)
data = self.app.client_manager.load_balancer.flavorprofile_list(
**attrs)
return (columns,
(utils.get_dict_properties(s, columns, formatters={})
for s in data['flavorprofiles']))
class ShowFlavorProfile(command.ShowOne):
"""Show the details for a single flavor profile"""
def get_parser(self, prog_name):
parser = super(ShowFlavorProfile, self).get_parser(prog_name)
parser.add_argument(
'flavorprofile',
metavar='<flavor_profile>',
help="Name or UUID of the flavor profile to show."
)
return parser
def take_action(self, parsed_args):
rows = const.FLAVORPROFILE_ROWS
attrs = v2_utils.get_flavorprofile_attrs(self.app.client_manager,
parsed_args)
flavorprofile_id = attrs.pop('flavorprofile_id')
data = self.app.client_manager.load_balancer.flavorprofile_show(
flavorprofile_id=flavorprofile_id
)
return (rows, (utils.get_dict_properties(
data, rows, formatters={})))
class SetFlavorProfile(command.Command):
"""Update a flavor profile"""
def get_parser(self, prog_name):
parser = super(SetFlavorProfile, self).get_parser(prog_name)
parser.add_argument(
'flavorprofile',
metavar='<flavor_profile>',
help='Name or UUID of the flavor profile to update.'
)
parser.add_argument(
'--name',
metavar='<name>',
help="Set the name of the flavor profile."
)
parser.add_argument(
'--provider',
metavar='<provider_name>',
help="Set the provider of the flavor profile."
)
parser.add_argument(
'--flavor-data',
metavar='<flavor_data>',
help="Set the flavor data of the flavor profile."
)
return parser
def take_action(self, parsed_args):
attrs = v2_utils.get_flavorprofile_attrs(self.app.client_manager,
parsed_args)
flavorprofile_id = attrs.pop('flavorprofile_id')
body = {'flavorprofile': attrs}
self.app.client_manager.load_balancer.flavorprofile_set(
flavorprofile_id, json=body)

42
octaviaclient/osc/v2/utils.py

@ -449,6 +449,48 @@ def get_provider_attrs(parsed_args):
return _map_attrs(vars(parsed_args), attr_map)
def get_flavor_attrs(client_manager, parsed_args):
attr_map = {
'name': ('name', str),
'flavor': (
'flavor_id',
'flavors',
client_manager.load_balancer.flavor_list,
),
'flavorprofile': (
'flavor_profile_id',
'flavorprofiles',
client_manager.load_balancer.flavorprofile_list,
),
'enable': ('enabled', lambda x: True),
'disable': ('enabled', lambda x: False),
'description': ('description', str),
}
_attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map)
return attrs
def get_flavorprofile_attrs(client_manager, parsed_args):
attr_map = {
'name': ('name', str),
'flavorprofile': (
'flavorprofile_id',
'flavorprofiles',
client_manager.load_balancer.flavorprofile_list,
),
'provider': ('provider_name', str),
'flavor_data': ('flavor_data', str),
}
_attrs = vars(parsed_args)
attrs = _map_attrs(_attrs, attr_map)
return attrs
def format_list(data):
return '\n'.join(i['id'] for i in data)

189
octaviaclient/tests/unit/api/test_octavia.py

@ -37,6 +37,8 @@ FAKE_HM = uuidutils.generate_uuid()
FAKE_PRJ = uuidutils.generate_uuid()
FAKE_AMP = uuidutils.generate_uuid()
FAKE_PROVIDER = 'fake_provider'
FAKE_FV = uuidutils.generate_uuid()
FAKE_FVPF = uuidutils.generate_uuid()
LIST_LB_RESP = {
@ -102,6 +104,16 @@ LIST_PROVIDER_RESP = {
{'name': 'provider2', 'description': 'description of provider2'}]
}
LIST_FV_RESP = {
'flavors': [{'name': 'fv1'},
{'name': 'fv2'}]
}
LIST_FVPF_RESP = {
'flavorprofiles': [{'name': 'fvpf1'},
{'name': 'fvpf2'}]
}
SINGLE_LB_RESP = {'loadbalancer': {'id': FAKE_LB, 'name': 'lb1'}}
SINGLE_LB_UPDATE = {"loadbalancer": {"admin_state_up": False}}
SINGLE_LB_STATS_RESP = {'bytes_in': '0'}
@ -135,6 +147,12 @@ SINGLE_PROVIDER_CAPABILITY_RESP = {
[{'some_capability': 'Capabilicy description'}]
}
SINGLE_FV_RESP = {'flavor': {'id': FAKE_FV, 'name': 'fv1'}}
SINGLE_FV_UPDATE = {'flavor': {'enabled': False}}
SINGLE_FVPF_RESP = {'flavorprofile': {'id': FAKE_FVPF, 'name': 'fvpf1'}}
SINGLE_FVPF_UPDATE = {'flavorprofile': {'provider_name': 'fake_provider'}}
class TestOctaviaClient(utils.TestCase):
@ -933,3 +951,174 @@ class TestLoadBalancer(TestOctaviaClient):
ret = self.api.provider_capability_list(FAKE_PROVIDER)
self.assertEqual(
SINGLE_PROVIDER_CAPABILITY_RESP, ret)
def test_list_flavor_no_options(self):
self.requests_mock.register_uri(
'GET',
FAKE_LBAAS_URL + 'flavors',
json=LIST_FV_RESP,
status_code=200,
)
ret = self.api.flavor_list()
self.assertEqual(LIST_FV_RESP, ret)
def test_show_flavor(self):
self.requests_mock.register_uri(
'GET',
FAKE_LBAAS_URL + 'flavors/' + FAKE_FV,
json=SINGLE_FV_RESP,
status_code=200
)
ret = self.api.flavor_show(FAKE_FV)
self.assertEqual(SINGLE_FV_RESP['flavor'], ret)
def test_create_flavor(self):
self.requests_mock.register_uri(
'POST',
FAKE_LBAAS_URL + 'flavors',
json=SINGLE_FV_RESP,
status_code=200
)
ret = self.api.flavor_create(json=SINGLE_FV_RESP)
self.assertEqual(SINGLE_FV_RESP, ret)
def test_create_flavor_error(self):
self.requests_mock.register_uri(
'POST',
FAKE_LBAAS_URL + 'flavors',
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self._error_message,
self.api.flavor_create,
json=SINGLE_FV_RESP)
def test_set_flavor(self):
self.requests_mock.register_uri(
'PUT',
FAKE_LBAAS_URL + 'flavors/' + FAKE_FV,
json=SINGLE_FV_UPDATE,
status_code=200
)
ret = self.api.flavor_set(FAKE_FV, json=SINGLE_FV_UPDATE)
self.assertEqual(SINGLE_FV_UPDATE, ret)
def test_set_flavor_error(self):
self.requests_mock.register_uri(
'PUT',
FAKE_LBAAS_URL + 'flavors/' + FAKE_FV,
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self._error_message,
self.api.flavor_set,
FAKE_FV,
json=SINGLE_FV_UPDATE)
def test_delete_flavor(self):
self.requests_mock.register_uri(
'DELETE',
FAKE_LBAAS_URL + 'flavors/' + FAKE_FV,
status_code=200
)
ret = self.api.flavor_delete(FAKE_FV)
self.assertEqual(200, ret.status_code)
def test_delete_flavor_error(self):
self.requests_mock.register_uri(
'DELETE',
FAKE_LBAAS_URL + 'flavors/' + FAKE_FV,
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self._error_message,
self.api.flavor_delete,
FAKE_FV)
def test_list_flavorprofiles_no_options(self):
self.requests_mock.register_uri(
'GET',
FAKE_LBAAS_URL + 'flavorprofiles',
json=LIST_FVPF_RESP,
status_code=200,
)
ret = self.api.flavorprofile_list()
self.assertEqual(LIST_FVPF_RESP, ret)
def test_show_flavorprofile(self):
self.requests_mock.register_uri(
'GET',
FAKE_LBAAS_URL + 'flavorprofiles/' + FAKE_FVPF,
json=SINGLE_FVPF_RESP,
status_code=200
)
ret = self.api.flavorprofile_show(FAKE_FVPF)
self.assertEqual(SINGLE_FVPF_RESP['flavorprofile'], ret)
def test_create_flavorprofile(self):
self.requests_mock.register_uri(
'POST',
FAKE_LBAAS_URL + 'flavorprofiles',
json=SINGLE_FVPF_RESP,
status_code=200
)
ret = self.api.flavorprofile_create(json=SINGLE_FVPF_RESP)
self.assertEqual(SINGLE_FVPF_RESP, ret)
def test_create_flavorprofile_error(self):
self.requests_mock.register_uri(
'POST',
FAKE_LBAAS_URL + 'flavorprofiles',
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self._error_message,
self.api.flavorprofile_create,
json=SINGLE_FVPF_RESP)
def test_set_flavorprofiles(self):
self.requests_mock.register_uri(
'PUT',
FAKE_LBAAS_URL + 'flavorprofiles/' + FAKE_FVPF,
json=SINGLE_FVPF_UPDATE,
status_code=200
)
ret = self.api.flavorprofile_set(FAKE_FVPF, json=SINGLE_FVPF_UPDATE)
self.assertEqual(SINGLE_FVPF_UPDATE, ret)
def test_set_flavorprofiles_error(self):
self.requests_mock.register_uri(
'PUT',
FAKE_LBAAS_URL + 'flavorprofiles/' + FAKE_FVPF,
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self._error_message,
self.api.flavorprofile_set,
FAKE_FVPF, json=SINGLE_FVPF_UPDATE)
def test_delete_flavorprofile(self):
self.requests_mock.register_uri(
'DELETE',
FAKE_LBAAS_URL + 'flavorprofiles/' + FAKE_FVPF,
status_code=200
)
ret = self.api.flavorprofile_delete(FAKE_FVPF)
self.assertEqual(200, ret.status_code)
def test_delete_flavorprofile_error(self):
self.requests_mock.register_uri(
'DELETE',
FAKE_LBAAS_URL + 'flavorprofiles/' + FAKE_FVPF,
text='{"faultstring": "%s"}' % self._error_message,
status_code=400
)
self.assertRaisesRegex(octavia.OctaviaClientException,
self._error_message,
self.api.flavorprofile_delete,
FAKE_FVPF)

14
octaviaclient/tests/unit/osc/v2/constants.py

@ -163,3 +163,17 @@ CAPABILITY_ATTRS = {
"name": "some_capabilicy",
"description": "Description of capabilicy."
}
FLAVOR_ATTRS = {
"id": uuidutils.generate_uuid(),
"name": "fv-name-" + uuidutils.generate_uuid(dashed=True),
"flavor_profile_id": None,
"enabled": True,
}
FLAVORPROFILE_ATTRS = {
"id": uuidutils.generate_uuid(),
"name": "fvpf-name-" + uuidutils.generate_uuid(dashed=True),
"provider_name": "mock_provider",
"flavor_data": '{"mock_key": "mock_value"}',
}

172
octaviaclient/tests/unit/osc/v2/test_flavor.py

@ -0,0 +1,172 @@
# Copyright (c) 2018 China Telecom 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.
import copy
import mock
from osc_lib import exceptions
from octaviaclient.osc.v2 import constants
from octaviaclient.osc.v2 import flavor
from octaviaclient.tests.unit.osc.v2 import constants as attr_consts
from octaviaclient.tests.unit.osc.v2 import fakes
class TestFlavor(fakes.TestOctaviaClient):
def setUp(self):
super(TestFlavor, self).setUp()
self._flavor = fakes.createFakeResource('flavor')
self.flavor_info = copy.deepcopy(attr_consts.FLAVOR_ATTRS)
self.columns = copy.deepcopy(constants.FLAVOR_COLUMNS)
self.api_mock = mock.Mock()
self.api_mock.flavor_list.return_value = copy.deepcopy(
{'flavors': [attr_consts.FLAVOR_ATTRS]})
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
class TestFlavorList(TestFlavor):
def setUp(self):
super(TestFlavorList, self).setUp()
self.datalist = (tuple(
attr_consts.FLAVOR_ATTRS[k] for k in self.columns),)
self.cmd = flavor.ListFlavor(self.app, None)
def test_flavor_list_no_options(self):
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.flavor_list.assert_called_with()
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_flavor_list_with_options(self):
arglist = ['--name', 'flavor1']
verifylist = [('name', 'flavor1')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.flavor_list.assert_called_with(name='flavor1')
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestFlavorDelete(TestFlavor):
def setUp(self):
super(TestFlavorDelete, self).setUp()
self.cmd = flavor.DeleteFlavor(self.app, None)
def test_flavor_delete(self):
arglist = [self._flavor.id]
verifylist = [
('flavor', self._flavor.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavor_delete.assert_called_with(
flavor_id=self._flavor.id)
def test_flavor_delete_failure(self):
arglist = ['unknown_flavor']
verifylist = [
('flavor', 'unknown_flavor')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args)
self.assertNotCalled(self.api_mock.flavor_delete)
class TestFlavorCreate(TestFlavor):
def setUp(self):
super(TestFlavorCreate, self).setUp()
self.api_mock.flavor_create.return_value = {
'flavor': self.flavor_info}
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
self.cmd = flavor.CreateFlavor(self.app, None)
@mock.patch('octaviaclient.osc.v2.utils.get_flavor_attrs')
def test_flavor_create(self, mock_client):
mock_client.return_value = self.flavor_info
arglist = ['--name', self._flavor.name,
'--flavorprofile', 'mock_fvpf_id',
'--description', 'description for flavor']
verifylist = [
('flavorprofile', 'mock_fvpf_id'),
('name', self._flavor.name),
('description', 'description for flavor')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavor_create.assert_called_with(
json={'flavor': self.flavor_info})
class TestFlavorShow(TestFlavor):
def setUp(self):
super(TestFlavorShow, self).setUp()
self.api_mock.flavor_show.return_value = self.flavor_info
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
self.cmd = flavor.ShowFlavor(self.app, None)
def test_flavor_show(self):
arglist = [self._flavor.id]
verifylist = [
('flavor', self._flavor.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavor_show.assert_called_with(
flavor_id=self._flavor.id)
class TestFlavorSet(TestFlavor):
def setUp(self):
super(TestFlavorSet, self).setUp()
self.cmd = flavor.SetFlavor(self.app, None)
def test_flavor_set(self):
arglist = [self._flavor.id, '--name', 'new_name']
verifylist = [
('flavor', self._flavor.id),
('name', 'new_name'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavor_set.assert_called_with(
self._flavor.id, json={
'flavor': {
'name': 'new_name'
}})

174
octaviaclient/tests/unit/osc/v2/test_flavorprofile.py

@ -0,0 +1,174 @@
# Copyright (c) 2018 China Telecom 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.
import copy
import mock
from osc_lib import exceptions
from octaviaclient.osc.v2 import constants
from octaviaclient.osc.v2 import flavorprofile
from octaviaclient.tests.unit.osc.v2 import constants as attr_consts
from octaviaclient.tests.unit.osc.v2 import fakes
class TestFlavorProfile(fakes.TestOctaviaClient):
def setUp(self):
super(TestFlavorProfile, self).setUp()
self._flavorprofile = fakes.createFakeResource('flavorprofile')
self.flavorprofile_info = copy.deepcopy(
attr_consts.FLAVORPROFILE_ATTRS)
self.columns = copy.deepcopy(constants.FLAVORPROFILE_COLUMNS)
self.api_mock = mock.Mock()
self.api_mock.flavorprofile_list.return_value = copy.deepcopy(
{'flavorprofiles': [attr_consts.FLAVORPROFILE_ATTRS]})
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
class TestFlavorProfileList(TestFlavorProfile):
def setUp(self):
super(TestFlavorProfileList, self).setUp()
self.datalist = (tuple(
attr_consts.FLAVORPROFILE_ATTRS[k] for k in self.columns),)
self.cmd = flavorprofile.ListFlavorProfile(self.app, None)
def test_flavorprofile_list_no_options(self):
arglist = []
verifylist = []
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.flavorprofile_list.assert_called_with()
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
def test_flavorprofile_list_with_options(self):
arglist = ['--name', 'flavorprofile1']
verifylist = [('name', 'flavorprofile1')]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.api_mock.flavorprofile_list.assert_called_with(
name='flavorprofile1')
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, tuple(data))
class TestFlavorProfileDelete(TestFlavorProfile):
def setUp(self):
super(TestFlavorProfileDelete, self).setUp()
self.cmd = flavorprofile.DeleteFlavorProfile(self.app, None)
def test_flavorprofile_delete(self):
arglist = [self._flavorprofile.id]
verifylist = [
('flavorprofile', self._flavorprofile.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavorprofile_delete.assert_called_with(
flavorprofile_id=self._flavorprofile.id)
def test_flavorprofile_delete_failure(self):
arglist = ['unknown_flavorprofile']
verifylist = [
('flavorprofile', 'unknown_flavorprofile')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError, self.cmd.take_action,
parsed_args)
self.assertNotCalled(self.api_mock.flavorprofile_delete)
class TestFlavorProfileCreate(TestFlavorProfile):
def setUp(self):
super(TestFlavorProfileCreate, self).setUp()
self.api_mock.flavorprofile_create.return_value = {
'flavorprofile': self.flavorprofile_info}
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
self.cmd = flavorprofile.CreateFlavorProfile(self.app, None)
@mock.patch('octaviaclient.osc.v2.utils.get_flavorprofile_attrs')
def test_flavorprofile_create(self, mock_client):
mock_client.return_value = self.flavorprofile_info
arglist = ['--name', self._flavorprofile.name,
'--provider', 'mock_provider',
'--flavor-data', '{"mock_key": "mock_value"}']
verifylist = [
('provider', 'mock_provider'),
('name', self._flavorprofile.name),
('flavor_data', '{"mock_key": "mock_value"}')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavorprofile_create.assert_called_with(
json={'flavorprofile': self.flavorprofile_info})
class TestFlavorProfileShow(TestFlavorProfile):
def setUp(self):
super(TestFlavorProfileShow, self).setUp()
self.api_mock.flavorprofile_show.return_value = self.flavorprofile_info
lb_client = self.app.client_manager
lb_client.load_balancer = self.api_mock
self.cmd = flavorprofile.ShowFlavorProfile(self.app, None)
def test_flavorprofile_show(self):
arglist = [self._flavorprofile.id]
verifylist = [
('flavorprofile', self._flavorprofile.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavorprofile_show.assert_called_with(
flavorprofile_id=self._flavorprofile.id)
class TestFlavorProfileSet(TestFlavorProfile):
def setUp(self):
super(TestFlavorProfileSet, self).setUp()
self.cmd = flavorprofile.SetFlavorProfile(self.app, None)
def test_flavorprofile_set(self):
arglist = [self._flavorprofile.id, '--name', 'new_name']
verifylist = [
('flavorprofile', self._flavorprofile.id),
('name', 'new_name'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.cmd.take_action(parsed_args)
self.api_mock.flavorprofile_set.assert_called_with(
self._flavorprofile.id, json={
'flavorprofile': {
'name': 'new_name'
}})

4
releasenotes/notes/add-flavor-support-75c6d5bec48b1d18.yaml

@ -0,0 +1,4 @@
---
features:
- |
Adds client support for octavia provider flavor and flavor_profile.

10
setup.cfg

@ -77,6 +77,16 @@ openstack.load_balancer.v2 =
loadbalancer_amphora_failover = octaviaclient.osc.v2.amphora:FailoverAmphora
loadbalancer_provider_list = octaviaclient.osc.v2.provider:ListProvider
loadbalancer_provider_capability_list = octaviaclient.osc.v2.provider:ListProviderFlavorCapability
loadbalancer_flavorprofile_create = octaviaclient.osc.v2.flavorprofile:CreateFlavorProfile
loadbalancer_flavorprofile_list = octaviaclient.osc.v2.flavorprofile:ListFlavorProfile
loadbalancer_flavorprofile_delete = octaviaclient.osc.v2.flavorprofile:DeleteFlavorProfile
loadbalancer_flavorprofile_show = octaviaclient.osc.v2.flavorprofile:ShowFlavorProfile
loadbalancer_flavorprofile_set = octaviaclient.osc.v2.flavorprofile:SetFlavorProfile
loadbalancer_flavor_create = octaviaclient.osc.v2.flavor:CreateFlavor
loadbalancer_flavor_list = octaviaclient.osc.v2.flavor:ListFlavor
loadbalancer_flavor_delete = octaviaclient.osc.v2.flavor:DeleteFlavor
loadbalancer_flavor_show = octaviaclient.osc.v2.flavor:ShowFlavor
loadbalancer_flavor_set = octaviaclient.osc.v2.flavor:SetFlavor
[build_sphinx]
source-dir = doc/source

Loading…
Cancel
Save