{% trans "Create a new network for any project as you need."%}
-
{% trans "Provider specified network can be created. You can specify a physical network type (like Flat, VLAN, GRE, and VXLAN) and its segmentation_id or physical network name for a new virtual network."%}
-
{% trans "In addition, you can create an external network or a shared network by checking the corresponding checkbox."%}
-
-{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/networks/templates/networks/create.html b/openstack_dashboard/dashboards/admin/networks/templates/networks/create.html
deleted file mode 100644
index 79d02fb63d..0000000000
--- a/openstack_dashboard/dashboards/admin/networks/templates/networks/create.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{% extends 'base.html' %}
-{% load i18n %}
-{% block title %}{% trans "Create Network" %}{% endblock %}
-
-{% block main %}
- {% include "admin/networks/_create.html" %}
-{% endblock %}
diff --git a/openstack_dashboard/dashboards/admin/networks/tests.py b/openstack_dashboard/dashboards/admin/networks/tests.py
index eb220f696d..7f2297919e 100644
--- a/openstack_dashboard/dashboards/admin/networks/tests.py
+++ b/openstack_dashboard/dashboards/admin/networks/tests.py
@@ -21,6 +21,7 @@ from django.utils.http import urlunquote
from mox3.mox import IsA # noqa
from openstack_dashboard import api
+from openstack_dashboard.dashboards.project.networks import tests
from openstack_dashboard.test import helpers as test
INDEX_TEMPLATE = 'horizon/common/_data_table_view.html'
@@ -381,7 +382,7 @@ class NetworkTests(test.BaseAdminViewTests):
url = reverse('horizon:admin:networks:create')
res = self.client.get(url)
- self.assertTemplateUsed(res, 'admin/networks/create.html')
+ self.assertTemplateUsed(res, 'horizon/common/_workflow_base.html')
@test.update_settings(
OPENSTACK_NEUTRON_NETWORK={'profile_support': 'cisco'})
@@ -390,7 +391,8 @@ class NetworkTests(test.BaseAdminViewTests):
@test.create_stubs({api.neutron: ('network_create',
'profile_list',
- 'is_extension_supported',),
+ 'is_extension_supported',
+ 'subnetpool_list'),
api.keystone: ('tenant_list',)})
def test_network_create_post(self,
test_with_profile=False):
@@ -405,7 +407,8 @@ class NetworkTests(test.BaseAdminViewTests):
'admin_state_up': network.admin_state_up,
'router:external': True,
'shared': True,
- 'provider:network_type': 'local'}
+ 'provider:network_type': 'local',
+ 'with_subnet': False}
if test_with_profile:
net_profiles = self.net_profiles.list()
net_profile_id = self.net_profiles.first().id
@@ -414,8 +417,14 @@ class NetworkTests(test.BaseAdminViewTests):
params['net_profile_id'] = net_profile_id
api.neutron.is_extension_supported(IsA(http.HttpRequest), 'provider').\
MultipleTimes().AndReturn(True)
+ api.neutron.is_extension_supported(IsA(http.HttpRequest),
+ 'subnet_allocation').\
+ MultipleTimes().AndReturn(True)
+ api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
+ AndReturn(self.subnetpools.list())
api.neutron.network_create(IsA(http.HttpRequest), **params)\
.AndReturn(network)
+
self.mox.ReplayAll()
form_data = {'tenant_id': tenant_id,
@@ -432,6 +441,62 @@ class NetworkTests(test.BaseAdminViewTests):
self.assertNoFormErrors(res)
self.assertRedirectsNoFollow(res, INDEX_URL)
+ @test.create_stubs({api.neutron: ('network_create',
+ 'subnet_create',
+ 'profile_list',
+ 'is_extension_supported',
+ 'subnetpool_list'),
+ api.keystone: ('tenant_list',)})
+ def test_network_create_post_with_subnet(self,
+ test_with_profile=False):
+ tenants = self.tenants.list()
+ tenant_id = self.tenants.first().id
+ network = self.networks.first()
+ subnet = self.subnets.first()
+ params = {'name': network.name,
+ 'tenant_id': tenant_id,
+ 'admin_state_up': network.admin_state_up,
+ 'router:external': True,
+ 'shared': True,
+ 'provider:network_type': 'local',
+ 'with_subnet': True}
+
+ api.keystone.tenant_list(IsA(http.HttpRequest))\
+ .AndReturn([tenants, False])
+
+ if test_with_profile:
+ net_profiles = self.net_profiles.list()
+ net_profile_id = self.net_profiles.first().id
+ api.neutron.profile_list(IsA(http.HttpRequest),
+ 'network').AndReturn(net_profiles)
+ params['net_profile_id'] = net_profile_id
+ api.neutron.is_extension_supported(IsA(http.HttpRequest), 'provider').\
+ MultipleTimes().AndReturn(True)
+ api.neutron.is_extension_supported(IsA(http.HttpRequest),
+ 'subnet_allocation').\
+ MultipleTimes().AndReturn(True)
+ api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
+ AndReturn(self.subnetpools.list())
+ api.neutron.network_create(IsA(http.HttpRequest), **params)\
+ .AndReturn(network)
+ self.mox.ReplayAll()
+
+ form_data = {'tenant_id': tenant_id,
+ 'name': network.name,
+ 'admin_state': network.admin_state_up,
+ 'external': True,
+ 'shared': True,
+ 'network_type': 'local',
+ 'with_subnet': True}
+ if test_with_profile:
+ form_data['net_profile_id'] = net_profile_id
+ form_data.update(tests.form_data_subnet(subnet, allocation_pools=[]))
+ url = reverse('horizon:admin:networks:create')
+ res = self.client.post(url, form_data)
+
+ self.assertNoFormErrors(res)
+ self.assertRedirectsNoFollow(res, INDEX_URL)
+
@test.update_settings(
OPENSTACK_NEUTRON_NETWORK={'profile_support': 'cisco'})
def test_network_create_post_with_profile(self):
@@ -439,7 +504,8 @@ class NetworkTests(test.BaseAdminViewTests):
@test.create_stubs({api.neutron: ('network_create',
'profile_list',
- 'is_extension_supported',),
+ 'is_extension_supported',
+ 'subnetpool_list'),
api.keystone: ('tenant_list',)})
def test_network_create_post_network_exception(self,
test_with_profile=False):
@@ -454,7 +520,8 @@ class NetworkTests(test.BaseAdminViewTests):
'admin_state_up': network.admin_state_up,
'router:external': True,
'shared': False,
- 'provider:network_type': 'local'}
+ 'provider:network_type': 'local',
+ 'with_subnet': False}
if test_with_profile:
net_profiles = self.net_profiles.list()
net_profile_id = self.net_profiles.first().id
@@ -463,6 +530,11 @@ class NetworkTests(test.BaseAdminViewTests):
params['net_profile_id'] = net_profile_id
api.neutron.is_extension_supported(IsA(http.HttpRequest), 'provider').\
MultipleTimes().AndReturn(True)
+ api.neutron.is_extension_supported(IsA(http.HttpRequest),
+ 'subnet_allocation').\
+ MultipleTimes().AndReturn(True)
+ api.neutron.subnetpool_list(IsA(http.HttpRequest)).\
+ AndReturn(self.subnetpools.list())
api.neutron.network_create(IsA(http.HttpRequest),
**params).AndRaise(self.exceptions.neutron)
self.mox.ReplayAll()
@@ -593,7 +665,7 @@ class NetworkTests(test.BaseAdminViewTests):
url = reverse('horizon:admin:networks:create')
res = self.client.get(url)
- self.assertTemplateUsed(res, 'admin/networks/create.html')
+ self.assertTemplateUsed(res, 'horizon/common/_workflow_base.html')
self.assertContains(
res,
'',
@@ -615,7 +687,7 @@ class NetworkTests(test.BaseAdminViewTests):
url = reverse('horizon:admin:networks:create')
res = self.client.get(url)
- self.assertTemplateUsed(res, 'admin/networks/create.html')
+ self.assertTemplateUsed(res, 'horizon/common/_workflow_base.html')
network_type = res.context['form'].fields['network_type']
self.assertListEqual(list(network_type.choices), [('local', 'Local'),
('flat', 'Flat'),
diff --git a/openstack_dashboard/dashboards/admin/networks/views.py b/openstack_dashboard/dashboards/admin/networks/views.py
index babbd5dacc..15898d8448 100644
--- a/openstack_dashboard/dashboards/admin/networks/views.py
+++ b/openstack_dashboard/dashboards/admin/networks/views.py
@@ -19,7 +19,6 @@ from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
-from horizon import forms
from horizon import tables
from horizon import tabs
from horizon.utils import memoized
@@ -39,6 +38,9 @@ from openstack_dashboard.dashboards.admin.networks.subnets \
import tables as subnets_tables
from openstack_dashboard.dashboards.admin.networks \
import tables as networks_tables
+from openstack_dashboard.dashboards.admin.networks import workflows
+from openstack_dashboard.dashboards.project.networks import views \
+ as project_view
class IndexView(tables.DataTableView):
@@ -122,11 +124,8 @@ class IndexView(tables.DataTableView):
return filters
-class CreateView(forms.ModalFormView):
- form_class = project_forms.CreateNetwork
- template_name = 'admin/networks/create.html'
- success_url = reverse_lazy('horizon:admin:networks:index')
- page_title = _("Create Network")
+class CreateView(project_view.CreateView):
+ workflow_class = workflows.CreateNetwork
class UpdateView(user_views.UpdateView):
diff --git a/openstack_dashboard/dashboards/admin/networks/workflows.py b/openstack_dashboard/dashboards/admin/networks/workflows.py
new file mode 100644
index 0000000000..77a05a3aab
--- /dev/null
+++ b/openstack_dashboard/dashboards/admin/networks/workflows.py
@@ -0,0 +1,87 @@
+# Copyright 2012 NEC 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 django.core.urlresolvers import reverse
+
+from openstack_dashboard.dashboards.admin.networks import forms \
+ as networks_forms
+from openstack_dashboard.dashboards.project.networks \
+ import workflows as network_workflows
+
+
+class CreateNetworkInfoAction(network_workflows.CreateNetworkInfoAction):
+
+ def __init__(self, request, context, *args, **kwargs):
+ self.create_network_form = context.get('create_network_form')
+ self.base_fields = self.create_network_form.base_fields
+
+ super(CreateNetworkInfoAction, self).__init__(
+ request, context, *args, **kwargs)
+ self.fields = self.create_network_form.fields
+
+ def clean(self):
+ self.create_network_form.cleaned_data = super(
+ CreateNetworkInfoAction, self).clean()
+ self.create_network_form._changed_data = self.changed_data
+ self.create_network_form._errors = self.errors
+ return self.create_network_form.clean()
+
+ class Meta(object):
+ name = network_workflows.CreateNetworkInfoAction.name
+ help_text = network_workflows.CreateNetworkInfoAction.help_text
+
+
+class CreateNetworkInfo(network_workflows.CreateNetworkInfo):
+ action_class = CreateNetworkInfoAction
+ contributes = ("net_name", "admin_state", "net_profile_id", "with_subnet")
+
+ def __init__(self, workflow):
+ self.contributes = tuple(workflow.create_network_form.fields.keys())
+ super(CreateNetworkInfo, self).__init__(workflow)
+
+ def prepare_action_context(self, request, context):
+ context = super(CreateNetworkInfo, self).prepare_action_context(
+ request, context)
+ context['create_network_form'] = self.workflow.create_network_form
+ return context
+
+
+class CreateNetwork(network_workflows.CreateNetwork):
+ default_steps = (CreateNetworkInfo,
+ network_workflows.CreateSubnetInfo,
+ network_workflows.CreateSubnetDetail)
+
+ def __init__(self, request=None, context_seed=None, entry_point=None,
+ *args, **kwargs):
+ self.create_network_form = networks_forms.CreateNetwork(
+ request, *args, **kwargs)
+ super(CreateNetwork, self).__init__(
+ request=request,
+ context_seed=context_seed,
+ entry_point=entry_point,
+ *args, **kwargs)
+
+ def get_success_url(self):
+ return reverse("horizon:admin:networks:index")
+
+ def get_failure_url(self):
+ return reverse("horizon:admin:networks:index")
+
+ def _create_network(self, request, data):
+ network = self.create_network_form.handle(request, data)
+ # Replicate logic from parent CreateNetwork._create_network
+ if network:
+ self.context['net_id'] = network.id
+ self.context['net_name'] = network.name
+ return network