Commit a65d9643 by Bach Dániel

Merge remote-tracking branch 'origin/master' into feature-django18

parents 3d1583e0 3122ce02
...@@ -213,6 +213,7 @@ PIPELINE_JS = { ...@@ -213,6 +213,7 @@ PIPELINE_JS = {
"dashboard/vm-common.js", "dashboard/vm-common.js",
"dashboard/vm-create.js", "dashboard/vm-create.js",
"dashboard/vm-list.js", "dashboard/vm-list.js",
"dashboard/help.js",
"js/host.js", "js/host.js",
"js/network.js", "js/network.js",
"js/switch-port.js", "js/switch-port.js",
......
...@@ -21,7 +21,8 @@ from logging import getLogger ...@@ -21,7 +21,8 @@ from logging import getLogger
from django.core.exceptions import PermissionDenied, ImproperlyConfigured from django.core.exceptions import PermissionDenied, ImproperlyConfigured
from django.utils.translation import ugettext_noop from django.utils.translation import ugettext_noop
from .models import activity_context, has_suffix, humanize_exception from .models import (activity_context, has_suffix, humanize_exception,
HumanReadableObject)
logger = getLogger(__name__) logger = getLogger(__name__)
...@@ -110,8 +111,12 @@ class Operation(object): ...@@ -110,8 +111,12 @@ class Operation(object):
arguments.update(auxargs) arguments.update(auxargs)
with activity_context(allargs['activity'], on_abort=self.on_abort, with activity_context(allargs['activity'], on_abort=self.on_abort,
on_commit=self.on_commit): on_commit=self.on_commit) as act:
return self._operation(**arguments) retval = self._operation(**arguments)
if (act.result is None and isinstance(
retval, (basestring, int, HumanReadableObject))):
act.result = retval
return retval
def _operation(self, **kwargs): def _operation(self, **kwargs):
"""This method is the operation's particular implementation. """This method is the operation's particular implementation.
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
from __future__ import absolute_import from __future__ import absolute_import
from datetime import timedelta
from itertools import chain from itertools import chain
from hashlib import md5 from hashlib import md5
from logging import getLogger from logging import getLogger
...@@ -31,6 +32,7 @@ from django.db.models import ( ...@@ -31,6 +32,7 @@ from django.db.models import (
) )
from django.db.models.signals import post_save, pre_delete, post_delete from django.db.models.signals import post_save, pre_delete, post_delete
from django.templatetags.static import static from django.templatetags.static import static
from django.utils import timezone
from django.utils.html import escape from django.utils.html import escape
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django_sshkey.models import UserKey from django_sshkey.models import UserKey
...@@ -132,6 +134,17 @@ class Notification(TimeStampedModel): ...@@ -132,6 +134,17 @@ class Notification(TimeStampedModel):
def message(self, value): def message(self, value):
self.message_data = None if value is None else value.to_dict() self.message_data = None if value is None else value.to_dict()
@property
def has_valid_renew_url(self):
params = self.message_data['params']
return ('token' in params and 'suspend' in params and
self.modified > timezone.now() - timedelta(days=3))
@property
def renew_url(self):
return (settings.DJANGO_URL.rstrip("/") +
str(self.message_data['params'].get('token')))
class ConnectCommand(Model): class ConnectCommand(Model):
user = ForeignKey(User, related_name='command_set') user = ForeignKey(User, related_name='command_set')
......
...@@ -1320,15 +1320,155 @@ textarea[name="new_members"] { ...@@ -1320,15 +1320,155 @@ textarea[name="new_members"] {
} }
} }
/* help page */
.help-tabs li {
width: 50%;
text-align: center;
}
// note: padding-margin hack to skip banner on anchor
#help-tab-content {
h1, h2, h3, h4, h5 {
font-weight: bold;
padding-top: 55px; margin-top: -55px;
}
blockquote {
background-color:#dfe4e4;
}
}
#wrapper {
position: fixed;
padding-left: 0px;
background: #252525;
left: 0px;
top: 46px;
height: 100%;
width: 210px;
transition: all .4s ease 0s;
/* Firefox */
height: -moz-calc(100% - 130px);
/* WebKit */
height: -webkit-calc(100% - 120px);
/* Opera */
height: -o-calc(100% - 110px);
/* Standard */
height: calc(100% - 130px);
}
#sidebar-wrapper {
margin-left: 0px;
left: 0px;
top: inherit;
bottom: 30px;
width: inherit;
position: inherit;
z-index: 10000;
transition: all .4s ease 0s;
overflow: auto;
overflow-x: hidden;
overflow-y: auto;
}
#sidebar-wrapper ul {
display: block;
float: left;
list-style: none;
margin: 0;
padding: 0px;
}
#sidebar-wrapper a {
font-family: "proxima-nova", 'Helvetica Neue', 'Helvetica', 'sans-serif';
color: #ddd;
display: block;
float: left;
width: 200px;
text-decoration: none;
background: #252525;
border-top: 1px solid #333;
border-bottom: 1px solid #222;
-webkit-transition: background .5s;
-moz-transition: background .5s;
-o-transition: background .5s;
-ms-transition: background .5s;
transition: background .5s;
}
#sidebar-wrapper ul a{
padding-top: 10px;
padding-bottom: 10px;
padding-left: 10px;
font-size: larger;
}
#sidebar-wrapper li a{
padding-top: 6px;
padding-bottom: 6px;
padding-left: 20px;
padding-right: 6px;
font-size: smaller;
}
#sidebar-wrapper ul ul a{
padding-top: 10px;
padding-bottom: 10px;
padding-left: 16px;
font-size: larger;
}
#sidebar-wrapper li li a{
padding-top: 6px;
padding-bottom: 6px;
padding-left: 24px;
padding-right: 6px;
font-size: smaller;
}
#sidebar-wrapper li a:hover, #sidebar-wrapper ul a:hover{
color: #fff;
background: rgba(200,200,255,0.15);
text-decoration: none;
}
#page-content {
margin-left: 200px;
}
@media only screen and (max-width: 600px) {
#wrapper {
-webkit-transform: translateX(-250px);
-moz-transform: translateX(-250px);
-o-transform: translateX(-250px);
-ms-transform: translateX(-250px);
transform: translateX(-250px);
}
#page-content {
margin-left: 0px;
-webkit-transition: background .5s;
-moz-transition: background .5s;
-o-transition: background .5s;
-ms-transition: background .5s;
transition: background .5s;
}
}
.overview_href {
cursor: pointer;
}
#request-buttons { #request-buttons {
form { form {
display: inline; display: inline;
} }
textarea {
textarea {
resize: none; resize: none;
min-height: 80px; min-height: 80px;
} }
} }
.nowrap { .nowrap {
......
$(function() {
$('.crosslink').click(function(e) {
e.preventDefault();
var menu = $(this).data("menu");
$(menu).click();
window.location = this.href;
});
var hash = window.location.hash;
if(hash) {
var pane = $(hash).closest(".tab-pane").prop("class");
if (pane) {
if (pane.indexOf("overview") != -1) {
$("#overview_menu").click();
} else {
$("#faq_menu").click();
}
$("html, body").animate({scrollTop: $(hash).offset().top}, 500);
window.location.hash = hash;
}
}
});
<img src="{{ STATIC_URL}}dashboard/img/logo.png" alt="circle logo" style="height: 25px;"/> {% load staticfiles %}
<img src="{{ STATIC_URL}}local-logo.png" alt="local logo" style="padding-left: 2px; height: 25px;"/> <img src="{% static "dashboard/img/logo.png" %}" alt="circle logo" style="height: 25px;"/>
<img src="{% static "local-logo.png" %}" alt="local logo" style="padding-left: 2px; height: 25px;"/>
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
{% blocktrans count n=messages|length %}You have a new notification:{% plural %}You have {{n}} new notifications:{% endblocktrans %} {% blocktrans count n=messages|length %}You have a new notification:{% plural %}You have {{n}} new notifications:{% endblocktrans %}
{% for msg in messages %} * {{msg.subject}} {% for msg in messages %} * {{msg.subject}}{% if msg.has_valid_renew_url %}
{% trans "You can renew it without logging in:" %}
{{ msg.renew_url }}{% endif %}
{% endfor %} {% endfor %}
{% blocktrans with url=url count n=messages|length %}See it in detail on <{{url}}>.{% plural %} See them in detail on <{{url}}>.{% endblocktrans %} {% blocktrans with url=url count n=messages|length %}See it in detail on <{{url}}>.{% plural %} See them in detail on <{{url}}>.{% endblocktrans %}
......
{% load i18n %} {% load i18n %}
{% load staticfiles %} {% load staticfiles %}
{% if not perms.vm.vm_access_console %} {% if not perms.vm.access_console %}
<div class="alert alert-warning"> <div class="alert alert-warning">
{% trans "You are not authorized to access the VNC console." %} {% trans "You are not authorized to access the VNC console." %}
</div> </div>
......
...@@ -148,7 +148,11 @@ ...@@ -148,7 +148,11 @@
</div> </div>
<div class="alert alert-info"> <div class="alert alert-info">
You can filter the list by certain attributes (owner, name, status, tags) in the following way: "owner:John Doe name:my little server". If you don't specify any attribute names the filtering will be done by name. {% blocktrans %}
You can filter the list by certain attributes (owner, name, status, tags)
in the following way: "owner:John Doe name:my little server !name:test".
If you don't specify any attribute names the filtering will be done by name.
{% endblocktrans %}
</div> </div>
<div class="alert alert-info"> <div class="alert alert-info">
......
...@@ -5,5 +5,8 @@ ...@@ -5,5 +5,8 @@
<div><strong>{{ field.label }}</strong>: {{ field.errors|striptags }}</div> <div><strong>{{ field.label }}</strong>: {{ field.errors|striptags }}</div>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% for error in form.non_field_errors %}
<div>{{ error|striptags }}</div>
{% endfor %}
</div> </div>
{% endif %} {% endif %}
...@@ -28,6 +28,7 @@ from braces.views import LoginRequiredMixin ...@@ -28,6 +28,7 @@ from braces.views import LoginRequiredMixin
from dashboard.models import GroupProfile from dashboard.models import GroupProfile
from vm.models import Instance, Node, InstanceTemplate from vm.models import Instance, Node, InstanceTemplate
from dashboard.views.vm import vm_ops
from ..store_api import Store from ..store_api import Store
...@@ -127,7 +128,10 @@ class HelpView(TemplateView): ...@@ -127,7 +128,10 @@ class HelpView(TemplateView):
def get_context_data(self, *args, **kwargs): def get_context_data(self, *args, **kwargs):
ctx = super(HelpView, self).get_context_data(*args, **kwargs) ctx = super(HelpView, self).get_context_data(*args, **kwargs)
operations = [(o, Instance._ops[o.op])
for o in vm_ops.values() if o.show_in_toolbar]
ctx.update({"saml": hasattr(settings, "SAML_CONFIG"), ctx.update({"saml": hasattr(settings, "SAML_CONFIG"),
"operations": operations,
"store": settings.STORE_URL}) "store": settings.STORE_URL})
return ctx return ctx
......
...@@ -237,7 +237,8 @@ class TemplateList(LoginRequiredMixin, FilterMixin, SingleTableView): ...@@ -237,7 +237,8 @@ class TemplateList(LoginRequiredMixin, FilterMixin, SingleTableView):
self.create_fake_get() self.create_fake_get()
try: try:
qs = qs.filter(**self.get_queryset_filters()).distinct() filters, excludes = self.get_queryset_filters()
qs = qs.filter(**filters).exclude(**excludes).distinct()
except ValueError: except ValueError:
messages.error(self.request, _("Error during filtering.")) messages.error(self.request, _("Error during filtering."))
......
...@@ -79,14 +79,26 @@ class FilterMixin(object): ...@@ -79,14 +79,26 @@ class FilterMixin(object):
def get_queryset_filters(self): def get_queryset_filters(self):
filters = {} filters = {}
for item in self.allowed_filters: excludes = {}
if item in self.request.GET:
filters[self.allowed_filters[item]] = ( for key, value in self.request.GET.items():
self.request.GET[item].split(",") if not key:
if self.allowed_filters[item].endswith("__in") else continue
self.request.GET[item]) exclude = key.startswith('!')
key = key.lstrip('!')
if key not in self.allowed_filters:
continue
filter_field = self.allowed_filters[key]
value = (value.split(",")
if filter_field.endswith("__in") else
value)
if exclude:
excludes[filter_field] = value
else:
filters[filter_field] = value
return filters return filters, excludes
def get_queryset(self): def get_queryset(self):
return super(FilterMixin, return super(FilterMixin,
...@@ -118,6 +130,9 @@ class FilterMixin(object): ...@@ -118,6 +130,9 @@ class FilterMixin(object):
>>> o = f._parse_get({'s': "name:hello ws node:node 3 oh"}).items() >>> o = f._parse_get({'s': "name:hello ws node:node 3 oh"}).items()
>>> sorted(o) # doctest: +ELLIPSIS >>> sorted(o) # doctest: +ELLIPSIS
[(u'name', u'hello ws'), (u'node', u'node 3 oh'), (...)] [(u'name', u'hello ws'), (u'node', u'node 3 oh'), (...)]
>>> o = f._parse_get({'s': "!hello:szia"}).items()
>>> sorted(o) # doctest: +ELLIPSIS
[(u'!hello', u'szia'), (...)]
""" """
s = GET_dict.get("s") s = GET_dict.get("s")
fake = GET_dict.copy() fake = GET_dict.copy()
......
...@@ -1002,7 +1002,8 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView): ...@@ -1002,7 +1002,8 @@ class VmList(LoginRequiredMixin, FilterMixin, ListView):
in [i.name for i in Instance._meta.fields] + ["pk"]): in [i.name for i in Instance._meta.fields] + ["pk"]):
queryset = queryset.order_by(sort) queryset = queryset.order_by(sort)
return queryset.filter(**self.get_queryset_filters()).prefetch_related( filters, excludes = self.get_queryset_filters()
return queryset.filter(**filters).exclude(**excludes).prefetch_related(
"owner", "node", "owner__profile", "interface_set", "lease", "owner", "node", "owner__profile", "interface_set", "lease",
"interface_set__host").distinct() "interface_set__host").distinct()
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# with CIRCLE. If not, see <http://www.gnu.org/licenses/>. # with CIRCLE. If not, see <http://www.gnu.org/licenses/>.
from django.forms import ( from django.forms import (
ModelForm, ModelChoiceField, ChoiceField, Form, CharField, RadioSelect, ModelForm, ModelChoiceField, ChoiceField, Form, CharField, RadioSelect,
Textarea, Textarea, ValidationError
) )
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.template import RequestContext from django.template import RequestContext
...@@ -70,6 +70,14 @@ class InitialFromFileMixin(object): ...@@ -70,6 +70,14 @@ class InitialFromFileMixin(object):
RequestContext(request, {}), RequestContext(request, {}),
) )
def clean(self):
cleaned_data = super(InitialFromFileMixin, self).clean()
if cleaned_data['message'].strip() == self.initial['message'].strip():
raise ValidationError(
_("Fill in the message."),
code="invalid")
return cleaned_data
class TemplateRequestForm(InitialFromFileMixin, Form): class TemplateRequestForm(InitialFromFileMixin, Form):
template = ModelChoiceField(TemplateAccessType.objects.all(), template = ModelChoiceField(TemplateAccessType.objects.all(),
...@@ -92,3 +100,13 @@ class ResourceRequestForm(InitialFromFileMixin, VmResourcesForm): ...@@ -92,3 +100,13 @@ class ResourceRequestForm(InitialFromFileMixin, VmResourcesForm):
message = CharField(widget=Textarea) message = CharField(widget=Textarea)
initial_template = "request/initials/resources.html" initial_template = "request/initials/resources.html"
def clean(self):
cleaned_data = super(ResourceRequestForm, self).clean()
inst = self.instance
if (cleaned_data['ram_size'] == inst.ram_size and
cleaned_data['num_cores'] == inst.num_cores and
int(cleaned_data['priority']) == inst.priority):
raise ValidationError(
_("You haven't changed any of the resources."),
code="invalid")
...@@ -2,257 +2,49 @@ ...@@ -2,257 +2,49 @@
{% load i18n %} {% load i18n %}
{% block title-page %}{% trans "Help" %}{% endblock %} {% block title-page %}{% trans "Help" %}{% endblock %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-lg-8 col-lg-offset-2"> <div id="wrapper">
<div id="sidebar-wrapper">
<div id="help-tab-content" class="tab-content">
<div class="tab-pane active _faq">
{% include "info/help/faq_toc.html" %}
</div>
<div class="tab-pane _overview">
{% include "info/help/overview_toc.html" %}
</div>
</div>
</div>
</div>
<div id="page-content" class="col-lg-8">
<div class="page-header"> <div class="page-header">
<h1>{% trans "Help" %} <small>{% trans "user guide in short" %}</small></h1> <h1>{% trans "Help" %} <small>{% trans "user guide in short" %}</small></h1>
</div> </div>
<div class="content">
<div class="panel panel-default"> <ul class="help-tabs nav nav-tabs">
<div class="panel-body"> <li class="active">
<h2>{% trans "Introduction" %}</h2> <a id="faq_menu" href="#faq" data-toggle="pill" data-target="._faq" class="text-center" >
<p> <i class="fa fa-comments-o fa-2x"></i>
{% blocktrans %} <br>
This is a deployment of <a href="http://circlecloud.org/">CIRCLE {% trans "FAQ" %}
Cloud</a>, which is a free and open source cloud manager. </a>
{% endblocktrans %} </li>
{% blocktrans %} <li>
Its most important function is starting and managing virtual machine <a id="overview_menu" href="#overview" data-toggle="pill" data-target="._overview" class="text-center" >
instances based on templates. <i class="fa fa-book fa-2x"></i><br>
These templates are also easy to create. {% trans "Overview" %}</a>
{% endblocktrans %} </li>
</p><p> </ul>
{% blocktrans %} <div id="help-tab-content" class="tab-content">
Apart from this tutorial we recommend to try the system, it is quite <div class="tab-pane active _faq">
intuitive, and the web interface shows detailed instructions on {% include "info/help/faq.html" %}
advanced options.
{% endblocktrans %}
</p>
<h2><i class="fa fa-dashboard"></i> {% trans "Dashboard" %}</h2>
<p>
{% blocktrans with host=request.get_host %}
You can reach this service at <tt>https://{{host}}/</tt> where you can log in
to the dashboard.
{% endblocktrans %}
<p>
{% blocktrans %}
The dashboard is a summary about your virtual machines and other
resources, and the main starting point to access the functions of
the system.
{% endblocktrans %}
</p>
<div id="vms" {% if not perms.vm %}class="text-muted"{% endif %}>
<h2><i class="fa fa-desktop"></i> {% trans "Virtual machines" %}</h2>
{% if not perms.vm %}
<p class="text-warning">
{% trans "Sorry, you have no permission to launch virtual machines." %}
</p>
{% endif %}
<p>
{% blocktrans %}
In the <em>virtual machines</em> box you will find your recent
virtual machines.
A summary view is also available by clicking the dashboard button
(<i class="fa fa-dashboard"></i>).
Click on the name of a virtual machine to see its connection
details, preferences, or to change its state.
{% endblocktrans %}
{% blocktrans %}
Important or frequently used machines can be pinned by the
favorite button (<i class="fa fa-star-o"></i>).
The search field shows results incrementally, and submitting (⏎)
jumps directly to the result, if there is exactly one.
You can start a new virtual machine by clicking on the
<span class="btn btn-success disabled btn-xs">
<i class="fa fa-plus-circle"></i> new</span> button, and
choosing a template.
{% endblocktrans %}
</p><p>
{% blocktrans %}
If you select a virtual machine, you get to a page with all the
details and operations listed. On the left, you will see the state
of the machine and a summary about how you can
<strong>connect</strong> to the
machine.
In the middle there is a tabbed pane, which contains details about
the machine in categories.
{% endblocktrans %}
{% blocktrans %}
The upper right corner is the operation toolbar with the most
important actions that control the <strong>lifecycle</strong> of
the machine.
{% endblocktrans %}
</p><p>
{% blocktrans %}
The tool buttons are color coded by their effect, and enabled/disabled
based on the current state of the machine.
The recommended operation is always the biggest tool button with
the name displayed.
You can click on them as the confirmation dialog explains in
detail what they do.
{% endblocktrans %}
</p><p>
{% blocktrans %}
<strong><i class="fa fa-compass"></i> Home</strong> pane shows
statistics about the virtual machine, and this is where you can
change the name, description and tags of the instance.
We strongly advise to add a description to make the work of the
cloud administrators easier in case of maintenance.
Here is a summary about the <strong>expiration times</strong> as
well. Each virtual machine has a deadline for suspending and
destroying based on predefined leases. With the renew button you
can reset the counters. Of course you will get a notification if
the machine is going to expire.
{% endblocktrans %}
</p><p>
{% blocktrans %}
<strong><i class="fa fa-tasks"></i> Resources</strong> pane shows
details about how much memory and CPU the VM has, and how is it
scheduled.
{% endblocktrans %}
<span{% if not perms.vm.change_resources %}
class="text-muted"{% endif %}>{% blocktrans %}
Users with specific permission can change these settings if
the machine is stopped.{% endblocktrans %}</span>
</p><p>
{% blocktrans %}
<strong><i class="fa fa-desktop"></i> Console</strong> pane allows
to see the console of the virutal machine for troubleshooting and
operating system installation.{% endblocktrans %}
{% if perms.vm.access_console %}
{% trans "You can also use the keyboard and mouse." %}
{% else %}
<span class="text-warning">{% blocktrans %}You have permission to create
screenshots, but not to use the console keyboard or mouse.
{% endblocktrans %}</span>
{% endif %}
{% blocktrans %}You should normally use the machine by connecting
remotely over SSH or Remote Desktop.{% endblocktrans %}
</p><p>
{% blocktrans %}
<strong><i class="fa fa-group"></i> Access</strong> pane allows
sharing the machine with others and transferring the ownership.
Users can see the details of the machine, operators can use most
functions, and owners can also destroy the machine.
{% endblocktrans %}
</p><p>
{% blocktrans %}
<strong><i class="fa fa-globe"></i> Network</strong> pane shows
how the virtual machine is connected to the network.
You can add or remove interfaces, and allow remote access of
different TCP/UDP ports.
{% endblocktrans %}
</p><p>
{% blocktrans %}
<strong><i class="fa fa-clock-o"></i> Activity</strong> pane shows
the full life history of the virtual machine. This is where you
can see the causes of failed actions (just point the mouse to the name of
the action).
{% endblocktrans %}
</p>
</div> </div>
<div id="templates" {% if not perms.vm.create_template %}class="text-muted"{% endif %}> <div class="tab-pane _overview">
<h2><i class="fa fa-puzzle-piece"></i> {% trans "Templates" %}</h2> {% include "info/help/overview.html" %}
{% if not perms.vm.create_template %}
<p class="text-warning">
{% trans "Sorry, you have no permission to create templates." %}
</p>
{% endif %}
<p>
{% blocktrans %}
<em>Templates</em> are the prototypes of virtual machine
instances: they contain configuration values for the different
technical details of a VM to create, and also the network
interfaces and disks to attach.
{% endblocktrans %}
</p><p>
{% blocktrans %}
In the dashboard box you see your own templates and those, for
which you have <em>operator</em> permission. This means that you can
share them with your groups or other users.
{% endblocktrans %}
</p><p>
{% blocktrans %}
You can create templates from any virtual machine with the
<span class="btn btn-info disabled btn-xs"><i class="fa fa-save"></i>
save as template</span>
button.
{% endblocktrans %}
{% blocktrans %}
Additionally, you can also click on the
<span class="btn btn-success disabled btn-xs">
<i class="fa fa-plus-circle"></i> new</span> button of the
template box, and follow the template creation wizard.
{% endblocktrans %}
</p>
</div>
<div id="groups" {% if not perms.auth %}class="text-muted"{% endif %}>
<h2><i class="fa fa-group"></i> {% trans "Groups" %}</h2>
{% if not perms.auth %}
<p class="text-warning">
{% trans "Sorry, you have no permission to create groups." %}
</p>
{% endif %}
<p>
{% blocktrans %}
Groups are the main building blocks of permission management.
On the dashboard you see a list of groups you have access to.
{% endblocktrans %}
</p><p>
{% blocktrans %}
You can also create your own groups by clicking on the
<span class="btn btn-success disabled btn-xs">
<i class="fa fa-plus-circle"></i> new</span> button of the
groups box.
{% endblocktrans %}
</p><p{% if not saml %} class="text-muted"{% endif %}>
{% blocktrans %}
Users logged in with SSO authentication can automatically become
members of groups based on its organizational identifier.
Those who are administrators of an organizational group (or a
professor of a subject in academics) can create groups with the
specific organizational identifier set, so members will
automatically added if they log in.
{% endblocktrans %}
{% blocktrans %}
You can also add users based on their identifier, also if they
have not logged in at the time.
{% endblocktrans %}
</p>
</div>
<div id="store" {% if not store or not user.is_authenticated %}class="text-muted"{% endif %}>
<h2><i class="fa fa-briefcase"></i> {% trans "Files" %}</h2>
{% if not store %}
<p class="text-warning">
{% trans "Sorry, this deployment of CIRCLE does not support file store." %}
</p>
{% endif %}
<p>
{% blocktrans %}
Each user has a simple personal file store, which is the easiest
way to keep and retrieve your work done on virtual machines.
{% endblocktrans %}
</p><p>
{% blocktrans %}
You can get and upload files from both the web interface and
from virtual machines. The web interface works like any other
graphical file browser. Virtual machines normally don't get the
credentials for your personal store, to prevent accidentally
sharing them with other users of the same machine. To use the
file store, press the
<span class="btn btn-info disabled btn-xs">
<i class="fa fa-briefcase"></i> mount store</span> button
of the virtual machine.
{% endblocktrans %}
</p><p>
{% blocktrans %}
{% endblocktrans %}
</div> </div>
</div> </div>
</div> </div> <!-- .content -->
</div> </div> <!-- #page-content .col-lg-8 -->
</div> </div>
{% endblock %} {% endblock %}
{% load i18n %}
<br/>
<h2 id="faq" >{% trans "FAQ" %}</h2>
<br/>
<h3 id="how-can-i-create-and-share-a-template">{% trans "How can I create and share a template?" %}</h3>
<blockquote>
<ol>
<li>{% trans "Start a virtual machine." %}</li>
<li>{% trans "Customize this machine - install and remove softwares, etc." %}</li>
<li>{% trans 'Click the “Save as Template” button.' %}</li>
<li>{% trans 'On the dashboard select this template to go to the "Edit template page".' %}</li>
<li>
{% trans 'Use the "Manage access" box to add a user or user group with "user" access level.' %}
(<a class="crosslink" data-menu="#overview_menu" href="#how-can-i-create-groups">
{% trans "You can easily create groups if you need to" %}</a>)
</li>
</ol>
</blockquote>
<h3 id="how-can-i-create-a-vm-and-give-to-another-user">{% trans "How can I create a VM and give to another user?" %}</h3>
<blockquote>
<ol>
<li>{% trans "Start a virtual machine." %}</li>
<li>{% trans "On the machine's Access panel you can grant access for users and groups to the VM." %}</li>
</ol>
</blockquote>
<h3 id="how-can-i-portforward">{% trans "How can I open ports?" %}</h3>
<blockquote>
<ol>
<li>{% trans "On the VM’s detail page click on the Network panel." %}</li>
<li>{% trans "On the prefered interface type the port number, select type and click ‘Add’." %}</li>
<li>{% trans "You have to open this port in the firewall too. Opening port 80 examples: " %}<br>
<ul>
<li>Ubuntu, Debian: <code>sudo ufw allow 80</code></li>
<li>
CentOS, RHEL: {% trans "append to" %} <code>/etc/sysconfig/iptables</code>:<br/>
<code>iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT</code>
{% trans "and restart the service:" %} <code>sudo service iptables restart</code>
</li>
</ul>
</li>
<li>{% trans "Now you can connect to the machine with the generated port number." %}</li>
</ol>
</blockquote>
<h3 id="my-machines-lease-is-short-how-can-i-extend-it">{% trans "My machine's lease is too short. How can I extend it?" %}</h3>
<blockquote>
<p>
{% blocktrans %}You can send a request to the administrators. On the VM's home panel click on the ‘renew’ button and ‘send request’.
Please explain why you need a longer lease and choose the most suitable one.{% endblocktrans %}
</p>
</blockquote>
<h3 id="how-can-i-have-more-cpumemory">{% trans "How can I have more CPU/memory?" %}</h3>
<blockquote>
<p>
{% blocktrans %}
You can send a request to the administrators.
On the VM's resources panel click <strong>Request&nbsp;more&nbsp;resources</strong>, modify the values, explain your request and finally hit save.
{% endblocktrans %}
</p>
</blockquote>
<h3 id="how-can-i-get-access-to-a-template">{% trans "How can I get access to a template?" %}</h3>
<blockquote>
<p>
{% blocktrans %}
When you want to create a VM below the template list there is an option to send a request.
Select which template you want, explain why you need it and then submit the form.
{% endblocktrans %}
</p>
</blockquote>
{% load i18n %}
<ul><a href="#faq">{% trans "FAQ" %}</a>
<li><a href="#how-can-i-create-and-share-a-template">{% trans "How can I create and share a template?" %}</a></li>
<li><a href="#how-can-i-create-a-vm-and-give-to-another-user">{% trans "How can I create a VM and give to another user?" %}</a></li>
<li><a href="#how-can-i-portforward">{% trans "How can I portforward?" %}</a></li>
<li><a href="#my-machines-lease-is-short-how-can-i-extend-it">{% trans "My machine’s lease is short. How can I extend it?" %}</a></li>
<li><a href="#how-can-i-have-more-cpumemory">{% trans "How can I have more CPU/memory?" %}</a></li>
<li><a href="#how-can-i-get-access-to-a-template">{% trans "How can I get acces to a template?" %}</a></li>
</li>
</ul>
{% load i18n %}
<br/>
<h2 id="overview" >{% trans "Overview" %}</h2>
<br/>
<h3 id="introduction">{% trans "Introduction" %}</h3>
<p>
{% blocktrans %}
This is a deployment of <a href="http://circlecloud.org/">CIRCLE Cloud</a>,
which is a free and open source cloud manager.
Its most important function is starting and managing virtual machine instances based on templates.
These templates are also easy to create.
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
Apart from this tutorial we recommend to try the system, it is quite intuitive,
and the web interface shows detailed instructions on advanced options.
{% endblocktrans %}
</p>
<h3 id="dashboard"><i class="fa fa-dashboard"></i> {% trans "Dashboard" %}</h3>
<p>
{% blocktrans with host=request.get_host %}
You can reach this service at <a href="//{{ host }}">https://{{host}}</a>
where you can log in to the dashboard.
The dashboard is a summary about your virtual machines and other resources,
and the main starting point to access the functions of the system.
{% endblocktrans %}
</p>
<h4 id="virtual-machines-box">{% trans "Virtual Machines box" %}</h4>
<p>
{% blocktrans %}
In the virtual machines box you will find your recent virtual machines.
A summary view is also available by clicking the dashboard button (<i class="fa fa-dashboard"></i>).
Click on the name of a virtual machine to see its connection details, preferences,
or to change its state.
{% endblocktrans %}
</p>
<h4 id="how-can-i-create-a-vm">{% trans "How can I create a VM?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
You can start a machine by clicking the
<span class="btn btn-success disabled btn-xs"><i class="fa fa-plus-circle"></i> new</span>
button and selecting a template. The machine starts automatically.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="how-can-i-mark-frequently-used-vms">{% trans "How can I mark frequently used VMs?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
Important or frequently used machines can be pinned with the <i class="fa fa-star-o"></i> button.
{% endblocktrans %}
</p>
</blockquote>
<div id="vms" {% if not perms.vm %} class="text-muted" {% endif %}>
<h3 id="virtual-machines"><i class="fa fa-desktop"></i> {% trans "Virtual Machines" %}</h3>
{% if not perms.vm %}
<p class="text-warning">
{% trans "Sorry, you have no permission to launch virtual machines." %}
</p>
{% endif %}
<p>
{% blocktrans %}
After selecting a virtual machine, you will see the machine’s detailed page.
Here, you can see the <strong>details</strong>, usage <strong>statistics</strong>,
<strong>manage</strong> the virtual machine, change <strong>access rights</strong> and
<strong>network interfaces</strong>, modify <strong>resources</strong>
and show the <strong>activity log</strong>.
{% endblocktrans %}
</p>
<h4 id="details">{% trans "Details" %}</h4>
<p>
{% blocktrans %}
If you select a virtual machine, you get to a page with all the details and operations listed.
On the left, you will see the state of the machine and a summary about how you can connect to the machine.
In the middle there is a tabbed pane, which contains details about the machine in categories.
{% endblocktrans %}
</p>
<h4 id="how-can-i-connect-to-the-virtual-machine">{% trans "How can I connect to the virtual machine?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
If the machine is already started click on the ‘connect’ button or simply copy the connection string to the terminal.
Another option is using the VNC console.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="how-can-i-change-the-vms-password">{% trans "How can I change the VM’s password?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
Click on the ‘Generate new password!’ link.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="operations">{% trans "Operations" %}</h4>
<p>
{% blocktrans %}
The upper right corner is the operation toolbar with the most important actions that control the lifecycle of the machine.
The tool buttons are color coded by their effect, and enabled/disabled based on the current state of the machine.
The recommended operation is always the biggest tool button with the name displayed.
You can click on them as the confirmation dialog explains in detail what they do.
{% endblocktrans %}
</p>
<h4 id="what-kind-of-operations-are-allowed-to-do-with-my-vm">{% trans "What kind of operations are allowed to do with my VM?" %}</h4>
<blockquote>
{% for view, op in operations %}
<p>
<span class="btn btn-xs btn-{{ view.effect }} disabled"><i class="fa fa-{{ view.icon }}"></i> {{ op.name }}</span>
{{ op.description }}
</p>
{% endfor %}
</blockquote>
<h4 id="home"><i class="fa fa-compass"></i> {% trans "Home" %}</h4>
<p>
{% blocktrans %}
This shows statistics about the virtual machine, and this is where you can change the name, description and tags of the instance.
We strongly advise to add a description to make the work of the cloud administrators easier in case of maintenance.
{% endblocktrans %}
</p>
<h4 id="expiration">{% trans "Expiration" %}</h4>
<p>
{% blocktrans %}
Here is a summary about the expiration times as well.
Each virtual machine has a deadline for suspending and destroying based on predefined leases.
{% endblocktrans %}
</p>
<h4 id="how-can-i-extend-the-vms-expiration-date">{% trans "How can I extend the VM's expiration date?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
With the renew button you can extend the suspend and remove time.
Before the virtual machine is suspended or removed you get a notification about it.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="how-can-i-share-previously-uploaded-files-with-the-vm">{% trans "How can I share previously uploaded files with the VM?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
With the ‘Mount Store’ option the virtual machine mounts your personal storage.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="resources"><i class="fa fa-tasks"></i> {% trans "Resources" %}</h4>
<p>
{% blocktrans %}
Resources contains details about how much <strong>memory</strong> and
<strong>CPU</strong> the VM has, and how is it <strong>scheduled</strong>.
Users with specific permission can change these settings if the machine is stopped.
{% endblocktrans %}
</p>
<p{% if not perms.vm.change_resources %} class="text-muted"{% endif %}>
{% blocktrans %}
Users with specific permission can change these settings if the machine is stopped.
{% endblocktrans %}
</p>
<h4 id="console"><i class="fa fa-desktop"></i> {% trans "Console" %}</h4>
<p>
{% blocktrans %}
This panel allows to see the console of the virtual machine for troubleshooting and operating system installation.
You can also use the keyboard and mouse.
You should normally use the machine by connecting remotely over SSH or Remote Desktop.
{% endblocktrans %}
</p>
<h4 id="access"><i class="fa fa-group"></i> {% trans "Access" %}</h4>
<p>
{% blocktrans %}
Allows sharing the machine with others and transferring the ownership.
Users can see the details of the machine, operators can use most functions and owners can also destroy the machine.
{% endblocktrans %}
</p>
<h4 id="how-can-i-give-access-to-others">{% trans "How can I give access to others?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
Type the user/group ID, set permissions and click
<span class="btn btn-success disabled">Save</span>.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="what-kind-of-permissions-are-available">{% trans "What kind of permissions are available?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
<strong>User</strong><br>
User level grants access to the virtual machine’s details page. Users are able to connect to this machine.
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
<strong>Operator</strong><br>
Operator level permit the modification of the name and description fields. Allow the operator to open ports and grant/revoke User level access to the virtual machine.
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
<strong>Owner</strong><br>
Owner level enables all operations on the virtual machine. Owners are able to grant/revoke Operator, User and Owner level access to others.
The accountable owner (the one who deployed the machine) can not be demoted.
The accountable ownership can be transferred to other User via the “Transfer onwership” button.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="network"><i class="fa fa-globe"></i> {% trans "Network" %}</h4>
<p>
{% blocktrans %}
Shows how the virtual machine is connected to the network.
You can add or remove interfaces and allow remote access of different TCP/UDP ports.
{% endblocktrans %}
</p>
<h4 id="how-can-i-add-a-network-interface">{% trans "How can I add a network interface?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
Click on the
<span class="btn btn-success disabled"><i class="fa fa-globe"></i> add interface</span>
on the Network pane and select from the list.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="activity"><i class="fa fa-clock-o"></i> {% trans "Activity" %}</h4>
<p>
{% blocktrans %}
Shows the full life cycle of the virtual machine.
This is where you can see the causes of failed actions (just point the mouse to the name of the action) with the starting/finishing times.
{% endblocktrans %}
</p>
<h4 id="multiple-vm-operations">{% trans "Multiple VM operations" %}</h4>
<p>
{% blocktrans %}
On the dashboard, by clicking the
<span class="btn btn-primary btn-xs disabled"><i class="fa fa-chevron-circle-right"></i> list</span>
button, the virtual machine list page opens.
Here the owner can execute operations on multiple virtual machines simultaneously.
{% endblocktrans %}
</p>
<h4 id="how-can-i-show-shared-or-destroyed-vms">{% trans "How can I see shared or destroyed VMs?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
Check the ‘Include deleted VMs’ checkbox to list already deleted machines.
{% endblocktrans %}
</p>
</blockquote>
</div> <!-- vms -->
<div id="templates" {% if not perms.vm.create_template %}class="text-muted"{% endif %}>
<h3 id="templates"><i class="fa fa-puzzle-piece"></i> {% trans "Templates" %}</h3>
{% if not perms.vm.create_template %}
<p class="text-warning">
{% trans "Sorry, you have no permission to create templates." %}
</p>
{% endif %}
<p>
{% blocktrans %}
Templates are the prototypes of virtual machine instances:
they contain <strong>configuration</strong> values for the different technical details
<strong>of a VM to create</strong>, and also the network interfaces and disks to attach.
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
In the dashboard box you see your own templates and those, for which you have operator permission.
This means that you can share them with your groups or other users.
{% endblocktrans %}
</p>
<h4 id="how-can-i-create-templates">{% trans "How can I create templates?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
You can create templates from any virtual machine with the save as template button.
Additionally, you can also click on the new button of the template box, and follow the template creation wizard.
{% endblocktrans %}
</p>
</blockquote>
<p>
{% blocktrans %}
On the template detail page you can modify the template's name and the given resources like CPU count and memory size.
{% endblocktrans %}
</p>
<h4 id="what-kind-of-options-are-customizable-in-the-template">{% trans "What kind of options are customizable in the template?" %}</h4>
<blockquote>
<p>
<h4>{% trans "Architecture" %}</h4>
The user can choose the template's architecture (x86 or x86-64).
</p>
<p>
<h4>{% trans "Access method" %}</h4>
The default access method is modifiable. Currently SSH, RDP and NX are supported.
</p>
<p>
<h4>{% trans "Boot menu" %} </h4>
Check it to turn on the boot menu.
</p>
<p>
<h4>{% trans "Traits" %}</h4>
By adding or removing traits we can guarantee specific features the host node will have (like <em>GPU</em>) for the virtual machine.
</p>
<p>
<h4>{% trans "Operating system" %}</h4>
The name of the operating system.
</p>
<p>
<h4>{% trans "Agent" %}</h4>
Check this if the machine has agent installed and the manager should wait for its start.
</p>
<p>
<h4>{% trans "Raw data" %}</h4>
The CIRCLE Cloud is using libvirt, so the owner can customize the running VM's options here by
<a href="https://libvirt.org/formatdomain.html">libvirt domain parameters</a>.
</p>
</blockquote>
<h4 id="how-can-i-give-the-template-to-other-user">{% trans "How can I transfer the template ownership to someone else?" %}</h4>
<blockquote>
<p>
{% blocktrans %}After clicking the ‘Transfer ownership’ you can select a user to give the template to.{% endblocktrans %}
</p>
</blockquote>
<h4 id="how-can-i-give-access-to-users-or-groups-to-the-template">{% trans "How can I grant access for users or groups to the template?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
Same as the VM access rights handling.
You can type the user or group ID at the template detail page's Manage access box and select a suitable access level.
{% endblocktrans %}
</p>
</blockquote>
</div>
<div id="groups" {% if not perms.auth %}class="text-muted"{% endif %}>
<h3 id="groups"><i class="fa fa-group"></i> {% trans "Groups" %}</h3>
{% if not perms.auth %}
<p class="text-warning">
{% trans "Sorry, you have no permission to create groups." %}
</p>
{% endif %}
<p>
{% blocktrans %}
Groups are the main building blocks of permission management. On the dashboard you see a list of groups you have access to.
{% endblocktrans %}
</p>
<h4 id="how-can-i-create-groups">{% trans "How can I create groups?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
You can create your own groups by clicking on the new button of the groups box.
{% endblocktrans %}
</p>
</blockquote>
<p{% if not saml %} class="text-muted"{% endif %}>
{% blocktrans %}
Users logged in with SSO authentication can automatically become members of groups based on its organizational identifier.
Those who are administrators of an organizational group (or a professor of a subject in academics)
can create groups with the specific organizational identifier set, so members will automatically added if they log in.
You can also add users based on their identifier, also if they have not logged in at the time.
{% endblocktrans %}
</p>
<h4 id="how-can-i-manage-the-users-in-a-group">{% trans "How can I manage the users in a group?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
On the group page the owner can add or remove users or change the access rights over the group.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="how-can-i-manage-privileges-with-the-group">{% trans "How can I manage privileges with the group?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
The owner can add or remove privileges at the bottom of the group page like ‘can download disk’ or ‘can configure port forwards’.
{% endblocktrans %}
</p>
</blockquote>
</div><!-- #groups -->
<div id="store" {% if not store or not user.is_authenticated %}class="text-muted"{% endif %}>
<h3 id="files"><i class="fa fa-briefcase"></i> {% trans "Files" %}</h3>
{% if not store %}
<p class="text-warning">
{% trans "Sorry, this deployment of CIRCLE does not support file store." %}
</p>
{% endif %}
<p>
{% blocktrans %}
Each user has a simple personal file store, which is the easiest way to keep and retrieve your work done on virtual machines.
{% endblocktrans %}
</p>
<p>
{% blocktrans %}
You can get and upload files from both the web interface and from virtual machines.
The web interface works like any other graphical file browser.
Virtual machines normally don’t get the credentials for your personal store,
to prevent accidentally sharing them with other users of the same machine.
{% endblocktrans %}
</p>
<h4 id="how-can-i-share-my-files-with-a-vm">{% trans "How can I share my files with a VM?" %}</h4>
<blockquote>
<p>{% blocktrans %}To access the file store press the mount store button on the virtual machine's home panel.{% endblocktrans %}</p>
</blockquote>
</div>
<h3 id="profile"><i class="fa fa-user"></i> {% trans "Profile" %}</h3>
<h4 id="how-can-i-change-my-password">{% trans "How can I change my password?" %}</h4>
<blockquote>
<p>
{% blocktrans %}
On the profile page type the new password twice and the old password. Users can’t change passwords if the profile is using SSO.
{% endblocktrans %}
</p>
</blockquote>
<h4 id="how-can-i-store-public-keys-on-the-vms">{% trans "How can I store public keys on the VMs?" %}</h4>
<blockquote>
<p>
{% blocktrans %}Go to your profile page, click on the ‘add SSH key’ and paste your public key's content to the textarea.{% endblocktrans %}
</p>
</blockquote>
{% load i18n %}
<ul>
<a href="#overview">{% trans "Overview" %}</a>
<li><ul><a href="#introduction">{% trans "Introduction" %}</a></ul></li>
<li>
<ul><a href="#dashboard">{% trans "Dashboard" %}</a>
<li><a href="#virtual-machines-box">{% trans "Virtual Machines box" %}</a>
<ul>
<li><a href="#how-can-i-create-a-vm">{% trans "How can I create a VM?" %}</a></li>
<li><a href="#how-can-i-mark-frequently-used-vms">{% trans "How can I mark frequently used VMs?" %}</a></li>
<li><a href="#how-can-i-search-for-vms">{% trans "How can I search for VMs?" %}</a></li>
</ul>
</li>
<li><a href="#templates-box">{% trans "Templates box" %}</a></li>
</ul>
</li>
<li>
<ul><a href="#virtual-machines">{% trans "Virtual Machines" %}</a>
<li>
<ul><a href="#details">{% trans "Details" %}</a>
<li><a href="#how-can-i-connect-to-the-virtual-machine">{% trans "How can I connect to the virtual machine?" %}</a></li>
<li><a href="#how-can-i-change-the-vms-password">{% trans "How can I change the VM’s password?" %}</a></li>
</ul>
</li>
<li>
<ul><a href="#operations">{% trans "Operations" %}</a>
<li><a href="#what-kind-of-operations-are-allowed-to-do-with-my-vm">{% trans "What kind of operations are allowed to do with my VM?" %}</a></li>
<li>
</ul>
</li>
<li>
<ul><a href="#home">{% trans "Home" %}</a>
<li><a href="#expiration">{% trans "Expiration" %}</a></li>
<li><a href="#how-can-i-expand-the-vms-expiration-date">{% trans "How can I expand the VM’s expiration date?" %}</a></li>
<li><a href="#file-management">{% trans "File management" %}</a></li>
<li><a href="#how-can-i-share-previously-uploaded-files-with-the-vm">{% trans "How can I share previously uploaded files with the VM?" %}</a></li>
</ul>
</li>
<li><ul><a href="#resources">{% trans "Resources" %}</a></ul></li>
<li><a href="#console">{% trans "Console" %}</a></li>
<li><a href="#access">{% trans "Access" %}</a><ul>
<li><a href="#how-can-i-give-access-to-others">{% trans "How can I give access to others?" %}</a></li>
<li><a href="#what-kind-of-permissions-are-available">{% trans "What kind of permissions are available?" %}</a></li>
<li>
<ul><a href="#network">{% trans "Network" %}</a>
<li><a href="#how-can-i-add-a-network-interface">{% trans "How can I add a network interface?" %}</a></li>
</ul>
</li>
<li><a href="#activity">{% trans "Activity" %}</a></li>
<li><a href="#multiple-vm-operations">{% trans "Multiple VM operations" %}</a>
<li><a href="#how-can-i-show-shared-or-destroyed-vms">{% trans "How can I show shared or destroyed VMs?" %}</a></li>
</ul>
</li>
</ul>
</li>
<li>
<ul><a href="#templates">{% trans "Templates" %}</a>
<li><a href="#how-can-i-create-templates">{% trans "How can I create templates?" %}</a></li>
<li><a href="#what-kind-of-options-are-customizable-in-the-template">{% trans "What kind of options are customizable in the template?" %}</a></li>
<li><a href="#how-can-i-change-the-expiration-of-the-templates-vms">{% trans "How can I change the expiration of the tempalte's VMs" %}</a></li>
<li><a href="#how-can-i-give-the-template-to-other-user">{% trans "How can I give the template to other user" %}</a></li>
<li><a href="#how-can-i-give-access-to-users-or-groups-to-the-template">{% trans "How can I give access to users or groups to the template?"%}</a></li>
</ul>
</li>
<li>
<ul><a href="#groups">{% trans "Groups" %}</a>
<li><a href="#how-can-i-create-groups">{% trans "How can I create groups?" %}</a></li>
<li><a href="#how-can-i-manage-the-users-in-a-group">{% trans "How can I manage the users in a group?" %}</a></li>
<li><a href="#how-can-i-manage-privileges-with-the-group">{% trans "How can I manage privileges with the group?" %}</a></li>
</ul>
</li>
<li>
<ul><a href="#files">{% trans "Files" %}</a>
<li><a href="#how-can-i-share-my-files-with-a-vm">{% trans "How can I share my files with a VM?" %}</a></li>
</ul>
</li>
<li>
<ul><a href="#profile">{% trans "Profile" %}</a>
<li><a href="#how-can-i-change-my-password">{% trans "How can I change my password?" %}</a></li>
<li><a href="#how-can-i-store-public-keys-on-the-vms">{% trans "How can I store public keys on the VMs?" %}</a></li>
<li><a href="#how-can-i-change-connection-template">{% trans "How can I change connection template" %}</a></li>
</ul>
</li>
</ul>
...@@ -28,6 +28,7 @@ import time ...@@ -28,6 +28,7 @@ import time
from urlparse import urlsplit from urlparse import urlsplit
from django.core.exceptions import PermissionDenied, SuspiciousOperation from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.core.urlresolvers import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _, ugettext_noop from django.utils.translation import ugettext_lazy as _, ugettext_noop
from django.conf import settings from django.conf import settings
...@@ -794,7 +795,10 @@ class SaveAsTemplateOperation(InstanceOperation): ...@@ -794,7 +795,10 @@ class SaveAsTemplateOperation(InstanceOperation):
tmpl.delete() tmpl.delete()
raise raise
else: else:
return tmpl return create_readable(
ugettext_noop("New template: %(template)s"),
template=reverse('dashboard.views.template-detail',
kwargs={'pk': tmpl.pk}))
@register_operation @register_operation
...@@ -986,7 +990,7 @@ class RenewOperation(InstanceOperation): ...@@ -986,7 +990,7 @@ class RenewOperation(InstanceOperation):
if save: if save:
self.instance.lease = lease self.instance.lease = lease
self.instance.save() self.instance.save()
activity.result = create_readable(ugettext_noop( return create_readable(ugettext_noop(
"Renewed to suspend at %(suspend)s and destroy at %(delete)s."), "Renewed to suspend at %(suspend)s and destroy at %(delete)s."),
suspend=suspend, delete=delete) suspend=suspend, delete=delete)
...@@ -1357,7 +1361,7 @@ class ResourcesOperation(InstanceOperation): ...@@ -1357,7 +1361,7 @@ class ResourcesOperation(InstanceOperation):
self.instance.full_clean() self.instance.full_clean()
self.instance.save() self.instance.save()
activity.result = create_readable(ugettext_noop( return create_readable(ugettext_noop(
"Priority: %(priority)s, Num cores: %(num_cores)s, " "Priority: %(priority)s, Num cores: %(num_cores)s, "
"Ram size: %(ram_size)s"), priority=priority, num_cores=num_cores, "Ram size: %(ram_size)s"), priority=priority, num_cores=num_cores,
ram_size=ram_size ram_size=ram_size
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment