Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / commands / cyclades.py @ ffe30114

History | View | Annotate | Download (35.9 kB)

1 b8220825 Stavros Sachtouris
# Copyright 2011-2014 GRNET S.A. All rights reserved.
2 7493ccb6 Stavros Sachtouris
#
3 7493ccb6 Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 7493ccb6 Stavros Sachtouris
# without modification, are permitted provided that the following
5 7493ccb6 Stavros Sachtouris
# conditions are met:
6 7493ccb6 Stavros Sachtouris
#
7 7493ccb6 Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 7493ccb6 Stavros Sachtouris
#      disclaimer.
10 7493ccb6 Stavros Sachtouris
#
11 7493ccb6 Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 7493ccb6 Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 7493ccb6 Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 7493ccb6 Stavros Sachtouris
#      provided with the distribution.
15 7493ccb6 Stavros Sachtouris
#
16 7493ccb6 Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 7493ccb6 Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 7493ccb6 Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 7493ccb6 Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 7493ccb6 Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 7493ccb6 Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 7493ccb6 Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 7493ccb6 Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 7493ccb6 Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 7493ccb6 Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 7493ccb6 Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 7493ccb6 Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 7493ccb6 Stavros Sachtouris
#
29 7493ccb6 Stavros Sachtouris
# The views and conclusions contained in the software and
30 7493ccb6 Stavros Sachtouris
# documentation are those of the authors and should not be
31 7493ccb6 Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 7493ccb6 Stavros Sachtouris
# or implied, of GRNET S.A.
33 c75be81a Stavros Sachtouris
import cStringIO
34 c75be81a Stavros Sachtouris
import codecs
35 76f58e2e Stavros Sachtouris
from base64 import b64encode
36 d62cba24 Stavros Sachtouris
from os.path import exists, expanduser
37 76f58e2e Stavros Sachtouris
from io import StringIO
38 76f58e2e Stavros Sachtouris
from pydoc import pager
39 c75be81a Stavros Sachtouris
from json import dumps
40 76f58e2e Stavros Sachtouris
41 f3e94e06 Stavros Sachtouris
from kamaki.cli import command
42 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
43 76f58e2e Stavros Sachtouris
from kamaki.cli.utils import remove_from_items, filter_dicts_by_dict
44 c788a761 Stavros Sachtouris
from kamaki.cli.errors import (
45 c788a761 Stavros Sachtouris
    raiseCLIError, CLISyntaxError, CLIBaseUrlError, CLIInvalidArgument)
46 d1bced10 Stavros Sachtouris
from kamaki.clients.cyclades import CycladesClient
47 0b052394 Stavros Sachtouris
from kamaki.cli.argument import (
48 0b052394 Stavros Sachtouris
    FlagArgument, ValueArgument, KeyValueArgument, RepeatableArgument,
49 c3d42104 Stavros Sachtouris
    ProgressBarArgument, DateArgument, IntArgument, StatusArgument)
