Statistics
| Branch: | Tag: | Revision:

root / snf-tools / snf-admin @ ead18dbc

History | View | Annotate | Download (18.6 kB)

1 8cdde414 Giorgos Verigakis
#!/usr/bin/env python
2 8cdde414 Giorgos Verigakis
3 8cdde414 Giorgos Verigakis
# Copyright 2011 GRNET S.A. All rights reserved.
4 8cdde414 Giorgos Verigakis
# 
5 8cdde414 Giorgos Verigakis
# Redistribution and use in source and binary forms, with or
6 8cdde414 Giorgos Verigakis
# without modification, are permitted provided that the following
7 8cdde414 Giorgos Verigakis
# conditions are met:
8 8cdde414 Giorgos Verigakis
# 
9 8cdde414 Giorgos Verigakis
#   1. Redistributions of source code must retain the above
10 8cdde414 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
11 8cdde414 Giorgos Verigakis
#      disclaimer.
12 8cdde414 Giorgos Verigakis
# 
13 8cdde414 Giorgos Verigakis
#   2. Redistributions in binary form must reproduce the above
14 8cdde414 Giorgos Verigakis
#      copyright notice, this list of conditions and the following
15 8cdde414 Giorgos Verigakis
#      disclaimer in the documentation and/or other materials
16 8cdde414 Giorgos Verigakis
#      provided with the distribution.
17 8cdde414 Giorgos Verigakis
# 
18 8cdde414 Giorgos Verigakis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
19 8cdde414 Giorgos Verigakis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 8cdde414 Giorgos Verigakis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 8cdde414 Giorgos Verigakis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
22 8cdde414 Giorgos Verigakis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 8cdde414 Giorgos Verigakis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 8cdde414 Giorgos Verigakis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25 8cdde414 Giorgos Verigakis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 8cdde414 Giorgos Verigakis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 8cdde414 Giorgos Verigakis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 8cdde414 Giorgos Verigakis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 8cdde414 Giorgos Verigakis
# POSSIBILITY OF SUCH DAMAGE.
30 8cdde414 Giorgos Verigakis
# 
31 8cdde414 Giorgos Verigakis
# The views and conclusions contained in the software and
32 8cdde414 Giorgos Verigakis
# documentation are those of the authors and should not be
33 8cdde414 Giorgos Verigakis
# interpreted as representing official policies, either expressed
34 8cdde414 Giorgos Verigakis
# or implied, of GRNET S.A.
35 8cdde414 Giorgos Verigakis
36 8cdde414 Giorgos Verigakis
from django.core.management import setup_environ
37 8cdde414 Giorgos Verigakis
try:
38 8cdde414 Giorgos Verigakis
    from synnefo import settings
39 8cdde414 Giorgos Verigakis
except ImportError:
40 8cdde414 Giorgos Verigakis
    raise Exception("Cannot import settings, make sure PYTHONPATH contains "
41 8cdde414 Giorgos Verigakis
                    "the parent directory of the Synnefo Django project.")
42 8cdde414 Giorgos Verigakis
setup_environ(settings)
43 8cdde414 Giorgos Verigakis
44 8cdde414 Giorgos Verigakis
import inspect
45 8cdde414 Giorgos Verigakis
import logging
46 8cdde414 Giorgos Verigakis
import sys
47 8cdde414 Giorgos Verigakis
48 8cdde414 Giorgos Verigakis
from collections import defaultdict
49 910f53d9 Giorgos Verigakis
from itertools import product
50 8cdde414 Giorgos Verigakis
from optparse import OptionParser
51 8cdde414 Giorgos Verigakis
from os.path import basename
52 8cdde414 Giorgos Verigakis
53 8cdde414 Giorgos Verigakis
from synnefo.db import models
54 06b7df28 Giorgos Verigakis
from synnefo.invitations.invitations import add_invitation, send_invitation
55 87c1dadc Giorgos Verigakis
from synnefo.logic import backend, users
56 8cdde414 Giorgos Verigakis
57 8cdde414 Giorgos Verigakis
58 8cdde414 Giorgos Verigakis
def get_user(uid):
59 8cdde414 Giorgos Verigakis
    try:
60 8cdde414 Giorgos Verigakis
        uid = int(uid)
61 8cdde414 Giorgos Verigakis
        return models.SynnefoUser.objects.get(id=uid)
62 8cdde414 Giorgos Verigakis
    except ValueError:
63 8cdde414 Giorgos Verigakis
        return None
64 8cdde414 Giorgos Verigakis
    except models.SynnefoUser.DoesNotExist:
65 8cdde414 Giorgos Verigakis
        return None
66 8cdde414 Giorgos Verigakis
67 8cdde414 Giorgos Verigakis
def print_dict(d, exclude=()):
68 ca8f8081 Giorgos Verigakis
    if not d:
69 ca8f8081 Giorgos Verigakis
        return
70 8cdde414 Giorgos Verigakis
    margin = max(len(key) for key in d) + 1
71 8cdde414 Giorgos Verigakis
72 8cdde414 Giorgos Verigakis
    for key, val in sorted(d.items()):
73 9a60dacb Giorgos Verigakis
        if key in exclude or key.startswith('_'):
74 8cdde414 Giorgos Verigakis
            continue
75 8cdde414 Giorgos Verigakis
        print '%s: %s' % (key.rjust(margin), val)
76 8cdde414 Giorgos Verigakis
77 13d2b7f7 Giorgos Verigakis
def print_item(item):
78 ead18dbc Giorgos Verigakis
    name = getattr(item, 'name', '')
