Revision f3740b99

b/kamaki/cli/commands/__init__.py
319 319
    def _non_exact_name_filter(self, items):
320 320
        np, ns, nl = self['name_pref'], self['name_suff'], self['name_like']
321 321
        return [item for item in items if (
322
            (not np) or item['name'].lower().startswith(np.lower())) and (
323
            (not ns) or item['name'].lower().endswith(ns.lower())) and (
324
            (not nl) or nl.lower() in item['name'].lower())]
322
            (not np) or (item['name'] or '').lower().startswith(
323
                np.lower())) and (
324
            (not ns) or (item['name'] or '').lower().endswith(
325
                ns.lower())) and (
326
            (not nl) or nl.lower() in (item['name'] or '').lower())]
325 327

  
326 328
    def _exact_name_filter(self, items):
327
        return filter_dicts_by_dict(items, dict(name=self['name'])) if (
329
        return filter_dicts_by_dict(items, dict(name=self['name'] or '')) if (
328 330
            self['name']) else items
329 331

  
330 332
    def _filter_by_name(self, items):
b/kamaki/cli/commands/cyclades.py
392 392
                        self.parsed_name[0])])
393 393
            self._value = getattr(self, '_value', list())
394 394
            self._value.append(
395
                dict(network=net_and_ip[0], fixed_ip=net_and_ip[1]))
395
                dict(uuid=net_and_ip[0], fixed_ip=net_and_ip[1]))
396 396

  
397 397

  
398 398
@command(server_cmds)
......
429 429
        if self['automatic_ip']:
430 430
            networks = []
431 431
        else:
432
            networks = [dict(network=netid) for netid in (
432
            networks = [dict(uuid=netid) for netid in (
433 433
                (self['network_id'] or []) + (self['network_id_and_ip'] or [])
434 434
            )] or None
435 435
        servers = [dict(
b/kamaki/cli/commands/network.py
38 38
from kamaki.cli.command_tree import CommandTree
39 39
from kamaki.cli.errors import (
40 40
    CLIBaseUrlError, CLIInvalidArgument, raiseCLIError)
41
from kamaki.clients.cyclades import CycladesNetworkClient
41
from kamaki.clients.cyclades import CycladesNetworkClient, ClientError
42 42
from kamaki.cli.argument import (
43 43
    FlagArgument, ValueArgument, RepeatableArgument, IntArgument)
44 44
from kamaki.cli.commands import _command_init, errors, addLogSettings
45 45
from kamaki.cli.commands import (
46 46
    _optional_output_cmd, _optional_json, _name_filter, _id_filter)
47
from kamaki.cli.utils import filter_dicts_by_dict
48 47
from kamaki.cli.commands.cyclades import _service_wait
49 48

  
50 49

  
......
93 92
        else:
94 93
            raise CLIBaseUrlError(service='network')
95 94

  
95
    def _filter_by_user_id(self, nets):
96
        return [net for net in nets if net['user_id'] == self['user_id']] if (
97
            self['user_id']) else nets
98

  
96 99
    def main(self):
97 100
        self._run()
98 101

  
......
112 115
            'show only networks belonging to user with this id', '--user-id')
113 116
    )
114 117

  
115
    def _filter_by_user_id(self, nets):
116
        return filter_dicts_by_dict(nets, dict(user_id=self['user_id'])) if (
117
            self['user_id']) else nets
118

  
119 118
    @errors.generic.all
120 119
    @errors.cyclades.connection
121 120
    def _run(self):
122
        nets = self.client.list_networks()
121
        detail = bool(self['detail'] or self['user_id'])
122
        nets = self.client.list_networks(detail=detail)
123 123
        nets = self._filter_by_user_id(nets)
124 124
        nets = self._filter_by_name(nets)
125 125
        nets = self._filter_by_id(nets)
126
        if not self['detail']:
126
        if detail and not self['detail']:
127 127
            nets = [dict(
128 128
                id=n['id'], name=n['name'], links=n['links']) for n in nets]
129 129
        kwargs = dict()
......
376 376

  
377 377

  
378 378
@command(port_cmds)
379
class port_list(_init_network, _optional_json):
379
class port_list(_init_network, _optional_json, _name_filter, _id_filter):
380 380
    """List all ports"""
381 381

  
382
    arguments = dict(
383
        detail=FlagArgument('show detailed output', ('-l', '--details')),
384
        more=FlagArgument(
385
            'output results in pages (-n to set items per page, default 10)',
386
            '--more'),
387
        user_id=ValueArgument(
388
            'show only networks belonging to user with this id', '--user-id')
389
    )
390

  
382 391
    @errors.generic.all
383 392
    @errors.cyclades.connection
384 393
    def _run(self):
385
        net = self.client.list_ports()
386
        self._print(net)
394
        detail = bool(self['detail'] or self['user_id'])
395
        ports = self.client.list_ports(detail=detail)
396
        ports = self._filter_by_user_id(ports)
397
        ports = self._filter_by_name(ports)
398
        ports = self._filter_by_id(ports)
399
        if detail and not self['detail']:
400
            ports = [dict(
401
                id=p['id'], name=p['name'], links=p['links']) for p in ports]
402
        kwargs = dict()
403
        if self['more']:
404
            kwargs['out'] = StringIO()
405
            kwargs['title'] = ()
406
        self._print(ports, **kwargs)
407
        if self['more']:
408
            pager(kwargs['out'].getvalue())
387 409

  
388 410
    def main(self):
389 411
        super(self.__class__, self)._run()
......
397 419
    @errors.generic.all
398 420
    @errors.cyclades.connection
399 421
    def _run(self, port_id):
400
        net = self.client.get_port_details(port_id)
401
        self._print(net, self.print_dict)
422
        port = self.client.get_port_details(port_id)
423
        self._print(port, self.print_dict)
402 424

  
403 425
    def main(self, port_id):
404 426
        super(self.__class__, self)._run()
......
416 438
    @errors.generic.all
417 439
    @errors.cyclades.connection
418 440
    def _run(self, port_id):
441
        if self['wait']:
442
            status = self.client.get_port_details(port_id)['status']
419 443
        r = self.client.delete_port(port_id)
420 444
        if self['wait']:
421
            self._wait(r['id'], r['status'])
445
            try:
446
                self._wait(port_id, status)
447
            except ClientError as ce:
448
                if ce.status not in (404, ):
449
                    raise
450
                self.error('Port %s is deleted' % port_id)
422 451
        self._optional_output(r)
423 452

  
424 453
    def main(self, port_id):
......
459 488
            fixed_ips=fixed_ips)
460 489
        if self['wait']:
461 490
            self._wait(r['id'], r['status'])
462
        self._print(r, self.print_dict)
491
            r = self.client.get_port_details(r['id'])
492
        self._print([r])
463 493

  
464 494

  
465 495
@command(port_cmds)
......
612 642
    @errors.cyclades.network_id
613 643
    @errors.cyclades.server_id
614 644
    def _run(self, network_id, server_id):
645
        self.error('Creating a port to connect network %s with device %s' % (
646
            network_id, server_id))
615 647
        self.connect(network_id, server_id)
616 648

  
617 649
    def main(self, network_id, device_id):
618 650
        super(self.__class__, self)._run()
619
        self._run(network_id=network_id, device_id=device_id)
651
        self._run(network_id=network_id, server_id=device_id)
620 652

  
621 653

  
622 654
@command(network_cmds)
......
638 670
    @errors.cyclades.connection
639 671
    @errors.cyclades.network_id
640 672
    @errors.cyclades.server_id
641
    def _run(self, network_id, device_id):
642
        vm = self._cyclades_client().get_server_details(device_id)
643
        nets = [net for net in vm['attachments'] if net['network_id'] not in (
644
            'network_id', )]
645
        if not nets:
673
    def _run(self, network_id, server_id):
674
        vm = self._cyclades_client().get_server_details(server_id)
675
        ports = [port for port in vm['attachments'] if (
676
            port['network_id'] not in ('network_id', ))]
677
        if not ports:
646 678
            raiseCLIError('Network %s is not connected to device %s' % (
647
                network_id, device_id))
648
        for net in nets:
649
            self.client.port_delete(net['id'])
650
            self.error('Deleting this connection:')
651
            self.print_dict(net)
679
                network_id, server_id))
