Statistics
| Branch: | Tag: | Revision:

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

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