Statistics
| Branch: | Tag: | Revision:

root / tools / snf-admin @ 9a60dacb

History | View | Annotate | Download (11.1 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 8cdde414 Giorgos Verigakis
from optparse import OptionParser
50 8cdde414 Giorgos Verigakis
from os.path import basename
51 8cdde414 Giorgos Verigakis
52 8cdde414 Giorgos Verigakis
from synnefo.db import models
53 8cdde414 Giorgos Verigakis
54 8cdde414 Giorgos Verigakis
55 8cdde414 Giorgos Verigakis
def get_user(uid):
56 8cdde414 Giorgos Verigakis
    try:
57 8cdde414 Giorgos Verigakis
        uid = int(uid)
58 8cdde414 Giorgos Verigakis
        return models.SynnefoUser.objects.get(id=uid)
59 8cdde414 Giorgos Verigakis
        servers = servers.filter(owner=user)
60 8cdde414 Giorgos Verigakis
    except ValueError:
61 8cdde414 Giorgos Verigakis
        return None
62 8cdde414 Giorgos Verigakis
    except models.SynnefoUser.DoesNotExist:
63 8cdde414 Giorgos Verigakis
        return None
64 8cdde414 Giorgos Verigakis
65 8cdde414 Giorgos Verigakis
def print_dict(d, exclude=()):
66 ca8f8081 Giorgos Verigakis
    if not d:
67 ca8f8081 Giorgos Verigakis
        return
68 8cdde414 Giorgos Verigakis
    margin = max(len(key) for key in d) + 1
69 8cdde414 Giorgos Verigakis
70 8cdde414 Giorgos Verigakis
    for key, val in sorted(d.items()):
71 9a60dacb Giorgos Verigakis
        if key in exclude or key.startswith('_'):
72 8cdde414 Giorgos Verigakis
            continue
73 8cdde414 Giorgos Verigakis
        print '%s: %s' % (key.rjust(margin), val)
74 8cdde414 Giorgos Verigakis
75 8cdde414 Giorgos Verigakis
def print_items(items, detail=False):
76 8cdde414 Giorgos Verigakis
    for item in items:
77 8cdde414 Giorgos Verigakis
        print '%d %s' % (item.id, item.name)
78 8cdde414 Giorgos Verigakis
        if detail:
79 9a60dacb Giorgos Verigakis
            print_dict(item.__dict__, exclude=('id', 'name'))
80 8cdde414 Giorgos Verigakis
            print
81 8cdde414 Giorgos Verigakis
82 8cdde414 Giorgos Verigakis
83 8cdde414 Giorgos Verigakis
class Command(object):
84 9a60dacb Giorgos Verigakis
    group = '<group>'
85 9a60dacb Giorgos Verigakis
    name = '<command>'
86 8cdde414 Giorgos Verigakis
    syntax = ''
87 8cdde414 Giorgos Verigakis
    description = ''
88 8cdde414 Giorgos Verigakis
    
89 9a60dacb Giorgos Verigakis
    def __init__(self, exe, argv):
90 8cdde414 Giorgos Verigakis
        parser = OptionParser()
91 9a60dacb Giorgos Verigakis
        syntax = '%s [options]' % self.syntax if self.syntax else '[options]'
92 9a60dacb Giorgos Verigakis
        parser.usage = '%s %s %s' % (exe, self.name, syntax)
93 9a60dacb Giorgos Verigakis
        parser.description = self.description
94 8cdde414 Giorgos Verigakis
        self.add_options(parser)
95 8cdde414 Giorgos Verigakis
        options, self.args = parser.parse_args(argv)
96 8cdde414 Giorgos Verigakis
        
97 8cdde414 Giorgos Verigakis
        # Add options to self
98 8cdde414 Giorgos Verigakis
        for opt in parser.option_list:
99 8cdde414 Giorgos Verigakis
            key = opt.dest
100 8cdde414 Giorgos Verigakis
            if key:
101 8cdde414 Giorgos Verigakis
                val = getattr(options, key)
102 8cdde414 Giorgos Verigakis
                setattr(self, key, val)
103 8cdde414 Giorgos Verigakis
        
104 8cdde414 Giorgos Verigakis
        ch = logging.StreamHandler()
105 8cdde414 Giorgos Verigakis
        ch.setFormatter(logging.Formatter('%(message)s'))
106 8cdde414 Giorgos Verigakis
        logger = logging.getLogger()
107 8cdde414 Giorgos Verigakis
        logger.addHandler(ch)
108 8cdde414 Giorgos Verigakis
        level = logging.WARNING
109 8cdde414 Giorgos Verigakis
        logger.setLevel(level)
110 8cdde414 Giorgos Verigakis
        
111 8cdde414 Giorgos Verigakis
        self.parser = parser
112 8cdde414 Giorgos Verigakis
    
113 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
114 8cdde414 Giorgos Verigakis
        pass
115 8cdde414 Giorgos Verigakis
    
116 8cdde414 Giorgos Verigakis
    def execute(self):
117 8cdde414 Giorgos Verigakis
        try:
118 8cdde414 Giorgos Verigakis
            self.main(*self.args)
119 8cdde414 Giorgos Verigakis
        except TypeError:
120 8cdde414 Giorgos Verigakis
            self.parser.print_help()
121 8cdde414 Giorgos Verigakis
122 8cdde414 Giorgos Verigakis
123 8cdde414 Giorgos Verigakis
class ListServers(Command):
124 9a60dacb Giorgos Verigakis
    group = 'server'
125 ca8f8081 Giorgos Verigakis
    name = 'list'
126 8cdde414 Giorgos Verigakis
    syntax = '[server id]'
127 8cdde414 Giorgos Verigakis
    description = 'list servers'
128 8cdde414 Giorgos Verigakis
    
129 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
130 8cdde414 Giorgos Verigakis
        parser.add_option('-a', action='store_true', dest='show_deleted',
131 8cdde414 Giorgos Verigakis
                        default=False, help='also list deleted servers')
132 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
133 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
134 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
135 8cdde414 Giorgos Verigakis
                            help='show servers of user with id UID')