680
        for port in ports:
681
            if self['wait']:
682
                port['status'] = self.client.get_port_details(port['id'])[
683
                    'status']
684
            self.client.delete_port(port['id'])
685
            self.error('Deleting port %s:' % port['id'])
686
            self.print_dict(port)
652 687
            if self['wait']:
653
                self._wait(net['id'], net['status'])
688
                try:
689
                    self._wait(port['id'], port['status'])
690
                except ClientError as ce:
691
                    if ce.status not in (404, ):
692
                        raise
693
                    self.error('Port %s is deleted' % port['id'])
654 694

  
655 695
    def main(self, network_id, device_id):
656 696
        super(self.__class__, self)._run()
657
        self._run(network_id=network_id, device_id=device_id)
697
        self._run(network_id=network_id, server_id=device_id)
b/kamaki/clients/cyclades/__init__.py
58 58

  
59 59
        :param networks: (list of dicts) Networks to connect to, list this:
60 60
            "networks": [
61
                {"network": <network_uuid>},
62
                {"network": <network_uuid>, "fixed_ip": address},
61
                {"uuid": <network_uuid>},
62
                {"uuid": <network_uuid>, "fixed_ip": address},
63 63
                {"port": <port_id>}, ...]
64 64
            ATTENTION: Empty list is different to None. None means ' do not
65 65
            mention it', empty list means 'automatically get an ip'
......
231 231
        r = self.networks_post(json_data=req, success=201)
232 232
        return r.json['network']
233 233

  
234
    def list_ports(self, detail=None):
235
        path = path4url('ports', 'detail' if detail else '')
236
        r = self.get(path, success=200)
237
        return r.json['ports']
238

  
234 239
    def create_port(
235 240
            self, network_id,
236 241
            device_id=None, security_groups=None, name=None, fixed_ips=None):
b/kamaki/clients/network/rest_api.py
33 33

  
34 34
from kamaki.clients import Client
35 35
from kamaki.clients.utils import path4url
36
from json import dumps
37 36

  
38 37

  
39 38
class NetworkRestClient(Client):

Also available in: Unified diff