Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (35.8 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 11925d1d Giorgos Korfiatis
                    [srv['user_id'] for srv in servers])))
208 f00db940 Stavros Sachtouris
        for srv in servers:
209 f00db940 Stavros Sachtouris
            srv['user_id'] += ' (%s)' % uuids[srv['user_id']]
210 f00db940 Stavros Sachtouris
        return servers
211 f00db940 Stavros Sachtouris
212 d8ff7b56 Stavros Sachtouris
    def _apply_common_filters(self, servers):
213 d8ff7b56 Stavros Sachtouris
        common_filters = dict()
214 d8ff7b56 Stavros Sachtouris
        if self['status']:
215 d8ff7b56 Stavros Sachtouris
            common_filters['status'] = self['status']
216 d8ff7b56 Stavros Sachtouris
        if self['user_id'] or self['user_name']:
217 d8ff7b56 Stavros Sachtouris
            uuid = self['user_id'] or self._username2uuid(self['user_name'])
218 d8ff7b56 Stavros Sachtouris
            common_filters['user_id'] = uuid
219 d8ff7b56 Stavros Sachtouris
        return filter_dicts_by_dict(servers, common_filters)
220 d8ff7b56 Stavros Sachtouris
221 6d190dd1 Stavros Sachtouris
    def _filter_by_image(self, servers):
222 89ea97e1 Stavros Sachtouris
        iid = self['image_id']
223 3185cd6d Stavros Sachtouris
        return [srv for srv in servers if srv['image']['id'] == iid]
224 89ea97e1 Stavros Sachtouris
225 6d190dd1 Stavros Sachtouris
    def _filter_by_flavor(self, servers):
226 89ea97e1 Stavros Sachtouris
        fid = self['flavor_id']
227 3185cd6d Stavros Sachtouris
        return [srv for srv in servers if (
228 3185cd6d Stavros Sachtouris
            '%s' % srv['image']['id'] == '%s' % fid)]
229 89ea97e1 Stavros Sachtouris
230 6d190dd1 Stavros Sachtouris
    def _filter_by_metadata(self, servers):
231 89ea97e1 Stavros Sachtouris
        new_servers = []
232 89ea97e1 Stavros Sachtouris
        for srv in servers:
233 89ea97e1 Stavros Sachtouris
            if not 'metadata' in srv:
234 89ea97e1 Stavros Sachtouris
                continue
235 89ea97e1 Stavros Sachtouris
            meta = [dict(srv['metadata'])]
236 89ea97e1 Stavros Sachtouris
            if self['meta']:
237 89ea97e1 Stavros Sachtouris
                meta = filter_dicts_by_dict(meta, self['meta'])
238 89ea97e1 Stavros Sachtouris
            if meta and self['meta_like']:
239 89ea97e1 Stavros Sachtouris
                meta = filter_dicts_by_dict(
240 89ea97e1 Stavros Sachtouris
                    meta, self['meta_like'], exact_match=False)
241 89ea97e1 Stavros Sachtouris
            if meta:
242 89ea97e1 Stavros Sachtouris
                new_servers.append(srv)
243 89ea97e1 Stavros Sachtouris
        return new_servers
244 89ea97e1 Stavros Sachtouris
245 b04288f7 Stavros Sachtouris
    @errors.generic.all
246 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
247 b04288f7 Stavros Sachtouris
    @errors.cyclades.date
248 b04288f7 Stavros Sachtouris
    def _run(self):
249 89ea97e1 Stavros Sachtouris
        withimage = bool(self['image_id'])
250 89ea97e1 Stavros Sachtouris
        withflavor = bool(self['flavor_id'])
251 89ea97e1 Stavros Sachtouris
        withmeta = bool(self['meta'] or self['meta_like'])
252 d8ff7b56 Stavros Sachtouris
        withcommons = bool(
253 d8ff7b56 Stavros Sachtouris
            self['status'] or self['user_id'] or self['user_name'])
254 d8ff7b56 Stavros Sachtouris
        detail = self['detail'] or (
255 d8ff7b56 Stavros Sachtouris
            withimage or withflavor or withmeta or withcommons)
256 89ea97e1 Stavros Sachtouris
        servers = self.client.list_servers(detail, self['since'])
257 89ea97e1 Stavros Sachtouris
258 6d190dd1 Stavros Sachtouris
        servers = self._filter_by_name(servers)
259 6d190dd1 Stavros Sachtouris
        servers = self._filter_by_id(servers)
260 d8ff7b56 Stavros Sachtouris
        servers = self._apply_common_filters(servers)
261 89ea97e1 Stavros Sachtouris
        if withimage:
262 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_image(servers)
263 89ea97e1 Stavros Sachtouris
        if withflavor:
264 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_flavor(servers)
265 89ea97e1 Stavros Sachtouris
        if withmeta:
266 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_metadata(servers)
267 89ea97e1 Stavros Sachtouris
268 c75be81a Stavros Sachtouris
        if detail and self['detail']:
269 bbd98565 Stavros Sachtouris
            #  servers = [self._restruct_server_info(vm) for vm in servers]
270 bbd98565 Stavros Sachtouris
            pass
271 c75be81a Stavros Sachtouris
        else:
272 89ea97e1 Stavros Sachtouris
            for srv in servers:
273 89ea97e1 Stavros Sachtouris
                for key in set(srv).difference(self.PERMANENTS):
274 89ea97e1 Stavros Sachtouris
                    srv.pop(key)
275 c75be81a Stavros Sachtouris
276 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
277 a4d0d88a Stavros Sachtouris
        if self['more']:
278 c75be81a Stavros Sachtouris
            codecinfo = codecs.lookup('utf-8')
279 c75be81a Stavros Sachtouris
            kwargs['out'] = codecs.StreamReaderWriter(
280 c75be81a Stavros Sachtouris
                cStringIO.StringIO(),
281 c75be81a Stavros Sachtouris
                codecinfo.streamreader,
282 c75be81a Stavros Sachtouris
                codecinfo.streamwriter)
283 6430d3a0 Stavros Sachtouris
            kwargs['title'] = ()
284 6430d3a0 Stavros Sachtouris
        if self['limit']:
285 545c6c29 Stavros Sachtouris
            servers = servers[:self['limit']]
286 545c6c29 Stavros Sachtouris
        self._print(servers, **kwargs)
287 6430d3a0 Stavros Sachtouris
        if self['more']:
288 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
289 7493ccb6 Stavros Sachtouris
290 b04288f7 Stavros Sachtouris
    def main(self):
291 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
292 b04288f7 Stavros Sachtouris
        self._run()
293 b04288f7 Stavros Sachtouris
294 234954d1 Stavros Sachtouris
295 d486baec Stavros Sachtouris
@command(server_cmds)
296 545c6c29 Stavros Sachtouris
class server_info(_init_cyclades, _optional_json):
297 61c2c62d Stavros Sachtouris
    """Detailed information on a Virtual Machine"""
