Statistics
| Branch: | Tag: | Revision:

root / snf-tools / snf-admin @ 79c33f4e

History | View | Annotate | Download (19.9 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
        if server_id:
153 79c33f4e Giorgos Verigakis
            servers = [models.VirtualMachine.objects.get(id=server_id)]
154 79c33f4e Giorgos Verigakis
        else:
155 79c33f4e Giorgos Verigakis
            servers = models.VirtualMachine.objects.order_by('id')
156 79c33f4e Giorgos Verigakis
            if not self.show_deleted:
157 79c33f4e Giorgos Verigakis
                servers = servers.exclude(deleted=True)
158 79c33f4e Giorgos Verigakis
            if self.uid:
159 79c33f4e Giorgos Verigakis
                user = get_user(self.uid)
160 79c33f4e Giorgos Verigakis
                if user:
161 79c33f4e Giorgos Verigakis
                    servers = servers.filter(owner=user)
162 79c33f4e Giorgos Verigakis
                else:
163 79c33f4e Giorgos Verigakis
                    print 'Unknown user id'
164 79c33f4e Giorgos Verigakis
                    return
165 8cdde414 Giorgos Verigakis
        
166 8cdde414 Giorgos Verigakis
        print_items(servers, self.detail)
167 8cdde414 Giorgos Verigakis
168 8cdde414 Giorgos Verigakis
169 13d2b7f7 Giorgos Verigakis
# User commands
170 13d2b7f7 Giorgos Verigakis
171 735f44fe Giorgos Verigakis
class CreateUser(Command):
172 735f44fe Giorgos Verigakis
    group = 'user'
173 735f44fe Giorgos Verigakis
    name = 'create'
174 06b7df28 Giorgos Verigakis
    syntax = '<username> <email>'
175 735f44fe Giorgos Verigakis
    description = 'create a user'
176 735f44fe Giorgos Verigakis
    
177 735f44fe Giorgos Verigakis
    def add_options(self, parser):
178 735f44fe Giorgos Verigakis
        parser.add_option('--realname', dest='realname', metavar='NAME',
179 735f44fe Giorgos Verigakis
                            help='set real name of user')
180 735f44fe Giorgos Verigakis
        parser.add_option('--type', dest='type', metavar='TYPE',
181 735f44fe Giorgos Verigakis
                            help='set user type')
182 735f44fe Giorgos Verigakis
    
183 06b7df28 Giorgos Verigakis
    def main(self, username, email):
184 22f79931 Giorgos Verigakis
        username = username.decode('utf8')
185 06b7df28 Giorgos Verigakis
        realname = self.realname or username
186 06b7df28 Giorgos Verigakis
        type = self.type or 'USER'
187 d1ceb341 Giorgos Verigakis
        types = [x[0] for x in models.SynnefoUser.ACCOUNT_TYPE]
188 d1ceb341 Giorgos Verigakis
        if type not in types:
189 d1ceb341 Giorgos Verigakis
            valid = ', '.join(types)
190 d1ceb341 Giorgos Verigakis
            print 'Invalid type. Must be one of:', valid
191 06b7df28 Giorgos Verigakis
            return
192 735f44fe Giorgos Verigakis
        
193 87c1dadc Giorgos Verigakis
        user = users._register_user(realname, username, email, type)
194 735f44fe Giorgos Verigakis
        print_item(user)
195 735f44fe Giorgos Verigakis
196 735f44fe Giorgos Verigakis
197 06b7df28 Giorgos Verigakis
class InviteUser(Command):
198 06b7df28 Giorgos Verigakis
    group = 'user'
199 06b7df28 Giorgos Verigakis
    name = 'invite'
200 06b7df28 Giorgos Verigakis
    syntax = '<inviter id> <invitee name> <invitee email>'
201 06b7df28 Giorgos Verigakis
    description = 'invite a user'
202 06b7df28 Giorgos Verigakis
    
203 06b7df28 Giorgos Verigakis
    def main(self, inviter_id, name, email):
204 22f79931 Giorgos Verigakis
        name = name.decode('utf8')
205 06b7df28 Giorgos Verigakis
        inviter = get_user(inviter_id)
206 06b7df28 Giorgos Verigakis
        inv = add_invitation(inviter, name, email)
207 06b7df28 Giorgos Verigakis
        send_invitation(inv)
208 735f44fe Giorgos Verigakis
209 735f44fe Giorgos Verigakis
210 8cdde414 Giorgos Verigakis
class ListUsers(Command):
211 9a60dacb Giorgos Verigakis
    group = 'user'
212 ca8f8081 Giorgos Verigakis
    name = 'list'
213 8cdde414 Giorgos Verigakis
    syntax = '[user id]'
214 8cdde414 Giorgos Verigakis
    description = 'list users'
215 8cdde414 Giorgos Verigakis
    
216 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
217 79c33f4e Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_deleted',
218 79c33f4e Giorgos Verigakis
                        default=False, help='also list deleted users')