50 6d190dd1 Stavros Sachtouris
from kamaki.cli.commands import (
51 c75be81a Stavros Sachtouris
    _command_init, errors, addLogSettings, dataModification,
52 6d190dd1 Stavros Sachtouris
    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
53 5eae854d Stavros Sachtouris
54 234954d1 Stavros Sachtouris
55 a29d2f88 Stavros Sachtouris
server_cmds = CommandTree('server', 'Cyclades/Compute API server commands')
56 a29d2f88 Stavros Sachtouris
flavor_cmds = CommandTree('flavor', 'Cyclades/Compute API flavor commands')
57 291cab21 Stavros Sachtouris
_commands = [server_cmds, flavor_cmds]
58 234954d1 Stavros Sachtouris
59 7493ccb6 Stavros Sachtouris
60 c314fc10 Stavros Sachtouris
about_authentication = '\nUser Authentication:\
61 4018326d Stavros Sachtouris
    \n* to check authentication: /user authenticate\
62 9e5341f5 Stavros Sachtouris
    \n* to set authentication token: /config set cloud.<cloud>.token <token>'
63 18edacfe Stavros Sachtouris
64 d7259dd5 Stavros Sachtouris
howto_personality = [
65 2bd23362 Stavros Sachtouris
    'Defines a file to be injected to virtual servers file system.',
66 3185cd6d Stavros Sachtouris
    'syntax:  PATH,[SERVER_PATH,[OWNER,[GROUP,[MODE]]]]',
67 0fccd79b Stavros Sachtouris
    '  [local-path=]PATH: local file to be injected (relative or absolute)',
68 0fccd79b Stavros Sachtouris
    '  [server-path=]SERVER_PATH: destination location inside server Image',
69 0fccd79b Stavros Sachtouris
    '  [owner=]OWNER: virtual servers user id for the remote file',
70 0fccd79b Stavros Sachtouris
    '  [group=]GROUP: virtual servers group id or name for the remote file',
71 d62cba24 Stavros Sachtouris
    '  [mode=]MODE: permission in octal (e.g., 0777)',
72 0fccd79b Stavros Sachtouris
    'e.g., -p /tmp/my.file,owner=root,mode=0777']
73 d7259dd5 Stavros Sachtouris
74 c3d42104 Stavros Sachtouris
server_states = ('BUILD', 'ACTIVE', 'STOPPED', 'REBOOT')
75 c3d42104 Stavros Sachtouris
76 18edacfe Stavros Sachtouris
77 3185cd6d Stavros Sachtouris
class _service_wait(object):
78 60c42f9f Stavros Sachtouris
79 60c42f9f Stavros Sachtouris
    wait_arguments = dict(
80 60c42f9f Stavros Sachtouris
        progress_bar=ProgressBarArgument(
81 3185cd6d Stavros Sachtouris
            'do not show progress bar', ('-N', '--no-progress-bar'), False)
82 60c42f9f Stavros Sachtouris
    )
83 60c42f9f Stavros Sachtouris
84 e9c73313 Stavros Sachtouris
    def _wait(
85 e9c73313 Stavros Sachtouris
            self, service, service_id, status_method, current_status,
86 8547cd19 Stavros Sachtouris
            countdown=True, timeout=60):
87 60c42f9f Stavros Sachtouris
        (progress_bar, wait_cb) = self._safe_progress_bar(
88 e9c73313 Stavros Sachtouris
            '%s %s: status is still %s' % (
89 e9c73313 Stavros Sachtouris
                service, service_id, current_status),
90 8547cd19 Stavros Sachtouris
            countdown=countdown, timeout=timeout)
91 60c42f9f Stavros Sachtouris
92 60c42f9f Stavros Sachtouris
        try:
93 3185cd6d Stavros Sachtouris
            new_mode = status_method(
94 8547cd19 Stavros Sachtouris
                service_id, current_status, max_wait=timeout, wait_cb=wait_cb)
95 a9598baf Stavros Sachtouris
            if new_mode:
96 e9c73313 Stavros Sachtouris
                self.error('%s %s: status is now %s' % (
97 a9598baf Stavros Sachtouris
                    service, service_id, new_mode))
98 a9598baf Stavros Sachtouris
            else:
99 8547cd19 Stavros Sachtouris
                self.error('%s %s: status is still %s' % (
100 e9c73313 Stavros Sachtouris
                    service, service_id, current_status))
101 a9598baf Stavros Sachtouris
        except KeyboardInterrupt:
102 a9598baf Stavros Sachtouris
            self.error('\n- canceled')
103 60c42f9f Stavros Sachtouris
        finally:
104 60c42f9f Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
105 60c42f9f Stavros Sachtouris
106 60c42f9f Stavros Sachtouris
107 3185cd6d Stavros Sachtouris
class _server_wait(_service_wait):
108 7b2e4bf1 Stavros Sachtouris
109 8547cd19 Stavros Sachtouris
    def _wait(self, server_id, current_status, timeout=60):
110 3185cd6d Stavros Sachtouris
        super(_server_wait, self)._wait(
111 e9c73313 Stavros Sachtouris
            'Server', server_id, self.client.wait_server, current_status,
112 8547cd19 Stavros Sachtouris
            countdown=(current_status not in ('BUILD', )),
113 8547cd19 Stavros Sachtouris
            timeout=timeout if current_status not in ('BUILD', ) else 100)
114 7b2e4bf1 Stavros Sachtouris
115 7b2e4bf1 Stavros Sachtouris
116 5eae854d Stavros Sachtouris
class _init_cyclades(_command_init):
117 b04288f7 Stavros Sachtouris
    @errors.generic.all
118 b4f69041 Stavros Sachtouris
    @addLogSettings
119 236e7d08 Stavros Sachtouris
    def _run(self, service='compute'):
120 b4f69041 Stavros Sachtouris
        if getattr(self, 'cloud', None):
121 3185cd6d Stavros Sachtouris
            base_url = self._custom_url(service) or self._custom_url(
122 3185cd6d Stavros Sachtouris
                'cyclades')
123 b4f69041 Stavros Sachtouris
            if base_url:
124 3185cd6d Stavros Sachtouris
                token = self._custom_token(service) or self._custom_token(
125 3185cd6d Stavros Sachtouris
                    'cyclades') or self.config.get_cloud('token')
126 3185cd6d Stavros Sachtouris
                self.client = CycladesClient(base_url=base_url, token=token)
127 b4f69041 Stavros Sachtouris
                return
128 b4f69041 Stavros Sachtouris
        else:
129 b4f69041 Stavros Sachtouris
            self.cloud = 'default'
130 8cec3671 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
131 8cec3671 Stavros Sachtouris
            cyclades_endpoints = self.auth_base.get_service_endpoints(
132 b4f69041 Stavros Sachtouris
                self._custom_type('cyclades') or 'compute',
133 b4f69041 Stavros Sachtouris
                self._custom_version('cyclades') or '')
134 8cec3671 Stavros Sachtouris
            base_url = cyclades_endpoints['publicURL']
135 b4f69041 Stavros Sachtouris
            token = self.auth_base.token
136 b4f69041 Stavros Sachtouris
            self.client = CycladesClient(base_url=base_url, token=token)
137 8cec3671 Stavros Sachtouris
        else:
138 8cec3671 Stavros Sachtouris
            raise CLIBaseUrlError(service='cyclades')
139 8cec3671 Stavros Sachtouris
140 c75be81a Stavros Sachtouris
    @dataModification
141 c75be81a Stavros Sachtouris
    def _restruct_server_info(self, vm):
142 c75be81a Stavros Sachtouris
        if not vm:
143 c75be81a Stavros Sachtouris
            return vm
144 c75be81a Stavros Sachtouris
        img = vm['image']
145 c75be81a Stavros Sachtouris
        try:
146 c75be81a Stavros Sachtouris
            img.pop('links', None)
147 c75be81a Stavros Sachtouris
            img['name'] = self.client.get_image_details(img['id'])['name']
148 c75be81a Stavros Sachtouris
        except Exception:
149 c75be81a Stavros Sachtouris
            pass
150 c75be81a Stavros Sachtouris
        flv = vm['flavor']
151 c75be81a Stavros Sachtouris
        try:
152 c75be81a Stavros Sachtouris
            flv.pop('links', None)
153 c75be81a Stavros Sachtouris
            flv['name'] = self.client.get_flavor_details(flv['id'])['name']
154 c75be81a Stavros Sachtouris
        except Exception:
155 c75be81a Stavros Sachtouris
            pass
156 c75be81a Stavros Sachtouris
        vm['ports'] = vm.pop('attachments', dict())
157 c75be81a Stavros Sachtouris
        for port in vm['ports']:
158 c75be81a Stavros Sachtouris
            netid = port.get('network_id')
159 c75be81a Stavros Sachtouris
            for k in vm['addresses'].get(netid, []):
160 c75be81a Stavros Sachtouris
                k.pop('addr', None)
161 c75be81a Stavros Sachtouris
                k.pop('version', None)
162 c75be81a Stavros Sachtouris
                port.update(k)
163 c75be81a Stavros Sachtouris
        uuids = self._uuids2usernames([vm['user_id'], vm['tenant_id']])
164 c75be81a Stavros Sachtouris
        vm['user_id'] += ' (%s)' % uuids[vm['user_id']]
165 c75be81a Stavros Sachtouris
        for key in ('addresses', 'tenant_id', 'links'):
166 c75be81a Stavros Sachtouris
            vm.pop(key, None)
167 c75be81a Stavros Sachtouris
        return vm
168 c75be81a Stavros Sachtouris
169 b04288f7 Stavros Sachtouris
    def main(self):
170 b04288f7 Stavros Sachtouris
        self._run()
171 236e7d08 Stavros Sachtouris
172 234954d1 Stavros Sachtouris
173 d486baec Stavros Sachtouris
@command(server_cmds)
174 6d190dd1 Stavros Sachtouris
class server_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
175 f6822a26 Stavros Sachtouris
    """List virtual servers accessible by user
176 16d7b9ff Stavros Sachtouris
    Use filtering arguments (e.g., --name-like) to manage long server lists
177 f6822a26 Stavros Sachtouris
    """
178 18edacfe Stavros Sachtouris
179 89ea97e1 Stavros Sachtouris
    PERMANENTS = ('id', 'name')
180 89ea97e1 Stavros Sachtouris
181 e15d78e2 Stavros Sachtouris
    arguments = dict(
182 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
183 67469d65 Stavros Sachtouris
        since=DateArgument(
184 a382ea56 Stavros Sachtouris
            'show only items since date (\' d/m/Y H:M:S \')',
185 a4d0d88a Stavros Sachtouris
            '--since'),
186 2bd23362 Stavros Sachtouris
        limit=IntArgument(
187 2bd23362 Stavros Sachtouris
            'limit number of listed virtual servers', ('-n', '--number')),
188 a4d0d88a Stavros Sachtouris
        more=FlagArgument(
189 ddc0b290 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
190 ed9af02c Stavros Sachtouris
            '--more'),
191 89ea97e1 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
192 89ea97e1 Stavros Sachtouris
        flavor_id=ValueArgument('filter by flavor id', ('--flavor-id')),
193 89ea97e1 Stavros Sachtouris
        image_id=ValueArgument('filter by image id', ('--image-id')),
194 d8ff7b56 Stavros Sachtouris
        user_id=ValueArgument('filter by user id', ('--user-id')),
195 d8ff7b56 Stavros Sachtouris
        user_name=ValueArgument('filter by user name', ('--user-name')),
196 d8ff7b56 Stavros Sachtouris
        status=ValueArgument(
197 d8ff7b56 Stavros Sachtouris
            'filter by status (ACTIVE, STOPPED, REBOOT, ERROR, etc.)',
198 d8ff7b56 Stavros Sachtouris
            ('--status')),
199 89ea97e1 Stavros Sachtouris
        meta=KeyValueArgument('filter by metadata key=values', ('--metadata')),
200 89ea97e1 Stavros Sachtouris
        meta_like=KeyValueArgument(
201 89ea97e1 Stavros Sachtouris
            'print only if in key=value, the value is part of actual value',
202 89ea97e1 Stavros Sachtouris
            ('--metadata-like')),
203 e15d78e2 Stavros Sachtouris
    )
204 e15d78e2 Stavros Sachtouris
205 f00db940 Stavros Sachtouris
    def _add_user_name(self, servers):
206 9d2f656a Stavros Sachtouris
        uuids = self._uuids2usernames(list(set(
207 9d2f656a Stavros Sachtouris
                [srv['user_id'] for srv in servers] +
208 9d2f656a Stavros Sachtouris
                [srv['tenant_id'] for srv in servers])))
209 f00db940 Stavros Sachtouris
        for srv in servers:
210 f00db940 Stavros Sachtouris
            srv['user_id'] += ' (%s)' % uuids[srv['user_id']]
211 9d2f656a Stavros Sachtouris
            srv['tenant_id'] += ' (%s)' % uuids[srv['tenant_id']]
212 f00db940 Stavros Sachtouris
        return servers
213 f00db940 Stavros Sachtouris
214 d8ff7b56 Stavros Sachtouris
    def _apply_common_filters(self, servers):
215 d8ff7b56 Stavros Sachtouris
        common_filters = dict()
216 d8ff7b56 Stavros Sachtouris
        if self['status']:
217 d8ff7b56 Stavros Sachtouris
            common_filters['status'] = self['status']
218 d8ff7b56 Stavros Sachtouris
        if self['user_id'] or self['user_name']:
219 d8ff7b56 Stavros Sachtouris
            uuid = self['user_id'] or self._username2uuid(self['user_name'])
220 d8ff7b56 Stavros Sachtouris
            common_filters['user_id'] = uuid
221 d8ff7b56 Stavros Sachtouris
        return filter_dicts_by_dict(servers, common_filters)
222 d8ff7b56 Stavros Sachtouris
223 6d190dd1 Stavros Sachtouris
    def _filter_by_image(self, servers):
224 89ea97e1 Stavros Sachtouris
        iid = self['image_id']
225 3185cd6d Stavros Sachtouris
        return [srv for srv in servers if srv['image']['id'] == iid]
226 89ea97e1 Stavros Sachtouris
227 6d190dd1 Stavros Sachtouris
    def _filter_by_flavor(self, servers):
228 89ea97e1 Stavros Sachtouris
        fid = self['flavor_id']
229 3185cd6d Stavros Sachtouris
        return [srv for srv in servers if (
230 3185cd6d Stavros Sachtouris
            '%s' % srv['image']['id'] == '%s' % fid)]
231 89ea97e1 Stavros Sachtouris
232 6d190dd1 Stavros Sachtouris
    def _filter_by_metadata(self, servers):
233 89ea97e1 Stavros Sachtouris
        new_servers = []
234 89ea97e1 Stavros Sachtouris
        for srv in servers:
235 89ea97e1 Stavros Sachtouris
            if not 'metadata' in srv:
236 89ea97e1 Stavros Sachtouris
                continue
237 89ea97e1 Stavros Sachtouris
            meta = [dict(srv['metadata'])]
238 89ea97e1 Stavros Sachtouris
            if self['meta']:
239 89ea97e1 Stavros Sachtouris
                meta = filter_dicts_by_dict(meta, self['meta'])
240 89ea97e1 Stavros Sachtouris
            if meta and self['meta_like']:
241 89ea97e1 Stavros Sachtouris
                meta = filter_dicts_by_dict(
242 89ea97e1 Stavros Sachtouris
                    meta, self['meta_like'], exact_match=False)
243 89ea97e1 Stavros Sachtouris
            if meta:
244 89ea97e1 Stavros Sachtouris
                new_servers.append(srv)
245 89ea97e1 Stavros Sachtouris
        return new_servers
246 89ea97e1 Stavros Sachtouris
247 b04288f7 Stavros Sachtouris
    @errors.generic.all
248 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
249 b04288f7 Stavros Sachtouris
    @errors.cyclades.date
250 b04288f7 Stavros Sachtouris
    def _run(self):
251 89ea97e1 Stavros Sachtouris
        withimage = bool(self['image_id'])
252 89ea97e1 Stavros Sachtouris
        withflavor = bool(self['flavor_id'])
253 89ea97e1 Stavros Sachtouris
        withmeta = bool(self['meta'] or self['meta_like'])
254 d8ff7b56 Stavros Sachtouris
        withcommons = bool(
255 d8ff7b56 Stavros Sachtouris
            self['status'] or self['user_id'] or self['user_name'])
256 d8ff7b56 Stavros Sachtouris
        detail = self['detail'] or (
257 d8ff7b56 Stavros Sachtouris
            withimage or withflavor or withmeta or withcommons)
258 89ea97e1 Stavros Sachtouris
        servers = self.client.list_servers(detail, self['since'])
259 89ea97e1 Stavros Sachtouris
260 6d190dd1 Stavros Sachtouris
        servers = self._filter_by_name(servers)
261 6d190dd1 Stavros Sachtouris
        servers = self._filter_by_id(servers)
262 d8ff7b56 Stavros Sachtouris
        servers = self._apply_common_filters(servers)
263 89ea97e1 Stavros Sachtouris
        if withimage:
264 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_image(servers)
265 89ea97e1 Stavros Sachtouris
        if withflavor:
266 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_flavor(servers)
267 89ea97e1 Stavros Sachtouris
        if withmeta:
268 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_metadata(servers)
269 89ea97e1 Stavros Sachtouris
270 c75be81a Stavros Sachtouris
        if detail and self['detail']:
271 bbd98565 Stavros Sachtouris
            #  servers = [self._restruct_server_info(vm) for vm in servers]
272 bbd98565 Stavros Sachtouris
            pass
273 c75be81a Stavros Sachtouris
        else:
274 89ea97e1 Stavros Sachtouris
            for srv in servers:
275 89ea97e1 Stavros Sachtouris
                for key in set(srv).difference(self.PERMANENTS):
276 89ea97e1 Stavros Sachtouris
                    srv.pop(key)
277 c75be81a Stavros Sachtouris
278 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
279 a4d0d88a Stavros Sachtouris
        if self['more']:
280 c75be81a Stavros Sachtouris
            codecinfo = codecs.lookup('utf-8')
281 c75be81a Stavros Sachtouris
            kwargs['out'] = codecs.StreamReaderWriter(
282 c75be81a Stavros Sachtouris
                cStringIO.StringIO(),
283 c75be81a Stavros Sachtouris
                codecinfo.streamreader,
284 c75be81a Stavros Sachtouris
                codecinfo.streamwriter)
285 6430d3a0 Stavros Sachtouris
            kwargs['title'] = ()
286 6430d3a0 Stavros Sachtouris
        if self['limit']:
287 545c6c29 Stavros Sachtouris
            servers = servers[:self['limit']]
288 545c6c29 Stavros Sachtouris
        self._print(servers, **kwargs)
289 6430d3a0 Stavros Sachtouris
        if self['more']:
290 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
291 7493ccb6 Stavros Sachtouris
292 b04288f7 Stavros Sachtouris
    def main(self):
293 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
294 b04288f7 Stavros Sachtouris
        self._run()
295 b04288f7 Stavros Sachtouris
296 234954d1 Stavros Sachtouris
297 d486baec Stavros Sachtouris
@command(server_cmds)
298 545c6c29 Stavros Sachtouris
class server_info(_init_cyclades, _optional_json):
299 61c2c62d Stavros Sachtouris
    """Detailed information on a Virtual Machine"""
300 61c2c62d Stavros Sachtouris
301 61c2c62d Stavros Sachtouris
    arguments = dict(
302 c77131f4 Stavros Sachtouris
        nics=FlagArgument(
303 61c2c62d Stavros Sachtouris
            'Show only the network interfaces of this virtual server',
304 61c2c62d Stavros Sachtouris
            '--nics'),
305 b45834eb Stavros Sachtouris
        stats=FlagArgument('Get URLs for server statistics', '--stats'),
306 b45834eb Stavros Sachtouris
        diagnostics=FlagArgument('Diagnostic information', '--diagnostics')
307 61c2c62d Stavros Sachtouris
    )
308 7493ccb6 Stavros Sachtouris
309 b04288f7 Stavros Sachtouris
    @errors.generic.all
310 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
311 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
312 b04288f7 Stavros Sachtouris
    def _run(self, server_id):
313 c77131f4 Stavros Sachtouris
        if self['nics']:
314 c3d42104 Stavros Sachtouris
            self._print(
315 c3d42104 Stavros Sachtouris
                self.client.get_server_nics(server_id), self.print_dict)
316 61c2c62d Stavros Sachtouris
        elif self['stats']:
317 61c2c62d Stavros Sachtouris
            self._print(
318 61c2c62d Stavros Sachtouris
                self.client.get_server_stats(server_id), self.print_dict)
319 b45834eb Stavros Sachtouris
        elif self['diagnostics']:
320 b45834eb Stavros Sachtouris
            self._print(self.client.get_server_diagnostics(server_id))
321 61c2c62d Stavros Sachtouris
        else:
322 c3d42104 Stavros Sachtouris
            vm = self.client.get_server_details(server_id)
323 bbd98565 Stavros Sachtouris
            # self._print(self._restruct_server_info(vm), self.print_dict)
324 f5ffc398 Stavros Sachtouris
            self._print(vm, self.print_dict)
325 7493ccb6 Stavros Sachtouris
326 b04288f7 Stavros Sachtouris
    def main(self, server_id):
327 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
328 c3d42104 Stavros Sachtouris
        choose_one = ('nics', 'stats', 'diagnostics')
329 61c2c62d Stavros Sachtouris
        count = len([a for a in choose_one if self[a]])
330 61c2c62d Stavros Sachtouris
        if count > 1:
331 fac7d59d Dionysis Grigoropoulos
            raise CLIInvalidArgument('Invalid argument combination', details=[
332 61c2c62d Stavros Sachtouris
                'Arguments %s cannot be used simultaneously' % ', '.join(
333 61c2c62d Stavros Sachtouris
                    [self.arguments[a].lvalue for a in choose_one])])
334 b04288f7 Stavros Sachtouris
        self._run(server_id=server_id)
335 b04288f7 Stavros Sachtouris
336 234954d1 Stavros Sachtouris
337 57d622b6 Stavros Sachtouris
class PersonalityArgument(KeyValueArgument):
338 0fccd79b Stavros Sachtouris
339 0fccd79b Stavros Sachtouris
    terms = (
340 0fccd79b Stavros Sachtouris
        ('local-path', 'contents'),
341 0fccd79b Stavros Sachtouris
        ('server-path', 'path'),
342 0fccd79b Stavros Sachtouris
        ('owner', 'owner'),
343 0fccd79b Stavros Sachtouris
        ('group', 'group'),
344 0fccd79b Stavros Sachtouris
        ('mode', 'mode'))
345 0fccd79b Stavros Sachtouris
346 234954d1 Stavros Sachtouris
    @property
347 f3e94e06 Stavros Sachtouris
    def value(self):
348 6c068db6 Stavros Sachtouris
        return getattr(self, '_value', [])
349 234954d1 Stavros Sachtouris
350 234954d1 Stavros Sachtouris
    @value.setter
351 f3e94e06 Stavros Sachtouris
    def value(self, newvalue):
352 f3e94e06 Stavros Sachtouris
        if newvalue == self.default:
353 f3e94e06 Stavros Sachtouris
            return self.value
354 0fccd79b Stavros Sachtouris
        self._value, input_dict = [], {}
355 57d622b6 Stavros Sachtouris
        for i, terms in enumerate(newvalue):
356 57d622b6 Stavros Sachtouris
            termlist = terms.split(',')
357 0fccd79b Stavros Sachtouris
            if len(termlist) > len(self.terms):
358 0fccd79b Stavros Sachtouris
                msg = 'Wrong number of terms (1<=terms<=%s)' % len(self.terms)
359 de73876b Stavros Sachtouris
                raiseCLIError(CLISyntaxError(msg), details=howto_personality)
360 0fccd79b Stavros Sachtouris
361 0fccd79b Stavros Sachtouris
            for k, v in self.terms:
362 0fccd79b Stavros Sachtouris
                prefix = '%s=' % k
363 0fccd79b Stavros Sachtouris
                for item in termlist:
364 0fccd79b Stavros Sachtouris
                    if item.lower().startswith(prefix):
365 0fccd79b Stavros Sachtouris
                        input_dict[k] = item[len(k) + 1:]
366 0fccd79b Stavros Sachtouris
                        break
367 0fccd79b Stavros Sachtouris
                    item = None
368 0fccd79b Stavros Sachtouris
                if item:
369 0fccd79b Stavros Sachtouris
                    termlist.remove(item)
370 0fccd79b Stavros Sachtouris
371 0fccd79b Stavros Sachtouris
            try:
372 0fccd79b Stavros Sachtouris
                path = input_dict['local-path']
373 0fccd79b Stavros Sachtouris
            except KeyError:
374 0fccd79b Stavros Sachtouris
                path = termlist.pop(0)
375 0fccd79b Stavros Sachtouris
                if not path:
376 0fccd79b Stavros Sachtouris
                    raise CLIInvalidArgument(
377 0fccd79b Stavros Sachtouris
                        '--personality: No local path specified',
378 0fccd79b Stavros Sachtouris
                        details=howto_personality)
379 0fccd79b Stavros Sachtouris
380 57d622b6 Stavros Sachtouris
            if not exists(path):
381 0fccd79b Stavros Sachtouris
                raise CLIInvalidArgument(
382 8194b51b Stavros Sachtouris
                    '--personality: File %s does not exist' % path,
383 0fccd79b Stavros Sachtouris
                    details=howto_personality)
384 0fccd79b Stavros Sachtouris
385 57d622b6 Stavros Sachtouris
            self._value.append(dict(path=path))
386 d62cba24 Stavros Sachtouris
            with open(expanduser(path)) as f:
387 57d622b6 Stavros Sachtouris
                self._value[i]['contents'] = b64encode(f.read())
388 0fccd79b Stavros Sachtouris
            for k, v in self.terms[1:]:
389 0fccd79b Stavros Sachtouris
                try:
390 0fccd79b Stavros Sachtouris
                    self._value[i][v] = input_dict[k]
391 0fccd79b Stavros Sachtouris
                except KeyError:
392 0fccd79b Stavros Sachtouris
                    try:
393 0fccd79b Stavros Sachtouris
                        self._value[i][v] = termlist.pop(0)
394 0fccd79b Stavros Sachtouris
                    except IndexError:
395 0fccd79b Stavros Sachtouris
                        continue
396 d62cba24 Stavros Sachtouris
                if k in ('mode', ) and self._value[i][v]:
397 d62cba24 Stavros Sachtouris
                    try:
398 d62cba24 Stavros Sachtouris
                        self._value[i][v] = int(self._value[i][v], 8)
399 d62cba24 Stavros Sachtouris
                    except ValueError as ve:
400 d62cba24 Stavros Sachtouris
                        raise CLIInvalidArgument(
401 d62cba24 Stavros Sachtouris
                            'Personality mode must be in octal', details=[
402 d62cba24 Stavros Sachtouris
                                '%s' % ve])
403 f3e94e06 Stavros Sachtouris
404 234954d1 Stavros Sachtouris
405 0bf38f8c Stavros Sachtouris
class NetworkArgument(RepeatableArgument):
406 0bf38f8c Stavros Sachtouris
    """[id=]NETWORK_ID[,[ip=]IP]"""
407 264a13f7 Stavros Sachtouris
408 264a13f7 Stavros Sachtouris
    @property
409 264a13f7 Stavros Sachtouris
    def value(self):
410 0bf38f8c Stavros Sachtouris
        return getattr(self, '_value', self.default)
411 264a13f7 Stavros Sachtouris
412 264a13f7 Stavros Sachtouris
    @value.setter
413 264a13f7 Stavros Sachtouris
    def value(self, new_value):
414 0bf38f8c Stavros Sachtouris
        for v in new_value or []:
415 0bf38f8c Stavros Sachtouris
            part1, sep, part2 = v.partition(',')
416 0bf38f8c Stavros Sachtouris
            netid, ip = '', ''
417 0bf38f8c Stavros Sachtouris
            if part1.startswith('id='):
418 0bf38f8c Stavros Sachtouris
                netid = part1[len('id='):]
419 0bf38f8c Stavros Sachtouris
            elif part1.startswith('ip='):
420 0bf38f8c Stavros Sachtouris
                ip = part1[len('ip='):]
421 0bf38f8c Stavros Sachtouris
            else:
422 0bf38f8c Stavros Sachtouris
                netid = part1
423 0bf38f8c Stavros Sachtouris
            if part2:
424 0bf38f8c Stavros Sachtouris
                if (part2.startswith('id=') and netid) or (
425 0bf38f8c Stavros Sachtouris
                        part2.startswith('ip=') and ip):
426 0bf38f8c Stavros Sachtouris
                    raise CLIInvalidArgument(
427 0bf38f8c Stavros Sachtouris
                        'Invalid network argument %s' % v, details=[
428 0bf38f8c Stavros Sachtouris
                        'Valid format: [id=]NETWORK_ID[,[ip=]IP]'])
429 0bf38f8c Stavros Sachtouris
                if part2.startswith('id='):
430 0bf38f8c Stavros Sachtouris
                    netid = part2[len('id='):]
431 0bf38f8c Stavros Sachtouris
                elif part2.startswith('ip='):
432 0bf38f8c Stavros Sachtouris
                    ip = part2[len('ip='):]
433 0bf38f8c Stavros Sachtouris
                elif netid:
434 0bf38f8c Stavros Sachtouris
                    ip = part2
435 0bf38f8c Stavros Sachtouris
                else:
436 0bf38f8c Stavros Sachtouris
                    netid = part2
437 0bf38f8c Stavros Sachtouris
            if not netid:
438 264a13f7 Stavros Sachtouris
                raise CLIInvalidArgument(
439 0bf38f8c Stavros Sachtouris
                    'Invalid network argument %s' % v, details=[
440 0bf38f8c Stavros Sachtouris
                    'Valid format: [id=]NETWORK_ID[,[ip=]IP]'])
441 0bf38f8c Stavros Sachtouris
            self._value = getattr(self, '_value', [])
442 0bf38f8c Stavros Sachtouris
            self._value.append(dict(uuid=netid))
443 0bf38f8c Stavros Sachtouris
            if ip:
444 0bf38f8c Stavros Sachtouris
                self._value[-1]['fixed_ip'] = ip
445 264a13f7 Stavros Sachtouris
446 264a13f7 Stavros Sachtouris
447 d486baec Stavros Sachtouris
@command(server_cmds)
448 60c42f9f Stavros Sachtouris
class server_create(_init_cyclades, _optional_json, _server_wait):
449 56d84a4e Stavros Sachtouris
    """Create a server (aka Virtual Machine)"""
450 7493ccb6 Stavros Sachtouris
451 93914390 Stavros Sachtouris
    arguments = dict(
452 56d84a4e Stavros Sachtouris
        server_name=ValueArgument('The name of the new server', '--name'),
453 3e79d925 Stavros Sachtouris
        flavor_id=IntArgument('The ID of the flavor', '--flavor-id'),
454 3e79d925 Stavros Sachtouris
        image_id=ValueArgument('The ID of the image', '--image-id'),
455 93914390 Stavros Sachtouris
        personality=PersonalityArgument(
456 60c42f9f Stavros Sachtouris
            (80 * ' ').join(howto_personality), ('-p', '--personality')),
457 81c60832 Stavros Sachtouris
        wait=FlagArgument('Wait server to build', ('-w', '--wait')),
458 81c60832 Stavros Sachtouris
        cluster_size=IntArgument(
459 81c60832 Stavros Sachtouris
            'Create a cluster of servers of this size. In this case, the name'
460 81c60832 Stavros Sachtouris
            'parameter is the prefix of each server in the cluster (e.g.,'
461 81c60832 Stavros Sachtouris
            'srv1, srv2, etc.',
462 ec5d658f Stavros Sachtouris
            '--cluster-size'),
463 ec5d658f Stavros Sachtouris
        max_threads=IntArgument(
464 fcd0f53d Stavros Sachtouris
            'Max threads in cluster mode (default 1)', '--threads'),
465 0bf38f8c Stavros Sachtouris
        network_configuration=NetworkArgument(
466 0bf38f8c Stavros Sachtouris
            'Connect server to network: [id=]NETWORK_ID[,[ip=]IP]        . '
467 0bf38f8c Stavros Sachtouris
            'Use only NETWORK_ID for private networks.        . '
468 0bf38f8c Stavros Sachtouris
            'Use NETWORK_ID,[ip=]IP for networks with IP.        . '
469 0bf38f8c Stavros Sachtouris
            'Can be repeated, mutually exclussive with --no-network',
470 0bf38f8c Stavros Sachtouris
            '--network'),
471 0bf38f8c Stavros Sachtouris
        no_network=FlagArgument(
472 0bf38f8c Stavros Sachtouris
            'Do not create any network NICs on the server.        . '
473 0bf38f8c Stavros Sachtouris
            'Mutually exclusive to --network        . '
474 0bf38f8c Stavros Sachtouris
            'If neither --network or --no-network are used, the default '
475 58f4caba Stavros Sachtouris
            'network policy is applied. These policies are set on the cloud, '
476 58f4caba Stavros Sachtouris
            'so kamaki is oblivious to them',
477 ffe30114 Giorgos Korfiatis
            '--no-network'),
478 ffe30114 Giorgos Korfiatis
        project=ValueArgument('Assign the server to project', '--project'),
479 93914390 Stavros Sachtouris
    )
480 56d84a4e Stavros Sachtouris
    required = ('server_name', 'flavor_id', 'image_id')
481 f3e94e06 Stavros Sachtouris
482 81c60832 Stavros Sachtouris
    @errors.cyclades.cluster_size
483 ffe30114 Giorgos Korfiatis
    def _create_cluster(self, prefix, flavor_id, image_id, size, project=None):
484 0bf38f8c Stavros Sachtouris
        networks = self['network_configuration'] or (
485 58f4caba Stavros Sachtouris
            [] if self['no_network'] else None)
486 81c60832 Stavros Sachtouris
        servers = [dict(
487 6c068db6 Stavros Sachtouris
            name='%s%s' % (prefix, i if size > 1 else ''),
488 81c60832 Stavros Sachtouris
            flavor_id=flavor_id,
489 81c60832 Stavros Sachtouris
            image_id=image_id,
490 ffe30114 Giorgos Korfiatis
            project=project,
491 264a13f7 Stavros Sachtouris
            personality=self['personality'],
492 264a13f7 Stavros Sachtouris
            networks=networks) for i in range(1, 1 + size)]
493 81c60832 Stavros Sachtouris
        if size == 1:
494 81c60832 Stavros Sachtouris
            return [self.client.create_server(**servers[0])]
495 ec5d658f Stavros Sachtouris
        self.client.MAX_THREADS = int(self['max_threads'] or 1)
496 c2e8d493 Stavros Sachtouris
        try:
497 40ddc207 Stavros Sachtouris
            r = self.client.async_run(self.client.create_server, servers)
498 40ddc207 Stavros Sachtouris
            return r
499 c2e8d493 Stavros Sachtouris
        except Exception as e:
500 c2e8d493 Stavros Sachtouris
            if size == 1:
501 c2e8d493 Stavros Sachtouris
                raise e
502 c2e8d493 Stavros Sachtouris
            try:
503 c2e8d493 Stavros Sachtouris
                requested_names = [s['name'] for s in servers]
504 c2e8d493 Stavros Sachtouris
                spawned_servers = [dict(
505 c2e8d493 Stavros Sachtouris
                    name=s['name'],
506 c2e8d493 Stavros Sachtouris
                    id=s['id']) for s in self.client.list_servers() if (
507 c2e8d493 Stavros Sachtouris
                        s['name'] in requested_names)]
508 c2e8d493 Stavros Sachtouris
                self.error('Failed to build %s servers' % size)
509 40ddc207 Stavros Sachtouris
                self.error('Found %s matching servers:' % len(spawned_servers))
510 c2e8d493 Stavros Sachtouris
                self._print(spawned_servers, out=self._err)
511 c2e8d493 Stavros Sachtouris
                self.error('Check if any of these servers should be removed\n')
512 c2e8d493 Stavros Sachtouris
            except Exception as ne:
513 c2e8d493 Stavros Sachtouris
                self.error('Error (%s) while notifying about errors' % ne)
514 c2e8d493 Stavros Sachtouris
            finally:
515 c2e8d493 Stavros Sachtouris
                raise e
516 81c60832 Stavros Sachtouris
517 b04288f7 Stavros Sachtouris
    @errors.generic.all
518 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
519 b04288f7 Stavros Sachtouris
    @errors.plankton.id
520 b04288f7 Stavros Sachtouris
    @errors.cyclades.flavor_id
521 b04288f7 Stavros Sachtouris
    def _run(self, name, flavor_id, image_id):
522 81c60832 Stavros Sachtouris
        for r in self._create_cluster(
523 ffe30114 Giorgos Korfiatis
                name, flavor_id, image_id, size=self['cluster_size'] or 1,
524 ffe30114 Giorgos Korfiatis
                project=self['project']):
525 c2e8d493 Stavros Sachtouris
            if not r:
526 c2e8d493 Stavros Sachtouris
                self.error('Create %s: server response was %s' % (name, r))
527 c2e8d493 Stavros Sachtouris
                continue
528 bbd98565 Stavros Sachtouris
            #  self._print(self._restruct_server_info(r), self.print_dict)
529 bbd98565 Stavros Sachtouris
            self._print(r, self.print_dict)
530 81c60832 Stavros Sachtouris
            if self['wait']:
531 f4589233 Stavros Sachtouris
                self._wait(r['id'], r['status'] or 'BUILD')
532 40ddc207 Stavros Sachtouris
            self.writeln(' ')
533 b04288f7 Stavros Sachtouris
534 56d84a4e Stavros Sachtouris
    def main(self):
535 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
536 3e79d925 Stavros Sachtouris
        if self['no_network'] and self['network_configuration']:
537 0bf38f8c Stavros Sachtouris
            raise CLIInvalidArgument(
538 0bf38f8c Stavros Sachtouris
                'Invalid argument compination', importance=2, details=[
539 0bf38f8c Stavros Sachtouris
                'Arguments %s and %s are mutually exclusive' % (
540 0bf38f8c Stavros Sachtouris
                    self.arguments['no_network'].lvalue,
541 3e79d925 Stavros Sachtouris
                    self.arguments['network_configuration'].lvalue)])
542 56d84a4e Stavros Sachtouris
        self._run(
543 56d84a4e Stavros Sachtouris
            name=self['server_name'],
544 56d84a4e Stavros Sachtouris
            flavor_id=self['flavor_id'],
545 56d84a4e Stavros Sachtouris
            image_id=self['image_id'])
546 7493ccb6 Stavros Sachtouris
547 234954d1 Stavros Sachtouris
548 0b052394 Stavros Sachtouris
class FirewallProfileArgument(ValueArgument):
549 0b052394 Stavros Sachtouris
550 0b052394 Stavros Sachtouris
    profiles = ('DISABLED', 'ENABLED', 'PROTECTED')
551 0b052394 Stavros Sachtouris
552 0b052394 Stavros Sachtouris
    @property
553 0b052394 Stavros Sachtouris
    def value(self):
554 0b052394 Stavros Sachtouris
        return getattr(self, '_value', None)
555 0b052394 Stavros Sachtouris
556 0b052394 Stavros Sachtouris
    @value.setter
557 0b052394 Stavros Sachtouris
    def value(self, new_profile):
558 0b052394 Stavros Sachtouris
        if new_profile:
559 0b052394 Stavros Sachtouris
            new_profile = new_profile.upper()
560 0b052394 Stavros Sachtouris
            if new_profile in self.profiles:
561 0b052394 Stavros Sachtouris
                self._value = new_profile
562 0b052394 Stavros Sachtouris
            else:
563 0b052394 Stavros Sachtouris
                raise CLIInvalidArgument(
564 0b052394 Stavros Sachtouris
                    'Invalid firewall profile %s' % new_profile,
565 0b052394 Stavros Sachtouris
                    details=['Valid values: %s' % ', '.join(self.profiles)])
566 7493ccb6 Stavros Sachtouris
567 234954d1 Stavros Sachtouris
568 d486baec Stavros Sachtouris
@command(server_cmds)
569 56d84a4e Stavros Sachtouris
class server_modify(_init_cyclades, _optional_output_cmd):
570 56d84a4e Stavros Sachtouris
    """Modify attributes of a virtual server"""
571 56d84a4e Stavros Sachtouris
572 56d84a4e Stavros Sachtouris
    arguments = dict(
573 56d84a4e Stavros Sachtouris
        server_name=ValueArgument('The new name', '--name'),
574 d1130026 Stavros Sachtouris
        flavor_id=IntArgument('Resize (set another flavor)', '--flavor-id'),
575 0b052394 Stavros Sachtouris
        firewall_profile=FirewallProfileArgument(
576 0b052394 Stavros Sachtouris
            'Valid values: %s' % (', '.join(FirewallProfileArgument.profiles)),
577 0b052394 Stavros Sachtouris
            '--firewall'),
578 0b052394 Stavros Sachtouris
        metadata_to_set=KeyValueArgument(
579 0b052394 Stavros Sachtouris
            'Set metadata in key=value form (can be repeated)',
580 00b1248e Stavros Sachtouris
            '--metadata-set'),
581 0b052394 Stavros Sachtouris
        metadata_to_delete=RepeatableArgument(
582 c75be81a Stavros Sachtouris
            'Delete metadata by key (can be repeated)', '--metadata-del'),
583 c75be81a Stavros Sachtouris
        public_network_port_id=ValueArgument(
584 c75be81a Stavros Sachtouris
            'Connection to set new firewall (* for all)', '--port-id'),
585 56d84a4e Stavros Sachtouris
    )
586 0b052394 Stavros Sachtouris
    required = [
587 0b052394 Stavros Sachtouris
        'server_name', 'flavor_id', 'firewall_profile', 'metadata_to_set',
588 00b1248e Stavros Sachtouris
        'metadata_to_delete']
589 7493ccb6 Stavros Sachtouris
590 4c33b869 Stavros Sachtouris
    def _set_firewall_profile(self, server_id):
591 4c33b869 Stavros Sachtouris
        vm = self._restruct_server_info(
592 4c33b869 Stavros Sachtouris
            self.client.get_server_details(server_id))
593 4c33b869 Stavros Sachtouris
        ports = [p for p in vm['ports'] if 'firewallProfile' in p]
594 4c33b869 Stavros Sachtouris
        pick_port = self.arguments['public_network_port_id']
595 4c33b869 Stavros Sachtouris
        if pick_port.value:
596 4c33b869 Stavros Sachtouris
            ports = [p for p in ports if pick_port.value in (
597 4c33b869 Stavros Sachtouris
                '*', '%s' % p['id'])]
598 4c33b869 Stavros Sachtouris
        elif len(ports) > 1:
599 4c33b869 Stavros Sachtouris
            port_strings = ['Server %s ports to public networks:' % server_id]
600 4c33b869 Stavros Sachtouris
            for p in ports:
601 4c33b869 Stavros Sachtouris
                port_strings.append('  %s' % p['id'])
602 4c33b869 Stavros Sachtouris
                for k in ('network_id', 'ipv4', 'ipv6', 'firewallProfile'):
603 4c33b869 Stavros Sachtouris
                    v = p.get(k)
604 4c33b869 Stavros Sachtouris
                    if v:
605 4c33b869 Stavros Sachtouris
                        port_strings.append('\t%s: %s' % (k, v))
606 4c33b869 Stavros Sachtouris
            raiseCLIError(
607 4c33b869 Stavros Sachtouris
                'Multiple public connections on server %s' % (
608 4c33b869 Stavros Sachtouris
                    server_id), details=port_strings + [
609 4c33b869 Stavros Sachtouris
                        'To select one:',
610 4c33b869 Stavros Sachtouris
                        '  %s <port id>' % pick_port.lvalue,
611 4c33b869 Stavros Sachtouris
                        'To set all:',
612 4c33b869 Stavros Sachtouris
                        '  %s *' % pick_port.lvalue, ])
613 4c33b869 Stavros Sachtouris
        if not ports:
614 4c33b869 Stavros Sachtouris
            pp = pick_port.value
615 4c33b869 Stavros Sachtouris
            raiseCLIError(
616 4c33b869 Stavros Sachtouris
                'No *public* networks attached on server %s%s' % (
617 4c33b869 Stavros Sachtouris
                    server_id, ' through port %s' % pp if pp else ''),
618 4c33b869 Stavros Sachtouris
                details=[
619 4c33b869 Stavros Sachtouris
                    'To see all networks:',
620 4c33b869 Stavros Sachtouris
                    '  kamaki network list',
621 4c33b869 Stavros Sachtouris
                    'To connect to a network:',
622 4c33b869 Stavros Sachtouris
                    '  kamaki network connect <net id> --device-id %s' % (
623 4c33b869 Stavros Sachtouris
                        server_id)])
624 4c33b869 Stavros Sachtouris
        for port in ports:
625 4c33b869 Stavros Sachtouris
            self.error('Set port %s firewall to %s' % (
626 4c33b869 Stavros Sachtouris
                port['id'], self['firewall_profile']))
627 4c33b869 Stavros Sachtouris
            self.client.set_firewall_profile(
628 4c33b869 Stavros Sachtouris
                server_id=server_id,
629 4c33b869 Stavros Sachtouris
                profile=self['firewall_profile'],
630 4c33b869 Stavros Sachtouris
                port_id=port['id'])
631 4c33b869 Stavros Sachtouris
632 5a673575 Stavros Sachtouris
    @errors.generic.all
633 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
634 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
635 56d84a4e Stavros Sachtouris
    def _run(self, server_id):
636 109fc65a Stavros Sachtouris
        if self['server_name'] is not None:
637 56d84a4e Stavros Sachtouris
            self.client.update_server_name((server_id), self['server_name'])
638 56d84a4e Stavros Sachtouris
        if self['flavor_id']:
639 56d84a4e Stavros Sachtouris
            self.client.resize_server(server_id, self['flavor_id'])
640 0b052394 Stavros Sachtouris
        if self['firewall_profile']:
641 4c33b869 Stavros Sachtouris
            self._set_firewall_profile(server_id)
642 0b052394 Stavros Sachtouris
        if self['metadata_to_set']:
643 0b052394 Stavros Sachtouris
            self.client.update_server_metadata(
644 0b052394 Stavros Sachtouris
                server_id, **self['metadata_to_set'])
645 f084bdc8 Stavros Sachtouris
        for key in (self['metadata_to_delete'] or []):
646 0b052394 Stavros Sachtouris
            errors.cyclades.metadata(
647 0b052394 Stavros Sachtouris
                self.client.delete_server_metadata)(server_id, key=key)
648 56d84a4e Stavros Sachtouris
        if self['with_output']:
649 56d84a4e Stavros Sachtouris
            self._optional_output(self.client.get_server_details(server_id))
650 5a673575 Stavros Sachtouris
651 56d84a4e Stavros Sachtouris
    def main(self, server_id):
652 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
653 c75be81a Stavros Sachtouris
        pnpid = self.arguments['public_network_port_id']
654 c75be81a Stavros Sachtouris
        fp = self.arguments['firewall_profile']
655 c75be81a Stavros Sachtouris
        if pnpid.value and not fp.value:
656 c75be81a Stavros Sachtouris
            raise CLIInvalidArgument('Invalid argument compination', details=[
657 c75be81a Stavros Sachtouris
                'Argument %s should always be combined with %s' % (
658 c75be81a Stavros Sachtouris
                    pnpid.lvalue, fp.lvalue)])
659 56d84a4e Stavros Sachtouris
        self._run(server_id=server_id)
660 234954d1 Stavros Sachtouris
661 7493ccb6 Stavros Sachtouris
662 d486baec Stavros Sachtouris
@command(server_cmds)
663 ffe30114 Giorgos Korfiatis
class server_reassign(_init_cyclades, _optional_json):
664 ffe30114 Giorgos Korfiatis
    """Assign a VM to a different project
665 ffe30114 Giorgos Korfiatis
    """
666 ffe30114 Giorgos Korfiatis
667 ffe30114 Giorgos Korfiatis
    @errors.generic.all
668 ffe30114 Giorgos Korfiatis
    @errors.cyclades.connection
669 ffe30114 Giorgos Korfiatis
    @errors.cyclades.server_id
670 ffe30114 Giorgos Korfiatis
    def _run(self, server_id, project):
671 ffe30114 Giorgos Korfiatis
        self.client.reassign_server(server_id, project)
672 ffe30114 Giorgos Korfiatis
673 ffe30114 Giorgos Korfiatis
    def main(self, server_id, project):
674 ffe30114 Giorgos Korfiatis
        super(self.__class__, self)._run()
675 ffe30114 Giorgos Korfiatis
        self._run(server_id=server_id, project=project)
676 ffe30114 Giorgos Korfiatis
677 ffe30114 Giorgos Korfiatis
678 ffe30114 Giorgos Korfiatis
@command(server_cmds)
679 60c42f9f Stavros Sachtouris
class server_delete(_init_cyclades, _optional_output_cmd, _server_wait):
680 2bd23362 Stavros Sachtouris
    """Delete a virtual server"""
681 7493ccb6 Stavros Sachtouris
682 60c42f9f Stavros Sachtouris
    arguments = dict(
683 81c60832 Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait')),
684 81c60832 Stavros Sachtouris
        cluster=FlagArgument(
685 81c60832 Stavros Sachtouris
            '(DANGEROUS) Delete all virtual servers prefixed with the cluster '
686 81c60832 Stavros Sachtouris
            'prefix. In that case, the prefix replaces the server id',
687 81c60832 Stavros Sachtouris
            '--cluster')
688 60c42f9f Stavros Sachtouris
    )
689 60c42f9f Stavros Sachtouris
690 81c60832 Stavros Sachtouris
    def _server_ids(self, server_var):
691 81c60832 Stavros Sachtouris
        if self['cluster']:
692 81c60832 Stavros Sachtouris
            return [s['id'] for s in self.client.list_servers() if (
693 81c60832 Stavros Sachtouris
                s['name'].startswith(server_var))]
694 81c60832 Stavros Sachtouris
695 81c60832 Stavros Sachtouris
        @errors.cyclades.server_id
696 81c60832 Stavros Sachtouris
        def _check_server_id(self, server_id):
697 81c60832 Stavros Sachtouris
            return server_id
698 81c60832 Stavros Sachtouris
699 81c60832 Stavros Sachtouris
        return [_check_server_id(self, server_id=server_var), ]
700 81c60832 Stavros Sachtouris
701 5a673575 Stavros Sachtouris
    @errors.generic.all
702 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
703 81c60832 Stavros Sachtouris
    def _run(self, server_var):
704 81c60832 Stavros Sachtouris
        for server_id in self._server_ids(server_var):
705 60c42f9f Stavros Sachtouris
            if self['wait']:
706 60c42f9f Stavros Sachtouris
                details = self.client.get_server_details(server_id)
707 60c42f9f Stavros Sachtouris
                status = details['status']
708 60c42f9f Stavros Sachtouris
709 81c60832 Stavros Sachtouris
            r = self.client.delete_server(server_id)
710 60c42f9f Stavros Sachtouris
            self._optional_output(r)
711 60c42f9f Stavros Sachtouris
712 60c42f9f Stavros Sachtouris
            if self['wait']:
713 60c42f9f Stavros Sachtouris
                self._wait(server_id, status)
714 5a673575 Stavros Sachtouris
715 81c60832 Stavros Sachtouris
    def main(self, server_id_or_cluster_prefix):
716 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
717 81c60832 Stavros Sachtouris
        self._run(server_id_or_cluster_prefix)
718 234954d1 Stavros Sachtouris
719 7493ccb6 Stavros Sachtouris
720 d486baec Stavros Sachtouris
@command(server_cmds)
721 60c42f9f Stavros Sachtouris
class server_reboot(_init_cyclades, _optional_output_cmd, _server_wait):
722 2bd23362 Stavros Sachtouris
    """Reboot a virtual server"""
723 18edacfe Stavros Sachtouris
724 93914390 Stavros Sachtouris
    arguments = dict(
725 a1dc95ac Stavros Sachtouris
        hard=FlagArgument(
726 a1dc95ac Stavros Sachtouris
            'perform a hard reboot (deprecated)', ('-f', '--force')),
727 a1dc95ac Stavros Sachtouris
        type=ValueArgument('SOFT or HARD - default: SOFT', ('--type')),
728 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
729 93914390 Stavros Sachtouris
    )
730 7493ccb6 Stavros Sachtouris
731 5a673575 Stavros Sachtouris
    @errors.generic.all
732 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
733 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
734 5a673575 Stavros Sachtouris
    def _run(self, server_id):
735 a1dc95ac Stavros Sachtouris
        hard_reboot = self['hard']
736 a1dc95ac Stavros Sachtouris
        if hard_reboot:
737 a1dc95ac Stavros Sachtouris
            self.error(
738 a1dc95ac Stavros Sachtouris
                'WARNING: -f/--force will be deprecated in version 0.12\n'
739 a1dc95ac Stavros Sachtouris
                '\tIn the future, please use --type=hard instead')
740 a1dc95ac Stavros Sachtouris
        if self['type']:
741 a1dc95ac Stavros Sachtouris
            if self['type'].lower() in ('soft', ):
742 a1dc95ac Stavros Sachtouris
                hard_reboot = False
743 a1dc95ac Stavros Sachtouris
            elif self['type'].lower() in ('hard', ):
744 a1dc95ac Stavros Sachtouris
                hard_reboot = True
745 a1dc95ac Stavros Sachtouris
            else:
746 a1dc95ac Stavros Sachtouris
                raise CLISyntaxError(
747 a1dc95ac Stavros Sachtouris
                    'Invalid reboot type %s' % self['type'],
748 a1dc95ac Stavros Sachtouris
                    importance=2, details=[
749 a1dc95ac Stavros Sachtouris
                        '--type values are either SOFT (default) or HARD'])
750 a1dc95ac Stavros Sachtouris
751 a1dc95ac Stavros Sachtouris
        r = self.client.reboot_server(int(server_id), hard_reboot)
752 60c42f9f Stavros Sachtouris
        self._optional_output(r)
753 60c42f9f Stavros Sachtouris
754 60c42f9f Stavros Sachtouris
        if self['wait']:
755 60c42f9f Stavros Sachtouris
            self._wait(server_id, 'REBOOT')
756 5a673575 Stavros Sachtouris
757 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
758 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
759 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
760 234954d1 Stavros Sachtouris
761 7493ccb6 Stavros Sachtouris
762 d486baec Stavros Sachtouris
@command(server_cmds)
763 60c42f9f Stavros Sachtouris
class server_start(_init_cyclades, _optional_output_cmd, _server_wait):
764 2bd23362 Stavros Sachtouris
    """Start an existing virtual server"""
765 7493ccb6 Stavros Sachtouris
766 60c42f9f Stavros Sachtouris
    arguments = dict(
767 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
768 60c42f9f Stavros Sachtouris
    )
769 60c42f9f Stavros Sachtouris
770 5a673575 Stavros Sachtouris
    @errors.generic.all
771 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
772 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
773 5a673575 Stavros Sachtouris
    def _run(self, server_id):
774 60c42f9f Stavros Sachtouris
        status = 'ACTIVE'
775 60c42f9f Stavros Sachtouris
        if self['wait']:
776 60c42f9f Stavros Sachtouris
            details = self.client.get_server_details(server_id)
777 60c42f9f Stavros Sachtouris
            status = details['status']
778 60c42f9f Stavros Sachtouris
            if status in ('ACTIVE', ):
779 60c42f9f Stavros Sachtouris
                return
780 60c42f9f Stavros Sachtouris
781 60c42f9f Stavros Sachtouris
        r = self.client.start_server(int(server_id))
782 60c42f9f Stavros Sachtouris
        self._optional_output(r)
783 60c42f9f Stavros Sachtouris
784 60c42f9f Stavros Sachtouris
        if self['wait']:
785 60c42f9f Stavros Sachtouris
            self._wait(server_id, status)
786 5a673575 Stavros Sachtouris
787 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
788 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
789 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
790 234954d1 Stavros Sachtouris
791 7493ccb6 Stavros Sachtouris
792 d486baec Stavros Sachtouris
@command(server_cmds)
793 60c42f9f Stavros Sachtouris
class server_shutdown(_init_cyclades, _optional_output_cmd, _server_wait):
794 2bd23362 Stavros Sachtouris
    """Shutdown an active virtual server"""
795 7493ccb6 Stavros Sachtouris
796 60c42f9f Stavros Sachtouris
    arguments = dict(
797 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
798 60c42f9f Stavros Sachtouris
    )
799 60c42f9f Stavros Sachtouris
800 5a673575 Stavros Sachtouris
    @errors.generic.all
801 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
802 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
803 5a673575 Stavros Sachtouris
    def _run(self, server_id):
804 60c42f9f Stavros Sachtouris
        status = 'STOPPED'
805 60c42f9f Stavros Sachtouris
        if self['wait']:
806 60c42f9f Stavros Sachtouris
            details = self.client.get_server_details(server_id)
807 60c42f9f Stavros Sachtouris
            status = details['status']
808 60c42f9f Stavros Sachtouris
            if status in ('STOPPED', ):
809 60c42f9f Stavros Sachtouris
                return
810 60c42f9f Stavros Sachtouris
811 60c42f9f Stavros Sachtouris
        r = self.client.shutdown_server(int(server_id))
812 60c42f9f Stavros Sachtouris
        self._optional_output(r)
813 60c42f9f Stavros Sachtouris
814 60c42f9f Stavros Sachtouris
        if self['wait']:
815 60c42f9f Stavros Sachtouris
            self._wait(server_id, status)
816 5a673575 Stavros Sachtouris
817 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
818 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
819 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
820 234954d1 Stavros Sachtouris
821 7493ccb6 Stavros Sachtouris
822 d486baec Stavros Sachtouris
@command(server_cmds)
823 61c2c62d Stavros Sachtouris
class server_console(_init_cyclades, _optional_json):
824 edd4eacc Stavros Sachtouris
    """Create a VMC console and show connection information"""
825 7493ccb6 Stavros Sachtouris
826 edd4eacc Stavros Sachtouris
    @errors.generic.all
827 edd4eacc Stavros Sachtouris
    @errors.cyclades.connection
828 edd4eacc Stavros Sachtouris
    @errors.cyclades.server_id
829 edd4eacc Stavros Sachtouris
    def _run(self, server_id):
830 edd4eacc Stavros Sachtouris
        self.error('The following credentials will be invalidated shortly')
831 edd4eacc Stavros Sachtouris
        self._print(
832 edd4eacc Stavros Sachtouris
            self.client.get_server_console(server_id), self.print_dict)
833 edd4eacc Stavros Sachtouris
834 edd4eacc Stavros Sachtouris
    def main(self, server_id):
835 edd4eacc Stavros Sachtouris
        super(self.__class__, self)._run()
836 edd4eacc Stavros Sachtouris
        self._run(server_id=server_id)
837 5a673575 Stavros Sachtouris
838 234954d1 Stavros Sachtouris
839 d486baec Stavros Sachtouris
@command(server_cmds)
840 60c42f9f Stavros Sachtouris
class server_wait(_init_cyclades, _server_wait):
841 c3d42104 Stavros Sachtouris
    """Wait for server to change its status (default: BUILD)"""
842 fd1f1d96 Stavros Sachtouris
843 8547cd19 Stavros Sachtouris
    arguments = dict(
844 8547cd19 Stavros Sachtouris
        timeout=IntArgument(
845 c3d42104 Stavros Sachtouris
            'Wait limit in seconds (default: 60)', '--timeout', default=60),
846 c3d42104 Stavros Sachtouris
        server_status=StatusArgument(
847 c3d42104 Stavros Sachtouris
            'Status to wait for (%s, default: %s)' % (
848 c3d42104 Stavros Sachtouris
                ', '.join(server_states), server_states[0]),
849 c3d42104 Stavros Sachtouris
            '--status',
850 c3d42104 Stavros Sachtouris
            valid_states=server_states)
851 8547cd19 Stavros Sachtouris
    )
852 8547cd19 Stavros Sachtouris
853 5a673575 Stavros Sachtouris
    @errors.generic.all
854 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
855 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
856 e9c73313 Stavros Sachtouris
    def _run(self, server_id, current_status):
857 e9c73313 Stavros Sachtouris
        r = self.client.get_server_details(server_id)
858 e9c73313 Stavros Sachtouris
        if r['status'].lower() == current_status.lower():
859 8547cd19 Stavros Sachtouris
            self._wait(server_id, current_status, timeout=self['timeout'])
860 e9c73313 Stavros Sachtouris
        else:
861 e9c73313 Stavros Sachtouris
            self.error(
862 e9c73313 Stavros Sachtouris
                'Server %s: Cannot wait for status %s, '
863 e9c73313 Stavros Sachtouris
                'status is already %s' % (
864 e9c73313 Stavros Sachtouris
                    server_id, current_status, r['status']))
865 fd1f1d96 Stavros Sachtouris
866 c3d42104 Stavros Sachtouris
    def main(self, server_id):
867 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
868 22663c4a Stavros Sachtouris
        self._run(
869 cf862450 Stavros Sachtouris
            server_id=server_id,
870 cf862450 Stavros Sachtouris
            current_status=self['server_status'] or 'BUILD')
871 5a673575 Stavros Sachtouris
872 fd1f1d96 Stavros Sachtouris
873 d486baec Stavros Sachtouris
@command(flavor_cmds)
874 6d190dd1 Stavros Sachtouris
class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
875 bd40efdf Stavros Sachtouris
    """List available hardware flavors"""
876 7493ccb6 Stavros Sachtouris
877 d8ff7b56 Stavros Sachtouris
    PERMANENTS = ('id', 'name')
878 d8ff7b56 Stavros Sachtouris
879 93914390 Stavros Sachtouris
    arguments = dict(
880 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
881 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit # of listed flavors', ('-n', '--number')),
882 bd40efdf Stavros Sachtouris
        more=FlagArgument(
883 de73876b Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
884 ed9af02c Stavros Sachtouris
            '--more'),
885 d8ff7b56 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
886 d8ff7b56 Stavros Sachtouris
        ram=ValueArgument('filter by ram', ('--ram')),
887 d8ff7b56 Stavros Sachtouris
        vcpus=ValueArgument('filter by number of VCPUs', ('--vcpus')),
888 d8ff7b56 Stavros Sachtouris
        disk=ValueArgument('filter by disk size in GB', ('--disk')),
889 d8ff7b56 Stavros Sachtouris
        disk_template=ValueArgument(
890 d8ff7b56 Stavros Sachtouris
            'filter by disk_templace', ('--disk-template'))
891 93914390 Stavros Sachtouris
    )
892 7493ccb6 Stavros Sachtouris
893 d8ff7b56 Stavros Sachtouris
    def _apply_common_filters(self, flavors):
894 d8ff7b56 Stavros Sachtouris
        common_filters = dict()
895 d8ff7b56 Stavros Sachtouris
        if self['ram']:
896 d8ff7b56 Stavros Sachtouris
            common_filters['ram'] = self['ram']
897 d8ff7b56 Stavros Sachtouris
        if self['vcpus']:
898 d8ff7b56 Stavros Sachtouris
            common_filters['vcpus'] = self['vcpus']
899 d8ff7b56 Stavros Sachtouris
        if self['disk']:
900 d8ff7b56 Stavros Sachtouris
            common_filters['disk'] = self['disk']
901 d8ff7b56 Stavros Sachtouris
        if self['disk_template']:
902 d8ff7b56 Stavros Sachtouris
            common_filters['SNF:disk_template'] = self['disk_template']
903 d8ff7b56 Stavros Sachtouris
        return filter_dicts_by_dict(flavors, common_filters)
904 d8ff7b56 Stavros Sachtouris
905 5a673575 Stavros Sachtouris
    @errors.generic.all
906 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
907 5a673575 Stavros Sachtouris
    def _run(self):
908 d8ff7b56 Stavros Sachtouris
        withcommons = self['ram'] or self['vcpus'] or (
909 d8ff7b56 Stavros Sachtouris
            self['disk'] or self['disk_template'])
910 d8ff7b56 Stavros Sachtouris
        detail = self['detail'] or withcommons
911 d8ff7b56 Stavros Sachtouris
        flavors = self.client.list_flavors(detail)
912 6d190dd1 Stavros Sachtouris
        flavors = self._filter_by_name(flavors)
913 6d190dd1 Stavros Sachtouris
        flavors = self._filter_by_id(flavors)
914 d8ff7b56 Stavros Sachtouris
        if withcommons:
915 d8ff7b56 Stavros Sachtouris
            flavors = self._apply_common_filters(flavors)
916 f76c6bbc Stavros Sachtouris
        if not (self['detail'] or (
917 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format'])):
918 7ba195e5 Stavros Sachtouris
            remove_from_items(flavors, 'links')
919 d8ff7b56 Stavros Sachtouris
        if detail and not self['detail']:
920 d8ff7b56 Stavros Sachtouris
            for flv in flavors:
921 d8ff7b56 Stavros Sachtouris
                for key in set(flv).difference(self.PERMANENTS):
922 d8ff7b56 Stavros Sachtouris
                    flv.pop(key)
923 6430d3a0 Stavros Sachtouris
        kwargs = dict(out=StringIO(), title=()) if self['more'] else {}
924 545c6c29 Stavros Sachtouris
        self._print(
925 ed9af02c Stavros Sachtouris
            flavors,
926 6430d3a0 Stavros Sachtouris
            with_redundancy=self['detail'], with_enumeration=self['enum'],
927 6430d3a0 Stavros Sachtouris
            **kwargs)
928 6430d3a0 Stavros Sachtouris
        if self['more']:
929 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
930 5a673575 Stavros Sachtouris
931 7493ccb6 Stavros Sachtouris
    def main(self):
932 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
933 5a673575 Stavros Sachtouris
        self._run()
934 7493ccb6 Stavros Sachtouris
935 234954d1 Stavros Sachtouris
936 d486baec Stavros Sachtouris
@command(flavor_cmds)
937 545c6c29 Stavros Sachtouris
class flavor_info(_init_cyclades, _optional_json):
938 769dbf53 Stavros Sachtouris
    """Detailed information on a hardware flavor
939 ddc0b290 Stavros Sachtouris
    To get a list of available flavors and flavor ids, try /flavor list
940 ddc0b290 Stavros Sachtouris
    """
941 7493ccb6 Stavros Sachtouris
942 5a673575 Stavros Sachtouris
    @errors.generic.all
943 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
944 5a673575 Stavros Sachtouris
    @errors.cyclades.flavor_id
945 5a673575 Stavros Sachtouris
    def _run(self, flavor_id):
946 bcef3ac9 Stavros Sachtouris
        self._print(
947 76f58e2e Stavros Sachtouris
            self.client.get_flavor_details(int(flavor_id)), self.print_dict)
948 7493ccb6 Stavros Sachtouris
949 5a673575 Stavros Sachtouris
    def main(self, flavor_id):
950 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
951 5a673575 Stavros Sachtouris
        self._run(flavor_id=flavor_id)
952 5a673575 Stavros Sachtouris
953 234954d1 Stavros Sachtouris
954 cf115aed Stavros Sachtouris
def _add_name(self, net):
955 cf115aed Stavros Sachtouris
        user_id, tenant_id, uuids = net['user_id'], net['tenant_id'], []
956 cf115aed Stavros Sachtouris
        if user_id:
957 cf115aed Stavros Sachtouris
            uuids.append(user_id)
958 cf115aed Stavros Sachtouris
        if tenant_id:
959 cf115aed Stavros Sachtouris
            uuids.append(tenant_id)
960 cf115aed Stavros Sachtouris
        if uuids:
961 cf115aed Stavros Sachtouris
            usernames = self._uuids2usernames(uuids)
962 cf115aed Stavros Sachtouris
            if user_id:
963 cf115aed Stavros Sachtouris
                net['user_id'] += ' (%s)' % usernames[user_id]
964 cf115aed Stavros Sachtouris
            if tenant_id:
965 cf115aed Stavros Sachtouris
                net['tenant_id'] += ' (%s)' % usernames[tenant_id]