Commit fee9c1a3 by Kálmán Viktor

Merge branch 'master' into feature-helppage

Conflicts:
	circle/dashboard/static/dashboard/dashboard.js
	circle/dashboard/static/dashboard/dashboard.less
parents f6293056 0c706599
...@@ -15,4 +15,8 @@ ...@@ -15,4 +15,8 @@
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. # with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from .test_acl import TestModel, Test2Model # noqa from django.conf import settings
# https://code.djangoproject.com/ticket/7835
if settings.SETTINGS_MODULE == 'circle.settings.test':
from .test_acl import TestModel, Test2Model # noqa
...@@ -156,6 +156,7 @@ STATIC_URL = get_env_variable('DJANGO_STATIC_URL', default='/static/') ...@@ -156,6 +156,7 @@ STATIC_URL = get_env_variable('DJANGO_STATIC_URL', default='/static/')
STATICFILES_FINDERS = ( STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'pipeline.finders.PipelineFinder',
) )
########## END STATIC FILE CONFIGURATION ########## END STATIC FILE CONFIGURATION
STATICFILES_DIRS = [normpath(join(SITE_ROOT, 'bower_components'))] STATICFILES_DIRS = [normpath(join(SITE_ROOT, 'bower_components'))]
...@@ -282,6 +283,7 @@ TEMPLATE_CONTEXT_PROCESSORS = ( ...@@ -282,6 +283,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request', 'django.core.context_processors.request',
'dashboard.context_processors.notifications', 'dashboard.context_processors.notifications',
'dashboard.context_processors.extract_settings', 'dashboard.context_processors.extract_settings',
'dashboard.context_processors.broadcast_messages',
) )
# See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs # See: https://docs.djangoproject.com/en/dev/ref/settings/#template-dirs
...@@ -355,6 +357,7 @@ LOCAL_APPS = ( ...@@ -355,6 +357,7 @@ LOCAL_APPS = (
'manager', 'manager',
'acl', 'acl',
'monitor', 'monitor',
'request',
) )
# See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps # See: https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
...@@ -449,7 +452,7 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE': ...@@ -449,7 +452,7 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
) )
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
'djangosaml2.backends.Saml2Backend', 'common.backends.Saml2Backend',
) )
remote_metadata = join(SITE_ROOT, 'remote_metadata.xml') remote_metadata = join(SITE_ROOT, 'remote_metadata.xml')
...@@ -527,6 +530,10 @@ except: ...@@ -527,6 +530,10 @@ except:
LOCALE_PATHS = (join(SITE_ROOT, 'locale'), ) LOCALE_PATHS = (join(SITE_ROOT, 'locale'), )
COMPANY_NAME = get_env_variable("COMPANY_NAME", "BME IK 2015") COMPANY_NAME = get_env_variable("COMPANY_NAME", "BME IK 2015")
first, last = get_env_variable(
'VNC_PORT_RANGE', '20000, 65536').replace(' ', '').split(',')
VNC_PORT_RANGE = (int(first), int(last)) # inclusive start, exclusive end
graphite_host = environ.get("GRAPHITE_HOST", None) graphite_host = environ.get("GRAPHITE_HOST", None)
graphite_port = environ.get("GRAPHITE_PORT", None) graphite_port = environ.get("GRAPHITE_PORT", None)
if graphite_host and graphite_port: if graphite_host and graphite_port:
...@@ -555,3 +562,4 @@ ADMIN_ENABLED = False ...@@ -555,3 +562,4 @@ ADMIN_ENABLED = False
BLACKLIST_PASSWORD = get_env_variable("BLACKLIST_PASSWORD", "") BLACKLIST_PASSWORD = get_env_variable("BLACKLIST_PASSWORD", "")
BLACKLIST_HOOK_URL = get_env_variable("BLACKLIST_HOOK_URL", "") BLACKLIST_HOOK_URL = get_env_variable("BLACKLIST_HOOK_URL", "")
REQUEST_HOOK_URL = get_env_variable("REQUEST_HOOK_URL", "")
...@@ -110,8 +110,8 @@ if DEBUG: ...@@ -110,8 +110,8 @@ if DEBUG:
from django.dispatch import Signal from django.dispatch import Signal
Signal.send_robust = Signal.send Signal.send_robust = Signal.send
PIPELINE_DISABLED_COMPILERS = ( PIPELINE_COMPILERS = (
'pipeline.compilers.less.LessCompiler', 'dashboard.compilers.DummyLessCompiler',
) )
ADMIN_ENABLED = True ADMIN_ENABLED = True
...@@ -40,7 +40,8 @@ INSTALLED_APPS += ( ...@@ -40,7 +40,8 @@ INSTALLED_APPS += (
) )
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
path_to_selenium_test = os.path.expanduser('~/circle/circle/dashboard/tests/selenium')
path_to_selenium_test = os.path.join(SITE_ROOT, "dashboard/tests/selenium")
NOSE_ARGS = ['--stop', '--with-doctest', '--with-selenium-driver', '--selenium-driver=firefox', '-w%s' % path_to_selenium_test] NOSE_ARGS = ['--stop', '--with-doctest', '--with-selenium-driver', '--selenium-driver=firefox', '-w%s' % path_to_selenium_test]
PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher'] PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher']
......
...@@ -56,6 +56,16 @@ LOGGING['handlers']['console'] = {'level': level, ...@@ -56,6 +56,16 @@ LOGGING['handlers']['console'] = {'level': level,
'formatter': 'simple'} 'formatter': 'simple'}
for i in LOCAL_APPS: for i in LOCAL_APPS:
LOGGING['loggers'][i] = {'handlers': ['console'], 'level': level} LOGGING['loggers'][i] = {'handlers': ['console'], 'level': level}
# don't print SQL queries
LOGGING['handlers']['null'] = {'level': "DEBUG",
'class': "django.utils.log.NullHandler"}
LOGGING['loggers']['django.db.backends'] = {
'handlers': ['null'],
'propagate': False,
'level': 'DEBUG',
}
# Forbid store usage # Forbid store usage
STORE_URL = "" STORE_URL = ""
......
...@@ -38,6 +38,7 @@ urlpatterns = patterns( ...@@ -38,6 +38,7 @@ urlpatterns = patterns(
url(r'^network/', include('network.urls')), url(r'^network/', include('network.urls')),
url(r'^blacklist-add/', add_blacklist_item), url(r'^blacklist-add/', add_blacklist_item),
url(r'^dashboard/', include('dashboard.urls')), url(r'^dashboard/', include('dashboard.urls')),
url(r'^request/', include('request.urls')),
# django/contrib/auth/urls.py (care when new version) # django/contrib/auth/urls.py (care when new version)
url((r'^accounts/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/' url((r'^accounts/reset/(?P<uidb64>[0-9A-Za-z_\-]+)/'
...@@ -87,3 +88,4 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE': ...@@ -87,3 +88,4 @@ if get_env_variable('DJANGO_SAML', 'FALSE') == 'TRUE':
) )
handler500 = 'common.views.handler500' handler500 = 'common.views.handler500'
handler403 = 'common.views.handler403'
# -*- coding: utf-8 -*-
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
import re
from djangosaml2.backends import Saml2Backend as Saml2BackendBase
class Saml2Backend(Saml2BackendBase):
u"""
>>> b = Saml2Backend()
>>> b.clean_user_main_attribute(u'Ékezetes Enikő')
u'+00c9kezetes+0020Enik+0151'
>>> b.clean_user_main_attribute(u'Cé++')
u'C+00e9+002b+002b'
>>> b.clean_user_main_attribute(u'test')
u'test'
>>> b.clean_user_main_attribute(u'3+4')
u'3+002b4'
"""
def clean_user_main_attribute(self, main_attribute):
def replace(match):
match = match.group()
return '+%04x' % ord(match)
if isinstance(main_attribute, str):
main_attribute = main_attribute.decode('UTF-8')
assert isinstance(main_attribute, unicode)
return re.sub(r'[^\w.@-]', replace, main_attribute)
def _set_attribute(self, obj, attr, value):
if attr == 'username':
value = self.clean_user_main_attribute(value)
return super(Saml2Backend, self)._set_attribute(obj, attr, value)
...@@ -76,7 +76,7 @@ class Operation(object): ...@@ -76,7 +76,7 @@ class Operation(object):
user = auxargs.pop('user') user = auxargs.pop('user')
parent_activity = auxargs.pop('parent_activity') parent_activity = auxargs.pop('parent_activity')
if parent_activity and user is None and not skip_auth_check: if parent_activity and user is None and not skip_auth_check:
user = parent_activity.user user = allargs['user'] = parent_activity.user
if user is None: # parent was a system call if user is None: # parent was a system call
skip_auth_check = True skip_auth_check = True
...@@ -170,8 +170,8 @@ class Operation(object): ...@@ -170,8 +170,8 @@ class Operation(object):
raise ImproperlyConfigured( raise ImproperlyConfigured(
"Set required_perms to () if none needed.") "Set required_perms to () if none needed.")
if not user.has_perms(cls.required_perms): if not user.has_perms(cls.required_perms):
raise PermissionDenied("%s doesn't have the required permissions." raise PermissionDenied(
% user) u"%s doesn't have the required permissions." % user)
if cls.superuser_required and not user.is_superuser: if cls.superuser_required and not user.is_superuser:
raise humanize_exception(ugettext_noop( raise humanize_exception(ugettext_noop(
"Superuser privileges are required."), PermissionDenied()) "Superuser privileges are required."), PermissionDenied())
......
...@@ -19,32 +19,42 @@ from sys import exc_info ...@@ -19,32 +19,42 @@ from sys import exc_info
import logging import logging
from django.template import RequestContext
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.template import RequestContext
from .models import HumanReadableException from .models import HumanReadableException
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def handler500(request): def get_context(request, exception):
cls, exception, traceback = exc_info()
logger.exception("unhandled exception")
ctx = {} ctx = {}
if isinstance(exception, HumanReadableException): if issubclass(exception.__class__, HumanReadableException):
try: try:
ctx['error'] = exception.get_user_text() if request.user.is_superuser:
ctx['error'] = exception.get_admin_text()
else:
ctx['error'] = exception.get_user_text()
except: except:
pass pass
else: return ctx
try:
if request.user.is_superuser():
ctx['error'] = exception.get_admin_text() def handler500(request):
except: cls, exception, traceback = exc_info()
pass logger.exception("unhandled exception")
ctx = get_context(request, exception)
try: try:
resp = render_to_response("500.html", ctx, RequestContext(request)) resp = render_to_response("500.html", ctx, RequestContext(request))
except: except:
resp = render_to_response("500.html", ctx) resp = render_to_response("500.html", ctx)
resp.status_code = 500 resp.status_code = 500
return resp return resp
def handler403(request):
cls, exception, traceback = exc_info()
ctx = get_context(request, exception)
resp = render_to_response("403.html", ctx)
resp.status_code = 403
return resp
...@@ -21,7 +21,7 @@ from django import contrib ...@@ -21,7 +21,7 @@ from django import contrib
from django.contrib.auth.admin import UserAdmin, GroupAdmin from django.contrib.auth.admin import UserAdmin, GroupAdmin
from django.contrib.auth.models import User, Group from django.contrib.auth.models import User, Group
from dashboard.models import Profile, GroupProfile, ConnectCommand from dashboard.models import Profile, GroupProfile, ConnectCommand, Message
class ProfileInline(contrib.admin.TabularInline): class ProfileInline(contrib.admin.TabularInline):
...@@ -43,3 +43,5 @@ contrib.admin.site.unregister(User) ...@@ -43,3 +43,5 @@ contrib.admin.site.unregister(User)
contrib.admin.site.register(User, UserAdmin) contrib.admin.site.register(User, UserAdmin)
contrib.admin.site.unregister(Group) contrib.admin.site.unregister(Group)
contrib.admin.site.register(Group, GroupAdmin) contrib.admin.site.register(Group, GroupAdmin)
contrib.admin.site.register(Message)
# Copyright 2014 Budapest University of Technology and Economics (BME IK)
#
# This file is part of CIRCLE Cloud.
#
# CIRCLE is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# CIRCLE is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from pipeline.compilers.less import LessCompiler
class DummyLessCompiler(LessCompiler):
def compile_file(self, *args, **kwargs):
pass
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
from django.conf import settings from django.conf import settings
from .models import Message
def notifications(request): def notifications(request):
count = (request.user.notification_set.filter(status="new").count() count = (request.user.notification_set.filter(status="new").count()
...@@ -31,3 +33,7 @@ def extract_settings(request): ...@@ -31,3 +33,7 @@ def extract_settings(request):
'COMPANY_NAME': getattr(settings, "COMPANY_NAME", None), 'COMPANY_NAME': getattr(settings, "COMPANY_NAME", None),
'ADMIN_ENABLED': getattr(settings, "ADMIN_ENABLED", False), 'ADMIN_ENABLED': getattr(settings, "ADMIN_ENABLED", False),
} }
def broadcast_messages(request):
return {'broadcast_messages': Message.timeframed.filter(enabled=True)}
...@@ -1395,6 +1395,7 @@ ...@@ -1395,6 +1395,7 @@
"vnc_port": 1234, "vnc_port": 1234,
"num_cores": 2, "num_cores": 2,
"status": "RUNNING", "status": "RUNNING",
"system": "system pls",
"modified": "2013-10-14T07:27:38.192Z" "modified": "2013-10-14T07:27:38.192Z"
} }
}, },
......
...@@ -57,7 +57,7 @@ from vm.models import ( ...@@ -57,7 +57,7 @@ from vm.models import (
from storage.models import DataStore, Disk from storage.models import DataStore, Disk
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from .models import Profile, GroupProfile from .models import Profile, GroupProfile, Message
from circle.settings.base import LANGUAGES, MAX_NODE_RAM from circle.settings.base import LANGUAGES, MAX_NODE_RAM
from django.utils.translation import string_concat from django.utils.translation import string_concat
...@@ -739,6 +739,7 @@ class LeaseForm(forms.ModelForm): ...@@ -739,6 +739,7 @@ class LeaseForm(forms.ModelForm):
class Meta: class Meta:
model = Lease model = Lease
exclude = ()
class VmRenewForm(OperationForm): class VmRenewForm(OperationForm):
...@@ -1604,6 +1605,7 @@ class DataStoreForm(ModelForm): ...@@ -1604,6 +1605,7 @@ class DataStoreForm(ModelForm):
class Meta: class Meta:
model = DataStore model = DataStore
fields = ("name", "path", "hostname", )
class DiskForm(ModelForm): class DiskForm(ModelForm):
...@@ -1620,3 +1622,17 @@ class DiskForm(ModelForm): ...@@ -1620,3 +1622,17 @@ class DiskForm(ModelForm):
class Meta: class Meta:
model = Disk model = Disk
fields = ("name", "filename", "datastore", "type", "bus", "size",
"base", "dev_num", "destroyed", "is_ready", )
class MessageForm(ModelForm):
class Meta:
model = Message
fields = ("message", "enabled", "effect", "start", "end")
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("submit", _("Save")))
return helper
...@@ -17,27 +17,29 @@ ...@@ -17,27 +17,29 @@
from __future__ import unicode_literals, absolute_import from __future__ import unicode_literals, absolute_import
import logging
from optparse import make_option from optparse import make_option
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from firewall.models import (Vlan, VlanGroup, Domain, Firewall, Rule, from firewall.models import Vlan, VlanGroup, Domain, Firewall, Rule
SwitchPort, EthernetDevice, Host)
from storage.models import DataStore from storage.models import DataStore
from vm.models import Lease from vm.models import Lease
logger = logging.getLogger(__name__)
class Command(BaseCommand): class Command(BaseCommand):
option_list = BaseCommand.option_list + ( option_list = BaseCommand.option_list + (
make_option('--force', action="store_true"), make_option('--force', action="store_true"),
make_option('--portal-ip'),
make_option('--external-net'), make_option('--external-net'),
make_option('--management-net'), make_option('--management-net'),
make_option('--vm-net'), make_option('--vm-net'),
make_option('--external-if'), make_option('--external-if'),
make_option('--management-if'), make_option('--management-if'),
make_option('--trunk-if'), make_option('--vm-if'),
make_option('--datastore-queue'), make_option('--datastore-queue'),
make_option('--firewall-queue'), make_option('--firewall-queue'),
make_option('--admin-user'), make_option('--admin-user'),
...@@ -49,18 +51,18 @@ class Command(BaseCommand): ...@@ -49,18 +51,18 @@ class Command(BaseCommand):
qs = model.objects.filter(**{field: value})[:1] qs = model.objects.filter(**{field: value})[:1]
if not qs.exists(): if not qs.exists():
obj = model.objects.create(**kwargs) obj = model.objects.create(**kwargs)
self.changed.append('New %s: %s' % (model, obj)) logger.info('New %s: %s', model, obj)
self.changed = True
return obj return obj
else: else:
return qs[0] return qs[0]
# http://docs.saltstack.com/en/latest/ref/states/all/salt.states.cmd.html # http://docs.saltstack.com/en/latest/ref/states/all/salt.states.cmd.html
def print_state(self): def print_state(self):
changed = "yes" if len(self.changed) else "no" print "\nchanged=%s" % ("yes" if self.changed else "no")
print "\nchanged=%s comment='%s'" % (changed, ", ".join(self.changed))
def handle(self, *args, **options): def handle(self, *args, **options):
self.changed = [] self.changed = False
if (DataStore.objects.exists() and Vlan.objects.exists() if (DataStore.objects.exists() and Vlan.objects.exists()
and not options['force']): and not options['force']):
...@@ -87,20 +89,28 @@ class Command(BaseCommand): ...@@ -87,20 +89,28 @@ class Command(BaseCommand):
suspend_interval_seconds=3600 * 24 * 365, suspend_interval_seconds=3600 * 24 * 365,
delete_interval_seconds=3600 * 24 * 365 * 3) delete_interval_seconds=3600 * 24 * 365 * 3)
domain = self.create(Domain, 'name', name='example.com', owner=admin) net_domain = self.create(Domain, 'name', name='net.example.com',
owner=admin)
man_domain = self.create(Domain, 'name', name='man.example.com',
owner=admin)
vm_domain = self.create(Domain, 'name', name='vm.example.com',
owner=admin)
# vlans # vlans
net = self.create(Vlan, 'name', name='net', vid=4, net = self.create(Vlan, 'vid', name=options['external_if'], vid=4,
network4=options['external_net'], domain=domain) network4=options['external_net'], domain=net_domain)
man = self.create(Vlan, 'name', name='man', vid=3, dhcp_pool='manual', man = self.create(Vlan, 'vid', name=options['management_if'], vid=3,
network4=options['management_net'], domain=domain, dhcp_pool='manual',
network4=options['management_net'],
domain=man_domain,
snat_ip=options['external_net'].split('/')[0]) snat_ip=options['external_net'].split('/')[0])
man.snat_to.add(net) man.snat_to.add(net)
man.snat_to.add(man) man.snat_to.add(man)
vm = self.create(Vlan, 'name', name='vm', vid=2, dhcp_pool='manual', vm = self.create(Vlan, 'vid', name=options['vm_if'], vid=2,
network4=options['vm_net'], domain=domain, dhcp_pool='manual',
network4=options['vm_net'], domain=vm_domain,
snat_ip=options['external_net'].split('/')[0]) snat_ip=options['external_net'].split('/')[0])
vm.snat_to.add(net) vm.snat_to.add(net)
vm.snat_to.add(vm) vm.snat_to.add(vm)
...@@ -115,14 +125,6 @@ class Command(BaseCommand): ...@@ -115,14 +125,6 @@ class Command(BaseCommand):
vg_net = self.create(VlanGroup, 'name', name='net') vg_net = self.create(VlanGroup, 'name', name='net')
vg_net.vlans.add(net) vg_net.vlans.add(net)
# portal host
portal = self.create(Host, 'hostname', hostname='portal', vlan=man,
mac='11:22:33:44:55:66', owner=admin,
shared_ip=True, external_ipv4=man.snat_ip,
ipv4=options['portal_ip'])
portal.add_port(proto='tcp', public=443, private=443)
portal.add_port(proto='tcp', public=22, private=22)
# firewall rules # firewall rules
fw = self.create(Firewall, 'name', name=options['firewall_queue']) fw = self.create(Firewall, 'name', name=options['firewall_queue'])
...@@ -130,8 +132,16 @@ class Command(BaseCommand): ...@@ -130,8 +132,16 @@ class Command(BaseCommand):
direction='out', action='accept', direction='out', action='accept',
foreign_network=vg_all, firewall=fw) foreign_network=vg_all, firewall=fw)
self.create(Rule, 'description', description='default input rule', self.create(Rule, 'description', description='portal https',
direction='in', action='accept', direction='in', action='accept', proto='tcp', dport=443,
foreign_network=vg_all, firewall=fw)
self.create(Rule, 'description', description='portal http',
direction='in', action='accept', proto='tcp', dport=80,
foreign_network=vg_all, firewall=fw)
self.create(Rule, 'description', description='ssh',
direction='in', action='accept', proto='tcp', dport=22,
foreign_network=vg_all, firewall=fw) foreign_network=vg_all, firewall=fw)
# vlan rules # vlan rules
...@@ -143,23 +153,4 @@ class Command(BaseCommand): ...@@ -143,23 +153,4 @@ class Command(BaseCommand):
direction='out', action='accept', direction='out', action='accept',
foreign_network=vg_net, vlan=man) foreign_network=vg_net, vlan=man)
# switch
# uplink interface
sp_net = self.create(SwitchPort, 'untagged_vlan', untagged_vlan=net)
self.create(EthernetDevice, 'switch_port', switch_port=sp_net,
name=options['external_if'])
# management interface
if options['management_if']:
sp_man = self.create(
SwitchPort, 'untagged_vlan', untagged_vlan=man)
self.create(EthernetDevice, 'switch_port', switch_port=sp_man,
name=options['management_if'])
# vm interface
sp_trunk = self.create(
SwitchPort, 'tagged_vlans', untagged_vlan=man, tagged_vlans=vg_all)
self.create(EthernetDevice, 'switch_port', switch_port=sp_trunk,
name=options['trunk_if'])
return self.print_state() return self.print_state()
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.utils.timezone
import model_utils.fields
class Migration(migrations.Migration):
dependencies = [
('dashboard', '0002_auto_20150318_1317'),
]
operations = [
migrations.CreateModel(
name='Message',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, verbose_name='created', editable=False)),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, verbose_name='modified', editable=False)),
('start', models.DateTimeField(null=True, verbose_name='start', blank=True)),
('end', models.DateTimeField(null=True, verbose_name='end', blank=True)),
('message', models.CharField(max_length=500, verbose_name='message')),
('effect', models.CharField(default=b'info', max_length=10, verbose_name='effect', choices=[(b'success', 'success'), (b'info', 'info'), (b'warning', 'warning'), (b'danger', 'danger')])),
('enabled', models.BooleanField(default=False, verbose_name='enabled')),
],
options={
'ordering': ['id'],
'verbose_name': 'message',
'verbose_name_plural': 'messages',
},
bases=(models.Model,),
),
]
...@@ -27,7 +27,7 @@ from django.contrib.auth.signals import user_logged_in ...@@ -27,7 +27,7 @@ from django.contrib.auth.signals import user_logged_in
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import ( from django.db.models import (
Model, ForeignKey, OneToOneField, CharField, IntegerField, TextField, Model, ForeignKey, OneToOneField, CharField, IntegerField, TextField,
DateTimeField, permalink, BooleanField DateTimeField, BooleanField
) )
from django.db.models.signals import post_save, pre_delete, post_delete from django.db.models.signals import post_save, pre_delete, post_delete
from django.templatetags.static import static from django.templatetags.static import static
...@@ -39,14 +39,13 @@ from django.core.exceptions import ObjectDoesNotExist ...@@ -39,14 +39,13 @@ from django.core.exceptions import ObjectDoesNotExist
from sizefield.models import FileSizeField from sizefield.models import FileSizeField
from jsonfield import JSONField from jsonfield import JSONField
from model_utils.models import TimeStampedModel from model_utils.models import TimeFramedModel, TimeStampedModel
from model_utils.fields import StatusField from model_utils.fields import StatusField
from model_utils import Choices from model_utils import Choices
from acl.models import AclBase from acl.models import AclBase
from common.models import HumanReadableObject, create_readable, Encoder from common.models import HumanReadableObject, create_readable, Encoder
from vm.tasks.agent_tasks import add_keys, del_keys
from vm.models.instance import ACCESS_METHODS from vm.models.instance import ACCESS_METHODS
from .store_api import Store, NoStoreException, NotOkException, Timeout from .store_api import Store, NoStoreException, NotOkException, Timeout
...@@ -59,6 +58,27 @@ def pwgen(): ...@@ -59,6 +58,27 @@ def pwgen():
return User.objects.make_random_password() return User.objects.make_random_password()