Skip to content

Commit 0fb1378

Browse files
committed
OSC Network Meter
Implement Neutron feature of Metering into OpenStack Client. Meter Rules will be implemented in seperate patchset. Partially Implements: blueprint neutron-client-metering Change-Id: Ie82d42759504cbdb1c991c5183c1f0adf59e60fe
1 parent 0948aa6 commit 0fb1378

8 files changed

Lines changed: 745 additions & 0 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
=============
2+
network meter
3+
=============
4+
5+
A **network meter** allows operators to measure
6+
traffic for a specific IP range. The following commands
7+
are specific to the L3 metering extension.
8+
9+
Network v2
10+
11+
network meter create
12+
--------------------
13+
14+
Create network meter
15+
16+
.. program:: network meter create
17+
.. code:: bash
18+
19+
openstack network meter create
20+
[--project <project> [--project-domain <project-domain>]]
21+
[--description <description>]
22+
[--share | --no-share]
23+
<name>
24+
25+
.. option:: --project <project>
26+
27+
Owner's project (name of ID)
28+
29+
*Network version 2 only*
30+
31+
.. option:: --description <description>
32+
33+
Description of meter
34+
35+
*Network version 2 only*
36+
37+
.. option:: --share
38+
39+
Share the meter between projects
40+
41+
.. option:: --no-share
42+
43+
Do not share the meter between projects (Default)
44+
45+
.. _network_meter_create:
46+
.. describe:: <name>
47+
48+
New meter name
49+
50+
network meter delete
51+
--------------------
52+
53+
Delete network meter(s)
54+
55+
.. program:: network meter delete
56+
.. code:: bash
57+
58+
openstack network meter delete
59+
<meter> [<meter> ...]
60+
61+
.. _network_meter_delete:
62+
.. describe:: <meter>
63+
64+
Meter(s) to delete (name or ID)
65+
66+
network meter list
67+
------------------
68+
69+
List network meters
70+
71+
.. program:: network meter list
72+
.. code:: bash
73+
74+
openstack network meter list
75+
76+
77+
network meter show
78+
------------------
79+
80+
Show network meter
81+
82+
.. program:: network meter show
83+
.. code:: bash
84+
85+
openstack network meter show
86+
<meter>
87+
88+
.. _network_meter_show:
89+
.. describe:: <meter>
90+
91+
Meter to display (name or ID)