79 ead18dbc Giorgos Verigakis
    print '%d %s' % (item.id, name)
80 13d2b7f7 Giorgos Verigakis
    print_dict(item.__dict__, exclude=('id', 'name'))
81 13d2b7f7 Giorgos Verigakis
82 1d133009 Giorgos Verigakis
def print_items(items, detail=False, keys=None):
83 1d133009 Giorgos Verigakis
    keys = keys or ('id', 'name')
84 8cdde414 Giorgos Verigakis
    for item in items:
85 1d133009 Giorgos Verigakis
        for key in keys:
86 1d133009 Giorgos Verigakis
            print getattr(item, key),
87 1d133009 Giorgos Verigakis
        print
88 1d133009 Giorgos Verigakis
        
89 8cdde414 Giorgos Verigakis
        if detail:
90 1d133009 Giorgos Verigakis
            print_dict(item.__dict__, exclude=keys)
91 8cdde414 Giorgos Verigakis
            print
92 8cdde414 Giorgos Verigakis
93 8cdde414 Giorgos Verigakis
94 8cdde414 Giorgos Verigakis
class Command(object):
95 9a60dacb Giorgos Verigakis
    group = '<group>'
96 9a60dacb Giorgos Verigakis
    name = '<command>'
97 8cdde414 Giorgos Verigakis
    syntax = ''
98 8cdde414 Giorgos Verigakis
    description = ''
99 735f44fe Giorgos Verigakis
    hidden = False
100 8cdde414 Giorgos Verigakis
    
101 9a60dacb Giorgos Verigakis
    def __init__(self, exe, argv):
102 8cdde414 Giorgos Verigakis
        parser = OptionParser()
103 9a60dacb Giorgos Verigakis
        syntax = '%s [options]' % self.syntax if self.syntax else '[options]'
104 9a60dacb Giorgos Verigakis
        parser.usage = '%s %s %s' % (exe, self.name, syntax)
105 9a60dacb Giorgos Verigakis
        parser.description = self.description
106 8cdde414 Giorgos Verigakis
        self.add_options(parser)
107 8cdde414 Giorgos Verigakis
        options, self.args = parser.parse_args(argv)
108 8cdde414 Giorgos Verigakis
        
109 8cdde414 Giorgos Verigakis
        # Add options to self
110 8cdde414 Giorgos Verigakis
        for opt in parser.option_list:
111 8cdde414 Giorgos Verigakis
            key = opt.dest
112 8cdde414 Giorgos Verigakis
            if key:
113 8cdde414 Giorgos Verigakis
                val = getattr(options, key)
114 8cdde414 Giorgos Verigakis
                setattr(self, key, val)
115 8cdde414 Giorgos Verigakis
        
116 8cdde414 Giorgos Verigakis
        ch = logging.StreamHandler()
117 8cdde414 Giorgos Verigakis
        ch.setFormatter(logging.Formatter('%(message)s'))
118 8cdde414 Giorgos Verigakis
        logger = logging.getLogger()
119 8cdde414 Giorgos Verigakis
        logger.addHandler(ch)
120 8cdde414 Giorgos Verigakis
        level = logging.WARNING
121 8cdde414 Giorgos Verigakis
        logger.setLevel(level)
122 8cdde414 Giorgos Verigakis
        
123 8cdde414 Giorgos Verigakis
        self.parser = parser
124 8cdde414 Giorgos Verigakis
    
125 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
126 8cdde414 Giorgos Verigakis
        pass
127 8cdde414 Giorgos Verigakis
    
128 8cdde414 Giorgos Verigakis
    def execute(self):
129 8cdde414 Giorgos Verigakis
        try:
130 8cdde414 Giorgos Verigakis
            self.main(*self.args)
131 8cdde414 Giorgos Verigakis
        except TypeError:
132 8cdde414 Giorgos Verigakis
            self.parser.print_help()
133 8cdde414 Giorgos Verigakis
134 8cdde414 Giorgos Verigakis
135 13d2b7f7 Giorgos Verigakis
# Server commands
136 13d2b7f7 Giorgos Verigakis
137 8cdde414 Giorgos Verigakis
class ListServers(Command):
138 9a60dacb Giorgos Verigakis
    group = 'server'
139 ca8f8081 Giorgos Verigakis
    name = 'list'
140 8cdde414 Giorgos Verigakis
    syntax = '[server id]'
141 8cdde414 Giorgos Verigakis
    description = 'list servers'
142 8cdde414 Giorgos Verigakis
    
143 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
144 8cdde414 Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_deleted',
145 8cdde414 Giorgos Verigakis
                        default=False, help='also list deleted servers')
146 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
147 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
148 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
149 8cdde414 Giorgos Verigakis
                            help='show servers of user with id UID')
150 8cdde414 Giorgos Verigakis
    
151 8cdde414 Giorgos Verigakis
    def main(self, server_id=None):
152 8cdde414 Giorgos Verigakis
        servers = models.VirtualMachine.objects.order_by('id')
153 8cdde414 Giorgos Verigakis
        if server_id:
154 8cdde414 Giorgos Verigakis
            servers = servers.filter(id=server_id)
155 8cdde414 Giorgos Verigakis
        if not self.show_deleted:
156 8cdde414 Giorgos Verigakis
            servers = servers.filter(deleted=False)
157 8cdde414 Giorgos Verigakis
        if self.uid:
158 8cdde414 Giorgos Verigakis
            user = get_user(self.uid)
159 8cdde414 Giorgos Verigakis
            if user:
160 8cdde414 Giorgos Verigakis
                servers = servers.filter(owner=user)
161 8cdde414 Giorgos Verigakis
            else:
162 8cdde414 Giorgos Verigakis
                print 'Unknown user id'
163 8cdde414 Giorgos Verigakis
                return
164 8cdde414 Giorgos Verigakis
        
165 8cdde414 Giorgos Verigakis
        print_items(servers, self.detail)
166 8cdde414 Giorgos Verigakis
167 8cdde414 Giorgos Verigakis
168 13d2b7f7 Giorgos Verigakis
# User commands
169 13d2b7f7 Giorgos Verigakis
170 735f44fe Giorgos Verigakis
class CreateUser(Command):
171 735f44fe Giorgos Verigakis
    group = 'user'
172 735f44fe Giorgos Verigakis
    name = 'create'
173 06b7df28 Giorgos Verigakis
    syntax = '<username> <email>'
174 735f44fe Giorgos Verigakis
    description = 'create a user'
175 735f44fe Giorgos Verigakis
    
176 735f44fe Giorgos Verigakis
    def add_options(self, parser):
177 735f44fe Giorgos Verigakis
        parser.add_option('--realname', dest='realname', metavar='NAME',
178 735f44fe Giorgos Verigakis
                            help='set real name of user')
179 735f44fe Giorgos Verigakis
        parser.add_option('--type', dest='type', metavar='TYPE',
180 735f44fe Giorgos Verigakis
                            help='set user type')
181 735f44fe Giorgos Verigakis
    
182 06b7df28 Giorgos Verigakis
    def main(self, username, email):
183 22f79931 Giorgos Verigakis
        username = username.decode('utf8')
184 06b7df28 Giorgos Verigakis
        realname = self.realname or username
185 06b7df28 Giorgos Verigakis
        type = self.type or 'USER'
186 06b7df28 Giorgos Verigakis
        if type not in [x[0] for x in models.SynnefoUser.ACCOUNT_TYPE]:
187 06b7df28 Giorgos Verigakis
            print 'Invalid type'
188 06b7df28 Giorgos Verigakis
            return
189 735f44fe Giorgos Verigakis
        
190 87c1dadc Giorgos Verigakis
        user = users._register_user(realname, username, email, type)
191 735f44fe Giorgos Verigakis
        print_item(user)
192 735f44fe Giorgos Verigakis
193 735f44fe Giorgos Verigakis
194 735f44fe Giorgos Verigakis
class DeleteUser(Command):
195 735f44fe Giorgos Verigakis
    group = 'user'
196 735f44fe Giorgos Verigakis
    name = 'delete'
197 735f44fe Giorgos Verigakis
    syntax = '<user id>'
198 735f44fe Giorgos Verigakis
    description = 'delete a user'
199 735f44fe Giorgos Verigakis
    hidden = True
200 735f44fe Giorgos Verigakis
    
201 735f44fe Giorgos Verigakis
    def add_options(self, parser):
202 735f44fe Giorgos Verigakis
        parser.add_option('--force', action='store_true', dest='force',
203 735f44fe Giorgos Verigakis
                        default=False, help='force deletion (use with care)')
204 735f44fe Giorgos Verigakis
    
205 735f44fe Giorgos Verigakis
    def main(self, user_id):
206 06b7df28 Giorgos Verigakis
        if self.force:
207 06b7df28 Giorgos Verigakis
            user = get_user(user_id)
208 87c1dadc Giorgos Verigakis
            users.delete_user(user)
209 06b7df28 Giorgos Verigakis
        else:
210 735f44fe Giorgos Verigakis
            print "WARNING: Deleting a user is a very destructive operation."
211 735f44fe Giorgos Verigakis
            print "Any objects with foreign keys pointing to this user will" \
212 735f44fe Giorgos Verigakis
                    " be deleted as well."
213 735f44fe Giorgos Verigakis
            print "Use --force to force deletion of this user."
214 735f44fe Giorgos Verigakis
            print "You have been warned!"
215 06b7df28 Giorgos Verigakis
216 06b7df28 Giorgos Verigakis
217 06b7df28 Giorgos Verigakis
class InviteUser(Command):
218 06b7df28 Giorgos Verigakis
    group = 'user'
219 06b7df28 Giorgos Verigakis
    name = 'invite'
220 06b7df28 Giorgos Verigakis
    syntax = '<inviter id> <invitee name> <invitee email>'
221 06b7df28 Giorgos Verigakis
    description = 'invite a user'
222 06b7df28 Giorgos Verigakis
    
223 06b7df28 Giorgos Verigakis
    def main(self, inviter_id, name, email):
224 22f79931 Giorgos Verigakis
        name = name.decode('utf8')
225 06b7df28 Giorgos Verigakis
        inviter = get_user(inviter_id)
226 06b7df28 Giorgos Verigakis
        inv = add_invitation(inviter, name, email)
227 06b7df28 Giorgos Verigakis
        send_invitation(inv)
228 735f44fe Giorgos Verigakis
229 735f44fe Giorgos Verigakis
230 8cdde414 Giorgos Verigakis
class ListUsers(Command):
231 9a60dacb Giorgos Verigakis
    group = 'user'
232 ca8f8081 Giorgos Verigakis
    name = 'list'
