root / snf-astakos-app / astakos / im / management / commands / project-modify.py @ b6426ead
History | View | Annotate | Download (6.8 kB)
1 |
# Copyright 2013-2014 GRNET S.A. All rights reserved.
|
---|---|
2 |
#
|
3 |
# Redistribution and use in source and binary forms, with or
|
4 |
# without modification, are permitted provided that the following
|
5 |
# conditions are met:
|
6 |
#
|
7 |
# 1. Redistributions of source code must retain the above
|
8 |
# copyright notice, this list of conditions and the following
|
9 |
# disclaimer.
|
10 |
#
|
11 |
# 2. Redistributions in binary form must reproduce the above
|
12 |
# copyright notice, this list of conditions and the following
|
13 |
# disclaimer in the documentation and/or other materials
|
14 |
# provided with the distribution.
|
15 |
#
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
# POSSIBILITY OF SUCH DAMAGE.
|
28 |
#
|
29 |
# The views and conclusions contained in the software and
|
30 |
# documentation are those of the authors and should not be
|
31 |
# interpreted as representing official policies, either expressed
|
32 |
# or implied, of GRNET S.A.
|
33 |
|
34 |
from optparse import make_option |
35 |
|
36 |
from django.db.models import Q |
37 |
from django.core.management.base import CommandError |
38 |
from django.db import transaction |
39 |
from synnefo.util import units |
40 |
from astakos.im import functions |
41 |
from astakos.im import models |
42 |
import astakos.api.projects as api |
43 |
import synnefo.util.date as date_util |
44 |
from snf_django.management import utils |
45 |
from astakos.im.management.commands import _common |
46 |
from snf_django.management.commands import SynnefoCommand |
47 |
|
48 |
|
49 |
def make_policies(limits): |
50 |
policies = {} |
51 |
for (name, member_capacity, project_capacity) in limits: |
52 |
try:
|
53 |
member_capacity = units.parse(member_capacity) |
54 |
project_capacity = units.parse(project_capacity) |
55 |
except units.ParseError:
|
56 |
m = "Please specify capacity as a decimal integer"
|
57 |
raise CommandError(m)
|
58 |
policies[name] = {"member_capacity": member_capacity,
|
59 |
"project_capacity": project_capacity}
|
60 |
return policies
|
61 |
|
62 |
Simple = type('Simple', (), {}) |
63 |
|
64 |
|
65 |
class Param(object): |
66 |
def __init__(self, key=Simple, mod=Simple, action=Simple, nargs=Simple, |
67 |
is_main=False, help=""): |
68 |
self.key = key
|
69 |
self.mod = mod
|
70 |
self.action = action
|
71 |
self.nargs = nargs
|
72 |
self.is_main = is_main
|
73 |
self.help = help
|
74 |
|
75 |
|
76 |
PARAMS = { |
77 |
"name": Param(key="realname", help="Set project name"), |
78 |
"owner": Param(mod=_common.get_accepted_user, help="Set project owner"), |
79 |
"homepage": Param(help="Set project homepage"), |
80 |
"description": Param(help="Set project description"), |
81 |
"end_date": Param(mod=date_util.isoparse, is_main=True, |
82 |
help=("Set project end date in ISO format "
|
83 |
"(e.g. 2014-01-01T00:00Z)")),
|
84 |
"join_policy": Param(key="member_join_policy", is_main=True, |
85 |
mod=(lambda x: api.MEMBERSHIP_POLICY[x]),
|
86 |
help="Set join policy (auto, moderated, or closed)"),
|
87 |
"leave_policy": Param(key="member_leave_policy", is_main=True, |
88 |
mod=(lambda x: api.MEMBERSHIP_POLICY[x]),
|
89 |
help=("Set leave policy "
|
90 |
"(auto, moderated, or closed)")),
|
91 |
"max_members": Param(key="limit_on_members_number", mod=int, is_main=True, |
92 |
help="Set maximum members limit"),
|
93 |
"private": Param(mod=utils.parse_bool, is_main=True, |
94 |
help="Set project private"),
|
95 |
"limit": Param(key="resources", mod=make_policies, is_main=True, |
96 |
nargs=3, action="append", |
97 |
help=("Set resource limits: "
|
98 |
"resource_name member_capacity project_capacity")),
|
99 |
} |
100 |
|
101 |
|
102 |
def make_options(): |
103 |
options = [] |
104 |
for key, param in PARAMS.iteritems(): |
105 |
opt = "--" + key.replace('_', '-') |
106 |
kwargs = {} |
107 |
if param.action is not Simple: |
108 |
kwargs["action"] = param.action
|
109 |
if param.nargs is not Simple: |
110 |
kwargs["nargs"] = param.nargs
|
111 |
kwargs["help"] = param.help
|
112 |
options.append(make_option(opt, **kwargs)) |
113 |
return tuple(options) |
114 |
|
115 |
|
116 |
class Command(SynnefoCommand): |
117 |
args = "<project id> (or --all-base-projects)"
|
118 |
help = "Modify an already initialized project"
|
119 |
option_list = SynnefoCommand.option_list + make_options() + ( |
120 |
make_option('--all-base-projects',
|
121 |
action='store_true',
|
122 |
default=False,
|
123 |
help="Modify in bulk all initialized base projects"),
|
124 |
make_option('--exclude',
|
125 |
help=("If `--all-base-projects' is given, exclude projects"
|
126 |
" given as a list of uuids: uuid1,uuid2,uuid3")),
|
127 |
) |
128 |
|
129 |
def check_args(self, args, all_base, exclude): |
130 |
if all_base and args or not all_base and len(args) != 1: |
131 |
m = "Please provide a project ID or --all-base-projects"
|
132 |
raise CommandError(m)
|
133 |
if not all_base and exclude: |
134 |
m = ("Option --exclude is meaningful only combined with "
|
135 |
" --all-base-projects.")
|
136 |
raise CommandError(m)
|
137 |
|
138 |
def mk_all_base_filter(self, all_base, exclude): |
139 |
flt = Q(state__in=models.Project.INITIALIZED_STATES, is_base=True)
|
140 |
if exclude:
|
141 |
exclude = exclude.split(',')
|
142 |
flt &= ~Q(uuid__in=exclude) |
143 |
return flt
|
144 |
|
145 |
@transaction.commit_on_success
|
146 |
def handle(self, *args, **options): |
147 |
all_base = options["all_base_projects"]
|
148 |
exclude = options["exclude"]
|
149 |
self.check_args(args, all_base, exclude)
|
150 |
|
151 |
try:
|
152 |
changes = {} |
153 |
for key, value in options.iteritems(): |
154 |
param = PARAMS.get(key) |
155 |
if param is None or value is None: |
156 |
continue
|
157 |
if all_base and not param.is_main: |
158 |
m = "Cannot modify field '%s' in bulk" % key
|
159 |
raise CommandError(m)
|
160 |
k = key if param.key is Simple else param.key |
161 |
v = value if param.mod is Simple else param.mod(value) |
162 |
changes[k] = v |
163 |
|
164 |
if all_base:
|
165 |
flt = self.mk_all_base_filter(all_base, exclude)
|
166 |
functions.modify_projects_in_bulk(flt, changes) |
167 |
else:
|
168 |
functions.modify_project(args[0], changes)
|
169 |
except BaseException as e: |
170 |
raise CommandError(e)
|