298 61c2c62d Stavros Sachtouris
299 61c2c62d Stavros Sachtouris
    arguments = dict(
300 c77131f4 Stavros Sachtouris
        nics=FlagArgument(
301 61c2c62d Stavros Sachtouris
            'Show only the network interfaces of this virtual server',
302 61c2c62d Stavros Sachtouris
            '--nics'),
303 b45834eb Stavros Sachtouris
        stats=FlagArgument('Get URLs for server statistics', '--stats'),
304 b45834eb Stavros Sachtouris
        diagnostics=FlagArgument('Diagnostic information', '--diagnostics')
305 61c2c62d Stavros Sachtouris
    )
306 7493ccb6 Stavros Sachtouris
307 b04288f7 Stavros Sachtouris
    @errors.generic.all
308 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
309 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
310 b04288f7 Stavros Sachtouris
    def _run(self, server_id):
311 c77131f4 Stavros Sachtouris
        if self['nics']:
312 c3d42104 Stavros Sachtouris
            self._print(
313 c3d42104 Stavros Sachtouris
                self.client.get_server_nics(server_id), self.print_dict)
314 61c2c62d Stavros Sachtouris
        elif self['stats']:
315 61c2c62d Stavros Sachtouris
            self._print(
316 61c2c62d Stavros Sachtouris
                self.client.get_server_stats(server_id), self.print_dict)
317 b45834eb Stavros Sachtouris
        elif self['diagnostics']:
318 b45834eb Stavros Sachtouris
            self._print(self.client.get_server_diagnostics(server_id))
319 61c2c62d Stavros Sachtouris
        else:
320 c3d42104 Stavros Sachtouris
            vm = self.client.get_server_details(server_id)
321 bbd98565 Stavros Sachtouris
            # self._print(self._restruct_server_info(vm), self.print_dict)
322 f5ffc398 Stavros Sachtouris
            self._print(vm, self.print_dict)
323 7493ccb6 Stavros Sachtouris
324 b04288f7 Stavros Sachtouris
    def main(self, server_id):
325 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
326 c3d42104 Stavros Sachtouris
        choose_one = ('nics', 'stats', 'diagnostics')
327 61c2c62d Stavros Sachtouris
        count = len([a for a in choose_one if self[a]])
328 61c2c62d Stavros Sachtouris
        if count > 1:
329 fac7d59d Dionysis Grigoropoulos
            raise CLIInvalidArgument('Invalid argument combination', details=[
330 61c2c62d Stavros Sachtouris
                'Arguments %s cannot be used simultaneously' % ', '.join(
331 61c2c62d Stavros Sachtouris
                    [self.arguments[a].lvalue for a in choose_one])])
332 b04288f7 Stavros Sachtouris
        self._run(server_id=server_id)
333 b04288f7 Stavros Sachtouris
334 234954d1 Stavros Sachtouris
335 57d622b6 Stavros Sachtouris
class PersonalityArgument(KeyValueArgument):
336 0fccd79b Stavros Sachtouris
337 0fccd79b Stavros Sachtouris
    terms = (
338 0fccd79b Stavros Sachtouris
        ('local-path', 'contents'),
339 0fccd79b Stavros Sachtouris
        ('server-path', 'path'),
340 0fccd79b Stavros Sachtouris
        ('owner', 'owner'),
341 0fccd79b Stavros Sachtouris
        ('group', 'group'),
342 0fccd79b Stavros Sachtouris
        ('mode', 'mode'))
343 0fccd79b Stavros Sachtouris
344 234954d1 Stavros Sachtouris
    @property
345 f3e94e06 Stavros Sachtouris
    def value(self):
346 6c068db6 Stavros Sachtouris
        return getattr(self, '_value', [])
347 234954d1 Stavros Sachtouris
348 234954d1 Stavros Sachtouris
    @value.setter
349 f3e94e06 Stavros Sachtouris
    def value(self, newvalue):
350 f3e94e06 Stavros Sachtouris
        if newvalue == self.default:
351 f3e94e06 Stavros Sachtouris
            return self.value
352 0fccd79b Stavros Sachtouris
        self._value, input_dict = [], {}
353 57d622b6 Stavros Sachtouris
        for i, terms in enumerate(newvalue):
354 57d622b6 Stavros Sachtouris
            termlist = terms.split(',')
355 0fccd79b Stavros Sachtouris
            if len(termlist) > len(self.terms):
356 0fccd79b Stavros Sachtouris
                msg = 'Wrong number of terms (1<=terms<=%s)' % len(self.terms)
357 de73876b Stavros Sachtouris
                raiseCLIError(CLISyntaxError(msg), details=howto_personality)
358 0fccd79b Stavros Sachtouris
359 0fccd79b Stavros Sachtouris
            for k, v in self.terms:
360 0fccd79b Stavros Sachtouris
                prefix = '%s=' % k
361 0fccd79b Stavros Sachtouris
                for item in termlist:
362 0fccd79b Stavros Sachtouris
                    if item.lower().startswith(prefix):
363 0fccd79b Stavros Sachtouris
                        input_dict[k] = item[len(k) + 1:]
364 0fccd79b Stavros Sachtouris
                        break
365 0fccd79b Stavros Sachtouris
                    item = None
366 0fccd79b Stavros Sachtouris
                if item:
367 0fccd79b Stavros Sachtouris
                    termlist.remove(item)
368 0fccd79b Stavros Sachtouris
369 0fccd79b Stavros Sachtouris
            try:
370 0fccd79b Stavros Sachtouris
                path = input_dict['local-path']
371 0fccd79b Stavros Sachtouris
            except KeyError:
372 0fccd79b Stavros Sachtouris
                path = termlist.pop(0)
373 0fccd79b Stavros Sachtouris
                if not path:
374 0fccd79b Stavros Sachtouris
                    raise CLIInvalidArgument(
375 0fccd79b Stavros Sachtouris
                        '--personality: No local path specified',
376 0fccd79b Stavros Sachtouris
                        details=howto_personality)
377 0fccd79b Stavros Sachtouris
378 57d622b6 Stavros Sachtouris
            if not exists(path):
379 0fccd79b Stavros Sachtouris
                raise CLIInvalidArgument(
380 8194b51b Stavros Sachtouris
                    '--personality: File %s does not exist' % path,
381 0fccd79b Stavros Sachtouris
                    details=howto_personality)
382 0fccd79b Stavros Sachtouris
383 57d622b6 Stavros Sachtouris
            self._value.append(dict(path=path))
384 d62cba24 Stavros Sachtouris
            with open(expanduser(path)) as f:
385 57d622b6 Stavros Sachtouris
                self._value[i]['contents'] = b64encode(f.read())
386 0fccd79b Stavros Sachtouris
            for k, v in self.terms[1:]:
387 0fccd79b Stavros Sachtouris
                try:
388 0fccd79b Stavros Sachtouris
                    self._value[i][v] = input_dict[k]
389 0fccd79b Stavros Sachtouris
                except KeyError:
390 0fccd79b Stavros Sachtouris
                    try:
391 0fccd79b Stavros Sachtouris
                        self._value[i][v] = termlist.pop(0)
392 0fccd79b Stavros Sachtouris
                    except IndexError:
393 0fccd79b Stavros Sachtouris
                        continue
394 d62cba24 Stavros Sachtouris
                if k in ('mode', ) and self._value[i][v]:
