├── COPYRIGHT ├── Changelog ├── README.md ├── _version.py ├── accounts ├── __init__.py ├── admin.py ├── forms.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── idle_accounts.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20161020_1643.py │ └── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── apply ├── __init__.py ├── admin.py ├── apps.py ├── decorators.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_auto_20161024_1512.py │ └── __init__.py ├── models.py ├── south_migrations │ └── 0012_auto__add_field_organization_synced.py ├── tests.py ├── urls │ ├── __init__.py │ ├── application.py │ └── user.py ├── utils.py └── views │ ├── __init__.py │ └── user.py ├── auditlog ├── __init__.py ├── admin.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── signals.py ├── tests.py ├── urls.py ├── utils.py └── views.py ├── context ├── __init__.py ├── global_vars.py ├── pending_notifications.py └── session_remaining.py ├── contrib ├── CONTENTS ├── default │ └── ganetimgr-watcher ├── fabric │ ├── fabfile.py │ ├── requirements.txt │ └── utils │ │ ├── __init__.py │ │ ├── database.py │ │ ├── django.py │ │ ├── git.py │ │ ├── operations.py │ │ └── services.py ├── gunicorn │ ├── ganetimgr_jessie │ └── ganetimgr_wheezy ├── init.d │ └── ganetimgr-watcher ├── jquery-1.5.2.js ├── jquery-ui │ ├── jquery.effects.blind.js │ ├── jquery.effects.bounce.js │ ├── jquery.effects.clip.js │ ├── jquery.effects.core.js │ ├── jquery.effects.drop.js │ ├── jquery.effects.explode.js │ ├── jquery.effects.fade.js │ ├── jquery.effects.fold.js │ ├── jquery.effects.highlight.js │ ├── jquery.effects.pulsate.js │ ├── jquery.effects.scale.js │ ├── jquery.effects.shake.js │ ├── jquery.effects.slide.js │ ├── jquery.effects.transfer.js │ ├── jquery.ui.accordion.js │ ├── jquery.ui.autocomplete.js │ ├── jquery.ui.button.js │ ├── jquery.ui.core.js │ ├── jquery.ui.datepicker.js │ ├── jquery.ui.dialog.js │ ├── jquery.ui.draggable.js │ ├── jquery.ui.droppable.js │ ├── jquery.ui.mouse.js │ ├── jquery.ui.position.js │ ├── jquery.ui.progressbar.js │ ├── jquery.ui.resizable.js │ ├── jquery.ui.selectable.js │ ├── jquery.ui.slider.js │ ├── jquery.ui.sortable.js │ ├── jquery.ui.tabs.js │ └── jquery.ui.widget.js ├── nginx │ └── ganetimgr_vhost ├── vima_policy.py └── vnc_javasrc │ ├── AuthPanel.java │ ├── ButtonPanel.java │ ├── CapabilityInfo.java │ ├── CapsContainer.java │ ├── ChangeLog │ ├── ClipboardFrame.java │ ├── DesCipher.java │ ├── HTTPConnectSocket.java │ ├── HTTPConnectSocketFactory.java │ ├── InStream.java │ ├── LICENCE.TXT │ ├── MANIFEST.MF │ ├── Makefile │ ├── MemInStream.java │ ├── OptionsFrame.java │ ├── README │ ├── RecordingFrame.java │ ├── ReloginPanel.java │ ├── RfbProto.java │ ├── SessionRecorder.java │ ├── SocketFactory.java │ ├── VncCanvas.java │ ├── VncCanvas2.java │ ├── VncViewer.java │ ├── WhatsNew │ ├── ZlibInStream.java │ ├── index.html │ └── index.vnc ├── docs ├── Makefile └── source │ ├── _static │ └── images │ │ ├── applications.png │ │ ├── audit-log.png │ │ ├── cluster_info.png │ │ ├── ganetimgr_create_instance.png │ │ ├── graphs.png │ │ ├── history.png │ │ ├── image00.png │ │ ├── image01.png │ │ ├── image02.png │ │ ├── image03.png │ │ ├── image04.png │ │ ├── instance-owners.png │ │ ├── instance_details.png │ │ ├── jobs.png │ │ ├── node_groups.png │ │ ├── ss_01_main.png │ │ ├── ss_02_user_main_view.png │ │ ├── ss_03_user_statistics.png │ │ ├── ss_04_user_profile.png │ │ ├── ss_05_user_application.png │ │ ├── ss_06_vm_info.png │ │ ├── ss_07_vm_graphs.png │ │ ├── ss_08_vm_conf.png │ │ ├── ss_09_vm_actions.png │ │ ├── ss_10_admin_node.png │ │ ├── ss_11_admin_stats.png │ │ ├── ss_12_admin_jobs.png │ │ ├── ss_14_admin_application.png │ │ └── ss_15_admin_mail.png │ ├── admin.rst │ ├── conf.py │ ├── devel.rst │ ├── index.rst │ ├── install.rst │ ├── interface.rst │ ├── patches.rst │ ├── upgrade.rst │ ├── version2.md │ └── vnc.rst ├── ganeti ├── __init__.py ├── admin.py ├── decorators │ └── __init__.py ├── fixtures │ └── flatpages.json ├── forms.py ├── management │ ├── __init__.py │ └── commands │ │ ├── __init__.py │ │ └── refresh_cluster_instances.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_custompermission.py │ ├── 0003_auto_20170807_1459.py │ └── __init__.py ├── models.py ├── templatetags │ ├── __init__.py │ ├── applicationstatus.py │ ├── bootstrappercent.py │ ├── days_since.py │ ├── disksizes.py │ ├── noderole.py │ ├── truncatedchars.py │ └── widget_tweaks.py ├── tests.py ├── urls │ ├── __init__.py │ ├── clusters.py │ ├── graphs.py │ ├── instances.py │ ├── jobs.py │ └── nodegroup.py ├── utils.py └── views │ ├── __init__.py │ ├── clusters.py │ ├── discovery.py │ ├── graphs.py │ ├── instances.py │ ├── jobs.py │ └── nodegroup.py ├── ganetimgr ├── __init__.py ├── settings-test.py ├── settings.py.dist ├── urls.py ├── urls │ └── __init__.py └── wsgi.py ├── locale └── el │ └── LC_MESSAGES │ ├── django.mo │ └── django.po ├── manage.py ├── middleware ├── ForceLogout.py ├── MobileDetectionMiddleware.py ├── UserMessages.py └── __init__.py ├── notifications ├── __init__.py ├── admin.py ├── forms.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── tests.py ├── urls.py ├── utils.py └── views.py ├── readthedocs-requirements.txt ├── requirements.txt ├── static ├── branding │ ├── logo.png │ └── logo.xcf ├── flatpagesassets │ ├── ownership.png │ ├── ownership_dropdown.png │ └── user_screen.png ├── ganetimgr │ ├── css │ │ ├── base.css │ │ ├── includes │ │ │ ├── bootstrap-responsive.min.css │ │ │ ├── bootstrap-switch.css │ │ │ ├── bootstrap.min.css │ │ │ ├── daterangepicker.css │ │ │ ├── feedek.css │ │ │ ├── font-awesome.min.css │ │ │ ├── img-on-top.css │ │ │ ├── nprogress.css │ │ │ ├── resp-modal.css │ │ │ ├── select2-spinner.gif │ │ │ ├── select2.css │ │ │ ├── select2.png │ │ │ └── select2x2.png │ │ ├── smoothness │ │ │ └── images │ │ │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ │ │ ├── ui-bg_flat_75_ffffff_40x100.png │ │ │ │ ├── ui-bg_glass_55_fbf9ee_1x400.png │ │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ │ ├── ui-bg_glass_75_dadada_1x400.png │ │ │ │ ├── ui-bg_glass_75_e6e6e6_1x400.png │ │ │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ │ │ ├── ui-bg_highlight-soft_75_cccccc_1x100.png │ │ │ │ ├── ui-icons_222222_256x240.png │ │ │ │ ├── ui-icons_2e83ff_256x240.png │ │ │ │ ├── ui-icons_454545_256x240.png │ │ │ │ ├── ui-icons_888888_256x240.png │ │ │ │ └── ui-icons_cd0a0a_256x240.png │ │ └── theme.css │ ├── fonts │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── img │ │ ├── background_grnet.png │ │ ├── favicon.ico │ │ ├── gifs │ │ │ └── ajax-loader.gif │ │ ├── learnmore.png │ │ ├── logo.png │ │ ├── nodata.jpg │ │ ├── rule.png │ │ ├── sprites │ │ │ ├── glyphicons-halflings-white.png │ │ │ └── glyphicons-halflings.png │ │ └── video-crop.png │ └── js │ │ ├── includes │ │ ├── bootstrap-switch.min.js │ │ ├── bootstrap.min.js │ │ ├── daterangepicker.js │ │ ├── feedek.js │ │ ├── highcharts.js │ │ ├── jquery-1.10.1.min.js │ │ ├── jquery-1.10.1.min.map │ │ ├── jquery.cookie.js │ │ ├── jquery.dataTables.bootstrap.js │ │ ├── jquery.dataTables.min.js │ │ ├── jquery.min.js │ │ ├── jquery.sparkline.min.js │ │ ├── moment.min.js │ │ ├── nprogress.js │ │ └── select2.js │ │ ├── jquery_csrf_protect.js │ │ └── messages.js ├── javavnc │ └── VncViewer.jar └── noVNC │ ├── .gitmodules │ ├── LICENSE.txt │ ├── README.md │ ├── docs │ ├── LICENSE.Apache-2.0 │ ├── LICENSE.BSD-2-Clause │ ├── LICENSE.BSD-3-Clause │ ├── LICENSE.GPL-3 │ ├── LICENSE.LGPL-3 │ ├── LICENSE.MPL-2.0 │ ├── LICENSE.OFL-1.1 │ ├── LICENSE.zlib │ ├── VERSION │ ├── flash_policy.txt │ ├── links │ ├── notes │ ├── packaging.txt │ ├── release.txt │ ├── rfb_notes │ ├── rfbproto-3.3.pdf │ ├── rfbproto-3.7.pdf │ └── rfbproto-3.8.pdf │ └── include │ ├── Orbitron700.ttf │ ├── Orbitron700.woff │ ├── base.css │ ├── base64.js │ ├── black.css │ ├── blue.css │ ├── chrome-app │ └── tcp-client.js │ ├── des.js │ ├── display.js │ ├── input.js │ ├── jsunzip.js │ ├── keyboard.js │ ├── keysym.js │ ├── keysymdef.js │ ├── logo.js │ ├── playback.js │ ├── rfb.js │ ├── ui.js │ ├── util.js │ ├── web-socket-js │ ├── README.txt │ ├── WebSocketMain.swf │ ├── swfobject.js │ └── web_socket.js │ ├── websock.js │ ├── websock_old.js │ └── webutil.js ├── stats ├── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── templates ├── 403.html ├── 404.html ├── 500.html ├── apply │ ├── admin_apply.html │ ├── application_list.html │ ├── apply.html │ ├── emails │ │ ├── application_rejected_mail.txt │ │ └── apply_mail.txt │ └── review.html ├── auditlog │ └── auditlog.html ├── base.html ├── clusters │ ├── cluster_nodes.html │ ├── cluster_nodes_pjax.html │ └── clusters.html ├── flatpages │ ├── default.html │ └── faq.html ├── graphs │ └── nodes-graphs.html ├── includes │ ├── analytics.html.dist │ └── banners.html ├── instances │ ├── emails │ │ ├── instance_created_mail.txt │ │ └── reinstall_mail.txt │ ├── includes │ │ ├── console-module.html │ │ └── instance_status.html │ ├── instance.html │ ├── instance_actions.html │ ├── instance_popup.html │ ├── novnc.html │ ├── rename_instance.html │ ├── user_instances_json.html │ ├── verify_action.html │ └── vnc.html ├── jobs │ ├── job_details.html │ └── jobs.html ├── news │ └── news.html ├── notifications │ ├── create.html │ ├── create_ajax.html │ ├── create_body.html │ ├── create_script.html │ └── detail.html ├── registration │ ├── activate.html │ ├── activation_complete_admin_pending.html │ ├── activation_complete_admin_pending.txt │ ├── activation_email.txt │ ├── activation_email_subject.txt │ ├── admin_approve.html │ ├── admin_approve_complete.html │ ├── admin_approve_complete_email.txt │ ├── admin_approve_email.txt │ ├── admin_approve_email_subject.txt │ ├── password_change_form.html │ ├── password_reset_complete.html │ ├── password_reset_confirm.html │ ├── password_reset_done.html │ ├── password_reset_email.html │ ├── password_reset_form.html │ ├── registration_complete.html │ ├── registration_form.html │ └── validation_expired.html ├── stats │ └── statistics.html ├── tagging │ ├── isolate.html │ ├── itags.html │ └── lock.html └── users │ ├── emails │ ├── idle_account.txt │ └── pass_change_notify_mail.txt │ ├── idle_accounts.html │ ├── login.html │ ├── mail_change.html │ ├── name_change.html │ ├── other_change.html │ ├── pass_change.html │ ├── pass_change_done.html │ ├── profile.html │ ├── user_info.html │ └── user_keys.html ├── util ├── __init__.py ├── client.py └── vapclient.py ├── version └── watcher.py /README.md: -------------------------------------------------------------------------------- 1 | # Ganetimgr 2 | [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/grnet/ganetimgr?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 3 | [![Documentation Status](https://readthedocs.org/projects/ganetimgr/badge/?version=latest)](https://readthedocs.org/projects/ganetimgr/?badge=latest) 4 | 5 | `Ganetimgr` is a web platform that eases the provisioning of virtual machines over multiple `ganeti` clusters. 6 | It leverages Ganeti's RAPI functionality to administer the clusters, and is stateless from the VM perspective. 7 | The project is written in `Django` and uses Bootstrap for the frontend. 8 | In essence, ganetimgr aims to be the frontend of a VPS service. 9 | 10 | ## Development 11 | 12 | - 2010-2012 Apollon Oikonomopoulos (@apoikos) 13 | - 2011-2014 Leonidas Poulopoulos (@leopoul) 14 | - 2014-2015 Stavros Kroustouris (@kroustou) 15 | - 2015-2017 Sergios Aftsidis (@sergafts) 16 | - 2017 John Paraskevopoulos (@ioparaskev) 17 | 18 | ## Contribution 19 | 20 | ### Code 21 | - Brian Candler (@candlerb) 22 | - Mike Gabriel (@sunweaver) 23 | - Dimitris Bliablias (@dblia) 24 | 25 | ### Documentation 26 | - 2014 Alex Kiousis (@alexkiousis) 27 | - 2014 Nikos Kokkalis (@nkokkalis) 28 | - 2013 George Kargiotakis (@kargig) 29 | 30 | ## Instructions 31 | For detailed instructions, go to our [readthedocs](http://ganetimgr.readthedocs.org/en/latest/) page. 32 | 33 | 34 | ## Contact Information 35 | 36 | User discussions: ganetimgr-users@lists.grnet.gr 37 | 38 | ===================================================================== 39 | 40 | ## Copyright and license 41 | 42 | Copyright © 2010-2018 Greek Research and Technology Network (GRNET S.A.) 43 | 44 | This program is free software: you can redistribute it and/or modify 45 | it under the terms of the GNU General Public License as published by 46 | the Free Software Foundation, either version 3 of the License, or 47 | (at your option) any later version. 48 | 49 | This program is distributed in the hope that it will be useful, 50 | but WITHOUT ANY WARRANTY; without even the implied warranty of 51 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 52 | GNU General Public License for more details. 53 | 54 | You should have received a copy of the GNU General Public License 55 | along with this program. If not, see . 56 | -------------------------------------------------------------------------------- /_version.py: -------------------------------------------------------------------------------- 1 | VERSION = '2.0.0' 2 | 3 | if __name__ == "__main__": 4 | print VERSION 5 | -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | 19 | from django.contrib import admin 20 | from accounts.models import UserProfile 21 | from registration.models import RegistrationProfile 22 | 23 | 24 | admin.site.register(UserProfile) 25 | # This unregisters the default RegistrationProfile so that we 26 | # can use our own 27 | admin.site.unregister(RegistrationProfile) 28 | -------------------------------------------------------------------------------- /accounts/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | from django import forms 18 | from django.utils.translation import ugettext_lazy as _ 19 | from django.contrib.auth.forms import PasswordResetForm 20 | from registration.forms import RegistrationFormUniqueEmail as _RegistrationForm 21 | from apply.models import Organization 22 | from nocaptcha_recaptcha.fields import NoReCaptchaField 23 | 24 | 25 | class RegistrationForm(_RegistrationForm): 26 | name = forms.CharField() 27 | surname = forms.CharField() 28 | phone = forms.CharField(required=False) 29 | organization = forms.ModelChoiceField( 30 | queryset=Organization.objects.all(), 31 | required=False, 32 | label=_("Organization") 33 | ) 34 | recaptcha = NoReCaptchaField() 35 | 36 | 37 | class PasswordResetFormPatched(PasswordResetForm): 38 | error_messages = { 39 | 'unknown': _("That e-mail address doesn't have an associated " 40 | "user account or the account has not been activated yet. Are you sure you've registered?"), 41 | 'unusable': _("The user account associated with this e-mail " 42 | "address cannot reset the password."), 43 | } 44 | -------------------------------------------------------------------------------- /accounts/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/accounts/management/__init__.py -------------------------------------------------------------------------------- /accounts/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/accounts/management/commands/__init__.py -------------------------------------------------------------------------------- /accounts/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | from django.conf import settings 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 12 | ('registration', '0004_supervisedregistrationprofile'), 13 | ('apply', '0001_initial'), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='CustomRegistrationProfile', 19 | fields=[ 20 | ('registrationprofile_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='registration.RegistrationProfile')), 21 | ('admin_activation_key', models.CharField(max_length=40, verbose_name='admin activation key')), 22 | ('validated', models.BooleanField(default=False)), 23 | ], 24 | options={ 25 | 'verbose_name': 'registration profile', 26 | 'verbose_name_plural': 'registration profiles', 27 | }, 28 | bases=('registration.registrationprofile',), 29 | ), 30 | migrations.CreateModel( 31 | name='UserProfile', 32 | fields=[ 33 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 34 | ('first_login', models.BooleanField(default=True)), 35 | ('force_logout_date', models.DateTimeField(null=True, blank=True)), 36 | ('telephone', models.CharField(max_length=13, null=True, blank=True)), 37 | ('organization', models.ForeignKey(blank=True, to='apply.Organization', null=True)), 38 | ('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)), 39 | ], 40 | ), 41 | ] 42 | -------------------------------------------------------------------------------- /accounts/migrations/0002_auto_20161020_1643.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('accounts', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.RemoveField( 15 | model_name='customregistrationprofile', 16 | name='registrationprofile_ptr', 17 | ), 18 | migrations.DeleteModel( 19 | name='CustomRegistrationProfile', 20 | ), 21 | ] 22 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | import datetime 19 | 20 | from apply.models import Organization 21 | 22 | from django.contrib.auth.models import User 23 | from django.contrib.auth.signals import user_logged_in 24 | from django.db import models 25 | from django.db.models.signals import post_save 26 | 27 | try: 28 | from django.utils.timezone import now as datetime_now 29 | except ImportError: 30 | datetime_now = datetime.datetime.now 31 | 32 | 33 | class UserProfile(models.Model): 34 | user = models.OneToOneField(User) 35 | first_login = models.BooleanField(default=True) 36 | force_logout_date = models.DateTimeField(null=True, blank=True) 37 | organization = models.ForeignKey(Organization, blank=True, null=True) 38 | telephone = models.CharField(max_length=13, blank=True, null=True) 39 | 40 | def force_logout(self): 41 | self.force_logout_date = datetime.datetime.now() 42 | self.save() 43 | 44 | def is_owner(self, instance): 45 | if self.user in instance.users: 46 | return True 47 | else: 48 | for group in self.user.groups.all(): 49 | if group in instance.groups: 50 | return True 51 | return False 52 | 53 | def __unicode__(self): 54 | return "%s profile" % self.user 55 | 56 | 57 | # Signals 58 | def create_user_profile(sender, instance, created, **kwargs): 59 | if created and not kwargs.get('raw', False): 60 | UserProfile.objects.create(user=instance) 61 | post_save.connect( 62 | create_user_profile, sender=User, dispatch_uid='create_UserProfile') 63 | 64 | 65 | def update_session_last_login(sender, user, request, **kwargs): 66 | if request: 67 | request.session['LAST_LOGIN_DATE'] = datetime.datetime.now() 68 | user_logged_in.connect(update_session_last_login) 69 | -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase, Client 2 | from django.core.urlresolvers import reverse 3 | from django.conf import settings 4 | from django.contrib.auth.models import User 5 | 6 | 7 | class AccountsTestCase(TestCase): 8 | def setUp(self): 9 | self.client = Client() 10 | # create a user 11 | self.user = User( 12 | email='test@test.com', 13 | username='test', 14 | ) 15 | self.user.save() 16 | 17 | def test_registration_url(self): 18 | res = self.client.get(reverse('registration_register')) 19 | self.assertEqual(res.status_code, 200) 20 | 21 | def test_login_url(self): 22 | res = self.client.get(settings.LOGIN_URL, follow=True) 23 | self.assertEqual(res.status_code, 200) 24 | 25 | def test_activate_url(self): 26 | res = self.client.get( 27 | reverse( 28 | 'registration_activate', 29 | kwargs={'activation_key': 'test'} 30 | ) 31 | ) 32 | self.assertEqual(res.status_code, 200) 33 | 34 | def test_register(self): 35 | data = { 36 | 'name': 'test2', 37 | 'surname': 'Test2', 38 | 'phone': '1212', 39 | 'email': 'test2@test.com', 40 | 'username': 'test2', 41 | 'recaptcha': 'test', 42 | 'password1': 'test', 43 | 'password2': 'test', 44 | } 45 | res = self.client.post(reverse('registration_register'), data) 46 | # make sure the user is redirected - form is valid 47 | self.assertEqual(res.status_code, 302) 48 | 49 | # there should be the user we just created in the db 50 | user = User.objects.get(email='test2@test.com') 51 | 52 | # make sure this new user is not active 53 | self.assertFalse(user.is_active) 54 | 55 | def test_user_profile(self): 56 | # there should also be a user profile 57 | self.user.userprofile.first_login 58 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from accounts.forms import PasswordResetFormPatched 19 | from django.conf.urls import url, include 20 | from django.contrib.auth import views as auth_views 21 | from .views import CustomRegistrationView as RegistrationView 22 | 23 | 24 | urlpatterns = [ 25 | url( 26 | r'^register/$', 27 | RegistrationView.as_view(), 28 | name='registration_register' 29 | ), 30 | url( 31 | r'^password/reset/$', 32 | auth_views.password_reset, 33 | { 34 | 'password_reset_form': 35 | PasswordResetFormPatched, 36 | }, 37 | name='password_reset' 38 | ), 39 | url(r'^reset/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', 40 | auth_views.password_reset_confirm, name='password_reset_confirm'), 41 | url(r'^reset/done/$', auth_views.password_reset_complete, name='password_reset_complete'), 42 | url( 43 | r'^password_reset/done/$', 44 | auth_views.password_reset_done, 45 | name='password_reset_done' 46 | ), 47 | url(r'^', include('registration.backends.admin_approval.urls')), 48 | ] 49 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from registration.backends.admin_approval.views import RegistrationView 19 | from apply.models import Organization 20 | from accounts.models import UserProfile 21 | 22 | 23 | class CustomRegistrationView(RegistrationView): 24 | 25 | def register(self, form): 26 | 27 | new_user = super(RegistrationView, self).register(form) 28 | 29 | telephone = form.cleaned_data['phone'] 30 | organization = form.cleaned_data['organization'] 31 | 32 | profile, created = UserProfile.objects.get_or_create(user=new_user) 33 | try: 34 | organization = Organization.objects.get(title=organization) 35 | profile.organization = organization 36 | except Organization.DoesNotExist: 37 | profile.organization = None 38 | 39 | profile.telephone = telephone 40 | profile.user = new_user 41 | profile.save() 42 | 43 | new_user.first_name = form.cleaned_data['name'] 44 | new_user.last_name = form.cleaned_data['surname'] 45 | new_user.save() 46 | 47 | return new_user 48 | -------------------------------------------------------------------------------- /apply/__init__.py: -------------------------------------------------------------------------------- 1 | # default_app_config = 'apply.apps.ApplyConfig' 2 | -------------------------------------------------------------------------------- /apply/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | import functools 18 | 19 | from django.contrib import admin 20 | 21 | from apply.models import Organization, InstanceApplication 22 | 23 | class InstanceApplicationAdmin(admin.ModelAdmin): 24 | list_display = ["hostname", "applicant", "organization", "cluster", 25 | "status", "filed"] 26 | list_filter = ["status", "organization"] 27 | search_fields = [ 28 | "hostname", "applicant__username", "organization__title", "status", "filed" 29 | ] 30 | list_editable = ["organization"] 31 | readonly_fields = ["job_id", "backend_message", "reviewer"] 32 | ordering = ["-filed", "hostname"] 33 | fieldsets = [ 34 | ('Instance Information', {'fields': ('hostname', 'memory', 'disk_size', 35 | 'vcpus', 'operating_system', 36 | 'hosts_mail_server')}), 37 | ('Placement', {'fields': ('instance_params',)}), 38 | ('Owner Information', {'fields': ('applicant', 'organization', 39 | 'admin_contact_name', 40 | 'admin_contact_phone', 41 | 'admin_contact_email')}), 42 | ('Backend Information', {'fields': ('status', 'job_id', 43 | 'backend_message', 'reviewer')}) 44 | ] 45 | 46 | 47 | admin.site.register(Organization) 48 | admin.site.register(InstanceApplication, InstanceApplicationAdmin) 49 | -------------------------------------------------------------------------------- /apply/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApplyConfig(AppConfig): 5 | name = 'apply' 6 | label = 'ganetimgrapply' 7 | verbose_name = "Apply" 8 | -------------------------------------------------------------------------------- /apply/decorators.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.decorators import user_passes_test 2 | 3 | 4 | def any_permission_required(*args): 5 | def test_func(user): 6 | for perm in args: 7 | if user.has_perm(perm): 8 | return True 9 | return False 10 | return user_passes_test(test_func) 11 | -------------------------------------------------------------------------------- /apply/migrations/0002_auto_20161024_1512.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | from django.conf import settings 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('apply', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterField( 16 | model_name='organization', 17 | name='users', 18 | field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, blank=True), 19 | ), 20 | ] 21 | -------------------------------------------------------------------------------- /apply/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/apply/migrations/__init__.py -------------------------------------------------------------------------------- /apply/urls/__init__.py: -------------------------------------------------------------------------------- 1 | from application import * 2 | from user import * 3 | -------------------------------------------------------------------------------- /apply/urls/application.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from apply import views 20 | 21 | urlpatterns = [ 22 | url(r'^apply/?$', views.apply, name="apply"), 23 | url(r'^list/?$', views.application_list, name="application-list"), 24 | # this url is accessible only if a superuser tries to create 25 | # an instance by himself 26 | url(r'^save/', views.review_application, name="application-save"), 27 | url(r'^(?P\d+)/review/$', views.review_application, name="application-review"), 28 | url(r'^(?P\d+)/(?P\w+)/ssh_keys', views.instance_ssh_keys, name="instance-ssh-keys"), 29 | ] 30 | -------------------------------------------------------------------------------- /apply/urls/user.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from apply import views 20 | from django.contrib.auth.views import login, logout, password_change, password_change_done 21 | from ganeti.forms import PickyAuthenticationForm 22 | 23 | urlpatterns = [ 24 | url(r'^info/(?P\w+)/(?P[\w\.\@-]+)/?$', views.user_info, name="user-info"), 25 | url(r'^details/$', views.detail_api, name="user-details-json"), 26 | url(r'^idle/$', views.idle_accounts, name="idle_accounts"), 27 | url(r'^profile/$', views.profile, name="profile"), 28 | url(r'^mail_change/$', views.mail_change, name="mail-change"), 29 | url(r'^name_change/$', views.name_change, name="name-change"), 30 | url(r'^other_change/$', views.other_change, name="other-change"), 31 | url(r'^keys/$', views.user_keys, name="user-keys"), 32 | url(r'^keys/delete/(?P\d+)?$', views.delete_key, name="delete-key"), 33 | url(r'^login/', login, {'template_name': 'users/login.html', 34 | 'authentication_form': PickyAuthenticationForm}, 35 | name="login"), 36 | url(r'^logout/', logout, {'next_page': '/'}, name="logout"), 37 | url(r'^pass_change/$', password_change, {'template_name':'users/pass_change.html', 'post_change_redirect':'pass_change_done'}, name="pass_change"), 38 | url(r'^pass_change/done/$', password_change_done, {'template_name':'users/pass_change_done.html'}, name="pass_change_done" ), 39 | url(r'^pass_change/notify/$', views.pass_notify, name="pass_change_notify"), 40 | ] 41 | -------------------------------------------------------------------------------- /apply/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | from ganeti.models import InstanceAction 18 | 19 | 20 | def check_mail_change_pending(user): 21 | actions = [] 22 | pending_actions = InstanceAction.objects.filter(applicant=user, action=4) 23 | for pending in pending_actions: 24 | if pending.activation_key_expired(): 25 | continue 26 | actions.append(pending) 27 | if len(actions) == 0: 28 | return False 29 | elif len(actions) == 1: 30 | return True 31 | else: 32 | return False 33 | 34 | -------------------------------------------------------------------------------- /auditlog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/auditlog/__init__.py -------------------------------------------------------------------------------- /auditlog/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.contrib import admin 19 | from models import AuditEntry 20 | 21 | 22 | class AuditEntryAdmin(admin.ModelAdmin): 23 | list_display = ( 24 | 'requester', 25 | 'action', 26 | 'instance', 27 | 'cluster', 28 | 'job_id', 29 | 'last_updated' 30 | ) 31 | list_filter = ('cluster', 'action', 'last_updated') 32 | 33 | admin.site.register(AuditEntry, AuditEntryAdmin) 34 | 35 | 36 | -------------------------------------------------------------------------------- /auditlog/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | from django.conf import settings 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='AuditEntry', 17 | fields=[ 18 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 19 | ('ipaddress', models.CharField(max_length=255, null=True, blank=True)), 20 | ('action', models.CharField(max_length=255)), 21 | ('instance', models.CharField(max_length=255)), 22 | ('cluster', models.CharField(max_length=50)), 23 | ('job_id', models.IntegerField(null=True, blank=True)), 24 | ('recorded', models.DateTimeField(auto_now_add=True)), 25 | ('last_updated', models.DateTimeField(auto_now=True)), 26 | ('is_authorized', models.BooleanField(default=True)), 27 | ('requester', models.ForeignKey(to=settings.AUTH_USER_MODEL)), 28 | ], 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /auditlog/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/auditlog/migrations/__init__.py -------------------------------------------------------------------------------- /auditlog/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.db import models 19 | from django.contrib.auth.models import User 20 | 21 | 22 | class AuditEntry(models.Model): 23 | requester = models.ForeignKey(User) 24 | ipaddress = models.CharField(max_length=255, null=True, blank=True) 25 | action = models.CharField(max_length=255) 26 | instance = models.CharField(max_length=255) 27 | cluster = models.CharField(max_length=50) 28 | job_id = models.IntegerField(null=True, blank=True) 29 | recorded = models.DateTimeField(auto_now_add=True) 30 | last_updated = models.DateTimeField(auto_now=True) 31 | is_authorized = models.BooleanField(default=True) 32 | 33 | def __unicode__(self): 34 | return "%s %s %s" % (self.requester, self.action, self.instance) 35 | 36 | def update(self, **kwargs): 37 | for k, v in kwargs.iteritems(): 38 | setattr(self, k, v) 39 | self.save() 40 | -------------------------------------------------------------------------------- /auditlog/signals.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (C) 2010-2014 GRNET S.A. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | import django.dispatch 19 | from django.contrib.auth.models import User 20 | from auditlog.models import AuditEntry 21 | audit_entry = django.dispatch.Signal() 22 | 23 | 24 | def store_audit_entry(sender, *args, **kwargs): 25 | if 'user' in kwargs.keys(): 26 | user = kwargs['user'] 27 | if 'ipaddress' in kwargs.keys(): 28 | ipaddress = kwargs['ipaddress'] 29 | if 'action' in kwargs.keys(): 30 | action = kwargs['action'] 31 | if 'instance' in kwargs.keys(): 32 | instance = kwargs['instance'] 33 | if 'cluster' in kwargs.keys(): 34 | cluster = kwargs['cluster'] 35 | auditlog = AuditEntry( 36 | requester=User.objects.get(pk=user), 37 | ipaddress=ipaddress, 38 | action=action, 39 | instance=instance, 40 | cluster=cluster 41 | ) 42 | auditlog.save 43 | 44 | audit_entry.connect(store_audit_entry) 45 | 46 | 47 | def get_client_ip(request): 48 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') 49 | if x_forwarded_for: 50 | ip = x_forwarded_for.split(',')[0] 51 | else: 52 | ip = request.META.get('REMOTE_ADDR') 53 | return ip 54 | -------------------------------------------------------------------------------- /auditlog/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from auditlog import views 20 | 21 | urlpatterns = [ 22 | url(r'^$', views.auditlog, name='auditlog'), 23 | url(r'^json/$', views.auditlog_json, name='auditlog_json'), 24 | ] 25 | -------------------------------------------------------------------------------- /auditlog/utils.py: -------------------------------------------------------------------------------- 1 | from auditlog.models import AuditEntry 2 | from django.contrib.auth.models import User 3 | 4 | 5 | def get_client_ip(request): 6 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') 7 | if x_forwarded_for: 8 | ip = x_forwarded_for.split(',')[0] 9 | else: 10 | ip = request.META.get('REMOTE_ADDR') 11 | return ip 12 | 13 | 14 | def auditlog_entry(request, action, instance, 15 | cluster, save=True, authorized=True): 16 | entry = AuditEntry( 17 | requester=User.objects.get(pk=request.user.id), 18 | ipaddress=get_client_ip(request), 19 | action=action, 20 | instance=instance, 21 | cluster=cluster, 22 | is_authorized=authorized 23 | ) 24 | if save: 25 | entry.save() 26 | return entry 27 | -------------------------------------------------------------------------------- /context/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/context/__init__.py -------------------------------------------------------------------------------- /context/global_vars.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf import settings 19 | 20 | 21 | def settings_vars(context): 22 | # return the value you want as a dictionary. you may add multiple 23 | # values in there. Also check if these values exist in settings.py 24 | 25 | return { 26 | 'HELPDESK_INTEGRATION_JAVASCRIPT_URL': settings.HELPDESK_INTEGRATION_JAVASCRIPT_URL if hasattr(settings, 'HELPDESK_INTEGRATION_JAVASCRIPT_URL') else '', 27 | 'HELPDESK_INTEGRATION_JAVASCRIPT_PARAMS': settings.HELPDESK_INTEGRATION_JAVASCRIPT_PARAMS if hasattr(settings, 'HELPDESK_INTEGRATION_JAVASCRIPT_PARAMS') else '', 28 | 'VERSION': settings.SW_VERSION if hasattr(settings, 'SW_VERSION') else '', 29 | 'WEBSOCK_VNC_ENABLED': settings.WEBSOCK_VNC_ENABLED if hasattr(settings, 'WEBSOCK_VNC_ENABLED') else '', 30 | 'LEGACY_VNC_ENABLED': getattr(settings, 'LEGACY_VNC_ENABLED', ''), 31 | 'BRANDING': settings.BRANDING if hasattr(settings, 'BRANDING') else '', 32 | 'FLATPAGES': settings.FLATPAGES if hasattr(settings, 'FLATPAGES') else '', 33 | 'COLLECTD_URL': settings.COLLECTD_URL if hasattr(settings, 'COLLECTD_URL') else '' 34 | } 35 | -------------------------------------------------------------------------------- /context/pending_notifications.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | from apply.models import InstanceApplication, STATUS_PENDING 18 | from django.core.cache import cache 19 | 20 | 21 | def notify(request): 22 | res = {} 23 | if request.user: 24 | if request.user.has_perm("apply.change_instanceapplication"): 25 | res.update(can_handle_applications=True) 26 | elif request.user.has_perm("apply.view_applications"): 27 | res.update(can_view_applications=True) 28 | else: 29 | return res 30 | cres = cache.get('pendingapplications') 31 | if cres is None: 32 | pend = InstanceApplication.objects.filter(status=STATUS_PENDING) 33 | res.update(pending_count=pend.count()) 34 | cache.set('pendingapplications', res, 45) 35 | else: 36 | res = cres 37 | return res 38 | -------------------------------------------------------------------------------- /context/session_remaining.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf import settings 19 | import datetime 20 | 21 | 22 | def seconds(request): 23 | remaining = False 24 | if ( 25 | request.user.is_authenticated() and 26 | request.user.userprofile.force_logout_date and 27 | ( 28 | 'LAST_LOGIN_DATE' not in request.session or 29 | request.session['LAST_LOGIN_DATE'] < request.user.userprofile.force_logout_date 30 | ) 31 | ): 32 | remaining = 2 33 | if not request.user.is_anonymous(): 34 | if 'LAST_LOGIN_DATE' in request.session: 35 | last_login = request.session['LAST_LOGIN_DATE'] 36 | now = datetime.datetime.now() 37 | if now > last_login: 38 | elapsed = (now - last_login).seconds 39 | remaining = settings.SESSION_COOKIE_AGE - elapsed 40 | if remaining < 0: 41 | remaining = 2 42 | else: 43 | remaining = 2 44 | return {"session_remaining": remaining} 45 | -------------------------------------------------------------------------------- /contrib/CONTENTS: -------------------------------------------------------------------------------- 1 | 3rd party sources 2 | 3 | vnc_javasrc: the source used to build /static/javavnc/VncViewer.jar 4 | 5 | init.d: init script to start ganetimgr-watcher 6 | 7 | default: sample defaults file for ganetimgr-watcher (use with init script) 8 | -------------------------------------------------------------------------------- /contrib/default/ganetimgr-watcher: -------------------------------------------------------------------------------- 1 | RUN=yes 2 | -------------------------------------------------------------------------------- /contrib/fabric/requirements.txt: -------------------------------------------------------------------------------- 1 | Fabric==1.10.2 2 | -------------------------------------------------------------------------------- /contrib/fabric/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/contrib/fabric/utils/__init__.py -------------------------------------------------------------------------------- /contrib/fabric/utils/database.py: -------------------------------------------------------------------------------- 1 | from fabric.api import run 2 | from fabric.operations import sudo 3 | 4 | 5 | def dump_mysql(settings, target): 6 | try: 7 | sudo('mysqldump -u %s --password=%s %s -h %s -P %s > %s' % ( 8 | settings.get('USER'), 9 | settings.get('PASSWORD'), 10 | settings.get('NAME'), 11 | settings.get('HOST') or 'localhost', 12 | settings.get('PORT') or '13306', 13 | target 14 | )) 15 | except: 16 | return False 17 | else: 18 | return True 19 | 20 | 21 | def drop_mysql(settings): 22 | sudo("mysql -u %s --password=%s -h %s -P %s -e 'DROP DATABASE %s'" % ( 23 | settings.get('USER'), 24 | settings.get('PASSWORD'), 25 | settings.get('HOST') or 'localhost', 26 | settings.get('PORT') or '13306', 27 | settings.get('NAME') 28 | )) 29 | 30 | 31 | def create_mysql(settings): 32 | sudo("mysql -u %s --password=%s -h %s -P %s -e 'CREATE DATABASE %s'" % ( 33 | settings.get('USER'), 34 | settings.get('PASSWORD'), 35 | settings.get('HOST') or 'localhost', 36 | settings.get('PORT') or '13306', 37 | settings.get('NAME'), 38 | )) 39 | 40 | 41 | def import_mysql(settings, dump_path): 42 | run('mysql -u %s --password=%s -h %s -P %s %s < %s' % 43 | ( 44 | settings.get('USER'), 45 | settings.get('PASSWORD'), 46 | settings.get('HOST') or 'localhost', 47 | settings.get('PORT') or '13306', 48 | settings.get('NAME'), 49 | dump_path 50 | )) 51 | 52 | 53 | def recreate_mysql(settings): 54 | drop_mysql(settings) 55 | create_mysql(settings) 56 | -------------------------------------------------------------------------------- /contrib/fabric/utils/django.py: -------------------------------------------------------------------------------- 1 | from fabric.api import cd, run, prefix 2 | from utils.operations import try_to_execute 3 | from fabric.operations import sudo 4 | 5 | 6 | def collectstatic(path, venv=False): 7 | with cd(path): 8 | if venv: 9 | with prefix(venv): 10 | try_to_execute('./manage.py collectstatic --noinput') 11 | else: 12 | try_to_execute('./manage.py collectstatic --noinput') 13 | 14 | 15 | def clean_pyc(path): 16 | with cd(path): 17 | sudo('find -name "*.pyc" -delete') 18 | 19 | 20 | def db_config(settings): 21 | # grep the database settings from settings.py 22 | database_settings = run(" grep -A10 '\DATABASES = {' %s | grep -E 'NAME|ENGINE|PASSWO|HOST|PORT|USER'" % settings) 23 | db_settings = {} 24 | for s in database_settings.split('\n'): 25 | s = s.strip().split(',')[0].split(':') 26 | db_settings.update({s[0].split('\'')[1]: s[1].split('\'')[1]}) 27 | return db_settings 28 | -------------------------------------------------------------------------------- /contrib/fabric/utils/git.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from datetime import datetime 4 | 5 | from fabric.api import cd, run, abort 6 | from fabric.contrib.files import exists 7 | from fabric.operations import sudo 8 | 9 | 10 | def get_new_version(project_name, target, repository, tag): 11 | ''' 12 | Fetches selected tag and puts it under the selected 13 | directory 14 | ''' 15 | dir_name = '%s-%s' % (project_name, datetime.today().strftime('%Y%m%d%H%M')) 16 | with cd('/tmp'): 17 | # remove junk dirs 18 | if exists(project_name): 19 | run('rm -rf %s' % project_name) 20 | if exists(dir_name): 21 | run('rm -rf %s' % dir_name) 22 | # fresh clone 23 | run('git clone %s --quiet' % repository) 24 | with cd(project_name): 25 | try: 26 | # archive tag 27 | run('git archive --format=tar --prefix=%s/ %s | (cd /tmp/ && tar xf -) ' % (dir_name, tag)) 28 | except: 29 | abort('Make sure %s exists in the repository.' % tag) 30 | # rm cloned code 31 | run('rm -rf %s' % project_name) 32 | # move into the proper dir 33 | if exists(os.path.join(target, dir_name)): 34 | sudo('rm -r %s' % os.path.join(target, dir_name)) 35 | sudo('mv %s %s' % (dir_name, target)) 36 | return os.path.join(target, dir_name) 37 | -------------------------------------------------------------------------------- /contrib/fabric/utils/operations.py: -------------------------------------------------------------------------------- 1 | import os 2 | from fabric.api import run 3 | from fabric.contrib.files import exists 4 | from fabric.operations import sudo 5 | from fabric.context_managers import settings 6 | 7 | 8 | def get_real_path(project_dir, project): 9 | link = run('ls -la %s' % os.path.join(project_dir, project)) 10 | return link.split('-> ')[-1] 11 | 12 | 13 | def new_symlink(new_path, project_dir, project): 14 | if exists(os.path.join(project_dir, project)): 15 | sudo('rm %s' % os.path.join(project_dir, project)) 16 | sudo('ln -s %s %s' % (new_path, os.path.join(project_dir, project))) 17 | 18 | 19 | def try_to_execute(cmd): 20 | # in case of an error raises exception with 21 | # the error message 22 | with settings(warn_only=True): 23 | result = sudo(cmd) 24 | if result.failed: 25 | raise Exception(result.stdout) 26 | -------------------------------------------------------------------------------- /contrib/fabric/utils/services.py: -------------------------------------------------------------------------------- 1 | from fabric.operations import sudo 2 | 3 | 4 | def stop_beanstalk(): 5 | sudo('service beanstalkd stop') 6 | 7 | 8 | def start_beanstalk(): 9 | sudo('service beanstalkd start') 10 | 11 | 12 | def restart_beanstalk(): 13 | stop_beanstalk() 14 | start_beanstalk() 15 | 16 | 17 | def stop_redis(): 18 | sudo('service redis-server stop') 19 | 20 | 21 | def start_redis(): 22 | sudo('service redis-server start') 23 | 24 | 25 | def restart_redis(): 26 | stop_redis() 27 | start_redis() 28 | 29 | 30 | def stop_nginx(): 31 | sudo('/etc/init.d/nginx stop') 32 | 33 | 34 | def start_nginx(): 35 | sudo('/etc/init.d/nginx start') 36 | 37 | 38 | def restart_nginx(): 39 | stop_nginx() 40 | start_nginx() 41 | 42 | 43 | def stop_gunicorn(): 44 | sudo('/etc/init.d/gunicorn stop') 45 | 46 | 47 | def start_gunicorn(app=None): 48 | sudo('/etc/init.d/gunicorn start %s' % (app or '')) 49 | 50 | 51 | def restart_gunicorn(app=None): 52 | stop_gunicorn() 53 | start_gunicorn(app) 54 | 55 | 56 | def stop_uwsgi(app=None): 57 | sudo('/etc/init.d/uwsgi stop %s' % (app or '')) 58 | 59 | 60 | def start_uwsgi(app=None): 61 | sudo('/etc/init.d/uwsgi stop %s' % (app or '')) 62 | 63 | 64 | def restart_uwsgi(app=None): 65 | stop_uwsgi(app) 66 | start_uwsgi(app) 67 | -------------------------------------------------------------------------------- /contrib/gunicorn/ganetimgr_jessie: -------------------------------------------------------------------------------- 1 | CONFIG = { 2 | 'mode': 'wsgi', 3 | 'user': 'www-data', 4 | 'group': 'www-data', 5 | 'args': ( 6 | '--chdir=/srv/www/ganetimgr', 7 | '--bind=127.0.0.1:8088', 8 | '--workers=2', 9 | '--worker-class=gevent', 10 | '--timeout=30', 11 | '--log-file=/var/log/ganetimgr.log', 12 | 'ganetimgr.wsgi:application', 13 | ), 14 | } 15 | -------------------------------------------------------------------------------- /contrib/gunicorn/ganetimgr_wheezy: -------------------------------------------------------------------------------- 1 | CONFIG = { 2 | 'mode': 'django', 3 | 'working_dir': '/srv/ganetimgr', 4 | 'user': 'www-data', 5 | 'group': 'www-data', 6 | 'args': ( 7 | '--bind=127.0.0.1:8088', 8 | '--workers=2', 9 | '--worker-class=egg:gunicorn#gevent', 10 | '--timeout=30', 11 | '--log-file=/var/log/ganetimgr/ganetimgr.log', 12 | ), 13 | } 14 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.blind.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Blind @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Blind 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.blind = function(o) { 16 | 17 | return this.queue(function() { 18 | 19 | // Create element 20 | var el = $(this), props = ['position','top','bottom','left','right']; 21 | 22 | // Set options 23 | var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 24 | var direction = o.options.direction || 'vertical'; // Default direction 25 | 26 | // Adjust 27 | $.effects.save(el, props); el.show(); // Save & Show 28 | var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 29 | var ref = (direction == 'vertical') ? 'height' : 'width'; 30 | var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width(); 31 | if(mode == 'show') wrapper.css(ref, 0); // Shift 32 | 33 | // Animation 34 | var animation = {}; 35 | animation[ref] = mode == 'show' ? distance : 0; 36 | 37 | // Animate 38 | wrapper.animate(animation, o.duration, o.options.easing, function() { 39 | if(mode == 'hide') el.hide(); // Hide 40 | $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 41 | if(o.callback) o.callback.apply(el[0], arguments); // Callback 42 | el.dequeue(); 43 | }); 44 | 45 | }); 46 | 47 | }; 48 | 49 | })(jQuery); 50 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.clip.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Clip @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Clip 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.clip = function(o) { 16 | 17 | return this.queue(function() { 18 | 19 | // Create element 20 | var el = $(this), props = ['position','top','bottom','left','right','height','width']; 21 | 22 | // Set options 23 | var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 24 | var direction = o.options.direction || 'vertical'; // Default direction 25 | 26 | // Adjust 27 | $.effects.save(el, props); el.show(); // Save & Show 28 | var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 29 | var animate = el[0].tagName == 'IMG' ? wrapper : el; 30 | var ref = { 31 | size: (direction == 'vertical') ? 'height' : 'width', 32 | position: (direction == 'vertical') ? 'top' : 'left' 33 | }; 34 | var distance = (direction == 'vertical') ? animate.height() : animate.width(); 35 | if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift 36 | 37 | // Animation 38 | var animation = {}; 39 | animation[ref.size] = mode == 'show' ? distance : 0; 40 | animation[ref.position] = mode == 'show' ? 0 : distance / 2; 41 | 42 | // Animate 43 | animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 44 | if(mode == 'hide') el.hide(); // Hide 45 | $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 46 | if(o.callback) o.callback.apply(el[0], arguments); // Callback 47 | el.dequeue(); 48 | }}); 49 | 50 | }); 51 | 52 | }; 53 | 54 | })(jQuery); 55 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.drop.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Drop @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Drop 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.drop = function(o) { 16 | 17 | return this.queue(function() { 18 | 19 | // Create element 20 | var el = $(this), props = ['position','top','bottom','left','right','opacity']; 21 | 22 | // Set options 23 | var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 24 | var direction = o.options.direction || 'left'; // Default Direction 25 | 26 | // Adjust 27 | $.effects.save(el, props); el.show(); // Save & Show 28 | $.effects.createWrapper(el); // Create Wrapper 29 | var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 30 | var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 31 | var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2); 32 | if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift 33 | 34 | // Animation 35 | var animation = {opacity: mode == 'show' ? 1 : 0}; 36 | animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; 37 | 38 | // Animate 39 | el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 40 | if(mode == 'hide') el.hide(); // Hide 41 | $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 42 | if(o.callback) o.callback.apply(this, arguments); // Callback 43 | el.dequeue(); 44 | }}); 45 | 46 | }); 47 | 48 | }; 49 | 50 | })(jQuery); 51 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.fade.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Fade @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Fade 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.fade = function(o) { 16 | return this.queue(function() { 17 | var elem = $(this), 18 | mode = $.effects.setMode(elem, o.options.mode || 'hide'); 19 | 20 | elem.animate({ opacity: mode }, { 21 | queue: false, 22 | duration: o.duration, 23 | easing: o.options.easing, 24 | complete: function() { 25 | (o.callback && o.callback.apply(this, arguments)); 26 | elem.dequeue(); 27 | } 28 | }); 29 | }); 30 | }; 31 | 32 | })(jQuery); 33 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.fold.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Fold @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Fold 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.fold = function(o) { 16 | 17 | return this.queue(function() { 18 | 19 | // Create element 20 | var el = $(this), props = ['position','top','bottom','left','right']; 21 | 22 | // Set options 23 | var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode 24 | var size = o.options.size || 15; // Default fold size 25 | var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value 26 | var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2; 27 | 28 | // Adjust 29 | $.effects.save(el, props); el.show(); // Save & Show 30 | var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 31 | var widthFirst = ((mode == 'show') != horizFirst); 32 | var ref = widthFirst ? ['width', 'height'] : ['height', 'width']; 33 | var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()]; 34 | var percent = /([0-9]+)%/.exec(size); 35 | if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1]; 36 | if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift 37 | 38 | // Animation 39 | var animation1 = {}, animation2 = {}; 40 | animation1[ref[0]] = mode == 'show' ? distance[0] : size; 41 | animation2[ref[1]] = mode == 'show' ? distance[1] : 0; 42 | 43 | // Animate 44 | wrapper.animate(animation1, duration, o.options.easing) 45 | .animate(animation2, duration, o.options.easing, function() { 46 | if(mode == 'hide') el.hide(); // Hide 47 | $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 48 | if(o.callback) o.callback.apply(el[0], arguments); // Callback 49 | el.dequeue(); 50 | }); 51 | 52 | }); 53 | 54 | }; 55 | 56 | })(jQuery); 57 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.highlight.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Highlight @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Highlight 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.highlight = function(o) { 16 | return this.queue(function() { 17 | var elem = $(this), 18 | props = ['backgroundImage', 'backgroundColor', 'opacity'], 19 | mode = $.effects.setMode(elem, o.options.mode || 'show'), 20 | animation = { 21 | backgroundColor: elem.css('backgroundColor') 22 | }; 23 | 24 | if (mode == 'hide') { 25 | animation.opacity = 0; 26 | } 27 | 28 | $.effects.save(elem, props); 29 | elem 30 | .show() 31 | .css({ 32 | backgroundImage: 'none', 33 | backgroundColor: o.options.color || '#ffff99' 34 | }) 35 | .animate(animation, { 36 | queue: false, 37 | duration: o.duration, 38 | easing: o.options.easing, 39 | complete: function() { 40 | (mode == 'hide' && elem.hide()); 41 | $.effects.restore(elem, props); 42 | (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter')); 43 | (o.callback && o.callback.apply(this, arguments)); 44 | elem.dequeue(); 45 | } 46 | }); 47 | }); 48 | }; 49 | 50 | })(jQuery); 51 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.pulsate.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Pulsate @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Pulsate 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.pulsate = function(o) { 16 | return this.queue(function() { 17 | var elem = $(this), 18 | mode = $.effects.setMode(elem, o.options.mode || 'show'); 19 | times = ((o.options.times || 5) * 2) - 1; 20 | duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2, 21 | isVisible = elem.is(':visible'), 22 | animateTo = 0; 23 | 24 | if (!isVisible) { 25 | elem.css('opacity', 0).show(); 26 | animateTo = 1; 27 | } 28 | 29 | if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) { 30 | times--; 31 | } 32 | 33 | for (var i = 0; i < times; i++) { 34 | elem.animate({ opacity: animateTo }, duration, o.options.easing); 35 | animateTo = (animateTo + 1) % 2; 36 | } 37 | 38 | elem.animate({ opacity: animateTo }, duration, o.options.easing, function() { 39 | if (animateTo == 0) { 40 | elem.hide(); 41 | } 42 | (o.callback && o.callback.apply(this, arguments)); 43 | }); 44 | 45 | elem 46 | .queue('fx', function() { elem.dequeue(); }) 47 | .dequeue(); 48 | }); 49 | }; 50 | 51 | })(jQuery); 52 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.shake.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Shake @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Shake 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.shake = function(o) { 16 | 17 | return this.queue(function() { 18 | 19 | // Create element 20 | var el = $(this), props = ['position','top','bottom','left','right']; 21 | 22 | // Set options 23 | var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode 24 | var direction = o.options.direction || 'left'; // Default direction 25 | var distance = o.options.distance || 20; // Default distance 26 | var times = o.options.times || 3; // Default # of times 27 | var speed = o.duration || o.options.duration || 140; // Default speed per shake 28 | 29 | // Adjust 30 | $.effects.save(el, props); el.show(); // Save & Show 31 | $.effects.createWrapper(el); // Create Wrapper 32 | var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 33 | var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 34 | 35 | // Animation 36 | var animation = {}, animation1 = {}, animation2 = {}; 37 | animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance; 38 | animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2; 39 | animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2; 40 | 41 | // Animate 42 | el.animate(animation, speed, o.options.easing); 43 | for (var i = 1; i < times; i++) { // Shakes 44 | el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing); 45 | }; 46 | el.animate(animation1, speed, o.options.easing). 47 | animate(animation, speed / 2, o.options.easing, function(){ // Last shake 48 | $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 49 | if(o.callback) o.callback.apply(this, arguments); // Callback 50 | }); 51 | el.queue('fx', function() { el.dequeue(); }); 52 | el.dequeue(); 53 | }); 54 | 55 | }; 56 | 57 | })(jQuery); 58 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.slide.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Slide @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Slide 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.slide = function(o) { 16 | 17 | return this.queue(function() { 18 | 19 | // Create element 20 | var el = $(this), props = ['position','top','bottom','left','right']; 21 | 22 | // Set options 23 | var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode 24 | var direction = o.options.direction || 'left'; // Default Direction 25 | 26 | // Adjust 27 | $.effects.save(el, props); el.show(); // Save & Show 28 | $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper 29 | var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left'; 30 | var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg'; 31 | var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true})); 32 | if (mode == 'show') el.css(ref, motion == 'pos' ? (isNaN(distance) ? "-" + distance : -distance) : distance); // Shift 33 | 34 | // Animation 35 | var animation = {}; 36 | animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance; 37 | 38 | // Animate 39 | el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() { 40 | if(mode == 'hide') el.hide(); // Hide 41 | $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore 42 | if(o.callback) o.callback.apply(this, arguments); // Callback 43 | el.dequeue(); 44 | }}); 45 | 46 | }); 47 | 48 | }; 49 | 50 | })(jQuery); 51 | -------------------------------------------------------------------------------- /contrib/jquery-ui/jquery.effects.transfer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Effects Transfer @VERSION 3 | * 4 | * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Effects/Transfer 9 | * 10 | * Depends: 11 | * jquery.effects.core.js 12 | */ 13 | (function( $, undefined ) { 14 | 15 | $.effects.transfer = function(o) { 16 | return this.queue(function() { 17 | var elem = $(this), 18 | target = $(o.options.to), 19 | endPosition = target.offset(), 20 | animation = { 21 | top: endPosition.top, 22 | left: endPosition.left, 23 | height: target.innerHeight(), 24 | width: target.innerWidth() 25 | }, 26 | startPosition = elem.offset(), 27 | transfer = $('
') 28 | .appendTo(document.body) 29 | .addClass(o.options.className) 30 | .css({ 31 | top: startPosition.top, 32 | left: startPosition.left, 33 | height: elem.innerHeight(), 34 | width: elem.innerWidth(), 35 | position: 'absolute' 36 | }) 37 | .animate(animation, o.duration, o.options.easing, function() { 38 | transfer.remove(); 39 | (o.callback && o.callback.apply(elem[0], arguments)); 40 | elem.dequeue(); 41 | }); 42 | }); 43 | }; 44 | 45 | })(jQuery); 46 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/HTTPConnectSocket.java: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2002 Constantin Kaplinsky, Inc. All Rights Reserved. 3 | // 4 | // This is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This software is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this software; if not, write to the Free Software 16 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | // USA. 18 | // 19 | 20 | // 21 | // HTTPConnectSocket.java together with HTTPConnectSocketFactory.java 22 | // implement an alternate way to connect to VNC servers via one or two 23 | // HTTP proxies supporting the HTTP CONNECT method. 24 | // 25 | 26 | import java.net.*; 27 | import java.io.*; 28 | 29 | class HTTPConnectSocket extends Socket { 30 | 31 | public HTTPConnectSocket(String host, int port, 32 | String proxyHost, int proxyPort) 33 | throws IOException { 34 | 35 | // Connect to the specified HTTP proxy 36 | super(proxyHost, proxyPort); 37 | 38 | // Send the CONNECT request 39 | getOutputStream().write(("CONNECT " + host + ":" + port + 40 | " HTTP/1.0\r\n\r\n").getBytes()); 41 | 42 | // Read the first line of the response 43 | DataInputStream is = new DataInputStream(getInputStream()); 44 | String str = is.readLine(); 45 | 46 | // Check the HTTP error code -- it should be "200" on success 47 | if (!str.startsWith("HTTP/1.0 200 ")) { 48 | if (str.startsWith("HTTP/1.0 ")) 49 | str = str.substring(9); 50 | throw new IOException("Proxy reports \"" + str + "\""); 51 | } 52 | 53 | // Success -- skip remaining HTTP headers 54 | do { 55 | str = is.readLine(); 56 | } while (str.length() != 0); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: VncViewer 3 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Making the VNC applet. 3 | # 4 | 5 | CP = cp 6 | JC = javac 7 | JCFLAGS = -target 1.1 -source 1.2 8 | JAR = jar 9 | ARCHIVE = VncViewer.jar 10 | MANIFEST = MANIFEST.MF 11 | PAGES = index.vnc 12 | INSTALL_DIR = /usr/local/vnc/classes 13 | 14 | CLASSES = VncViewer.class RfbProto.class AuthPanel.class VncCanvas.class \ 15 | VncCanvas2.class \ 16 | OptionsFrame.class ClipboardFrame.class ButtonPanel.class \ 17 | DesCipher.class CapabilityInfo.class CapsContainer.class \ 18 | RecordingFrame.class SessionRecorder.class \ 19 | SocketFactory.class HTTPConnectSocketFactory.class \ 20 | HTTPConnectSocket.class ReloginPanel.class \ 21 | InStream.class MemInStream.class ZlibInStream.class 22 | 23 | SOURCES = VncViewer.java RfbProto.java AuthPanel.java VncCanvas.java \ 24 | VncCanvas2.java \ 25 | OptionsFrame.java ClipboardFrame.java ButtonPanel.java \ 26 | DesCipher.java CapabilityInfo.java CapsContainer.java \ 27 | RecordingFrame.java SessionRecorder.java \ 28 | SocketFactory.java HTTPConnectSocketFactory.java \ 29 | HTTPConnectSocket.java ReloginPanel.java \ 30 | InStream.java MemInStream.java ZlibInStream.java 31 | 32 | all: $(CLASSES) $(ARCHIVE) 33 | 34 | $(CLASSES): $(SOURCES) 35 | $(JC) $(JCFLAGS) -O $(SOURCES) 36 | 37 | $(ARCHIVE): $(CLASSES) $(MANIFEST) 38 | $(JAR) cfm $(ARCHIVE) $(MANIFEST) $(CLASSES) 39 | 40 | install: $(CLASSES) $(ARCHIVE) 41 | $(CP) $(CLASSES) $(ARCHIVE) $(PAGES) $(INSTALL_DIR) 42 | 43 | export:: $(CLASSES) $(ARCHIVE) $(PAGES) 44 | @$(ExportJavaClasses) 45 | 46 | clean:: 47 | $(RM) *.class *.jar 48 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/MemInStream.java: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. 2 | * 3 | * This is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This software is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this software; if not, write to the Free Software 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 16 | * USA. 17 | */ 18 | 19 | public class MemInStream extends InStream { 20 | 21 | public MemInStream(byte[] data, int offset, int len) { 22 | b = data; 23 | ptr = offset; 24 | end = offset + len; 25 | } 26 | 27 | public int pos() { return ptr; } 28 | 29 | protected int overrun(int itemSize, int nItems) throws Exception { 30 | throw new Exception("MemInStream overrun: end of stream"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/ReloginPanel.java: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2002 Cendio Systems. All Rights Reserved. 3 | // Copyright (C) 2002 Constantin Kaplinsky. All Rights Reserved. 4 | // 5 | // This is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 2 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This software is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this software; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18 | // USA. 19 | // 20 | 21 | // 22 | // ReloginPanel class implements panel with a button for logging in again, 23 | // after fatal errors or disconnect 24 | // 25 | 26 | 27 | import java.awt.*; 28 | import java.awt.event.*; 29 | import java.applet.*; 30 | 31 | // 32 | // The panel which implements the Relogin button 33 | // 34 | 35 | class ReloginPanel extends Panel implements ActionListener { 36 | Button reloginButton; 37 | Button closeButton; 38 | VncViewer viewer; 39 | 40 | // 41 | // Constructor. 42 | // 43 | public ReloginPanel(VncViewer v) { 44 | viewer = v; 45 | setLayout(new FlowLayout(FlowLayout.CENTER)); 46 | reloginButton = new Button("Login again"); 47 | add(reloginButton); 48 | reloginButton.addActionListener(this); 49 | if (viewer.inSeparateFrame) { 50 | closeButton = new Button("Close window"); 51 | add(closeButton); 52 | closeButton.addActionListener(this); 53 | } 54 | } 55 | 56 | // 57 | // This method is called when a button is pressed. 58 | // 59 | public synchronized void actionPerformed(ActionEvent evt) { 60 | if (viewer.inSeparateFrame) 61 | viewer.vncFrame.dispose(); 62 | if (evt.getSource() == reloginButton) 63 | viewer.getAppletContext().showDocument(viewer.getDocumentBase()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/SocketFactory.java: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2002 HorizonLive.com, Inc. All Rights Reserved. 3 | // 4 | // This is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This software is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this software; if not, write to the Free Software 16 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | // USA. 18 | // 19 | 20 | // 21 | // SocketFactory.java describes an interface used to substitute the 22 | // standard Socket class by its alternative implementations. 23 | // 24 | 25 | import java.applet.*; 26 | import java.net.*; 27 | import java.io.*; 28 | 29 | public interface SocketFactory { 30 | 31 | public Socket createSocket(String host, int port, Applet applet) 32 | throws IOException; 33 | 34 | public Socket createSocket(String host, int port, String[] args) 35 | throws IOException; 36 | } 37 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/VncCanvas2.java: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2006 Constantin Kaplinsky. All Rights Reserved. 3 | // 4 | // This is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 2 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This software is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this software; if not, write to the Free Software 16 | // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 | // USA. 18 | // 19 | 20 | import java.awt.*; 21 | import java.io.*; 22 | 23 | // 24 | // VncCanvas2 is a special version of VncCanvas which may use Java 2 API. 25 | // 26 | 27 | class VncCanvas2 extends VncCanvas { 28 | 29 | public VncCanvas2(VncViewer v) throws IOException { 30 | super(v); 31 | disableFocusTraversalKeys(); 32 | } 33 | 34 | public VncCanvas2(VncViewer v, int maxWidth_, int maxHeight_) 35 | throws IOException { 36 | 37 | super(v, maxWidth_, maxHeight_); 38 | disableFocusTraversalKeys(); 39 | } 40 | 41 | public void paintScaledFrameBuffer(Graphics g) { 42 | Graphics2D g2d = (Graphics2D)g; 43 | g2d.setRenderingHint(RenderingHints.KEY_RENDERING, 44 | RenderingHints.VALUE_RENDER_QUALITY); 45 | g2d.drawImage(memImage, 0, 0, scaledWidth, scaledHeight, null); 46 | } 47 | 48 | // 49 | // Try to disable focus traversal keys (JVMs 1.4 and higher). 50 | // 51 | 52 | private void disableFocusTraversalKeys() { 53 | try { 54 | Class[] argClasses = { Boolean.TYPE }; 55 | java.lang.reflect.Method method = 56 | getClass().getMethod("setFocusTraversalKeysEnabled", argClasses); 57 | Object[] argObjects = { new Boolean(false) }; 58 | method.invoke(this, argObjects); 59 | } catch (Exception e) {} 60 | } 61 | 62 | } 63 | 64 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/index.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | TightVNC desktop 22 | 23 | 25 | 26 | 27 |
28 | TightVNC site 29 | 30 | -------------------------------------------------------------------------------- /contrib/vnc_javasrc/index.vnc: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | $USER's $DESKTOP desktop ($DISPLAY) 17 | 18 | 20 | 21 | $PARAMS 22 | 23 |
24 | TightVNC site 25 | 26 | -------------------------------------------------------------------------------- /docs/source/_static/images/applications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/applications.png -------------------------------------------------------------------------------- /docs/source/_static/images/audit-log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/audit-log.png -------------------------------------------------------------------------------- /docs/source/_static/images/cluster_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/cluster_info.png -------------------------------------------------------------------------------- /docs/source/_static/images/ganetimgr_create_instance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ganetimgr_create_instance.png -------------------------------------------------------------------------------- /docs/source/_static/images/graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/graphs.png -------------------------------------------------------------------------------- /docs/source/_static/images/history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/history.png -------------------------------------------------------------------------------- /docs/source/_static/images/image00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/image00.png -------------------------------------------------------------------------------- /docs/source/_static/images/image01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/image01.png -------------------------------------------------------------------------------- /docs/source/_static/images/image02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/image02.png -------------------------------------------------------------------------------- /docs/source/_static/images/image03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/image03.png -------------------------------------------------------------------------------- /docs/source/_static/images/image04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/image04.png -------------------------------------------------------------------------------- /docs/source/_static/images/instance-owners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/instance-owners.png -------------------------------------------------------------------------------- /docs/source/_static/images/instance_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/instance_details.png -------------------------------------------------------------------------------- /docs/source/_static/images/jobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/jobs.png -------------------------------------------------------------------------------- /docs/source/_static/images/node_groups.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/node_groups.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_01_main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_01_main.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_02_user_main_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_02_user_main_view.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_03_user_statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_03_user_statistics.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_04_user_profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_04_user_profile.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_05_user_application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_05_user_application.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_06_vm_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_06_vm_info.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_07_vm_graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_07_vm_graphs.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_08_vm_conf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_08_vm_conf.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_09_vm_actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_09_vm_actions.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_10_admin_node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_10_admin_node.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_11_admin_stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_11_admin_stats.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_12_admin_jobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_12_admin_jobs.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_14_admin_application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_14_admin_application.png -------------------------------------------------------------------------------- /docs/source/_static/images/ss_15_admin_mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/docs/source/_static/images/ss_15_admin_mail.png -------------------------------------------------------------------------------- /docs/source/devel.rst: -------------------------------------------------------------------------------- 1 | ************************* 2 | Development documentation 3 | ************************* 4 | 5 | The following instructions are meant *only* for developers. Do NOT use them to setup a production ganetimgr service. 6 | 7 | python packages 8 | ############### 9 | 10 | A requirements.txt file is included in order to help you install the required python dependencies. 11 | You can do that by running:: 12 | 13 | pip install -r requirements.txt 14 | 15 | How to update/test 16 | ################## 17 | 18 | We have created a fabric sript in order to set up and deploy ganetimgr. It is included under "contrib/fabric/". One can use it by running:: 19 | 20 | fab deploy:tag='v1.6.0' -H ganetimgr.example.com -u user 21 | 22 | You will need to have fabric installed though. 23 | 24 | This scrip will connect to the specified server and try to set up ganetimgr under "/srv/ganetimgr" which will be a symlink to the actual directory. 25 | 26 | In general it performs the following steps: 27 | 28 | - stop redis, beanstalk, touch "/srv/maintenance.on" 29 | - git clone, git archive under "/tmp" and move to "/srv/ganetimgr" 30 | - check if there is an old installation under /srv/ganetimgr and get all the dist files in order to compare them with the newer version 31 | - create a buckup of the database 32 | - If no differences have been found between the two versions of ganetimgr, the old configuration files (whatever has also a dist file) will be copied to the new installation. 33 | - "/srv/ganetimgr" will be point to the new installation 34 | - management commands (migrate, collectstatic) will be run 35 | - fabric will ask your permission to remove old installations 36 | - restart nginx, gunicorn, redis, beanstalk, rm "maintenance.on" 37 | - in case something goes wrong it will try to make a rollback 38 | - in case no older installations exist or the dist files, it will ask you to log in the server and edit the settings, while waiting for your input. 39 | -------------------------------------------------------------------------------- /docs/source/patches.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Ganeti Modifications 3 | ==================== 4 | 5 | For the time being, ganetimgr requires using some patched ganeti packages to enable all ganetimgr's features. We are working on merging those changes upstream so that it works on vanilla software. 6 | The following software needs to be installed on the ganeti nodes/clusters. 7 | 8 | .. note:: 9 | All patches that enabled special ganetimgr's features have been merged upstream since Ganeti 2.12. If you're using Ganeti 2.12 or newer you 10 | don't need a patched ganeti any more. 11 | 12 | Repository 13 | ---------- 14 | 15 | We provide Debian packages for all the different software listed here. To get them you need to use our public repository. 16 | 17 | Add our repository to your sources.list:: 18 | 19 | echo 'deb http://repo.noc.grnet.gr/ wheezy main backports' > /etc/apt/sources.list.d/grnet.list 20 | 21 | Add our gpg key to apt's keyring:: 22 | 23 | wget -O - http://repo.noc.grnet.gr/grnet.gpg.key| apt-key add - 24 | 25 | And refresh the package list to discover the new packages:: 26 | 27 | apt-get update 28 | 29 | 30 | ganeti-instance-image 31 | --------------------- 32 | 33 | This is a forked version of the [ganeti-instance-image](https://code.osuosl.org/projects/ganeti-image) OS provider written by UOSL:: 34 | 35 | apt-get install ganeti-instance-image 36 | 37 | 38 | It uses the Ganeti OS API v20 to specify runtime osparams so we can specify the instance os during instance creation. It also injects the ssh key of the user inside the instance. 39 | The code from which the package is built can be found [here](https://github.com/grnet/ganeti-instance-image). 40 | You can find a sample Debian 7 Wheezy image [here](http://repo.noc.grnet.gr/debian-wheezy-x86_64.tgz) 41 | 42 | 43 | Ganeti 44 | ------ 45 | .. note:: 46 | This feature has been merged upstream since Ganeti version 2.12. 47 | 48 | If you want to use the ``boot from url`` feature of ganetimgr, you will need our ganeti package:: 49 | 50 | apt-get install ganeti ganeti-htools 51 | 52 | Our package version has *+grnet* appended to the version string. 53 | -------------------------------------------------------------------------------- /ganeti/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/ganeti/__init__.py -------------------------------------------------------------------------------- /ganeti/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.contrib import admin 19 | from models import Cluster, Network, InstanceAction 20 | 21 | 22 | def enable(modeladmin, request, queryset): 23 | queryset.update(disabled=False) 24 | enable.short_description = "Enable clusters" 25 | 26 | 27 | def disable(modeladmin, request, queryset): 28 | queryset.update(disabled=True) 29 | 30 | disable.short_description = "Disable clusters" 31 | 32 | 33 | class ClusterAdmin(admin.ModelAdmin): 34 | list_display = ('hostname', 'description', 'disabled') 35 | list_editable = ('disabled',) 36 | prepopulated_fields = {'slug': ('hostname',)} 37 | exclude = ('fast_create', 'use_gnt_network') 38 | actions = [enable, disable] 39 | search_fields = ('hostname', 'slug', 'description') 40 | 41 | 42 | class NetworkAdmin(admin.ModelAdmin): 43 | list_display = ( 44 | 'description', 45 | 'cluster', 46 | 'cluster_default', 47 | 'mode', 48 | 'link' 49 | ) 50 | list_filter = ('cluster',) 51 | 52 | 53 | class InstanceActionAdmin(admin.ModelAdmin): 54 | list_display = ( 55 | 'instance', 56 | 'cluster', 57 | 'action', 58 | 'action_value', 59 | 'activation_key' 60 | ) 61 | list_filter = ('instance',) 62 | 63 | admin.site.register(Cluster, ClusterAdmin) 64 | admin.site.register(Network, NetworkAdmin) 65 | admin.site.register(InstanceAction, InstanceActionAdmin) 66 | 67 | -------------------------------------------------------------------------------- /ganeti/fixtures/flatpages.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pk": 5, 4 | "model": "flatpages.flatpage", 5 | "fields": { 6 | "registration_required": true, 7 | "title": "Frequently Asked Questions", 8 | "url": "/about/faq/el/", 9 | "template_name": "flatpages/faq.html", 10 | "sites": [ 11 | 1 12 | ], 13 | "content": "FAQ placeholder", 14 | "enable_comments": false 15 | } 16 | }, 17 | { 18 | "pk": 6, 19 | "model": "flatpages.flatpage", 20 | "fields": { 21 | "registration_required": true, 22 | "title": "Frequently Asked Questions", 23 | "url": "/about/faq/en/", 24 | "template_name": "flatpages/faq.html", 25 | "sites": [ 26 | 1 27 | ], 28 | "content": "FAQ placeholder", 29 | "enable_comments": false 30 | } 31 | }, 32 | { 33 | "pk": 4, 34 | "model": "flatpages.flatpage", 35 | "fields": { 36 | "registration_required": false, 37 | "title": "Info Title placeholder", 38 | "url": "/about/info/el/", 39 | "template_name": "", 40 | "sites": [ 41 | 1 42 | ], 43 | "content": "