219 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
220 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
221 8cdde414 Giorgos Verigakis
    
222 8cdde414 Giorgos Verigakis
    def main(self, user_id=None):
223 8cdde414 Giorgos Verigakis
        if user_id:
224 8cdde414 Giorgos Verigakis
            users = [models.SynnefoUser.objects.get(id=user_id)]
225 8cdde414 Giorgos Verigakis
        else:
226 79c33f4e Giorgos Verigakis
            users = models.SynnefoUser.objects.order_by('id')
227 79c33f4e Giorgos Verigakis
            if not self.show_deleted:
228 79c33f4e Giorgos Verigakis
                users = users.exclude(state='DELETED')
229 1d133009 Giorgos Verigakis
        print_items(users, self.detail, keys=('id', 'name', 'uniq'))
230 8cdde414 Giorgos Verigakis
231 8cdde414 Giorgos Verigakis
232 13d2b7f7 Giorgos Verigakis
class ModifyUser(Command):
233 13d2b7f7 Giorgos Verigakis
    group = 'user'
234 13d2b7f7 Giorgos Verigakis
    name = 'modify'
235 13d2b7f7 Giorgos Verigakis
    syntax = '<user id>'
236 13d2b7f7 Giorgos Verigakis
    description = 'modify a user'
237 13d2b7f7 Giorgos Verigakis
    
238 13d2b7f7 Giorgos Verigakis
    def add_options(self, parser):
239 d1ceb341 Giorgos Verigakis
        types = ', '.join(x[0] for x in models.SynnefoUser.ACCOUNT_TYPE)
240 870c24a0 Giorgos Verigakis
        states = ', '.join(x[0] for x in models.SynnefoUser.ACCOUNT_STATE)
241 d1ceb341 Giorgos Verigakis
        
242 13d2b7f7 Giorgos Verigakis
        parser.add_option('--credit', dest='credit', metavar='VALUE',
243 13d2b7f7 Giorgos Verigakis
                            help='set user credits')
244 13d2b7f7 Giorgos Verigakis
        parser.add_option('--invitations', dest='invitations',
245 13d2b7f7 Giorgos Verigakis
                            metavar='VALUE', help='set max invitations')
246 13d2b7f7 Giorgos Verigakis
        parser.add_option('--realname', dest='realname', metavar='NAME',
247 13d2b7f7 Giorgos Verigakis
                            help='set real name of user')
248 13d2b7f7 Giorgos Verigakis
        parser.add_option('--type', dest='type', metavar='TYPE',
249 d1ceb341 Giorgos Verigakis
                            help='set user type (%s)' % types)
250 870c24a0 Giorgos Verigakis
        parser.add_option('--state', dest='state', metavar='STATE',
251 870c24a0 Giorgos Verigakis
                            help='set user state (%s)' % states)
252 735f44fe Giorgos Verigakis
        parser.add_option('--uniq', dest='uniq', metavar='ID',
253 735f44fe Giorgos Verigakis
                            help='set external unique ID')
254 13d2b7f7 Giorgos Verigakis
        parser.add_option('--username', dest='username', metavar='NAME',
255 13d2b7f7 Giorgos Verigakis
                            help='set username')
256 13d2b7f7 Giorgos Verigakis
    
257 13d2b7f7 Giorgos Verigakis
    def main(self, user_id):
258 13d2b7f7 Giorgos Verigakis
        user = get_user(user_id)
259 13d2b7f7 Giorgos Verigakis
        
260 13d2b7f7 Giorgos Verigakis
        if self.credit:
261 13d2b7f7 Giorgos Verigakis
            user.credit = self.credit
262 13d2b7f7 Giorgos Verigakis
        if self.invitations:
263 13d2b7f7 Giorgos Verigakis
            user.max_invitations = self.invitations
264 13d2b7f7 Giorgos Verigakis
        if self.realname:
265 13d2b7f7 Giorgos Verigakis
            user.realname = self.realname