395 d62cba24 Stavros Sachtouris
                    try:
396 d62cba24 Stavros Sachtouris
                        self._value[i][v] = int(self._value[i][v], 8)
397 d62cba24 Stavros Sachtouris
                    except ValueError as ve:
398 d62cba24 Stavros Sachtouris
                        raise CLIInvalidArgument(
399 d62cba24 Stavros Sachtouris
                            'Personality mode must be in octal', details=[
400 d62cba24 Stavros Sachtouris
                                '%s' % ve])
401 f3e94e06 Stavros Sachtouris
402 234954d1 Stavros Sachtouris
403 0bf38f8c Stavros Sachtouris
class NetworkArgument(RepeatableArgument):
404 0bf38f8c Stavros Sachtouris
    """[id=]NETWORK_ID[,[ip=]IP]"""
405 264a13f7 Stavros Sachtouris
406 264a13f7 Stavros Sachtouris
    @property
407 264a13f7 Stavros Sachtouris
    def value(self):
408 0bf38f8c Stavros Sachtouris
        return getattr(self, '_value', self.default)
409 264a13f7 Stavros Sachtouris
410 264a13f7 Stavros Sachtouris
    @value.setter
411 264a13f7 Stavros Sachtouris
    def value(self, new_value):
412 0bf38f8c Stavros Sachtouris
        for v in new_value or []:
413 0bf38f8c Stavros Sachtouris
            part1, sep, part2 = v.partition(',')
414 0bf38f8c Stavros Sachtouris
            netid, ip = '', ''
415 0bf38f8c Stavros Sachtouris
            if part1.startswith('id='):
416 0bf38f8c Stavros Sachtouris
                netid = part1[len('id='):]
417 0bf38f8c Stavros Sachtouris
            elif part1.startswith('ip='):
418 0bf38f8c Stavros Sachtouris
                ip = part1[len('ip='):]
419 0bf38f8c Stavros Sachtouris
            else:
420 0bf38f8c Stavros Sachtouris
                netid = part1
421 0bf38f8c Stavros Sachtouris
            if part2:
422 0bf38f8c Stavros Sachtouris
                if (part2.startswith('id=') and netid) or (
423 0bf38f8c Stavros Sachtouris
                        part2.startswith('ip=') and ip):
424 0bf38f8c Stavros Sachtouris
                    raise CLIInvalidArgument(
425 0bf38f8c Stavros Sachtouris
                        'Invalid network argument %s' % v, details=[
426 0bf38f8c Stavros Sachtouris
                        'Valid format: [id=]NETWORK_ID[,[ip=]IP]'])
427 0bf38f8c Stavros Sachtouris
                if part2.startswith('id='):
428 0bf38f8c Stavros Sachtouris
                    netid = part2[len('id='):]
429 0bf38f8c Stavros Sachtouris
                elif part2.startswith('ip='):
430 0bf38f8c Stavros Sachtouris
                    ip = part2[len('ip='):]
431 0bf38f8c Stavros Sachtouris
                elif netid:
432 0bf38f8c Stavros Sachtouris
                    ip = part2
433 0bf38f8c Stavros Sachtouris
                else:
434 0bf38f8c Stavros Sachtouris
                    netid = part2
435 0bf38f8c Stavros Sachtouris
            if not netid:
436 264a13f7 Stavros Sachtouris
                raise CLIInvalidArgument(
437 0bf38f8c Stavros Sachtouris
                    'Invalid network argument %s' % v, details=[
438 0bf38f8c Stavros Sachtouris
                    'Valid format: [id=]NETWORK_ID[,[ip=]IP]'])
439 0bf38f8c Stavros Sachtouris
            self._value = getattr(self, '_value', [])
440 0bf38f8c Stavros Sachtouris
            self._value.append(dict(uuid=netid))
441 0bf38f8c Stavros Sachtouris
            if ip:
442 0bf38f8c Stavros Sachtouris
                self._value[-1]['fixed_ip'] = ip
443 264a13f7 Stavros Sachtouris
444 264a13f7 Stavros Sachtouris
445 d486baec Stavros Sachtouris
@command(server_cmds)
446 60c42f9f Stavros Sachtouris
class server_create(_init_cyclades, _optional_json, _server_wait):
447 56d84a4e Stavros Sachtouris
    """Create a server (aka Virtual Machine)"""
448 7493ccb6 Stavros Sachtouris
449 93914390 Stavros Sachtouris
    arguments = dict(
450 56d84a4e Stavros Sachtouris
        server_name=ValueArgument('The name of the new server', '--name'),
451 3e79d925 Stavros Sachtouris
        flavor_id=IntArgument('The ID of the flavor', '--flavor-id'),
452 3e79d925 Stavros Sachtouris
        image_id=ValueArgument('The ID of the image', '--image-id'),
453 93914390 Stavros Sachtouris
        personality=PersonalityArgument(
454 60c42f9f Stavros Sachtouris
            (80 * ' ').join(howto_personality), ('-p', '--personality')),
455 81c60832 Stavros Sachtouris
        wait=FlagArgument('Wait server to build', ('-w', '--wait')),
456 81c60832 Stavros Sachtouris
        cluster_size=IntArgument(
457 81c60832 Stavros Sachtouris
            'Create a cluster of servers of this size. In this case, the name'
458 81c60832 Stavros Sachtouris
            'parameter is the prefix of each server in the cluster (e.g.,'
459 81c60832 Stavros Sachtouris
            'srv1, srv2, etc.',
460 ec5d658f Stavros Sachtouris
            '--cluster-size'),
461 ec5d658f Stavros Sachtouris
        max_threads=IntArgument(
462 fcd0f53d Stavros Sachtouris
            'Max threads in cluster mode (default 1)', '--threads'),
463 0bf38f8c Stavros Sachtouris
        network_configuration=NetworkArgument(
464 0bf38f8c Stavros Sachtouris
            'Connect server to network: [id=]NETWORK_ID[,[ip=]IP]        . '
465 0bf38f8c Stavros Sachtouris
            'Use only NETWORK_ID for private networks.        . '
466 0bf38f8c Stavros Sachtouris
            'Use NETWORK_ID,[ip=]IP for networks with IP.        . '
467 0bf38f8c Stavros Sachtouris
            'Can be repeated, mutually exclussive with --no-network',
468 0bf38f8c Stavros Sachtouris
            '--network'),
469 0bf38f8c Stavros Sachtouris
        no_network=FlagArgument(
470 0bf38f8c Stavros Sachtouris
            'Do not create any network NICs on the server.        . '
471 0bf38f8c Stavros Sachtouris
            'Mutually exclusive to --network        . '
472 0bf38f8c Stavros Sachtouris
            'If neither --network or --no-network are used, the default '
473 58f4caba Stavros Sachtouris
            'network policy is applied. These policies are set on the cloud, '
474 58f4caba Stavros Sachtouris
            'so kamaki is oblivious to them',
475 75ae8a08 Giorgos Korfiatis
            '--no-network'),
476 f1e45161 Stavros Sachtouris
        project_id=ValueArgument('Assign server to project', '--project-id'),
477 93914390 Stavros Sachtouris
    )