233 8cdde414 Giorgos Verigakis
    syntax = '[user id]'
234 8cdde414 Giorgos Verigakis
    description = 'list users'
235 8cdde414 Giorgos Verigakis
    
236 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
237 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
238 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
239 8cdde414 Giorgos Verigakis
    
240 8cdde414 Giorgos Verigakis
    def main(self, user_id=None):
241 8cdde414 Giorgos Verigakis
        if user_id:
242 8cdde414 Giorgos Verigakis
            users = [models.SynnefoUser.objects.get(id=user_id)]
243 8cdde414 Giorgos Verigakis
        else:
244 8cdde414 Giorgos Verigakis
            users = models.SynnefoUser.objects.order_by('id')
245 1d133009 Giorgos Verigakis
        print_items(users, self.detail, keys=('id', 'name', 'uniq'))
246 8cdde414 Giorgos Verigakis
247 8cdde414 Giorgos Verigakis
248 13d2b7f7 Giorgos Verigakis
class ModifyUser(Command):
249 13d2b7f7 Giorgos Verigakis
    group = 'user'
250 13d2b7f7 Giorgos Verigakis
    name = 'modify'
251 13d2b7f7 Giorgos Verigakis
    syntax = '<user id>'
252 13d2b7f7 Giorgos Verigakis
    description = 'modify a user'
253 13d2b7f7 Giorgos Verigakis
    
254 13d2b7f7 Giorgos Verigakis
    def add_options(self, parser):
255 13d2b7f7 Giorgos Verigakis
        parser.add_option('--credit', dest='credit', metavar='VALUE',
256 13d2b7f7 Giorgos Verigakis
                            help='set user credits')
257 13d2b7f7 Giorgos Verigakis
        parser.add_option('--invitations', dest='invitations',
258 13d2b7f7 Giorgos Verigakis
                            metavar='VALUE', help='set max invitations')
259 13d2b7f7 Giorgos Verigakis
        parser.add_option('--realname', dest='realname', metavar='NAME',
260 13d2b7f7 Giorgos Verigakis
                            help='set real name of user')
261 13d2b7f7 Giorgos Verigakis
        parser.add_option('--type', dest='type', metavar='TYPE',
262 13d2b7f7 Giorgos Verigakis
                            help='set user type')
263 735f44fe Giorgos Verigakis
        parser.add_option('--uniq', dest='uniq', metavar='ID',
264 735f44fe Giorgos Verigakis
                            help='set external unique ID')
265 13d2b7f7 Giorgos Verigakis
        parser.add_option('--username', dest='username', metavar='NAME',
266 13d2b7f7 Giorgos Verigakis
                            help='set username')
267 13d2b7f7 Giorgos Verigakis
    
268 13d2b7f7 Giorgos Verigakis
    def main(self, user_id):
269 13d2b7f7 Giorgos Verigakis
        user = get_user(user_id)
270 13d2b7f7 Giorgos Verigakis
        
271 13d2b7f7 Giorgos Verigakis
        if self.credit:
272 13d2b7f7 Giorgos Verigakis
            user.credit = self.credit
273 13d2b7f7 Giorgos Verigakis
        if self.invitations:
274 13d2b7f7 Giorgos Verigakis
            user.max_invitations = self.invitations
275 13d2b7f7 Giorgos Verigakis
        if self.realname:
276 13d2b7f7 Giorgos Verigakis
            user.realname = self.realname
277 13d2b7f7 Giorgos Verigakis
        if self.type:
278 13d2b7f7 Giorgos Verigakis
            allowed = [x[0] for x in models.SynnefoUser.ACCOUNT_TYPE]
279 13d2b7f7 Giorgos Verigakis
            if self.type not in allowed:
280 13d2b7f7 Giorgos Verigakis
                print 'Invalid type'
281 13d2b7f7 Giorgos Verigakis
                return
282 13d2b7f7 Giorgos Verigakis
            user.type = self.type
283 735f44fe Giorgos Verigakis
        if self.uniq:
284 735f44fe Giorgos Verigakis
            user.uniq = self.uniq
285 13d2b7f7 Giorgos Verigakis
        if self.username:
286 13d2b7f7 Giorgos Verigakis
            user.name = self.username
287 13d2b7f7 Giorgos Verigakis
        
288 13d2b7f7 Giorgos Verigakis
        user.save()
289 13d2b7f7 Giorgos Verigakis
        print_item(user)
290 13d2b7f7 Giorgos Verigakis
291 13d2b7f7 Giorgos Verigakis
292 13d2b7f7 Giorgos Verigakis
# Image commands
293 13d2b7f7 Giorgos Verigakis
294 8cdde414 Giorgos Verigakis
class ListImages(Command):
295 9a60dacb Giorgos Verigakis
    group = 'image'
296 ca8f8081 Giorgos Verigakis
    name = 'list'
297 8cdde414 Giorgos Verigakis
    syntax = '[image id]'
298 8cdde414 Giorgos Verigakis
    description = 'list images'
299 8cdde414 Giorgos Verigakis
    
300 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
301 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
302 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
303 8cdde414 Giorgos Verigakis
    
304 8cdde414 Giorgos Verigakis
    def main(self, image_id=None):
305 8cdde414 Giorgos Verigakis
        if image_id:
306 8cdde414 Giorgos Verigakis
            images = [models.Image.objects.get(id=image_id)]
307 8cdde414 Giorgos Verigakis
        else:
308 8cdde414 Giorgos Verigakis
            images = models.Image.objects.order_by('id')