136 8cdde414 Giorgos Verigakis
    
137 8cdde414 Giorgos Verigakis
    def main(self, server_id=None):
138 8cdde414 Giorgos Verigakis
        servers = models.VirtualMachine.objects.order_by('id')
139 8cdde414 Giorgos Verigakis
        if server_id:
140 8cdde414 Giorgos Verigakis
            servers = servers.filter(id=server_id)
141 8cdde414 Giorgos Verigakis
        if not self.show_deleted:
142 8cdde414 Giorgos Verigakis
            servers = servers.filter(deleted=False)
143 8cdde414 Giorgos Verigakis
        if self.uid:
144 8cdde414 Giorgos Verigakis
            user = get_user(self.uid)
145 8cdde414 Giorgos Verigakis
            if user:
146 8cdde414 Giorgos Verigakis
                servers = servers.filter(owner=user)
147 8cdde414 Giorgos Verigakis
            else:
148 8cdde414 Giorgos Verigakis
                print 'Unknown user id'
149 8cdde414 Giorgos Verigakis
                return
150 8cdde414 Giorgos Verigakis
        
151 8cdde414 Giorgos Verigakis
        print_items(servers, self.detail)
152 8cdde414 Giorgos Verigakis
153 8cdde414 Giorgos Verigakis
154 8cdde414 Giorgos Verigakis
class ListUsers(Command):
155 9a60dacb Giorgos Verigakis
    group = 'user'
156 ca8f8081 Giorgos Verigakis
    name = 'list'
157 8cdde414 Giorgos Verigakis
    syntax = '[user id]'
158 8cdde414 Giorgos Verigakis
    description = 'list users'
159 8cdde414 Giorgos Verigakis
    
160 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
161 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
162 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
163 8cdde414 Giorgos Verigakis
    
164 8cdde414 Giorgos Verigakis
    def main(self, user_id=None):
165 8cdde414 Giorgos Verigakis
        if user_id:
166 8cdde414 Giorgos Verigakis
            users = [models.SynnefoUser.objects.get(id=user_id)]
167 8cdde414 Giorgos Verigakis
        else:
168 8cdde414 Giorgos Verigakis
            users = models.SynnefoUser.objects.order_by('id')
169 8cdde414 Giorgos Verigakis
        print_items(users, self.detail)
170 8cdde414 Giorgos Verigakis
171 8cdde414 Giorgos Verigakis
172 8cdde414 Giorgos Verigakis
class ListImages(Command):
173 9a60dacb Giorgos Verigakis
    group = 'image'
174 ca8f8081 Giorgos Verigakis
    name = 'list'
175 8cdde414 Giorgos Verigakis
    syntax = '[image id]'
176 8cdde414 Giorgos Verigakis
    description = 'list images'
177 8cdde414 Giorgos Verigakis
    