478 56d84a4e Stavros Sachtouris
    required = ('server_name', 'flavor_id', 'image_id')
479 f3e94e06 Stavros Sachtouris
480 81c60832 Stavros Sachtouris
    @errors.cyclades.cluster_size
481 75ae8a08 Giorgos Korfiatis
    def _create_cluster(self, prefix, flavor_id, image_id, size, project=None):
482 0bf38f8c Stavros Sachtouris
        networks = self['network_configuration'] or (
483 58f4caba Stavros Sachtouris
            [] if self['no_network'] else None)
484 81c60832 Stavros Sachtouris
        servers = [dict(
485 6c068db6 Stavros Sachtouris
            name='%s%s' % (prefix, i if size > 1 else ''),
486 81c60832 Stavros Sachtouris
            flavor_id=flavor_id,
487 81c60832 Stavros Sachtouris
            image_id=image_id,
488 75ae8a08 Giorgos Korfiatis
            project=project,
489 264a13f7 Stavros Sachtouris
            personality=self['personality'],
490 264a13f7 Stavros Sachtouris
            networks=networks) for i in range(1, 1 + size)]
491 81c60832 Stavros Sachtouris
        if size == 1:
492 81c60832 Stavros Sachtouris
            return [self.client.create_server(**servers[0])]
493 ec5d658f Stavros Sachtouris
        self.client.MAX_THREADS = int(self['max_threads'] or 1)
494 c2e8d493 Stavros Sachtouris
        try:
495 40ddc207 Stavros Sachtouris
            r = self.client.async_run(self.client.create_server, servers)
496 40ddc207 Stavros Sachtouris
            return r
497 c2e8d493 Stavros Sachtouris
        except Exception as e:
498 c2e8d493 Stavros Sachtouris
            if size == 1:
499 c2e8d493 Stavros Sachtouris
                raise e
500 c2e8d493 Stavros Sachtouris
            try:
501 c2e8d493 Stavros Sachtouris
                requested_names = [s['name'] for s in servers]
502 c2e8d493 Stavros Sachtouris
                spawned_servers = [dict(
503 c2e8d493 Stavros Sachtouris
                    name=s['name'],
504 c2e8d493 Stavros Sachtouris
                    id=s['id']) for s in self.client.list_servers() if (
505 c2e8d493 Stavros Sachtouris
                        s['name'] in requested_names)]
506 c2e8d493 Stavros Sachtouris
                self.error('Failed to build %s servers' % size)
507 40ddc207 Stavros Sachtouris
                self.error('Found %s matching servers:' % len(spawned_servers))
508 c2e8d493 Stavros Sachtouris
                self._print(spawned_servers, out=self._err)
509 c2e8d493 Stavros Sachtouris
                self.error('Check if any of these servers should be removed\n')
510 c2e8d493 Stavros Sachtouris
            except Exception as ne:
511 c2e8d493 Stavros Sachtouris
                self.error('Error (%s) while notifying about errors' % ne)
512 c2e8d493 Stavros Sachtouris
            finally:
513 c2e8d493 Stavros Sachtouris
                raise e
514 81c60832 Stavros Sachtouris
515 b04288f7 Stavros Sachtouris
    @errors.generic.all
516 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
517 b04288f7 Stavros Sachtouris
    @errors.plankton.id
518 b04288f7 Stavros Sachtouris
    @errors.cyclades.flavor_id
519 b04288f7 Stavros Sachtouris
    def _run(self, name, flavor_id, image_id):
520 81c60832 Stavros Sachtouris
        for r in self._create_cluster(
521 75ae8a08 Giorgos Korfiatis
                name, flavor_id, image_id, size=self['cluster_size'] or 1,
522 f1e45161 Stavros Sachtouris
                project=self['project_id']):
523 c2e8d493 Stavros Sachtouris
            if not r:
524 c2e8d493 Stavros Sachtouris
                self.error('Create %s: server response was %s' % (name, r))
525 c2e8d493 Stavros Sachtouris
                continue
526 bbd98565 Stavros Sachtouris
            #  self._print(self._restruct_server_info(r), self.print_dict)
527 bbd98565 Stavros Sachtouris
            self._print(r, self.print_dict)
528 81c60832 Stavros Sachtouris
            if self['wait']:
529 f4589233 Stavros Sachtouris
                self._wait(r['id'], r['status'] or 'BUILD')
530 40ddc207 Stavros Sachtouris
            self.writeln(' ')
531 b04288f7 Stavros Sachtouris
532 56d84a4e Stavros Sachtouris
    def main(self):
533 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
534 3e79d925 Stavros Sachtouris
        if self['no_network'] and self['network_configuration']:
535 0bf38f8c Stavros Sachtouris
            raise CLIInvalidArgument(
536 0bf38f8c Stavros Sachtouris
                'Invalid argument compination', importance=2, details=[
537 0bf38f8c Stavros Sachtouris
                'Arguments %s and %s are mutually exclusive' % (
538 0bf38f8c Stavros Sachtouris
                    self.arguments['no_network'].lvalue,
539 3e79d925 Stavros Sachtouris
                    self.arguments['network_configuration'].lvalue)])
540 56d84a4e Stavros Sachtouris
        self._run(
541 56d84a4e Stavros Sachtouris
            name=self['server_name'],
542 56d84a4e Stavros Sachtouris
            flavor_id=self['flavor_id'],
543 56d84a4e Stavros Sachtouris
            image_id=self['image_id'])
544 7493ccb6 Stavros Sachtouris
545 234954d1 Stavros Sachtouris
546 0b052394 Stavros Sachtouris
class FirewallProfileArgument(ValueArgument):
547 0b052394 Stavros Sachtouris
548 0b052394 Stavros Sachtouris
    profiles = ('DISABLED', 'ENABLED', 'PROTECTED')
549 0b052394 Stavros Sachtouris
550 0b052394 Stavros Sachtouris
    @property
551 0b052394 Stavros Sachtouris
    def value(self):
552 0b052394 Stavros Sachtouris
        return getattr(self, '_value', None)
553 0b052394 Stavros Sachtouris
554 0b052394 Stavros Sachtouris
    @value.setter
555 0b052394 Stavros Sachtouris
    def value(self, new_profile):
556 0b052394 Stavros Sachtouris
        if new_profile:
557 0b052394 Stavros Sachtouris
            new_profile = new_profile.upper()
558 0b052394 Stavros Sachtouris
            if new_profile in self.profiles:
559 0b052394 Stavros Sachtouris
                self._value = new_profile
560 0b052394 Stavros Sachtouris
            else:
561 0b052394 Stavros Sachtouris
                raise CLIInvalidArgument(
562 0b052394 Stavros Sachtouris
                    'Invalid firewall profile %s' % new_profile,
563 0b052394 Stavros Sachtouris
                    details=['Valid values: %s' % ', '.join(self.profiles)])
564 7493ccb6 Stavros Sachtouris
565 234954d1 Stavros Sachtouris
566 d486baec Stavros Sachtouris
@command(server_cmds)
567 56d84a4e Stavros Sachtouris
class server_modify(_init_cyclades, _optional_output_cmd):
568 56d84a4e Stavros Sachtouris
    """Modify attributes of a virtual server"""