266 13d2b7f7 Giorgos Verigakis
        if self.type:
267 13d2b7f7 Giorgos Verigakis
            allowed = [x[0] for x in models.SynnefoUser.ACCOUNT_TYPE]
268 13d2b7f7 Giorgos Verigakis
            if self.type not in allowed:
269 d1ceb341 Giorgos Verigakis
                valid = ', '.join(allowed)
270 d1ceb341 Giorgos Verigakis
                print 'Invalid type. Must be one of:', valid
271 13d2b7f7 Giorgos Verigakis
                return
272 13d2b7f7 Giorgos Verigakis
            user.type = self.type
273 870c24a0 Giorgos Verigakis
        if self.state:
274 870c24a0 Giorgos Verigakis
            allowed = [x[0] for x in models.SynnefoUser.ACCOUNT_STATE]
275 870c24a0 Giorgos Verigakis
            if self.state not in allowed:
276 870c24a0 Giorgos Verigakis
                valid = ', '.join(allowed)
277 870c24a0 Giorgos Verigakis
                print 'Invalid state. Must be one of:', valid
278 870c24a0 Giorgos Verigakis
                return
279 870c24a0 Giorgos Verigakis
            user.state = self.state
280 735f44fe Giorgos Verigakis
        if self.uniq:
281 735f44fe Giorgos Verigakis
            user.uniq = self.uniq
282 13d2b7f7 Giorgos Verigakis
        if self.username:
283 13d2b7f7 Giorgos Verigakis
            user.name = self.username
284 13d2b7f7 Giorgos Verigakis
        
285 13d2b7f7 Giorgos Verigakis
        user.save()
286 13d2b7f7 Giorgos Verigakis
        print_item(user)
287 13d2b7f7 Giorgos Verigakis
288 13d2b7f7 Giorgos Verigakis
289 13d2b7f7 Giorgos Verigakis
# Image commands
290 13d2b7f7 Giorgos Verigakis
291 8cdde414 Giorgos Verigakis
class ListImages(Command):
292 9a60dacb Giorgos Verigakis
    group = 'image'
293 ca8f8081 Giorgos Verigakis
    name = 'list'
294 8cdde414 Giorgos Verigakis
    syntax = '[image id]'
295 8cdde414 Giorgos Verigakis
    description = 'list images'
296 8cdde414 Giorgos Verigakis
    
297 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
298 79c33f4e Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_deleted',
299 79c33f4e Giorgos Verigakis
                        default=False, help='also list deleted images')
300 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
301 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
302 8cdde414 Giorgos Verigakis
    
303 8cdde414 Giorgos Verigakis
    def main(self, image_id=None):
304 8cdde414 Giorgos Verigakis
        if image_id:
305 8cdde414 Giorgos Verigakis
            images = [models.Image.objects.get(id=image_id)]
306 8cdde414 Giorgos Verigakis
        else:
307 8cdde414 Giorgos Verigakis
            images = models.Image.objects.order_by('id')
308 79c33f4e Giorgos Verigakis
            if not self.show_deleted:
309 79c33f4e Giorgos Verigakis
                images = images.exclude(state='DELETED')
310 8cdde414 Giorgos Verigakis
        print_items(images, self.detail)
311 8cdde414 Giorgos Verigakis
312 8cdde414 Giorgos Verigakis
313 8cdde414 Giorgos Verigakis
class RegisterImage(Command):
314 9a60dacb Giorgos Verigakis
    group = 'image'
315 8cdde414 Giorgos Verigakis
    name = 'register'
316 d1ceb341 Giorgos Verigakis
    syntax = '<name> <backend id> <format>'
317 8cdde414 Giorgos Verigakis
    description = 'register an image'
318 8cdde414 Giorgos Verigakis
    
319 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
320 ca8f8081 Giorgos Verigakis
        parser.add_option('--public', action='store_true', dest='public',
321 8cdde414 Giorgos Verigakis
                            default=False, help='make image public')
322 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
323 8cdde414 Giorgos Verigakis
                            help='assign image to user with id UID')
324 8cdde414 Giorgos Verigakis
    
325 d1ceb341 Giorgos Verigakis
    def main(self, name, backend_id, format):
326 d1ceb341 Giorgos Verigakis
        formats = [x[0] for x in models.Image.FORMATS]
327 d1ceb341 Giorgos Verigakis
        if format not in formats:
328 d1ceb341 Giorgos Verigakis
            valid = ', '.join(formats)
329 d1ceb341 Giorgos Verigakis
            print 'Invalid format. Must be one of:', valid
330 d1ceb341 Giorgos Verigakis
            return
331 d1ceb341 Giorgos Verigakis
        
332 8cdde414 Giorgos Verigakis
        user = None
333 8cdde414 Giorgos Verigakis
        if self.uid:
334 8cdde414 Giorgos Verigakis
            user = get_user(self.uid)
335 8cdde414 Giorgos Verigakis
            if not user:
336 8cdde414 Giorgos Verigakis
                print 'Unknown user id'
337 8cdde414 Giorgos Verigakis
                return
338 8cdde414 Giorgos Verigakis
        
339 8cdde414 Giorgos Verigakis
        image = models.Image.objects.create(
340 8cdde414 Giorgos Verigakis
            name=name,
341 8cdde414 Giorgos Verigakis
            state='ACTIVE',
342 8cdde414 Giorgos Verigakis
            owner=user,
343 8cdde414 Giorgos Verigakis
            backend_id=backend_id,
344 d1ceb341 Giorgos Verigakis
            format=format,
345 8cdde414 Giorgos Verigakis
            public=self.public)
346 9a60dacb Giorgos Verigakis
        
347 13d2b7f7 Giorgos Verigakis
        print_item(image)
348 8cdde414 Giorgos Verigakis
349 8cdde414 Giorgos Verigakis
350 8cdde414 Giorgos Verigakis
class ModifyImage(Command):
351 9a60dacb Giorgos Verigakis
    group = 'image'
352 8cdde414 Giorgos Verigakis
    name = 'modify'
353 8cdde414 Giorgos Verigakis
    syntax = '<image id>'
354 8cdde414 Giorgos Verigakis
    description = 'modify an image'
355 8cdde414 Giorgos Verigakis
    
356 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
357 d1ceb341 Giorgos Verigakis
        states = ', '.join(x[0] for x in models.Image.IMAGE_STATES)
358 d1ceb341 Giorgos Verigakis
        formats = ', '.join(x[0] for x in models.Image.FORMATS)
359 d1ceb341 Giorgos Verigakis
360 8cdde414 Giorgos Verigakis
        parser.add_option('-b', dest='backend_id', metavar='BACKEND_ID',
361 8cdde414 Giorgos Verigakis
                            help='set image backend id')
362 8cdde414 Giorgos Verigakis
        parser.add_option('-f', dest='format', metavar='FORMAT',
363 d1ceb341 Giorgos Verigakis
                            help='set image format (%s)' % formats)
364 8cdde414 Giorgos Verigakis
        parser.add_option('-n', dest='name', metavar='NAME',
365 8cdde414 Giorgos Verigakis
                            help='set image name')
366 ca8f8081 Giorgos Verigakis
        parser.add_option('--public', action='store_true', dest='public',
367 8cdde414 Giorgos Verigakis
                            default=False, help='make image public')
368 ca8f8081 Giorgos Verigakis
        parser.add_option('--nopublic', action='store_true', dest='private',
369 8cdde414 Giorgos Verigakis
                            default=False, help='make image private')
370 d1ceb341 Giorgos Verigakis
        parser.add_option('-s', dest='state', metavar='STATE', default=False,
371 d1ceb341 Giorgos Verigakis
                            help='set image state (%s)' % states)
372 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
373 8cdde414 Giorgos Verigakis
                            help='assign image to user with id UID')
374 8cdde414 Giorgos Verigakis
    
375 8cdde414 Giorgos Verigakis
    def main(self, image_id):
376 8cdde414 Giorgos Verigakis
        try:
377 8cdde414 Giorgos Verigakis
            image = models.Image.objects.get(id=image_id)
378 8cdde414 Giorgos Verigakis
        except:
379 8cdde414 Giorgos Verigakis
            print 'Image not found'
380 8cdde414 Giorgos Verigakis
            return
381 8cdde414 Giorgos Verigakis
        
382 8cdde414 Giorgos Verigakis
        if self.backend_id:
383 8cdde414 Giorgos Verigakis
            image.backend_id = self.backend_id
384 8cdde414 Giorgos Verigakis
        if self.format:
385 13d2b7f7 Giorgos Verigakis
            allowed = [x[0] for x in models.Image.FORMATS]
386 13d2b7f7 Giorgos Verigakis
            if self.format not in allowed:
387 d1ceb341 Giorgos Verigakis
                valid = ', '.join(allowed)
388 d1ceb341 Giorgos Verigakis
                print 'Invalid format. Must be one of:', valid
389 13d2b7f7 Giorgos Verigakis
                return
390 13d2b7f7 Giorgos Verigakis
            image.format = self.format
391 8cdde414 Giorgos Verigakis
        if self.name:
392 8cdde414 Giorgos Verigakis
            image.name = self.name
393 8cdde414 Giorgos Verigakis
        if self.public:
394 8cdde414 Giorgos Verigakis
            image.public = True
395 8cdde414 Giorgos Verigakis
        if self.private:
396 8cdde414 Giorgos Verigakis
            image.public = False
397 8cdde414 Giorgos Verigakis
        if self.state:
398 13d2b7f7 Giorgos Verigakis
            allowed = [x[0] for x in models.Image.IMAGE_STATES]
399 13d2b7f7 Giorgos Verigakis
            if self.state not in allowed:
400 d1ceb341 Giorgos Verigakis
                valid = ', '.join(allowed)
401 d1ceb341 Giorgos Verigakis
                print 'Invalid state. Must be one of:', valid
402 13d2b7f7 Giorgos Verigakis
                return
403 8cdde414 Giorgos Verigakis
            image.state = self.state
404 8cdde414 Giorgos Verigakis
        if self.uid:
405 8cdde414 Giorgos Verigakis
            image.owner = get_user(self.uid)
406 8cdde414 Giorgos Verigakis
        
407 8cdde414 Giorgos Verigakis
        image.save()
408 13d2b7f7 Giorgos Verigakis
        print_item(image)
409 8cdde414 Giorgos Verigakis
410 8cdde414 Giorgos Verigakis
411 ca8f8081 Giorgos Verigakis
class ModifyImageMeta(Command):
412 9a60dacb Giorgos Verigakis
    group = 'image'
413 ca8f8081 Giorgos Verigakis
    name = 'meta'
414 ca8f8081 Giorgos Verigakis
    syntax = '<image id> [key[=val]]'
415 ca8f8081 Giorgos Verigakis
    description = 'get and manipulate image metadata'
416 ca8f8081 Giorgos Verigakis
    
417 ca8f8081 Giorgos Verigakis
    def main(self, image_id, arg=''):
418 ca8f8081 Giorgos Verigakis
        try:
419 ca8f8081 Giorgos Verigakis
            image = models.Image.objects.get(id=image_id)
420 ca8f8081 Giorgos Verigakis
        except:
421 ca8f8081 Giorgos Verigakis
            print 'Image not found'
422 ca8f8081 Giorgos Verigakis
            return
423 ca8f8081 Giorgos Verigakis
        
424 ca8f8081 Giorgos Verigakis
        key, sep, val = arg.partition('=')
425 ca8f8081 Giorgos Verigakis
        if not sep:
426 ca8f8081 Giorgos Verigakis
            val = None
427 ca8f8081 Giorgos Verigakis
        
428 ca8f8081 Giorgos Verigakis
        if not key:
429 ca8f8081 Giorgos Verigakis
            metadata = {}
430 ca8f8081 Giorgos Verigakis
            for meta in image.imagemetadata_set.order_by('meta_key'):
431 ca8f8081 Giorgos Verigakis
                metadata[meta.meta_key] = meta.meta_value
432 ca8f8081 Giorgos Verigakis
            print_dict(metadata)
433 ca8f8081 Giorgos Verigakis
            return
434 ca8f8081 Giorgos Verigakis
        
435 ca8f8081 Giorgos Verigakis
        try:
436 ca8f8081 Giorgos Verigakis
            meta = image.imagemetadata_set.get(meta_key=key)
437 ca8f8081 Giorgos Verigakis
        except models.ImageMetadata.DoesNotExist:
438 ca8f8081 Giorgos Verigakis
            meta = None
439 ca8f8081 Giorgos Verigakis
        
440 ca8f8081 Giorgos Verigakis
        if val is None:
441 ca8f8081 Giorgos Verigakis
            if meta:
442 ca8f8081 Giorgos Verigakis
                print_dict({key: meta.meta_value})
443 ca8f8081 Giorgos Verigakis
            return
444 ca8f8081 Giorgos Verigakis
        
445 ca8f8081 Giorgos Verigakis
        if val:
446 ca8f8081 Giorgos Verigakis
            if not meta:
447 ca8f8081 Giorgos Verigakis
                meta = image.imagemetadata_set.create(meta_key=key)
448 ca8f8081 Giorgos Verigakis
            meta.meta_value = val
449 ca8f8081 Giorgos Verigakis
            meta.save()
450 ca8f8081 Giorgos Verigakis
        else:
451 ca8f8081 Giorgos Verigakis
            # Delete if val is empty
452 ca8f8081 Giorgos Verigakis
            if meta:
453 ca8f8081 Giorgos Verigakis
                meta.delete()
454 ca8f8081 Giorgos Verigakis
455 ca8f8081 Giorgos Verigakis
456 910f53d9 Giorgos Verigakis
# Flavor commands
457 910f53d9 Giorgos Verigakis
458 910f53d9 Giorgos Verigakis
class CreateFlavor(Command):
459 910f53d9 Giorgos Verigakis
    group = 'flavor'
460 910f53d9 Giorgos Verigakis
    name = 'create'
461 910f53d9 Giorgos Verigakis
    syntax = '<cpu>[,<cpu>,...] <ram>[,<ram>,...] <disk>[,<disk>,...]'
462 910f53d9 Giorgos Verigakis
    description = 'create one or more flavors'
463 910f53d9 Giorgos Verigakis
    
464 910f53d9 Giorgos Verigakis
    def main(self, cpu, ram, disk):
465 910f53d9 Giorgos Verigakis
        cpus = cpu.split(',')
466 910f53d9 Giorgos Verigakis
        rams = ram.split(',')
467 910f53d9 Giorgos Verigakis
        disks = disk.split(',')
468 910f53d9 Giorgos Verigakis
        
469 910f53d9 Giorgos Verigakis
        flavors = []
470 910f53d9 Giorgos Verigakis
        for cpu, ram, disk in product(cpus, rams, disks):
471 910f53d9 Giorgos Verigakis
            try:
472 910f53d9 Giorgos Verigakis
                flavors.append((int(cpu), int(ram), int(disk)))
473 910f53d9 Giorgos Verigakis
            except ValueError:
474 910f53d9 Giorgos Verigakis
                print 'Invalid values'
475 910f53d9 Giorgos Verigakis
                return
476 910f53d9 Giorgos Verigakis
        
477 910f53d9 Giorgos Verigakis
        created = []
478 910f53d9 Giorgos Verigakis
        for cpu, ram, disk in flavors:
479 910f53d9 Giorgos Verigakis
            flavor = models.Flavor.objects.create(cpu=cpu, ram=ram, disk=disk)
480 910f53d9 Giorgos Verigakis
            created.append(flavor)
481 910f53d9 Giorgos Verigakis
        
482 910f53d9 Giorgos Verigakis
        print_items(created, detail=True)
483 910f53d9 Giorgos Verigakis
484 910f53d9 Giorgos Verigakis
485 910f53d9 Giorgos Verigakis
class DeleteFlavor(Command):
486 910f53d9 Giorgos Verigakis
    group = 'flavor'
487 910f53d9 Giorgos Verigakis
    name = 'delete'
488 910f53d9 Giorgos Verigakis
    syntax = '<flavor id> [<flavor id>] [...]'
489 910f53d9 Giorgos Verigakis
    description = 'delete one or more flavors'
490 910f53d9 Giorgos Verigakis
    
491 910f53d9 Giorgos Verigakis
    def main(self, *args):
492 910f53d9 Giorgos Verigakis
        if not args:
493 910f53d9 Giorgos Verigakis
            raise TypeError
494 910f53d9 Giorgos Verigakis
        for flavor_id in args:
495 910f53d9 Giorgos Verigakis
            flavor = models.Flavor.objects.get(id=int(flavor_id))
496 870c24a0 Giorgos Verigakis
            flavor.deleted = True
497 870c24a0 Giorgos Verigakis
            flavor.save()
498 910f53d9 Giorgos Verigakis
499 910f53d9 Giorgos Verigakis
500 910f53d9 Giorgos Verigakis
class ListFlavors(Command):
501 910f53d9 Giorgos Verigakis
    group = 'flavor'
502 910f53d9 Giorgos Verigakis
    name = 'list'
503 910f53d9 Giorgos Verigakis
    syntax = '[flavor id]'
504 910f53d9 Giorgos Verigakis
    description = 'list images'
505 910f53d9 Giorgos Verigakis
    