doc/source/commands.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ referring to both Compute and Volume quotas.
111111
* ``module``: (**Internal**) - installed Python modules in the OSC process
112112
* ``network``: (**Compute**, **Network**) - a virtual network for connecting servers and other resources
113113
* ``network agent``: (**Network**) - A network agent is an agent that handles various tasks used to implement virtual networks
114+
* ``network meter``: (**Network**) - allow traffic metering in a network
114115
* ``network rbac``: (**Network**) - an RBAC policy for network resources
115116
* ``network qos policy``: (**Network**) - a QoS policy for network resources
116117
* ``network qos rule type``: (**Network**) - list of QoS available rule types
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
#
13+
14+
"""Metering Label Implementations"""
15+
16+
import logging
17+
18+
from osc_lib.command import command
19+
from osc_lib import exceptions
20+
from osc_lib import utils
21+
22+
from openstackclient.i18n import _
23+
from openstackclient.identity import common as identity_common
24+
from openstackclient.network import sdk_utils
25+
26+
LOG = logging.getLogger(__name__)
27+
28+
29+
def _get_columns(item):
30+
column_map = {
31+
'is_shared': 'shared',
32+
'tenant_id': 'project_id',
33+
}
34+
return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map)
35+
36+
37+
def _get_attrs(client_manager, parsed_args):
38+
attrs = {}
39+
40+
if parsed_args.description is not None:
41+
attrs['description'] = parsed_args.description
42+
if parsed_args.project is not None and 'project' in parsed_args:
43+
identity_client = client_manager.identity
44+
project_id = identity_common.find_project(
45+
identity_client,
46+
parsed_args.project,
47+
parsed_args.project_domain,
48+
).id
49+
attrs['tenant_id'] = project_id
50+
if parsed_args.share:
51+
attrs['shared'] = True
52+
if parsed_args.no_share:
53+
attrs['shared'] = False
54+
if parsed_args.name is not None:
55+
attrs['name'] = parsed_args.name
56+
57+
return attrs
58+
59+
60+
# TODO(ankur-gupta-f): Use the SDK resource mapped attribute names once the
61+
# OSC minimum requirements include SDK 1.0.
62+
class CreateMeter(command.ShowOne):
63+
_description = _("Create network meter")
64+
65+
def get_parser(self, prog_name):
66+
parser = super(CreateMeter, self).get_parser(prog_name)
67+
68+
parser.add_argument(
69+
'--description',
70+
metavar='<description>',
71+
help=_("Create description for meter")
72+
)
73+
parser.add_argument(
74+
'--project',
75+
metavar='<project>',
76+
help=_("Owner's project (name or ID)")
77+
)
78+
79+
identity_common.add_project_domain_option_to_parser(parser)
80+
share_group = parser.add_mutually_exclusive_group()
81+
share_group.add_argument(
82+
'--share',
83+
action='store_true',
84+
default=None,
85+
help=_("Share meter between projects")
86+
)
87+
share_group.add_argument(
88+
'--no-share',
89+
action='store_true',
90+
help=_("Do not share meter between projects")
91+
)
92+
parser.add_argument(
93+
'name',
94+
metavar='<name>',
95+
help=_('Name of meter'),
96+
)
97+
98+
return parser
99+
100+
def take_action(self, parsed_args):
101+
client = self.app.client_manager.network
102+
attrs = _get_attrs(self.app.client_manager, parsed_args)
103+
obj = client.create_metering_label(**attrs)
104+
display_columns, columns = _get_columns(obj)
105+
data = utils.get_item_properties(obj, columns, formatters={})
106+
107+
return (display_columns, data)
108+
109+
110+
# TODO(ankur-gupta-f): Use the SDK resource mapped attribute names once the
111+
# OSC minimum requirements include SDK 1.0.
112+
class DeleteMeter(command.Command):
113+
_description = _("Delete network meter")
114+
115+
def get_parser(self, prog_name):
116+
parser = super(DeleteMeter, self).get_parser(prog_name)
117+
118+
parser.add_argument(
119+
'meter',
120+
metavar='<meter>',
121+
nargs='+',
122+
help=_('Meter to delete (name or ID)')
123+
)
124+
return parser
125+
126+
def take_action(self, parsed_args):
127+
client = self.app.client_manager.network
128+
result = 0
129+
130+
for meter in parsed_args.meter:
131+
try:
132+
obj = client.find_metering_label(meter, ignore_missing=False)
133+
client.delete_metering_label(obj)
134+
except Exception as e:
135+
result += 1
136+
LOG.error(_("Failed to delete meter with "
137+
"ID '%(meter)s': %(e)s"),
138+
{"meter": meter, "e": e})
139+
if result > 0:
140+
total = len(parsed_args.meter)
141+
msg = (_("%(result)s of %(total)s meters failed "
142+
"to delete.") % {"result": result, "total": total})
143+
raise exceptions.CommandError(msg)
144+
145+
146+
class ListMeter(command.Lister):
147+
_description = _("List network meters")
148+
149+
def take_action(self, parsed_args):
150+
client = self.app.client_manager.network
151+
152+
columns = (
153+
'id',
154+
'name',
155+
'description',
156+
'shared',
157+
)
158+
column_headers = (
159+
'ID',
160+
'Name',
161+
'Description',
162+
'Shared',
163+
)
164+
165+
data = client.metering_labels()
166+
return (column_headers,
167+
(utils.get_item_properties(
168+
s, columns,
169+
) for s in data))
170+
171+
172+
class ShowMeter(command.ShowOne):
173+
_description = _("Show network meter")
174+
175+
def get_parser(self, prog_name):
176+
parser = super(ShowMeter, self).get_parser(prog_name)
177+
parser.add_argument(
178+
'meter',
179+
metavar='<meter>',
180+
help=_('Meter to display (name or ID)')
181+
)
182+
return parser
183+
184+
def take_action(self, parsed_args):
185+
client = self.app.client_manager.network
186+
obj = client.find_metering_label(parsed_args.meter,
187+
ignore_missing=False)
188+
display_columns, columns = _get_columns(obj)
189+
data = utils.get_item_properties(obj, columns)
190+
return display_columns, data
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Copyright (c) 2016, Intel Corporation.
2+
# All Rights Reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
# not use this file except in compliance with the License. You may obtain
6+
# a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations
14+
# under the License.
15+
16+
import re
17+
import uuid
18+
19+
from openstackclient.tests.functional import base
20+
21+
22+
class TestMeter(base.TestCase):
23+
"""Functional tests for network meter."""
24+
25+
# NOTE(dtroyer): Do not normalize the setup and teardown of the resource
26+
# creation and deletion. Little is gained when each test
27+
# has its own needs and there are collisions when running
28+
# tests in parallel.
29+
30+
@classmethod
31+
def setUpClass(cls):
32+
# Set up some regex for matching below
33+
cls.re_name = re.compile("name\s+\|\s+([^|]+?)\s+\|")
34+
cls.re_shared = re.compile("shared\s+\|\s+(\S+)")
35+
cls.re_description = re.compile("description\s+\|\s+([^|]+?)\s+\|")
36+
37+
def test_meter_delete(self):
38+
"""Test create, delete multiple"""
39+
name1 = uuid.uuid4().hex
40+
name2 = uuid.uuid4().hex
41+
42+
raw_output = self.openstack(
43+
'network meter create ' + name1,
44+
)
45+
self.assertEqual(
46+
name1,
47+
re.search(self.re_name, raw_output).group(1),
48+
)
49+
# Check if default shared values
50+
self.assertEqual(
51+
'False',
52+
re.search(self.re_shared, raw_output).group(1)
53+
)
54+
55+
raw_output = self.openstack(
56+
'network meter create ' + name2,
57+
)
58+
self.assertEqual(
59+
name2,
60+
re.search(self.re_name, raw_output).group(1),
61+
)
62+
63+
raw_output = self.openstack(
64+
'network meter delete ' + name1 + ' ' + name2,
65+
)
66+
self.assertOutput('', raw_output)
67+
68+
def test_meter_list(self):
69+
"""Test create, list filters, delete"""
70+
name1 = uuid.uuid4().hex
71+
raw_output = self.openstack(
72+
'network meter create --description Test1 --share ' + name1,
73+
)
74+
self.addCleanup(self.openstack, 'network meter delete ' + name1)
75+
76+
self.assertEqual(
77+
'Test1',
78+
re.search(self.re_description, raw_output).group(1),
79+
)
80+
self.assertEqual(
81+
'True',
82+
re.search(self.re_shared, raw_output).group(1),
83+
)
84+
85+
name2 = uuid.uuid4().hex
86+
raw_output = self.openstack(
87+
'network meter create --description Test2 --no-share ' + name2,
88+
)
89+
self.addCleanup(self.openstack, 'network meter delete ' + name2)
90+
91+
self.assertEqual(
92+
'Test2',
93+
re.search(self.re_description, raw_output).group(1),
94+
)
95+
self.assertEqual(
96+
'False',
97+
re.search(self.re_shared, raw_output).group(1),
98+
)
99+
100+
raw_output = self.openstack('network meter list')
101+
self.assertIsNotNone(re.search(name1 + "\s+\|\s+Test1", raw_output))
102+
self.assertIsNotNone(re.search(name2 + "\s+\|\s+Test2", raw_output))

0 commit comments

Comments
 (0)