WIP. Updates to Openstack CLI to reflect Database.

Updates to Openstack Client to reflect current
state of Neutron Classiifier classifications
and comply with pep8 standards. Tests included but incomplete
until further changes to core code takes place.

Change-Id: I33165dcf3519912cdbb975366cdc5324d91f3fd7
Co-Authored-By: Nakul Dahiwade <nakul.dahiwade@intel.com>
This commit is contained in:
David Shaughnessy
2017-09-04 20:47:34 +00:00
committed by Nakul Dahiwade
parent 133d5be638
commit f296e4e96c
15 changed files with 1362 additions and 22 deletions

View File

View File

@@ -0,0 +1,164 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classification_groups"
resource = 'classification_group'
class CreateClassificationGroup(command.ShowOne):
"""Create a Classification Group."""
def get_parser(self, prog_name):
parser = super(CreateClassificationGroup, self).get_parser(prog_name)
parser.add_argument(
'name', metavar='NAME',
help=('Name of the Classification Group.'))
parser.add_argument(
'--description',
help=('Description for the Classification Group.'))
parser.add_argument(
'--classification', nargs='*',
help=('Classification value.'))
parser.add_argument(
'--classification-group', nargs='*',
help=('ID of the Classification group.'))
parser.add_argument(
'--operator',
help=('Operator to be performed.'))
parser.add_argument(
'--shared',
help=('Whether the Classification group should be '
'shared with other projects.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=True)
obj = client.create_ext(object_path, {resource: attrs})
columns = _get_columns(obj[resource])
data = utils.get_dict_properties(obj[resource], columns)
return columns, data
class DeleteClassificationGroup(command.Command):
"""Delete a given Classification Group."""
def get_parser(self, prog_name):
parser = super(DeleteClassificationGroup, self).get_parser(prog_name)
parser.add_argument(
'classification_group',
metavar="CLASSIFICATION_GROUP",
help=('ID of the Classification Group to delete.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.classification_group
client = self.app.client_manager.neutronclient
client.delete_ext(object_path + '/%s', id)
class ListClassificationGroup(command.Lister):
"""List the Classification Groups that belong to a given tenant."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classification_groups', path=object_path,
retrieve_all=True)
headers = ('ID', 'Name', 'Description', 'Classification',
'Classification_Group', 'Operator', 'Shared')
columns = ('id', 'name', 'description', 'classification',
'cg_id', 'operator', 'shared')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classification_groups']))
class ShowClassificationGroup(command.ShowOne):
"""Show information of a given Classification Group."""
def get_parser(self, prog_name):
parser = super(ShowClassificationGroup, self).get_parser(prog_name)
parser.add_argument(
'classification_group',
metavar="CLASSIFICATION_GROUP",
help=('ID of the Classification Group to display.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
cl = client.show_ext(object_path + '/%s',
parsed_args.classification_group)
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
class UpdateClassificationGroup(command.Command):
def get_parser(self, prog_name):
parser = super(UpdateClassificationGroup, self).get_parser(prog_name)
parser.add_argument(
'--name', default='',
metavar='NAME',
help=('Name of the Classification Group.'))
parser.add_argument(
'--description', default='',
help=('Description for the Classification Group.'))
parser.add_argument(
'classification_group',
metavar="CLASSIFICATION_GROUP",
help=('ID of the Classification Group to update.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.classification_group
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=False)
client.update_ext(object_path + '/%s', id, {resource: attrs})
def _get_attrs(client_manager, parsed_args, is_create=False):
attrs = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.description is not None:
attrs['description'] = str(parsed_args.description)
if is_create:
if parsed_args.classification is not None:
attrs['classification'] = parsed_args.classification
if parsed_args.classification_group is not None:
attrs['cg_id'] = parsed_args.classification_group
if parsed_args.operator is not None:
attrs['operator'] = parsed_args.operator
if parsed_args.shared is not None:
attrs['shared'] = parsed_args.shared
return attrs
def _get_columns(resource):
columns = list(resource.keys())
if 'tenant_id' in columns:
columns.remove('tenant_id')
if 'project_id' not in columns:
columns.append('project_id')
return tuple(sorted(columns))

View File

@@ -0,0 +1,33 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classification_type"
resource = 'classification_type'
class ListClassificationType(command.Lister):
"""List the Classification Types available."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classification_type',
path=object_path, retrieve_all=True)
headers = ('Name', 'Definition')
columns = ('type', 'supported_parameters')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classification_type']))

View File

@@ -0,0 +1,184 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classifications"
resource = 'classification'
class CreateEthernetClassification(command.ShowOne):
"""Create an Ethernet Classification."""
def get_parser(self, prog_name):
parser = super(CreateEthernetClassification,
self).get_parser(prog_name)
parser.add_argument(
'name', metavar='NAME',
help=('Name of the Ethernet Classification.'))
parser.add_argument(
'--description',
help=('Description for the Ethernet Classification.'))
parser.add_argument(
'--negated',
help=('Whether the complement of the Ethernet '
'Classification should be matched.'))
parser.add_argument(
'--shared',
help=('Whether the Ethernet Classification should '
'be shared with other projects.'))
parser.add_argument(
'--src-addr',
help=('Source MAC Address of the Ethernet Classification.'))
parser.add_argument(
'--dst-addr',
help=('Destination MAC Address of the Ethernet '
'Classification.'))
parser.add_argument(
'--ethertype',
help=('Protocol value of the Ethernet Classification.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=True)
obj = client.create_ext(object_path, {resource: attrs})
columns = _get_columns(obj[resource])
data = utils.get_dict_properties(obj[resource], columns)
return columns, data
class DeleteEthernetClassification(command.Command):
"""Delete a given Ethernet Classification."""
def get_parser(self, prog_name):
parser = super(DeleteEthernetClassification,
self).get_parser(prog_name)
parser.add_argument(
'ethernet_classification',
metavar="ETHERNET_CLASSIFICATION",
help=('ID of the Ethernet Classification to delete.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.ethernet_classification
client = self.app.client_manager.neutronclient
client.delete_ext(object_path + '/%s', id)
class ListEthernetClassification(command.Lister):
"""List the Ethernet Classifications that belong to a given tenant."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classifications',
path=object_path, retrieve_all=True, c_type='ethernet')
headers = ('ID', 'Name', 'Description', 'Negated', 'Shared',
'Definition')
columns = ('id', 'name', 'description', 'negated', 'shared',
'definition')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classifications']))
class ShowEthernetClassification(command.ShowOne):
"""Show information of a given Ethernet Classification."""
def get_parser(self, prog_name):
parser = super(ShowEthernetClassification, self).get_parser(prog_name)
parser.add_argument(
'ethernet_classification',
metavar="ETHERNET_CLASSIFICATION",
help=('ID of the Ethernet Classification to display.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
cl = client.show_ext(object_path + '/%s',
parsed_args.ethernet_classification,
c_type='ethernet')
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
class UpdateEthernetClassification(command.ShowOne):
"""Update name and description of a given Ethernet Classification."""
def get_parser(self, prog_name):
parser = super(UpdateEthernetClassification,
self).get_parser(prog_name)
parser.add_argument(
'--name', default='',
metavar='NAME',
help=('Name of the Ethernet Classification.'))
parser.add_argument(
'--description', default='',
help=('Description for the Ethernet Classification.'))
parser.add_argument(
'ethernet_classification',
metavar="ETHERNET_CLASSIFICATION",
help=('ID of the Ethernet Classification to update.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.ethernet_classification
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=False)
cl = client.update_ext(object_path + '/%s', id, {resource: attrs})
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
def _get_attrs(client_manager, parsed_args, is_create=False):
attrs = {}
definition = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.description is not None:
attrs['description'] = str(parsed_args.description)
if is_create:
attrs['c_type'] = 'ethernet'
if parsed_args.negated is not None:
attrs['negated'] = str(parsed_args.negated)
if parsed_args.shared is not None:
attrs['shared'] = str(parsed_args.shared)
if parsed_args.src_addr is not None:
definition['src_addr'] = parsed_args.src_addr
if parsed_args.dst_addr is not None:
definition['dst_addr'] = parsed_args.dst_addr
if parsed_args.ethertype is not None:
definition['ethertype'] = parsed_args.ethertype
attrs['definition'] = definition
return attrs
def _get_columns(resource):
columns = list(resource.keys())
if 'tenant_id' in columns:
columns.remove('tenant_id')
if 'project_id' not in columns:
columns.append('project_id')
return tuple(sorted(columns))

View File

@@ -0,0 +1,235 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classifications"
resource = 'classification'
class CreateIPV4Classification(command.ShowOne):
"""Create an IPV4 Classification."""
def get_parser(self, prog_name):
parser = super(CreateIPV4Classification, self).get_parser(prog_name)
parser.add_argument(
'name', metavar='NAME',
help=('Name of the IPV4 Classification.'))
parser.add_argument(
'--description',
help=('Description for the IPV4 Classification.'))
parser.add_argument(
'--negated',
help=('Whether the complement of the IPV4 '
'Classification should be matched.'))
parser.add_argument(
'--shared',
help=('Whether the IPV4 Classification should be '
'shared with other projects.'))
parser.add_argument(
'--dscp',
help=('DSCP Classification value. Type of Service.'))
parser.add_argument(
'--dscp-mask',
help=('DSCP Classification value. Type of Service.'))
parser.add_argument(
'--ecn',
help=('Allows notification of network congestion.'))
parser.add_argument(
'--length-min',
help=('Minimum length of the IP Packet, including '
'IP header and IP payload.'))
parser.add_argument(
'--length-max',
help=('Maximum length of the IP Packet, including '
'IP header and IP payload.'))
parser.add_argument(
'--flags',
help=('Whether the packet can be fragmented.'))
parser.add_argument(
'--flags-mask',
help=('Whether the packet can be fragmented.'))
parser.add_argument(
'--ttl-min',
help=('Minimum number of hops which the packet may '
'be routed over.'))
parser.add_argument(
'--ttl-max',
help=('Maximum number of hops which the packet may '
'be routed over.'))
parser.add_argument(
'--protocol',
help=('Type of transport the packet belongs to.'))
parser.add_argument(
'--src-addr',
help=('Source Address of the IPV4 Classification.'))
parser.add_argument(
'--dst-addr',
help=('Destination Address of the IPV4 Classification.'))
parser.add_argument(
'--options',
help=('Options values for the IPV4 Classification.'))
parser.add_argument(
'--options-mask',
help=('Options values for the IPV4 Classification.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=True)
obj = client.create_ext(object_path, {resource: attrs})
columns = _get_columns(obj[resource])
data = utils.get_dict_properties(obj[resource], columns)
return columns, data
class DeleteIPV4Classification(command.Command):
"""Delete a given IPV4 Classification."""
def get_parser(self, prog_name):
parser = super(DeleteIPV4Classification, self).get_parser(prog_name)
parser.add_argument(
'ipv4_classification',
metavar="IPV4_CLASSIFICATION",
help=('ID of the IPV4 Classification to delete.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.ipv4_classification
client = self.app.client_manager.neutronclient
client.delete_ext(object_path + '/%s', id)
class ListIPV4Classification(command.Lister):
"""List the IPV4 Classification that belong to a given tenant."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classifications',
path=object_path, retrieve_all=True, c_type='ipv4')
headers = ('ID', 'Name', 'Description', 'Negated', 'Shared',
'Definition')
columns = ('id', 'name', 'description', 'negated', 'shared',
'definition')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classifications']))
class ShowIPV4Classification(command.ShowOne):
"""Show information of a given IPV4 Classification"""
def get_parser(self, prog_name):
parser = super(ShowIPV4Classification, self).get_parser(prog_name)
parser.add_argument(
'ipv4_classification',
metavar="IPV4_CLASSIFICATION",
help=('ID of the IPV4 Classification to display.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
cl = client.show_ext(object_path + '/%s',
parsed_args.ipv4_classification, c_type='ipv4')
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
class UpdateIPV4Classification(command.ShowOne):
"""Update name and description of a given IPV4Classification."""
def get_parser(self, prog_name):
parser = super(UpdateIPV4Classification, self).get_parser(prog_name)
parser.add_argument(
'--name', default='',
metavar='NAME',
help=('Name of the IPV4 Classification.'))
parser.add_argument(
'--description', default='',
help=('Description of the IPV4 Classification.'))
parser.add_argument(
'ipv4_classification',
metavar="IPV4_CLASSIFICATION",
help=('ID of the IPV4 Classification to update.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.ipv4_classification
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=False)
cl = client.update_ext(object_path + '/%s', id, {resource: attrs})
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
def _get_attrs(client_manager, parsed_args, is_create=False):
attrs = {}
definition = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.description is not None:
attrs['description'] = str(parsed_args.description)
if is_create:
attrs['c_type'] = 'ipv4'
if parsed_args.negated is not None:
attrs['negated'] = str(parsed_args.negated)
if parsed_args.shared is not None:
attrs['shared'] = str(parsed_args.shared)
if parsed_args.dscp is not None:
definition['dscp'] = parsed_args.dscp
if parsed_args.dscp_mask is not None:
definition['dscp_mask'] = parsed_args.dscp_mask
if parsed_args.ecn is not None:
definition['ecn'] = parsed_args.ecn
if parsed_args.length_min is not None:
definition['length_min'] = parsed_args.length_min
if parsed_args.length_max is not None:
definition['length_max'] = parsed_args.length_max
if parsed_args.ttl_min is not None:
definition['ttl_min'] = parsed_args.ttl_min
if parsed_args.flags is not None:
definition['flags'] = parsed_args.flags
if parsed_args.flags_mask is not None:
definition['flags_mask'] = parsed_args.flags_mask
if parsed_args.protocol is not None:
definition['protocol'] = parsed_args.protocol
if parsed_args.src_addr is not None:
definition['src_addr'] = parsed_args.src_addr
if parsed_args.dst_addr is not None:
definition['dst_addr'] = parsed_args.dst_addr
if parsed_args.options is not None:
definition['options'] = parsed_args.options
if parsed_args.options_mask is not None:
definition['options_mask'] = parsed_args.options_mask
attrs['definition'] = definition
return attrs
def _get_columns(resource):
columns = list(resource.keys())
if 'tenant_id' in columns:
columns.remove('tenant_id')
if 'project_id' not in columns:
columns.append('project_id')
return tuple(sorted(columns))

View File

@@ -0,0 +1,219 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classifications"
resource = 'classification'
class CreateIPV6Classification(command.ShowOne):
"""Create an IPV6 Classification."""
def get_parser(self, prog_name):
parser = super(CreateIPV6Classification, self).get_parser(prog_name)
parser.add_argument(
'name', metavar='NAME',
help=('Name of the IPV6 Classification.'))
parser.add_argument(
'--description',
help=('Description for the IPV6 Classification.'))
parser.add_argument(
'--negated',
help=('Whether the complement of the IPV6 '
'Classification should be matched.'))
parser.add_argument(
'--shared',
help=('Whether the IPV6 Classification should be '
'shared with other projects.'))
parser.add_argument(
'--dscp',
help=('DSCP Classification value. Type of Service.'))
parser.add_argument(
'--dscp-mask',
help=('DSCP Classification value. Type of Service.'))
parser.add_argument(
'--ecn',
help=('Allows notification of network congestion.'))
parser.add_argument(
'--length-min',
help=('Minimum length of the Packet, following the IPV6 '
'Header.'))
parser.add_argument(
'--length-max',
help=('Maximum length of the Packet, following the IPV6 '
'Header.'))
parser.add_argument(
'--next-header',
help=('Type of the next header. Transport protocol used by '
'the packet\'s payload.'))
parser.add_argument(
'--hops-min',
help=('Minimum number of hops which the packet may be routed '
'over.'))
parser.add_argument(
'--hops-max',
help=('Maximum number of hops which the packet may be routed '
'over.'))
parser.add_argument(
'--src-addr',
help=('Source Address of the IPV6 Classification.'))
parser.add_argument(
'--dst-addr',
help=('Destination Address of the IPV6 Classification.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=True)
obj = client.create_ext(object_path, {resource: attrs})
columns = _get_columns(obj[resource])
data = utils.get_dict_properties(obj[resource], columns)
return columns, data
class DeleteIPV6Classification(command.Command):
"""Delete a given IPV6 Classification."""
def get_parser(self, prog_name):
parser = super(DeleteIPV6Classification, self).get_parser(prog_name)
parser.add_argument(
'ipv6_classification',
metavar="IPV6_CLASSIFICATION",
help=('ID of the IPV6 Classification to delete.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.ipv6_classification
client = self.app.client_manager.neutronclient
client.delete_ext(object_path + '/%s', id)
class ListIPV6Classification(command.Lister):
"""List the IPV6 Classification that belong to a given tenant."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classifications',
path=object_path, retrieve_all=True, c_type='ipv6')
headers = ('ID', 'Name', 'Description', 'Negated', 'Shared',
'Definition')
columns = ('id', 'name', 'description', 'negated', 'shared',
'definition')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classifications']))
class ShowIPV6Classification(command.ShowOne):
"""Show informcation of a given IPV6 Classification."""
def get_parser(self, prog_name):
parser = super(ShowIPV6Classification, self).get_parser(prog_name)
parser.add_argument(
'ipv6_classification',
metavar="IPV6_CLASSIFICATION",
help=('ID of the IPV6 Classification to display.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
cl = client.show_ext(object_path + '/%s',
parsed_args.ipv6_classification, c_type='ipv6')
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
class UpdateIPV6Classification(command.ShowOne):
"""Update name and description of a given IPV6 Classification."""
def get_parser(self, prog_name):
parser = super(UpdateIPV6Classification, self).get_parser(prog_name)
parser.add_argument(
'--name', default='',
metavar='NAME',
help=('Name of the IPV6 Classification.'))
parser.add_argument(
'--description', default='',
help=('Description for the IPV6 Classification.'))
parser.add_argument(
'ipv6_classification',
metavar="IPV6_CLASSIFICATION",
help=('ID of the IPV6 Classification to update.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.ipv6_classification
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=False)
cl = client.update_ext(object_path + '/%s', id, {resource: attrs})
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
def _get_attrs(client_manager, parsed_args, is_create=False):
attrs = {}
definition = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.description is not None:
attrs['description'] = str(parsed_args.description)
if is_create:
attrs['c_type'] = 'ipv6'
if parsed_args.negated is not None:
attrs['negated'] = str(parsed_args.negated)
if parsed_args.shared is not None:
attrs['shared'] = str(parsed_args.shared)
if parsed_args.dscp is not None:
definition['dscp'] = parsed_args.dscp
if parsed_args.dscp_mask is not None:
definition['dscp_mask'] = parsed_args.dscp_mask
if parsed_args.ecn is not None:
definition['ecn'] = parsed_args.ecn
if parsed_args.length_min is not None:
definition['length_min'] = parsed_args.length_min
if parsed_args.length_max is not None:
definition['length_max'] = parsed_args.length_max
if parsed_args.next_header is not None:
definition['next_header'] = parsed_args.next_header
if parsed_args.hops_min is not None:
definition['hops_min'] = parsed_args.hops_min
if parsed_args.hops_max is not None:
definition['hops_max'] = parsed_args.hops_max
if parsed_args.src_addr is not None:
definition['src_addr'] = parsed_args.src_addr
if parsed_args.dst_addr is not None:
definition['dst_addr'] = parsed_args.dst_addr
attrs['definition'] = definition
return attrs
def _get_columns(resource):
columns = list(resource.keys())
if 'tenant_id' in columns:
columns.remove('tenant_id')
if 'project_id' not in columns:
columns.append('project_id')
return tuple(sorted(columns))

View File

@@ -0,0 +1,205 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classifications"
resource = 'classification'
class CreateTCPClassification(command.ShowOne):
"""Create a TCP Classification."""
def get_parser(self, prog_name):
parser = super(CreateTCPClassification, self).get_parser(prog_name)
parser.add_argument(
'name', metavar='NAME',
help=('Name of the TCP Classification.'))
parser.add_argument(
'--description',
help=('Description for the TCP Classification.'))
parser.add_argument(
'--negated',
help=('Whether the complement of the TCP '
'Classification should be matched.'))
parser.add_argument(
'--shared',
help=('Whether the TCP Classification should be '
'shared with other projects.'))
parser.add_argument(
'--src-port-min',
help=('Source port TCP Classification minimum value.'))
parser.add_argument(
'--src-port-max',
help=('Source port TCP Classification maximum value.'))
parser.add_argument(
'--dst-port-min',
help=('Destination port TCP Classification minimum value.'))
parser.add_argument(
'--dst-port-max',
help=('Destination port TCP Classification maximum value.'))
parser.add_argument(
'--flags',
help=('Control flag value for the TCP Classification.'))
parser.add_argument(
'--flags-mask',
help=('Control flag valye for the TCP Classification.'))
parser.add_argument(
'--window-min',
help=('The minimum size of the receive window. Number of data '
'octets the receiver is willing to accept.'))
parser.add_argument(
'--window-max',
help=('The maximum size of the receive window. Number of data '
'octets the receiver is willing to accept.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=True)
obj = client.create_ext(object_path, {resource: attrs})
columns = _get_columns(obj[resource])
data = utils.get_dict_properties(obj[resource], columns)
return columns, data
class DeleteTCPClassification(command.Command):
"""Delete a given TCP Classification."""
def get_parser(self, prog_name):
parser = super(DeleteTCPClassification, self).get_parser(prog_name)
parser.add_argument(
'tcp_classification',
metavar="TCP_CLASSIFICATION",
help=('ID of the TCP Classification to delete.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.tcp_classification
client = self.app.client_manager.neutronclient
client.delete_ext(object_path + '/%s', id)
class ListTCPClassification(command.Lister):
"""List the TCP Classification that belong to a given tenant."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classifications',
path=object_path, retrieve_all=True, c_type='tcp')
headers = ('ID', 'Name', 'Description', 'Negated', 'Shared',
'Definition')
columns = ('id', 'name', 'description', 'negated', 'shared',
'definition')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classifications']))
class ShowTCPClassification(command.ShowOne):
"""Show information of a given TCP Classification."""
def get_parser(self, prog_name):
parser = super(ShowTCPClassification, self).get_parser(prog_name)
parser.add_argument(
'tcp_classification',
metavar="TCP_CLASSIFICATION",
help=('ID of the TCP Classification to display.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
cl = client.show_ext(object_path + '/%s',
parsed_args.tcp_classification, c_type='tcp')
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
class UpdateTCPClassification(command.ShowOne):
"""Update name and description of a given TCP Classification."""
def get_parser(self, prog_name):
parser = super(UpdateTCPClassification, self).get_parser(prog_name)
parser.add_argument(
'--name', default='',
metavar='NAME',
help=('Name of the TCP Classification.'))
parser.add_argument(
'--description', default='',
help=('Description of the TCP Classification.'))
parser.add_argument(
'tcp_classification',
metavar="TCP_CLASSIFICATION",
help=('ID of the TCP Classification to update.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.tcp_classification
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=False)
cl = client.update_ext(object_path + '/%s', id, {resource: attrs})
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
def _get_attrs(client_manager, parsed_args, is_create=False):
attrs = {}
definition = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.description is not None:
attrs['description'] = str(parsed_args.description)
if is_create:
attrs['c_type'] = 'tcp'
if parsed_args.negated is not None:
attrs['negated'] = str(parsed_args.negated)
if parsed_args.shared is not None:
attrs['shared'] = str(parsed_args.shared)
if parsed_args.src_port_min is not None:
definition['src_port_min'] = parsed_args.src_port_min
if parsed_args.src_port_max is not None:
definition['src_port_max'] = parsed_args.src_port_max
if parsed_args.dst_port_min is not None:
definition['dst_port_min'] = parsed_args.dst_port_min
if parsed_args.dst_port_max is not None:
definition['dst_port_max'] = parsed_args.dst_port_max
if parsed_args.flags is not None:
definition['flags'] = parsed_args.flags
if parsed_args.flags_mask is not None:
definition['flags_mask'] = parsed_args.flags_mask
if parsed_args.window_min is not None:
definition['window_min'] = parsed_args.window_min
if parsed_args.window_max is not None:
definition['window_max'] = parsed_args.window_max
attrs['definition'] = definition
return attrs
def _get_columns(resource):
columns = list(resource.keys())
if 'tenant_id' in columns:
columns.remove('tenant_id')
if 'project_id' not in columns:
columns.append('project_id')
return tuple(sorted(columns))

View File

@@ -0,0 +1,193 @@
# Copyright (c) 2017 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.
from osc_lib.command import command
from osc_lib import utils
object_path = "/classifications"
resource = 'classification'
class CreateUDPClassification(command.ShowOne):
"""Create an UDP Classification."""
def get_parser(self, prog_name):
parser = super(CreateUDPClassification, self).get_parser(prog_name)
parser.add_argument(
'name', metavar='NAME',
help=('Name of the UDP Classification.'))
parser.add_argument(
'--description',
help=('Description for the UDP Classification.'))
parser.add_argument(
'--negated',
help=('Whether the complement of the UDP '
'Classification should be matched.'))
parser.add_argument(
'--shared',
help=('Whether the UDP Classification should be '
'shared with other projects.'))
parser.add_argument(
'--src-port-min',
help=('Source port UDP Classification minimum value.'))
parser.add_argument(
'--src-port-max',
help=('Source port UDP Classification maximum value.'))
parser.add_argument(
'--dst-port-min',
help=('Destination port UDP Classification minimum value.'))
parser.add_argument(
'--dst-port-max',
help=('Destination port UDP Classification maximum value.'))
parser.add_argument(
'--length-min',
help=('Minimum length of the UDP header and payload data.'))
parser.add_argument(
'--length-max',
help=('Maximum length of the UDP header and payload data.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=True)
obj = client.create_ext(object_path, {resource: attrs})
columns = _get_columns(obj[resource])
data = utils.get_dict_properties(obj[resource], columns)
return columns, data
class DeleteUDPClassification(command.Command):
"""Delete a given UDP Classification."""
def get_parser(self, prog_name):
parser = super(DeleteUDPClassification, self).get_parser(prog_name)
parser.add_argument(
'udp_classification',
metavar="UDP_CLASSIFICATION",
help=('ID of the UDP Classification to delete.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.udp_classification
client = self.app.client_manager.neutronclient
client.delete_ext(object_path + '/%s', id)
class ListUDPClassification(command.Lister):
"""List the UDP Classifications that belong to a given tenant."""
def take_action(self, parsed_args):
data = self.app.client_manager.neutronclient.list(
collection='classifications',
path=object_path, retrieve_all=True, c_type='udp')
headers = ('ID', 'Name', 'Description', 'Negated', 'Shared',
'Definition')
columns = ('id', 'name', 'description', 'negated', 'shared',
'definition')
return (headers, (utils.get_dict_properties(
s, columns) for s in data['classifications']))
class ShowUDPClassification(command.ShowOne):
"""Show information of a given UDP Classification."""
def get_parser(self, prog_name):
parser = super(ShowUDPClassification, self).get_parser(prog_name)
parser.add_argument(
'udp_classification',
metavar="UDP_CLASSIFICATION",
help=('ID of the UDP Classification to display.'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.neutronclient
cl = client.show_ext(object_path + '/%s',
parsed_args.udp_classification, c_type='udp')
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
class UpdateUDPClassification(command.ShowOne):
"""Update name and description of a given UDP Classification."""
def get_parser(self, prog_name):
parser = super(UpdateUDPClassification, self).get_parser(prog_name)
parser.add_argument(
'--name', default='',
metavar='NAME',
help=('Name of the UDP Classification.'))
parser.add_argument(
'--description', default='',
help=('Description of the UDP Classification.'))
parser.add_argument(
'udp_classification',
metavar="UDP_CLASSIFICATION",
help=('ID of the UDP Classification to update.'))
return parser
def take_action(self, parsed_args):
id = parsed_args.udp_classification
client = self.app.client_manager.neutronclient
attrs = _get_attrs(self.app.client_manager,
parsed_args, is_create=False)
cl = client.update_ext(object_path + '/%s', id, {resource: attrs})
columns = _get_columns(cl[resource])
data = utils.get_dict_properties(cl[resource], columns)
return columns, data
def _get_attrs(client_manager, parsed_args, is_create=False):
attrs = {}
definition = {}
if parsed_args.name is not None:
attrs['name'] = str(parsed_args.name)
if parsed_args.description is not None:
attrs['description'] = str(parsed_args.description)
if is_create:
attrs['c_type'] = 'udp'
if parsed_args.negated is not None:
attrs['negated'] = str(parsed_args.negated)
if parsed_args.shared is not None:
attrs['shared'] = str(parsed_args.shared)
if parsed_args.src_port_min is not None:
definition['src_port_min'] = parsed_args.src_port_min
if parsed_args.src_port_max is not None:
definition['src_port_max'] = parsed_args.src_port_max
if parsed_args.dst_port_min is not None:
definition['dst_port_min'] = parsed_args.dst_port_min
if parsed_args.dst_port_max is not None:
definition['dst_port_max'] = parsed_args.dst_port_max
if parsed_args.length_min is not None:
definition['length_min'] = parsed_args.length_min
if parsed_args.length_max is not None:
definition['length_max'] = parsed_args.length_max
attrs['definition'] = definition
return attrs
def _get_columns(resource):
columns = list(resource.keys())
if 'tenant_id' in columns:
columns.remove('tenant_id')
if 'project_id' in columns:
columns.append('project_id')
return tuple(sorted(columns))

View File

@@ -33,17 +33,21 @@ class TrafficClassificationGroupPlugin(common_db_mixin.CommonDbMixin):
def create_classification_group(self, context, classification_group):
details = classification_group['classification_group']
c_flag = cg_flag = False
if details['classifications']:
if 'classifications' in details:
c_flag = True
validators.check_valid_classifications(context,
details['classifications'])
if details['classification_groups']:
if 'classification_groups' in details:
cg_flag = True
validators.check_valid_classification_groups(
context, details['classification_groups'])
details['id'] = uuidutils.generate_uuid()
mappings = {'c_ids': details['classifications'],
'cg_ids': details['classification_groups']}
mappings = {'c_ids': details['classifications'] if c_flag else [],
'cg_ids': details['classification_groups']
if cg_flag else []}
db_dict = details
cg = classifications.ClassificationGroup(context, **details)
@@ -52,21 +56,26 @@ class TrafficClassificationGroupPlugin(common_db_mixin.CommonDbMixin):
db_dict['id'] = cg.id
with db_api.context_manager.writer.using(context):
for cl in mappings['c_ids']:
cg_c_mapping = classifications.CGToClassificationMapping(
context,
container_cg_id=cg.id,
stored_classification_id=cl)
cg_c_mapping.create()
for cg_id in mappings['cg_ids']:
cg_cg_mapping = classifications.CGToClassificationGroupMapping(
context,
container_cg_id=cg.id,
stored_cg_id=cg_id
)
cg_cg_mapping.create()
db_dict['classifications'] = details['classifications']
db_dict['classification_group'] = details['classification_groups']
if c_flag:
for cl in mappings['c_ids']:
cg_c_mapping = classifications.CGToClassificationMapping(
context,
container_cg_id=cg.id,
stored_classification_id=cl)
cg_c_mapping.create()
if cg_flag:
for cg_id in mappings['cg_ids']:
cg_cg_mapping =\
classifications.CGToClassificationGroupMapping(
context,
container_cg_id=cg.id,
stored_cg_id=cg_id
)
cg_cg_mapping.create()
db_dict['classifications'] = details['classifications']\
if c_flag else []
db_dict['classification_group'] = details['classification_groups']\
if cg_flag else []
return db_dict

View File

@@ -87,7 +87,7 @@ class Classification(api_ext.ExtensionDescriptor):
allow_bulk=True)
for resource in resources:
resource.path_prefix = '/classifications'
resource.path_prefix = 'ccf/classifications'
return resources
@@ -102,7 +102,7 @@ class Classification(api_ext.ExtensionDescriptor):
@six.add_metaclass(ABCMeta)
class NeutronClassificationPluginBase(service_base.ServicePluginBase):
path_prefix = '/classifications'
path_prefix = 'ccf/classifications'
def get_plugin_name(self):
return EXT_NAME

View File

@@ -140,6 +140,8 @@ class ClassificationPlugin(classification.NeutronClassificationPluginBase,
return cl_dict
def merge_headers(self, classifications):
if not classifications:
return {}
c_type = classifications[0]['c_type']
ret_list = {CLASSIFICATION_MAP[c_type]: []}

View File

@@ -0,0 +1,65 @@
# Can't be run at the moment until migration with openstack-client
# Copyright (c) 2018 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.
import mock
from neutron.tests.unit.extensions import base as test_extensions_base
from neutronclient.v2_0 import client
OPENSTACK_CLI_ID = "/ccf/classifications"
ASSOCS_PATH = "/ccf/classifications"
NET_ASSOC_ID = "uuid_client_foo"
class OpenstackClientTestCase(test_extensions_base.ExtensionTestCase):
def setUp(self):
super(OpenstackClientTestCase, self).setUp()
self.client = client.Client()
self.client.list_ext = mock.Mock()
self.client.create_ext = mock.Mock()
self.client.show_ext = mock.Mock()
self.client.update_ext = mock.Mock()
self.client.delete_ext = mock.Mock()
print ("self.client keys: ", dir(self.client))
def test_client_url_list(self):
self.client.ListIPV4Classification(OPENSTACK_CLI_ID)
self.client.list_ext.assert_called_once_with(mock.ANY, ASSOCS_PATH,
mock.ANY)
def test_client_url_create(self):
self.client.CreateIPV4Classification(OPENSTACK_CLI_ID, {})
self.client.create_ext.assert_called_once_with(ASSOCS_PATH, mock.ANY)
def test_client_url_show(self):
self.client.ShowIPV4Classification(NET_ASSOC_ID, OPENSTACK_CLI_ID)
self.client.show_ext.assert_called_once_with(ASSOCS_PATH,
NET_ASSOC_ID)
def test_client_url_update(self):
self.client.UpdateIPV4Classification(NET_ASSOC_ID,
OPENSTACK_CLI_ID, {})
self.client.update_ext.assert_called_once_with(ASSOCS_PATH,
NET_ASSOC_ID,
mock.ANY)
def test_client_url_delete(self):
self.client.DeleteIPV4Classification(NET_ASSOC_ID, OPENSTACK_CLI_ID)
self.client.delete_ext.assert_called_once_with(ASSOCS_PATH,
NET_ASSOC_ID)

View File

@@ -27,7 +27,38 @@ packages =
[entry_points]
neutron.service_plugins =
neutron_classifier = neutron_classifier.services.classification.plugin:ClassificationPlugin
openstack.neutronclient.v2 =
network classification ethernet create = neutron_classifier.cli.openstack_cli.eth_classification:CreateEthernetClassification
network classification ethernet delete = neutron_classifier.cli.openstack_cli.eth_classification:DeleteEthernetClassification
network classification ethernet list = neutron_classifier.cli.openstack_cli.eth_classification:ListEthernetClassification
network classification ethernet show = neutron_classifier.cli.openstack_cli.eth_classification:ShowEthernetClassification
network classification ethernet update = neutron_classifier.cli.openstack_cli.eth_classification:UpdateEthernetClassification
network classification ipv4 create = neutron_classifier.cli.openstack_cli.ipv4_classification:CreateIPV4Classification
network classification ipv4 delete = neutron_classifier.cli.openstack_cli.ipv4_classification:DeleteIPV4Classification
network classification ipv4 list = neutron_classifier.cli.openstack_cli.ipv4_classification:ListIPV4Classification
network classification ipv4 show = neutron_classifier.cli.openstack_cli.ipv4_classification:ShowIPV4Classification
network classification ipv4 update = neutron_classifier.cli.openstack_cli.ipv4_classification:UpdateIPV4Classification
network classification ipv6 create = neutron_classifier.cli.openstack_cli.ipv6_classification:CreateIPV6Classification
network classification ipv6 delete = neutron_classifier.cli.openstack_cli.ipv6_classification:DeleteIPV6Classification
network classification ipv6 list = neutron_classifier.cli.openstack_cli.ipv6_classification:ListIPV6Classification
network classification ipv6 show = neutron_classifier.cli.openstack_cli.ipv6_classification:ShowIPV6Classification
network classification ipv6 update = neutron_classifier.cli.openstack_cli.ipv6_classification:UpdateIPV6Classification
network classification tcp create = neutron_classifier.cli.openstack_cli.tcp_classification:CreateTCPClassification
network classification tcp delete = neutron_classifier.cli.openstack_cli.tcp_classification:DeleteTCPClassification
network classification tcp list = neutron_classifier.cli.openstack_cli.tcp_classification:ListTCPClassification
network classification tcp show = neutron_classifier.cli.openstack_cli.tcp_classification:ShowTCPClassification
network classification tcp update = neutron_classifier.cli.openstack_cli.tcp_classification:UpdateTCPClassification
network classification udp create = neutron_classifier.cli.openstack_cli.udp_classification:CreateUDPClassification
network classification udp delete = neutron_classifier.cli.openstack_cli.udp_classification:DeleteUDPClassification
network classification udp list = neutron_classifier.cli.openstack_cli.udp_classification:ListUDPClassification
network classification udp show = neutron_classifier.cli.openstack_cli.udp_classification:ShowUDPClassification
network classification udp update = neutron_classifier.cli.openstack_cli.udp_classification:UpdateUDPClassification
network classification type list = neutron_classifier.cli.openstack_cli.classification_type:ListClassificationType
network classification group create = neutron_classifier.cli.openstack_cli.classification_group:CreateClassificationGroup
network classification group delete = neutron_classifier.cli.openstack_cli.classification_group:DeleteClassificationGroup
network classification group list = neutron_classifier.cli.openstack_cli.classification_group:ListClassificationGroup
network classification group show = neutron_classifier.cli.openstack_cli.classification_group:ShowClassificationGroup
network classification group update = neutron_classifier.cli.openstack_cli.classification_group:UpdateClassificationGroup
neutron.db.alembic_migrations =
neutron-classifier = neutron_classifier.db.migration:alembic_migrations