569 56d84a4e Stavros Sachtouris
570 56d84a4e Stavros Sachtouris
    arguments = dict(
571 56d84a4e Stavros Sachtouris
        server_name=ValueArgument('The new name', '--name'),
572 d1130026 Stavros Sachtouris
        flavor_id=IntArgument('Resize (set another flavor)', '--flavor-id'),
573 0b052394 Stavros Sachtouris
        firewall_profile=FirewallProfileArgument(
574 0b052394 Stavros Sachtouris
            'Valid values: %s' % (', '.join(FirewallProfileArgument.profiles)),
575 0b052394 Stavros Sachtouris
            '--firewall'),
576 0b052394 Stavros Sachtouris
        metadata_to_set=KeyValueArgument(
577 0b052394 Stavros Sachtouris
            'Set metadata in key=value form (can be repeated)',
578 00b1248e Stavros Sachtouris
            '--metadata-set'),
579 0b052394 Stavros Sachtouris
        metadata_to_delete=RepeatableArgument(
580 c75be81a Stavros Sachtouris
            'Delete metadata by key (can be repeated)', '--metadata-del'),
581 c75be81a Stavros Sachtouris
        public_network_port_id=ValueArgument(
582 c75be81a Stavros Sachtouris
            'Connection to set new firewall (* for all)', '--port-id'),
583 56d84a4e Stavros Sachtouris
    )
584 0b052394 Stavros Sachtouris
    required = [
585 0b052394 Stavros Sachtouris
        'server_name', 'flavor_id', 'firewall_profile', 'metadata_to_set',
586 00b1248e Stavros Sachtouris
        'metadata_to_delete']
587 7493ccb6 Stavros Sachtouris
588 4c33b869 Stavros Sachtouris
    def _set_firewall_profile(self, server_id):
589 4c33b869 Stavros Sachtouris
        vm = self._restruct_server_info(
590 4c33b869 Stavros Sachtouris
            self.client.get_server_details(server_id))
591 4c33b869 Stavros Sachtouris
        ports = [p for p in vm['ports'] if 'firewallProfile' in p]
592 4c33b869 Stavros Sachtouris
        pick_port = self.arguments['public_network_port_id']
593 4c33b869 Stavros Sachtouris
        if pick_port.value:
594 4c33b869 Stavros Sachtouris
            ports = [p for p in ports if pick_port.value in (
595 4c33b869 Stavros Sachtouris
                '*', '%s' % p['id'])]
596 4c33b869 Stavros Sachtouris
        elif len(ports) > 1:
597 4c33b869 Stavros Sachtouris
            port_strings = ['Server %s ports to public networks:' % server_id]
598 4c33b869 Stavros Sachtouris
            for p in ports:
599 4c33b869 Stavros Sachtouris
                port_strings.append('  %s' % p['id'])
600 4c33b869 Stavros Sachtouris
                for k in ('network_id', 'ipv4', 'ipv6', 'firewallProfile'):
601 4c33b869 Stavros Sachtouris
                    v = p.get(k)
602 4c33b869 Stavros Sachtouris
                    if v:
603 4c33b869 Stavros Sachtouris
                        port_strings.append('\t%s: %s' % (k, v))
604 4c33b869 Stavros Sachtouris
            raiseCLIError(
605 4c33b869 Stavros Sachtouris
                'Multiple public connections on server %s' % (
606 4c33b869 Stavros Sachtouris
                    server_id), details=port_strings + [
607 4c33b869 Stavros Sachtouris
                        'To select one:',
608 4c33b869 Stavros Sachtouris
                        '  %s <port id>' % pick_port.lvalue,
609 4c33b869 Stavros Sachtouris
                        'To set all:',
610 4c33b869 Stavros Sachtouris
                        '  %s *' % pick_port.lvalue, ])
611 4c33b869 Stavros Sachtouris
        if not ports:
612 4c33b869 Stavros Sachtouris
            pp = pick_port.value
613 4c33b869 Stavros Sachtouris
            raiseCLIError(
614 4c33b869 Stavros Sachtouris
                'No *public* networks attached on server %s%s' % (
615 4c33b869 Stavros Sachtouris
                    server_id, ' through port %s' % pp if pp else ''),
616 4c33b869 Stavros Sachtouris
                details=[
617 4c33b869 Stavros Sachtouris
                    'To see all networks:',
618 4c33b869 Stavros Sachtouris
                    '  kamaki network list',
619 4c33b869 Stavros Sachtouris
                    'To connect to a network:',
620 4c33b869 Stavros Sachtouris
                    '  kamaki network connect <net id> --device-id %s' % (
621 4c33b869 Stavros Sachtouris
                        server_id)])
622 4c33b869 Stavros Sachtouris
        for port in ports:
623 4c33b869 Stavros Sachtouris
            self.error('Set port %s firewall to %s' % (
624 4c33b869 Stavros Sachtouris
                port['id'], self['firewall_profile']))
625 4c33b869 Stavros Sachtouris
            self.client.set_firewall_profile(
626 4c33b869 Stavros Sachtouris
                server_id=server_id,
627 4c33b869 Stavros Sachtouris
                profile=self['firewall_profile'],
628 4c33b869 Stavros Sachtouris
                port_id=port['id'])
629 4c33b869 Stavros Sachtouris
630 5a673575 Stavros Sachtouris
    @errors.generic.all
631 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
632 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
633 56d84a4e Stavros Sachtouris
    def _run(self, server_id):
634 109fc65a Stavros Sachtouris
        if self['server_name'] is not None:
635 56d84a4e Stavros Sachtouris
            self.client.update_server_name((server_id), self['server_name'])
636 56d84a4e Stavros Sachtouris
        if self['flavor_id']:
637 56d84a4e Stavros Sachtouris
            self.client.resize_server(server_id, self['flavor_id'])
638 0b052394 Stavros Sachtouris
        if self['firewall_profile']:
639 4c33b869 Stavros Sachtouris
            self._set_firewall_profile(server_id)
640 0b052394 Stavros Sachtouris
        if self['metadata_to_set']:
641 0b052394 Stavros Sachtouris
            self.client.update_server_metadata(
642 0b052394 Stavros Sachtouris
                server_id, **self['metadata_to_set'])
643 f084bdc8 Stavros Sachtouris
        for key in (self['metadata_to_delete'] or []):
644 0b052394 Stavros Sachtouris
            errors.cyclades.metadata(
645 0b052394 Stavros Sachtouris
                self.client.delete_server_metadata)(server_id, key=key)
646 56d84a4e Stavros Sachtouris
        if self['with_output']:
647 56d84a4e Stavros Sachtouris
            self._optional_output(self.client.get_server_details(server_id))
648 5a673575 Stavros Sachtouris
649 56d84a4e Stavros Sachtouris
    def main(self, server_id):
650 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
651 c75be81a Stavros Sachtouris
        pnpid = self.arguments['public_network_port_id']
652 c75be81a Stavros Sachtouris
        fp = self.arguments['firewall_profile']