178 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
179 8cdde414 Giorgos Verigakis
        parser.add_option('-l', action='store_true', dest='detail',
180 8cdde414 Giorgos Verigakis
                        default=False, help='show detailed output')
181 8cdde414 Giorgos Verigakis
    
182 8cdde414 Giorgos Verigakis
    def main(self, image_id=None):
183 8cdde414 Giorgos Verigakis
        if image_id:
184 8cdde414 Giorgos Verigakis
            images = [models.Image.objects.get(id=image_id)]
185 8cdde414 Giorgos Verigakis
        else:
186 8cdde414 Giorgos Verigakis
            images = models.Image.objects.order_by('id')
187 8cdde414 Giorgos Verigakis
        print_items(images, self.detail)
188 8cdde414 Giorgos Verigakis
189 8cdde414 Giorgos Verigakis
190 8cdde414 Giorgos Verigakis
class RegisterImage(Command):
191 9a60dacb Giorgos Verigakis
    group = 'image'
192 8cdde414 Giorgos Verigakis
    name = 'register'
193 8cdde414 Giorgos Verigakis
    syntax = '<name> <backend id>'
194 8cdde414 Giorgos Verigakis
    description = 'register an image'
195 8cdde414 Giorgos Verigakis
    
196 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
197 ca8f8081 Giorgos Verigakis
        parser.add_option('--public', action='store_true', dest='public',
198 8cdde414 Giorgos Verigakis
                            default=False, help='make image public')
199 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
200 8cdde414 Giorgos Verigakis
                            help='assign image to user with id UID')
201 8cdde414 Giorgos Verigakis
    
202 8cdde414 Giorgos Verigakis
    def main(self, name, backend_id):
203 8cdde414 Giorgos Verigakis
        user = None
204 8cdde414 Giorgos Verigakis
        if self.uid:
205 8cdde414 Giorgos Verigakis
            user = get_user(self.uid)
206 8cdde414 Giorgos Verigakis
            if not user:
207 8cdde414 Giorgos Verigakis
                print 'Unknown user id'
208 8cdde414 Giorgos Verigakis
                return
209 8cdde414 Giorgos Verigakis
        
210 8cdde414 Giorgos Verigakis
        image = models.Image.objects.create(
211 8cdde414 Giorgos Verigakis
            name=name,
212 8cdde414 Giorgos Verigakis
            state='ACTIVE',
213 8cdde414 Giorgos Verigakis
            owner=user,
214 8cdde414 Giorgos Verigakis
            backend_id=backend_id,
215 8cdde414 Giorgos Verigakis
            public=self.public)
216 9a60dacb Giorgos Verigakis
        
217 9a60dacb Giorgos Verigakis
        print_items([image], detail=True)
218 8cdde414 Giorgos Verigakis
219 8cdde414 Giorgos Verigakis
220 8cdde414 Giorgos Verigakis
class ModifyImage(Command):
221 9a60dacb Giorgos Verigakis
    group = 'image'
222 8cdde414 Giorgos Verigakis
    name = 'modify'
223 8cdde414 Giorgos Verigakis
    syntax = '<image id>'
224 8cdde414 Giorgos Verigakis
    description = 'modify an image'
225 8cdde414 Giorgos Verigakis
    
226 8cdde414 Giorgos Verigakis
    def add_options(self, parser):
227 8cdde414 Giorgos Verigakis
        parser.add_option('-b', dest='backend_id', metavar='BACKEND_ID',
228 8cdde414 Giorgos Verigakis
                            help='set image backend id')
229 8cdde414 Giorgos Verigakis
        parser.add_option('-f', dest='format', metavar='FORMAT',
230 8cdde414 Giorgos Verigakis
                            help='set image format')
231 8cdde414 Giorgos Verigakis
        parser.add_option('-n', dest='name', metavar='NAME',
232 8cdde414 Giorgos Verigakis
                            help='set image name')
233 ca8f8081 Giorgos Verigakis
        parser.add_option('--public', action='store_true', dest='public',
234 8cdde414 Giorgos Verigakis
                            default=False, help='make image public')
235 ca8f8081 Giorgos Verigakis
        parser.add_option('--nopublic', action='store_true', dest='private',
236 8cdde414 Giorgos Verigakis
                            default=False, help='make image private')
237 8cdde414 Giorgos Verigakis
        parser.add_option('-s', dest='state', metavar='STATE',
238 8cdde414 Giorgos Verigakis
                            default=False, help='set image state')