506 910f53d9 Giorgos Verigakis
    def add_options(self, parser):
507 79c33f4e Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_deleted',
508 79c33f4e Giorgos Verigakis
                default=False, help='also list deleted flavors')
509 910f53d9 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
510 910f53d9 Giorgos Verigakis
                        default=False, help='show detailed output')
511 910f53d9 Giorgos Verigakis
    
512 910f53d9 Giorgos Verigakis
    def main(self, flavor_id=None):
513 910f53d9 Giorgos Verigakis
        if flavor_id:
514 910f53d9 Giorgos Verigakis
            flavors = [models.Flavor.objects.get(id=flavor_id)]
515 910f53d9 Giorgos Verigakis
        else:
516 79c33f4e Giorgos Verigakis
            flavors = models.Flavor.objects.order_by('id')
517 79c33f4e Giorgos Verigakis
            if not self.show_deleted:
518 79c33f4e Giorgos Verigakis
                flavors = flavors.exclude(deleted=True)
519 910f53d9 Giorgos Verigakis
        print_items(flavors, self.detail)
520 910f53d9 Giorgos Verigakis
521 910f53d9 Giorgos Verigakis
522 87c1dadc Giorgos Verigakis
class ShowStats(Command):
523 87c1dadc Giorgos Verigakis
    group = 'stats'
524 87c1dadc Giorgos Verigakis
    name = None
525 87c1dadc Giorgos Verigakis
    description = 'show statistics'
526 87c1dadc Giorgos Verigakis
527 87c1dadc Giorgos Verigakis
    def main(self):
528 87c1dadc Giorgos Verigakis
        stats = {}
529 87c1dadc Giorgos Verigakis
        stats['Users'] = models.SynnefoUser.objects.count()
530 87c1dadc Giorgos Verigakis
        stats['Images'] = models.Image.objects.exclude(state='DELETED').count()
531 87c1dadc Giorgos Verigakis
        stats['Flavors'] = models.Flavor.objects.count()
532 87c1dadc Giorgos Verigakis
        stats['VMs'] = models.VirtualMachine.objects.filter(deleted=False).count()
533 87c1dadc Giorgos Verigakis
        stats['Networks'] = models.Network.objects.exclude(state='DELETED').count()
534 87c1dadc Giorgos Verigakis
        stats['Invitations'] = models.Invitations.objects.count()
535 87c1dadc Giorgos Verigakis
        
536 87c1dadc Giorgos Verigakis
        stats['Ganeti Instances'] = len(backend.get_ganeti_instances())
537 87c1dadc Giorgos Verigakis
        stats['Ganeti Nodes'] = len(backend.get_ganeti_nodes())
538 87c1dadc Giorgos Verigakis
        stats['Ganeti Jobs'] = len(backend.get_ganeti_jobs())
539 87c1dadc Giorgos Verigakis
        
540 87c1dadc Giorgos Verigakis
        print_dict(stats)
541 87c1dadc Giorgos Verigakis
542 87c1dadc Giorgos Verigakis
543 ead18dbc Giorgos Verigakis
class ListInvitations(Command):
544 ead18dbc Giorgos Verigakis
    group = 'invitation'
545 ead18dbc Giorgos Verigakis
    name = 'list'
546 ead18dbc Giorgos Verigakis
    syntax = '[invitation id]'
547 ead18dbc Giorgos Verigakis
    description = 'list invitations'
548 ead18dbc Giorgos Verigakis
    
549 ead18dbc Giorgos Verigakis
    def main(self, invitation_id=None):
550 ead18dbc Giorgos Verigakis
        if invitation_id:
551 ead18dbc Giorgos Verigakis
            invitations = [models.Invitations.objects.get(id=invitation_id)]
552 ead18dbc Giorgos Verigakis
        else:
553 ead18dbc Giorgos Verigakis
            invitations = models.Invitations.objects.order_by('id')
554 ead18dbc Giorgos Verigakis
        print_items(invitations, detail=True, keys=('id',))
555 ead18dbc Giorgos Verigakis
556 ead18dbc Giorgos Verigakis
557 ead18dbc Giorgos Verigakis
class ResendInviation(Command):
558 ead18dbc Giorgos Verigakis
    group = 'invitation'
559 ead18dbc Giorgos Verigakis
    name = 'resend'
560 ead18dbc Giorgos Verigakis
    syntax = '<invitation id>'
561 ead18dbc Giorgos Verigakis
    description = 'resend an invitation'