309 8cdde414 Giorgos Verigakis
        print_items(images, self.detail)
310 8cdde414 Giorgos Verigakis
311 8cdde414 Giorgos Verigakis
312 8cdde414 Giorgos Verigakis
class RegisterImage(Command):
313 9a60dacb Giorgos Verigakis
    group = 'image'
314 8cdde414 Giorgos Verigakis
    name = 'register'
315 8cdde414 Giorgos Verigakis
    syntax = '<name> <backend id>'
316 8cdde414 Giorgos Verigakis
    description = 'register an image'
317 8cdde414 Giorgos Verigakis
    
318 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
319 ca8f8081 Giorgos Verigakis
        parser.add_option('--public', action='store_true', dest='public',
320 8cdde414 Giorgos Verigakis
                            default=False, help='make image public')
321 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
322 8cdde414 Giorgos Verigakis
                            help='assign image to user with id UID')
323 8cdde414 Giorgos Verigakis
    
324 8cdde414 Giorgos Verigakis
    def main(self, name, backend_id):
325 8cdde414 Giorgos Verigakis
        user = None
326 8cdde414 Giorgos Verigakis
        if self.uid:
327 8cdde414 Giorgos Verigakis
            user = get_user(self.uid)
328 8cdde414 Giorgos Verigakis
            if not user:
329 8cdde414 Giorgos Verigakis
                print 'Unknown user id'
330 8cdde414 Giorgos Verigakis
                return
331 8cdde414 Giorgos Verigakis
        
332 8cdde414 Giorgos Verigakis
        image = models.Image.objects.create(
333 8cdde414 Giorgos Verigakis
            name=name,
334 8cdde414 Giorgos Verigakis
            state='ACTIVE',
335 8cdde414 Giorgos Verigakis
            owner=user,
336 8cdde414 Giorgos Verigakis
            backend_id=backend_id,
337 8cdde414 Giorgos Verigakis
            public=self.public)
338 9a60dacb Giorgos Verigakis
        
339 13d2b7f7 Giorgos Verigakis
        print_item(image)
340 8cdde414 Giorgos Verigakis
341 8cdde414 Giorgos Verigakis
342 8cdde414 Giorgos Verigakis
class ModifyImage(Command):
343 9a60dacb Giorgos Verigakis
    group = 'image'
344 8cdde414 Giorgos Verigakis
    name = 'modify'
345 8cdde414 Giorgos Verigakis
    syntax = '<image id>'
346 8cdde414 Giorgos Verigakis
    description = 'modify an image'
347 8cdde414 Giorgos Verigakis
    
348 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
349 8cdde414 Giorgos Verigakis
        parser.add_option('-b', dest='backend_id', metavar='BACKEND_ID',
350 8cdde414 Giorgos Verigakis
                            help='set image backend id')
351 8cdde414 Giorgos Verigakis
        parser.add_option('-f', dest='format', metavar='FORMAT',
352 8cdde414 Giorgos Verigakis
                            help='set image format')
353 8cdde414 Giorgos Verigakis
        parser.add_option('-n', dest='name', metavar='NAME',
354 8cdde414 Giorgos Verigakis
                            help='set image name')
355 ca8f8081 Giorgos Verigakis
        parser.add_option('--public', action='store_true', dest='public',
356 8cdde414 Giorgos Verigakis
                            default=False, help='make image public')
357 ca8f8081 Giorgos Verigakis
        parser.add_option('--nopublic', action='store_true', dest='private',
358 8cdde414 Giorgos Verigakis
                            default=False, help='make image private')
359 8cdde414 Giorgos Verigakis
        parser.add_option('-s', dest='state', metavar='STATE',
360 8cdde414 Giorgos Verigakis
                            default=False, help='set image state')
361 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
362 8cdde414 Giorgos Verigakis
                            help='assign image to user with id UID')
363 8cdde414 Giorgos Verigakis
    
364 8cdde414 Giorgos Verigakis
    def main(self, image_id):
365 8cdde414 Giorgos Verigakis
        try:
366 8cdde414 Giorgos Verigakis
            image = models.Image.objects.get(id=image_id)
367 8cdde414 Giorgos Verigakis
        except:
368 8cdde414 Giorgos Verigakis
            print 'Image not found'
369 8cdde414 Giorgos Verigakis
            return
370 8cdde414 Giorgos Verigakis
        
371 8cdde414 Giorgos Verigakis
        if self.backend_id:
372 8cdde414 Giorgos Verigakis
            image.backend_id = self.backend_id
373 8cdde414 Giorgos Verigakis
        if self.format:
374 13d2b7f7 Giorgos Verigakis
            allowed = [x[0] for x in models.Image.FORMATS]
375 13d2b7f7 Giorgos Verigakis
            if self.format not in allowed:
376 13d2b7f7 Giorgos Verigakis
                print 'Invalid format'
377 13d2b7f7 Giorgos Verigakis
                return
378 13d2b7f7 Giorgos Verigakis
            image.format = self.format
379 8cdde414 Giorgos Verigakis
        if self.name:
380 8cdde414 Giorgos Verigakis
            image.name = self.name
381 8cdde414 Giorgos Verigakis
        if self.public:
382 8cdde414 Giorgos Verigakis
            image.public = True
383 8cdde414 Giorgos Verigakis
        if self.private:
384 8cdde414 Giorgos Verigakis
            image.public = False
385 8cdde414 Giorgos Verigakis
        if self.state:
386 13d2b7f7 Giorgos Verigakis
            allowed = [x[0] for x in models.Image.IMAGE_STATES]
387 13d2b7f7 Giorgos Verigakis
            if self.state not in allowed:
388 13d2b7f7 Giorgos Verigakis
                print 'Invalid state'
389 13d2b7f7 Giorgos Verigakis
                return
390 8cdde414 Giorgos Verigakis
            image.state = self.state
391 8cdde414 Giorgos Verigakis
        if self.uid:
392 8cdde414 Giorgos Verigakis
            image.owner = get_user(self.uid)
393 8cdde414 Giorgos Verigakis
        
394 8cdde414 Giorgos Verigakis
        image.save()
395 13d2b7f7 Giorgos Verigakis
        print_item(image)
396 8cdde414 Giorgos Verigakis
397 8cdde414 Giorgos Verigakis
398 ca8f8081 Giorgos Verigakis
class ModifyImageMeta(Command):
399 9a60dacb Giorgos Verigakis
    group = 'image'
400 ca8f8081 Giorgos Verigakis
    name = 'meta'
401 ca8f8081 Giorgos Verigakis
    syntax = '<image id> [key[=val]]'
402 ca8f8081 Giorgos Verigakis
    description = 'get and manipulate image metadata'
403 ca8f8081 Giorgos Verigakis
    
404 ca8f8081 Giorgos Verigakis
    def main(self, image_id, arg=''):
405 ca8f8081 Giorgos Verigakis
        try:
406 ca8f8081 Giorgos Verigakis
            image = models.Image.objects.get(id=image_id)
407 ca8f8081 Giorgos Verigakis
        except:
408 ca8f8081 Giorgos Verigakis
            print 'Image not found'
409 ca8f8081 Giorgos Verigakis
            return
410 ca8f8081 Giorgos Verigakis
        
411 ca8f8081 Giorgos Verigakis
        key, sep, val = arg.partition('=')
412 ca8f8081 Giorgos Verigakis
        if not sep:
413 ca8f8081 Giorgos Verigakis
            val = None
414 ca8f8081 Giorgos Verigakis
        
415 ca8f8081 Giorgos Verigakis
        if not key:
416 ca8f8081 Giorgos Verigakis
            metadata = {}
417 ca8f8081 Giorgos Verigakis
            for meta in image.imagemetadata_set.order_by('meta_key'):
418 ca8f8081 Giorgos Verigakis
                metadata[meta.meta_key] = meta.meta_value
419 ca8f8081 Giorgos Verigakis
            print_dict(metadata)
420 ca8f8081 Giorgos Verigakis
            return
421 ca8f8081 Giorgos Verigakis
        
422 ca8f8081 Giorgos Verigakis
        try:
423 ca8f8081 Giorgos Verigakis
            meta = image.imagemetadata_set.get(meta_key=key)
424 ca8f8081 Giorgos Verigakis
        except models.ImageMetadata.DoesNotExist:
425 ca8f8081 Giorgos Verigakis
            meta = None
426 ca8f8081 Giorgos Verigakis
        
427 ca8f8081 Giorgos Verigakis
        if val is None:
428 ca8f8081 Giorgos Verigakis
            if meta:
429 ca8f8081 Giorgos Verigakis
                print_dict({key: meta.meta_value})
430 ca8f8081 Giorgos Verigakis
            return
431 ca8f8081 Giorgos Verigakis
        
432 ca8f8081 Giorgos Verigakis
        if val:
433 ca8f8081 Giorgos Verigakis
            if not meta:
434 ca8f8081 Giorgos Verigakis
                meta = image.imagemetadata_set.create(meta_key=key)
435 ca8f8081 Giorgos Verigakis
            meta.meta_value = val
436 ca8f8081 Giorgos Verigakis
            meta.save()
437 ca8f8081 Giorgos Verigakis
        else:
438 ca8f8081 Giorgos Verigakis
            # Delete if val is empty
439 ca8f8081 Giorgos Verigakis
            if meta:
440 ca8f8081 Giorgos Verigakis
                meta.delete()
441 ca8f8081 Giorgos Verigakis
442 ca8f8081 Giorgos Verigakis
443 910f53d9 Giorgos Verigakis
# Flavor commands
444 910f53d9 Giorgos Verigakis
445 910f53d9 Giorgos Verigakis
class CreateFlavor(Command):
446 910f53d9 Giorgos Verigakis
    group = 'flavor'
447 910f53d9 Giorgos Verigakis
    name = 'create'
448 910f53d9 Giorgos Verigakis
    syntax = '<cpu>[,<cpu>,...] <ram>[,<ram>,...] <disk>[,<disk>,...]'
449 910f53d9 Giorgos Verigakis
    description = 'create one or more flavors'
450 910f53d9 Giorgos Verigakis
    
451 910f53d9 Giorgos Verigakis
    def main(self, cpu, ram, disk):
452 910f53d9 Giorgos Verigakis
        cpus = cpu.split(',')
453 910f53d9 Giorgos Verigakis
        rams = ram.split(',')
454 910f53d9 Giorgos Verigakis
        disks = disk.split(',')
455 910f53d9 Giorgos Verigakis
        
456 910f53d9 Giorgos Verigakis
        flavors = []
457 910f53d9 Giorgos Verigakis
        for cpu, ram, disk in product(cpus, rams, disks):
458 910f53d9 Giorgos Verigakis
            try:
459 910f53d9 Giorgos Verigakis
                flavors.append((int(cpu), int(ram), int(disk)))
460 910f53d9 Giorgos Verigakis
            except ValueError:
461 910f53d9 Giorgos Verigakis
                print 'Invalid values'
462 910f53d9 Giorgos Verigakis
                return
463 910f53d9 Giorgos Verigakis
        
464 910f53d9 Giorgos Verigakis
        created = []
465 910f53d9 Giorgos Verigakis
        for cpu, ram, disk in flavors:
466 910f53d9 Giorgos Verigakis
            flavor = models.Flavor.objects.create(cpu=cpu, ram=ram, disk=disk)
467 910f53d9 Giorgos Verigakis
            created.append(flavor)
468 910f53d9 Giorgos Verigakis
        
469 910f53d9 Giorgos Verigakis
        print_items(created, detail=True)
470 910f53d9 Giorgos Verigakis
471 910f53d9 Giorgos Verigakis
472 910f53d9 Giorgos Verigakis
class DeleteFlavor(Command):
473 910f53d9 Giorgos Verigakis
    group = 'flavor'
474 910f53d9 Giorgos Verigakis
    name = 'delete'
475 910f53d9 Giorgos Verigakis
    syntax = '<flavor id> [<flavor id>] [...]'
476 910f53d9 Giorgos Verigakis
    description = 'delete one or more flavors'
477 910f53d9 Giorgos Verigakis
    
478 910f53d9 Giorgos Verigakis
    def main(self, *args):
479 910f53d9 Giorgos Verigakis
        if not args:
480 910f53d9 Giorgos Verigakis
            raise TypeError
481 910f53d9 Giorgos Verigakis
        for flavor_id in args:
482 910f53d9 Giorgos Verigakis
            flavor = models.Flavor.objects.get(id=int(flavor_id))
483 910f53d9 Giorgos Verigakis
            flavor.delete()
484 910f53d9 Giorgos Verigakis
485 910f53d9 Giorgos Verigakis
486 910f53d9 Giorgos Verigakis
class ListFlavors(Command):
487 910f53d9 Giorgos Verigakis
    group = 'flavor'
488 910f53d9 Giorgos Verigakis
    name = 'list'
489 910f53d9 Giorgos Verigakis
    syntax = '[flavor id]'
490 910f53d9 Giorgos Verigakis
    description = 'list images'
491 910f53d9 Giorgos Verigakis
    
492 910f53d9 Giorgos Verigakis
    def add_options(self, parser):
493 910f53d9 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
494 910f53d9 Giorgos Verigakis
                        default=False, help='show detailed output')
495 910f53d9 Giorgos Verigakis
    
496 910f53d9 Giorgos Verigakis
    def main(self, flavor_id=None):
497 910f53d9 Giorgos Verigakis
        if flavor_id:
498 910f53d9 Giorgos Verigakis
            flavors = [models.Flavor.objects.get(id=flavor_id)]
499 910f53d9 Giorgos Verigakis
        else:
500 910f53d9 Giorgos Verigakis
            flavors = models.Flavor.objects.order_by('id')
501 910f53d9 Giorgos Verigakis
        print_items(flavors, self.detail)
502 910f53d9 Giorgos Verigakis
503 910f53d9 Giorgos Verigakis
504 87c1dadc Giorgos Verigakis
class ShowStats(Command):
505 87c1dadc Giorgos Verigakis
    group = 'stats'
506 87c1dadc Giorgos Verigakis
    name = None
507 87c1dadc Giorgos Verigakis
    description = 'show statistics'
508 87c1dadc Giorgos Verigakis
509 87c1dadc Giorgos Verigakis
    def main(self):
510 87c1dadc Giorgos Verigakis
        stats = {}
511 87c1dadc Giorgos Verigakis
        stats['Users'] = models.SynnefoUser.objects.count()
512 87c1dadc Giorgos Verigakis
        stats['Images'] = models.Image.objects.exclude(state='DELETED').count()
513 87c1dadc Giorgos Verigakis
        stats['Flavors'] = models.Flavor.objects.count()
514 87c1dadc Giorgos Verigakis
        stats['VMs'] = models.VirtualMachine.objects.filter(deleted=False).count()
515 87c1dadc Giorgos Verigakis
        stats['Networks'] = models.Network.objects.exclude(state='DELETED').count()
516 87c1dadc Giorgos Verigakis
        stats['Invitations'] = models.Invitations.objects.count()
517 87c1dadc Giorgos Verigakis
        
518 87c1dadc Giorgos Verigakis
        stats['Ganeti Instances'] = len(backend.get_ganeti_instances())
519 87c1dadc Giorgos Verigakis
        stats['Ganeti Nodes'] = len(backend.get_ganeti_nodes())
520 87c1dadc Giorgos Verigakis
        stats['Ganeti Jobs'] = len(backend.get_ganeti_jobs())
521 87c1dadc Giorgos Verigakis
        
522 87c1dadc Giorgos Verigakis
        print_dict(stats)
523 87c1dadc Giorgos Verigakis
524 87c1dadc Giorgos Verigakis
525 ead18dbc Giorgos Verigakis
class ListInvitations(Command):
526 ead18dbc Giorgos Verigakis
    group = 'invitation'
527 ead18dbc Giorgos Verigakis
    name = 'list'
528 ead18dbc Giorgos Verigakis
    syntax = '[invitation id]'
529 ead18dbc Giorgos Verigakis
    description = 'list invitations'