239 8cdde414 Giorgos Verigakis
        parser.add_option('-u', dest='uid', metavar='UID',
240 8cdde414 Giorgos Verigakis
                            help='assign image to user with id UID')
241 8cdde414 Giorgos Verigakis
    
242 8cdde414 Giorgos Verigakis
    def main(self, image_id):
243 8cdde414 Giorgos Verigakis
        try:
244 8cdde414 Giorgos Verigakis
            image = models.Image.objects.get(id=image_id)
245 8cdde414 Giorgos Verigakis
        except:
246 8cdde414 Giorgos Verigakis
            print 'Image not found'
247 8cdde414 Giorgos Verigakis
            return
248 8cdde414 Giorgos Verigakis
        
249 8cdde414 Giorgos Verigakis
        if self.backend_id:
250 8cdde414 Giorgos Verigakis
            image.backend_id = self.backend_id
251 8cdde414 Giorgos Verigakis
        if self.format:
252 8cdde414 Giorgos Verigakis
            image.format = format
253 8cdde414 Giorgos Verigakis
        if self.name:
254 8cdde414 Giorgos Verigakis
            image.name = self.name
255 8cdde414 Giorgos Verigakis
        if self.public:
256 8cdde414 Giorgos Verigakis
            image.public = True
257 8cdde414 Giorgos Verigakis
        if self.private:
258 8cdde414 Giorgos Verigakis
            image.public = False
259 8cdde414 Giorgos Verigakis
        if self.state:
260 8cdde414 Giorgos Verigakis
            image.state = self.state
261 8cdde414 Giorgos Verigakis
        if self.uid:
262 8cdde414 Giorgos Verigakis
            image.owner = get_user(self.uid)
263 8cdde414 Giorgos Verigakis
        
264 8cdde414 Giorgos Verigakis
        image.save()
265 8cdde414 Giorgos Verigakis
266 8cdde414 Giorgos Verigakis
267 ca8f8081 Giorgos Verigakis
class ModifyImageMeta(Command):
268 9a60dacb Giorgos Verigakis
    group = 'image'
269 ca8f8081 Giorgos Verigakis
    name = 'meta'
270 ca8f8081 Giorgos Verigakis
    syntax = '<image id> [key[=val]]'
271 ca8f8081 Giorgos Verigakis
    description = 'get and manipulate image metadata'
272 ca8f8081 Giorgos Verigakis
    
273 ca8f8081 Giorgos Verigakis
    def main(self, image_id, arg=''):
274 ca8f8081 Giorgos Verigakis
        try:
275 ca8f8081 Giorgos Verigakis
            image = models.Image.objects.get(id=image_id)
276 ca8f8081 Giorgos Verigakis
        except:
277 ca8f8081 Giorgos Verigakis
            print 'Image not found'
278 ca8f8081 Giorgos Verigakis
            return
279 ca8f8081 Giorgos Verigakis
        
280 ca8f8081 Giorgos Verigakis
        key, sep, val = arg.partition('=')
281 ca8f8081 Giorgos Verigakis
        if not sep:
282 ca8f8081 Giorgos Verigakis
            val = None
283 ca8f8081 Giorgos Verigakis
        
284 ca8f8081 Giorgos Verigakis
        if not key:
285 ca8f8081 Giorgos Verigakis
            metadata = {}
286 ca8f8081 Giorgos Verigakis
            for meta in image.imagemetadata_set.order_by('meta_key'):
287 ca8f8081 Giorgos Verigakis
                metadata[meta.meta_key] = meta.meta_value
288 ca8f8081 Giorgos Verigakis
            print_dict(metadata)
289 ca8f8081 Giorgos Verigakis
            return
290 ca8f8081 Giorgos Verigakis
        
291 ca8f8081 Giorgos Verigakis
        try:
292 ca8f8081 Giorgos Verigakis
            meta = image.imagemetadata_set.get(meta_key=key)
293 ca8f8081 Giorgos Verigakis
        except models.ImageMetadata.DoesNotExist:
294 ca8f8081 Giorgos Verigakis
            meta = None
295 ca8f8081 Giorgos Verigakis
        
296 ca8f8081 Giorgos Verigakis
        if val is None:
297 ca8f8081 Giorgos Verigakis
            if meta:
298 ca8f8081 Giorgos Verigakis
                print_dict({key: meta.meta_value})
299 ca8f8081 Giorgos Verigakis
            return
300 ca8f8081 Giorgos Verigakis
        
301 ca8f8081 Giorgos Verigakis
        if val:
302 ca8f8081 Giorgos Verigakis
            if not meta:
303 ca8f8081 Giorgos Verigakis
                meta = image.imagemetadata_set.create(meta_key=key)
304 ca8f8081 Giorgos Verigakis
            meta.meta_value = val
305 ca8f8081 Giorgos Verigakis
            meta.save()
306 ca8f8081 Giorgos Verigakis
        else:
307 ca8f8081 Giorgos Verigakis
            # Delete if val is empty
308 ca8f8081 Giorgos Verigakis
            if meta:
309 ca8f8081 Giorgos Verigakis
                meta.delete()
310 ca8f8081 Giorgos Verigakis
311 ca8f8081 Giorgos Verigakis
312 9a60dacb Giorgos Verigakis
def print_usage(exe, groups, group=None, shortcut=False):
313 9a60dacb Giorgos Verigakis
    nop = Command(exe, [])
314 9a60dacb Giorgos Verigakis
    nop.parser.print_help()
315 9a60dacb Giorgos Verigakis
    if group:
316 9a60dacb Giorgos Verigakis
        groups = {group: groups[group]}
317 8cdde414 Giorgos Verigakis
318 8cdde414 Giorgos Verigakis
    print
319 8cdde414 Giorgos Verigakis
    print 'Commands:'
320 9a60dacb Giorgos Verigakis
    
321 9a60dacb Giorgos Verigakis
    for group, commands in sorted(groups.items()):
322 9a60dacb Giorgos Verigakis
        for command, cls in sorted(commands.items()):
323 9a60dacb Giorgos Verigakis
            name = '  %s %s' % (group, command)
324 9a60dacb Giorgos Verigakis
            print '%s %s' % (name.ljust(22), cls.description)
325 9a60dacb Giorgos Verigakis
        print
326 8cdde414 Giorgos Verigakis
327 8cdde414 Giorgos Verigakis
328 8cdde414 Giorgos Verigakis
def main():
329 9a60dacb Giorgos Verigakis
    groups = defaultdict(dict)
330 8cdde414 Giorgos Verigakis
    module = sys.modules[__name__]
331 8cdde414 Giorgos Verigakis
    for name, cls in inspect.getmembers(module, inspect.isclass):
332 9a60dacb Giorgos Verigakis
        if not issubclass(cls, Command) or cls == Command:
333 9a60dacb Giorgos Verigakis
            continue
334 9a60dacb Giorgos Verigakis
        groups[cls.group][cls.name] = cls
335 8cdde414 Giorgos Verigakis
    
336 8cdde414 Giorgos Verigakis
    argv = list(sys.argv)
337 8cdde414 Giorgos Verigakis
    exe = basename(argv.pop(0))
338 9a60dacb Giorgos Verigakis
    prefix, sep, suffix = exe.partition('-')
339 9a60dacb Giorgos Verigakis
    if sep and prefix == 'snf' and suffix in groups:
340 9a60dacb Giorgos Verigakis
        # Allow shortcut aliases like snf-image, snf-server, etc
341 9a60dacb Giorgos Verigakis
        group = suffix
342 8cdde414 Giorgos Verigakis
    else:
343 9a60dacb Giorgos Verigakis
        group = argv.pop(0) if argv else None
344 9a60dacb Giorgos Verigakis
        if group in groups:
345 9a60dacb Giorgos Verigakis
            exe = '%s %s' % (exe, group)
346 9a60dacb Giorgos Verigakis
        else:
347 9a60dacb Giorgos Verigakis
            exe = '%s <group>' % exe
348 9a60dacb Giorgos Verigakis
            group = None
349 8cdde414 Giorgos Verigakis
    
350 8cdde414 Giorgos Verigakis
    command = argv.pop(0) if argv else None
351 8cdde414 Giorgos Verigakis
    
352 9a60dacb Giorgos Verigakis
    if group not in groups or command not in groups[group]:
353 9a60dacb Giorgos Verigakis
        print_usage(exe, groups, group)
354 8cdde414 Giorgos Verigakis
        sys.exit(1)
355 8cdde414 Giorgos Verigakis
    
356 9a60dacb Giorgos Verigakis
    cls = groups[group][command]
357 9a60dacb Giorgos Verigakis
    cmd = cls(exe, argv)
358 8cdde414 Giorgos Verigakis
    cmd.execute()
359 8cdde414 Giorgos Verigakis
360 8cdde414 Giorgos Verigakis
361 8cdde414 Giorgos Verigakis
if __name__ == '__main__':
362 8cdde414 Giorgos Verigakis
    main()