Cisco Standalone fabric horizon GUI
Extended Horizon Cisco UI for supporting Network Configuration Profile for Nexus Programmable Fabric Change-Id: I66381ec1a04b098eed27101dc55551776c8a1e3a
This commit is contained in:
parent
e3952d15e6
commit
8c630c4765
|
@ -0,0 +1,92 @@
|
|||
# Copyright 2014 Cisco Systems, Inc.
|
||||
# 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 json
|
||||
import logging
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from networking_cisco.apps.saf.common import config
|
||||
from networking_cisco.apps.saf.common import constants
|
||||
from networking_cisco.apps.saf.common import rpc
|
||||
|
||||
from horizon import exceptions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DFAClient(object):
|
||||
"""Represents fabric enabler command line interface."""
|
||||
|
||||
def __init__(self):
|
||||
self.ctl_host = platform.node()
|
||||
self._cfg = config.CiscoDFAConfig().cfg
|
||||
url = self._cfg.dfa_rpc.transport_url % ({'ip': self.ctl_host})
|
||||
self.clnt = rpc.DfaRpcClient(url, constants.DFA_SERVER_QUEUE,
|
||||
exchange=constants.DFA_EXCHANGE)
|
||||
|
||||
def do_precreate_network(self, network):
|
||||
'''Precreate network on current version of Fabric Enabler'''
|
||||
|
||||
context = {}
|
||||
args = json.dumps(network)
|
||||
msg = self.clnt.make_msg('precreate_network', context, msg=args)
|
||||
try:
|
||||
resp = self.clnt.call(msg)
|
||||
if not resp:
|
||||
raise exceptions.NotAvailable("Project %(id)s not present in "
|
||||
"fabric enabler" %
|
||||
{'id': network.get('tenant_id')})
|
||||
return resp
|
||||
except (rpc.MessagingTimeout, rpc.RPCException, rpc.RemoteError):
|
||||
LOG.error("RPC: Request to precreate network failed.")
|
||||
raise exceptions.NotAvailable("RPC to Fabric Enabler failed")
|
||||
|
||||
def do_delete_precreate_network(self, network):
|
||||
'''Delete precreate network on current version of Fabric Enabler'''
|
||||
|
||||
context = {}
|
||||
args = json.dumps(network)
|
||||
msg = self.clnt.make_msg('delete_precreate_network', context, msg=args)
|
||||
try:
|
||||
resp = self.clnt.call(msg)
|
||||
if not resp:
|
||||
raise exceptions.NotAvailable("Project %(id)s not present in "
|
||||
"fabric enabler" %
|
||||
{'id': network.get('tenant_id')})
|
||||
return resp
|
||||
except (rpc.MessagingTimeout, rpc.RPCException, rpc.RemoteError):
|
||||
LOG.error("RPC: Request to delete precreated network failed.")
|
||||
raise exceptions.NotAvailable("RPC to Fabric Enabler failed")
|
||||
|
||||
def get_config_profiles_detail(self):
|
||||
'''Get all config Profiles details from the Fabric Enabler'''
|
||||
|
||||
context = {}
|
||||
args = json.dumps({})
|
||||
msg = self.clnt.make_msg('get_config_profiles_detail',
|
||||
context, msg=args)
|
||||
try:
|
||||
resp = self.clnt.call(msg)
|
||||
return resp
|
||||
except (rpc.MessagingTimeout, rpc.RPCException, rpc.RemoteError):
|
||||
LOG.error("RPC: Request for detailed Config Profiles failed.")
|
||||
raise exceptions.NotAvailable("RPC to Fabric Enabler failed")
|
||||
|
||||
|
||||
def dfa_client():
|
||||
sys.argv.append('--config-file')
|
||||
sys.argv.append('/etc/saf/enabler_conf.ini')
|
||||
return DFAClient()
|
|
@ -0,0 +1,83 @@
|
|||
# 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 json
|
||||
import mock
|
||||
import platform
|
||||
|
||||
from horizon_cisco_ui.cisco.dfa import dfa_client
|
||||
|
||||
from networking_cisco.apps.saf.common import config
|
||||
from networking_cisco.apps.saf.common import constants
|
||||
|
||||
from openstack_dashboard.test import helpers as test
|
||||
|
||||
|
||||
class DFAClientTestCase(test.BaseAdminViewTests):
|
||||
|
||||
def setUp(self):
|
||||
'''Setup routine '''
|
||||
super(DFAClientTestCase, self).setUp()
|
||||
self.ip = platform.node()
|
||||
self._test_dfa_client_init()
|
||||
|
||||
def _test_dfa_client_init(self):
|
||||
with mock.patch('networking_cisco.apps.saf.common.rpc.DfaRpcClient') as dfa_rpc, \
|
||||
mock.patch.object(config.CiscoDFAConfig, 'cfg') as dfa_cfg:
|
||||
self.DFAClient = dfa_client.DFAClient()
|
||||
self.url = dfa_cfg.dfa_rpc.transport_url % ({'ip': self.ip})
|
||||
dfa_rpc.assert_called_with(self.url,
|
||||
constants.DFA_SERVER_QUEUE,
|
||||
exchange=constants.DFA_EXCHANGE)
|
||||
|
||||
def test_do_precreate_network(self):
|
||||
network = dict(tenant_id=1,
|
||||
nwk_name='net1',
|
||||
subnet='10.0.0.0/24',
|
||||
cfgp='defaultNetworkL2Profile')
|
||||
|
||||
message = json.dumps(network)
|
||||
with mock.patch.object(self.DFAClient.clnt, 'make_msg') as mock_make_msg, \
|
||||
mock.patch.object(self.DFAClient.clnt, 'call') as mock_call:
|
||||
self.DFAClient.do_precreate_network(network)
|
||||
|
||||
rpc_make_obj = mock_make_msg.return_value
|
||||
mock_make_msg.assert_called_with('precreate_network', {}, msg=message)
|
||||
mock_call.assert_called_with(rpc_make_obj)
|
||||
|
||||
def test_do_precreate_network_not_available_exception(self):
|
||||
network = dict(tenant_id=1,
|
||||
nwk_name='net1',
|
||||
subnet='10.0.0.0/24',
|
||||
cfgp='defaultNetworkL2Profile')
|
||||
|
||||
with mock.patch.object(self.DFAClient.clnt, 'call',
|
||||
return_value=False), \
|
||||
self.assertRaises(dfa_client.exceptions.NotAvailable) as cm:
|
||||
self.DFAClient.do_precreate_network(network)
|
||||
|
||||
self.assertEqual('Project 1 not present in fabric enabler',
|
||||
str(cm.exception))
|
||||
|
||||
def test_do_precreate_network_rpc_exception(self):
|
||||
network = dict(tenant_id=1,
|
||||
nwk_name='net1',
|
||||
subnet='10.0.0.0/24',
|
||||
cfgp='defaultNetworkL2Profile')
|
||||
|
||||
with mock.patch.object(self.DFAClient.clnt, 'call',
|
||||
side_effect=dfa_client.rpc.RPCException), \
|
||||
self.assertRaises(dfa_client.exceptions.NotAvailable) as cm:
|
||||
self.DFAClient.do_precreate_network(network)
|
||||
|
||||
self.assertEqual('RPC to Fabric Enabler failed',
|
||||
str(cm.exception))
|
|
@ -0,0 +1,154 @@
|
|||
# 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 ugettext_lazy as _
|
||||
|
||||
import logging
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import workflows
|
||||
from horizon_cisco_ui.cisco.dfa import dfa_client
|
||||
|
||||
from openstack_dashboard import api
|
||||
from openstack_dashboard.dashboards.project.networks import \
|
||||
workflows as upstream_networks_workflows
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DFAConfigProfileAction(workflows.Action):
|
||||
cfg_profile = forms.ChoiceField(label=_("Config Profile"), required=False,
|
||||
help_text=_("Select Config Profile to "
|
||||
"associate with Network."))
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(DFAConfigProfileAction, self).__init__(request, *args, **kwargs)
|
||||
self.fields['cfg_profile'].choices = \
|
||||
self.get_config_profile_choices(request)
|
||||
|
||||
def get_config_profile_choices(self, request):
|
||||
profile_choices = [('', _("Select a config profile"))]
|
||||
for profile in self._get_cfg_profiles(request):
|
||||
profile_choices.append((profile, profile))
|
||||
return profile_choices
|
||||
|
||||
def _get_cfg_profiles(self, request):
|
||||
profiles = []
|
||||
try:
|
||||
cfgplist = dfa_client.dfa_client().get_config_profiles_detail()
|
||||
profiles = [profile for cfgp in cfgplist
|
||||
if (cfgp.get('profileSubType') == 'network:universal')
|
||||
for profile in [cfgp.get('profileName')]]
|
||||
except Exception as exc:
|
||||
exceptions.handle(request, exc.message)
|
||||
return profiles
|
||||
|
||||
class Meta(object):
|
||||
name = _("Programmable Fabric")
|
||||
help_text = _("Select Config Profile from the list "
|
||||
"to associate with your network.")
|
||||
|
||||
|
||||
class DFAConfigProfileInfo(workflows.Step):
|
||||
action_class = DFAConfigProfileAction
|
||||
|
||||
def contribute(self, data, context):
|
||||
for key, value in data.items():
|
||||
context[key] = value
|
||||
return context
|
||||
|
||||
|
||||
class DFACreateNetwork(upstream_networks_workflows.CreateNetwork):
|
||||
default_steps = (upstream_networks_workflows.CreateNetworkInfo,
|
||||
upstream_networks_workflows.CreateSubnetInfo,
|
||||
upstream_networks_workflows.CreateSubnetDetail,
|
||||
DFAConfigProfileInfo)
|
||||
|
||||
@staticmethod
|
||||
def _create_network(self, request, data):
|
||||
try:
|
||||
params = {'name': data['net_name'],
|
||||
'admin_state_up': (data['admin_state'] == 'True'),
|
||||
'shared': data['shared']}
|
||||
if api.neutron.is_port_profiles_supported():
|
||||
params['net_profile_id'] = data['net_profile_id']
|
||||
network = api.neutron.network_create(request, **params)
|
||||
self.context['net_id'] = network.id
|
||||
msg = (_('Network "%s" was successfully created.') %
|
||||
network.name_or_id)
|
||||
LOG.debug(msg)
|
||||
return network
|
||||
except Exception as e:
|
||||
msg = (_('Failed to create network "%(network)s": %(reason)s') %
|
||||
{"network": data['net_name'], "reason": e})
|
||||
LOG.info(msg)
|
||||
# Delete Precreated Network
|
||||
try:
|
||||
precreate_network = dict(tenant_id=request.user.project_id,
|
||||
nwk_name=data['net_name'],
|
||||
subnet=data['cidr'],
|
||||
cfgp=data['cfg_profile'])
|
||||
dfaclient = dfa_client.dfa_client()
|
||||
dfaclient.do_delete_precreate_network(precreate_network)
|
||||
except Exception as exc:
|
||||
LOG.error('Unable to delete precreated Network')
|
||||
exceptions.handle(self.request, exc.message)
|
||||
redirect = self.get_failure_url()
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def handle(self, request, data):
|
||||
precreate_flag = False
|
||||
'''Pre-create network in enabler'''
|
||||
precreate_network = dict(tenant_id=request.user.project_id,
|
||||
nwk_name=data['net_name'],
|
||||
subnet=data['cidr'],
|
||||
cfgp=data['cfg_profile'])
|
||||
if data['cfg_profile']:
|
||||
dfaclient = dfa_client.dfa_client()
|
||||
try:
|
||||
precreate_flag = dfaclient.do_precreate_network(
|
||||
precreate_network)
|
||||
except Exception as exc:
|
||||
LOG.error('Unable to do precreate Network')
|
||||
exceptions.handle(self.request, exc.message)
|
||||
return False
|
||||
|
||||
network = self._create_network(request, data)
|
||||
if not network:
|
||||
if precreate_flag:
|
||||
# do precreate delete
|
||||
try:
|
||||
dfaclient.do_delete_precreate_network(precreate_network)
|
||||
precreate_flag = False
|
||||
except Exception as exc:
|
||||
LOG.error('Unable to delete precreatedd Network')
|
||||
exceptions.handle(self.request, exc.message)
|
||||
return False
|
||||
# If we do not need to create a subnet, return here.
|
||||
if not data['with_subnet']:
|
||||
return True
|
||||
subnet = self._create_subnet(request, data, network, no_redirect=True)
|
||||
if subnet:
|
||||
return True
|
||||
else:
|
||||
self._delete_network(request, network)
|
||||
if precreate_flag:
|
||||
# do precreate delete
|
||||
try:
|
||||
dfaclient.do_delete_precreate_network(precreate_network)
|
||||
except Exception as exc:
|
||||
LOG.error('Unable to delete precreated Network')
|
||||
exceptions.handle(self.request, exc.message)
|
||||
return False
|
|
@ -13,10 +13,22 @@
|
|||
# under the License.
|
||||
|
||||
|
||||
from horizon_cisco_ui.cisco.dfa \
|
||||
import workflows as cisco_network_workflows
|
||||
from horizon_cisco_ui.firewalls \
|
||||
import views as cisco_firewall_views
|
||||
from openstack_dashboard.dashboards.project.firewalls \
|
||||
import views as firewall_views
|
||||
from openstack_dashboard.dashboards.project.networks \
|
||||
import workflows as horizon_network_workflows
|
||||
|
||||
horizon_network_workflows.CreateNetwork.default_steps = \
|
||||
cisco_network_workflows.DFACreateNetwork.default_steps
|
||||
horizon_network_workflows.CreateNetwork.handle = \
|
||||
cisco_network_workflows.DFACreateNetwork.handle
|
||||
horizon_network_workflows.CreateNetwork._create_network = \
|
||||
cisco_network_workflows.DFACreateNetwork._create_network
|
||||
|
||||
|
||||
# TODO(robcresswell): remove example
|
||||
# Silly example that does nothing, but illustrates an override.
|
||||
|
|
Loading…
Reference in New Issue