562 ead18dbc Giorgos Verigakis
563 ead18dbc Giorgos Verigakis
    def main(self, invitation_id):
564 ead18dbc Giorgos Verigakis
        invitation = models.Invitations.objects.get(id=invitation_id)
565 ead18dbc Giorgos Verigakis
        send_invitation(invitation)
566 ead18dbc Giorgos Verigakis
567 ead18dbc Giorgos Verigakis
568 9a60dacb Giorgos Verigakis
def print_usage(exe, groups, group=None, shortcut=False):
569 9a60dacb Giorgos Verigakis
    nop = Command(exe, [])
570 9a60dacb Giorgos Verigakis
    nop.parser.print_help()
571 9a60dacb Giorgos Verigakis
    if group:
572 9a60dacb Giorgos Verigakis
        groups = {group: groups[group]}
573 8cdde414 Giorgos Verigakis
574 8cdde414 Giorgos Verigakis
    print
575 8cdde414 Giorgos Verigakis
    print 'Commands:'
576 9a60dacb Giorgos Verigakis
    
577 9a60dacb Giorgos Verigakis
    for group, commands in sorted(groups.items()):
578 9a60dacb Giorgos Verigakis
        for command, cls in sorted(commands.items()):
579 735f44fe Giorgos Verigakis
            if cls.hidden:
580 735f44fe Giorgos Verigakis
                continue
581 ead18dbc Giorgos Verigakis
            name = '  %s %s' % (group, command or '')
582 9a60dacb Giorgos Verigakis
            print '%s %s' % (name.ljust(22), cls.description)
583 9a60dacb Giorgos Verigakis
        print
584 8cdde414 Giorgos Verigakis
585 8cdde414 Giorgos Verigakis
586 8cdde414 Giorgos Verigakis
def main():
587 9a60dacb Giorgos Verigakis
    groups = defaultdict(dict)
588 8cdde414 Giorgos Verigakis
    module = sys.modules[__name__]
589 8cdde414 Giorgos Verigakis
    for name, cls in inspect.getmembers(module, inspect.isclass):
590 9a60dacb Giorgos Verigakis
        if not issubclass(cls, Command) or cls == Command:
591 9a60dacb Giorgos Verigakis
            continue
592 9a60dacb Giorgos Verigakis
        groups[cls.group][cls.name] = cls
593 8cdde414 Giorgos Verigakis
    
594 8cdde414 Giorgos Verigakis
    argv = list(sys.argv)
595 8cdde414 Giorgos Verigakis
    exe = basename(argv.pop(0))
596 9a60dacb Giorgos Verigakis
    prefix, sep, suffix = exe.partition('-')
597 9a60dacb Giorgos Verigakis
    if sep and prefix == 'snf' and suffix in groups:
598 9a60dacb Giorgos Verigakis
        # Allow shortcut aliases like snf-image, snf-server, etc
599 9a60dacb Giorgos Verigakis
        group = suffix
600 8cdde414 Giorgos Verigakis
    else:
601 9a60dacb Giorgos Verigakis
        group = argv.pop(0) if argv else None
602 9a60dacb Giorgos Verigakis
        if group in groups:
603 9a60dacb Giorgos Verigakis
            exe = '%s %s' % (exe, group)
604 9a60dacb Giorgos Verigakis
        else:
605 9a60dacb Giorgos Verigakis
            exe = '%s <group>' % exe
606 9a60dacb Giorgos Verigakis
            group = None
607 8cdde414 Giorgos Verigakis
    
608 8cdde414 Giorgos Verigakis
    command = argv.pop(0) if argv else None
609 8cdde414 Giorgos Verigakis
    
610 9a60dacb Giorgos Verigakis
    if group not in groups or command not in groups[group]:
611 9a60dacb Giorgos Verigakis
        print_usage(exe, groups, group)
612 8cdde414 Giorgos Verigakis
        sys.exit(1)
613 8cdde414 Giorgos Verigakis
    
614 9a60dacb Giorgos Verigakis
    cls = groups[group][command]
615 9a60dacb Giorgos Verigakis
    cmd = cls(exe, argv)
616 8cdde414 Giorgos Verigakis
    cmd.execute()
617 8cdde414 Giorgos Verigakis
618 8cdde414 Giorgos Verigakis
619 8cdde414 Giorgos Verigakis
if __name__ == '__main__':
620 8cdde414 Giorgos Verigakis
    main()