ganetimgr info page

", 44 | "enable_comments": false 45 | } 46 | }, 47 | { 48 | "pk": 3, 49 | "model": "flatpages.flatpage", 50 | "fields": { 51 | "registration_required": false, 52 | "title": "Info Title placeholder", 53 | "url": "/about/info/en/", 54 | "template_name": "", 55 | "sites": [ 56 | 1 57 | ], 58 | "content": "

ganetimgr info page

", 59 | "enable_comments": false 60 | } 61 | }, 62 | { 63 | "pk": 1, 64 | "model": "flatpages.flatpage", 65 | "fields": { 66 | "registration_required": false, 67 | "title": "ToS placeholer", 68 | "url": "/about/terms-of-service/el/", 69 | "template_name": "", 70 | "sites": [ 71 | 1 72 | ], 73 | "content": "

ganetimgr ToS page

", 74 | "enable_comments": false 75 | } 76 | }, 77 | { 78 | "pk": 2, 79 | "model": "flatpages.flatpage", 80 | "fields": { 81 | "registration_required": false, 82 | "title": "ToS placeholer", 83 | "url": "/about/terms-of-service/en/", 84 | "template_name": "", 85 | "sites": [ 86 | 1 87 | ], 88 | "content": "

ganetimgr ToS page

", 89 | "enable_comments": false 90 | } 91 | } 92 | ] -------------------------------------------------------------------------------- /ganeti/management/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/ganeti/management/__init__.py -------------------------------------------------------------------------------- /ganeti/management/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/ganeti/management/commands/__init__.py -------------------------------------------------------------------------------- /ganeti/management/commands/refresh_cluster_instances.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | from django.core.management.base import BaseCommand 4 | from ganeti.models import Cluster 5 | 6 | 7 | logger = logging.getLogger('refresh_logger') 8 | 9 | 10 | class Command(BaseCommand): 11 | help = "Updates cache cluster instances for specific/all clusters" 12 | 13 | @staticmethod 14 | def add_arguments(parser): 15 | parser.add_argument("clusters", nargs="*") 16 | parser.add_argument("seconds", nargs="?", type=int) 17 | 18 | @staticmethod 19 | def fetch_clusters(cluster_hostnames=None): 20 | if not cluster_hostnames: 21 | return Cluster.objects.all() 22 | return Cluster.objects.filter(hostname__in=cluster_hostnames) 23 | 24 | @staticmethod 25 | def refresh(cluster, seconds): 26 | if seconds: 27 | cluster.refresh_instances(seconds=seconds) 28 | cluster.refresh_nodes(seconds=seconds) 29 | else: 30 | cluster.refresh_instances() 31 | cluster.refresh_nodes() 32 | 33 | def handle(self, *args, **options): 34 | exit_code = 0 35 | for cluster in self.fetch_clusters(options.get("clusters")): 36 | print("Refreshing cache for cluster: {0}".format(cluster)) 37 | try: 38 | self.refresh(cluster, options.get("seconds")) 39 | except Exception as err: 40 | logger.info("Error while refreshing cache for cluster {0}: {1}" 41 | .format(cluster, err)) 42 | exit_code = 1 43 | 44 | sys.exit(exit_code) 45 | -------------------------------------------------------------------------------- /ganeti/migrations/0002_custompermission.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ganeti', '0001_initial'), 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='CustomPermission', 16 | fields=[ 17 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 18 | ], 19 | options={ 20 | 'managed': False, 21 | 'permissions': (('view_all_graphs', 'Can view all graphs'),), 22 | }, 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /ganeti/migrations/0003_auto_20170807_1459.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | 6 | 7 | class Migration(migrations.Migration): 8 | 9 | dependencies = [ 10 | ('ganeti', '0002_custompermission'), 11 | ] 12 | 13 | operations = [ 14 | migrations.AlterModelOptions( 15 | name='custompermission', 16 | options={'managed': False, 'permissions': (('view_all_graphs', 'Can view all graphs'), ('can_isolate', 'Can Isolate'), ('can_lock', 'Can Lock'))}, 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /ganeti/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/ganeti/migrations/__init__.py -------------------------------------------------------------------------------- /ganeti/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/ganeti/templatetags/__init__.py -------------------------------------------------------------------------------- /ganeti/templatetags/applicationstatus.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django import template 19 | 20 | register = template.Library() 21 | 22 | 23 | @register.filter 24 | def appstatus(value): 25 | if value == "pending": 26 | return "info" 27 | if value == "approved": 28 | return "success" 29 | if value == "failed": 30 | return "important" 31 | if value == "refused": 32 | return "warning" 33 | return "info" 34 | -------------------------------------------------------------------------------- /ganeti/templatetags/bootstrappercent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django import template 19 | 20 | register = template.Library() 21 | 22 | 23 | @register.filter 24 | def perctobootstrap(value): 25 | if value < 50: 26 | return "success" 27 | if value >= 50 and value < 80: 28 | return "warning" 29 | if value >= 80: 30 | return "danger" 31 | 32 | 33 | @register.filter 34 | def perctobootstrapbadge(value): 35 | if value < 50: 36 | return "success" 37 | if value >= 50 and value < 80: 38 | return "warning" 39 | if value >= 80: 40 | return "important" 41 | -------------------------------------------------------------------------------- /ganeti/templatetags/days_since.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django import template 19 | register = template.Library() 20 | 21 | import datetime 22 | 23 | @register.filter(name='days_since') 24 | def days_since(value): 25 | since = 0 26 | try: 27 | since = (datetime.datetime.now() - value).days 28 | except: 29 | pass 30 | return since -------------------------------------------------------------------------------- /ganeti/templatetags/disksizes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django import template 19 | from django.template.defaultfilters import filesizeformat 20 | 21 | register = template.Library() 22 | 23 | @register.filter 24 | def disksizes(value): 25 | return [filesizeformat(v * 1024**2) for v in value] 26 | 27 | @register.filter 28 | def memsize(value): 29 | return filesizeformat(value * 1024**2) 30 | -------------------------------------------------------------------------------- /ganeti/templatetags/noderole.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django import template 19 | 20 | register = template.Library() 21 | 22 | @register.filter 23 | def noderole(value): 24 | if value == "M": 25 | return "Master" 26 | if value == "C": 27 | return "Candidate" 28 | if value == "R": 29 | return "Regular" 30 | if value == "D": 31 | return "Drained" 32 | if value == "O": 33 | return "Offline" 34 | 35 | @register.filter 36 | def nodelabel(value): 37 | if value == "M": 38 | return "success" 39 | if value == "C": 40 | return "info" 41 | if value == "R": 42 | return "" 43 | if value == "D": 44 | return "warning" 45 | if value == "O": 46 | return "important" 47 | -------------------------------------------------------------------------------- /ganeti/templatetags/truncatedchars.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django import template 19 | 20 | register = template.Library() 21 | 22 | @register.filter 23 | # truncate after a certain number of characters 24 | def truncchar(value, arg): 25 | if len(value) < arg: 26 | return value 27 | else: 28 | return value[:arg] + '...' 29 | -------------------------------------------------------------------------------- /ganeti/urls/__init__.py: -------------------------------------------------------------------------------- 1 | # proxy 2 | from graphs import * 3 | from instances import * 4 | from jobs import * 5 | from nodegroup import * 6 | from clusters import * 7 | -------------------------------------------------------------------------------- /ganeti/urls/clusters.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from ganeti import views 20 | 21 | urlpatterns = [ 22 | # this view lives in jobs.py 23 | url(r'^jobdetails/?$', views.job_details, name="jobdets-popup"), 24 | url(r'^popup/?', views.instance_popup, name="instance-popup"), 25 | url(r'^nodes/$', views.get_clusternodes, name="cluster-nodes"), 26 | url(r'^nodes/pjax/$', views.get_clusternodes_pjax, name="cluster-nodes-pjax"), 27 | url(r'^jnodes/(?P[0-9]+)/$', views.clusternodes_json, name="cluster-nodes-json"), 28 | url(r'^jnodes/$', views.clusternodes_json, name="cluster-nodes-json"), 29 | url(r'^instance/destreinst/(?P\w+)/(?P\d+)/$', views.reinstalldestreview, name='reinstall-destroy-review'), 30 | url(r'^detail/$', views.clusterdetails, name="clusterdetails"), 31 | url(r'^detail/json/$', views.clusterdetails_json, name="clusterdetails_json"), 32 | 33 | ] 34 | -------------------------------------------------------------------------------- /ganeti/urls/graphs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from ganeti import views 20 | 21 | urlpatterns = [ 22 | url(r'^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)(/(?P[\\:\w\d\s\.+-]+),(?P[\\:\w\d\s\.+-]+))?(/(?Peth\d+))?$', views.graph, name='graph'), 23 | url(r'^all/$', views.cluster_nodes_graphs, name="cluster-get-nodes-graphs"), 24 | url(r'^(?P[^/]+)/instances/$', views.cluster_nodes_graphs, name="cluster-get-nodes-graphs"), 25 | ] 26 | -------------------------------------------------------------------------------- /ganeti/urls/instances.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | 20 | from ganeti import views 21 | 22 | urlpatterns = [ 23 | url(r'^list/$', views.list_user_instances, name='instances-list'), 24 | url(r'^tags/(?P[^/]+)?$', views.tagInstance, name="instance-tags"), 25 | url(r'^json/$', views.user_index_json, name="user-instances-json"), 26 | url(r'^stats/json/$', views.user_sum_stats, name="user-stats-json"), 27 | url(r'^lock/(?P[^/]+)?$', views.lock, name="lock"), 28 | url(r'^isolate/(?P[^/]+)?$', views.isolate, name="isolate"), 29 | url(r'^(?P[^/]+)/(?P[^/]+)/poll/?$', views.poll, name="instance-poll"), 30 | url(r'^(?P[^/]+)/(?P[^/]+)/vnc/?$', views.vnc, name="instance-vnc"), 31 | url(r'^(?P[^/]+)/(?P[^/]+)/novnc/?$', views.novnc, name="instance-novnc"), 32 | url(r'^(?P[^/]+)/(?P[^/]+)/novnc-proxy/?$', views.novnc_proxy, name="instance-novnc-proxy"), 33 | url(r'^(?P[^/]+)/(?P[^/]+)/shutdown/?$', views.shutdown, name="instance-shutdown"), 34 | url(r'^(?P[^/]+)/(?P[^/]+)/startup/?$', views.startup, name="instance-startup"), 35 | url(r'^(?P[^/]+)/(?P[^/]+)/reboot/?$', views.reboot, name="instance-reboot"), 36 | url(r'^(?P[^/]+)/(?P[^/]+)/reinstalldestroy/?$', views.destroy, name="instance-destroy"), 37 | url(r'^(?P[^/]+)/(?P[^/]+)/reinstall/?$', views.reinstall, name="instance-reinstall"), 38 | url(r'^(?P[^/]+)/(?P[^/]+)/rename/?$', views.rename_instance, name="instance-rename"), 39 | url(r'^(?P[^/]+)/(?P[^/]+)/?', views.instance, name="instance-detail"), 40 | ] 41 | -------------------------------------------------------------------------------- /ganeti/urls/jobs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from ganeti import views 20 | 21 | urlpatterns = [ 22 | url(r'^json/$', views.jobs_index_json, name="jobs_json"), 23 | url(r'^$', views.jobs, name="jobs"), 24 | ] 25 | -------------------------------------------------------------------------------- /ganeti/urls/nodegroup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from ganeti import views 20 | 21 | urlpatterns = [ 22 | url(r'^fromnet/$', views.get_nodegroups_fromnet, name='ng_from_net'), 23 | url(r'^cluster/$', views.get_cluster_node_group_stack, name='cluster_ng_stack'), 24 | 25 | ] 26 | -------------------------------------------------------------------------------- /ganeti/views/discovery.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | from ganeti.decorators import ajax_required 18 | from django.http import HttpResponse 19 | from ganeti.utils import operating_systems 20 | 21 | 22 | @ajax_required 23 | def get_operating_systems(request): 24 | return HttpResponse(operating_systems()) 25 | 26 | -------------------------------------------------------------------------------- /ganeti/views/nodegroup.py: -------------------------------------------------------------------------------- 1 | import json 2 | from django.http import HttpResponse, HttpResponseBadRequest, Http404 3 | from django.contrib.auth.decorators import permission_required 4 | from django.contrib import messages 5 | from django.shortcuts import get_object_or_404 6 | from ganeti.models import Network, Cluster 7 | from ganeti.utils import prepare_cluster_node_group_stack, format_ganeti_api_error 8 | from util.client import GanetiApiError 9 | 10 | 11 | @permission_required("apply.change_instanceapplication") 12 | def get_nodegroups_fromnet(request): 13 | network_id = request.GET.get('network_id') 14 | if network_id: 15 | try: 16 | cluster = Network.objects.get(pk=network_id).cluster 17 | except Network.DoesNotExist: 18 | raise Http404 19 | else: 20 | return HttpResponseBadRequest() 21 | nodegroups = cluster.get_node_groups() 22 | nodegroups_list = [] 23 | for g in nodegroups: 24 | nodeg_dict = {} 25 | nodeg_dict['name'] = g['name'] 26 | nodegroups_list.append(nodeg_dict) 27 | return HttpResponse(json.dumps(nodegroups_list), content_type='application/json') 28 | 29 | 30 | @permission_required("apply.change_instanceapplication") 31 | def get_cluster_node_group_stack(request): 32 | res = '' 33 | error = None 34 | cluster_id = request.GET.get('cluster_id', None) 35 | if cluster_id: 36 | cluster = get_object_or_404(Cluster, pk=cluster_id) 37 | else: 38 | return HttpResponseBadRequest() 39 | 40 | try: 41 | res = prepare_cluster_node_group_stack(cluster) 42 | except GanetiApiError as e: 43 | error = format_ganeti_api_error(e) 44 | except Exception as e: 45 | error = e 46 | if error: 47 | messages.add_message(request, messages.ERROR, error) 48 | return HttpResponse(json.dumps(res), content_type='application/json') 49 | -------------------------------------------------------------------------------- /ganetimgr/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/ganetimgr/__init__.py -------------------------------------------------------------------------------- /ganetimgr/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ganetimgrw project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ganetimgr.settings") 19 | 20 | # This application object is used by any WSGI server configured to use this 21 | # file. This includes Django's development server, if the WSGI_APPLICATION 22 | # setting points here. 23 | from django.core.wsgi import get_wsgi_application 24 | application = get_wsgi_application() 25 | 26 | # Apply WSGI middleware here. 27 | # from helloworld.wsgi import HelloWorldApplication 28 | # application = HelloWorldApplication(application) 29 | -------------------------------------------------------------------------------- /locale/el/LC_MESSAGES/django.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/locale/el/LC_MESSAGES/django.mo -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 3 | # Copyright (C) 2010-2014 GRNET S.A. 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | import os 20 | import sys 21 | 22 | if __name__ == "__main__": 23 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ganetimgr.settings") 24 | 25 | from gevent import monkey 26 | monkey.patch_all() 27 | from django.core.management import execute_from_command_line 28 | 29 | execute_from_command_line(sys.argv) 30 | -------------------------------------------------------------------------------- /middleware/ForceLogout.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.contrib.auth import logout 19 | 20 | 21 | class ForceLogoutMiddleware(object): 22 | def process_request(self, request): 23 | if ( 24 | request.user.is_authenticated() and 25 | request.user.userprofile.force_logout_date and 26 | ( 27 | 'LAST_LOGIN_DATE' not in request.session or 28 | request.session['LAST_LOGIN_DATE'] < request.user.userprofile.force_logout_date 29 | ) 30 | ): 31 | logout(request) 32 | -------------------------------------------------------------------------------- /middleware/UserMessages.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.contrib import messages 19 | from django.utils.translation import ugettext as _ 20 | from django.core.urlresolvers import reverse 21 | from django.utils.safestring import mark_safe 22 | from django.core.exceptions import ObjectDoesNotExist 23 | 24 | from accounts.models import UserProfile 25 | 26 | 27 | class UserMessageMiddleware(object): 28 | """ 29 | Middleware to display various messages to the users. 30 | """ 31 | 32 | def process_request(self, request): 33 | if not hasattr(request, "session"): 34 | return 35 | 36 | if request.user.is_authenticated(): 37 | try: 38 | first_login = request.session["first_login"] 39 | except KeyError: 40 | try: 41 | profile = request.user.userprofile 42 | except ObjectDoesNotExist: 43 | profile = UserProfile.objects.create(user=request.user) 44 | first_login = profile.first_login 45 | request.session["first_login"] = first_login 46 | 47 | if first_login: 48 | messages.add_message( 49 | request, 50 | messages.INFO, 51 | mark_safe( 52 | _( 53 | "Welcome! Please take some time to" 54 | " update your profile" 55 | " and upload your SSH keys." 56 | ) % reverse("profile") 57 | ) 58 | ) 59 | profile = request.user.userprofile 60 | profile.first_login = False 61 | profile.save() 62 | request.session["first_login"] = False 63 | -------------------------------------------------------------------------------- /middleware/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/middleware/__init__.py -------------------------------------------------------------------------------- /notifications/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/notifications/__init__.py -------------------------------------------------------------------------------- /notifications/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from notifications.models import NotificationArchive 3 | 4 | 5 | class NotificationArchiveAdmin(admin.ModelAdmin): 6 | list_display = ('subject', 'sender', 'date', ) 7 | 8 | admin.site.register(NotificationArchive, NotificationArchiveAdmin) 9 | -------------------------------------------------------------------------------- /notifications/forms.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | from django import forms 18 | from django.utils.translation import ugettext_lazy 19 | from django.contrib.auth.models import User 20 | from notifications.models import NotificationArchive 21 | from notifications.utils import get_mails 22 | 23 | 24 | TYPE_CHOICES = ( 25 | ('cluster', 'clusters'), 26 | ('nodes', 'nodes'), 27 | ('nodegroups', 'nodegroups'), 28 | ('users', 'users'), 29 | ('groups', 'groups'), 30 | ('instances', 'instances') 31 | ) 32 | 33 | 34 | class MessageForm(forms.Form): 35 | search_for = forms.ChoiceField( 36 | label=ugettext_lazy("Search for"), 37 | choices=TYPE_CHOICES 38 | ) 39 | subject = forms.CharField(max_length=100, label=ugettext_lazy("Subject")) 40 | message = forms.CharField( 41 | widget=forms.Textarea, 42 | label=ugettext_lazy("Body"), 43 | help_text='You can use {% for i in instances %} {{ i }} {% endfor %} if you want to use the body as a mail template.' 44 | ) 45 | recipient_list = forms.CharField(label=ugettext_lazy("Recipients")) 46 | 47 | def add_to_archive(self, user): 48 | if self.is_valid(): 49 | notification = NotificationArchive( 50 | subject=self.cleaned_data['subject'], 51 | message=self.cleaned_data['message'], 52 | sender=user 53 | ) 54 | notification.save() 55 | mail_list = get_mails(self.cleaned_data['recipient_list'].split(',')) 56 | for user in User.objects.filter(email__in=mail_list): 57 | notification.recipients.add(user) 58 | notification.save() 59 | -------------------------------------------------------------------------------- /notifications/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models, migrations 5 | from django.conf import settings 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 12 | ] 13 | 14 | operations = [ 15 | migrations.CreateModel( 16 | name='NotificationArchive', 17 | fields=[ 18 | ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), 19 | ('subject', models.CharField(max_length=255)), 20 | ('message', models.TextField()), 21 | ('date', models.DateTimeField(auto_now_add=True)), 22 | ('recipients', models.ManyToManyField(related_name='notifications', to=settings.AUTH_USER_MODEL)), 23 | ('sender', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True)), 24 | ], 25 | options={ 26 | 'ordering': ['-date'], 27 | 'permissions': (('can_view_notif', 'Can view all notifications'),), 28 | }, 29 | ), 30 | ] 31 | -------------------------------------------------------------------------------- /notifications/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/notifications/migrations/__init__.py -------------------------------------------------------------------------------- /notifications/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | from django.core.urlresolvers import reverse 4 | 5 | 6 | class NotificationArchive(models.Model): 7 | recipients = models.ManyToManyField(User, related_name='notifications') 8 | subject = models.CharField(max_length=255) 9 | message = models.TextField() 10 | date = models.DateTimeField(auto_now_add=True) 11 | sender = models.ForeignKey(User, blank=True, null=True) 12 | 13 | def __unicode__(self): 14 | return self.subject 15 | 16 | def get_absolute_url(self): 17 | return reverse('notification-details', kwargs={'notification': self.pk}) 18 | 19 | class Meta(): 20 | ordering = ['-date'] 21 | permissions = ( 22 | ("can_view_notif", "Can view all notifications"), 23 | ) 24 | -------------------------------------------------------------------------------- /notifications/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from notifications import views 20 | 21 | urlpatterns = [ 22 | url(r'^usergrps/$', views.get_user_group_list, name="usergroups"), 23 | url(r'^(?P[^/]+)/$', views.notify, name="notify"), 24 | url(r'^archive/(?P\w+)/$', views.archive, name="notification-details"), 25 | url(r'^$', views.notify, name="notify"), 26 | ] 27 | -------------------------------------------------------------------------------- /readthedocs-requirements.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ## dependencies for the ganetimgr project 2 | django==1.11 3 | # we target the latest LTS release 4 | gevent==1.1.2 5 | # gevent is used to pool cluster RAPI communication 6 | django-registration-redux==2.4 7 | # used for our registration workflow 8 | paramiko==2.0.0 9 | # used for user SSH key management 10 | python-daemon==2.1.2 11 | # used by watcher 12 | setproctitle==1.1.10 13 | # used by watcher to set it's process name 14 | pycurl==7.43.0 15 | # depenency for ganeti client library 16 | django-nocaptcha-recaptcha==0.0.20 17 | # used in the registration form 18 | ipaddr==2.1.11 19 | # used to calculate Instance ipv6addresses 20 | beautifulsoup4==4.5.3 21 | # used by the image autodiscovery mechanism 22 | requests==2.12.4 23 | # used by the image autodiscovery mechanism 24 | beanstalkc==0.4.0 25 | # used to pass messages between watcher and django 26 | django-redis-cache==1.7.1 27 | # used to cache cluster nodes/instances info 28 | pyyaml==3.12 29 | # used by beanstalkc 30 | django-jsonfield==1.0.1 31 | -------------------------------------------------------------------------------- /static/branding/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/branding/logo.png -------------------------------------------------------------------------------- /static/branding/logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/branding/logo.xcf -------------------------------------------------------------------------------- /static/flatpagesassets/ownership.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/flatpagesassets/ownership.png -------------------------------------------------------------------------------- /static/flatpagesassets/ownership_dropdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/flatpagesassets/ownership_dropdown.png -------------------------------------------------------------------------------- /static/flatpagesassets/user_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/flatpagesassets/user_screen.png -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/feedek.css: -------------------------------------------------------------------------------- 1 | .feedEkList { 2 | /*width: 450px;*/ 3 | list-style: none outside none; 4 | background-color: #FFFFFF; 5 | /*border: 1px solid #D3CAD7;*/ 6 | /*padding: 4px 6px;*/ 7 | color: #3E3E3E; 8 | } 9 | 10 | .feedEkList li { 11 | border-bottom: 1px solid #D3CAD7; 12 | padding: 5px; 13 | } 14 | 15 | .feedEkList li:last-child { 16 | border-bottom: none; 17 | } 18 | 19 | /*.itemTitle a { 20 | font-weight: bold; 21 | color: #4EBAFF !important; 22 | text-decoration: none 23 | }*/ 24 | 25 | /*.itemTitle a:hover { 26 | text-decoration: underline 27 | }*/ 28 | 29 | .itemDate { 30 | font-size: 11px; 31 | color: #AAAAAA; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/img-on-top.css: -------------------------------------------------------------------------------- 1 | .imgstack-container{ 2 | 3 | /* relative positioning to match parent */ 4 | position:relative; 5 | } 6 | 7 | .imgstack-container > a { 8 | 9 | /* make appear clickable */ 10 | cursor:pointer; 11 | } 12 | 13 | .imgstack-container > a > img { 14 | 15 | /* Center image on container, make it responsive */ 16 | left:50%; 17 | top:50%; 18 | --webkit-transform:translate(-50%,-50%); 19 | --ms-transform:translate(-50%,-50%); 20 | transform:translate(-50%,-50%); 21 | 22 | /* absolute positioning to stack it on top 23 | of other image */ 24 | position:absolute; 25 | 26 | /* z-index is greater than the background element's */ 27 | z-index:99; 28 | } 29 | 30 | .imgstack-container img { 31 | 32 | /* relative positioning to match parent */ 33 | position:relative; 34 | 35 | /* z-index less than the element that will go on top */ 36 | z-index:90; 37 | } -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/nprogress.css: -------------------------------------------------------------------------------- 1 | /* Make clicks pass-through */ 2 | #nprogress { 3 | pointer-events: none; 4 | } 5 | 6 | #nprogress .bar { 7 | background: #29d; 8 | 9 | position: fixed; 10 | z-index: 1031; 11 | top: 0; 12 | left: 0; 13 | 14 | width: 100%; 15 | height: 2px; 16 | } 17 | 18 | /* Fancy blur effect */ 19 | #nprogress .peg { 20 | display: block; 21 | position: absolute; 22 | right: 0px; 23 | width: 100px; 24 | height: 100%; 25 | box-shadow: 0 0 10px #29d, 0 0 5px #29d; 26 | opacity: 1.0; 27 | 28 | -webkit-transform: rotate(3deg) translate(0px, -4px); 29 | -ms-transform: rotate(3deg) translate(0px, -4px); 30 | transform: rotate(3deg) translate(0px, -4px); 31 | } 32 | 33 | /* Remove these to get rid of the spinner */ 34 | #nprogress .spinner { 35 | display: block; 36 | position: fixed; 37 | z-index: 1031; 38 | top: 15px; 39 | right: 15px; 40 | } 41 | 42 | #nprogress .spinner-icon { 43 | width: 18px; 44 | height: 18px; 45 | box-sizing: border-box; 46 | 47 | border: solid 2px transparent; 48 | border-top-color: #29d; 49 | border-left-color: #29d; 50 | border-radius: 50%; 51 | 52 | -webkit-animation: nprogress-spinner 400ms linear infinite; 53 | animation: nprogress-spinner 400ms linear infinite; 54 | } 55 | 56 | .nprogress-custom-parent { 57 | overflow: hidden; 58 | position: relative; 59 | } 60 | 61 | .nprogress-custom-parent #nprogress .spinner, 62 | .nprogress-custom-parent #nprogress .bar { 63 | position: absolute; 64 | } 65 | 66 | @-webkit-keyframes nprogress-spinner { 67 | 0% { -webkit-transform: rotate(0deg); } 68 | 100% { -webkit-transform: rotate(360deg); } 69 | } 70 | @keyframes nprogress-spinner { 71 | 0% { transform: rotate(0deg); } 72 | 100% { transform: rotate(360deg); } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/resp-modal.css: -------------------------------------------------------------------------------- 1 | 2 | .video-container { 3 | position: relative; 4 | padding-bottom: 56.25%; 5 | padding-top: 35px; 6 | height: 0; 7 | overflow: hidden; 8 | } 9 | .video-container iframe { 10 | position: absolute; 11 | top:0; 12 | left: 0; 13 | width: 100%; 14 | height: 100%; 15 | } 16 | 17 | .resp-modal { 18 | width:60%; 19 | margin-left:-21%; 20 | left:41%; 21 | } -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/select2-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/includes/select2-spinner.gif -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/includes/select2.png -------------------------------------------------------------------------------- /static/ganetimgr/css/includes/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/includes/select2x2.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-icons_2e83ff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-icons_2e83ff_256x240.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-icons_888888_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-icons_888888_256x240.png -------------------------------------------------------------------------------- /static/ganetimgr/css/smoothness/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/css/smoothness/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /static/ganetimgr/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/ganetimgr/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/ganetimgr/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/ganetimgr/img/background_grnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/background_grnet.png -------------------------------------------------------------------------------- /static/ganetimgr/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/favicon.ico -------------------------------------------------------------------------------- /static/ganetimgr/img/gifs/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/gifs/ajax-loader.gif -------------------------------------------------------------------------------- /static/ganetimgr/img/learnmore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/learnmore.png -------------------------------------------------------------------------------- /static/ganetimgr/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/logo.png -------------------------------------------------------------------------------- /static/ganetimgr/img/nodata.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/nodata.jpg -------------------------------------------------------------------------------- /static/ganetimgr/img/rule.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/rule.png -------------------------------------------------------------------------------- /static/ganetimgr/img/sprites/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/sprites/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /static/ganetimgr/img/sprites/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/sprites/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/ganetimgr/img/video-crop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/ganetimgr/img/video-crop.png -------------------------------------------------------------------------------- /static/ganetimgr/js/includes/feedek.js: -------------------------------------------------------------------------------- 1 | /* 2 | * FeedEk jQuery RSS/ATOM Feed Plugin v3.0 with YQL API 3 | * http://jquery-plugins.net/FeedEk/FeedEk.html https://github.com/enginkizil/FeedEk 4 | * Author : Engin KIZIL http://www.enginkizil.com 5 | */ 6 | 7 | !function (a) { a.fn.FeedEk = function (b) { var g, c = a.extend({ MaxCount: 5, ShowDesc: !0, ShowPubDate: !0, DescCharacterLimit: 0, TitleLinkTarget: "_blank", DateFormat: "", DateFormatLang: "en" }, b), d = a(this).attr("id"), f = ""; if (a("#" + d).empty(), void 0 != c.FeedUrl) { a("#" + d).append(''); var h = 'SELECT channel.item FROM feednormalizer WHERE output="rss_2.0" AND url ="' + c.FeedUrl + '" LIMIT ' + c.MaxCount; a.ajax({ url: "https://query.yahooapis.com/v1/public/yql?q=" + encodeURIComponent(h) + "&format=json&diagnostics=false&callback=?", dataType: "json", success: function (b) { a("#" + d).empty(), b.query.results.rss instanceof Array || (b.query.results.rss = [b.query.results.rss]), a.each(b.query.results.rss, function (b, d) { if (f += '
  • ", c.ShowPubDate) { if (g = new Date(d.channel.item.pubDate), f += '
    ', a.trim(c.DateFormat).length > 0) try { moment.lang(c.DateFormatLang), f += moment(g).format(c.DateFormat) } catch (b) { f += g.toLocaleDateString() } else f += g.toLocaleDateString(); f += "
    " } c.ShowDesc && (f += '
    ', f += c.DescCharacterLimit > 0 && d.channel.item.description.length > c.DescCharacterLimit ? d.channel.item.description.substring(0, c.DescCharacterLimit) + "..." : d.channel.item.description, f += "
    ") }), a("#" + d).append('
      ' + f + "
    ") } }) } } }(jQuery); 8 | -------------------------------------------------------------------------------- /static/ganetimgr/js/includes/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | function createCookie(name,value,days) { 2 | if (days) { 3 | var date = new Date(); 4 | date.setTime(date.getTime()+(days*24*60*60*1000)); 5 | var expires = "; expires="+date.toGMTString(); 6 | } 7 | else var expires = ""; 8 | document.cookie = name+"="+value+expires+"; path=/"; 9 | } 10 | 11 | function readCookie(name) { 12 | var nameEQ = name + "="; 13 | var ca = document.cookie.split(';'); 14 | for(var i=0;i < ca.length;i++) { 15 | var c = ca[i]; 16 | while (c.charAt(0)==' ') c = c.substring(1,c.length); 17 | if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); 18 | } 19 | return null; 20 | } 21 | 22 | function eraseCookie(name) { 23 | createCookie(name,"",-1); 24 | } -------------------------------------------------------------------------------- /static/ganetimgr/js/jquery_csrf_protect.js: -------------------------------------------------------------------------------- 1 | $(document).ajaxSend(function(event, xhr, settings) { 2 | var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); 3 | 4 | function csrfSafeMethod(method) { 5 | // these HTTP methods do not require CSRF protection 6 | return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 7 | } 8 | 9 | if (!csrfSafeMethod(settings.type) && !this.crossDomain) { 10 | xhr.setRequestHeader("X-CSRFToken", csrftoken); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /static/ganetimgr/js/messages.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | 3 | var content = $('.content'); 4 | var message_container = $('#jsonmessages'); 5 | var messages_url = message_container.data('messages'); 6 | var last = ''; 7 | NProgress.configure({ showSpinner: false }); 8 | 9 | $.add_message = function(text, css) { 10 | if (last !== text) { 11 | var css_class = 'alert-'; 12 | if (css != undefined) { 13 | css_class += css; 14 | } else { 15 | css_class += 'warning'; 16 | } 17 | var message_div = message_container.find('.message-template').clone(); 18 | message_div.removeClass('message-template'); 19 | message_div.find('span').text(text); 20 | message_div.addClass(css_class); 21 | message_container.append(message_div); 22 | message_container.show(); 23 | last = text; 24 | } 25 | } 26 | 27 | $(document).ajaxError(function(event, request, settings) { 28 | // in case of ajax Error 29 | if (request.status === 500) { 30 | $.add_message('An error occured with your request'); 31 | } 32 | }); 33 | 34 | $(document).ajaxComplete(function(event, xhr, settings) { 35 | // in case an ajax request is completed 36 | if (xhr.readyState < 4) { 37 | xhr.abort(); 38 | } else { 39 | NProgress.done(); 40 | } 41 | }); 42 | 43 | $(document).ajaxSend(function() { 44 | // in case an ajax request is sent 45 | // This does NOT work with jquery datatables. 46 | NProgress.start(); 47 | }); 48 | 49 | $( document ).ajaxSuccess(function(event, xhr, settings) { 50 | if (settings.url != messages_url) { 51 | $.get( messages_url, function(data) { 52 | if (data.logout === false) { 53 | for (var i=0; i < data.messages.length; i++) { 54 | $.add_message(data.messages[i].message, data.messages[i].css); 55 | } 56 | } else { 57 | $.add_message('Logging out...', 'info'); 58 | setTimeout( 59 | function(){ 60 | location.reload(); 61 | }, 62 | 3000 63 | ); 64 | } 65 | }); 66 | } 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /static/javavnc/VncViewer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/javavnc/VncViewer.jar -------------------------------------------------------------------------------- /static/noVNC/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "include/web-socket-js-project"] 2 | path = include/web-socket-js-project 3 | url = https://github.com/gimite/web-socket-js.git 4 | -------------------------------------------------------------------------------- /static/noVNC/docs/LICENSE.BSD-2-Clause: -------------------------------------------------------------------------------- 1 | Copyright (c) , 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 17 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /static/noVNC/docs/LICENSE.BSD-3-Clause: -------------------------------------------------------------------------------- 1 | Copyright (c) , 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /static/noVNC/docs/LICENSE.zlib: -------------------------------------------------------------------------------- 1 | Copyright (c) , 2 | All rights reserved. 3 | 4 | This software is provided 'as-is', without any express 5 | or implied warranty. In no event will the authors be 6 | held liable for any damages arising from the use of 7 | this software. 8 | 9 | Permission is granted to anyone to use this software 10 | for any purpose, including commercial applications, 11 | and to alter it and redistribute it freely, subject to 12 | the following restrictions: 13 | 14 | 1. The origin of this software must not be 15 | misrepresented; you must not claim that you 16 | wrote the original software. If you use this 17 | software in a product, an acknowledgment in 18 | the product documentation would be appreciated 19 | but is not required. 20 | 21 | 2. Altered source versions must be plainly marked 22 | as such, and must not be misrepresented as 23 | being the original software. 24 | 25 | 3. This notice may not be removed or altered from 26 | any source distribution. 27 | 28 | -------------------------------------------------------------------------------- /static/noVNC/docs/VERSION: -------------------------------------------------------------------------------- 1 | 0.4 2 | -------------------------------------------------------------------------------- /static/noVNC/docs/flash_policy.txt: -------------------------------------------------------------------------------- 1 | Manual setup: 2 | 3 | DATA="echo \'\'" 4 | /usr/bin/socat -T 1 TCP-L:843,reuseaddr,fork,crlf SYSTEM:"$DATA" 5 | -------------------------------------------------------------------------------- /static/noVNC/docs/links: -------------------------------------------------------------------------------- 1 | New tight PNG protocol: 2 | http://wiki.qemu.org/VNC_Tight_PNG 3 | http://xf.iksaif.net/blog/index.php?post/2010/06/14/QEMU:-Tight-PNG-and-some-profiling 4 | 5 | RFB protocol and extensions: 6 | http://tigervnc.org/cgi-bin/rfbproto 7 | 8 | Canvas Browser Compatibility: 9 | http://philip.html5.org/tests/canvas/suite/tests/results.html 10 | 11 | WebSockets API standard: 12 | http://www.whatwg.org/specs/web-apps/current-work/complete.html#websocket 13 | http://dev.w3.org/html5/websockets/ 14 | http://www.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-00.txt 15 | 16 | Browser Keyboard Events detailed: 17 | http://unixpapa.com/js/key.html 18 | 19 | ActionScript (Flash) WebSocket implementation: 20 | http://github.com/gimite/web-socket-js 21 | 22 | ActionScript (Flash) crypto/TLS library: 23 | http://code.google.com/p/as3crypto 24 | http://github.com/lyokato/as3crypto_patched 25 | 26 | TLS Protocol: 27 | http://en.wikipedia.org/wiki/Transport_Layer_Security 28 | 29 | Generate self-signed certificate: 30 | http://docs.python.org/dev/library/ssl.html#certificates 31 | 32 | Cursor appearance/style (for Cursor pseudo-encoding): 33 | http://en.wikipedia.org/wiki/ICO_(file_format) 34 | http://www.daubnet.com/en/file-format-cur 35 | https://developer.mozilla.org/en/Using_URL_values_for_the_cursor_property 36 | http://www.fileformat.info/format/bmp/egff.htm 37 | 38 | Icon/Cursor file format: 39 | http://msdn.microsoft.com/en-us/library/ms997538 40 | http://msdn.microsoft.com/en-us/library/aa921550.aspx 41 | http://msdn.microsoft.com/en-us/library/aa930622.aspx 42 | 43 | 44 | RDP Protocol specification: 45 | http://msdn.microsoft.com/en-us/library/cc240445(v=PROT.10).aspx 46 | 47 | 48 | Related projects: 49 | 50 | guacamole: http://guacamole.sourceforge.net/ 51 | 52 | - Web client, but Java servlet does pre-processing 53 | 54 | jsvnc: http://code.google.com/p/jsvnc/ 55 | 56 | - No releases 57 | 58 | webvnc: http://code.google.com/p/webvnc/ 59 | 60 | - Jetty web server gateway, no updates since April 2008. 61 | 62 | RealVNC Java applet: http://www.realvnc.com/support/javavncviewer.html 63 | 64 | - Java applet 65 | 66 | Flashlight-VNC: http://www.wizhelp.com/flashlight-vnc/ 67 | 68 | - Adobe Flash implementation 69 | 70 | FVNC: http://osflash.org/fvnc 71 | 72 | - Adbove Flash implementation 73 | 74 | CanVNC: http://canvnc.sourceforge.net/ 75 | 76 | - HTML client with REST to VNC python proxy. Mostly vapor. 77 | -------------------------------------------------------------------------------- /static/noVNC/docs/notes: -------------------------------------------------------------------------------- 1 | Some implementation notes: 2 | 3 | There is an included flash object (web-socket-js) that is used to 4 | emulate websocket support on browsers without websocket support 5 | (currently only Chrome has WebSocket support). 6 | 7 | Javascript doesn't have a bytearray type, so what you get out of 8 | a WebSocket object is just Javascript strings. Javascript has UTF-16 9 | unicode strings and anything sent through the WebSocket gets converted 10 | to UTF-8 and vice-versa. So, one additional (and necessary) function 11 | of websockify is base64 encoding/decoding what is sent to/from the 12 | browser. 13 | 14 | Building web-socket-js emulator: 15 | 16 | cd include/web-socket-js/flash-src 17 | mxmlc -static-link-runtime-shared-libraries WebSocketMain.as 18 | -------------------------------------------------------------------------------- /static/noVNC/docs/packaging.txt: -------------------------------------------------------------------------------- 1 | noVNC packaging steps for Debian/Ubuntu: 2 | 3 | - Update the noVNC version in docs/VERSION and add a new entry for the 4 | version in debian/changelog 5 | 6 | - Rename the novnc source directory to match the form "novnc-VERSION". 7 | 8 | - In the novnc source directory, run the packaging command: 9 | 10 | debuild -I -uc -us 11 | 12 | - The -I option ignores the .git directory when generating the 13 | source tarball. 14 | - the -uc and -us may be omitted in order to create a signed 15 | package. 16 | 17 | - Alternatively, use pbuilder instead of debuild in order to build 18 | for other distributions and to guarantee a sanitized package. 19 | 20 | - Verify the package and then commit the changes to docs/VERSION and 21 | debian/changelog. 22 | 23 | - Upload the new package file(s). 24 | -------------------------------------------------------------------------------- /static/noVNC/docs/release.txt: -------------------------------------------------------------------------------- 1 | - Update and commit docs/VERSION and debian/changelog 2 | - Create version tag and tarball from tag 3 | WVER=0.3 4 | git tag v${WVER} 5 | git push origin master 6 | git push origin v${WVER} 7 | git archive --format=tar --prefix=novnc-${WVER}/ v${WVER} > novnc-${WVER}.tar 8 | gzip novnc-${WVER}.tar 9 | - Upload tarball to repo 10 | -------------------------------------------------------------------------------- /static/noVNC/docs/rfbproto-3.3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/noVNC/docs/rfbproto-3.3.pdf -------------------------------------------------------------------------------- /static/noVNC/docs/rfbproto-3.7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/noVNC/docs/rfbproto-3.7.pdf -------------------------------------------------------------------------------- /static/noVNC/docs/rfbproto-3.8.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/noVNC/docs/rfbproto-3.8.pdf -------------------------------------------------------------------------------- /static/noVNC/include/Orbitron700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/noVNC/include/Orbitron700.ttf -------------------------------------------------------------------------------- /static/noVNC/include/Orbitron700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/noVNC/include/Orbitron700.woff -------------------------------------------------------------------------------- /static/noVNC/include/blue.css: -------------------------------------------------------------------------------- 1 | /* 2 | * noVNC blue CSS 3 | * Copyright (C) 2012 Joel Martin 4 | * Copyright (C) 2013 Samuel Mannehed for Cendio AB 5 | * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) 6 | * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). 7 | */ 8 | 9 | .noVNC_status_normal { 10 | background-color:#04073d; 11 | background-image: -webkit-gradient( 12 | linear, 13 | left bottom, 14 | left top, 15 | color-stop(0.54, rgb(10,15,79)), 16 | color-stop(0.5, rgb(4,7,61)) 17 | ); 18 | background-image: -moz-linear-gradient( 19 | center bottom, 20 | rgb(10,15,79) 54%, 21 | rgb(4,7,61) 50% 22 | ); 23 | } 24 | .noVNC_status_error { 25 | background-color:#f04040; 26 | background-image: -webkit-gradient( 27 | linear, 28 | left bottom, 29 | left top, 30 | color-stop(0.54, rgb(240,64,64)), 31 | color-stop(0.5, rgb(4,7,61)) 32 | ); 33 | background-image: -moz-linear-gradient( 34 | center bottom, 35 | rgb(4,7,61) 54%, 36 | rgb(249,64,64) 50% 37 | ); 38 | } 39 | .noVNC_status_warn { 40 | background-color:#f0f040; 41 | background-image: -webkit-gradient( 42 | linear, 43 | left bottom, 44 | left top, 45 | color-stop(0.54, rgb(240,240,64)), 46 | color-stop(0.5, rgb(4,7,61)) 47 | ); 48 | background-image: -moz-linear-gradient( 49 | center bottom, 50 | rgb(4,7,61) 54%, 51 | rgb(240,240,64) 50% 52 | ); 53 | } 54 | 55 | .triangle-right { 56 | border:2px solid #fff; 57 | background:#04073d; 58 | color:#fff; 59 | } 60 | 61 | #keyboardinput { 62 | background-color:#04073d; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /static/noVNC/include/web-socket-js/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/static/noVNC/include/web-socket-js/WebSocketMain.swf -------------------------------------------------------------------------------- /stats/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/stats/__init__.py -------------------------------------------------------------------------------- /stats/models.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/stats/models.py -------------------------------------------------------------------------------- /stats/urls.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 2 | # Copyright (C) 2010-2014 GRNET S.A. 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | # 17 | 18 | from django.conf.urls import url 19 | from stats import views 20 | 21 | urlpatterns = [ 22 | url(r'^applications/?', views.stats_ajax_applications, name="stats_ajax_apps"), 23 | url(r'^instances/?', views.stats_ajax_instances, name="stats_ajax_instances"), 24 | url(r'^vms_cluster/(?P[^/]+)/?', views.stats_ajax_vms_per_cluster, name="stats_ajax_vms_pc"), 25 | url(r'^$', views.stats, name="stats"), 26 | ] 27 | -------------------------------------------------------------------------------- /templates/403.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Access denied{% endblock %} 4 | 5 | {% block navbars %}{% endblock %} 6 | 7 | {% block blockcontainer %} 8 |
    9 |
    10 |
    11 |
    12 |
    13 | 28 |
    29 |
    30 |
    31 |
    32 |
    33 | {% endblock %} 34 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Nice 404 - Page not found{% endblock %} 4 | {% block navbars %}{% endblock %} 5 | {% block blockcontainer %} 6 |
    7 |
    8 |
    9 |
    10 |
    11 | 26 |
    27 |
    28 |
    29 |
    30 |
    31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /templates/500.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}Ohhhh a 500 - Internal Error{% endblock %} 5 | {% block navbars %}{% endblock %} 6 | {% block blockcontainer %} 7 |
    8 |
    9 |
    10 |
    11 |
    12 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /templates/apply/emails/application_rejected_mail.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans with username=application.applicant.username pk=application.pk hostname=application.hostname admin_comments=application.admin_comments service=BRANDING.SERVICE_PROVIDED_BY.NAME %}Dear {{ username }}, 2 | Your request #{{ pk }} to create virtual machine name 3 | {{ hostname }} has been rejected for the following reasons: 4 | 5 | {{ admin_comments }} 6 | 7 | For more information please contact the {{ service }} Helpdesk. 8 | {% endblocktrans %} 9 | -------------------------------------------------------------------------------- /templates/apply/emails/apply_mail.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans with username=user.username first_name=user.first_name last_name=user.last_name %}User {{ username }} ({{ first_name }} {{ last_name }}) made the following request:{% endblocktrans %} 2 | {% load disksizes %} 3 | {% blocktrans with hostname=application.hostname memory=application.memory|memsize vcpus=application.vcpus disk_size=application.disk_size operating_system=application.operating_system hosts_mail_server=application.hosts_mail_server|yesno:"Yes,No" %} 4 | VM parameters 5 | ------------- 6 | Name: {{ hostname }} 7 | Memory: {{ memory }} 8 | vCPUs: {{ vcpus }} 9 | Disk: {{ disk_size }} GB 10 | Operating system: {{ operating_system }} 11 | Hosting mail server: {{ hosts_mail_server }} 12 | {% endblocktrans %} 13 | {% if application.network %}{% blocktrans %}The user requested the VM to connect to the network{% endblocktrans %} «{{application.network}}»{% endif %} 14 | 15 | {% trans "Contact" %}: 16 | {% if application.organization %} 17 | 18 | {% trans "Responsible entity" %}: {{application.organization}} {% else %} 19 | {% trans "Administrative Contact" %} 20 | ---------------------- 21 | {{ application.admin_contact_name }} 22 | {{ application.admin_contact_email }} 23 | {{ application.admin_contact_phone }}{% endif %} 24 | 25 | {% if application.comments %} 26 | {% trans "Comments" %} 27 | -------- 28 | {{ application.comments }}{% endif %} 29 | 30 | {% blocktrans %}To manage the request, visit {{url}}{% endblocktrans %} 31 | -------------------------------------------------------------------------------- /templates/flatpages/default.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% load staticfiles %} 4 | 5 | {% block navbars %}{% endblock %} 6 | 7 | {% block title %}{{ flatpage.title }}{% endblock %} 8 | 9 | {% block brcrmb_container %}{% endblock %} 10 | 11 | {% block extrahead %} 12 | 27 | {% endblock %} 28 | 29 | {% block blockcontainer %} 30 |
    31 |
    32 |
    33 |
    34 |
    35 |
    36 | 49 |
    50 |
    51 |
    52 |
    53 |
    54 |
    55 | {% endblock %} 56 | 57 | -------------------------------------------------------------------------------- /templates/flatpages/faq.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block extrahead %} 4 | 19 | {% endblock %} 20 | 21 | {% block title %} 22 | {{ flatpage.title }} 23 | {% endblock %} 24 | 25 | {% block faq %}class="active"{% endblock %} 26 | 27 | {% block crumbs %} 28 |
  • {% trans "Home" %}/
  • 29 |
  • {% trans flatpage.title %}
  • 30 | {% endblock %} 31 | 32 | {% block content %} 33 |
    34 |
    35 |
    36 |

    {% trans flatpage.title %}

    37 | {{ flatpage.content }} 38 |
    39 |
    40 |
    41 | {% endblock %} 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /templates/includes/analytics.html.dist: -------------------------------------------------------------------------------- 1 | {% comment %} 2 | This is an example. 3 | Copy this file to the templates/analytics.html file 4 | 5 | Change provider according to your needs or leave this file empty if no analytics is required. 6 | 7 | Examples: 8 | PIWIK: 9 | 10 | 23 | 24 | 25 | 26 | 27 | GOOGLE ANALYTICS: 28 | 41 | {% endcomment %} 42 | 43 | -------------------------------------------------------------------------------- /templates/includes/banners.html: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | 6 |

    7 |
    8 | -------------------------------------------------------------------------------- /templates/instances/emails/instance_created_mail.txt: -------------------------------------------------------------------------------- 1 | Η εικονική μηχανή με όνομα {{ application.hostname }} δημιουργήθηκε. 2 | 3 | Μπορείτε να τη χειριστείτε και να δείτε τα στοιχεία της στην ακόλουθη 4 | διεύθυνση: 5 | {{instance_url}} 6 | 7 | {% if application.admin_comments %}Σχόλια διαχειριστή: 8 | {{ application.admin_comments }} 9 | {% endif %} 10 | 11 | {% if reviewer %}Εγκρίθηκε από: {{reviewer}} 12 | {% endif %} 13 | 14 | Για περισσότερες πληροφορίες για την εικονική μηχανή σας ή για οποιοιδήποτε 15 | άλλο αίτημα αφορά την υπηρεσία, μπορείτε να επικοινωνήσετε με το Helpdesk του 16 | {{ BRANDING.SERVICE_PROVIDED_BY.NAME }}. 17 | 18 | ----------------------------------------------------------------------------- 19 | 20 | The virtual machine name {{ application.hostname }} has been created. 21 | 22 | You can manipulate and view the data at the following address: 23 |    {{instance_url}} 24 | 25 | {% if application.admin_comments %}Comments from the administrator: 26 | {{ application.admin_comments }} 27 | {% endif %} 28 | 29 | {% if reviewer %}Approved by: {{reviewer}} 30 | {% endif %} 31 | For more information on the virtual machine or any 32 | other request regarding the service, you can contact the {{ BRANDING.SERVICE_PROVIDED_BY.NAME }} Helpdesk. 33 | -------------------------------------------------------------------------------- /templates/instances/emails/reinstall_mail.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans with username=user.username %}User {{ user.username }} {% endblocktrans%}{% if user.first_name or user.last_name %}({{user.first_name}} {{user.last_name}}){% endif %} {% trans "has made the following request" %}: 2 | ------------------------ 3 | 4 | {% if action == 'reinstall' %}{% trans "Reinstall" %}:{% endif %}{% if action == 'destroy' %}{% trans "Delete" %}:{% endif %}{% if action == 'rename' %}{% trans "Rename" %}:{% endif %}{% if action == 'mailchange' %}{% trans "Change email" %}{% endif %} 5 | {% if action == 'mailchange' %}{% trans "New email" %}: {{action_value}}{% endif %}{% if action != 'mailchange' %} 6 | {{instance}} {% if action == 'rename' %}{% trans "to" %} {{action_value}}{% endif %}{% if action != 'rename' %} 7 | {% trans "WARNING! The above action will" %} {% if action == 'reinstall' %}{% trans "delete your data" %}{% if operating_system %} {% trans "and install" %} {{ operating_system }}{% endif %}{% endif %}{% if action == 'destroy' %}{% trans "delete your virtual machine" %}{% endif %}. {% blocktrans %}Make sure you take backups of any data you need. 8 | WARNING! Once you start the process, it cannot be undone. {% endblocktrans %} 9 | {% endif %}{% endif %} 10 | {% blocktrans %}To continue, please visit {{url}}{% endblocktrans %} 11 | -------------------------------------------------------------------------------- /templates/instances/includes/console-module.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 3 | {% if WEBSOCK_VNC_ENABLED %} 4 | 5 | {% endif %} 6 | {% if LEGACY_VNC_ENABLED %} 7 | 8 | {% endif %} 9 | -------------------------------------------------------------------------------- /templates/instances/includes/instance_status.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /templates/instances/vnc.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | 5 | {% block homepage %}class="active"{% endblock %} 6 | 7 | {% block homepagetop %}class="active"{% endblock %} 8 | 9 | {% block title %}{{ instance }} - {% trans "Console" %}{% endblock %} 10 | 11 | {% block crumbs %} 12 |
  • {% trans "Home" %}/
  • 13 |
  • {{ instance }}/
  • 14 |
  • {% trans "Console" %}
  • 15 | {% endblock %} 16 | 17 | {% block content %} 18 | {% if LEGACY_VNC_ENABLED %} 19 |
    20 |
    21 |
    22 |

    {% trans "VNC session on" %} {{ instance }}

    23 | 24 | 25 | 26 | 30 | 31 |
    32 |
    33 |
    34 | {% else %} 35 |
    36 |
    37 | Java VNC is not enabled. 38 |
    39 | {% endif %} 40 | {% endblock %} 41 | -------------------------------------------------------------------------------- /templates/jobs/job_details.html: -------------------------------------------------------------------------------- 1 |
    {{job}}
    -------------------------------------------------------------------------------- /templates/news/news.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load staticfiles %} 3 | {% load i18n %} 4 | {% block extrahead %} 5 | {% if BRANDING.FEED_URL %} 6 | 7 | 8 | 9 | 10 | 22 | {% endif %} 23 | {% endblock %} 24 | 25 | {% block title %} 26 | {% trans "Latest News" %} 27 | {% endblock %} 28 | 29 | {% block news %}class="active"{% endblock %} 30 | 31 | {% block crumbs %} 32 |
  • {% trans "Home" %}/
  • 33 |
  • {% trans "Latest News" %}
  • 34 | {% endblock %} 35 | 36 | {% block content %} 37 |
    38 |
    39 |
    40 |

    {% trans "Latest News" %}

    41 | {% if BRANDING.FEED_URL %}
    {% else %}No news channel set.{% endif %} 42 |
    43 |
    44 |
    45 | {% endblock %} 46 | -------------------------------------------------------------------------------- /templates/notifications/create.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block notify %}class="active"{% endblock %} 4 | {% block title %}{% trans "Notifications" %}{% endblock %} 5 | 6 | {% block crumbs %} 7 |
  • 8 | {% trans "Home" %} 9 | / 10 |
  • 11 |
  • {% trans "Notifications" %}
  • 12 | {% endblock %} 13 | 14 | {% block extrahead %} 15 | 16 | {% include "notifications/create_script.html" %} 17 | 18 | {% endblock %} 19 | 20 | {% block content %} 21 | {% include "notifications/create_body.html" %} 22 | {% if archive %} 23 |

    Archive

    24 | 31 | {% endif %} 32 | {% endblock %} 33 | 34 | -------------------------------------------------------------------------------- /templates/notifications/create_ajax.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | {% block extrahead %} 3 | 4 | {% include "notifications/create_script.html" %} 5 | 34 | {% endblock %} 35 | 36 | {% block content %} 37 | {% include "notifications/create_body.html" %} 38 | {% endblock %} 39 | -------------------------------------------------------------------------------- /templates/notifications/detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | 4 | {% block notify %}class="active"{% endblock %} 5 | 6 | {% block title %}{% trans "Notifications" %}{% endblock %} 7 | 8 | {% block crumbs %} 9 |
  • 10 | {% trans "Home" %} 11 | / 12 |
  • 13 |
  • {% trans "Notifications" %}
  • 14 | {% endblock %} 15 | 16 | {% block content %} 17 |

    {{ notification.subject }}

    18 |
    {{ notification.date }}
    19 | {% if notification.sender %} 20 |

    Sender

    21 | {{ notification.sender }} 22 | {% endif %} 23 |

    Message

    24 |

    {{ notification.message }}

    25 |

    Recipients

    26 |
    27 | {% for user in notification.recipients.all %} 28 | {{ user }} {% if not forloop.last %}, {% endif %} 29 | {% endfor %} 30 |
    31 | {% endblock %} 32 | 33 | -------------------------------------------------------------------------------- /templates/registration/activate.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Activation Status" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | {% block blockcontainer %} 6 |
    7 |
    8 |
    9 |
    10 |
    11 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /templates/registration/activation_complete_admin_pending.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Activation Complete" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | {% block blockcontainer %} 6 |
    7 |
    8 |
    9 |
    10 |
    11 | 26 |
    27 |
    28 |
    29 |
    30 |
    31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /templates/registration/activation_complete_admin_pending.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans %}You have successfully validated your email address. 2 | Your account with username {% endblocktrans %}“{{ user.username }}” {% blocktrans %} will be activated by an administrator and you will be notified via email.{% endblocktrans %} -------------------------------------------------------------------------------- /templates/registration/activation_email.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% url validate_email validation_key as validation_url %}{% blocktrans with full_name=user.get_full_name username=user.username email=user.email domain=site.domain %}You have registered for a new account. 2 | 3 | Username: {{ username }} 4 | E-mail: {{ email }} 5 | 6 | To proceed with with your account activation, you must first validate your email 7 | address. To do so, click on the following link or copy the address to your browser 8 | {% endblocktrans %} 9 | 10 | http://{{ site.domain }}{% url 'registration_activate' activation_key %} 11 | 12 | {% blocktrans %} 13 | The site's administrator will then be notified about your newly created account and 14 | proceed to approve it. 15 | 16 | You have {{ expiration_days }} days to validate your email address. If you fail to 17 | do so within the time limit, you will have to register again. 18 | 19 | Upon approval, you will receive a new email message. 20 | {% endblocktrans %} 21 | -------------------------------------------------------------------------------- /templates/registration/activation_email_subject.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}[{{site.name}}]{% trans "User account activation" %} 2 | -------------------------------------------------------------------------------- /templates/registration/admin_approve.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Admin approval status" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | {% block blockcontainer %} 6 |
    7 |
    8 |
    9 |
    10 |
    11 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /templates/registration/admin_approve_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Admin approval Complete" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | 6 | {% block blockcontainer %} 7 |
    8 |
    9 |
    10 |
    11 |
    12 | 24 |
    25 |
    26 |
    27 |
    28 |
    29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /templates/registration/admin_approve_complete_email.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans %}Your account {% endblocktrans %} {% blocktrans %}has been approved.{% endblocktrans %} 2 | {% blocktrans %}You may login using the following URL:{% endblocktrans %} 3 | 4 | http://{{ site.domain }}{% url 'login' %} 5 | -------------------------------------------------------------------------------- /templates/registration/admin_approve_email.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans with full_name=user.get_full_name username=user.username email=user.email %}User {{ full_name }} has registered for a new account. 2 | 3 | Username: {{ username }} 4 | E-mail: {{ email }} 5 | 6 | To approve the user's account, click on the following url: 7 | {% endblocktrans %} 8 | 9 | http://{{ site.domain }}{% url 'registration_admin_approve' profile_id %}" 10 | 11 | {% blocktrans %} 12 | Upon approval the user will receive a new email message. 13 | {% endblocktrans %} 14 | -------------------------------------------------------------------------------- /templates/registration/admin_approve_email_subject.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}[{{site.name}}]{% trans "User account approval" %} 2 | -------------------------------------------------------------------------------- /templates/registration/password_change_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block content %} 4 |
    5 |

    {% trans "Change Password" %}

    6 |
    7 |
    8 | 9 | {{ form.as_table }} 10 |
    11 | 12 |
    13 |
    14 |
    15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /templates/registration/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Password Reset Complete" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | 6 | {% block blockcontainer %} 7 |
    8 |
    9 |
    10 |
    11 |
    12 | 26 |
    27 |
    28 |
    29 |
    30 |
    31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /templates/registration/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} {% load i18n %} 2 | {% block title %}{% trans "Reset Password" %}{% endblock %} 3 | {% block brcrmb_container %}{% endblock %} 4 | {% block blockcontainer %} 5 |
    6 |
    7 |
    8 |
    9 |
    10 | 51 |
    52 |
    53 |
    54 |
    55 |
    56 | {% endblock %} 57 | -------------------------------------------------------------------------------- /templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Email sent" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | {% block blockcontainer %} 6 |
    7 |
    8 |
    9 |
    10 |
    11 | 23 |
    24 |
    25 |
    26 |
    27 |
    28 | {% endblock %} 29 | -------------------------------------------------------------------------------- /templates/registration/password_reset_email.html: -------------------------------------------------------------------------------- 1 | Dear {{ user.username }}, 2 | Reset password at {{ site_name }}: 3 | {% block reset_link %} 4 | {{ protocol }}://{{ domain }}{% url 'auth_password_reset_confirm' uid token %} 5 | {% endblock %} 6 | -------------------------------------------------------------------------------- /templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} {% load i18n %} {% block title %} 2 | {% trans "Reset Password" %}{% endblock %} {% block brcrmb_container %}{% endblock %} 3 | {% load widget_tweaks %} 4 | {% block blockcontainer %} 5 |
    6 |
    7 |
    8 |
    9 |
    10 | 39 |
    40 |
    41 |
    42 |
    43 |
    44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /templates/registration/registration_complete.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Activation email sent" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | 6 | {% block blockcontainer %} 7 |
    8 |
    9 |
    10 |
    11 |
    12 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /templates/registration/validation_expired.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% load i18n %} 3 | {% block title %}{% trans "Activation Expired" %}{% endblock %} 4 | {% block brcrmb_container %}{% endblock %} 5 | 6 | {% block blockcontainer %} 7 |
    8 |
    9 |
    10 |
    11 |
    12 | 27 |
    28 |
    29 |
    30 |
    31 |
    32 | {% endblock %} 33 | -------------------------------------------------------------------------------- /templates/tagging/isolate.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 5 | 35 | 36 | 48 | 49 |
    50 |
    51 | {% csrf_token %} 52 | {% if form.non_field_errors %} 53 |

    54 | {{ form.non_field_errors}} 55 |

    56 | {% endif %} 57 |
    58 |
    59 | {{ form.isolate }} 60 |
    61 |
    62 |
    63 |
    64 | Save 65 |
    66 |
    67 |
    68 |
    69 | 70 | 71 | -------------------------------------------------------------------------------- /templates/tagging/lock.html: -------------------------------------------------------------------------------- 1 | {% load staticfiles %} 2 | 3 | 4 | 34 | 46 |
    47 |
    48 | {% csrf_token %} 49 | {% if form.non_field_errors %} 50 |

    51 | {{ form.non_field_errors}} 52 |

    53 | {% endif %} 54 |
    55 |
    56 | {{ form.lock }} 57 |
    58 |
    59 |
    60 |
    61 | Save 62 |
    63 |
    64 |
    65 |
    66 | 67 | 68 | -------------------------------------------------------------------------------- /templates/users/emails/idle_account.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% trans 'Dear' %} {{ user.username }}, 2 | {% blocktrans %}To ensure the validity of user accounts in the 3 | service we monitor usage of the web management interface.{% endblocktrans %} 4 | {% blocktrans %}We would like to inform you that the last time you logged in was {{days}} ago (or more). {% endblocktrans %} 5 | 6 | {% blocktrans %}Therefore we kindly ask you to confirm the validity of your account. 7 | The confirmation is performed by accessing the login page of the service: {% endblocktrans %} 8 | https://{{ site.domain }}{% url 'login' %} 9 | {% blocktrans %}Please do this as soon as possible.{% endblocktrans %} 10 | {% blocktrans with service_name=service.TITLE %} 11 | Sincerely, 12 | The {{ service_name }} Management. 13 | {% endblocktrans %} 14 | -------------------------------------------------------------------------------- /templates/users/emails/pass_change_notify_mail.txt: -------------------------------------------------------------------------------- 1 | {% load i18n %}{% blocktrans %}Dear {{ user }},{% endblocktrans %}{% blocktrans %} 2 | We hereby inform you that the password for your account 3 | in the {{ service_title }} service has been changed successfully. 4 | {% endblocktrans %}{% blocktrans %} 5 | If the password change was not made by you, please inform 6 | the {{ provider }} Helpdesk. 7 | {% endblocktrans %} 8 | -------------------------------------------------------------------------------- /templates/users/pass_change_done.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 | 15 |
    {% trans "Password changed" %} {% trans "successfully" %}
    16 | -------------------------------------------------------------------------------- /util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grnet/ganetimgr/314173e7f0b7001174fb77fcb6bf679d4d33012b/util/__init__.py -------------------------------------------------------------------------------- /util/vapclient.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- vim:fileencoding=utf-8: 3 | # 4 | 5 | import sys 6 | import json 7 | import socket 8 | 9 | 10 | CTRL_SOCKET = "/var/run/vncauthproxy/vncproxy.sock" 11 | 12 | def request_forwarding(sport, daddr, dport, password): 13 | assert(len(password) > 0) 14 | req = { 15 | "source_port": int(sport), 16 | "destination_address": daddr, 17 | "destination_port": int(dport), 18 | "password": password 19 | } 20 | 21 | ctrl = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 22 | ctrl.connect(CTRL_SOCKET) 23 | ctrl.send(json.dumps(req)) 24 | 25 | response = ctrl.recv(1024) 26 | res = json.loads(response) 27 | return res 28 | 29 | if __name__ == '__main__': 30 | res = request_forwarding(*sys.argv[1:]) 31 | if res['status'] == "OK": 32 | sys.exit(0) 33 | else: 34 | sys.exit(1) 35 | 36 | 37 | def request_novnc_forwarding(server, daddr, dport, password, sport=None, tls=True): 38 | """ 39 | Ask TVAP/VNCAP for a forwarding port. 40 | 41 | The control socket on TVAP wants a JSON dictionary containing at least the 42 | destination port and address, and VNC password. It optionally can accept a 43 | requested source port, whether WebSockets should be used, and whether TLS 44 | (SSL/WSS) should be used. 45 | """ 46 | 47 | try: 48 | host, port = server 49 | port = int(port) 50 | dport = int(dport) 51 | if not password: 52 | return False 53 | 54 | request = { 55 | "daddr": daddr, 56 | "dport": dport, 57 | "password": password, 58 | "ws": True, 59 | "tls": tls, 60 | } 61 | 62 | if sport: 63 | request["sport"] = sport 64 | 65 | request = json.dumps(request) 66 | 67 | ctrl = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 68 | ctrl.connect((host, port)) 69 | ctrl.send("%s\r\n" % request) 70 | response = ctrl.recv(1024).strip() 71 | ctrl.close() 72 | 73 | if response.startswith("FAIL"): 74 | return False 75 | else: 76 | return response 77 | 78 | # XXX bare except 79 | except: 80 | return False 81 | -------------------------------------------------------------------------------- /version: -------------------------------------------------------------------------------- 1 | 314173e7 2 | --------------------------------------------------------------------------------