653 c75be81a Stavros Sachtouris
        if pnpid.value and not fp.value:
654 c75be81a Stavros Sachtouris
            raise CLIInvalidArgument('Invalid argument compination', details=[
655 c75be81a Stavros Sachtouris
                'Argument %s should always be combined with %s' % (
656 c75be81a Stavros Sachtouris
                    pnpid.lvalue, fp.lvalue)])
657 56d84a4e Stavros Sachtouris
        self._run(server_id=server_id)
658 234954d1 Stavros Sachtouris
659 7493ccb6 Stavros Sachtouris
660 d486baec Stavros Sachtouris
@command(server_cmds)
661 75ae8a08 Giorgos Korfiatis
class server_reassign(_init_cyclades, _optional_json):
662 f1e45161 Stavros Sachtouris
    """Assign a virtual server to a different project"""
663 f1e45161 Stavros Sachtouris
664 f1e45161 Stavros Sachtouris
    arguments = dict(
665 f1e45161 Stavros Sachtouris
        project_id=ValueArgument('The project to assign', '--project-id')
666 f1e45161 Stavros Sachtouris
    )
667 f1e45161 Stavros Sachtouris
    required = ('project_id', )
668 75ae8a08 Giorgos Korfiatis
669 75ae8a08 Giorgos Korfiatis
    @errors.generic.all
670 75ae8a08 Giorgos Korfiatis
    @errors.cyclades.connection
671 75ae8a08 Giorgos Korfiatis
    @errors.cyclades.server_id
672 75ae8a08 Giorgos Korfiatis
    def _run(self, server_id, project):
673 75ae8a08 Giorgos Korfiatis
        self.client.reassign_server(server_id, project)
674 75ae8a08 Giorgos Korfiatis
675 75ae8a08 Giorgos Korfiatis
    def main(self, server_id, project):
676 75ae8a08 Giorgos Korfiatis
        super(self.__class__, self)._run()
677 f1e45161 Stavros Sachtouris
        self._run(server_id=server_id, project=self['project'])
678 75ae8a08 Giorgos Korfiatis
679 75ae8a08 Giorgos Korfiatis
680 75ae8a08 Giorgos Korfiatis
@command(server_cmds)
681 60c42f9f Stavros Sachtouris
class server_delete(_init_cyclades, _optional_output_cmd, _server_wait):
682 2bd23362 Stavros Sachtouris
    """Delete a virtual server"""
683 7493ccb6 Stavros Sachtouris
684 60c42f9f Stavros Sachtouris
    arguments = dict(
685 81c60832 Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait')),
686 81c60832 Stavros Sachtouris
        cluster=FlagArgument(
687 81c60832 Stavros Sachtouris
            '(DANGEROUS) Delete all virtual servers prefixed with the cluster '
688 81c60832 Stavros Sachtouris
            'prefix. In that case, the prefix replaces the server id',
689 81c60832 Stavros Sachtouris
            '--cluster')
690 60c42f9f Stavros Sachtouris
    )
691 60c42f9f Stavros Sachtouris
692 81c60832 Stavros Sachtouris
    def _server_ids(self, server_var):
693 81c60832 Stavros Sachtouris
        if self['cluster']:
694 81c60832 Stavros Sachtouris
            return [s['id'] for s in self.client.list_servers() if (
695 81c60832 Stavros Sachtouris
                s['name'].startswith(server_var))]
696 81c60832 Stavros Sachtouris
697 81c60832 Stavros Sachtouris
        @errors.cyclades.server_id
698 81c60832 Stavros Sachtouris
        def _check_server_id(self, server_id):
699 81c60832 Stavros Sachtouris
            return server_id
700 81c60832 Stavros Sachtouris
701 81c60832 Stavros Sachtouris
        return [_check_server_id(self, server_id=server_var), ]
702 81c60832 Stavros Sachtouris
703 5a673575 Stavros Sachtouris
    @errors.generic.all
704 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
705 81c60832 Stavros Sachtouris
    def _run(self, server_var):
706 81c60832 Stavros Sachtouris
        for server_id in self._server_ids(server_var):
707 60c42f9f Stavros Sachtouris
            if self['wait']:
708 60c42f9f Stavros Sachtouris
                details = self.client.get_server_details(server_id)
709 60c42f9f Stavros Sachtouris
                status = details['status']
710 60c42f9f Stavros Sachtouris
711 81c60832 Stavros Sachtouris
            r = self.client.delete_server(server_id)
712 60c42f9f Stavros Sachtouris
            self._optional_output(r)
713 60c42f9f Stavros Sachtouris
714 60c42f9f Stavros Sachtouris
            if self['wait']:
715 60c42f9f Stavros Sachtouris
                self._wait(server_id, status)
716 5a673575 Stavros Sachtouris
717 81c60832 Stavros Sachtouris
    def main(self, server_id_or_cluster_prefix):
718 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
719 81c60832 Stavros Sachtouris
        self._run(server_id_or_cluster_prefix)
720 234954d1 Stavros Sachtouris
721 7493ccb6 Stavros Sachtouris
722 d486baec Stavros Sachtouris
@command(server_cmds)
723 60c42f9f Stavros Sachtouris
class server_reboot(_init_cyclades, _optional_output_cmd, _server_wait):
724 2bd23362 Stavros Sachtouris
    """Reboot a virtual server"""
725 18edacfe Stavros Sachtouris
726 93914390 Stavros Sachtouris
    arguments = dict(
727 a1dc95ac Stavros Sachtouris
        hard=FlagArgument(
728 a1dc95ac Stavros Sachtouris
            'perform a hard reboot (deprecated)', ('-f', '--force')),
729 a1dc95ac Stavros Sachtouris
        type=ValueArgument('SOFT or HARD - default: SOFT', ('--type')),
730 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
731 93914390 Stavros Sachtouris
    )
732 7493ccb6 Stavros Sachtouris
733 5a673575 Stavros Sachtouris
    @errors.generic.all
734 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
735 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
736 5a673575 Stavros Sachtouris
    def _run(self, server_id):
737 a1dc95ac Stavros Sachtouris
        hard_reboot = self['hard']
738 a1dc95ac Stavros Sachtouris
        if hard_reboot:
739 a1dc95ac Stavros Sachtouris
            self.error(
740 a1dc95ac Stavros Sachtouris
                'WARNING: -f/--force will be deprecated in version 0.12\n'
741 a1dc95ac Stavros Sachtouris
                '\tIn the future, please use --type=hard instead')
742 a1dc95ac Stavros Sachtouris
        if self['type']:
743 a1dc95ac Stavros Sachtouris
            if self['type'].lower() in ('soft', ):
744 a1dc95ac Stavros Sachtouris
                hard_reboot = False
745 a1dc95ac Stavros Sachtouris
            elif self['type'].lower() in ('hard', ):
746 a1dc95ac Stavros Sachtouris
                hard_reboot = True
747 a1dc95ac Stavros Sachtouris
            else:
748 a1dc95ac Stavros Sachtouris
                raise CLISyntaxError(
749 a1dc95ac Stavros Sachtouris
                    'Invalid reboot type %s' % self['type'],
750 a1dc95ac Stavros Sachtouris
                    importance=2, details=[
751 a1dc95ac Stavros Sachtouris
                        '--type values are either SOFT (default) or HARD'])