530 ead18dbc Giorgos Verigakis
    
531 ead18dbc Giorgos Verigakis
    def main(self, invitation_id=None):
532 ead18dbc Giorgos Verigakis
        if invitation_id:
533 ead18dbc Giorgos Verigakis
            invitations = [models.Invitations.objects.get(id=invitation_id)]
534 ead18dbc Giorgos Verigakis
        else:
535 ead18dbc Giorgos Verigakis
            invitations = models.Invitations.objects.order_by('id')
536 ead18dbc Giorgos Verigakis
        print_items(invitations, detail=True, keys=('id',))
537 ead18dbc Giorgos Verigakis
538 ead18dbc Giorgos Verigakis
539 ead18dbc Giorgos Verigakis
class ResendInviation(Command):
540 ead18dbc Giorgos Verigakis
    group = 'invitation'
541 ead18dbc Giorgos Verigakis
    name = 'resend'
542 ead18dbc Giorgos Verigakis
    syntax = '<invitation id>'
543 ead18dbc Giorgos Verigakis
    description = 'resend an invitation'
544 ead18dbc Giorgos Verigakis
545 ead18dbc Giorgos Verigakis
    def main(self, invitation_id):
546 ead18dbc Giorgos Verigakis
        invitation = models.Invitations.objects.get(id=invitation_id)
547 ead18dbc Giorgos Verigakis
        send_invitation(invitation)
548 ead18dbc Giorgos Verigakis
549 ead18dbc Giorgos Verigakis
550 9a60dacb Giorgos Verigakis
def print_usage(exe, groups, group=None, shortcut=False):
551 9a60dacb Giorgos Verigakis
    nop = Command(exe, [])
552 9a60dacb Giorgos Verigakis
    nop.parser.print_help()
553 9a60dacb Giorgos Verigakis
    if group:
554 9a60dacb Giorgos Verigakis
        groups = {group: groups[group]}
555 8cdde414 Giorgos Verigakis
556 8cdde414 Giorgos Verigakis
    print
557 8cdde414 Giorgos Verigakis
    print 'Commands:'
558 9a60dacb Giorgos Verigakis
    
559 9a60dacb Giorgos Verigakis
    for group, commands in sorted(groups.items()):
560 9a60dacb Giorgos Verigakis
        for command, cls in sorted(commands.items()):
561 735f44fe Giorgos Verigakis
            if cls.hidden:
562 735f44fe Giorgos Verigakis
                continue
563 ead18dbc Giorgos Verigakis
            name = '  %s %s' % (group, command or '')
564 9a60dacb Giorgos Verigakis
            print '%s %s' % (name.ljust(22), cls.description)
565 9a60dacb Giorgos Verigakis
        print
566 8cdde414 Giorgos Verigakis
567 8cdde414 Giorgos Verigakis
568 8cdde414 Giorgos Verigakis
def main():
569 9a60dacb Giorgos Verigakis
    groups = defaultdict(dict)
570 8cdde414 Giorgos Verigakis
    module = sys.modules[__name__]
571 8cdde414 Giorgos Verigakis
    for name, cls in inspect.getmembers(module, inspect.isclass):
572 9a60dacb Giorgos Verigakis
        if not issubclass(cls, Command) or cls == Command:
573 9a60dacb Giorgos Verigakis
            continue
574 9a60dacb Giorgos Verigakis
        groups[cls.group][cls.name] = cls
575 8cdde414 Giorgos Verigakis
    
576 8cdde414 Giorgos Verigakis
    argv = list(sys.argv)
577 8cdde414 Giorgos Verigakis
    exe = basename(argv.pop(0))
578 9a60dacb Giorgos Verigakis
    prefix, sep, suffix = exe.partition('-')
579 9a60dacb Giorgos Verigakis
    if sep and prefix == 'snf' and suffix in groups:
580 9a60dacb Giorgos Verigakis
        # Allow shortcut aliases like snf-image, snf-server, etc
581 9a60dacb Giorgos Verigakis
        group = suffix
582 8cdde414 Giorgos Verigakis
    else:
583 9a60dacb Giorgos Verigakis
        group = argv.pop(0) if argv else None
584 9a60dacb Giorgos Verigakis
        if group in groups:
585 9a60dacb Giorgos Verigakis
            exe = '%s %s' % (exe, group)
586 9a60dacb Giorgos Verigakis
        else:
587 9a60dacb Giorgos Verigakis
            exe = '%s <group>' % exe
588 9a60dacb Giorgos Verigakis
            group = None
589 8cdde414 Giorgos Verigakis
    
590 8cdde414 Giorgos Verigakis
    command = argv.pop(0) if argv else None
591 8cdde414 Giorgos Verigakis
    
592 9a60dacb Giorgos Verigakis
    if group not in groups or command not in groups[group]:
593 9a60dacb Giorgos Verigakis
        print_usage(exe, groups, group)
594 8cdde414 Giorgos Verigakis
        sys.exit(1)
595 8cdde414 Giorgos Verigakis
    
596 9a60dacb Giorgos Verigakis
    cls = groups[group][command]
597 9a60dacb Giorgos Verigakis
    cmd = cls(exe, argv)
598 8cdde414 Giorgos Verigakis
    cmd.execute()
599 8cdde414 Giorgos Verigakis
600 8cdde414 Giorgos Verigakis
601 8cdde414 Giorgos Verigakis
if __name__ == '__main__':
602 8cdde414 Giorgos Verigakis
    main()