From cc3985c2678afc28ca10b087eb9d2a016b62c67a Mon Sep 17 00:00:00 2001 From: tspyderboy Date: Mon, 15 Jul 2024 23:18:25 +0530 Subject: [PATCH] Add workflow to create share network subnets Partially-implements: bp share-network-subnets Change-Id: Ic3a5e63e34ca7c8eb4ce41d93e9558e04a08e6a7 --- manila_ui/api/manila.py | 10 +++ .../share_network_subnets/__init__.py | 0 .../share_network_subnets/tables.py | 25 ++++++ .../share_network_subnets/views.py | 26 ++++++ .../share_network_subnets/workflows.py | 69 ++++++++++++++++ .../project/share_networks/tables.py | 4 +- .../dashboards/project/share_networks/urls.py | 6 ++ manila_ui/tests/api/test_manila.py | 20 +++++ .../share_network_subnets/__init__.py | 0 .../share_network_subnets/tests.py | 80 +++++++++++++++++++ ...subnet-create-option-a8f8a8e6305cc94d.yaml | 4 + 11 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 manila_ui/dashboards/project/share_networks/share_network_subnets/__init__.py create mode 100644 manila_ui/dashboards/project/share_networks/share_network_subnets/tables.py create mode 100644 manila_ui/dashboards/project/share_networks/share_network_subnets/views.py create mode 100644 manila_ui/dashboards/project/share_networks/share_network_subnets/workflows.py create mode 100644 manila_ui/tests/dashboards/project/share_networks/share_network_subnets/__init__.py create mode 100644 manila_ui/tests/dashboards/project/share_networks/share_network_subnets/tests.py create mode 100644 releasenotes/notes/add-share-network-subnet-create-option-a8f8a8e6305cc94d.yaml diff --git a/manila_ui/api/manila.py b/manila_ui/api/manila.py index 4cb58079..cf25fe2e 100644 --- a/manila_ui/api/manila.py +++ b/manila_ui/api/manila.py @@ -322,6 +322,16 @@ def share_network_delete(request, share_network_id): return manilaclient(request).share_networks.delete(share_network_id) +def share_network_subnet_create(request, share_network_id=None, + neutron_net_id=None, neutron_subnet_id=None, + availability_zone=None): + return manilaclient(request).share_network_subnets.create( + share_network_id=share_network_id, + neutron_net_id=neutron_net_id, + neutron_subnet_id=neutron_subnet_id, + availability_zone=availability_zone) + + def security_service_list(request, search_opts=None): return manilaclient(request).security_services.list( detailed=True, diff --git a/manila_ui/dashboards/project/share_networks/share_network_subnets/__init__.py b/manila_ui/dashboards/project/share_networks/share_network_subnets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manila_ui/dashboards/project/share_networks/share_network_subnets/tables.py b/manila_ui/dashboards/project/share_networks/share_network_subnets/tables.py new file mode 100644 index 00000000..eca6123b --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/share_network_subnets/tables.py @@ -0,0 +1,25 @@ +# 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 django.utils.translation import gettext_lazy as _ +from horizon import tables + + +class CreateShareNetworkSubnet(tables.LinkAction): + name = "subnet" + verbose_name = _("Create Subnet") + url = "horizon:project:share_networks:share_network_subnet_create" + classes = ("ajax-modal", "btn-create") + policy_rules = (("share", "share_network_subnet:create"),) + + def allowed(self, request, obj_id): + return True diff --git a/manila_ui/dashboards/project/share_networks/share_network_subnets/views.py b/manila_ui/dashboards/project/share_networks/share_network_subnets/views.py new file mode 100644 index 00000000..34ba9a4d --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/share_network_subnets/views.py @@ -0,0 +1,26 @@ +# 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 django.utils.translation import gettext_lazy as _ +from horizon import workflows + +from manila_ui.dashboards.project.share_networks.share_network_subnets \ + import workflows as subnet_workflows + + +class CreateSubnet(workflows.WorkflowView): + workflow_class = subnet_workflows.CreateShareNetworkSubnetsWorkflow + success_url = 'horizon:project:share_networks:index' + page_title = _('Create Share Network Subnet') + + def get_initial(self): + return {'share_network_id': self.kwargs["share_network_id"]} diff --git a/manila_ui/dashboards/project/share_networks/share_network_subnets/workflows.py b/manila_ui/dashboards/project/share_networks/share_network_subnets/workflows.py new file mode 100644 index 00000000..11ceb479 --- /dev/null +++ b/manila_ui/dashboards/project/share_networks/share_network_subnets/workflows.py @@ -0,0 +1,69 @@ +# 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 django.utils.translation import gettext_lazy as _ +from horizon import exceptions +from horizon import messages +from horizon import workflows + +from manila_ui.api import manila +from manila_ui.dashboards.project.share_networks \ + import workflows as sn_workflows +from manila_ui.dashboards import utils + + +class AddShareNetworkSubnetStep(workflows.Step): + action_class = sn_workflows.AddShareNetworkSubnetAction + depends_on = ("share_network_id",) + contributes = ("neutron_net_id", "neutron_subnet_id", "availability_zone") + + +class CreateShareNetworkSubnetsWorkflow(workflows.Workflow): + slug = "create_share_network_subnet" + name = _("Create Share Network Subnet") + finalize_button_name = _("Create Share Network Subnet") + success_message = _('') + failure_message = _('') + success_url = 'horizon:project:share_networks:index' + default_steps = (AddShareNetworkSubnetStep,) + + def handle(self, request, context): + try: + data = request.POST + share_network_id = self.context['share_network_id'] + share_network_name = manila.share_network_get( + request, share_network_id).name + send_data = {'share_network_id': share_network_id} + + neutron_net_id = context.get('neutron_net_id') + if neutron_net_id: + send_data['neutron_net_id'] = utils.transform_dashed_name( + neutron_net_id.strip()) + subnet_key = ( + 'subnet-choices-%s' % neutron_net_id.strip() + ) + if data.get(subnet_key) is not None: + send_data['neutron_subnet_id'] = data.get(subnet_key) + if context['availability_zone']: + send_data['availability_zone'] = context['availability_zone'] + share_network = manila.share_network_subnet_create(request, + **send_data) + + messages.success( + request, + _('Successfully created share network subnet for: %s') % + share_network_name) + return share_network + except Exception: + exceptions.handle(request, + _('Unable to create share network subnet.')) + return False diff --git a/manila_ui/dashboards/project/share_networks/tables.py b/manila_ui/dashboards/project/share_networks/tables.py index 38d76ba8..dc42e806 100644 --- a/manila_ui/dashboards/project/share_networks/tables.py +++ b/manila_ui/dashboards/project/share_networks/tables.py @@ -20,7 +20,8 @@ from openstack_dashboard.api import base from openstack_dashboard.api import neutron from manila_ui.api import manila - +from manila_ui.dashboards.project.share_networks.share_network_subnets \ + import tables as subnet_tables DELETABLE_STATES = ("INACTIVE", "ERROR") EDITABLE_STATES = ("INACTIVE", ) @@ -130,4 +131,5 @@ class ShareNetworksTable(tables.DataTable): row_actions = ( EditShareNetwork, Delete, + subnet_tables.CreateShareNetworkSubnet, ) diff --git a/manila_ui/dashboards/project/share_networks/urls.py b/manila_ui/dashboards/project/share_networks/urls.py index b831438d..6c44c4ae 100644 --- a/manila_ui/dashboards/project/share_networks/urls.py +++ b/manila_ui/dashboards/project/share_networks/urls.py @@ -14,6 +14,8 @@ from django.urls import re_path +from manila_ui.dashboards.project.share_networks.share_network_subnets \ + import views as subnet_views from manila_ui.dashboards.project.share_networks import views @@ -34,4 +36,8 @@ urlpatterns = [ r'^(?P[^/]+)$', views.Detail.as_view(), name='share_network_detail'), + re_path( + r'^(?P[^/]+)/subnets/create$', + subnet_views.CreateSubnet.as_view(), + name='share_network_subnet_create'), ] diff --git a/manila_ui/tests/api/test_manila.py b/manila_ui/tests/api/test_manila.py index c4c1b80b..f0eaf8ed 100644 --- a/manila_ui/tests/api/test_manila.py +++ b/manila_ui/tests/api/test_manila.py @@ -449,6 +449,26 @@ class ManilaApiTests(base.APITestCase): self.manilaclient.share_networks.delete.assert_called_once_with( share_network_id) + @ddt.data( + {"share_network_id": "some_network_id"}, + {"share_network_id": "some_network_id", + "neutron_net_id": "some_neutron_net_id", + "neutron_subnet_id": "some_neutron_subnet_id", + "availability_zone": "some_availability_zone"}, + ) + def test_share_network_subnet_create(self, kwargs): + expected_kwargs = { + "share_network_id": None, + "neutron_net_id": None, + "neutron_subnet_id": None, + "availability_zone": None + } + + expected_kwargs.update(**kwargs) + api.share_network_subnet_create(self.request, **kwargs) + self.manilaclient.share_network_subnets.create.assert_called_once_with( + **expected_kwargs) + # Share server tests @ddt.data( diff --git a/manila_ui/tests/dashboards/project/share_networks/share_network_subnets/__init__.py b/manila_ui/tests/dashboards/project/share_networks/share_network_subnets/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/manila_ui/tests/dashboards/project/share_networks/share_network_subnets/tests.py b/manila_ui/tests/dashboards/project/share_networks/share_network_subnets/tests.py new file mode 100644 index 00000000..b66ea19d --- /dev/null +++ b/manila_ui/tests/dashboards/project/share_networks/share_network_subnets/tests.py @@ -0,0 +1,80 @@ +# 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 openstack_dashboard import api +from oslo_utils import timeutils +from unittest import mock + +from manila_ui.api import manila as api_manila +from manila_ui.dashboards import utils +from manila_ui.tests.dashboards.project import test_data +from manila_ui.tests import helpers as test + + +class ShareNetworkSubnetsViewTests(test.TestCase): + class FakeAZ(object): + def __init__(self, name, id): + self.name = name + self.id = id + self.created_at = timeutils.utcnow() + + def test_create_share_network_subnets(self): + share_net = test_data.active_share_network + network_id = share_net.id + url = '/project/share_networks/' + network_id + '/subnets/create' + neutron_net_id = self.networks.first().id + sanitized_net_id = utils.transform_dashed_name(neutron_net_id) + + formData = { + 'method': 'CreateForm', + 'neutron_net_id': utils.transform_dashed_name(neutron_net_id), + 'availability_zone': 'fake_az', + f'subnet-choices-{sanitized_net_id}': + self.networks.first().subnets[0].id, + } + + self.mock_object( + api.neutron, "subnet_list", + mock.Mock(return_value=self.subnets.list())) + self.mock_object( + api.neutron, "network_list", + mock.Mock(return_value=self.networks.list())) + self.mock_object( + api_manila, "share_network_get", + mock.Mock(return_value=mock.Mock(name='test_network')) + ) + self.mock_object( + api_manila, "share_network_subnet_create", + mock.Mock(return_value=share_net)) + self.mock_object( + api_manila, "availability_zone_list", + mock.Mock(return_value=[self.FakeAZ('fake_az', 'fake_az')]) + ) + + # Get response from create subnet url using formData values + res = self.client.post(url, formData) + + self.assertNoFormErrors(res) + self.assertMessageCount(error=0, warning=0) + + api_manila.availability_zone_list.assert_called_once_with(mock.ANY) + api.neutron.network_list.assert_called_once_with(mock.ANY) + api.neutron.subnet_list.assert_has_calls([ + mock.call(mock.ANY, network_id=network.id) + for network in self.networks.list() + ], any_order=True) + api_manila.share_network_subnet_create.assert_called_once_with( + mock.ANY, + share_network_id=network_id, + neutron_net_id=neutron_net_id, + neutron_subnet_id=self.networks.first().subnets[0].id, + availability_zone='fake_az') diff --git a/releasenotes/notes/add-share-network-subnet-create-option-a8f8a8e6305cc94d.yaml b/releasenotes/notes/add-share-network-subnet-create-option-a8f8a8e6305cc94d.yaml new file mode 100644 index 00000000..5052825e --- /dev/null +++ b/releasenotes/notes/add-share-network-subnet-create-option-a8f8a8e6305cc94d.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Add share network subnet create option under share network actions.