752 a1dc95ac Stavros Sachtouris
753 a1dc95ac Stavros Sachtouris
        r = self.client.reboot_server(int(server_id), hard_reboot)
754 60c42f9f Stavros Sachtouris
        self._optional_output(r)
755 60c42f9f Stavros Sachtouris
756 60c42f9f Stavros Sachtouris
        if self['wait']:
757 60c42f9f Stavros Sachtouris
            self._wait(server_id, 'REBOOT')
758 5a673575 Stavros Sachtouris
759 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
760 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
761 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
762 234954d1 Stavros Sachtouris
763 7493ccb6 Stavros Sachtouris
764 d486baec Stavros Sachtouris
@command(server_cmds)
765 60c42f9f Stavros Sachtouris
class server_start(_init_cyclades, _optional_output_cmd, _server_wait):
766 2bd23362 Stavros Sachtouris
    """Start an existing virtual server"""
767 7493ccb6 Stavros Sachtouris
768 60c42f9f Stavros Sachtouris
    arguments = dict(
769 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
770 60c42f9f Stavros Sachtouris
    )
771 60c42f9f Stavros Sachtouris
772 5a673575 Stavros Sachtouris
    @errors.generic.all
773 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
774 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
775 5a673575 Stavros Sachtouris
    def _run(self, server_id):
776 60c42f9f Stavros Sachtouris
        status = 'ACTIVE'
777 60c42f9f Stavros Sachtouris
        if self['wait']:
778 60c42f9f Stavros Sachtouris
            details = self.client.get_server_details(server_id)
779 60c42f9f Stavros Sachtouris
            status = details['status']
780 60c42f9f Stavros Sachtouris
            if status in ('ACTIVE', ):
781 60c42f9f Stavros Sachtouris
                return
782 60c42f9f Stavros Sachtouris
783 60c42f9f Stavros Sachtouris
        r = self.client.start_server(int(server_id))
784 60c42f9f Stavros Sachtouris
        self._optional_output(r)
785 60c42f9f Stavros Sachtouris
786 60c42f9f Stavros Sachtouris
        if self['wait']:
787 60c42f9f Stavros Sachtouris
            self._wait(server_id, status)
788 5a673575 Stavros Sachtouris
789 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
790 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
791 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
792 234954d1 Stavros Sachtouris
793 7493ccb6 Stavros Sachtouris
794 d486baec Stavros Sachtouris
@command(server_cmds)
795 60c42f9f Stavros Sachtouris
class server_shutdown(_init_cyclades, _optional_output_cmd, _server_wait):
796 2bd23362 Stavros Sachtouris
    """Shutdown an active virtual server"""
797 7493ccb6 Stavros Sachtouris
798 60c42f9f Stavros Sachtouris
    arguments = dict(
799 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
800 60c42f9f Stavros Sachtouris
    )
801 60c42f9f Stavros Sachtouris
802 5a673575 Stavros Sachtouris
    @errors.generic.all
803 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
804 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
805 5a673575 Stavros Sachtouris
    def _run(self, server_id):
806 60c42f9f Stavros Sachtouris
        status = 'STOPPED'
807 60c42f9f Stavros Sachtouris
        if self['wait']:
808 60c42f9f Stavros Sachtouris
            details = self.client.get_server_details(server_id)
809 60c42f9f Stavros Sachtouris
            status = details['status']
810 60c42f9f Stavros Sachtouris
            if status in ('STOPPED', ):
811 60c42f9f Stavros Sachtouris
                return
812 60c42f9f Stavros Sachtouris
813 60c42f9f Stavros Sachtouris
        r = self.client.shutdown_server(int(server_id))
814 60c42f9f Stavros Sachtouris
        self._optional_output(r)
815 60c42f9f Stavros Sachtouris
816 60c42f9f Stavros Sachtouris
        if self['wait']:
817 60c42f9f Stavros Sachtouris
            self._wait(server_id, status)
818 5a673575 Stavros Sachtouris
819 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
820 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
821 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
822 234954d1 Stavros Sachtouris
823 7493ccb6 Stavros Sachtouris
824 d486baec Stavros Sachtouris
@command(server_cmds)
825 61c2c62d Stavros Sachtouris
class server_console(_init_cyclades, _optional_json):
826 edd4eacc Stavros Sachtouris
    """Create a VMC console and show connection information"""
827 7493ccb6 Stavros Sachtouris
828 edd4eacc Stavros Sachtouris
    @errors.generic.all
829 edd4eacc Stavros Sachtouris
    @errors.cyclades.connection
830 edd4eacc Stavros Sachtouris
    @errors.cyclades.server_id
831 edd4eacc Stavros Sachtouris
    def _run(self, server_id):
832 edd4eacc Stavros Sachtouris
        self.error('The following credentials will be invalidated shortly')
833 edd4eacc Stavros Sachtouris
        self._print(
834 edd4eacc Stavros Sachtouris
            self.client.get_server_console(server_id), self.print_dict)
835 edd4eacc Stavros Sachtouris
836 edd4eacc Stavros Sachtouris
    def main(self, server_id):
837 edd4eacc Stavros Sachtouris
        super(self.__class__, self)._run()
838 edd4eacc Stavros Sachtouris
        self._run(server_id=server_id)
839 5a673575 Stavros Sachtouris
840 234954d1 Stavros Sachtouris
841 d486baec Stavros Sachtouris
@command(server_cmds)
842 60c42f9f Stavros Sachtouris
class server_wait(_init_cyclades, _server_wait):
843 c3d42104 Stavros Sachtouris
    """Wait for server to change its status (default: BUILD)"""
844 fd1f1d96 Stavros Sachtouris
845 8547cd19 Stavros Sachtouris
    arguments = dict(
846 8547cd19 Stavros Sachtouris
        timeout=IntArgument(
847 c3d42104 Stavros Sachtouris
            'Wait limit in seconds (default: 60)', '--timeout', default=60),
848 c3d42104 Stavros Sachtouris
        server_status=StatusArgument(
849 c3d42104 Stavros Sachtouris
            'Status to wait for (%s, default: %s)' % (
850 c3d42104 Stavros Sachtouris
                ', '.join(server_states), server_states[0]),
851 c3d42104 Stavros Sachtouris
            '--status',
852 c3d42104 Stavros Sachtouris
            valid_states=server_states)
853 8547cd19 Stavros Sachtouris
    )
854 8547cd19 Stavros Sachtouris
855 5a673575 Stavros Sachtouris
    @errors.generic.all
856 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
857 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
858 e9c73313 Stavros Sachtouris
    def _run(self, server_id, current_status):
859 e9c73313 Stavros Sachtouris
        r = self.client.get_server_details(server_id)
860 e9c73313 Stavros Sachtouris
        if r['status'].lower() == current_status.lower():
861 8547cd19 Stavros Sachtouris
            self._wait(server_id, current_status, timeout=self['timeout'])
862 e9c73313 Stavros Sachtouris
        else:
