class SliceSerializer(SliceCreateSerializer): # Hack to show explicit handled resource (Vlan) - #46-note87 # FIXME: can be removed when monkey-patch works in resources.serializers if is_installed('resources'): from resources.serializers import VlanResourceReqSerializer resources = VlanResourceReqSerializer(source='*', read_only=True, required=False) class Meta: model = Slice read_only_fields = ('group',)
def test_get_modeladmin(self): # Try to get every modeladmin from controller's models CONTROLLER_APPS = ['communitynetworks', 'firmware', 'gis', 'issues', 'maintenance', 'monitor', 'nodes', 'notifications', 'pings', 'resources', 'slices', 'state', 'tinc', 'users'] for app_name in CONTROLLER_APPS: if not is_installed(app_name): continue app = get_app(app_name) for model in get_models(app): get_modeladmin(model)
class SliverSerializer(serializers.UriHyperlinkedModelSerializer): id = serializers.Field(source='api_id') interfaces = SliverIfaceSerializer(required=False, many=True, allow_add_remove=True) properties = serializers.PropertyField() data_uri = FakeFileField(field='data', required=False) instance_sn = serializers.IntegerField(read_only=True) mgmt_net = serializers.Field() # FIXME remove when api.aggregate supports nested serializers # is only required because SliverDefaultsSerializer imports resources # serializers, and breaks api.aggregate functionality based on # api._registry (see class SliverDefaultsSerializer) if is_installed('resources'): from resources.serializers import ResourceReqSerializer resources = ResourceReqSerializer(many=True, required=False) class Meta: model = Sliver exclude = ('data',) def to_native(self, obj): """ hack for implementing dynamic file_uri's on FakeFile """ self.__object__ = obj return super(SliverSerializer, self).to_native(obj) def validate(self, attrs): """ workaround about nested serialization sliverifaces need to be validated with an associated sliver """ super(SliverSerializer, self).validate(attrs) ifaces = attrs.get('interfaces', []) or [] for iface in ifaces: Sliver.get_registered_ifaces()[iface.type].clean_model(iface) return attrs def validate_interfaces(self, attrs, source): """Check that one interface of type private has been defined.""" interfaces = attrs.get(source, []) # check that mandatory private interface has been defined priv_ifaces = 0 for iface in interfaces: if iface.type == 'private': priv_ifaces += 1 if priv_ifaces > 1: raise serializers.ValidationError('There can only be one interface of type private.') if priv_ifaces == 0: raise serializers.ValidationError('There must exist one interface of type private.') validate_private_iface(interfaces) for name, iface_cls in Sliver.get_registered_ifaces().items(): validate_ifaces_nr(name, iface_cls, interfaces) return attrs
def test_notify_operators(self): self.client.logout() self.assertFalse(is_installed('captcha')) name = "user" + str(int(round(time.time() * 1000))) password = "******" data = { "name": name, "username": name, "email": name + "@localhost", "password1": password, "password2": password, } response = self.client.post(reverse('registration_register'), data=data) self.assertRedirects(response, reverse('registration_complete')) # registration successful sends an email with confirmation URL self.assertEquals(len(mail.outbox), 1) URL_REGEX = 'http[s]?://\w+/accounts/activate/\w+' urls = re.findall(URL_REGEX, mail.outbox[0].body) self.assertEquals(len(urls), 1) mail.outbox = [] # Confirm user email response = self.client.get(urls[0], follow=True) self.assertRedirects(response, reverse('registration_activation_complete'), status_code=301) # One email to operators should be sent requesting approvation self.assertEquals(len(mail.outbox), 1) self.assertTrue(settings.MAIL_REGISTRATION_APPROVE, mail.outbox[0].to) # The email contains the user URL URL_REGEX = 'http[s]?://\w+/admin/users/user/\d+/' urls = re.findall(URL_REGEX, mail.outbox[0].body) self.assertEquals(len(urls), 1) mail.outbox = [] # Mark user as active user = User.objects.get(name=name) user.is_active = True user.save() # Two emails should be sent: one to user and another to operators self.assertEquals(len(mail.outbox), 2) self.assertTrue(user.email in mail.outbox[0].to) self.assertTrue(settings.MAIL_REGISTRATION_APPROVE, mail.outbox[1].to) # Registered user should be able to login self.client.login(username=name, password=password) response = self.client.get(reverse('admin:index')) self.assertEquals(response.status_code, 200)
class SliverDefaultsSerializer(serializers.ModelSerializer): instance_sn = serializers.IntegerField(read_only=True) data_uri = FakeFileField(field='data', required=False) template = serializers.RelHyperlinkedRelatedField(view_name='template-detail') # FIXME refactor move to resources app when api.aggregate supports nested serializers if is_installed('resources'): from resources.serializers import ResourceReqSerializer resources = ResourceReqSerializer(source='slice_resources', many=True, required=False) class Meta: model = SliverDefaults exclude = ('id', 'slice', 'data') def to_native(self, obj): """ hack for implementing dynamic file_uri's on FakeFile """ self.__object__ = obj return super(SliverDefaultsSerializer, self).to_native(obj)
def cache_cndb(self, *fields): """ fetches fields from cndb and stores it into the database """ cndb = self.fetch_cndb() for field in fields: node = self.content_object if field == 'gis': if not is_installed('gis'): raise ImproperlyConfigured( "'%s' field cannot be cached from CNDB (gis app is not installed)." % field) from gis.models import NodeGeolocation position = cndb.get('attributes').get('position') lat, lon = position.get('lat'), position.get('lon') # update the node info try: gis = node.gis # exist related object? except NodeGeolocation.DoesNotExist: gis = NodeGeolocation.objects.create(node=node) gis.geolocation = "%s,%s" % (lat, lon) gis.save() else: raise NotImplementedError( "'%s' field cannot be cached from CNDB." % field) # TODO How to get other info from CNDB API? # can be generic? (proposal) # value = cndb.get(CNDB_FIELD_MAP[field]) # setattr(node, field, value) # node.save() # # another generalization proposal: # CNDB_FIELD_MAP = { # 'arch': lambda j: j.get('machine').get('architecture'), # 'sliver_pub_ipv4': lambda j: j.get('sliver_pub_ipv4'), # 'sliver_pub_ipv4_range': lambda j: '#%d' % len(j.get('ips')) # } # value = CNDB_FIELD_MAP[field](cndb) # update last cached time # use timezone aware datetime self.cndb_cached_on = now() self.save()
def cache_cndb(self, *fields): """ fetches fields from cndb and stores it into the database """ cndb = self.fetch_cndb() for field in fields: node = self.content_object if field == 'gis': if not is_installed('gis'): raise ImproperlyConfigured("'%s' field cannot be cached from CNDB (gis app is not installed)." % field) from gis.models import NodeGeolocation position = cndb.get('attributes').get('position') lat, lon = position.get('lat'), position.get('lon') # update the node info try: gis = node.gis # exist related object? except NodeGeolocation.DoesNotExist: gis = NodeGeolocation.objects.create(node=node) gis.geolocation = "%s,%s" % (lat, lon) gis.save() else: raise NotImplementedError("'%s' field cannot be cached from CNDB." % field) # TODO How to get other info from CNDB API? # can be generic? (proposal) # value = cndb.get(CNDB_FIELD_MAP[field]) # setattr(node, field, value) # node.save() # # another generalization proposal: # CNDB_FIELD_MAP = { # 'arch': lambda j: j.get('machine').get('architecture'), # 'sliver_pub_ipv4': lambda j: j.get('sliver_pub_ipv4'), # 'sliver_pub_ipv4_range': lambda j: '#%d' % len(j.get('ips')) # } # value = CNDB_FIELD_MAP[field](cndb) # update last cached time # use timezone aware datetime self.cndb_cached_on = now() self.save()
def wrapper(request, obj): if request.user.is_anonymous() and "HTTP_AUTHORIZATION" in request.META: auth = request.META["HTTP_AUTHORIZATION"].split() if len(auth) == 2: method, digest = auth if method == "Basic": uname, passwd = base64.b64decode(digest).split(":") user = authenticate(username=uname, password=passwd) if user is not None: if user.is_active: login(request, user) request.user = user elif method == "Token" and is_installed("rest_framework"): from rest_framework.authentication import TokenAuthentication from rest_framework.exceptions import AuthenticationFailed try: user = TokenAuthentication().authenticate_credentials(digest)[0] except AuthenticationFailed: pass else: request.user = user return condition(request, obj)
def notify_user_enabled(sender, instance, *args, **kwargs): """ Notify by email user and operators when an account is enabled on RESTRICTED mode. """ if kwargs.get('raw', False): return # avoid conflicts when loading fixtures if settings.USERS_REGISTRATION_MODE != 'RESTRICTED': return if not is_installed('registration'): return # Only notify if user has been created via registration reg_profile = instance.registrationprofile_set.first() if reg_profile and instance.pk and instance.is_active: old = User.objects.get(pk=instance.pk) if not old.is_active: send_email_template('registration/account_approved.email', {}, instance.email) send_email_template('registration/account_approved_operators.email', {'user': instance}, settings.EMAIL_REGISTRATION_APPROVE) # remove registration profile to avoid duplicate mails reg_profile.delete()
def wrapper(request, obj): if request.user.is_anonymous( ) and 'HTTP_AUTHORIZATION' in request.META: auth = request.META['HTTP_AUTHORIZATION'].split() if len(auth) == 2: method, digest = auth if method == "Basic": uname, passwd = base64.b64decode(digest).split(':') user = authenticate(username=uname, password=passwd) if user is not None: if user.is_active: login(request, user) request.user = user elif method == "Token" and is_installed('rest_framework'): from rest_framework.authentication import TokenAuthentication from rest_framework.exceptions import AuthenticationFailed try: user = TokenAuthentication().authenticate_credentials( digest)[0] except AuthenticationFailed: pass else: request.user = user return condition(request, obj)
from django.conf.urls import patterns, url from django.views.generic.base import TemplateView from controller.utils.apps import is_installed from registration.backends.default.urls import urlpatterns as registration_urlpatterns from . import BackendFactory if is_installed('captcha'): from .forms import RegistrationCaptchaForm as RegistrationForm else: from .forms import RegistrationFormUniqueEmail as RegistrationForm backend = BackendFactory.create() ActivationView = backend.get_activation_view() RegistrationView = backend.get_registration_view() urlpatterns = patterns('', url(r'^activate/complete/$', TemplateView.as_view(template_name='registration/activation_complete.html'), name='registration_activation_complete'), url(r'^activate/(?P<activation_key>\w+)/$', ActivationView.as_view(), name='registration_activate'), url(r'^register/$', RegistrationView.as_view(form_class=RegistrationForm), name='registration_register'), ) + registration_urlpatterns
pings = pings.filter(date__gt=ini) if pings: for __, ping_set in group_by_interval(pings, delta): aggregated, set_size = aggregate(ping_set) result['aggregated'] += aggregated result['total'] += set_size result['created'] += 1 if aggregated else 0 ini = end return "(%(aggregated)s -> %(created)s) / %(total)s" % result for instance in PING_INSTANCES: # get instance settings based on defaults settings = Ping.get_instance_settings(instance.get('model')) # Create periodic tasks hour = 2 if is_installed(instance.get('app')) and settings.get('schedule') > 0: name = "pings.%s_ping" % instance.get('app') run_every = settings.get('schedule') @periodic_task(name=name, run_every=run_every, expires=run_every) def ping_instance(model=instance.get('model')): return ping(model) name = "pings.%s_downsample" % instance.get('app') @periodic_task(name=name, run_every=crontab(minute=0, hour=hour), time_limit=60*60*2) def downsample_pings(model=instance.get('model')): return downsample(model) hour += 1
def app_is_installed(app_name): return is_installed(app_name)
for __, ping_set in group_by_interval(pings, delta): aggregated, set_size = aggregate(ping_set) result['aggregated'] += aggregated result['total'] += set_size result['created'] += 1 if aggregated else 0 ini = end return "(%(aggregated)s -> %(created)s) / %(total)s" % result for instance in PING_INSTANCES: # get instance settings based on defaults settings = Ping.get_instance_settings(instance.get('model')) # Create periodic tasks hour = 2 if is_installed(instance.get('app')) and settings.get('schedule') > 0: name = "pings.%s_ping" % instance.get('app') run_every = settings.get('schedule') @periodic_task(name=name, run_every=run_every, expires=run_every) def ping_instance(model=instance.get('model')): return ping(model) name = "pings.%s_downsample" % instance.get('app') @periodic_task(name=name, run_every=crontab(minute=0, hour=hour), time_limit=60 * 60 * 2) def downsample_pings(model=instance.get('model')): return downsample(model)
self.fields[field_name].required = False self.fields[field_name].widget = forms.widgets.Select(choices=choices) for field_name in field_names: def clean_field(self, field_name=field_name): value = self.cleaned_data.get(field_name) return value if value != "empty" else "" attributes["clean_" + field_name] = clean_field attributes["__init__"] = __init__ return type("VCTLocalFileForm", (base_class,), attributes) if is_installed("firmware"): from firmware.admin import BaseImageInline from firmware.models import BaseImage from firmware.settings import FIRMWARE_BASE_IMAGE_EXTENSIONS if settings.VCT_LOCAL_FILES: BaseImageInline.form = local_files_form_factory(BaseImage, "image", extensions=FIRMWARE_BASE_IMAGE_EXTENSIONS) # Replace node firmware download for "VM manager" if settings.VCT_VM_MANAGEMENT: insert_change_view_action(Node, vm_management) insertattr(Node, "actions", vm_management) node_modeladmin = get_modeladmin(Node) old_get_change_view_actions_as_class = node_modeladmin.get_change_view_actions_as_class def get_change_view_actions_as_class(self):
roles_qs = Roles.objects.filter(user=uid, group=gid) self.assertTrue(roles_qs.exists()) self.assertTrue(roles_qs.get().is_slice_admin) def test_join_request_reject(self): uid = 3 gid = 1 self._do_action_join_request('reject') def test_join_request_ignore(self): uid = 3 gid = 1 self._do_action_join_request('ignore') @unittest.skipUnless(is_installed('registration'), "django-registration is required") class RegistrationTestCase(AuthenticatedTestCase): @unittest.skipIf( is_installed('captcha'), "remove 'captcha' from INSTALLED_APPS for properly run this test.") @override_settings(USERS_REGISTRATION_MODE='RESTRICTED', MAIL_REGISTRATION_APPROVE='vct@localhost') # Removing captcha doesn't seems to work #INSTALLED_APPS = remove_app(settings.INSTALLED_APPS, 'captcha')) def test_notify_operators(self): self.client.logout() self.assertFalse(is_installed('captcha')) name = "user" + str(int(round(time.time() * 1000))) password = "******" data = {
from django.conf.urls import patterns, url from django.views.generic.base import TemplateView from controller.utils.apps import is_installed from registration.backends.default.urls import urlpatterns as registration_urlpatterns from . import BackendFactory if is_installed('captcha'): from .forms import RegistrationCaptchaForm as RegistrationForm else: from .forms import RegistrationFormUniqueEmail as RegistrationForm backend = BackendFactory.create() ActivationView = backend.get_activation_view() RegistrationView = backend.get_registration_view() urlpatterns = patterns( '', url(r'^activate/complete/$', TemplateView.as_view( template_name='registration/activation_complete.html'), name='registration_activation_complete'), url(r'^activate/(?P<activation_key>\w+)/$', ActivationView.as_view(), name='registration_activate'), url(r'^register/$', RegistrationView.as_view(form_class=RegistrationForm), name='registration_register'), ) + registration_urlpatterns
return run_instance.AsyncResult(self.task_id) def revoke(self): self.state = self.REVOKED self.save() def kill(self): with current_app.default_connection() as connection: revoke(self.task_id, connection=connection, terminate=True, signal='KILL') @property def script(self): return self.execution.script @receiver(node_heartbeat, sender=State, dispatch_uid="maintenance.retry_pending_operations") def retry_pending_operations(sender, node, **kwargs): """ runs timeout instances when a node heart beat is received """ instances = Instance.objects.filter(node=node, state=Instance.TIMEOUT, execution__is_active=True, execution__retry_if_offline=True) for instance in instances: instance.run() if is_installed('firmware'): from firmware.models import construct_safe_locals @receiver(construct_safe_locals, dispatch_uid="maintenance.update_safe_locals") def update_safe_locals(sender, safe_locals, **kwargs): safe_locals.update(dict((setting, getattr(settings, setting)) for setting in dir(settings) if setting.isupper() ))
url(r'^admin/password_reset/(?P<uidb64>[-\w]+)/(?P<token>[-\w]+)/$', 'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm' ), url(r'^admin/password_reset/complete/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete' ), # Admin url(r'^admin/', include(admin.site.urls)), url(r'^admin_tools/', include('admin_tools.urls')), url(r'^private/', include('privatefiles.urls')), ) if is_installed('registration'): urlpatterns += patterns('', url(r'^accounts/', include('users.registration.urls')),) if is_installed('captcha'): urlpatterns += patterns('', url(r'^captcha/', include('captcha.urls')), ) if is_installed('api'): from api import api api.autodiscover() urlpatterns += patterns('', url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token', name='api-token-auth'),
url(r'^admin/password_reset/done/$', 'django.contrib.auth.views.password_reset_done', name='password_reset_done'), url(r'^admin/password_reset/(?P<uidb64>[-\w]+)/(?P<token>[-\w]+)/$', 'django.contrib.auth.views.password_reset_confirm', name='password_reset_confirm'), url(r'^admin/password_reset/complete/$', 'django.contrib.auth.views.password_reset_complete', name='password_reset_complete'), # Admin url(r'^admin/', include(admin.site.urls)), url(r'^admin_tools/', include('admin_tools.urls')), url(r'^private/', include('privatefiles.urls')), ) if is_installed('registration'): urlpatterns += patterns( '', url(r'^accounts/', include('users.registration.urls')), ) if is_installed('captcha'): urlpatterns += patterns( '', url(r'^captcha/', include('captcha.urls')), ) if is_installed('api'): from api import api api.autodiscover()
def handle(self, *args, **options): # Warn about deprecated options if options.get('local'): self.stderr.write( "Warning: 'local' option is deprecated and will be ignored.\n") version = options.get('version') upgrade_notes = [] if version: try: major, major2, minor = decode_version(version) except ValueError as e: raise CommandError(e) # Represent version as two digits per number: 1.2.2 -> 10202 version = int( str(major) + "%02d" % int(major2) + "%02d" % int(minor)) # Pre-upgrade operations (version specific) if version < 835: # prevent schema migrations from failing if is_installed('firmware'): from firmware.models import Build Build.objects.filter(base_image=None).update(base_image='') if version <= 902: if is_installed('maintenance'): # Apply losed migrations from south.models import MigrationHistory migrated = MigrationHistory.objects.filter( app_name='maintenance').exists() if not migrated: run('python manage.py migrate maintenance 0001 --fake') if version < 1002: # Update monitor settings (fix typo and add DiskFreeMonitor) context = { 'settings': run("find . -type f -name 'settings.py'|grep -v 'vct/'") } # Try automaticate update (making a backup) if context['settings']: run("cp %(settings)s %(settings)s.upgrade.bak" % context) # fix NumProcessesMonitor typo run("sed -i 's/NumPocessesMonitor/NumProcessesMonitor/g' " "%(settings)s" % context) # append disk monitor (if needed) # this is a rude check (but runned in a conservative way) if 'DiskFreeMonitor' not in open( context['settings']).read(): run("sed -i '/MONITOR_MONITORS = ($/ a\ " " (\"monitor.monitors.DiskFreeMonitor\",),' " "%(settings)s" % context) # warn the user about settings changes autoupdate_status = 'OK' if context['settings'] else 'FAIL' upgrade_notes.append( 'The monitor application has changed and .' 'some settings updates are required:\n' ' - Fix typo on NumProcessesMonitor (missing "r")\n' ' - Enable disk monitor\n' ' Please read the monitor app doc (MONITOR_MONITORS setting)\n' 'AUTOUPDATE: %s' % autoupdate_status) if version <= 1102: # Handle InconsistentMigrationHistory on tinc app # * v0.11.2 tinc includes 0022, 0028..0030 # * v0.11.3 tinc adds 0023..0027 # We can force south to merge migrations because # are implemented to be runned without dependencies run('python manage.py migrate tinc 0030 --merge --noinput') if not options.get('specifics_only'): # Common stuff development = options.get('development') controller_admin = os.path.join(os.path.dirname(__file__), '../../bin/') controller_admin = os.path.join(controller_admin, 'controller-admin.sh') run('chmod +x %s' % controller_admin) extra = '--development' if development else '' if options.get('proxy'): extra += ' --proxy %s' % options.get('proxy') run("%s install_requirements " % controller_admin + extra) run("python manage.py collectstatic --noinput") run("python manage.py syncdb --noinput") run("python manage.py migrate --noinput") if is_installed('firmware'): run("python manage.py syncfirmwareplugins") if is_installed('notifications'): run("python manage.py syncnotifications") if is_installed('resources'): run("python manage.py syncresources") if options.get('restart'): run("python manage.py restartservices") if not version: self.stderr.write( '\nNext time you migth want to provide a --from argument ' 'in order to run version specific upgrade operations\n') return # Post-upgrade operations (version specific) if version <= 629: # Clean existing sessions because of change on auth backend run('echo "delete from django_session;" | python manage.py dbshell' ) if version < 801: deprecate_periodic_tasks(('state.ping', )) if version < 809: # Add PKI directories from pki import ca from controller.utils.paths import get_site_root site_root = get_site_root() username = run("stat -c %%U %s" % site_root) get_dir = lambda f: os.path.dirname(getattr(ca, f + '_path')) for d in set(get_dir(f) for f in ['priv_key', 'pub_key', 'cert']): run('mkdir -p %s' % d) run('chown %s %s' % (username, d)) upgrade_notes.append( 'HTTPS certificate support for the management ' 'network has been introduced in version 0.8.9.\n' 'In order to use it you sould run:\n' ' > python manage.py setuppki\n' ' > sudo python manage.py setupapache\n') if version < 838: # Purge communitynetworks.periodic_cache_node_db from djcelery.models import PeriodicTask PeriodicTask.objects.filter( name='communitynetworks.periodic_cache_node_db').delete() run('rabbitmqctl stop_app') run('rabbitmqctl reset') run('rabbitmqctl start_app') run('service celeryd restart') upgrade_notes.append( 'New Celeryd init.d configuration has been ' 'introduced in 0.8.38.\nIt is strongly recommended to upgrade by\n' ' > sudo python manage.py setupceleryd\n') # Deprecate x86 and amd64 architectures from nodes.models import Node Node.objects.filter(arch='x86').update(arch='i686') Node.objects.filter(arch='amd64').update(arch='x86_64') upgrade_notes.append( 'In order to support Base authentication while downloading ' 'firmwares you should add "WSGIPassAuthorization On" on your apache config.\n' 'Alternatively you can perform this operation with the following command\n' ' > sudo python manage.py setupapache\n' ' > /etc/init.d/apache2 reload\n') if version < 900: upgrade_notes.append( 'Apache configuration is now placed under ' '/etc/apache2/conf.d/<project_name>.conf. It is convenient for you ' 'to migrate your current configuration located on /etc/apache2/httpd.conf ' 'to this new location.\n') upgrade_notes.append( 'Celery workers configuration has been updated. ' 'Please update it by running:\n' ' > sudo python manage.py setupceleryd\n') if version < 905: # TODO find the root cause of this # maybe is shit imported on settings that import settings like add_app # Prevent crazy import erros to appear :S from django.utils import translation translation.activate('en-us') # Change template types for more generic ones from slices.models import Template from slices.settings import SLICES_TEMPLATE_TYPES template_types = [t[0] for t in SLICES_TEMPLATE_TYPES] if 'debian' in template_types: Template.objects.filter(type='debian6').update(type='debian') if 'openwrt' in template_types: Template.objects.filter(type='openwrt-backfire').update( type='openwrt') if version < 906: deprecate_periodic_tasks(('state.nodestate', 'state.sliverstate')) if version <= 907: # Generate sha256 from slices.models import Template for template in Template.objects.all(): template.save() upgrade_notes.append( "It is extremly recommended to update your database " "settings to enable atomic request behaviour:\n" " https://docs.djangoproject.com/en/dev/topics/db/transactions/#tying-transactions-to-http-requests\n" "Just add:\n" " 'ATOMIC_REQUESTS': True,\n" "into DATABASES setting within <project_name>/<project_name>/settings.py" ) if version <= 1003: # Update firmware configuration after Island refactor (#264) from firmware.models import ConfigFile try: cfg_file = ConfigFile.objects.get( path__contains="node.tinc.connect_to") except (ConfigFile.DoesNotExist, ConfigFile.MultipleObjectsReturned): # Warn the user that needs to perform manual update msg = "Firmware configuration update has failed. " else: cfg_file.content = cfg_file.content.replace( "node.tinc.island", "node.island") cfg_file.save() msg = "Firmware configuration updated successfully. Updated ConfigFile ID: %i." % cfg_file.pk upgrade_notes.append( "%s\nPlease check version 0.10.4 release notes:\n" "https://wiki.confine-project.eu/soft:server-release-notes#section0104" % msg) if version < 1103: # Update mgmt network Server APIs certificate # perform raw SQL querie because models hasn't been # reloaded yet and cannot access e.g. server.api from django.db import connection from nodes.models import Server from pki import ca server_id = Server.objects.order_by('id').first().pk try: cert = ca.get_cert().as_pem() except IOError: msg = ("Failed to update Server APIs certificate. Missing " "server certificate '%s'.\n" "Run 'python manage.py setuppki --help'" % ca.cert_path) upgrade_notes.append(msg) else: update_sql = ('UPDATE "nodes_serverapi" SET cert = %s ' 'WHERE "nodes_serverapi"."server_id" = %s') cursor = connection.cursor() cursor.execute(update_sql, [cert, server_id]) del cursor upgrade_notes.append("Updated Server APIs certificate.") if upgrade_notes and options.get('print_upgrade_notes'): self.stdout.write('\n\033[1m\n' ' ===================\n' ' ** UPGRADE NOTES **\n' ' ===================\n\n' + '\n'.join(upgrade_notes) + '\033[m\n')
def init_with_context(self, context): user = context['user'] self.children += [ items.MenuItem('Dashboard', reverse('admin:index')), items.Bookmarks(), ] if is_installed('nodes') and user.has_module_perms('nodes'): node_items = [ items.MenuItem('Nodes', reverse('admin:nodes_node_changelist')), items.MenuItem('Servers', reverse('admin:nodes_server_changelist')), items.MenuItem('Islands', reverse('admin:nodes_island_changelist')), ] if is_installed('state'): node_items.append( items.MenuItem('Summary', reverse('admin:state_report'))) if is_installed('gis'): node_items.insert( 1, items.MenuItem('Nodes Map', reverse('gis_map'))) self.children.append( items.MenuItem('Nodes', reverse('admin:nodes_node_changelist'), children=node_items)) if is_installed('slices') and user.has_module_perms('slices'): slice_children = sliver_children = None if is_installed('state'): slice_children = [ items.MenuItem('Status Overview', reverse('admin:state_slices')), ] sliver_children = [ items.MenuItem('Status Overview', reverse('admin:state_slivers')), ] self.children.append( items.MenuItem( 'Slices', reverse('admin:slices_slice_changelist'), children=[ items.MenuItem( 'Slices', reverse('admin:slices_slice_changelist'), children=slice_children), items.MenuItem( 'Slivers', reverse('admin:slices_sliver_changelist'), children=sliver_children), items.MenuItem( 'Templates', reverse('admin:slices_template_changelist')), ])) if is_installed('tinc'): if user.has_module_perms('tinc'): self.children.append( items.MenuItem( 'Tinc', reverse('admin:app_list', args=['tinc']), children=[ items.MenuItem( 'TincAddresses', reverse('admin:tinc_tincaddress_changelist')), items.MenuItem( 'Hosts', reverse('admin:tinc_host_changelist')), ])) if user.is_superuser: administration_models = () if is_installed('djcelery'): administration_models += ('djcelery.*', ) admin_item = items.AppList('Administration', models=administration_models) # Users menu item user_items = [ items.MenuItem('User', reverse('admin:users_user_changelist')), items.MenuItem('Group', reverse('admin:users_group_changelist')), items.MenuItem('Roles', reverse('admin:users_roles_changelist')), ] if is_installed('registration'): user_items.append( items.MenuItem( 'User Registration', reverse( 'admin:registration_registrationprofile_changelist' ))) admin_item.children.append( items.MenuItem('Users', reverse('admin:app_list', args=['users']), children=user_items)) if is_installed('maintenance'): maintenance_items = [ items.MenuItem( 'Operation', reverse('admin:maintenance_operation_changelist')), items.MenuItem( 'Instance', reverse('admin:maintenance_instance_changelist')) ] admin_item.children.append( items.MenuItem('Maintenance', reverse('admin:app_list', args=['maintenance']), children=maintenance_items)) if is_installed('issues'): issues_items = [ items.MenuItem('Tickets', reverse('admin:issues_ticket_changelist')), items.MenuItem('Queues', reverse('admin:issues_queue_changelist')) ] admin_item.children.append( items.MenuItem('Issues', reverse('admin:issues_ticket_changelist'), children=issues_items)) if is_installed('firmware'): firmware_items = [ items.MenuItem('Configuration', reverse('admin:firmware_config_change')), items.MenuItem('Builds', reverse('admin:firmware_build_changelist')) ] admin_item.children.append( items.MenuItem('Firmware', reverse('admin:app_list', args=['firmware']), children=firmware_items)) if is_installed('notifications'): admin_item.children.append( items.MenuItem( 'Notifications', reverse( 'admin:notifications_notification_changelist')), ) else: admin_items = [ items.MenuItem('Users', reverse('admin:users_user_changelist')), items.MenuItem('Groups', reverse('admin:users_group_changelist')), ] if is_installed('issues'): admin_items.append( items.MenuItem('Tickets', reverse('admin:issues_ticket_changelist'))) admin_item = items.MenuItem('Administration', children=admin_items) self.children.append(admin_item) if is_installed('api'): self.children.append(items.MenuItem('API', api_link(context))) self.children.append( items.MenuItem('Documentation', 'http://wiki.confine-project.eu/soft:server'))
class RegistrationTestCase(AuthenticatedTestCase): @unittest.skipIf( is_installed('captcha'), "remove 'captcha' from INSTALLED_APPS for properly run this test.") @override_settings(USERS_REGISTRATION_MODE='RESTRICTED', MAIL_REGISTRATION_APPROVE='vct@localhost') # Removing captcha doesn't seems to work #INSTALLED_APPS = remove_app(settings.INSTALLED_APPS, 'captcha')) def test_notify_operators(self): self.client.logout() self.assertFalse(is_installed('captcha')) name = "user" + str(int(round(time.time() * 1000))) password = "******" data = { "name": name, "username": name, "email": name + "@localhost", "password1": password, "password2": password, } response = self.client.post(reverse('registration_register'), data=data) self.assertRedirects(response, reverse('registration_complete')) # registration successful sends an email with confirmation URL self.assertEquals(len(mail.outbox), 1) URL_REGEX = 'http[s]?://\w+/accounts/activate/\w+' urls = re.findall(URL_REGEX, mail.outbox[0].body) self.assertEquals(len(urls), 1) mail.outbox = [] # Confirm user email response = self.client.get(urls[0], follow=True) self.assertRedirects(response, reverse('registration_activation_complete'), status_code=301) # One email to operators should be sent requesting approvation self.assertEquals(len(mail.outbox), 1) self.assertTrue(settings.MAIL_REGISTRATION_APPROVE, mail.outbox[0].to) # The email contains the user URL URL_REGEX = 'http[s]?://\w+/admin/users/user/\d+/' urls = re.findall(URL_REGEX, mail.outbox[0].body) self.assertEquals(len(urls), 1) mail.outbox = [] # Mark user as active user = User.objects.get(name=name) user.is_active = True user.save() # Two emails should be sent: one to user and another to operators self.assertEquals(len(mail.outbox), 2) self.assertTrue(user.email in mail.outbox[0].to) self.assertTrue(settings.MAIL_REGISTRATION_APPROVE, mail.outbox[1].to) # Registered user should be able to login self.client.login(username=name, password=password) response = self.client.get(reverse('admin:index')) self.assertEquals(response.status_code, 200) def test_registration_form(self): """Test registration form validation.""" # Create user to validate duplicated username, name, email User.objects.create(name='Frank', email='frank@localhost', username='******') # Define valid data for user registration data = { 'name': 'Name Lastname', 'username': '******', 'email': 'name.lastname@localhost', 'password1': 's3cr3t', 'password2': 's3cr3t', } # check form with valid data form = RegistrationForm(data=data) self.assertTrue(form.is_valid()) # check form with valid but uncommon e-mail address data_test = data.copy() data_test[ 'email'] = 'name.lastname+suffix@localhost' # a plus sign is valid! form = RegistrationForm(data=data_test) self.assertTrue(form.is_valid()) # doesn't validate with invalid username data_test = data.copy() data_test['username'] = '******' # spaces not accepted form = RegistrationForm(data=data_test) self.assertFalse(form.is_valid(), "Invalid username shouldn't validate.") # check invalid email validation data_test = data.copy() data_test['email'] = 'invalid-email' form = RegistrationForm(data=data_test) self.assertFalse(form.is_valid(), "Invalid email shouldn't validate.") # check duplicated username data_test = data.copy() data_test['username'] = '******' form = RegistrationForm(data=data_test) self.assertFalse(form.is_valid(), "Duplicated username shouldn't validate.") # check duplicated name data_test = data.copy() data_test['name'] = 'Frank' form = RegistrationForm(data=data_test) self.assertFalse(form.is_valid(), "Duplicated name shouldn't validate.") # check duplicated email data_test = data.copy() data_test['email'] = 'frank@localhost' form = RegistrationForm(data=data_test) self.assertFalse(form.is_valid(), "Duplicated email shouldn't validate.") # check not matching passwords data_test = data.copy() data_test['password2'] = 'pass-not-matchs!' form = RegistrationForm(data=data_test) self.assertFalse(form.is_valid(), "Different passwords shouldn't validate.") def test_registration_admin_search(self): """ Test registration profile admin search with custom user model (#518). """ self._login(superuser=True) url = reverse('admin:registration_registrationprofile_changelist') resp = self.client.get(url, {'q': 'foo'}) self.assertEquals(resp.status_code, 200)
roles_qs = Roles.objects.filter(user=uid, group=gid) self.assertTrue(roles_qs.exists()) self.assertTrue(roles_qs.get().is_slice_admin) def test_join_request_reject(self): uid = 3 gid = 1 self._do_action_join_request('reject') def test_join_request_ignore(self): uid = 3 gid = 1 self._do_action_join_request('ignore') @unittest.skipUnless(is_installed('registration'), "django-registration is required") class RegistrationTestCase(AuthenticatedTestCase): @unittest.skipIf(is_installed('captcha'), "remove 'captcha' from INSTALLED_APPS for properly run this test.") @override_settings(USERS_REGISTRATION_MODE = 'RESTRICTED', MAIL_REGISTRATION_APPROVE = 'vct@localhost') # Removing captcha doesn't seems to work #INSTALLED_APPS = remove_app(settings.INSTALLED_APPS, 'captcha')) def test_notify_operators(self): self.client.logout() self.assertFalse(is_installed('captcha')) name = "user" + str(int(round(time.time() * 1000))) password = "******" data = { "name": name, "username": name,
FIRMWARE_BUILD_IMAGE_STORAGE = getattr(settings, 'FIRMWARE_BUILD_IMAGE_STORAGE', FileSystemStorage(location=settings.PRIVATE_MEDIA_ROOT)) FIRMWARE_BUILD_IMAGE_PATH = getattr(settings, 'FIRMWARE_BUILD_IMAGE_PATH', 'firmwares') FIRMWARE_BASE_IMAGE_EXTENSIONS = getattr(settings, 'FIRMWARE_BASE_IMAGE_EXTENSIONS', ('.img.gz',)) FIRMWARE_PLUGINS_USB_IMAGE = getattr(settings, 'FIRMWARE_PLUGINS_USB_IMAGE', '%(site_root)s/confine-install.img.gz') # FIRMWARE DEFAULT PASSWORD REMOVED if hasattr(settings, 'FIRMWARE_PLUGINS_PASSWORD_DEFAULT'): import warnings warnings.warn("FIRMWARE_PLUGINS_PASSWORD_DEFAULT setting has been deprecated " "and is currently unused. You can safely remove it.") auth_keys_path = '' if is_installed('maintenance'): from maintenance.settings import MAINTENANCE_PUB_KEY_PATH auth_keys_path = MAINTENANCE_PUB_KEY_PATH FIRMWARE_PLUGINS_INITIAL_AUTH_KEYS_PATH = getattr(settings, 'FIRMWARE_PLUGINS_INITIAL_AUTH_KEYS_PATH', auth_keys_path) del auth_keys_path
for k,v in filters.items(): if getattr(obj, k) != v: return addr obj = getattr(obj, field, obj) ct = ContentType.objects.get_for_model(type(obj)) url = reverse('admin:pings_ping_list', args=(ct.pk, obj.pk)) state = Ping.get_state(obj) color = STATES_COLORS.get(state, "black") context = { 'color': color, 'title': state, 'url': url, 'addr': addr } colored = '<b><a style="color: %(color)s;" title="%(title)s" href="%(url)s">%(addr)s</a></b>' % context return mark_safe(colored) colored_address.short_description = getattr(old_method, 'short_description', old_method.__name__) return colored_address for instance in PING_INSTANCES: if is_installed(instance.get('app')): context = {'app': instance.get('app')} for admin_class, field_name, field, __ in instance.get('admin_classes'): context['admin'] = admin_class exec('from %(app)s.admin import %(admin)s as admin' % context) model_field = lambda self, obj: getattr(obj, field_name) model_field.short_description = field_name old_method = getattr(admin, field_name, model_field) filters = instance.get('filter', {}) setattr(admin, field_name, make_colored_address(old_method, field=field, filters=filters))
return value or None class PEMCertificateField(models.TextField): """X.509 PEM-encoded certificate.""" default_validators = [validate_cert] def get_db_prep_value(self, value, connection=None, prepared=False): """Remove carriage return to avoid problems on API representation.""" return value.replace('\r\n', '\n').strip() if value else None class TrimmedCharField(models.CharField): """ Remove trailing spaces """ __metaclass__ = models.SubfieldBase def to_python(self, value): if value: value = value.strip() return super(TrimmedCharField, self).to_python(value) if is_installed('south'): from south.modelsinspector import add_introspection_rules add_introspection_rules([], ["^controller\.models\.fields\.MultiSelectField"]) add_introspection_rules([], ["^controller\.models\.fields\.RSAPublicKeyField"]) add_introspection_rules([], ["^controller\.models\.fields\.URIField"]) add_introspection_rules([], ["^controller\.models\.fields\.NullableCharField"]) add_introspection_rules([], ["^controller\.models\.fields\.NullableTextField"]) add_introspection_rules([], ["^controller\.models\.fields\.PEMCertificateField"]) add_introspection_rules([], ["^controller\.models\.fields\.TrimmedCharField"])
from time import time from django.contrib.contenttypes import generic from django.contrib.contenttypes.models import ContentType from django.db import models from controller.utils.apps import is_installed from controller.utils.time import heartbeat_expires from .settings import PING_DEFAULT_INSTANCE, PING_INSTANCES, PING_COUNT for instance in PING_INSTANCES: # This has to be before Ping class in order to avoid import problems if is_installed(instance.get('app')): context = { 'app': instance.get('app'), 'model': instance.get('model').split('.')[1] } exec('from %(app)s.models import %(model)s as model' % context) model.add_to_class('pings', generic.GenericRelation('pings.Ping')) class Ping(models.Model): ONLINE = 'ONLINE' OFFLINE = 'OFFLINE' NODATA = 'NODATA' content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() samples = models.PositiveIntegerField(default=PING_COUNT)
def handle(self, *args, **options): # Warn about deprecated options if options.get('local'): self.stderr.write("Warning: 'local' option is deprecated and will be ignored.\n") version = options.get('version') upgrade_notes = [] if version: try: major, major2, minor = decode_version(version) except ValueError as e: raise CommandError(e) # Represent version as two digits per number: 1.2.2 -> 10202 version = int(str(major) + "%02d" % int(major2) + "%02d" % int(minor)) # Pre-upgrade operations (version specific) if version < 835: # prevent schema migrations from failing if is_installed('firmware'): from firmware.models import Build Build.objects.filter(base_image=None).update(base_image='') if version <= 902: if is_installed('maintenance'): # Apply losed migrations from south.models import MigrationHistory migrated = MigrationHistory.objects.filter(app_name='maintenance').exists() if not migrated: run('python manage.py migrate maintenance 0001 --fake') if version < 1002: # Update monitor settings (fix typo and add DiskFreeMonitor) context = { 'settings': run("find . -type f -name 'settings.py'|grep -v 'vct/'") } # Try automaticate update (making a backup) if context['settings']: run("cp %(settings)s %(settings)s.upgrade.bak" % context) # fix NumProcessesMonitor typo run("sed -i 's/NumPocessesMonitor/NumProcessesMonitor/g' " "%(settings)s" % context) # append disk monitor (if needed) # this is a rude check (but runned in a conservative way) if 'DiskFreeMonitor' not in open(context['settings']).read(): run("sed -i '/MONITOR_MONITORS = ($/ a\ " " (\"monitor.monitors.DiskFreeMonitor\",),' " "%(settings)s" % context) # warn the user about settings changes autoupdate_status = 'OK' if context['settings'] else 'FAIL' upgrade_notes.append('The monitor application has changed and .' 'some settings updates are required:\n' ' - Fix typo on NumProcessesMonitor (missing "r")\n' ' - Enable disk monitor\n' ' Please read the monitor app doc (MONITOR_MONITORS setting)\n' 'AUTOUPDATE: %s' % autoupdate_status) if version <= 1102: # Handle InconsistentMigrationHistory on tinc app # * v0.11.2 tinc includes 0022, 0028..0030 # * v0.11.3 tinc adds 0023..0027 # We can force south to merge migrations because # are implemented to be runned without dependencies run('python manage.py migrate tinc 0030 --merge --noinput') if not options.get('specifics_only'): # Common stuff development = options.get('development') controller_admin = os.path.join(os.path.dirname(__file__), '../../bin/') controller_admin = os.path.join(controller_admin, 'controller-admin.sh') run('chmod +x %s' % controller_admin) extra = '--development' if development else '' if options.get('proxy'): extra += ' --proxy %s' % options.get('proxy') run("%s install_requirements " % controller_admin + extra) run("python manage.py collectstatic --noinput") run("python manage.py syncdb --noinput") run("python manage.py migrate --noinput") if is_installed('firmware'): run("python manage.py syncfirmwareplugins") if is_installed('notifications'): run("python manage.py syncnotifications") if is_installed('resources'): run("python manage.py syncresources") if options.get('restart'): run("python manage.py restartservices") if not version: self.stderr.write('\nNext time you migth want to provide a --from argument ' 'in order to run version specific upgrade operations\n') return # Post-upgrade operations (version specific) if version <= 629: # Clean existing sessions because of change on auth backend run('echo "delete from django_session;" | python manage.py dbshell') if version < 801: deprecate_periodic_tasks(('state.ping',)) if version < 809: # Add PKI directories from pki import ca from controller.utils.paths import get_site_root site_root = get_site_root() username = run("stat -c %%U %s" % site_root) get_dir = lambda f: os.path.dirname(getattr(ca, f+'_path')) for d in set( get_dir(f) for f in ['priv_key', 'pub_key', 'cert'] ): run('mkdir -p %s' % d) run('chown %s %s' % (username, d)) upgrade_notes.append('HTTPS certificate support for the management ' 'network has been introduced in version 0.8.9.\n' 'In order to use it you sould run:\n' ' > python manage.py setuppki\n' ' > sudo python manage.py setupapache\n') if version < 838: # Purge communitynetworks.periodic_cache_node_db from djcelery.models import PeriodicTask PeriodicTask.objects.filter(name='communitynetworks.periodic_cache_node_db').delete() run('rabbitmqctl stop_app') run('rabbitmqctl reset') run('rabbitmqctl start_app') run('service celeryd restart') upgrade_notes.append('New Celeryd init.d configuration has been ' 'introduced in 0.8.38.\nIt is strongly recommended to upgrade by\n' ' > sudo python manage.py setupceleryd\n') # Deprecate x86 and amd64 architectures from nodes.models import Node Node.objects.filter(arch='x86').update(arch='i686') Node.objects.filter(arch='amd64').update(arch='x86_64') upgrade_notes.append('In order to support Base authentication while downloading ' 'firmwares you should add "WSGIPassAuthorization On" on your apache config.\n' 'Alternatively you can perform this operation with the following command\n' ' > sudo python manage.py setupapache\n' ' > /etc/init.d/apache2 reload\n') if version < 900: upgrade_notes.append('Apache configuration is now placed under ' '/etc/apache2/conf.d/<project_name>.conf. It is convenient for you ' 'to migrate your current configuration located on /etc/apache2/httpd.conf ' 'to this new location.\n') upgrade_notes.append('Celery workers configuration has been updated. ' 'Please update it by running:\n' ' > sudo python manage.py setupceleryd\n') if version < 905: # TODO find the root cause of this # maybe is shit imported on settings that import settings like add_app # Prevent crazy import erros to appear :S from django.utils import translation translation.activate('en-us') # Change template types for more generic ones from slices.models import Template from slices.settings import SLICES_TEMPLATE_TYPES template_types = [ t[0] for t in SLICES_TEMPLATE_TYPES ] if 'debian' in template_types: Template.objects.filter(type='debian6').update(type='debian') if 'openwrt' in template_types: Template.objects.filter(type='openwrt-backfire').update(type='openwrt') if version < 906: deprecate_periodic_tasks(('state.nodestate', 'state.sliverstate')) if version <= 907: # Generate sha256 from slices.models import Template for template in Template.objects.all(): template.save() upgrade_notes.append("It is extremly recommended to update your database " "settings to enable atomic request behaviour:\n" " https://docs.djangoproject.com/en/dev/topics/db/transactions/#tying-transactions-to-http-requests\n" "Just add:\n" " 'ATOMIC_REQUESTS': True,\n" "into DATABASES setting within <project_name>/<project_name>/settings.py") if version <= 1003: # Update firmware configuration after Island refactor (#264) from firmware.models import ConfigFile try: cfg_file = ConfigFile.objects.get(path__contains="node.tinc.connect_to") except (ConfigFile.DoesNotExist, ConfigFile.MultipleObjectsReturned): # Warn the user that needs to perform manual update msg = "Firmware configuration update has failed. " else: cfg_file.content = cfg_file.content.replace("node.tinc.island", "node.island") cfg_file.save() msg = "Firmware configuration updated successfully. Updated ConfigFile ID: %i." % cfg_file.pk upgrade_notes.append("%s\nPlease check version 0.10.4 release notes:\n" "https://wiki.confine-project.eu/soft:server-release-notes#section0104" % msg) if version < 1103: # Update mgmt network Server APIs certificate # perform raw SQL querie because models hasn't been # reloaded yet and cannot access e.g. server.api from django.db import connection from nodes.models import Server from pki import ca server_id = Server.objects.order_by('id').first().pk try: cert = ca.get_cert().as_pem() except IOError: msg = ("Failed to update Server APIs certificate. Missing " "server certificate '%s'.\n" "Run 'python manage.py setuppki --help'" % ca.cert_path) upgrade_notes.append(msg) else: update_sql = ('UPDATE "nodes_serverapi" SET cert = %s ' 'WHERE "nodes_serverapi"."server_id" = %s') cursor = connection.cursor() cursor.execute(update_sql, [cert, server_id]) del cursor upgrade_notes.append("Updated Server APIs certificate.") if upgrade_notes and options.get('print_upgrade_notes'): self.stdout.write('\n\033[1m\n' ' ===================\n' ' ** UPGRADE NOTES **\n' ' ===================\n\n' + '\n'.join(upgrade_notes) + '\033[m\n')
from django.core.urlresolvers import reverse, resolve from django.db import models from django.utils.safestring import mark_safe from controller.admin import ChangeViewActions, SortableTabularInline from controller.admin.utils import get_admin_link from controller.utils.apps import is_installed from permissions.admin import PermissionModelAdmin, PermissionTabularInline from .actions import join_request, enable_account, send_email from .filters import MyGroupsListFilter from .forms import (UserCreationForm, UserChangeForm, GroupRolesFormSet, UserRolesForm, JoinRequestForm, GroupAdminForm, GroupRolesInlineForm) from .models import User, AuthToken, Roles, Group, JoinRequest, ResourceRequest if is_installed('registration'): from .registration import admin as reg_admin # overrides registration.admin class AuthTokenInline(PermissionTabularInline): model = AuthToken extra = 0 class Media: css = { 'all': ('users/monospace-authtoken.css',) } def formfield_for_dbfield(self, db_field, **kwargs): """ Use monospace font style in script textarea """ if db_field.name == 'data':
def init_with_context(self, context): user = context['user'] self.children += [ items.MenuItem('Dashboard', reverse('admin:index')), items.Bookmarks(),] if is_installed('nodes') and user.has_module_perms('nodes'): node_items = [ items.MenuItem('Nodes', reverse('admin:nodes_node_changelist')), items.MenuItem('Servers', reverse('admin:nodes_server_changelist')), items.MenuItem('Islands', reverse('admin:nodes_island_changelist')), ] if is_installed('state'): node_items.append( items.MenuItem('Summary', reverse('admin:state_report')) ) if is_installed('gis'): node_items.insert( 1, items.MenuItem('Nodes Map', reverse('gis_map')) ) self.children.append( items.MenuItem('Nodes', reverse('admin:nodes_node_changelist'), children=node_items)) if is_installed('slices') and user.has_module_perms('slices'): slice_children = sliver_children = None if is_installed('state'): slice_children = [ items.MenuItem('Status Overview', reverse('admin:state_slices')), ] sliver_children = [ items.MenuItem('Status Overview', reverse('admin:state_slivers')), ] self.children.append(items.MenuItem('Slices', reverse('admin:slices_slice_changelist'), children=[ items.MenuItem('Slices', reverse('admin:slices_slice_changelist'), children=slice_children), items.MenuItem('Slivers', reverse('admin:slices_sliver_changelist'), children=sliver_children), items.MenuItem('Templates', reverse('admin:slices_template_changelist')), ])) if is_installed('tinc'): if user.has_module_perms('tinc'): self.children.append(items.MenuItem('Tinc', reverse('admin:app_list', args=['tinc']), children=[ items.MenuItem('TincAddresses', reverse('admin:tinc_tincaddress_changelist')), items.MenuItem('Hosts', reverse('admin:tinc_host_changelist')), ])) if user.is_superuser: administration_models = () if is_installed('djcelery'): administration_models += ('djcelery.*',) admin_item = items.AppList('Administration', models=administration_models) # Users menu item user_items = [ items.MenuItem('User', reverse('admin:users_user_changelist')), items.MenuItem('Group', reverse('admin:users_group_changelist')), items.MenuItem('Roles', reverse('admin:users_roles_changelist')), ] if is_installed('registration'): user_items.append( items.MenuItem('User Registration', reverse('admin:registration_registrationprofile_changelist'))) admin_item.children.append( items.MenuItem('Users', reverse('admin:app_list', args=['users']), children=user_items) ) if is_installed('maintenance'): maintenance_items = [ items.MenuItem('Operation', reverse('admin:maintenance_operation_changelist')), items.MenuItem('Instance', reverse('admin:maintenance_instance_changelist')) ] admin_item.children.append( items.MenuItem('Maintenance', reverse('admin:app_list', args=['maintenance']), children=maintenance_items) ) if is_installed('issues'): issues_items = [ items.MenuItem('Tickets', reverse('admin:issues_ticket_changelist')), items.MenuItem('Queues', reverse('admin:issues_queue_changelist')) ] admin_item.children.append( items.MenuItem('Issues', reverse('admin:issues_ticket_changelist'), children=issues_items) ) if is_installed('firmware'): firmware_items = [ items.MenuItem('Configuration', reverse('admin:firmware_config_change')), items.MenuItem('Builds', reverse('admin:firmware_build_changelist')) ] admin_item.children.append( items.MenuItem('Firmware', reverse('admin:app_list', args=['firmware']), children=firmware_items) ) if is_installed('notifications'): admin_item.children.append( items.MenuItem('Notifications', reverse('admin:notifications_notification_changelist')), ) else: admin_items = [ items.MenuItem('Users', reverse('admin:users_user_changelist')), items.MenuItem('Groups', reverse('admin:users_group_changelist')), ] if is_installed('issues'): admin_items.append( items.MenuItem('Tickets', reverse('admin:issues_ticket_changelist')) ) admin_item = items.MenuItem('Administration', children=admin_items) self.children.append(admin_item) if is_installed('api'): self.children.append(items.MenuItem('API', api_link(context))) self.children.append(items.MenuItem('Documentation', 'http://wiki.confine-project.eu/soft:server'))
from django.db import models from django.utils.safestring import mark_safe from controller.admin import ChangeViewActions, SortableTabularInline from controller.admin.utils import get_admin_link from controller.utils.apps import is_installed from permissions.admin import PermissionModelAdmin, PermissionTabularInline from .actions import join_request, enable_account, send_email from .filters import MyGroupsListFilter from .forms import (UserCreationForm, UserChangeForm, GroupRolesFormSet, UserRolesForm, JoinRequestForm, GroupAdminForm, GroupRolesInlineForm) from .models import User, AuthToken, Roles, Group, JoinRequest, ResourceRequest if is_installed('registration'): from .registration import admin as reg_admin # overrides registration.admin class AuthTokenInline(PermissionTabularInline): model = AuthToken extra = 0 class Media: css = {'all': ('users/monospace-authtoken.css', )} def formfield_for_dbfield(self, db_field, **kwargs): """ Use monospace font style in script textarea """ if db_field.name == 'data': kwargs['widget'] = forms.Textarea(attrs={'cols': 130, 'rows': '6'}) return super(AuthTokenInline,
def post_save(self, obj, created=False): if created and is_installed('resources'): management.call_command('syncresources')