Commit ce868137 authored by Olga Brani's avatar Olga Brani
Browse files

Merge branch 'latest-quota' of https://code.grnet.gr/git/synnefo into latest-quota

parents c2cd6eb4 dc9ade6a
......@@ -86,14 +86,17 @@ def api_method(http_method=None):
return decorator
@api_method(http_method='GET')
def get_services(request):
callback = request.GET.get('callback', None)
def get_services_dict():
services = Service.objects.all()
data = tuple({'id': s.pk, 'name': s.name, 'url': s.url, 'icon':
s.icon} for s in services)
data = json.dumps(data)
return data
@api_method(http_method=None)
def get_services(request):
callback = request.GET.get('callback', None)
mimetype = 'application/json'
data = json.dumps(get_services_dict())
if callback:
mimetype = 'application/javascript'
......@@ -126,7 +129,7 @@ def get_menu(request, with_extra_links=False, with_signout=True):
append(item(
url=absolute(request, reverse('invite')),
name="Invitations"))
if QUOTAHOLDER_URL:
append(item(
url=absolute(request, reverse('project_list')),
......
......@@ -45,6 +45,9 @@ from . import render_fault
from astakos.im.models import AstakosUser
from astakos.im.util import epoch
from astakos.im.api.callpoint import AstakosCallpoint
callpoint = AstakosCallpoint()
logger = logging.getLogger(__name__)
format = ('%a, %d %b %Y %H:%M:%S GMT')
......@@ -114,6 +117,17 @@ def authenticate(request, user=None):
'auth_token_created': epoch(user.auth_token_created),
'auth_token_expires': epoch(user.auth_token_expires),
'has_credits': user.has_credits}
# append usage data if requested
if request.REQUEST.get('usage', None):
resource_usage = None
result = callpoint.get_user_usage(user.id)
if result.is_success:
resource_usage = result.data
else:
resource_usage = []
user_info['usage'] = resource_usage
response.content = json.dumps(user_info)
response['Content-Type'] = 'application/json; charset=UTF-8'
response['Content-Length'] = len(response.content)
......
......@@ -46,6 +46,7 @@ if QUOTAHOLDER_URL:
from kamaki.clients.quotaholder import QuotaholderClient
ENTITY_KEY = '1'
PRACTICALLY_INF = pow(2, 70)
inf = float('inf')
......@@ -134,8 +135,8 @@ def register_users(users):
key=ENTITY_KEY,
quantity=0,
capacity=uplimit if uplimit != inf else None,
import_limit=0,
export_limit=0,
import_limit=PRACTICALLY_INF,
export_limit=PRACTICALLY_INF,
flags=0))
return set_quota(payload)
......@@ -154,10 +155,10 @@ def register_resources(resources):
holder=resource.service,
resource=resource,
key=ENTITY_KEY,
quantity=None,
capacity=None,
import_limit=None,
export_limit=None,
quantity=0,
capacity=0,
import_limit=PRACTICALLY_INF,
export_limit=PRACTICALLY_INF,
flags=0) for resource in resources)
return set_quota(payload)
......
......@@ -627,41 +627,128 @@ class ExtendedSetPasswordForm(SetPasswordForm):
return super(ExtendedSetPasswordForm, self).save(commit=commit)
app_name_label = "Project name"
app_name_placeholder = _("myproject.mylab.ntua.gr")
app_name_validator = validators.RegexValidator(
DOMAIN_VALUE_REGEX,
_(astakos_messages.DOMAIN_VALUE_ERR),
'invalid')
app_name_help = _("""
The Project's name should be in a domain format.
The domain shouldn't neccessarily exist in the real
world but is helpful to imply a structure.
e.g.: myproject.mylab.ntua.gr or
myservice.myteam.myorganization""")
app_name_widget = forms.TextInput(
attrs={'placeholder': app_name_placeholder})
app_home_label = "Homepage URL"
app_home_placeholder = 'http://myteam.myinstitution.org/myproject/'
app_home_help = _("""
URL pointing at your project's site.
e.g.: http://myteam.myinstitution.org/myproject.
Leave blank if there is no website.""")
app_home_widget = forms.TextInput(
attrs={'placeholder': app_home_placeholder})
app_desc_label = _("Description")
app_desc_help = _("""
Please provide a short but descriptive abstract of your Project,
so that anyone searching can quickly understand
what this Project is about.""")
app_comment_label = _("Comments for review (private)")
app_comment_help = _("""
Write down any comments you may have for the reviewer
of this application (e.g. background and rationale to
support your request).
The comments are strictly for the review process
and will not be published.""")
app_start_date_label = _("Start date")
app_start_date_help = _("""
Provide a date when your need your project to be created,
and members to be able to join and get resources.
This date is only a hint to help prioritize reviews.""")
app_end_date_label = _("Termination date")
app_end_date_help = _("""
At this date, the project will be automatically terminated
and its resource grants revoked from all members.
Unless you know otherwise,
it is best to start with a conservative estimation.
You can always re-apply for an extension, if you need.""")
join_policy_label = _("Joining policy")
leave_policy_label = _("Leaving policy")
max_members_label = _("Maximum member count")
max_members_help = _("""
Specify the maximum number of members this project may have,
including the owner. Beyond this number, no new members
may join the project and be granted the project resources.
Unless you certainly for otherwise,
it is best to start with a conservative limit.
You can always request a raise when you need it.""")
join_policies = PROJECT_MEMBER_JOIN_POLICIES.iteritems()
leave_policies = PROJECT_MEMBER_LEAVE_POLICIES.iteritems()
class ProjectApplicationForm(forms.ModelForm):
name = forms.CharField(
validators=[validators.RegexValidator(
DOMAIN_VALUE_REGEX,
_(astakos_messages.DOMAIN_VALUE_ERR),
'invalid'
)],
widget=forms.TextInput(
attrs={'placeholder': 'myproject.mylab.ntua.gr'}),
help_text="""The Project's name should be in a domain format.
The domain shouldn't neccessarily exist in the real
world but is helpful to imply a structure.
e.g.: myproject.mylab.ntua.gr or
myservice.myteam.myorganization"""
)
label = app_name_label,
help_text = app_name_help,
widget = app_name_widget,
validators = [app_name_validator])
homepage = forms.URLField(
label="Homepage Url",
help_text="""This should be a URL pointing at your project's site.
e.g.: http://myproject.com""",
widget=forms.TextInput(attrs={'placeholder': 'http://myproject.com'}),
label = app_home_label,
help_text = app_home_help,
widget = app_home_widget,
required = False)
description = forms.CharField(
label = app_desc_label,
help_text = app_desc_help,
widget = forms.Textarea,
required = False)
comments = forms.CharField(
label = app_comment_label,
help_text = app_comment_help,
widget = forms.Textarea,
required = False)
start_date = forms.DateTimeField(
label = app_start_date_label,
help_text = app_start_date_help,
required = False)
end_date = forms.DateTimeField(
label = app_end_date_label,
help_text = app_end_date_help)
member_join_policy = forms.ChoiceField(
label = join_policy_label,
choices = join_policies)
required=False
)
comments = forms.CharField(widget=forms.Textarea, required=False)
member_join_policy = forms.ChoiceField(
choices=PROJECT_MEMBER_JOIN_POLICIES.iteritems())
member_leave_policy = forms.ChoiceField(
choices=PROJECT_MEMBER_LEAVE_POLICIES.iteritems())
label = leave_policy_label,
choices = leave_policies)
limit_on_members_number = forms.IntegerField(
label = max_members_label,
help_text = max_members_help,
required = False)
class Meta:
model = ProjectApplication
exclude = (
'project',
'resource_grants', 'id', 'applicant', 'owner',
'precursor_application', 'state', 'issue_date')
#include = ( 'name', 'homepage', 'description',
# 'start_date', 'end_date', 'comments')
def __init__(self, *args, **kwargs):
self.precursor_application = kwargs.get('instance')
......
......@@ -1152,20 +1152,14 @@ class ProjectApplication(models.Model):
blank=True,
db_index=True)
name = models.CharField(max_length=80,
help_text=_("The Project's name should be in a domain format. The domain shouldn't neccessarily exist in the real world but is helpful to imply a structure. e.g.: myproject.mylab.ntua.gr or myservice.myteam.myorganization"))
homepage = models.URLField(max_length=255,
null=True,
blank=True,help_text=_("This should be a URL pointing at your project's site. e.g.: http://myproject.com ",))
description = models.TextField(null=True,
blank=True,
help_text=_("Please provide a short but descriptive abstract of your Project, so that anyone searching can quickly understand what this Project is about. "))
start_date = models.DateTimeField(help_text=_("Here you specify the date you want your Project to start granting its resources. Its members will get the resources coming from this Project on this exact date."))
end_date = models.DateTimeField(help_text=_("Here you specify the date you want your Project to cease. This means that after this date all members will no longer be able to allocate resources from this Project. "))
name = models.CharField(max_length=80)
homepage = models.URLField(max_length=255, null=True)
description = models.TextField(null=True, blank=True)
start_date = models.DateTimeField()
end_date = models.DateTimeField()
member_join_policy = models.IntegerField()
member_leave_policy = models.IntegerField()
limit_on_members_number = models.PositiveIntegerField(null=True,
blank=True,help_text=_("Here you specify the number of members this Project is going to have. This means that this number of people will be granted the resources you will specify in the next step. This can be '1' if you are the only one wanting to get resources. "))
limit_on_members_number = models.PositiveIntegerField(null=True)
resource_grants = models.ManyToManyField(
Resource,
null=True,
......
......@@ -4,14 +4,15 @@
 
</div>
<div class="lt">
<p>
{% blocktrans %}
~okeanos gives the opportunity to Greek Academic or Research Organizations/Institutions/Faculty
to run their own projects remotely on virtual infrastructure. Simple, fast and with minimal to no cost at all.
~okeanos gives the opportunity to
Greek Academic or Research Organizations/Institutions/Faculty
to run their own projects remotely on virtual infrastructure.
Simple, fast, and with minimal to no cost at all.
{% endblocktrans %}
</p>
<p><a href="{% url how_it_works %}" style="font-size:1.154em;">{% trans "How it works &gt;" %}</a></p>
<p><a href="{% url how_it_works %}" style="font-size:1.154em;">How it works ></a></p>
</div>
</div>
......@@ -22,15 +23,15 @@
<li class="create">
<div>
<div class="wrap">
<p class="centered"><a href="{% url project_add %}"><img alt="THINK ABOUT IT" src="/static/im/images/create.png"></a></p>
<p class="txt">
{% blocktrans %}
Create a new Project in seconds.
Specify how many members it will have, which and how many virtual
resources it will provide to its members. Describe its purpose.
Submit your request and if accepted, you and your colleagues are ready to deploy!<br><br> </p>
Create a new Project. Name it, describe its purpose,
choose virtual resources to be granted to members, and submit.
Your application will be reviewed, and if accepted,
you and your colleagues are ready to deploy!<br/><br/>
{% endblocktrans %}
</p>
<p><a href="{% url project_add %}">create a project ></a></p>
</div>
</div>
......@@ -41,10 +42,13 @@
<p class="centered"><a href="{% url project_search %}"><img alt="THINK ABOUT IT" src="/static/im/images/join.png"></a></p>
<p class="txt">
{% blocktrans %}
Become a member of an existing Project and instantly gain access to the resources
it has to offer you. Search for open Projects and join for free. Contact the closed
Projects administrators, if you think they will accept you. In two words: try to Join now. </p>
Request to be a member of an existing Project
and instantly gain access to the resources it has to offer you.
Search for public Projects, or submit a join request to a private Project,
if you think its administrators will accept you.
In short: try to Join now.
{% endblocktrans %}
</p>
<p><a href="{% url project_search %}">join a project ></a></p>
</div>
</div>
......
......@@ -18,7 +18,9 @@
1. PROJECT DETAILS
<span class="info">
<em>more info</em>
<span> To create a new Project, first enter the following required fields. The information you enter will be visible to all ~okeanos users. </span>
<span> To create a new Project, first enter the following required fields.
The information you enter (except <em>Comments for review)</em>)
will be visible to all ~okeanos users. </span>
</span>
</legend>
{% for field in form %}
......
......@@ -100,7 +100,7 @@ from astakos.im.settings import (
LOGGING_LEVEL, PAGINATE_BY,
RESOURCES_PRESENTATION_DATA, PAGINATE_BY_ALL,
MODERATION_ENABLED)
from astakos.im.api import get_services
from astakos.im.api import get_services_dict
from astakos.im import settings as astakos_settings
from astakos.im.api.callpoint import AstakosCallpoint
from astakos.im import auth_providers
......@@ -399,13 +399,7 @@ def edit_profile(request, template_name='im/profile.html', extra_context=None):
# providers that user can add
user_available_providers = request.user.get_available_auth_providers()
try:
resp = get_services(request)
except Exception, e:
services = ()
else:
services = json.loads(resp.content)
extra_context['services'] = services
extra_context['services'] = get_services_dict()
return render_response(template_name,
profile_form = form,
user_providers = user_providers,
......
Synnefo Projects
================
Synnefo Projects: General Design Notes
======================================
Projects can be thought of as "contracts" between the infrastructure
and the members of the Project, so that members can allocate and use
resources for a specified period in time.
For every Project there is an *application*, and a *membership set*.
The application must be approved before the Project "contract"
comes in effect, and before any members join.
Applications contain a Project *definition* that formally includes
all the policy of the Project "contract", such as name, ownership,
dates, and resource limits.
Applications and the definitions they contain are, like contracts,
immutable objects that can be tracked and effected in their entirety.
Every change made to a pending application or an existing Project
must be applied for through a new application.
Project Synchronization
-----------------------
A Project has two kinds of effects, global and per-membership.
Global effects are encoded within the Project object itself,
and may include services (e.g. dns name, website, forum/collaboration),
project-wide resources (e.g. VMs, IPs, diskspace), etc.
Per-membership effects are encoded within Membership objects,
and are prescribed by the policy in the project definition.
By design, the effects of the project are expected to extend
beyond the database system that records the project approval,
therefore these effects cannot be relied to be implemented
instantly and atomically upon request.
For example, project creation or modification may involve
updating resource management services, notification services,
project website services, which may all have their own separate
database systems.
Consequently, once a policy is (atomically) registered as being in effect,
it must be propagated for implementation with separate (non-atomic) procedures,
collectively called Project Synchronization.
Currently, the general approach for Synchronization of synnefo Projects,
is to maintain appropriate states for the objects encoding policy effects
(i.e. Project and Membership objects), and execute careful transitions
among those states, respecting semanting dependencies and limitations,
and remote system accesses.
For example, a project cannot be considered "synchronized" unless
all its Memberships are also considered "synchronized",
or you cannot declare a Membership as synchronized if the newly-set
quotas have not been acknowledged by the remote quota service.
Creating and Modifying Projects
-------------------------------
Projects are created and modified by issuing a corresponding application.
Applications that refer to the same Project are chained by including
a reference to the precursor application into the new one.
Applications that do not specify a precursor always create a new Project
(that is, a new project object with a new membership set).
Project applications that have not yet been approved may also be modified.
When an unapproved application is modified (ie. it is succeeded by another),
it may or may not be automatically rejected, depending on policy.
Projects once created, are expected to always remain in record,
even if they have been deactivated (i.e. their policies removed from effect).
Deactivating a project may be the result of a policy-specific action,
such as *termination* on a pre-defined date or *suspension* following
an administrative decision.
Deactivated projects retain both their Definition and their Membership sets,
allowing them to be reactivated by another kind of policy-specific action.
Adding and Removing Project Members
-----------------------------------
Memberships once created, are also expected to remain in historical record,
even if they have been marked as removed by a policy-specific action,
such as the user leaving the project,
or the project owner suspending, or terminating them altogether.
Reference Schema for Projects
=============================
General Terms
-------------
For clarity and precision, we (try to) use different terms for similar meanings.
We also separate low-level technical primitives from related higher-level
policy actions that include them.
synchronize, synchronized, synchronization
A low-level term for Projects and Memberships.
Refers to the controlled (non-atomic) process that implements
a newly modified policy (i.e. adds or removes policy effects
such as quota limits).
activate, deactivate, active, inactive
A low-level term for Projects and Memberships.
A Project or Membership is considered active as long as
its policy is in effect.
suspend, suspended, suspension
A policy term for Projects and Memberships,
implying temporary deactivation by an administrative action
(e.g. abuse report, limits violation).
terminate, terminated, termination
A policyu term for Projects and Memberships,
implying permanent deactivation, especially
according to a pre-defined end-of-life event
(e.g. project/contract "expiration").
add or remove membership
Low-level terms for managing memberships to projects.
join or leave project
Policy terms for when users request their addition or removal
from a project membership set.
accept or reject membership request
Policy terms for a project administrator to decide on
join or leave requests.
approve or disapprove project
Policy terms for service administrators to decide whether
to create/activate a project according or not
alter project
Low-level term for changes made to the global (i.e. not Membership)
project status (e.g. new application, suspension).
modify project
Policy term for submitting a new application as a successor
to an existing one, to alter the definition of a project.
project leader
The user who has authority over a project,
to accept or reject membership requests,
or to perform other actions according to policy.
project applicant
The user who submits a project application for creation
or modification of a project.
The applicant can be a different user than the leader.
project administrator
A user who has authority to approve, disapprove, and modify
projects of a certain class (e.g. according to their domain names).
Projects can be thought of as contracts between the infrastructure
and the members of the project, so that resources can be allocated
by the members and used for a specified period in time.
Definition
----------
......@@ -17,10 +157,10 @@ or modification of a project, has the following attributes:
*text describing the project for the public*
``start_date``
*when the project is to be started*
*when the project is requested to become active*
``end_date``
*when the project is to be ended*
*when the project is to be deactivatedended*
``member_join_policy``
*an enumeration of policies on how new join requests are to be accepted.
......@@ -48,7 +188,7 @@ or modification of a project, has the following attributes:
``closed``
*no member can leave the project*
``limit_on_members_number``
``limit_on_member_count``
*the maximum number of members that can be admitted to the project*
``limits_on_resources``
......@@ -62,7 +202,7 @@ or modification of a project, has the following attributes:
Application for a Project
-------------------------
An **application** for a project must be issued by a user and
approved by the Service before any resources are granted.
*approved* by the service before any resources are granted.
Its attributes are:
``serial``
......@@ -96,14 +236,14 @@ The *application status* can be:
:(2b): rejected
:(3): replaced
When an application becomes *approved* and set to the project,
its precursor must automatically be set to *replaced*.
When an application becomes *approved* and therefore defines
a the project, its precursor (if any) must atomically be set to *replaced*.
Project Membership
-------------------------
A *project membership* object maps a user to a project and holds
state for this mapping.
A *project membership* maps a user to a project and holds state for this mapping.
There are no inherent constraints to this mapping,
any user might be a member to any project.
......@@ -117,13 +257,15 @@ The **state** of membership can be:
:(5): *removed, pending synchronization*
:(6): *removed*
The transitions from 2b to 3, and 5 to 6, must first
commit their starting state and then only update to the next state
The transitions from 2b to 3, and 5 to 6, must first commit
their starting state and then only update to the next state
after the *Synchronize Membership* procedure has been
acknowledged as successful.
Except states 2b and 5 which explicitly state that they are *pending*,
all other states are considered *synchronized*
Except states 2b and 5, which explicitly state that they are
*pending synchronization*, all other states are considered *synchronized*
**Synchronization** refers to all external communication
(i.e. not within the limits to) required
......@@ -142,19 +284,6 @@ The attributes for a project are:
``application``
*the last application that was successfully synchronized with Quotaholder.*
``last_application_approved``
*the application which has created or modified the project.
An application is approved by setting it to this attribute.
Normally, this is the same as the ``application`` above.
However, on approval, only ``last_application_approved`` is set
so the two attributes differ, marking the project as pending definition
synchronization. Upon successful synchronization with Quotaholder,
``application`` is also set, marking the project definition synchronized.
Note that if during the synchronization another approval
updates ``last_application_approved``, then after synchronization
the project is still out of sync, and needs another loop.*
``creation_date``
*when the project was created (i.e. was first approved)*
......@@ -162,27 +291,21 @@ The attributes for a project are:
*when was the last approval (i.e. creation or modification).
Null if the project has not been approved or has been suspended.*
``termination_start_date``
*when the project was ordered to terminate,
``deactivation_start_date``
*when the project was ordered to deactivate,