Revision cc5da5a5

b/docs/commands.rst
280 280
    create    Reserve an IP on a network
281 281
    list      List reserved floating IPs
282 282
    delete    Unreserve an IP (also delete the port, if attached)
283
    attach    Attach an IP on a virtual server
284
    detach    Detach an IP from a virtual server
283 285

  
284 286
port (Network/Cyclades)
285 287
-----------------------
b/kamaki/cli/commands/network.py
482 482

  
483 483
    def connect(self, network_id, device_id):
484 484
        fixed_ips = [dict(ip_address=self['ip_address'])] if (
485
            self['subnet_id']) else None
485
            self['ip_address']) else None
486 486
        if fixed_ips and self['subnet_id']:
487 487
            fixed_ips[0]['subnet_id'] = self['subnet_id']
488 488
        r = self.client.create_port(
......
592 592
    arguments = dict(
593 593
        network_id=ValueArgument(
594 594
            'The network to preserve the IP on', '--network-id'),
595
        ip_address=ValueArgument('Allocate a specific IP address', '--address')
595
        ip_address=ValueArgument('Allocate an IP address', '--address')
596 596
    )
597 597
    required = ('network_id', )
598 598

  
......
622 622
        self._run(ip_id=ip_id)
623 623

  
624 624

  
625
@command(ip_cmds)
626
class ip_attach(_port_create):
627
    """Attach an IP on a virtual server"""
628

  
629
    arguments = dict(
630
        name=ValueArgument('A human readable name for the port', '--name'),
631
        security_group_id=RepeatableArgument(
632
            'Add a security group id (can be repeated)',
633
            ('-g', '--security-group')),
634
        subnet_id=ValueArgument('Subnet id', '--subnet-id'),
635
        wait=FlagArgument('Wait IP to be attached', ('-w', '--wait')),
636
        server_id=ValueArgument(
637
            'Server to attach to this IP', '--server-id')
638
    )
639
    required = ('server_id', )
640

  
641
    @errors.generic.all
642
    @errors.cyclades.connection
643
    @errors.cyclades.server_id
644
    def _run(self, ip_address, server_id):
645
        netid = None
646
        for ip in self.client.list_floatingips():
647
            if ip['floating_ip_address'] == ip_address:
648
                netid = ip['floating_network_id']
649
                iparg = ValueArgument(parsed_name='--ip')
650
                iparg.value = ip_address
651
                self.arguments['ip_address'] = iparg
652
                break
653
        if netid:
654
            self.error('Creating a port to attach IP %s to server %s' % (
655
                ip_address, server_id))
656
            self.connect(netid, server_id)
657
        else:
658
            raiseCLIError(
659
                'IP address %s does not match any reserved IPs' % ip_address,
660
                details=[
661
                    'To reserve an IP:', '  [kamaki] ip create',
662
                    'To see all reserved IPs:', '  [kamaki] ip list'])
663

  
664
    def main(self, ip_address):
665
        super(self.__class__, self)._run()
666
        self._run(ip_address=ip_address, server_id=self['server_id'])
667

  
668

  
669
@command(ip_cmds)
670
class ip_detach(_init_network, _port_wait, _optional_json):
671
    """Detach an IP from a virtual server"""
672

  
673
    arguments = dict(
674
        wait=FlagArgument('Wait network to disconnect', ('-w', '--wait')),
675
    )
676

  
677
    @errors.generic.all
678
    @errors.cyclades.connection
679
    def _run(self, ip_address):
680
        for ip in self.client.list_floatingips():
681
            if ip['floating_ip_address'] == ip_address:
682
                if not ip['port_id']:
683
                    raiseCLIError('IP %s is not attached' % ip_address)
684
                self.error('Deleting port %s:' % ip['port_id'])
685
                self.client.delete_port(ip['port_id'])
686
                if self['wait']:
687
                    port_status = self.client.get_port_details(ip['port_id'])[
688
                        'status']
689
                    try:
690
                        self._wait(ip['port_id'], port_status)
691
                    except ClientError as ce:
692
                        if ce.status not in (404, ):
693
                            raise
694
                        self.error('Port %s is deleted' % ip['port_id'])
695
                return
696
        raiseCLIError('IP %s not found' % ip_address)
697

  
698
    def main(self, ip_address):
699
        super(self.__class__, self)._run()
700
        self._run(ip_address)
701

  
702

  
625 703
#  Warn users for some importand changes
626 704

  
627 705
@command(network_cmds)

Also available in: Unified diff