863 e9c73313 Stavros Sachtouris
            self.error(
864 e9c73313 Stavros Sachtouris
                'Server %s: Cannot wait for status %s, '
865 e9c73313 Stavros Sachtouris
                'status is already %s' % (
866 e9c73313 Stavros Sachtouris
                    server_id, current_status, r['status']))
867 fd1f1d96 Stavros Sachtouris
868 c3d42104 Stavros Sachtouris
    def main(self, server_id):
869 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
870 22663c4a Stavros Sachtouris
        self._run(
871 cf862450 Stavros Sachtouris
            server_id=server_id,
872 cf862450 Stavros Sachtouris
            current_status=self['server_status'] or 'BUILD')
873 5a673575 Stavros Sachtouris
874 fd1f1d96 Stavros Sachtouris
875 d486baec Stavros Sachtouris
@command(flavor_cmds)
876 6d190dd1 Stavros Sachtouris
class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
877 bd40efdf Stavros Sachtouris
    """List available hardware flavors"""
878 7493ccb6 Stavros Sachtouris
879 d8ff7b56 Stavros Sachtouris
    PERMANENTS = ('id', 'name')
880 d8ff7b56 Stavros Sachtouris
881 93914390 Stavros Sachtouris
    arguments = dict(
882 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
883 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit # of listed flavors', ('-n', '--number')),
884 bd40efdf Stavros Sachtouris
        more=FlagArgument(
885 de73876b Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
886 ed9af02c Stavros Sachtouris
            '--more'),
887 d8ff7b56 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
888 d8ff7b56 Stavros Sachtouris
        ram=ValueArgument('filter by ram', ('--ram')),
889 d8ff7b56 Stavros Sachtouris
        vcpus=ValueArgument('filter by number of VCPUs', ('--vcpus')),
890 d8ff7b56 Stavros Sachtouris
        disk=ValueArgument('filter by disk size in GB', ('--disk')),
891 d8ff7b56 Stavros Sachtouris
        disk_template=ValueArgument(
892 d8ff7b56 Stavros Sachtouris
            'filter by disk_templace', ('--disk-template'))
893 93914390 Stavros Sachtouris
    )
894 7493ccb6 Stavros Sachtouris
895 d8ff7b56 Stavros Sachtouris
    def _apply_common_filters(self, flavors):
896 d8ff7b56 Stavros Sachtouris
        common_filters = dict()
897 d8ff7b56 Stavros Sachtouris
        if self['ram']:
898 d8ff7b56 Stavros Sachtouris
            common_filters['ram'] = self['ram']
899 d8ff7b56 Stavros Sachtouris
        if self['vcpus']:
900 d8ff7b56 Stavros Sachtouris
            common_filters['vcpus'] = self['vcpus']
901 d8ff7b56 Stavros Sachtouris
        if self['disk']:
902 d8ff7b56 Stavros Sachtouris
            common_filters['disk'] = self['disk']
903 d8ff7b56 Stavros Sachtouris
        if self['disk_template']:
904 d8ff7b56 Stavros Sachtouris
            common_filters['SNF:disk_template'] = self['disk_template']
905 d8ff7b56 Stavros Sachtouris
        return filter_dicts_by_dict(flavors, common_filters)
906 d8ff7b56 Stavros Sachtouris
907 5a673575 Stavros Sachtouris
    @errors.generic.all
908 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
909 5a673575 Stavros Sachtouris
    def _run(self):
910 d8ff7b56 Stavros Sachtouris
        withcommons = self['ram'] or self['vcpus'] or (
911 d8ff7b56 Stavros Sachtouris
            self['disk'] or self['disk_template'])
912 d8ff7b56 Stavros Sachtouris
        detail = self['detail'] or withcommons
913 d8ff7b56 Stavros Sachtouris
        flavors = self.client.list_flavors(detail)
914 6d190dd1 Stavros Sachtouris
        flavors = self._filter_by_name(flavors)
915 6d190dd1 Stavros Sachtouris
        flavors = self._filter_by_id(flavors)
916 d8ff7b56 Stavros Sachtouris
        if withcommons:
917 d8ff7b56 Stavros Sachtouris
            flavors = self._apply_common_filters(flavors)
918 f76c6bbc Stavros Sachtouris
        if not (self['detail'] or (
919 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format'])):
920 7ba195e5 Stavros Sachtouris
            remove_from_items(flavors, 'links')
921 d8ff7b56 Stavros Sachtouris
        if detail and not self['detail']:
922 d8ff7b56 Stavros Sachtouris
            for flv in flavors:
923 d8ff7b56 Stavros Sachtouris
                for key in set(flv).difference(self.PERMANENTS):
924 d8ff7b56 Stavros Sachtouris
                    flv.pop(key)
925 6430d3a0 Stavros Sachtouris
        kwargs = dict(out=StringIO(), title=()) if self['more'] else {}
926 545c6c29 Stavros Sachtouris
        self._print(
927 ed9af02c Stavros Sachtouris
            flavors,
928 6430d3a0 Stavros Sachtouris
            with_redundancy=self['detail'], with_enumeration=self['enum'],
929 6430d3a0 Stavros Sachtouris
            **kwargs)
930 6430d3a0 Stavros Sachtouris
        if self['more']:
931 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
932 5a673575 Stavros Sachtouris
933 7493ccb6 Stavros Sachtouris
    def main(self):
934 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
935 5a673575 Stavros Sachtouris
        self._run()
936 7493ccb6 Stavros Sachtouris
937 234954d1 Stavros Sachtouris
938 d486baec Stavros Sachtouris
@command(flavor_cmds)
939 545c6c29 Stavros Sachtouris
class flavor_info(_init_cyclades, _optional_json):
940 769dbf53 Stavros Sachtouris
    """Detailed information on a hardware flavor
941 ddc0b290 Stavros Sachtouris
    To get a list of available flavors and flavor ids, try /flavor list
942 ddc0b290 Stavros Sachtouris
    """
943 7493ccb6 Stavros Sachtouris
944 5a673575 Stavros Sachtouris
    @errors.generic.all
945 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
946 5a673575 Stavros Sachtouris
    @errors.cyclades.flavor_id
947 5a673575 Stavros Sachtouris
    def _run(self, flavor_id):
948 bcef3ac9 Stavros Sachtouris
        self._print(
949 76f58e2e Stavros Sachtouris
            self.client.get_flavor_details(int(flavor_id)), self.print_dict)
950 7493ccb6 Stavros Sachtouris
951 5a673575 Stavros Sachtouris
    def main(self, flavor_id):
952 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
953 5a673575 Stavros Sachtouris
        self._run(flavor_id=flavor_id)
954 5a673575 Stavros Sachtouris
955 234954d1 Stavros Sachtouris
956 cf115aed Stavros Sachtouris
def _add_name(self, net):
957 cf115aed Stavros Sachtouris
        user_id, tenant_id, uuids = net['user_id'], net['tenant_id'], []
958 cf115aed Stavros Sachtouris
        if user_id:
959 cf115aed Stavros Sachtouris
            uuids.append(user_id)
960 11925d1d Giorgos Korfiatis
        if uuids or tenant_id:
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]