Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (31.7 kB)

1 a494a741 Stavros Sachtouris
# Copyright 2011-2013 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 7493ccb6 Stavros Sachtouris
34 76f58e2e Stavros Sachtouris
from base64 import b64encode
35 d62cba24 Stavros Sachtouris
from os.path import exists, expanduser
36 76f58e2e Stavros Sachtouris
from io import StringIO
37 76f58e2e Stavros Sachtouris
from pydoc import pager
38 76f58e2e Stavros Sachtouris
39 f3e94e06 Stavros Sachtouris
from kamaki.cli import command
40 d486baec Stavros Sachtouris
from kamaki.cli.command_tree import CommandTree
41 76f58e2e Stavros Sachtouris
from kamaki.cli.utils import remove_from_items, filter_dicts_by_dict
42 c788a761 Stavros Sachtouris
from kamaki.cli.errors import (
43 c788a761 Stavros Sachtouris
    raiseCLIError, CLISyntaxError, CLIBaseUrlError, CLIInvalidArgument)
44 d1bced10 Stavros Sachtouris
from kamaki.clients.cyclades import CycladesClient
45 0b052394 Stavros Sachtouris
from kamaki.cli.argument import (
46 0b052394 Stavros Sachtouris
    FlagArgument, ValueArgument, KeyValueArgument, RepeatableArgument,
47 0b052394 Stavros Sachtouris
    ProgressBarArgument, DateArgument, IntArgument)
