Merge pull request #92 from CiscoSystems/dashboard-quantum-integration
Dashboard quantum integration
This commit is contained in:
commit
c158f6fd15
@ -47,9 +47,9 @@ import openstackx.admin
|
||||
import openstackx.api.exceptions as api_exceptions
|
||||
import openstackx.extras
|
||||
import openstackx.auth
|
||||
import quantum.client
|
||||
from urlparse import urlparse
|
||||
|
||||
|
||||
LOG = logging.getLogger('django_openstack.api')
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ class Server(APIResourceWrapper):
|
||||
"""
|
||||
_attrs = ['addresses', 'attrs', 'hostId', 'id', 'image', 'links',
|
||||
'metadata', 'name', 'private_ip', 'public_ip', 'status', 'uuid',
|
||||
'image_name']
|
||||
'image_name', 'VirtualInterfaces']
|
||||
|
||||
def __init__(self, apiresource, request):
|
||||
super(Server, self).__init__(apiresource)
|
||||
@ -240,11 +240,17 @@ class SwiftAuthentication(object):
|
||||
def authenticate(self):
|
||||
return (self.storage_url, '', self.auth_token)
|
||||
|
||||
|
||||
class ServiceCatalogException(api_exceptions.ApiException):
|
||||
def __init__(self, service_name):
|
||||
message = 'Invalid service catalog service: %s' % service_name
|
||||
super(ServiceCatalogException, self).__init__(404, message)
|
||||
|
||||
|
||||
class VirtualInterface(APIResourceWrapper):
|
||||
_attrs = ['id','mac_address']
|
||||
|
||||
|
||||
def url_for(request, service_name, admin=False):
|
||||
catalog = request.user.service_catalog
|
||||
try:
|
||||
@ -345,6 +351,11 @@ def swift_api(request):
|
||||
return cloudfiles.get_connection(auth=auth)
|
||||
|
||||
|
||||
def quantum_api(request):
|
||||
return quantum.client.Client(settings.QUANTUM_URL, settings.QUANTUM_PORT,
|
||||
False, request.user.tenant, 'json')
|
||||
|
||||
|
||||
def console_create(request, instance_id, kind='text'):
|
||||
return Console(extras_api(request).consoles.create(instance_id, kind))
|
||||
|
||||
@ -642,6 +653,41 @@ def swift_get_object_data(request, container_name, object_name):
|
||||
container = swift_api(request).get_container(container_name)
|
||||
return container.get_object(object_name).stream()
|
||||
|
||||
def get_vif_ids(request):
|
||||
vifs = []
|
||||
attached_vifs = []
|
||||
# Get a list of all networks
|
||||
networks_list = quantum_api(request).list_networks()
|
||||
for network in networks_list['networks']:
|
||||
ports = quantum_api(request).list_ports(network['id'])
|
||||
# Get port attachments
|
||||
for port in ports['ports']:
|
||||
port_attachment = quantum_api(request).show_port_attachment(network['id'], port['id'])
|
||||
if port_attachment['attachment']:
|
||||
attached_vifs.append(port_attachment['attachment'].encode('ascii'))
|
||||
# Get all instances
|
||||
instances = server_list(request)
|
||||
# Get virtual interface ids by instance
|
||||
for instance in instances:
|
||||
instance_vifs = extras_api(request).virtual_interfaces.list(instance.id)
|
||||
for vif in instance_vifs:
|
||||
# Check if this VIF is already connected to any port
|
||||
if str(vif.id) in attached_vifs:
|
||||
vifs.append({
|
||||
'id' : vif.id,
|
||||
'instance' : instance.id,
|
||||
'instance_name' : instance.name,
|
||||
'available' : False
|
||||
})
|
||||
else:
|
||||
vifs.append({
|
||||
'id' : vif.id,
|
||||
'instance' : instance.id,
|
||||
'instance_name' : instance.name,
|
||||
'available' : True
|
||||
})
|
||||
return vifs
|
||||
|
||||
class GlobalSummary(object):
|
||||
node_resources = ['vcpus', 'disk_size', 'ram_size']
|
||||
unit_mem_size = {'disk_size': ['GiB', 'TiB'], 'ram_size': ['MiB', 'GiB']}
|
||||
|
@ -38,3 +38,7 @@ def tenants(request):
|
||||
|
||||
def swift(request):
|
||||
return {'swift_configured': settings.SWIFT_ENABLED}
|
||||
|
||||
|
||||
def quantum(request):
|
||||
return {'quantum_configured': settings.QUANTUM_ENABLED}
|
||||
|
@ -26,6 +26,8 @@ KEYPAIRS = r'^(?P<tenant_id>[^/]+)/keypairs/%s$'
|
||||
SNAPSHOTS = r'^(?P<tenant_id>[^/]+)/snapshots/(?P<instance_id>[^/]+)/%s$'
|
||||
CONTAINERS = r'^(?P<tenant_id>[^/]+)/containers/%s$'
|
||||
OBJECTS = r'^(?P<tenant_id>[^/]+)/containers/(?P<container_name>[^/]+)/%s$'
|
||||
NETWORKS = r'^(?P<tenant_id>[^/]+)/networks/%s$'
|
||||
PORTS = r'^(?P<tenant_id>[^/]+)/networks/(?P<network_id>[^/]+)/ports/%s$'
|
||||
|
||||
urlpatterns = patterns('django_openstack.dash.views.instances',
|
||||
url(r'^(?P<tenant_id>[^/]+)/$', 'usage', name='dash_usage'),
|
||||
@ -65,3 +67,15 @@ urlpatterns += patterns('django_openstack.dash.views.objects',
|
||||
url(OBJECTS % '(?P<object_name>[^/]+)/download',
|
||||
'download', name='dash_objects_download'),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('django_openstack.dash.views.networks',
|
||||
url(r'^(?P<tenant_id>[^/]+)/networks/$', 'index', name='dash_networks'),
|
||||
url(NETWORKS % 'create', 'create', name='dash_network_create'),
|
||||
url(NETWORKS % '(?P<network_id>[^/]+)/detail', 'detail', name='dash_networks_detail'),
|
||||
url(NETWORKS % '(?P<network_id>[^/]+)/rename', 'rename', name='dash_network_rename'),
|
||||
)
|
||||
|
||||
urlpatterns += patterns('django_openstack.dash.views.ports',
|
||||
url(PORTS % 'create', 'create', name='dash_ports_create'),
|
||||
url(PORTS % '(?P<port_id>[^/]+)/attach', 'attach', name='dash_ports_attach'),
|
||||
)
|
||||
|
237
django-openstack/django_openstack/dash/views/networks.py
Normal file
237
django-openstack/django_openstack/dash/views/networks.py
Normal file
@ -0,0 +1,237 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Fourth Paradigm Development, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Views for managing api.quantum_api(request) networks.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django import http
|
||||
from django import shortcuts
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils import simplejson
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from django_openstack import forms
|
||||
from django_openstack import api
|
||||
|
||||
from django_openstack.dash.views.ports import DeletePort
|
||||
from django_openstack.dash.views.ports import DetachPort
|
||||
from django_openstack.dash.views.ports import TogglePort
|
||||
|
||||
import warnings
|
||||
|
||||
|
||||
LOG = logging.getLogger('django_openstack.dash.views.networks')
|
||||
|
||||
class CreateNetwork(forms.SelfHandlingForm):
|
||||
name = forms.CharField(required=True, label="Network Name")
|
||||
|
||||
def handle(self, request, data):
|
||||
network_name = data['name']
|
||||
|
||||
try:
|
||||
LOG.info('Creating network %s ' % network_name)
|
||||
send_data = {'network': {'net-name': '%s' % network_name}}
|
||||
api.quantum_api(request).create_network(send_data)
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to create network %s: %s' %
|
||||
(network_name, e.message,))
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
else:
|
||||
msg = 'Network %s has been created.' % network_name
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
return shortcuts.redirect('dash_networks', tenant_id=request.user.tenant)
|
||||
|
||||
|
||||
class DeleteNetwork(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Deleting network %s ' % data['network'])
|
||||
api.quantum_api(request).delete_network(data['network'])
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to delete network %s: %s' %
|
||||
(data['network'], e.message,))
|
||||
else:
|
||||
msg = 'Network %s has been deleted.' % data['network']
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
class RenameNetwork(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
new_name = forms.CharField(required=True)
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Renaming network %s to %s' % (data['network'], data['new_name']))
|
||||
send_data = {'network': {'net-name': '%s' % data['new_name']}}
|
||||
api.quantum_api(request).update_network(data['network'], send_data)
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to rename network %s: %s' %
|
||||
(data['network'], e.message,))
|
||||
else:
|
||||
msg = 'Network %s has been renamed to %s.' % (data['network'], data['new_name'])
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request, tenant_id):
|
||||
delete_form, delete_handled = DeleteNetwork.maybe_handle(request)
|
||||
|
||||
networks = []
|
||||
instances = []
|
||||
|
||||
try:
|
||||
networks_list = api.quantum_api(request).list_networks()
|
||||
details = []
|
||||
for network in networks_list['networks']:
|
||||
net_stats = _calc_network_stats(request, tenant_id, network['id'])
|
||||
# Get network details like name and id
|
||||
details = api.quantum_api(request).show_network_details(network['id'])
|
||||
networks.append({
|
||||
'name' : details['network']['name'],
|
||||
'id' : network['id'],
|
||||
'total' : net_stats['total'],
|
||||
'available' : net_stats['available'],
|
||||
'used' : net_stats['used'],
|
||||
'tenant' : tenant_id
|
||||
})
|
||||
|
||||
except Exception, e:
|
||||
messages.error(request, 'Unable to get network list: %s' % e.message)
|
||||
|
||||
return shortcuts.render_to_response('dash_networks.html', {
|
||||
'networks': networks,
|
||||
'delete_form' : delete_form,
|
||||
}, context_instance=template.RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def create(request, tenant_id):
|
||||
network_form, handled = CreateNetwork.maybe_handle(request)
|
||||
if handled:
|
||||
return shortcuts.redirect('dash_networks', request.user.tenant)
|
||||
|
||||
return shortcuts.render_to_response('dash_network_create.html', {
|
||||
'network_form' : network_form
|
||||
}, context_instance=template.RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def detail(request, tenant_id, network_id):
|
||||
delete_port_form, delete_handled = DeletePort.maybe_handle(request)
|
||||
detach_port_form, detach_handled = DetachPort.maybe_handle(request)
|
||||
toggle_port_form, port_toggle_handled = TogglePort.maybe_handle(request)
|
||||
|
||||
network = {}
|
||||
|
||||
try:
|
||||
network_details = api.quantum_api(request).show_network_details(network_id)
|
||||
network['name'] = network_details['network']['name']
|
||||
network['id'] = network_id
|
||||
network['ports'] = _get_port_states(request, tenant_id, network_id)
|
||||
except Exception, e:
|
||||
messages.error(request, 'Unable to get network details: %s' % e.message)
|
||||
|
||||
return shortcuts.render_to_response('dash_networks_detail.html', {
|
||||
'network': network,
|
||||
'tenant' : tenant_id,
|
||||
'delete_port_form' : delete_port_form,
|
||||
'detach_port_form' : detach_port_form,
|
||||
'toggle_port_form' : toggle_port_form
|
||||
}, context_instance=template.RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def rename(request, tenant_id, network_id):
|
||||
rename_form, handled = RenameNetwork.maybe_handle(request)
|
||||
network_details = api.quantum_api(request).show_network_details(network_id)
|
||||
|
||||
if handled:
|
||||
return shortcuts.redirect('dash_networks', request.user.tenant)
|
||||
|
||||
return shortcuts.render_to_response('dash_network_rename.html', {
|
||||
'network' : network_details,
|
||||
'rename_form' : rename_form
|
||||
}, context_instance=template.RequestContext(request))
|
||||
|
||||
"""
|
||||
Helper method to find port states for a network
|
||||
"""
|
||||
def _get_port_states(request, tenant_id, network_id):
|
||||
network_ports = []
|
||||
# Get all vifs for comparison with port attachments
|
||||
vifs = api.get_vif_ids(request)
|
||||
|
||||
# Get all ports on this network
|
||||
ports = api.quantum_api(request).list_ports(network_id)
|
||||
for port in ports['ports']:
|
||||
port_details = api.quantum_api(request).show_port_details(network_id, port['id'])
|
||||
# Get port attachments
|
||||
port_attachment = api.quantum_api(request).show_port_attachment(network_id, port['id'])
|
||||
# Find instance the attachment belongs to
|
||||
connected_instance = None
|
||||
for vif in vifs:
|
||||
if str(vif['id']) == str(port_attachment['attachment']):
|
||||
connected_instance = vif['instance_name']
|
||||
break
|
||||
network_ports.append({
|
||||
'id' : port_details['port']['id'],
|
||||
'state' : port_details['port']['state'],
|
||||
'attachment' : port_attachment['attachment'],
|
||||
'instance' : connected_instance
|
||||
})
|
||||
|
||||
return network_ports
|
||||
|
||||
"""
|
||||
Helper method to calculate statistics for a network
|
||||
"""
|
||||
def _calc_network_stats(request, tenant_id, network_id):
|
||||
# Get all ports statistics for the network
|
||||
total = 0
|
||||
available = 0
|
||||
used = 0
|
||||
ports = api.quantum_api(request).list_ports(network_id)
|
||||
for port in ports['ports']:
|
||||
total += 1
|
||||
# Get port attachment
|
||||
port_attachment = api.quantum_api(request).show_port_attachment(network_id, port['id'])
|
||||
if port_attachment['attachment'] == None:
|
||||
available += 1
|
||||
else:
|
||||
used += 1
|
||||
|
||||
return { 'total' : total, 'used' : used, 'available': available }
|
192
django-openstack/django_openstack/dash/views/ports.py
Normal file
192
django-openstack/django_openstack/dash/views/ports.py
Normal file
@ -0,0 +1,192 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2011 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2011 Fourth Paradigm Development, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Views for managing api.quantum_api(request) network ports.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django import http
|
||||
from django import shortcuts
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from django_openstack import forms
|
||||
from django_openstack import api
|
||||
|
||||
|
||||
LOG = logging.getLogger('django_openstack.dash.views.ports')
|
||||
|
||||
|
||||
class CreatePort(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
ports_num = forms.IntegerField(required=True, label="Number of Ports")
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Creating %s ports on network %s' % (data['ports_num'], data['network']))
|
||||
for i in range(0, data['ports_num']):
|
||||
api.quantum_api(request).create_port(data['network'])
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to create ports on network %s: %s' %
|
||||
(data['network'], e.message,))
|
||||
else:
|
||||
msg = '%s ports created on network %s.' % (data['ports_num'], data['network'])
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
class DeletePort(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
port = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Deleting %s ports on network %s' % (data['port'], data['network']))
|
||||
api.quantum_api(request).delete_port(data['network'], data['port'])
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to delete port %s: %s' %
|
||||
(data['port'], e.message,))
|
||||
else:
|
||||
msg = 'Port %s deleted from network %s.' % (data['port'], data['network'])
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
class AttachPort(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
port = forms.CharField(widget=forms.HiddenInput())
|
||||
vif_id = forms.CharField(widget=forms.Select(), label="Select VIF to connect")
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Attaching %s port to VIF %s' % (data['port'], data['vif_id']))
|
||||
body = {'port': {'attachment-id': '%s' % data['vif_id']}}
|
||||
api.quantum_api(request).attach_resource(data['network'], data['port'], body)
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to attach port %s to VIF %s: %s' %
|
||||
(data['port'], data['vif_id'], e.message,))
|
||||
else:
|
||||
msg = 'Port %s connect to VIF %s.' % (data['port'], data['vif_id'])
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
class DetachPort(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
port = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Detaching port %s' % data['port'])
|
||||
api.quantum_api(request).detach_resource(data['network'], data['port'])
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to detach port %s: %s' %
|
||||
(data['port'], e.message,))
|
||||
else:
|
||||
msg = 'Port %s detached.' % (data['port'])
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
class TogglePort(forms.SelfHandlingForm):
|
||||
network = forms.CharField(widget=forms.HiddenInput())
|
||||
port = forms.CharField(widget=forms.HiddenInput())
|
||||
state = forms.CharField(widget=forms.HiddenInput())
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
LOG.info('Toggling port state to %s' % data['state'])
|
||||
body = {'port': {'port-state': '%s' % data['state']}}
|
||||
api.quantum_api(request).set_port_state(data['network'], data['port'], body)
|
||||
except Exception, e:
|
||||
messages.error(request,
|
||||
'Unable to set port state to %s: %s' %
|
||||
(data['state'], e.message,))
|
||||
else:
|
||||
msg = 'Port %s state set to %s.' % (data['port'],data['state'])
|
||||
LOG.info(msg)
|
||||
messages.success(request, msg)
|
||||
return shortcuts.redirect(request.build_absolute_uri())
|
||||
|
||||
|
||||
@login_required
|
||||
def create(request, tenant_id, network_id):
|
||||
create_form, handled = CreatePort.maybe_handle(request)
|
||||
|
||||
if handled:
|
||||
return shortcuts.redirect(
|
||||
'dash_networks_detail',
|
||||
tenant_id=request.user.tenant,
|
||||
network_id=network_id
|
||||
)
|
||||
|
||||
return shortcuts.render_to_response('dash_ports_create.html', {
|
||||
'network_id' : network_id,
|
||||
'create_form' : create_form
|
||||
}, context_instance=template.RequestContext(request))
|
||||
|
||||
|
||||
@login_required
|
||||
def attach(request, tenant_id, network_id, port_id):
|
||||
attach_form, handled = AttachPort.maybe_handle(request)
|
||||
|
||||
if handled:
|
||||
return shortcuts.redirect('dash_networks_detail', request.user.tenant, network_id)
|
||||
|
||||
# Get all avaliable vifs
|
||||
vifs = _get_available_vifs(request)
|
||||
|
||||
return shortcuts.render_to_response('dash_port_attach.html', {
|
||||
'network' : network_id,
|
||||
'port' : port_id,
|
||||
'attach_form' : attach_form,
|
||||
'vifs' : vifs,
|
||||
}, context_instance=template.RequestContext(request))
|
||||
|
||||
|
||||
"""
|
||||
Method to get a list of available virtual interfaces
|
||||
"""
|
||||
def _get_available_vifs(request):
|
||||
vif_choices = []
|
||||
vifs = api.get_vif_ids(request)
|
||||
|
||||
for vif in vifs:
|
||||
if vif['available']:
|
||||
name = "Instance %s VIF %s" % (str(vif['instance_name']), str(vif['id']))
|
||||
vif_choices.append({
|
||||
'name' : str(name),
|
||||
'id' : str(vif['id'])
|
||||
})
|
||||
|
||||
return vif_choices
|
@ -44,6 +44,9 @@ class TestCase(test.TestCase):
|
||||
'region': 'RegionOne',
|
||||
'internalURL': 'http://127.0.0.1:8080/v1/AUTH_1234',
|
||||
'publicURL': 'http://swift.publicinternets.com/v1/AUTH_1234'}],
|
||||
'quantum':
|
||||
[{'adminURL': 'http://127.0.0.1:9696/v0.1',
|
||||
'internalURL': 'http://127.0.0.1:9696/v0.1'}],
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
|
@ -0,0 +1,113 @@
|
||||
from django import http
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django_openstack import api
|
||||
from django_openstack.tests.view_tests import base
|
||||
from mox import IgnoreArg, IsA
|
||||
|
||||
|
||||
class NetworkViewTests(base.BaseViewTests):
|
||||
def setUp(self):
|
||||
super(NetworkViewTests, self).setUp()
|
||||
self.network = {}
|
||||
self.network['networks'] = []
|
||||
self.network['networks'].append({id : 'n1'})
|
||||
self.network_details = {'network' : {'name' : 'test_network'}}
|
||||
self.ports = {}
|
||||
self.ports['ports'] = []
|
||||
self.ports['ports'].append({'id' : 'p1'})
|
||||
self.port_attachment = {}
|
||||
self.port_attachment['attachment'] = 'vif1'
|
||||
|
||||
def test_network_index(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'list_networks')
|
||||
q_api.list_networks()(
|
||||
IsA(http.HttpRequest)).AndReturn([self.network])
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'show_network_details')
|
||||
q_api.show_network_details("n1")(
|
||||
IsA(http.HttpRequest)).AndReturn([self.network_details])
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'list_ports')
|
||||
q_api.list_ports("n1")(
|
||||
IsA(http.HttpRequest)).AndReturn([self.ports])
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'show_port_attachment')
|
||||
q_api.show_port_attachment("p1")(
|
||||
IsA(http.HttpRequest)).AndReturn([self.port_attachment])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(reverse('dash_networks', args=['tenant']))
|
||||
|
||||
self.assertTemplateUsed(res, 'dash_networks.html')
|
||||
self.assertIn('networks', res.context)
|
||||
networks = res.context['networks']
|
||||
|
||||
self.assertEqual(len(networks), 1)
|
||||
self.assertEqual(networks[0].name, 'test')
|
||||
self.assertEqual(networks[0].id, 'n1')
|
||||
self.assertEqual(networks[0].id, 'n1')
|
||||
self.assertEqual(networks[0].total, 1)
|
||||
self.assertEqual(networks[0].used, 1)
|
||||
self.assertEqual(networks[0].available, 0)
|
||||
|
||||
self.mox.VerifyAll()
|
||||
|
||||
def test_network_create(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'name': 'Test',
|
||||
'method': 'CreateNetwork'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'create_network')
|
||||
q_api.create_network(
|
||||
IsA(http.HttpRequest), 'CreateNetwork')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_network_create',
|
||||
args=[self.request.user.tenant]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks',
|
||||
args=[self.request.user.tenant]))
|
||||
|
||||
def test_network_delete(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'id': 'n1',
|
||||
'method': 'DeleteNetwork'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'delete_network')
|
||||
q_api.delete_network(
|
||||
IsA(http.HttpRequest), 'DeleteNetwork')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_networks',
|
||||
args=[self.request.user.tenant]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks',
|
||||
args=[self.request.user.tenant]))
|
||||
|
||||
def test_network_rename(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'new_name' : 'Test1',
|
||||
'method': 'DeleteNetwork'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'update_network')
|
||||
q_api.update_network("n1")(
|
||||
IsA(http.HttpRequest), 'DeleteNetwork')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_network_rename',
|
||||
args=[self.request.user.tenant, "n1"]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks',
|
||||
args=[self.request.user.tenant]))
|
@ -0,0 +1,92 @@
|
||||
from django import http
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django_openstack import api
|
||||
from django_openstack.tests.view_tests import base
|
||||
from mox import IgnoreArg, IsA
|
||||
|
||||
|
||||
class PortViewTests(base.BaseViewTests):
|
||||
def setUp(self):
|
||||
super(PortViewTests, self).setUp()
|
||||
|
||||
def test_port_create(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'ports_num' : 1,
|
||||
'network' : 'n1',
|
||||
'method': 'CreatePort'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'create_port')
|
||||
q_api.create_port(self.request.user.tenant, "n1")(
|
||||
IsA(http.HttpRequest), 'CreatePort')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_ports_create',
|
||||
args=[self.request.user.tenant, "n1"]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks_detail',
|
||||
args=[self.request.user.tenant, "n1"]))
|
||||
|
||||
def test_port_delete(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'port' : 'p1',
|
||||
'network' : 'n1',
|
||||
'method': 'DeletePort'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'delete_port')
|
||||
q_api.delete_port(self.request.user.tenant, "n1", "p1")(
|
||||
IsA(http.HttpRequest), 'DeletePort')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_networks_detail',
|
||||
args=[self.request.user.tenant, "n1"]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks_detail',
|
||||
args=[self.request.user.tenant, "n1"]))
|
||||
|
||||
def test_port_attach(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'port' : 'p1',
|
||||
'network' : 'n1',
|
||||
'vif_id' : 'v1',
|
||||
'method': 'AttachPort'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'attach_resource')
|
||||
q_api.attach_resource(self.request.user.tenant, "n1", "p1")(
|
||||
IsA(http.HttpRequest), 'AttachPort')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_ports_attach',
|
||||
args=[self.request.user.tenant, "n1", "p1"]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks_detail',
|
||||
args=[self.request.user.tenant, "n1"]))
|
||||
|
||||
def test_port_detach(self):
|
||||
q_api = api.quantum_api(self.request)
|
||||
formData = {'port' : 'p1',
|
||||
'network' : 'n1',
|
||||
'method': 'DetachPort'}
|
||||
|
||||
self.mox.StubOutWithMock(q_api, 'detach_resource')
|
||||
q_api.detach_resource(self.request.user.tenant, "n1", "p1")(
|
||||
IsA(http.HttpRequest), 'DetachPort')
|
||||
|
||||
self.mox.StubOutWithMock(messages, 'success')
|
||||
messages.success(IgnoreArg(), IsA(str))
|
||||
|
||||
res = self.client.post(reverse('dash_networks_detail',
|
||||
args=[self.request.user.tenant, "n1"]),
|
||||
formData)
|
||||
|
||||
self.assertRedirectsNoFollow(res, reverse('dash_networks_detail',
|
||||
args=[self.request.user.tenant, "n1"]))
|
@ -64,6 +64,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django_openstack.context_processors.swift',
|
||||
'django_openstack.context_processors.tenants',
|
||||
'django_openstack.context_processors.quantum',
|
||||
)
|
||||
|
||||
TEMPLATE_LOADERS = (
|
||||
|
12
openstack-dashboard/dashboard/templates/_attach_port.html
Normal file
12
openstack-dashboard/dashboard/templates/_attach_port.html
Normal file
@ -0,0 +1,12 @@
|
||||
<form id="attach_port_form_{{port.id}}" class="form-attach" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}{{hidden}}{% endfor %}
|
||||
{% for field in form.visible_fields %}
|
||||
{{ field.label_tag }}
|
||||
{{ field.errors }}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<input name="network" type="hidden" value="{{network}}" />
|
||||
<input name="port" type="hidden" value="{{port}}" />
|
||||
<input type="submit" value="Attach" class="large-rounded" />
|
||||
</form>
|
11
openstack-dashboard/dashboard/templates/_create_port.html
Normal file
11
openstack-dashboard/dashboard/templates/_create_port.html
Normal file
@ -0,0 +1,11 @@
|
||||
<form id="create_port_form" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
||||
{% for field in form.visible_fields %}
|
||||
{{ field.label_tag }}
|
||||
{{ field.errors }}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<input name="network" type="hidden" value="{{network_id}}" />
|
||||
<input type="submit" value="Create Ports" class="large-rounded" />
|
||||
</form>
|
@ -8,6 +8,9 @@
|
||||
<li><a {% if current_sidebar == "images" %} class="active" {% endif %} href="{% url dash_images request.user.tenant %}">Images</a></li>
|
||||
<li><a {% if current_sidebar == "snapshots" %} class="active" {% endif %} href="{% url dash_snapshots request.user.tenant %}">Snapshots</a></li>
|
||||
<li><a {% if current_sidebar == "keypairs" %} class="active" {% endif %} href="{% url dash_keypairs request.user.tenant %}">Keypairs</a></li>
|
||||
{% if quantum_configured %}
|
||||
<li><a {% if current_sidebar == "networks" %} class="active" {% endif %} href="{% url dash_networks request.user.tenant %}">Networks</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% if swift_configured %}
|
||||
<h3>Manage Object Store</h3>
|
||||
|
@ -0,0 +1,8 @@
|
||||
<form id="delete_form" class="form-delete" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}
|
||||
{{hidden}}
|
||||
{% endfor %}
|
||||
<input name="network" type="hidden" value="{{network.id}}" />
|
||||
<input title="Network" id="delete_{{network.id}}" class="delete" type="submit" value="Delete" />
|
||||
</form>
|
@ -0,0 +1,9 @@
|
||||
<form id="delete_port_form" class="form-delete" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}
|
||||
{{hidden}}
|
||||
{% endfor %}
|
||||
<input name="network" type="hidden" value="{{network.id}}" />
|
||||
<input name="port" type="hidden" value="{{port.id}}" />
|
||||
<input title="Delete this port" id="delete_{{port.id}}" class="delete" type="submit" value="Delete" />
|
||||
</form>
|
@ -0,0 +1,9 @@
|
||||
<form id="detach_port_form" class="form-detach" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}
|
||||
{{hidden}}
|
||||
{% endfor %}
|
||||
<input name="network" type="hidden" value="{{network.id}}" />
|
||||
<input name="port" type="hidden" value="{{port.id}}" />
|
||||
<input title="Detach port from instance" id="detach_{{port.id}}" class="detach" type="submit" value="Detach" />
|
||||
</form>
|
49
openstack-dashboard/dashboard/templates/_network_detail.html
Normal file
49
openstack-dashboard/dashboard/templates/_network_detail.html
Normal file
@ -0,0 +1,49 @@
|
||||
<table id='Ports' class="wide">
|
||||
<tr id='headings'>
|
||||
<th>ID</th>
|
||||
<th>State</th>
|
||||
<th>Attachment</th>
|
||||
<th>Actions</th>
|
||||
<th>Extensions</th>
|
||||
</tr>
|
||||
<tbody class='main'>
|
||||
{% for port in network.ports %}
|
||||
<tr class="{% cycle 'odd' 'even' %}">
|
||||
<td>{{port.id}}</td>
|
||||
<td class="{{port.state}}">{{port.state}}</td>
|
||||
<td>
|
||||
{% if port.attachment == None %}
|
||||
--
|
||||
{% else %}
|
||||
<table class="attachmend_details">
|
||||
<tr>
|
||||
<td> Instance </td>
|
||||
<td> VIF Id </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{port.instance}} </td>
|
||||
<td> {{port.attachment}} </td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td id="actions">
|
||||
<ul>
|
||||
{% if port.attachment == None %}
|
||||
<li><a href='{% url dash_ports_attach request.user.tenant network.id port.id %}'>Attach</a></li>
|
||||
{% else %}
|
||||
<li class="form">{% include "_detach_port.html" with form=detach_port_form %}</li>
|
||||
{% endif %}
|
||||
<li class="form">{% include "_delete_port.html" with form=delete_port_form %}</li>
|
||||
<li class="form">{% include "_toggle_port.html" with form=toggle_port_form %}</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td id="extensions">
|
||||
<ul>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
10
openstack-dashboard/dashboard/templates/_network_form.html
Normal file
10
openstack-dashboard/dashboard/templates/_network_form.html
Normal file
@ -0,0 +1,10 @@
|
||||
<form id="network_form" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
||||
{% for field in form.visible_fields %}
|
||||
{{ field.label_tag }}
|
||||
{{ field.errors }}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<input type="submit" value="Create Network" class="large-rounded" />
|
||||
</form>
|
27
openstack-dashboard/dashboard/templates/_network_list.html
Normal file
27
openstack-dashboard/dashboard/templates/_network_list.html
Normal file
@ -0,0 +1,27 @@
|
||||
<table id='networks' class="wide">
|
||||
<tr id='headings'>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Ports</th>
|
||||
<th>Available</th>
|
||||
<th>Used</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
<tbody class='main'>
|
||||
{% for network in networks %}
|
||||
<tr class="{% cycle 'odd' 'even' %}" id="{{network.id}}">
|
||||
<td><a href='{% url dash_networks_detail request.user.tenant network.id %}'>{{network.id}}</a></td>
|
||||
<td class="name">{{network.name}}</td>
|
||||
<td>{{network.total}}</td>
|
||||
<td>{{network.available}}</td>
|
||||
<td>{{network.used}}</td>
|
||||
<td id="actions">
|
||||
<ul>
|
||||
<li class="form">{% include "_delete_network.html" with form=delete_form %}</li>
|
||||
<li><a href='{% url dash_network_rename request.user.tenant network.id %}'>Rename</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
@ -1,6 +1,8 @@
|
||||
{% block page_header %}
|
||||
<div id='page_header'>
|
||||
<h2>{{title}}</h2>
|
||||
{% block breadcrumbs %}
|
||||
{% endblock %}
|
||||
{% if searchable %}
|
||||
<div class="right">
|
||||
<div class='search'>
|
||||
|
11
openstack-dashboard/dashboard/templates/_rename_form.html
Normal file
11
openstack-dashboard/dashboard/templates/_rename_form.html
Normal file
@ -0,0 +1,11 @@
|
||||
<form id="rename_form" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
|
||||
{% for field in form.visible_fields %}
|
||||
{{ field.label_tag }}
|
||||
{{ field.errors }}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<input type="hidden" name="network" value="{{network.network.id}}"/>
|
||||
<input type="submit" value="Rename Network" class="large-rounded" />
|
||||
</form>
|
17
openstack-dashboard/dashboard/templates/_rename_network.html
Normal file
17
openstack-dashboard/dashboard/templates/_rename_network.html
Normal file
@ -0,0 +1,17 @@
|
||||
<form id="form_rename_{{network.id}}" class="form-rename" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}
|
||||
{{hidden}}
|
||||
{% endfor %}
|
||||
|
||||
<input name="network" type="hidden" value="{{network.id}}" />
|
||||
<input id="new_name_{{network.id}}" name="new_name" type="hidden" value="{{network.name}}" />
|
||||
|
||||
<input id="rename_{{network.id}}" class="rename" type="submit" value="Rename" />
|
||||
|
||||
<div class="network_rename_div" id="rename_div_{{network.id}}">
|
||||
<input id="change_to_{{network.id}}" name="change_to" class="change_to ui-corner-all ui-state-highlight" size="20" value="{{network.name}}"/><br/><br/>
|
||||
<button id="{{network.id}}" class="dialog_rename">Rename</button>
|
||||
</div>
|
||||
|
||||
</form>
|
15
openstack-dashboard/dashboard/templates/_toggle_port.html
Normal file
15
openstack-dashboard/dashboard/templates/_toggle_port.html
Normal file
@ -0,0 +1,15 @@
|
||||
<form id="port_toggle_form" class="form-toggle" method="post">
|
||||
{% csrf_token %}
|
||||
{% for hidden in form.hidden_fields %}
|
||||
{{hidden}}
|
||||
{% endfor %}
|
||||
<input name="network" type="hidden" value="{{network.id}}" />
|
||||
<input name="port" type="hidden" value="{{port.id}}" />
|
||||
{% if port.state == 'DOWN' %}
|
||||
<input name="state" type="hidden" value="ACTIVE" />
|
||||
<input title="Turn port UP" id="port_up_{{port.id}}" class="port_up" type="submit" value="Port UP" />
|
||||
{% else %}
|
||||
<input name="state" type="hidden" value="DOWN" />
|
||||
<input title="Turn port DOWN" id="port_up_{{port.id}}" class="port_down" type="submit" value="Port DOWN" />
|
||||
{% endif %}
|
||||
</form>
|
@ -0,0 +1,28 @@
|
||||
{% extends 'dash_base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with current_sidebar="networks" %}
|
||||
{{block.super}}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "_page_header.html" with title="Create Network" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block dash_main %}
|
||||
<div class="dash_block">
|
||||
<div class="left">
|
||||
{% include '_network_form.html' with form=network_form %}
|
||||
<h3><a href="{% url dash_networks request.user.tenant %}"><< Return to networks list</a></h3>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<h3>Description:</h3>
|
||||
<p>Networks provide layer 2 connectivity to your instances.</p>
|
||||
</div>
|
||||
<div class="clear"> </div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -0,0 +1,36 @@
|
||||
{% extends 'dash_base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with current_sidebar="networks" %}
|
||||
{{block.super}}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "_page_header.html" with title="Rename Network" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block headerjs %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('input#id_new_name').val('{{network.network.name}}');
|
||||
});
|
||||
</script>
|
||||
{% endblock headerjs %}
|
||||
|
||||
{% block dash_main %}
|
||||
<div class="dash_block">
|
||||
<div class="left">
|
||||
{% include '_rename_form.html' with form=rename_form %}
|
||||
<h3><a href="{% url dash_networks request.user.tenant %}"><< Return to networks list</a></h3>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<h3>Rename:</h3>
|
||||
<p>Enter a new name for your network.</p>
|
||||
</div>
|
||||
<div class="clear"> </div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
26
openstack-dashboard/dashboard/templates/dash_networks.html
Normal file
26
openstack-dashboard/dashboard/templates/dash_networks.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% extends 'dash_base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with current_sidebar="networks" %}
|
||||
{{block.super}}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% url dash_networks request.user.tenant as refresh_link %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "_page_header.html" with title="Networks" refresh_link=refresh_link searchable="true" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block dash_main %}
|
||||
{% if networks %}
|
||||
{% include '_network_list.html' %}
|
||||
<a id="network_create_link" class="action_link large-rounded" href="{% url dash_network_create request.user.tenant %}">Create New Network</a>
|
||||
{% else %}
|
||||
<div class="message_box info">
|
||||
<h2>Info</h2>
|
||||
<p>There are currently no networks. <a href='{% url dash_network_create request.user.tenant %}'>Create A Network >></a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,30 @@
|
||||
{% extends 'dash_base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with current_sidebar="networks" %}
|
||||
{{block.super}}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% url dash_networks_detail request.user.tenant network.id as refresh_link %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "_page_header.html" with title=network.name refresh_link=refresh_link searchable="true" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<a href="{% url dash_networks tenant %}">Networks</a> »
|
||||
<a href="{% url dash_networks_detail tenant network.id %}">{{network.name}}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block dash_main %}
|
||||
{% if network.ports %}
|
||||
{% include '_network_detail.html' %}
|
||||
<a id="network_create_link" class="action_link large-rounded" href="{% url dash_ports_create request.user.tenant network.id %}">Create Ports</a>
|
||||
{% else %}
|
||||
<div class="message_box info">
|
||||
<h2>Info</h2>
|
||||
<p>There are currently no ports in this network. <a href="{% url dash_ports_create request.user.tenant network.id %}">Create Ports >></a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -0,0 +1,48 @@
|
||||
{% extends 'dash_base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with current_sidebar="networks" %}
|
||||
{{block.super}}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "_page_header.html" with title="Attach Port" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block headerjs %}
|
||||
<script type="text/javascript">
|
||||
var VIF_OPTIONS = {
|
||||
{% for vif in vifs %}
|
||||
'{{vif.id}}' : '{{vif.name}}',
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
$.each(VIF_OPTIONS, function(val, text) {
|
||||
$('select#id_vif_id')
|
||||
.append($("<option></option>")
|
||||
.attr("value", val)
|
||||
.text(text));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock headerjs %}
|
||||
|
||||
{% block dash_main %}
|
||||
<div class="dash_block">
|
||||
<div class="left">
|
||||
{% include '_attach_port.html' with form=attach_form %}
|
||||
<h3><a href="{% url dash_networks_detail request.user.tenant network %}"><< Return to network detail</a></h3>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<p>Select an interface from the list on the left to attach it to this port.</p>
|
||||
<p>Only interfaces that are not connected to any existing port are shown</p>
|
||||
<p>If you want to reconnect a connected interface, please detach it first</p>
|
||||
</div>
|
||||
<div class="clear"> </div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -0,0 +1,28 @@
|
||||
{% extends 'dash_base.html' %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% with current_sidebar="networks" %}
|
||||
{{block.super}}
|
||||
{% endwith %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{# to make searchable false, just remove it from the include statement #}
|
||||
{% include "_page_header.html" with title="Create Network" %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block dash_main %}
|
||||
<div class="dash_block">
|
||||
<div class="left">
|
||||
{% include '_create_port.html' with form=create_form %}
|
||||
<h3><a href="{% url dash_networks_detail request.user.tenant network_id %}"><< Return to network detail</a></h3>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<h3>Description:</h3>
|
||||
<p>You can plug virtual interfaces from your instances to ports created in the network</p>
|
||||
</div>
|
||||
<div class="clear"> </div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -39,6 +39,13 @@ OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"
|
||||
# catalog in Keystone.
|
||||
SWIFT_ENABLED = False
|
||||
|
||||
# Configure quantum connection details for networking
|
||||
QUANTUM_ENABLED = True
|
||||
QUANTUM_URL = '127.0.0.1'
|
||||
QUANTUM_PORT = '9696'
|
||||
QUANTUM_TENANT = '1234'
|
||||
QUANTUM_CLIENT_VERSION='0.1'
|
||||
|
||||
# If you have external monitoring links
|
||||
EXTERNAL_MONITORING = [
|
||||
['Nagios','http://foo.com'],
|
||||
|
@ -907,3 +907,48 @@ h3 span, .left h3 { color: #6a6a6a; }
|
||||
margin: 25px 0 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* Network details page */
|
||||
td.ACTIVE {
|
||||
color:#6EAF6E;
|
||||
}
|
||||
|
||||
td.DOWN {
|
||||
color:#CC3333;
|
||||
}
|
||||
|
||||
.vif-list {
|
||||
font: 12px/21px arial,sans-serif;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
table.attachment_table {
|
||||
margin-top: 10px;
|
||||
border: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
table.attachment_table td {
|
||||
padding: 5px;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
table.attachment_table td.row_head {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.attachment_table td.row_val {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.error_block {
|
||||
padding: 5px;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
span.attachment_value {
|
||||
font-weight:bold;
|
||||
display:inline-block;
|
||||
font-style:italic;
|
||||
color:#6EAF6E;
|
||||
}
|
||||
|
@ -45,5 +45,9 @@ $(function(){
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
$(".detach").click(function(e){
|
||||
var response = confirm('Are you sure you want to detach the '+$(this).attr('title')+" ?");
|
||||
return response;
|
||||
})
|
||||
})
|
||||
|
@ -3,6 +3,7 @@ Django==1.3
|
||||
django-nose==0.1.2
|
||||
django-mailer
|
||||
django-registration==0.7
|
||||
kombu
|
||||
nova-adminclient
|
||||
python-cloudfiles
|
||||
python-dateutil
|
||||
@ -14,9 +15,9 @@ PasteDeploy
|
||||
sqlalchemy-migrate
|
||||
eventlet
|
||||
xattr
|
||||
kombu
|
||||
|
||||
bzr+https://launchpad.net/glance#egg=glance
|
||||
-e git://github.com/jacobian/openstack.compute.git#egg=openstack
|
||||
-e git://github.com/cloudbuilders/openstackx.git#egg=openstackx
|
||||
bzr+https://launchpad.net/quantum#egg=quantum
|
||||
-e git+https://github.com/jacobian/openstack.compute.git#egg=openstack
|
||||
-e git+https://github.com/cloudbuilders/openstackx.git#egg=openstackx
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user