diff --git a/doc/source/cli/osc/v2/subnet-onboard.rst b/doc/source/cli/osc/v2/subnet-onboard.rst new file mode 100644 index 000000000..006970372 --- /dev/null +++ b/doc/source/cli/osc/v2/subnet-onboard.rst @@ -0,0 +1,17 @@ +======================= +network onboard subnets +======================= + +**network onboard subnets** enables a subnet to be adopted or +"onboarded" into an existing subnet pool. The CIDR of the subnet +is checked for uniqueness across any applicable address scopes +and all subnets allocated from the target subnet pool. Once +onboarded, the subnet CIDR is added to the prefix list of the +subnet pool and the subnet appears as though it has been allocated +from the subnet pool. The subnet also begins participating in the +applicable address scope if the subnet pool belongs to one. + +Network v2 + +.. autoprogram-cliff:: openstack.neutronclient.v2 + :command: network onboard subnets diff --git a/neutronclient/osc/v2/subnet_onboard/__init__.py b/neutronclient/osc/v2/subnet_onboard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutronclient/osc/v2/subnet_onboard/subnet_onboard.py b/neutronclient/osc/v2/subnet_onboard/subnet_onboard.py new file mode 100644 index 000000000..10c6ab4c2 --- /dev/null +++ b/neutronclient/osc/v2/subnet_onboard/subnet_onboard.py @@ -0,0 +1,59 @@ +# Copyright (c) 2019 SUSE Linux Products GmbH +# 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. +# + +"""Subnet onboard action implementation""" +import logging + +from osc_lib.command import command +from osc_lib import exceptions + +from neutronclient._i18n import _ + +LOG = logging.getLogger(__name__) + + +class NetworkOnboardSubnets(command.Command): + """Onboard network subnets into a subnet pool""" + + def get_parser(self, prog_name): + parser = super(NetworkOnboardSubnets, self).get_parser(prog_name) + parser.add_argument( + 'network', + metavar="", + help=_("Onboard all subnets associated with this network") + ) + parser.add_argument( + 'subnetpool', + metavar="", + help=_("Target subnet pool for onboarding subnets") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.neutronclient + subnetpool_id = _get_id(client, parsed_args.subnetpool, 'subnetpool') + network_id = _get_id(client, parsed_args.network, 'network') + body = {'network_id': network_id} + try: + client.onboard_network_subnets(subnetpool_id, body) + except Exception as e: + msg = (_("Failed to onboard subnets for network '%(n)s': %(e)s") + % {'n': parsed_args.network, 'e': e}) + raise exceptions.CommandError(msg) + + +def _get_id(client, id_or_name, resource): + return client.find_resource(resource, str(id_or_name))['id'] diff --git a/neutronclient/tests/unit/osc/v2/subnet_onboard/__init__.py b/neutronclient/tests/unit/osc/v2/subnet_onboard/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/neutronclient/tests/unit/osc/v2/subnet_onboard/test_network_onboard_subnets.py b/neutronclient/tests/unit/osc/v2/subnet_onboard/test_network_onboard_subnets.py new file mode 100644 index 000000000..efd3d1d11 --- /dev/null +++ b/neutronclient/tests/unit/osc/v2/subnet_onboard/test_network_onboard_subnets.py @@ -0,0 +1,54 @@ +# Copyright (c) 2019 SUSE Linux Products GmbH +# 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 mock + +from neutronclient.osc.v2.subnet_onboard import subnet_onboard +from neutronclient.tests.unit.osc.v2 import fakes as test_fakes + + +def _get_id(client, id_or_name, resource): + return id_or_name + + +class TestNetworkOnboardSubnets(test_fakes.TestNeutronClientOSCV2): + + def setUp(self): + super(TestNetworkOnboardSubnets, self).setUp() + mock.patch( + 'neutronclient.osc.v2.subnet_onboard.subnet_onboard._get_id', + new=_get_id).start() + + self.network_id = 'my_network_id' + self.subnetpool_id = 'my_subnetpool_id' + + # Get the command object to test + self.cmd = subnet_onboard.NetworkOnboardSubnets(self.app, + self.namespace) + + def test_options(self): + arglist = [ + self.network_id, + self.subnetpool_id + ] + verifylist = [ + ('network', self.network_id), + ('subnetpool', self.subnetpool_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.cmd.take_action(parsed_args) + self.neutronclient.onboard_network_subnets.assert_called_once_with( + self.subnetpool_id, {'network_id': self.network_id}) diff --git a/neutronclient/v2_0/client.py b/neutronclient/v2_0/client.py index 560b531d0..ed8dbd49d 100644 --- a/neutronclient/v2_0/client.py +++ b/neutronclient/v2_0/client.py @@ -494,6 +494,7 @@ class Client(ClientBase): port_path = "/ports/%s" subnets_path = "/subnets" subnet_path = "/subnets/%s" + onboard_network_subnets_path = "/subnetpools/%s/onboard_network_subnets" subnetpools_path = "/subnetpools" subnetpool_path = "/subnetpools/%s" address_scopes_path = "/address-scopes" @@ -2370,6 +2371,11 @@ class Client(ClientBase): return self.list('loggable_resources', self.network_loggables_path, retrieve_all, **_params) + def onboard_network_subnets(self, subnetpool, body=None): + """Onboard the specified network's subnets into a subnet pool.""" + return self.put(self.onboard_network_subnets_path % (subnetpool), + body=body) + def __init__(self, **kwargs): """Initialize a new client for the Neutron v2.0 API.""" super(Client, self).__init__(**kwargs) diff --git a/releasenotes/notes/add-subnet-onboard-e60772bc4984f698.yaml b/releasenotes/notes/add-subnet-onboard-e60772bc4984f698.yaml new file mode 100644 index 000000000..358fdf006 --- /dev/null +++ b/releasenotes/notes/add-subnet-onboard-e60772bc4984f698.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add ``network onboard subnets`` OSC command to enable subnet onboard support from the CLI + [Blueprint `subnet-onboard `_] diff --git a/setup.cfg b/setup.cfg index b5a837b25..0262adf9e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -171,6 +171,8 @@ openstack.neutronclient.v2 = vpn_ipsec_site_connection_set = neutronclient.osc.v2.vpnaas.ipsec_site_connection:SetIPsecSiteConnection vpn_ipsec_site_connection_show = neutronclient.osc.v2.vpnaas.ipsec_site_connection:ShowIPsecSiteConnection + network_onboard_subnets = neutronclient.osc.v2.subnet_onboard.subnet_onboard:NetworkOnboardSubnets + neutron.cli.v2 = bash-completion = neutronclient.shell:BashCompletionCommand