48 b4f69041 Stavros Sachtouris
from kamaki.cli.commands import _command_init, errors, addLogSettings
49 6d190dd1 Stavros Sachtouris
from kamaki.cli.commands import (
50 6d190dd1 Stavros Sachtouris
    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
51 5eae854d Stavros Sachtouris
52 234954d1 Stavros Sachtouris
53 a29d2f88 Stavros Sachtouris
server_cmds = CommandTree('server', 'Cyclades/Compute API server commands')
54 a29d2f88 Stavros Sachtouris
flavor_cmds = CommandTree('flavor', 'Cyclades/Compute API flavor commands')
55 291cab21 Stavros Sachtouris
_commands = [server_cmds, flavor_cmds]
56 234954d1 Stavros Sachtouris
57 7493ccb6 Stavros Sachtouris
58 c314fc10 Stavros Sachtouris
about_authentication = '\nUser Authentication:\
59 4018326d Stavros Sachtouris
    \n* to check authentication: /user authenticate\
60 9e5341f5 Stavros Sachtouris
    \n* to set authentication token: /config set cloud.<cloud>.token <token>'
61 18edacfe Stavros Sachtouris
62 d7259dd5 Stavros Sachtouris
howto_personality = [
63 2bd23362 Stavros Sachtouris
    'Defines a file to be injected to virtual servers file system.',
64 3185cd6d Stavros Sachtouris
    'syntax:  PATH,[SERVER_PATH,[OWNER,[GROUP,[MODE]]]]',
65 0fccd79b Stavros Sachtouris
    '  [local-path=]PATH: local file to be injected (relative or absolute)',
66 0fccd79b Stavros Sachtouris
    '  [server-path=]SERVER_PATH: destination location inside server Image',
67 0fccd79b Stavros Sachtouris
    '  [owner=]OWNER: virtual servers user id for the remote file',
68 0fccd79b Stavros Sachtouris
    '  [group=]GROUP: virtual servers group id or name for the remote file',
69 d62cba24 Stavros Sachtouris
    '  [mode=]MODE: permission in octal (e.g., 0777)',
70 0fccd79b Stavros Sachtouris
    'e.g., -p /tmp/my.file,owner=root,mode=0777']
71 d7259dd5 Stavros Sachtouris
72 18edacfe Stavros Sachtouris
73 3185cd6d Stavros Sachtouris
class _service_wait(object):
74 60c42f9f Stavros Sachtouris
75 60c42f9f Stavros Sachtouris
    wait_arguments = dict(
76 60c42f9f Stavros Sachtouris
        progress_bar=ProgressBarArgument(
77 3185cd6d Stavros Sachtouris
            'do not show progress bar', ('-N', '--no-progress-bar'), False)
78 60c42f9f Stavros Sachtouris
    )
79 60c42f9f Stavros Sachtouris
80 e9c73313 Stavros Sachtouris
    def _wait(
81 e9c73313 Stavros Sachtouris
            self, service, service_id, status_method, current_status,
82 8547cd19 Stavros Sachtouris
            countdown=True, timeout=60):
83 60c42f9f Stavros Sachtouris
        (progress_bar, wait_cb) = self._safe_progress_bar(
84 e9c73313 Stavros Sachtouris
            '%s %s: status is still %s' % (
85 e9c73313 Stavros Sachtouris
                service, service_id, current_status),
86 8547cd19 Stavros Sachtouris
            countdown=countdown, timeout=timeout)
87 60c42f9f Stavros Sachtouris
88 60c42f9f Stavros Sachtouris
        try:
89 3185cd6d Stavros Sachtouris
            new_mode = status_method(
90 8547cd19 Stavros Sachtouris
                service_id, current_status, max_wait=timeout, wait_cb=wait_cb)
91 a9598baf Stavros Sachtouris
            if new_mode:
92 e9c73313 Stavros Sachtouris
                self.error('%s %s: status is now %s' % (
93 a9598baf Stavros Sachtouris
                    service, service_id, new_mode))
94 a9598baf Stavros Sachtouris
            else:
95 8547cd19 Stavros Sachtouris
                self.error('%s %s: status is still %s' % (
96 e9c73313 Stavros Sachtouris
                    service, service_id, current_status))
97 a9598baf Stavros Sachtouris
        except KeyboardInterrupt:
98 a9598baf Stavros Sachtouris
            self.error('\n- canceled')
99 60c42f9f Stavros Sachtouris
        finally:
100 60c42f9f Stavros Sachtouris
            self._safe_progress_bar_finish(progress_bar)
101 60c42f9f Stavros Sachtouris
102 60c42f9f Stavros Sachtouris
103 3185cd6d Stavros Sachtouris
class _server_wait(_service_wait):
104 7b2e4bf1 Stavros Sachtouris
105 8547cd19 Stavros Sachtouris
    def _wait(self, server_id, current_status, timeout=60):
106 3185cd6d Stavros Sachtouris
        super(_server_wait, self)._wait(
107 e9c73313 Stavros Sachtouris
            'Server', server_id, self.client.wait_server, current_status,
108 8547cd19 Stavros Sachtouris
            countdown=(current_status not in ('BUILD', )),
109 8547cd19 Stavros Sachtouris
            timeout=timeout if current_status not in ('BUILD', ) else 100)
110 7b2e4bf1 Stavros Sachtouris
111 7b2e4bf1 Stavros Sachtouris
112 5eae854d Stavros Sachtouris
class _init_cyclades(_command_init):
113 b04288f7 Stavros Sachtouris
    @errors.generic.all
114 b4f69041 Stavros Sachtouris
    @addLogSettings
115 236e7d08 Stavros Sachtouris
    def _run(self, service='compute'):
116 b4f69041 Stavros Sachtouris
        if getattr(self, 'cloud', None):
117 3185cd6d Stavros Sachtouris
            base_url = self._custom_url(service) or self._custom_url(
118 3185cd6d Stavros Sachtouris
                'cyclades')
119 b4f69041 Stavros Sachtouris
            if base_url:
120 3185cd6d Stavros Sachtouris
                token = self._custom_token(service) or self._custom_token(
121 3185cd6d Stavros Sachtouris
                    'cyclades') or self.config.get_cloud('token')
122 3185cd6d Stavros Sachtouris
                self.client = CycladesClient(base_url=base_url, token=token)
123 b4f69041 Stavros Sachtouris
                return
124 b4f69041 Stavros Sachtouris
        else:
125 b4f69041 Stavros Sachtouris
            self.cloud = 'default'
126 8cec3671 Stavros Sachtouris
        if getattr(self, 'auth_base', False):
127 8cec3671 Stavros Sachtouris
            cyclades_endpoints = self.auth_base.get_service_endpoints(
128 b4f69041 Stavros Sachtouris
                self._custom_type('cyclades') or 'compute',
129 b4f69041 Stavros Sachtouris
                self._custom_version('cyclades') or '')
130 8cec3671 Stavros Sachtouris
            base_url = cyclades_endpoints['publicURL']
131 b4f69041 Stavros Sachtouris
            token = self.auth_base.token
132 b4f69041 Stavros Sachtouris
            self.client = CycladesClient(base_url=base_url, token=token)
133 8cec3671 Stavros Sachtouris
        else:
134 8cec3671 Stavros Sachtouris
            raise CLIBaseUrlError(service='cyclades')
135 8cec3671 Stavros Sachtouris
136 b04288f7 Stavros Sachtouris
    def main(self):
137 b04288f7 Stavros Sachtouris
        self._run()
138 236e7d08 Stavros Sachtouris
139 234954d1 Stavros Sachtouris
140 d486baec Stavros Sachtouris
@command(server_cmds)
141 6d190dd1 Stavros Sachtouris
class server_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
142 f6822a26 Stavros Sachtouris
    """List virtual servers accessible by user
143 16d7b9ff Stavros Sachtouris
    Use filtering arguments (e.g., --name-like) to manage long server lists
144 f6822a26 Stavros Sachtouris
    """
145 18edacfe Stavros Sachtouris
146 89ea97e1 Stavros Sachtouris
    PERMANENTS = ('id', 'name')
147 89ea97e1 Stavros Sachtouris
148 e15d78e2 Stavros Sachtouris
    arguments = dict(
149 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
150 67469d65 Stavros Sachtouris
        since=DateArgument(
151 a382ea56 Stavros Sachtouris
            'show only items since date (\' d/m/Y H:M:S \')',
152 a4d0d88a Stavros Sachtouris
            '--since'),
153 2bd23362 Stavros Sachtouris
        limit=IntArgument(
154 2bd23362 Stavros Sachtouris
            'limit number of listed virtual servers', ('-n', '--number')),
155 a4d0d88a Stavros Sachtouris
        more=FlagArgument(
156 ddc0b290 Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
157 ed9af02c Stavros Sachtouris
            '--more'),
158 89ea97e1 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
159 89ea97e1 Stavros Sachtouris
        flavor_id=ValueArgument('filter by flavor id', ('--flavor-id')),
160 89ea97e1 Stavros Sachtouris
        image_id=ValueArgument('filter by image id', ('--image-id')),
161 d8ff7b56 Stavros Sachtouris
        user_id=ValueArgument('filter by user id', ('--user-id')),
162 d8ff7b56 Stavros Sachtouris
        user_name=ValueArgument('filter by user name', ('--user-name')),
163 d8ff7b56 Stavros Sachtouris
        status=ValueArgument(
164 d8ff7b56 Stavros Sachtouris
            'filter by status (ACTIVE, STOPPED, REBOOT, ERROR, etc.)',
165 d8ff7b56 Stavros Sachtouris
            ('--status')),
166 89ea97e1 Stavros Sachtouris
        meta=KeyValueArgument('filter by metadata key=values', ('--metadata')),
167 89ea97e1 Stavros Sachtouris
        meta_like=KeyValueArgument(
168 89ea97e1 Stavros Sachtouris
            'print only if in key=value, the value is part of actual value',
169 89ea97e1 Stavros Sachtouris
            ('--metadata-like')),
170 e15d78e2 Stavros Sachtouris
    )
171 e15d78e2 Stavros Sachtouris
172 f00db940 Stavros Sachtouris
    def _add_user_name(self, servers):
173 9d2f656a Stavros Sachtouris
        uuids = self._uuids2usernames(list(set(
174 9d2f656a Stavros Sachtouris
                [srv['user_id'] for srv in servers] +
175 9d2f656a Stavros Sachtouris
                [srv['tenant_id'] for srv in servers])))
176 f00db940 Stavros Sachtouris
        for srv in servers:
177 f00db940 Stavros Sachtouris
            srv['user_id'] += ' (%s)' % uuids[srv['user_id']]
178 9d2f656a Stavros Sachtouris
            srv['tenant_id'] += ' (%s)' % uuids[srv['tenant_id']]
179 f00db940 Stavros Sachtouris
        return servers
180 f00db940 Stavros Sachtouris
181 d8ff7b56 Stavros Sachtouris
    def _apply_common_filters(self, servers):
182 d8ff7b56 Stavros Sachtouris
        common_filters = dict()
183 d8ff7b56 Stavros Sachtouris
        if self['status']:
184 d8ff7b56 Stavros Sachtouris
            common_filters['status'] = self['status']
185 d8ff7b56 Stavros Sachtouris
        if self['user_id'] or self['user_name']:
186 d8ff7b56 Stavros Sachtouris
            uuid = self['user_id'] or self._username2uuid(self['user_name'])
187 d8ff7b56 Stavros Sachtouris
            common_filters['user_id'] = uuid
188 d8ff7b56 Stavros Sachtouris
        return filter_dicts_by_dict(servers, common_filters)
189 d8ff7b56 Stavros Sachtouris
190 6d190dd1 Stavros Sachtouris
    def _filter_by_image(self, servers):
191 89ea97e1 Stavros Sachtouris
        iid = self['image_id']
192 3185cd6d Stavros Sachtouris
        return [srv for srv in servers if srv['image']['id'] == iid]
193 89ea97e1 Stavros Sachtouris
194 6d190dd1 Stavros Sachtouris
    def _filter_by_flavor(self, servers):
195 89ea97e1 Stavros Sachtouris
        fid = self['flavor_id']
196 3185cd6d Stavros Sachtouris
        return [srv for srv in servers if (
197 3185cd6d Stavros Sachtouris
            '%s' % srv['image']['id'] == '%s' % fid)]
198 89ea97e1 Stavros Sachtouris
199 6d190dd1 Stavros Sachtouris
    def _filter_by_metadata(self, servers):
200 89ea97e1 Stavros Sachtouris
        new_servers = []
201 89ea97e1 Stavros Sachtouris
        for srv in servers:
202 89ea97e1 Stavros Sachtouris
            if not 'metadata' in srv:
203 89ea97e1 Stavros Sachtouris
                continue
204 89ea97e1 Stavros Sachtouris
            meta = [dict(srv['metadata'])]
205 89ea97e1 Stavros Sachtouris
            if self['meta']:
206 89ea97e1 Stavros Sachtouris
                meta = filter_dicts_by_dict(meta, self['meta'])
207 89ea97e1 Stavros Sachtouris
            if meta and self['meta_like']:
208 89ea97e1 Stavros Sachtouris
                meta = filter_dicts_by_dict(
209 89ea97e1 Stavros Sachtouris
                    meta, self['meta_like'], exact_match=False)
210 89ea97e1 Stavros Sachtouris
            if meta:
211 89ea97e1 Stavros Sachtouris
                new_servers.append(srv)
212 89ea97e1 Stavros Sachtouris
        return new_servers
213 89ea97e1 Stavros Sachtouris
214 b04288f7 Stavros Sachtouris
    @errors.generic.all
215 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
216 b04288f7 Stavros Sachtouris
    @errors.cyclades.date
217 b04288f7 Stavros Sachtouris
    def _run(self):
218 89ea97e1 Stavros Sachtouris
        withimage = bool(self['image_id'])
219 89ea97e1 Stavros Sachtouris
        withflavor = bool(self['flavor_id'])
220 89ea97e1 Stavros Sachtouris
        withmeta = bool(self['meta'] or self['meta_like'])
221 d8ff7b56 Stavros Sachtouris
        withcommons = bool(
222 d8ff7b56 Stavros Sachtouris
            self['status'] or self['user_id'] or self['user_name'])
223 d8ff7b56 Stavros Sachtouris
        detail = self['detail'] or (
224 d8ff7b56 Stavros Sachtouris
            withimage or withflavor or withmeta or withcommons)
225 89ea97e1 Stavros Sachtouris
        servers = self.client.list_servers(detail, self['since'])
226 89ea97e1 Stavros Sachtouris
227 6d190dd1 Stavros Sachtouris
        servers = self._filter_by_name(servers)
228 6d190dd1 Stavros Sachtouris
        servers = self._filter_by_id(servers)
229 d8ff7b56 Stavros Sachtouris
        servers = self._apply_common_filters(servers)
230 89ea97e1 Stavros Sachtouris
        if withimage:
231 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_image(servers)
232 89ea97e1 Stavros Sachtouris
        if withflavor:
233 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_flavor(servers)
234 89ea97e1 Stavros Sachtouris
        if withmeta:
235 6d190dd1 Stavros Sachtouris
            servers = self._filter_by_metadata(servers)
236 89ea97e1 Stavros Sachtouris
237 f76c6bbc Stavros Sachtouris
        if self['detail'] and not (
238 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format']):
239 f00db940 Stavros Sachtouris
            servers = self._add_user_name(servers)
240 f76c6bbc Stavros Sachtouris
        elif not (self['detail'] or (
241 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format'])):
242 7ba195e5 Stavros Sachtouris
            remove_from_items(servers, 'links')
243 89ea97e1 Stavros Sachtouris
        if detail and not self['detail']:
244 89ea97e1 Stavros Sachtouris
            for srv in servers:
245 89ea97e1 Stavros Sachtouris
                for key in set(srv).difference(self.PERMANENTS):
246 89ea97e1 Stavros Sachtouris
                    srv.pop(key)
247 545c6c29 Stavros Sachtouris
        kwargs = dict(with_enumeration=self['enum'])
248 a4d0d88a Stavros Sachtouris
        if self['more']:
249 6430d3a0 Stavros Sachtouris
            kwargs['out'] = StringIO()
250 6430d3a0 Stavros Sachtouris
            kwargs['title'] = ()
251 6430d3a0 Stavros Sachtouris
        if self['limit']:
252 545c6c29 Stavros Sachtouris
            servers = servers[:self['limit']]
253 545c6c29 Stavros Sachtouris
        self._print(servers, **kwargs)
254 6430d3a0 Stavros Sachtouris
        if self['more']:
255 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
256 7493ccb6 Stavros Sachtouris
257 b04288f7 Stavros Sachtouris
    def main(self):
258 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
259 b04288f7 Stavros Sachtouris
        self._run()
260 b04288f7 Stavros Sachtouris
261 234954d1 Stavros Sachtouris
262 d486baec Stavros Sachtouris
@command(server_cmds)
263 545c6c29 Stavros Sachtouris
class server_info(_init_cyclades, _optional_json):
264 61c2c62d Stavros Sachtouris
    """Detailed information on a Virtual Machine"""
265 61c2c62d Stavros Sachtouris
266 61c2c62d Stavros Sachtouris
    arguments = dict(
267 61c2c62d Stavros Sachtouris
        addr=FlagArgument(
268 61c2c62d Stavros Sachtouris
            'Show only the network interfaces of this virtual server',
269 61c2c62d Stavros Sachtouris
            '--nics'),
270 61c2c62d Stavros Sachtouris
        vnc=FlagArgument(
271 61c2c62d Stavros Sachtouris
            'Show VNC connection information (valid for a short period)',
272 61c2c62d Stavros Sachtouris
            '--vnc-credentials'),
273 61c2c62d Stavros Sachtouris
        stats=FlagArgument('Get URLs for server statistics', '--stats')
274 61c2c62d Stavros Sachtouris
    )
275 7493ccb6 Stavros Sachtouris
276 b04288f7 Stavros Sachtouris
    @errors.generic.all
277 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
278 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
279 b04288f7 Stavros Sachtouris
    def _run(self, server_id):
280 cf115aed Stavros Sachtouris
        vm = self.client.get_server_details(server_id)
281 61c2c62d Stavros Sachtouris
        if self['addr']:
282 61c2c62d Stavros Sachtouris
            self._print(vm.get('attachments', []))
283 61c2c62d Stavros Sachtouris
        elif self['vnc']:
284 61c2c62d Stavros Sachtouris
            self.error(
285 61c2c62d Stavros Sachtouris
                '(!) For security reasons, the following credentials are '
286 61c2c62d Stavros Sachtouris
                'invalidated\nafter a short time period, depending on the '
287 61c2c62d Stavros Sachtouris
                'server settings\n')
288 61c2c62d Stavros Sachtouris
            self._print(
289 61c2c62d Stavros Sachtouris
                self.client.get_server_console(server_id), self.print_dict)
290 61c2c62d Stavros Sachtouris
        elif self['stats']:
291 61c2c62d Stavros Sachtouris
            self._print(
292 61c2c62d Stavros Sachtouris
                self.client.get_server_stats(server_id), self.print_dict)
293 61c2c62d Stavros Sachtouris
        else:
294 61c2c62d Stavros Sachtouris
            uuids = self._uuids2usernames([vm['user_id'], vm['tenant_id']])
295 61c2c62d Stavros Sachtouris
            vm['user_id'] += ' (%s)' % uuids[vm['user_id']]
296 61c2c62d Stavros Sachtouris
            vm['tenant_id'] += ' (%s)' % uuids[vm['tenant_id']]
297 61c2c62d Stavros Sachtouris
            self._print(vm, self.print_dict)
298 7493ccb6 Stavros Sachtouris
299 b04288f7 Stavros Sachtouris
    def main(self, server_id):
300 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
301 61c2c62d Stavros Sachtouris
        choose_one = ('addr', 'vnc', 'stats')
302 61c2c62d Stavros Sachtouris
        count = len([a for a in choose_one if self[a]])
303 61c2c62d Stavros Sachtouris
        if count > 1:
304 61c2c62d Stavros Sachtouris
            raise CLIInvalidArgument('Invalid argument compination', details=[
305 61c2c62d Stavros Sachtouris
                'Arguments %s cannot be used simultaneously' % ', '.join(
306 61c2c62d Stavros Sachtouris
                    [self.arguments[a].lvalue for a in choose_one])])
307 b04288f7 Stavros Sachtouris
        self._run(server_id=server_id)
308 b04288f7 Stavros Sachtouris
309 234954d1 Stavros Sachtouris
310 57d622b6 Stavros Sachtouris
class PersonalityArgument(KeyValueArgument):
311 0fccd79b Stavros Sachtouris
312 0fccd79b Stavros Sachtouris
    terms = (
313 0fccd79b Stavros Sachtouris
        ('local-path', 'contents'),
314 0fccd79b Stavros Sachtouris
        ('server-path', 'path'),
315 0fccd79b Stavros Sachtouris
        ('owner', 'owner'),
316 0fccd79b Stavros Sachtouris
        ('group', 'group'),
317 0fccd79b Stavros Sachtouris
        ('mode', 'mode'))
318 0fccd79b Stavros Sachtouris
319 234954d1 Stavros Sachtouris
    @property
320 f3e94e06 Stavros Sachtouris
    def value(self):
321 6c068db6 Stavros Sachtouris
        return getattr(self, '_value', [])
322 234954d1 Stavros Sachtouris
323 234954d1 Stavros Sachtouris
    @value.setter
324 f3e94e06 Stavros Sachtouris
    def value(self, newvalue):
325 f3e94e06 Stavros Sachtouris
        if newvalue == self.default:
326 f3e94e06 Stavros Sachtouris
            return self.value
327 0fccd79b Stavros Sachtouris
        self._value, input_dict = [], {}
328 57d622b6 Stavros Sachtouris
        for i, terms in enumerate(newvalue):
329 57d622b6 Stavros Sachtouris
            termlist = terms.split(',')
330 0fccd79b Stavros Sachtouris
            if len(termlist) > len(self.terms):
331 0fccd79b Stavros Sachtouris
                msg = 'Wrong number of terms (1<=terms<=%s)' % len(self.terms)
332 de73876b Stavros Sachtouris
                raiseCLIError(CLISyntaxError(msg), details=howto_personality)
333 0fccd79b Stavros Sachtouris
334 0fccd79b Stavros Sachtouris
            for k, v in self.terms:
335 0fccd79b Stavros Sachtouris
                prefix = '%s=' % k
336 0fccd79b Stavros Sachtouris
                for item in termlist:
337 0fccd79b Stavros Sachtouris
                    if item.lower().startswith(prefix):
338 0fccd79b Stavros Sachtouris
                        input_dict[k] = item[len(k) + 1:]
339 0fccd79b Stavros Sachtouris
                        break
340 0fccd79b Stavros Sachtouris
                    item = None
341 0fccd79b Stavros Sachtouris
                if item:
342 0fccd79b Stavros Sachtouris
                    termlist.remove(item)
343 0fccd79b Stavros Sachtouris
344 0fccd79b Stavros Sachtouris
            try:
345 0fccd79b Stavros Sachtouris
                path = input_dict['local-path']
346 0fccd79b Stavros Sachtouris
            except KeyError:
347 0fccd79b Stavros Sachtouris
                path = termlist.pop(0)
348 0fccd79b Stavros Sachtouris
                if not path:
349 0fccd79b Stavros Sachtouris
                    raise CLIInvalidArgument(
350 0fccd79b Stavros Sachtouris
                        '--personality: No local path specified',
351 0fccd79b Stavros Sachtouris
                        details=howto_personality)
352 0fccd79b Stavros Sachtouris
353 57d622b6 Stavros Sachtouris
            if not exists(path):
354 0fccd79b Stavros Sachtouris
                raise CLIInvalidArgument(
355 8194b51b Stavros Sachtouris
                    '--personality: File %s does not exist' % path,
356 0fccd79b Stavros Sachtouris
                    details=howto_personality)
357 0fccd79b Stavros Sachtouris
358 57d622b6 Stavros Sachtouris
            self._value.append(dict(path=path))
359 d62cba24 Stavros Sachtouris
            with open(expanduser(path)) as f:
360 57d622b6 Stavros Sachtouris
                self._value[i]['contents'] = b64encode(f.read())
361 0fccd79b Stavros Sachtouris
            for k, v in self.terms[1:]:
362 0fccd79b Stavros Sachtouris
                try:
363 0fccd79b Stavros Sachtouris
                    self._value[i][v] = input_dict[k]
364 0fccd79b Stavros Sachtouris
                except KeyError:
365 0fccd79b Stavros Sachtouris
                    try:
366 0fccd79b Stavros Sachtouris
                        self._value[i][v] = termlist.pop(0)
367 0fccd79b Stavros Sachtouris
                    except IndexError:
368 0fccd79b Stavros Sachtouris
                        continue
369 d62cba24 Stavros Sachtouris
                if k in ('mode', ) and self._value[i][v]:
370 d62cba24 Stavros Sachtouris
                    try:
371 d62cba24 Stavros Sachtouris
                        self._value[i][v] = int(self._value[i][v], 8)
372 d62cba24 Stavros Sachtouris
                    except ValueError as ve:
373 d62cba24 Stavros Sachtouris
                        raise CLIInvalidArgument(
374 d62cba24 Stavros Sachtouris
                            'Personality mode must be in octal', details=[
375 d62cba24 Stavros Sachtouris
                                '%s' % ve])
376 f3e94e06 Stavros Sachtouris
377 234954d1 Stavros Sachtouris
378 264a13f7 Stavros Sachtouris
class NetworkIpArgument(RepeatableArgument):
379 264a13f7 Stavros Sachtouris
380 264a13f7 Stavros Sachtouris
    @property
381 264a13f7 Stavros Sachtouris
    def value(self):
382 264a13f7 Stavros Sachtouris
        return getattr(self, '_value', [])
383 264a13f7 Stavros Sachtouris
384 264a13f7 Stavros Sachtouris
    @value.setter
385 264a13f7 Stavros Sachtouris
    def value(self, new_value):
386 264a13f7 Stavros Sachtouris
        for v in (new_value or []):
387 264a13f7 Stavros Sachtouris
            net_and_ip = v.split(',')
388 264a13f7 Stavros Sachtouris
            if len(net_and_ip) < 2:
389 264a13f7 Stavros Sachtouris
                raise CLIInvalidArgument(
390 264a13f7 Stavros Sachtouris
                    'Value "%s" is missing parts' % v,
391 264a13f7 Stavros Sachtouris
                    details=['Correct format: %s NETWORK_ID,IP' % (
392 264a13f7 Stavros Sachtouris
                        self.parsed_name[0])])
393 264a13f7 Stavros Sachtouris
            self._value = getattr(self, '_value', list())
394 264a13f7 Stavros Sachtouris
            self._value.append(
395 264a13f7 Stavros Sachtouris
                dict(network=net_and_ip[0], fixed_ip=net_and_ip[1]))
396 264a13f7 Stavros Sachtouris
397 264a13f7 Stavros Sachtouris
398 d486baec Stavros Sachtouris
@command(server_cmds)
399 60c42f9f Stavros Sachtouris
class server_create(_init_cyclades, _optional_json, _server_wait):
400 56d84a4e Stavros Sachtouris
    """Create a server (aka Virtual Machine)"""
401 7493ccb6 Stavros Sachtouris
402 93914390 Stavros Sachtouris
    arguments = dict(
403 56d84a4e Stavros Sachtouris
        server_name=ValueArgument('The name of the new server', '--name'),
404 56d84a4e Stavros Sachtouris
        flavor_id=IntArgument('The ID of the hardware flavor', '--flavor-id'),
405 86900a30 Stavros Sachtouris
        image_id=ValueArgument('The ID of the hardware image', '--image-id'),
406 93914390 Stavros Sachtouris
        personality=PersonalityArgument(
407 60c42f9f Stavros Sachtouris
            (80 * ' ').join(howto_personality), ('-p', '--personality')),
408 81c60832 Stavros Sachtouris
        wait=FlagArgument('Wait server to build', ('-w', '--wait')),
409 81c60832 Stavros Sachtouris
        cluster_size=IntArgument(
410 81c60832 Stavros Sachtouris
            'Create a cluster of servers of this size. In this case, the name'
411 81c60832 Stavros Sachtouris
            'parameter is the prefix of each server in the cluster (e.g.,'
412 81c60832 Stavros Sachtouris
            'srv1, srv2, etc.',
413 ec5d658f Stavros Sachtouris
            '--cluster-size'),
414 ec5d658f Stavros Sachtouris
        max_threads=IntArgument(
415 fcd0f53d Stavros Sachtouris
            'Max threads in cluster mode (default 1)', '--threads'),
416 264a13f7 Stavros Sachtouris
        network_id=RepeatableArgument(
417 264a13f7 Stavros Sachtouris
            'Connect server to network (can be repeated)', '--network'),
418 264a13f7 Stavros Sachtouris
        network_id_and_ip=NetworkIpArgument(
419 264a13f7 Stavros Sachtouris
            'Connect server to network w. floating ip ( NETWORK_ID,IP )'
420 264a13f7 Stavros Sachtouris
            '(can be repeated)',
421 264a13f7 Stavros Sachtouris
            '--network-with-ip'),
422 eb647cfe Stavros Sachtouris
        automatic_ip=FlagArgument(
423 eb647cfe Stavros Sachtouris
            'Automatically assign an IP to the server', '--automatic-ip')
424 93914390 Stavros Sachtouris
    )
425 56d84a4e Stavros Sachtouris
    required = ('server_name', 'flavor_id', 'image_id')
426 f3e94e06 Stavros Sachtouris
427 81c60832 Stavros Sachtouris
    @errors.cyclades.cluster_size
428 81c60832 Stavros Sachtouris
    def _create_cluster(self, prefix, flavor_id, image_id, size):
429 eb647cfe Stavros Sachtouris
        if self['automatic_ip']:
430 eb647cfe Stavros Sachtouris
            networks = []
431 eb647cfe Stavros Sachtouris
        else:
432 eb647cfe Stavros Sachtouris
            networks = [dict(network=netid) for netid in (
433 eb647cfe Stavros Sachtouris
                (self['network_id'] or []) + (self['network_id_and_ip'] or [])
434 eb647cfe Stavros Sachtouris
            )] or None
435 81c60832 Stavros Sachtouris
        servers = [dict(
436 6c068db6 Stavros Sachtouris
            name='%s%s' % (prefix, i if size > 1 else ''),
437 81c60832 Stavros Sachtouris
            flavor_id=flavor_id,
438 81c60832 Stavros Sachtouris
            image_id=image_id,
439 264a13f7 Stavros Sachtouris
            personality=self['personality'],
440 264a13f7 Stavros Sachtouris
            networks=networks) for i in range(1, 1 + size)]
441 81c60832 Stavros Sachtouris
        if size == 1:
442 81c60832 Stavros Sachtouris
            return [self.client.create_server(**servers[0])]
443 ec5d658f Stavros Sachtouris
        self.client.MAX_THREADS = int(self['max_threads'] or 1)
444 c2e8d493 Stavros Sachtouris
        try:
445 40ddc207 Stavros Sachtouris
            r = self.client.async_run(self.client.create_server, servers)
446 40ddc207 Stavros Sachtouris
            return r
447 c2e8d493 Stavros Sachtouris
        except Exception as e:
448 c2e8d493 Stavros Sachtouris
            if size == 1:
449 c2e8d493 Stavros Sachtouris
                raise e
450 c2e8d493 Stavros Sachtouris
            try:
451 c2e8d493 Stavros Sachtouris
                requested_names = [s['name'] for s in servers]
452 c2e8d493 Stavros Sachtouris
                spawned_servers = [dict(
453 c2e8d493 Stavros Sachtouris
                    name=s['name'],
454 c2e8d493 Stavros Sachtouris
                    id=s['id']) for s in self.client.list_servers() if (
455 c2e8d493 Stavros Sachtouris
                        s['name'] in requested_names)]
456 c2e8d493 Stavros Sachtouris
                self.error('Failed to build %s servers' % size)
457 40ddc207 Stavros Sachtouris
                self.error('Found %s matching servers:' % len(spawned_servers))
458 c2e8d493 Stavros Sachtouris
                self._print(spawned_servers, out=self._err)
459 c2e8d493 Stavros Sachtouris
                self.error('Check if any of these servers should be removed\n')
460 c2e8d493 Stavros Sachtouris
            except Exception as ne:
461 c2e8d493 Stavros Sachtouris
                self.error('Error (%s) while notifying about errors' % ne)
462 c2e8d493 Stavros Sachtouris
            finally:
463 c2e8d493 Stavros Sachtouris
                raise e
464 81c60832 Stavros Sachtouris
465 b04288f7 Stavros Sachtouris
    @errors.generic.all
466 b04288f7 Stavros Sachtouris
    @errors.cyclades.connection
467 b04288f7 Stavros Sachtouris
    @errors.plankton.id
468 b04288f7 Stavros Sachtouris
    @errors.cyclades.flavor_id
469 b04288f7 Stavros Sachtouris
    def _run(self, name, flavor_id, image_id):
470 81c60832 Stavros Sachtouris
        for r in self._create_cluster(
471 81c60832 Stavros Sachtouris
                name, flavor_id, image_id, size=self['cluster_size'] or 1):
472 c2e8d493 Stavros Sachtouris
            if not r:
473 c2e8d493 Stavros Sachtouris
                self.error('Create %s: server response was %s' % (name, r))
474 c2e8d493 Stavros Sachtouris
                continue
475 c2e8d493 Stavros Sachtouris
            usernames = self._uuids2usernames(
476 c2e8d493 Stavros Sachtouris
                [r['user_id'], r['tenant_id']])
477 81c60832 Stavros Sachtouris
            r['user_id'] += ' (%s)' % usernames[r['user_id']]
478 81c60832 Stavros Sachtouris
            r['tenant_id'] += ' (%s)' % usernames[r['tenant_id']]
479 81c60832 Stavros Sachtouris
            self._print(r, self.print_dict)
480 81c60832 Stavros Sachtouris
            if self['wait']:
481 81c60832 Stavros Sachtouris
                self._wait(r['id'], r['status'])
482 40ddc207 Stavros Sachtouris
            self.writeln(' ')
483 b04288f7 Stavros Sachtouris
484 56d84a4e Stavros Sachtouris
    def main(self):
485 b04288f7 Stavros Sachtouris
        super(self.__class__, self)._run()
486 eb647cfe Stavros Sachtouris
        if self['automatic_ip'] and (
487 eb647cfe Stavros Sachtouris
                self['network_id'] or self['network_id_and_ip']):
488 eb647cfe Stavros Sachtouris
            raise CLIInvalidArgument('Invalid argument combination', details=[
489 eb647cfe Stavros Sachtouris
                'Argument %s should not be combined with other' % (
490 eb647cfe Stavros Sachtouris
                    self.arguments['automatic_ip'].lvalue),
491 eb647cfe Stavros Sachtouris
                'network-related arguments i.e., %s or %s' % (
492 eb647cfe Stavros Sachtouris
                    self.arguments['network_id'].lvalue,
493 eb647cfe Stavros Sachtouris
                    self.arguments['network_id_and_ip'].lvalue)])
494 56d84a4e Stavros Sachtouris
        self._run(
495 56d84a4e Stavros Sachtouris
            name=self['server_name'],
496 56d84a4e Stavros Sachtouris
            flavor_id=self['flavor_id'],
497 56d84a4e Stavros Sachtouris
            image_id=self['image_id'])
498 7493ccb6 Stavros Sachtouris
499 234954d1 Stavros Sachtouris
500 0b052394 Stavros Sachtouris
class FirewallProfileArgument(ValueArgument):
501 0b052394 Stavros Sachtouris
502 0b052394 Stavros Sachtouris
    profiles = ('DISABLED', 'ENABLED', 'PROTECTED')
503 0b052394 Stavros Sachtouris
504 0b052394 Stavros Sachtouris
    @property
505 0b052394 Stavros Sachtouris
    def value(self):
506 0b052394 Stavros Sachtouris
        return getattr(self, '_value', None)
507 0b052394 Stavros Sachtouris
508 0b052394 Stavros Sachtouris
    @value.setter
509 0b052394 Stavros Sachtouris
    def value(self, new_profile):
510 0b052394 Stavros Sachtouris
        if new_profile:
511 0b052394 Stavros Sachtouris
            new_profile = new_profile.upper()
512 0b052394 Stavros Sachtouris
            if new_profile in self.profiles:
513 0b052394 Stavros Sachtouris
                self._value = new_profile
514 0b052394 Stavros Sachtouris
            else:
515 0b052394 Stavros Sachtouris
                raise CLIInvalidArgument(
516 0b052394 Stavros Sachtouris
                    'Invalid firewall profile %s' % new_profile,
517 0b052394 Stavros Sachtouris
                    details=['Valid values: %s' % ', '.join(self.profiles)])
518 7493ccb6 Stavros Sachtouris
519 234954d1 Stavros Sachtouris
520 d486baec Stavros Sachtouris
@command(server_cmds)
521 56d84a4e Stavros Sachtouris
class server_modify(_init_cyclades, _optional_output_cmd):
522 56d84a4e Stavros Sachtouris
    """Modify attributes of a virtual server"""
523 56d84a4e Stavros Sachtouris
524 56d84a4e Stavros Sachtouris
    arguments = dict(
525 56d84a4e Stavros Sachtouris
        server_name=ValueArgument('The new name', '--name'),
526 56d84a4e Stavros Sachtouris
        flavor_id=IntArgument('Set a different flavor', '--flavor-id'),
527 0b052394 Stavros Sachtouris
        firewall_profile=FirewallProfileArgument(
528 0b052394 Stavros Sachtouris
            'Valid values: %s' % (', '.join(FirewallProfileArgument.profiles)),
529 0b052394 Stavros Sachtouris
            '--firewall'),
530 0b052394 Stavros Sachtouris
        metadata_to_set=KeyValueArgument(
531 0b052394 Stavros Sachtouris
            'Set metadata in key=value form (can be repeated)',
532 00b1248e Stavros Sachtouris
            '--metadata-set'),
533 0b052394 Stavros Sachtouris
        metadata_to_delete=RepeatableArgument(
534 00b1248e Stavros Sachtouris
            'Delete metadata by key (can be repeated)', '--metadata-del')
535 56d84a4e Stavros Sachtouris
    )
536 0b052394 Stavros Sachtouris
    required = [
537 0b052394 Stavros Sachtouris
        'server_name', 'flavor_id', 'firewall_profile', 'metadata_to_set',
538 00b1248e Stavros Sachtouris
        'metadata_to_delete']
539 7493ccb6 Stavros Sachtouris
540 5a673575 Stavros Sachtouris
    @errors.generic.all
541 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
542 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
543 56d84a4e Stavros Sachtouris
    def _run(self, server_id):
544 56d84a4e Stavros Sachtouris
        if self['server_name']:
545 56d84a4e Stavros Sachtouris
            self.client.update_server_name((server_id), self['server_name'])
546 56d84a4e Stavros Sachtouris
        if self['flavor_id']:
547 56d84a4e Stavros Sachtouris
            self.client.resize_server(server_id, self['flavor_id'])
548 0b052394 Stavros Sachtouris
        if self['firewall_profile']:
549 0b052394 Stavros Sachtouris
            self.client.set_firewall_profile(
550 0b052394 Stavros Sachtouris
                server_id=server_id, profile=self['firewall_profile'])
551 0b052394 Stavros Sachtouris
        if self['metadata_to_set']:
552 0b052394 Stavros Sachtouris
            self.client.update_server_metadata(
553 0b052394 Stavros Sachtouris
                server_id, **self['metadata_to_set'])
554 0b052394 Stavros Sachtouris
        for key in self['metadata_to_delete']:
555 0b052394 Stavros Sachtouris
            errors.cyclades.metadata(
556 0b052394 Stavros Sachtouris
                self.client.delete_server_metadata)(server_id, key=key)
557 56d84a4e Stavros Sachtouris
        if self['with_output']:
558 56d84a4e Stavros Sachtouris
            self._optional_output(self.client.get_server_details(server_id))
559 5a673575 Stavros Sachtouris
560 56d84a4e Stavros Sachtouris
    def main(self, server_id):
561 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
562 56d84a4e Stavros Sachtouris
        self._run(server_id=server_id)
563 234954d1 Stavros Sachtouris
564 7493ccb6 Stavros Sachtouris
565 d486baec Stavros Sachtouris
@command(server_cmds)
566 60c42f9f Stavros Sachtouris
class server_delete(_init_cyclades, _optional_output_cmd, _server_wait):
567 2bd23362 Stavros Sachtouris
    """Delete a virtual server"""
568 7493ccb6 Stavros Sachtouris
569 60c42f9f Stavros Sachtouris
    arguments = dict(
570 81c60832 Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait')),
571 81c60832 Stavros Sachtouris
        cluster=FlagArgument(
572 81c60832 Stavros Sachtouris
            '(DANGEROUS) Delete all virtual servers prefixed with the cluster '
573 81c60832 Stavros Sachtouris
            'prefix. In that case, the prefix replaces the server id',
574 81c60832 Stavros Sachtouris
            '--cluster')
575 60c42f9f Stavros Sachtouris
    )
576 60c42f9f Stavros Sachtouris
577 81c60832 Stavros Sachtouris
    def _server_ids(self, server_var):
578 81c60832 Stavros Sachtouris
        if self['cluster']:
579 81c60832 Stavros Sachtouris
            return [s['id'] for s in self.client.list_servers() if (
580 81c60832 Stavros Sachtouris
                s['name'].startswith(server_var))]
581 81c60832 Stavros Sachtouris
582 81c60832 Stavros Sachtouris
        @errors.cyclades.server_id
583 81c60832 Stavros Sachtouris
        def _check_server_id(self, server_id):
584 81c60832 Stavros Sachtouris
            return server_id
585 81c60832 Stavros Sachtouris
586 81c60832 Stavros Sachtouris
        return [_check_server_id(self, server_id=server_var), ]
587 81c60832 Stavros Sachtouris
588 5a673575 Stavros Sachtouris
    @errors.generic.all
589 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
590 81c60832 Stavros Sachtouris
    def _run(self, server_var):
591 81c60832 Stavros Sachtouris
        for server_id in self._server_ids(server_var):
592 60c42f9f Stavros Sachtouris
            if self['wait']:
593 60c42f9f Stavros Sachtouris
                details = self.client.get_server_details(server_id)
594 60c42f9f Stavros Sachtouris
                status = details['status']
595 60c42f9f Stavros Sachtouris
596 81c60832 Stavros Sachtouris
            r = self.client.delete_server(server_id)
597 60c42f9f Stavros Sachtouris
            self._optional_output(r)
598 60c42f9f Stavros Sachtouris
599 60c42f9f Stavros Sachtouris
            if self['wait']:
600 60c42f9f Stavros Sachtouris
                self._wait(server_id, status)
601 5a673575 Stavros Sachtouris
602 81c60832 Stavros Sachtouris
    def main(self, server_id_or_cluster_prefix):
603 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
604 81c60832 Stavros Sachtouris
        self._run(server_id_or_cluster_prefix)
605 234954d1 Stavros Sachtouris
606 7493ccb6 Stavros Sachtouris
607 d486baec Stavros Sachtouris
@command(server_cmds)
608 60c42f9f Stavros Sachtouris
class server_reboot(_init_cyclades, _optional_output_cmd, _server_wait):
609 2bd23362 Stavros Sachtouris
    """Reboot a virtual server"""
610 18edacfe Stavros Sachtouris
611 93914390 Stavros Sachtouris
    arguments = dict(
612 a1dc95ac Stavros Sachtouris
        hard=FlagArgument(
613 a1dc95ac Stavros Sachtouris
            'perform a hard reboot (deprecated)', ('-f', '--force')),
614 a1dc95ac Stavros Sachtouris
        type=ValueArgument('SOFT or HARD - default: SOFT', ('--type')),
615 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
616 93914390 Stavros Sachtouris
    )
617 7493ccb6 Stavros Sachtouris
618 5a673575 Stavros Sachtouris
    @errors.generic.all
619 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
620 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
621 5a673575 Stavros Sachtouris
    def _run(self, server_id):
622 a1dc95ac Stavros Sachtouris
        hard_reboot = self['hard']
623 a1dc95ac Stavros Sachtouris
        if hard_reboot:
624 a1dc95ac Stavros Sachtouris
            self.error(
625 a1dc95ac Stavros Sachtouris
                'WARNING: -f/--force will be deprecated in version 0.12\n'
626 a1dc95ac Stavros Sachtouris
                '\tIn the future, please use --type=hard instead')
627 a1dc95ac Stavros Sachtouris
        if self['type']:
628 a1dc95ac Stavros Sachtouris
            if self['type'].lower() in ('soft', ):
629 a1dc95ac Stavros Sachtouris
                hard_reboot = False
630 a1dc95ac Stavros Sachtouris
            elif self['type'].lower() in ('hard', ):
631 a1dc95ac Stavros Sachtouris
                hard_reboot = True
632 a1dc95ac Stavros Sachtouris
            else:
633 a1dc95ac Stavros Sachtouris
                raise CLISyntaxError(
634 a1dc95ac Stavros Sachtouris
                    'Invalid reboot type %s' % self['type'],
635 a1dc95ac Stavros Sachtouris
                    importance=2, details=[
636 a1dc95ac Stavros Sachtouris
                        '--type values are either SOFT (default) or HARD'])
637 a1dc95ac Stavros Sachtouris
638 a1dc95ac Stavros Sachtouris
        r = self.client.reboot_server(int(server_id), hard_reboot)
639 60c42f9f Stavros Sachtouris
        self._optional_output(r)
640 60c42f9f Stavros Sachtouris
641 60c42f9f Stavros Sachtouris
        if self['wait']:
642 60c42f9f Stavros Sachtouris
            self._wait(server_id, 'REBOOT')
643 5a673575 Stavros Sachtouris
644 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
645 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
646 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
647 234954d1 Stavros Sachtouris
648 7493ccb6 Stavros Sachtouris
649 d486baec Stavros Sachtouris
@command(server_cmds)
650 60c42f9f Stavros Sachtouris
class server_start(_init_cyclades, _optional_output_cmd, _server_wait):
651 2bd23362 Stavros Sachtouris
    """Start an existing virtual server"""
652 7493ccb6 Stavros Sachtouris
653 60c42f9f Stavros Sachtouris
    arguments = dict(
654 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
655 60c42f9f Stavros Sachtouris
    )
656 60c42f9f Stavros Sachtouris
657 5a673575 Stavros Sachtouris
    @errors.generic.all
658 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
659 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
660 5a673575 Stavros Sachtouris
    def _run(self, server_id):
661 60c42f9f Stavros Sachtouris
        status = 'ACTIVE'
662 60c42f9f Stavros Sachtouris
        if self['wait']:
663 60c42f9f Stavros Sachtouris
            details = self.client.get_server_details(server_id)
664 60c42f9f Stavros Sachtouris
            status = details['status']
665 60c42f9f Stavros Sachtouris
            if status in ('ACTIVE', ):
666 60c42f9f Stavros Sachtouris
                return
667 60c42f9f Stavros Sachtouris
668 60c42f9f Stavros Sachtouris
        r = self.client.start_server(int(server_id))
669 60c42f9f Stavros Sachtouris
        self._optional_output(r)
670 60c42f9f Stavros Sachtouris
671 60c42f9f Stavros Sachtouris
        if self['wait']:
672 60c42f9f Stavros Sachtouris
            self._wait(server_id, status)
673 5a673575 Stavros Sachtouris
674 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
675 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
676 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
677 234954d1 Stavros Sachtouris
678 7493ccb6 Stavros Sachtouris
679 d486baec Stavros Sachtouris
@command(server_cmds)
680 60c42f9f Stavros Sachtouris
class server_shutdown(_init_cyclades, _optional_output_cmd, _server_wait):
681 2bd23362 Stavros Sachtouris
    """Shutdown an active virtual server"""
682 7493ccb6 Stavros Sachtouris
683 60c42f9f Stavros Sachtouris
    arguments = dict(
684 60c42f9f Stavros Sachtouris
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait'))
685 60c42f9f Stavros Sachtouris
    )
686 60c42f9f Stavros Sachtouris
687 5a673575 Stavros Sachtouris
    @errors.generic.all
688 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
689 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
690 5a673575 Stavros Sachtouris
    def _run(self, server_id):
691 60c42f9f Stavros Sachtouris
        status = 'STOPPED'
692 60c42f9f Stavros Sachtouris
        if self['wait']:
693 60c42f9f Stavros Sachtouris
            details = self.client.get_server_details(server_id)
694 60c42f9f Stavros Sachtouris
            status = details['status']
695 60c42f9f Stavros Sachtouris
            if status in ('STOPPED', ):
696 60c42f9f Stavros Sachtouris
                return
697 60c42f9f Stavros Sachtouris
698 60c42f9f Stavros Sachtouris
        r = self.client.shutdown_server(int(server_id))
699 60c42f9f Stavros Sachtouris
        self._optional_output(r)
700 60c42f9f Stavros Sachtouris
701 60c42f9f Stavros Sachtouris
        if self['wait']:
702 60c42f9f Stavros Sachtouris
            self._wait(server_id, status)
703 5a673575 Stavros Sachtouris
704 7493ccb6 Stavros Sachtouris
    def main(self, server_id):
705 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
706 5a673575 Stavros Sachtouris
        self._run(server_id=server_id)
707 234954d1 Stavros Sachtouris
708 7493ccb6 Stavros Sachtouris
709 d486baec Stavros Sachtouris
@command(server_cmds)
710 61c2c62d Stavros Sachtouris
class server_addr(_init_cyclades):
711 fd981f77 Stavros Sachtouris
    """DEPRECATED, use: [kamaki] server info <SERVER_ID> --nics"""
712 7493ccb6 Stavros Sachtouris
713 61c2c62d Stavros Sachtouris
    def main(self, *args):
714 fd981f77 Stavros Sachtouris
        raiseCLIError('DEPRECATED since v0.12', importance=3, details=[
715 61c2c62d Stavros Sachtouris
            'Replaced by',
716 61c2c62d Stavros Sachtouris
            '  [kamaki] server info <SERVER_ID> --nics'])
717 7493ccb6 Stavros Sachtouris
718 234954d1 Stavros Sachtouris
719 d486baec Stavros Sachtouris
@command(server_cmds)
720 61c2c62d Stavros Sachtouris
class server_console(_init_cyclades, _optional_json):
721 fd981f77 Stavros Sachtouris
    """DEPRECATED, use: [kamaki] server info <SERVER_ID> --vnc-credentials"""
722 7493ccb6 Stavros Sachtouris
723 61c2c62d Stavros Sachtouris
    def main(self, *args):
724 fd981f77 Stavros Sachtouris
        raiseCLIError('DEPRECATED since v0.12', importance=3, details=[
725 61c2c62d Stavros Sachtouris
            'Replaced by',
726 61c2c62d Stavros Sachtouris
            '  [kamaki] server info <SERVER_ID> --vnc-credentials'])
727 5a673575 Stavros Sachtouris
728 234954d1 Stavros Sachtouris
729 d486baec Stavros Sachtouris
@command(server_cmds)
730 545c6c29 Stavros Sachtouris
class server_stats(_init_cyclades, _optional_json):
731 fd981f77 Stavros Sachtouris
    """DEPRECATED, use: [kamaki] server info <SERVER_ID> --stats"""
732 5a673575 Stavros Sachtouris
733 61c2c62d Stavros Sachtouris
    def main(self, *args):
734 fd981f77 Stavros Sachtouris
        raiseCLIError('DEPRECATED since v0.12', importance=3, details=[
735 61c2c62d Stavros Sachtouris
            'Replaced by',
736 61c2c62d Stavros Sachtouris
            '  [kamaki] server info <SERVER_ID> --stats'])
737 7493ccb6 Stavros Sachtouris
738 234954d1 Stavros Sachtouris
739 d486baec Stavros Sachtouris
@command(server_cmds)
740 60c42f9f Stavros Sachtouris
class server_wait(_init_cyclades, _server_wait):
741 fd1f1d96 Stavros Sachtouris
    """Wait for server to finish [BUILD, STOPPED, REBOOT, ACTIVE]"""
742 fd1f1d96 Stavros Sachtouris
743 8547cd19 Stavros Sachtouris
    arguments = dict(
744 8547cd19 Stavros Sachtouris
        timeout=IntArgument(
745 8547cd19 Stavros Sachtouris
            'Wait limit in seconds (default: 60)', '--timeout', default=60)
746 8547cd19 Stavros Sachtouris
    )
747 8547cd19 Stavros Sachtouris
748 5a673575 Stavros Sachtouris
    @errors.generic.all
749 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
750 5a673575 Stavros Sachtouris
    @errors.cyclades.server_id
751 e9c73313 Stavros Sachtouris
    def _run(self, server_id, current_status):
752 e9c73313 Stavros Sachtouris
        r = self.client.get_server_details(server_id)
753 e9c73313 Stavros Sachtouris
        if r['status'].lower() == current_status.lower():
754 8547cd19 Stavros Sachtouris
            self._wait(server_id, current_status, timeout=self['timeout'])
755 e9c73313 Stavros Sachtouris
        else:
756 e9c73313 Stavros Sachtouris
            self.error(
757 e9c73313 Stavros Sachtouris
                'Server %s: Cannot wait for status %s, '
758 e9c73313 Stavros Sachtouris
                'status is already %s' % (
759 e9c73313 Stavros Sachtouris
                    server_id, current_status, r['status']))
760 fd1f1d96 Stavros Sachtouris
761 e9c73313 Stavros Sachtouris
    def main(self, server_id, current_status='BUILD'):
762 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
763 e9c73313 Stavros Sachtouris
        self._run(server_id=server_id, current_status=current_status)
764 5a673575 Stavros Sachtouris
765 fd1f1d96 Stavros Sachtouris
766 d486baec Stavros Sachtouris
@command(flavor_cmds)
767 6d190dd1 Stavros Sachtouris
class flavor_list(_init_cyclades, _optional_json, _name_filter, _id_filter):
768 bd40efdf Stavros Sachtouris
    """List available hardware flavors"""
769 7493ccb6 Stavros Sachtouris
770 d8ff7b56 Stavros Sachtouris
    PERMANENTS = ('id', 'name')
771 d8ff7b56 Stavros Sachtouris
772 93914390 Stavros Sachtouris
    arguments = dict(
773 f40f0cb7 Stavros Sachtouris
        detail=FlagArgument('show detailed output', ('-l', '--details')),
774 f40f0cb7 Stavros Sachtouris
        limit=IntArgument('limit # of listed flavors', ('-n', '--number')),
775 bd40efdf Stavros Sachtouris
        more=FlagArgument(
776 de73876b Stavros Sachtouris
            'output results in pages (-n to set items per page, default 10)',
777 ed9af02c Stavros Sachtouris
            '--more'),
778 d8ff7b56 Stavros Sachtouris
        enum=FlagArgument('Enumerate results', '--enumerate'),
779 d8ff7b56 Stavros Sachtouris
        ram=ValueArgument('filter by ram', ('--ram')),
780 d8ff7b56 Stavros Sachtouris
        vcpus=ValueArgument('filter by number of VCPUs', ('--vcpus')),
781 d8ff7b56 Stavros Sachtouris
        disk=ValueArgument('filter by disk size in GB', ('--disk')),
782 d8ff7b56 Stavros Sachtouris
        disk_template=ValueArgument(
783 d8ff7b56 Stavros Sachtouris
            'filter by disk_templace', ('--disk-template'))
784 93914390 Stavros Sachtouris
    )
785 7493ccb6 Stavros Sachtouris
786 d8ff7b56 Stavros Sachtouris
    def _apply_common_filters(self, flavors):
787 d8ff7b56 Stavros Sachtouris
        common_filters = dict()
788 d8ff7b56 Stavros Sachtouris
        if self['ram']:
789 d8ff7b56 Stavros Sachtouris
            common_filters['ram'] = self['ram']
790 d8ff7b56 Stavros Sachtouris
        if self['vcpus']:
791 d8ff7b56 Stavros Sachtouris
            common_filters['vcpus'] = self['vcpus']
792 d8ff7b56 Stavros Sachtouris
        if self['disk']:
793 d8ff7b56 Stavros Sachtouris
            common_filters['disk'] = self['disk']
794 d8ff7b56 Stavros Sachtouris
        if self['disk_template']:
795 d8ff7b56 Stavros Sachtouris
            common_filters['SNF:disk_template'] = self['disk_template']
796 d8ff7b56 Stavros Sachtouris
        return filter_dicts_by_dict(flavors, common_filters)
797 d8ff7b56 Stavros Sachtouris
798 5a673575 Stavros Sachtouris
    @errors.generic.all
799 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
800 5a673575 Stavros Sachtouris
    def _run(self):
801 d8ff7b56 Stavros Sachtouris
        withcommons = self['ram'] or self['vcpus'] or (
802 d8ff7b56 Stavros Sachtouris
            self['disk'] or self['disk_template'])
803 d8ff7b56 Stavros Sachtouris
        detail = self['detail'] or withcommons
804 d8ff7b56 Stavros Sachtouris
        flavors = self.client.list_flavors(detail)
805 6d190dd1 Stavros Sachtouris
        flavors = self._filter_by_name(flavors)
806 6d190dd1 Stavros Sachtouris
        flavors = self._filter_by_id(flavors)
807 d8ff7b56 Stavros Sachtouris
        if withcommons:
808 d8ff7b56 Stavros Sachtouris
            flavors = self._apply_common_filters(flavors)
809 f76c6bbc Stavros Sachtouris
        if not (self['detail'] or (
810 f76c6bbc Stavros Sachtouris
                self['json_output'] or self['output_format'])):
811 7ba195e5 Stavros Sachtouris
            remove_from_items(flavors, 'links')
812 d8ff7b56 Stavros Sachtouris
        if detail and not self['detail']:
813 d8ff7b56 Stavros Sachtouris
            for flv in flavors:
814 d8ff7b56 Stavros Sachtouris
                for key in set(flv).difference(self.PERMANENTS):
815 d8ff7b56 Stavros Sachtouris
                    flv.pop(key)
816 6430d3a0 Stavros Sachtouris
        kwargs = dict(out=StringIO(), title=()) if self['more'] else {}
817 545c6c29 Stavros Sachtouris
        self._print(
818 ed9af02c Stavros Sachtouris
            flavors,
819 6430d3a0 Stavros Sachtouris
            with_redundancy=self['detail'], with_enumeration=self['enum'],
820 6430d3a0 Stavros Sachtouris
            **kwargs)
821 6430d3a0 Stavros Sachtouris
        if self['more']:
822 6430d3a0 Stavros Sachtouris
            pager(kwargs['out'].getvalue())
823 5a673575 Stavros Sachtouris
824 7493ccb6 Stavros Sachtouris
    def main(self):
825 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
826 5a673575 Stavros Sachtouris
        self._run()
827 7493ccb6 Stavros Sachtouris
828 234954d1 Stavros Sachtouris
829 d486baec Stavros Sachtouris
@command(flavor_cmds)
830 545c6c29 Stavros Sachtouris
class flavor_info(_init_cyclades, _optional_json):
831 769dbf53 Stavros Sachtouris
    """Detailed information on a hardware flavor
832 ddc0b290 Stavros Sachtouris
    To get a list of available flavors and flavor ids, try /flavor list
833 ddc0b290 Stavros Sachtouris
    """
834 7493ccb6 Stavros Sachtouris
835 5a673575 Stavros Sachtouris
    @errors.generic.all
836 5a673575 Stavros Sachtouris
    @errors.cyclades.connection
837 5a673575 Stavros Sachtouris
    @errors.cyclades.flavor_id
838 5a673575 Stavros Sachtouris
    def _run(self, flavor_id):
839 bcef3ac9 Stavros Sachtouris
        self._print(
840 76f58e2e Stavros Sachtouris
            self.client.get_flavor_details(int(flavor_id)), self.print_dict)
841 7493ccb6 Stavros Sachtouris
842 5a673575 Stavros Sachtouris
    def main(self, flavor_id):
843 5a673575 Stavros Sachtouris
        super(self.__class__, self)._run()
844 5a673575 Stavros Sachtouris
        self._run(flavor_id=flavor_id)
845 5a673575 Stavros Sachtouris
846 234954d1 Stavros Sachtouris
847 cf115aed Stavros Sachtouris
def _add_name(self, net):
848 cf115aed Stavros Sachtouris
        user_id, tenant_id, uuids = net['user_id'], net['tenant_id'], []
849 cf115aed Stavros Sachtouris
        if user_id:
850 cf115aed Stavros Sachtouris
            uuids.append(user_id)
851 cf115aed Stavros Sachtouris
        if tenant_id:
852 cf115aed Stavros Sachtouris
            uuids.append(tenant_id)
853 cf115aed Stavros Sachtouris
        if uuids:
854 cf115aed Stavros Sachtouris
            usernames = self._uuids2usernames(uuids)
855 cf115aed Stavros Sachtouris
            if user_id:
856 cf115aed Stavros Sachtouris
                net['user_id'] += ' (%s)' % usernames[user_id]
857 cf115aed Stavros Sachtouris
            if tenant_id:
858 cf115aed Stavros Sachtouris
                net['tenant_id'] += ' (%s)' % usernames[tenant_id]