コード例 #1
0
ファイル: network.py プロジェクト: vgerak/kamaki
class port_list(_NetworkInit, OptionalOutput, NameFilter, IDFilter):
    """List all ports"""

    arguments = dict(detail=FlagArgument('show detailed output',
                                         ('-l', '--details')),
                     more=FlagArgument('output results in pages', '--more'),
                     user_id=ValueArgument(
                         'show only networks belonging to user with this id',
                         '--user-id'))

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        ports = self.client.list_ports()
        ports = self._filter_by_user_id(ports)
        ports = self._filter_by_name(ports)
        ports = self._filter_by_id(ports)
        if not self['detail']:
            ports = [dict(id=p['id'], name=p['name']) for p in ports]
        kwargs = dict()
        if self['more']:
            kwargs['out'] = StringIO()
            kwargs['title'] = ()
        self.print_(ports, **kwargs)
        if self['more']:
            pager(kwargs['out'].getvalue())

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #2
0
ファイル: astakos.py プロジェクト: vgerak/kamaki
class commission_issue(_AstakosInit, OptionalOutput):
    """Issue commissions as a json string (special privileges required)"""

    arguments = dict(uuid=ValueArgument('User UUID', '--uuid'),
                     source=ValueArgument('Commission source (ex system)',
                                          '--source'),
                     file_path=ValueArgument('File of provisions',
                                             '--provisions-file'),
                     description=ValueArgument('Commision description',
                                               '--description'),
                     force=FlagArgument('Force commission', '--force'),
                     accept=FlagArgument('Do not wait for verification',
                                         '--accept'))
    required = ('uuid', 'source', 'file_path')

    @errors.Generic.all
    @errors.Astakos.astakosclient
    def _run(self):
        try:
            with open(self['file_path']) as f:
                provisions = loads(f.read())
        except Exception as e:
            raise CLIError('Failed load a json dict from file %s' %
                           self['file_path'],
                           importance=2,
                           details=['%s' % e])
        self.print_(
            self.client.issue_one_commission(self['uuid'], self['source'],
                                             provisions, self['description']
                                             or '', self['force'],
                                             self['accept']))

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #3
0
class subnet_create(_NetworkInit, OptionalOutput):
    """Create a new subnet"""

    arguments = dict(
        name=ValueArgument('Subnet name', '--name'),
        allocation_pools=AllocationPoolArgument(
            'start_address,end_address of allocation pool (can be repeated)'
            ' e.g., --alloc-pool=123.45.67.1,123.45.67.8', '--alloc-pool'),
        gateway=ValueArgument('Gateway IP', '--gateway'),
        subnet_id=ValueArgument('The id for the subnet', '--id'),
        ipv6=FlagArgument('If set, IP version is set to 6, else 4', '--ipv6'),
        enable_dhcp=FlagArgument('Enable dhcp (default: off)', '--with-dhcp'),
        network_id=ValueArgument('Set the network ID', '--network-id'),
        cidr=ValueArgument('Set the CIDR', '--cidr'))
    required = ('network_id', 'cidr')

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        try:
            net = self.client.create_subnet(self['network_id'], self['cidr'],
                                            self['name'],
                                            self['allocation_pools'],
                                            self['gateway'], self['subnet_id'],
                                            self['ipv6'], self['enable_dhcp'])
        except ClientError as ce:
            if ce.status in (404, 400):
                self._network_exists(network_id=self['network_id'])
            raise
        self.print_(net, self.print_dict)

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #4
0
ファイル: network.py プロジェクト: vgerak/kamaki
class subnet_list(_NetworkInit, OptionalOutput, NameFilter, IDFilter):
    """List subnets
    Use filtering arguments (e.g., --name-like) to manage long server lists
    """

    arguments = dict(detail=FlagArgument('show detailed output',
                                         ('-l', '--details')),
                     more=FlagArgument('output results in pages', '--more'))

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        nets = self.client.list_subnets()
        nets = self._filter_by_name(nets)
        nets = self._filter_by_id(nets)
        if not self['detail']:
            nets = [
                dict(id=n['id'],
                     name=n['name'],
                     net='( of network %s )' % n['network_id']) for n in nets
            ]
            kwargs = dict(title=('id', 'name', 'net'))
        else:
            kwargs = dict()
        if self['more']:
            kwargs['out'] = StringIO()
            kwargs['title'] = ()
        self.print_(nets, **kwargs)
        if self['more']:
            pager('%s' % kwargs['out'].getvalue())

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #5
0
class flavor_list(_CycladesInit, OptionalOutput, NameFilter, IDFilter):
    """List available hardware flavors"""

    arguments = dict(
        detail=FlagArgument('show detailed output', ('-l', '--details')),
        limit=IntArgument('limit # of listed flavors', ('-n', '--number')),
        more=FlagArgument(
            'output results in pages (-n to set items per page, default 10)',
            '--more'),
        enum=FlagArgument('Enumerate results', '--enumerate'),
        ram=ValueArgument('filter by ram', ('--ram')),
        vcpus=ValueArgument('filter by number of VCPUs', ('--vcpus')),
        disk=ValueArgument('filter by disk size in GB', ('--disk')),
        disk_template=ValueArgument(
            'filter by disk_templace', ('--disk-template')),
        project_id=ValueArgument('filter by project ID', '--project'),
        is_public=FlagArgument('list only public flavors', '--public'),
    )

    def _apply_common_filters(self, flavors):
        common_filters = dict()
        if self['ram']:
            common_filters['ram'] = self['ram']
        if self['vcpus']:
            common_filters['vcpus'] = self['vcpus']
        if self['disk']:
            common_filters['disk'] = self['disk']
        if self['disk_template']:
            common_filters['SNF:disk_template'] = self['disk_template']
        return filter_dicts_by_dict(flavors, common_filters)

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        withcommons = self['ram'] or self['vcpus'] or (
            self['disk'] or self['disk_template'])
        detail = self['detail'] or withcommons
        flavors = self.client.list_flavors(
            detail, is_public=self['is_public'], project_id=self['project_id'])
        flavors = self._filter_by_name(flavors)
        flavors = self._filter_by_id(flavors)
        if withcommons:
            flavors = self._apply_common_filters(flavors)
        if not (self['detail'] or self['output_format']):
            remove_from_items(flavors, 'links')
        if detail and not self['detail']:
            for flv in flavors:
                for key in set(flv).difference(['id', 'name']):
                    flv.pop(key)
        kwargs = dict(out=StringIO(), title=()) if self['more'] else {}
        self.print_(flavors, with_enumeration=self['enum'], **kwargs)
        if self['more']:
            pager(kwargs['out'].getvalue())

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #6
0
class image_modify(_ImageInit):
    """Add / update metadata and properties for an image
    Preserves values not explicitly modified
    """

    arguments = dict(
        image_name=ValueArgument('Change name', '--name'),
        disk_format=ValueArgument('Change disk format', '--disk-format'),
        container_format=ValueArgument('Change container format',
                                       '--container-format'),
        status=ValueArgument('Change status', '--status'),
        publish=FlagArgument('Make the image public', '--public'),
        unpublish=FlagArgument('Make the image private', '--private'),
        property_to_set=KeyValueArgument(
            'set property in key=value form (can be repeated)',
            ('-p', '--property-set')),
        property_to_del=RepeatableArgument(
            'Delete property by key (can be repeated)', '--property-del'),
        member_ID_to_add=RepeatableArgument(
            'Add member to image (can be repeated)', '--member-add'),
        member_ID_to_remove=RepeatableArgument(
            'Remove a member (can be repeated)', '--member-del'),
    )
    required = [
        'image_name', 'disk_format', 'container_format', 'status', 'publish',
        'unpublish', 'property_to_set', 'member_ID_to_add',
        'member_ID_to_remove', 'property_to_del'
    ]

    @errors.Generic.all
    @errors.Image.connection
    @errors.Image.permissions
    @errors.Image.id
    def _run(self, image_id):
        for mid in (self['member_ID_to_add'] or []):
            self.client.add_member(image_id, mid)
        for mid in (self['member_ID_to_remove'] or []):
            self.client.remove_member(image_id, mid)
        meta = self.client.get_meta(image_id)
        for k, v in self['property_to_set'].items():
            meta['properties'][k.upper()] = v
        for k in (self['property_to_del'] or []):
            meta['properties'][k.upper()] = None
        self.client.update_image(image_id,
                                 name=self['image_name'],
                                 disk_format=self['disk_format'],
                                 container_format=self['container_format'],
                                 status=self['status'],
                                 public=self['publish']
                                 or (False if self['unpublish'] else None),
                                 **meta['properties'])

    def main(self, image_id):
        super(self.__class__, self)._run()
        self._run(image_id=image_id)
コード例 #7
0
ファイル: config.py プロジェクト: vgerak/kamaki
class config_list(CommandInit):
    """List all configuration options
    FAQ:
    Q: I haven't set any options!
    A: Defaults are used (override with /config set )
    Q: There are more options than I have set
    A: Default options remain if not explicitly replaced or deleted
    """

    arguments = dict(
        describe_options=FlagArgument(
            'List all option keys, if known to kamaki, including inactive '
            'ones', '--describe-option-keys'),
        with_description=FlagArgument('Add description to listed options',
                                      '--with-description'),
    )

    @errors.Generic.all
    def _run(self):
        if self['describe_options']:
            for group, options in DOCUMENTATION.items():
                self.writeln()
                for k, v in options.items():
                    self.writeln('%s.%s: \t%s' % (group, k, v[0]))
        else:
            for section in sorted(self.config.sections()):
                items = self.config.items(section)
                for key, val in sorted(items):
                    if section in ('cloud', ):
                        prefix = '%s.%s' % (section, key)
                        for k, v in val.items():
                            if self['with_description']:
                                try:
                                    self.writeln(
                                        '# %s' %
                                        DOCUMENTATION['cloud.<CLOUD NAME>'][k])
                                except KeyError:
                                    self.writeln('# unknown option')
                            self.writeln('%s.%s %s' % (prefix, k, v))
                        self.writeln()
                    else:
                        if self['with_description']:
                            try:
                                self.writeln('# %s' %
                                             DOCUMENTATION[section][key])
                            except KeyError:
                                self.writeln('# unknown option')
                        self.writeln('%s.%s %s' % (section, key, val))

    def main(self):
        self._run()
コード例 #8
0
ファイル: network.py プロジェクト: vgerak/kamaki
class port_create(_port_create):
    """Create a new port (== connect server to network)"""

    arguments = dict(
        name=ValueArgument('A human readable name', '--name'),
        security_group_id=RepeatableArgument(
            'Add a security group id (can be repeated)',
            ('-g', '--security-group')),
        subnet_id=ValueArgument(
            'Subnet id for fixed ips (used with --ip-address)', '--subnet-id'),
        ip_address=ValueArgument('IP address for subnet id', '--ip-address'),
        network_id=ValueArgument('Set the network ID', '--network-id'),
        device_id=ValueArgument(
            'The device is either a virtual server or a virtual router',
            '--device-id'),
        wait=FlagArgument('Wait port to be established', ('-w', '--wait')),
    )
    required = ('network_id', 'device_id')

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        self.connect(self['network_id'], self['device_id'])

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #9
0
ファイル: network.py プロジェクト: vgerak/kamaki
class network_create(_NetworkInit, OptionalOutput):
    """Create a new network (default type: MAC_FILTERED)"""

    arguments = dict(
        name=ValueArgument('Network name', '--name'),
        shared=FlagArgument(
            'Make network shared (special privileges required)', '--shared'),
        project_id=ValueArgument('Assign network to project', '--project-id'),
        network_type=NetworkTypeArgument(
            'Valid network types: %s' % (', '.join(NetworkTypeArgument.types)),
            '--type'))

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        try:
            net = self.client.create_network(self['network_type'],
                                             name=self['name'],
                                             shared=self['shared'],
                                             project_id=self['project_id'])
        except ClientError as ce:
            if self['project_id'] and ce.status in (400, 403, 404):
                self._project_id_exists(project_id=self['project_id'])
            raise
        self.print_(net, self.print_dict)

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #10
0
ファイル: config.py プロジェクト: vgerak/kamaki
class config_delete(CommandInit):
    """Delete a configuration option
    Default values are not removed by default. To alter this behavior in a
    session, use --default.
    """

    arguments = dict(default=FlagArgument(
        'Remove default value as well (persists until end of session)',
        '--default'))

    @errors.Generic.all
    def _run(self, option):
        section, sep, key = option.rpartition('.')
        section = section or 'global'
        prefix = 'cloud.'
        if section.startswith(prefix):
            cloud = section[len(prefix):]
            try:
                self.config.remove_from_cloud(cloud, key)
            except KeyError:
                raise CLIError('Field %s does not exist' % option)
        else:
            self.config.remove_option(section, key, self['default'])
        self.config.write()
        self.config.reload()

    def main(self, option):
        self._run(option)
コード例 #11
0
class image_info(_ImageInit, OptionalOutput):
    """Get image metadata"""

    arguments = dict(hashmap=FlagArgument(
        'Get image file hashmap instead of metadata', '--hashmap'), )

    @errors.Generic.all
    @errors.Image.connection
    @errors.Image.id
    def _run(self, image_id):
        meta = self.client.get_meta(image_id)
        if self['hashmap']:
            print meta['location']
            location = meta['location'].split('pithos://')[1]
            location = location.split('/')
            uuid, container = location[0], location[1]
            pithos = self.get_client(PithosClient, 'pithos')
            pithos.account, pithos.container = uuid, container
            path = '/'.join(location[2:])
            meta = pithos.get_object_hashmap(path)
        elif not self['output_format']:
            try:
                meta['owner'] += ' (%s)' % self._uuid2username(meta['owner'])
            except KeyError as ke:
                log.debug('%s' % ke)
            try:
                meta['size'] = format_size(meta['size'])
            except KeyError as ke:
                log.debug('%s' % ke)
        self.print_(meta, self.print_dict)

    def main(self, image_id):
        super(self.__class__, self)._run()
        self._run(image_id=image_id)
コード例 #12
0
ファイル: astakos.py プロジェクト: vgerak/kamaki
class project_list(_AstakosInit, OptionalOutput):
    """List all projects"""

    arguments = dict(
        details=FlagArgument('Show details', ('-l', '--details')),
        name=ValueArgument('Filter by name', ('--with-name', )),
        state=ValueArgument('Filter by state', ('--with-state', )),
        owner=ValueArgument('Filter by owner', ('--with-owner', )),
    )

    @errors.Generic.all
    @errors.Astakos.astakosclient
    def _run(self):
        r = self.client.get_projects(self['name'], self['state'],
                                     self['owner'])
        if not (self['details'] or self['output_format']):
            r = [
                dict(id=i['id'], name=i['name'], description=i['description'])
                for i in r
            ]
        self.print_(r)

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #13
0
class server_reboot(_CycladesInit, _ServerWait):
    """Reboot a virtual server"""

    arguments = dict(
        type=ValueArgument('SOFT or HARD - default: SOFT', ('--type')),
        wait=FlagArgument('Wait server to start again', ('-w', '--wait'))
    )

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.server_id
    def _run(self, server_id):
        hard_reboot = None
        if self['type']:
            if self['type'].lower() in ('soft', ):
                hard_reboot = False
            elif self['type'].lower() in ('hard', ):
                hard_reboot = True
            else:
                raise CLISyntaxError(
                    'Invalid reboot type %s' % self['type'],
                    importance=2, details=[
                        '--type values are either SOFT (default) or HARD'])

        self.client.reboot_server(int(server_id), hard_reboot)
        if self['wait']:
            self.wait_while(server_id, 'REBOOT')

    def main(self, server_id):
        super(self.__class__, self)._run()
        self._run(server_id=server_id)
コード例 #14
0
ファイル: network.py プロジェクト: vgerak/kamaki
class network_connect(_port_create):
    """Connect a network with a device (server or router)"""

    arguments = dict(
        name=ValueArgument('A human readable name for the port', '--name'),
        security_group_id=RepeatableArgument(
            'Add a security group id (can be repeated)',
            ('-g', '--security-group')),
        subnet_id=ValueArgument(
            'Subnet id for fixed ips (used with --ip-address)', '--subnet-id'),
        ip_address=ValueArgument(
            'IP address for subnet id (used with --subnet-id', '--ip-address'),
        wait=FlagArgument('Wait network to connect', ('-w', '--wait')),
        device_id=RepeatableArgument(
            'Connect this device to the network (can be repeated)',
            '--device-id'))
    required = ('device_id', )

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.network_id
    def _run(self, network_id, server_id):
        self.error('Creating a port to connect network %s with device %s' %
                   (network_id, server_id))
        try:
            self.connect(network_id, server_id)
        except ClientError as ce:
            if ce.status in (400, 404):
                self._server_exists(server_id=server_id)
            raise

    def main(self, network_id):
        super(self.__class__, self)._run()
        for sid in self['device_id']:
            self._run(network_id=network_id, server_id=sid)
コード例 #15
0
ファイル: network.py プロジェクト: vgerak/kamaki
class ip_detach(_NetworkInit, _PortWait, OptionalOutput):
    """Detach an IP from a virtual server"""

    arguments = dict(wait=FlagArgument('Wait until IP is detached',
                                       ('-w', '--wait')), )

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self, ip_or_ip_id):
        for ip in self.client.list_floatingips():
            if ip_or_ip_id in (ip['floating_ip_address'], ip['id']):
                if not ip['port_id']:
                    raiseCLIError('IP %s is not attached' % ip_or_ip_id)
                self.error('Deleting port %s:' % ip['port_id'])
                self.client.delete_port(ip['port_id'])
                if self['wait']:
                    port_status = self.client.get_port_details(
                        ip['port_id'])['status']
                    try:
                        self.wait_while(ip['port_id'], port_status)
                    except ClientError as ce:
                        if ce.status not in (404, ):
                            raise
                        self.error('Port %s is deleted' % ip['port_id'])
                return
        raiseCLIError('IP or IP id %s not found' % ip_or_ip_id)

    def main(self, ip_or_ip_id):
        super(self.__class__, self)._run()
        self._run(ip_or_ip_id)
コード例 #16
0
ファイル: cyclades.py プロジェクト: dimara/kamaki
class server_delete(_CycladesInit, _ServerWait):
    """Delete a virtual server"""

    arguments = dict(
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait')),
        cluster=FlagArgument(
            '(DANGEROUS) Delete all VMs with names starting with the cluster '
            'prefix. Do not use it if unsure. Syntax:'
            ' kamaki server delete --cluster CLUSTER_PREFIX', '--cluster'))

    def _server_ids(self, server_var):
        if self['cluster']:
            return [
                s['id'] for s in self.client.list_servers()
                if (s['name'].startswith(server_var))
            ]

        return [
            server_var,
        ]

    @errors.Cyclades.server_id
    def _delete_server(self, server_id):
        if self['wait']:
            details = self.client.get_server_details(server_id)
            status = details['status']

        self.client.delete_server(server_id)
        if self['wait']:
            self.wait(server_id, status)

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self, server_var):
        deleted_vms = []
        for server_id in self._server_ids(server_var):
            self._delete_server(server_id=server_id)
            deleted_vms.append(server_id)
        if self['cluster']:
            dlen = len(deleted_vms)
            self.error('%s virtual server %s deleted' %
                       (dlen, '' if dlen == 1 else 's'))

    def main(self, server_id_or_cluster_prefix):
        super(self.__class__, self)._run()
        self._run(server_id_or_cluster_prefix)
コード例 #17
0
ファイル: network.py プロジェクト: vgerak/kamaki
class network_list(_NetworkInit, OptionalOutput, NameFilter, IDFilter):
    """List networks
    Use filtering arguments (e.g., --name-like) to manage long lists
    """

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

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        nets = self.client.list_networks(detail=True)
        nets = self._filter_by_user_id(nets)
        nets = self._filter_by_name(nets)
        nets = self._filter_by_id(nets)
        if not self['detail']:
            nets = [
                dict(id=n['id'],
                     name=n['name'],
                     public='( %s )' %
                     ('public' if (n.get('public', None)) else 'private'))
                for n in nets
            ]
            kwargs = dict(title=('id', 'name', 'public'))
        else:
            kwargs = dict()
        if self['more']:
            kwargs['out'] = StringIO()
            kwargs['title'] = ()
        self.print_(nets, **kwargs)
        if self['more']:
            pager(kwargs['out'].getvalue())

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #18
0
ファイル: cyclades.py プロジェクト: dimara/kamaki
class server_info(_CycladesInit, OptionalOutput):
    """Detailed information on a Virtual Machine"""

    arguments = dict(nics=FlagArgument(
        'Show only the network interfaces of this virtual server', '--nics'),
                     stats=FlagArgument('Get URLs for server statistics',
                                        '--stats'),
                     diagnostics=FlagArgument('Diagnostic information',
                                              '--diagnostics'))

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.server_id
    def _run(self, server_id):
        if self['nics']:
            self.print_(self.client.get_server_nics(server_id),
                        self.print_dict)
        elif self['stats']:
            self.print_(self.client.get_server_stats(server_id),
                        self.print_dict)
        elif self['diagnostics']:
            self.print_(self.client.get_server_diagnostics(server_id))
        else:
            vm = self.client.get_server_details(server_id)
            self.print_(vm, self.print_dict)

    def main(self, server_id):
        super(self.__class__, self)._run()
        choose_one = ('nics', 'stats', 'diagnostics')
        count = len([a for a in choose_one if self[a]])
        if count > 1:
            raise CLIInvalidArgument(
                'Invalid argument combination',
                details=[
                    'Arguments %s cannot be used simultaneously' %
                    ', '.join([self.arguments[a].lvalue for a in choose_one])
                ])
        self._run(server_id=server_id)
コード例 #19
0
class keypair_upload(_CycladesInit, OptionalOutput):
    """Upload or update a keypair"""

    arguments = dict(
        key_name=ValueArgument(
            'The name of the key',
            '--key-name'),
        public_key=ValueArgument(
            'The contents of the keypair(the public key)',
            '--public-key'),
        force=FlagArgument(
            '(DANGEROUS) Force keypair creation. This option'
            ' will delete an existing keypair in case of a name'
            'conflict. Do not use it if unsure.',
            ('-f', '--force')
        )
    )

    required = ['public_key']

    @errors.Generic.all
    @errors.Keypair.connection
    def _run(self):
        key_name = self['key_name']
        if key_name is None:
            uniq = str(uuid.uuid4())[:8]
            key_name = 'kamaki-key_autogen_{:%m_%d_%H_%M_%S_%f}_{uniq}'.format(
                datetime.now(), uniq=uniq)
        try:
            keypair = self.client.create_key(
                key_name=key_name, public_key=self['public_key'])
        except ClientError as e:
            if e.status == 409 and self['force']:
                self.client.delete_keypair(key_name)
                keypair = self.client.create_key(
                    key_name=key_name, public_key=self['public_key'])
            else:
                help_command = ('kamaki keypair upload -f --key-name %s '
                                '--public-key %s'
                                % (key_name, self['public_key']))
                self._err.write('A keypair with that name already exists. '
                                'To override the conflicting key you can use '
                                'the following command:\n%s\n' %
                                (help_command))
                raise e
        self.print_(keypair, self.print_dict)

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #20
0
ファイル: astakos.py プロジェクト: vgerak/kamaki
class quota_list(_AstakosInit, OptionalOutput):
    """Show user quotas"""

    _to_format = set(['cyclades.disk', 'pithos.diskspace', 'cyclades.ram'])
    arguments = dict(resource=ValueArgument('Filter by resource',
                                            '--resource'),
                     project_id=ValueArgument('Filter by project',
                                              '--project-id'),
                     bytes=FlagArgument('Show data size in bytes', '--bytes'))

    def _print_quotas(self, quotas, *args, **kwargs):
        if not self['bytes']:
            for project_id, resources in quotas.items():
                for r in self._to_format.intersection(resources):
                    resources[r] = dict([(k, format_size(v))
                                         for k, v in resources[r].items()])
        self.print_dict(quotas, *args, **kwargs)

    @errors.Generic.all
    @errors.Astakos.astakosclient
    def _run(self):
        quotas = self.client.get_quotas()
        if self['project_id']:
            try:
                resources = quotas[self['project_id']]
            except KeyError:
                raise CLIError('User not assigned to project with id "%s" ' %
                               (self['project_id']),
                               details=[
                                   'See all quotas of current user:'******'  kamaki quota list'
                               ])
            quotas = {self['project_id']: resources}
        if self['resource']:
            d = dict()
            for project_id, resources in quotas.items():
                r = dict()
                for resource, value in resources.items():
                    if (resource.startswith(self['resource'])):
                        r[resource] = value
                if r:
                    d[project_id] = r
            if not d:
                raise CLIError('Resource "%s" not found' % self['resource'])
            quotas = d
        self.print_(quotas, self._print_quotas)

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #21
0
ファイル: network.py プロジェクト: vgerak/kamaki
class network_disconnect(_NetworkInit, _PortWait, OptionalOutput):
    """Disconnect a network from a device"""

    arguments = dict(
        wait=FlagArgument('Wait network to disconnect', ('-w', '--wait')),
        device_id=RepeatableArgument(
            'Disconnect device from the network (can be repeated)',
            '--device-id'))
    required = ('device_id', )

    @errors.Cyclades.server_id
    def _get_vm(self, server_id):
        return self._get_compute_client().get_server_details(server_id)

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.network_id
    def _run(self, network_id, server_id):
        vm = self._get_vm(server_id=server_id)
        ports = [
            port for port in vm['attachments']
            if (port['network_id'] in (network_id, ))
        ]
        if not ports:
            raiseCLIError('Device %s has no network %s attached' %
                          (server_id, network_id),
                          importance=2,
                          details=[
                              'To get device networking',
                              '  kamaki server info %s --nics' % server_id
                          ])
        for port in ports:
            if self['wait']:
                port['status'] = self.client.get_port_details(
                    port['id'])['status']
            self.client.delete_port(port['id'])
            self.error('Deleting port %s (net-id: %s, device-id: %s):' %
                       (port['id'], network_id, server_id))
            if self['wait']:
                try:
                    self.wait_while(port['id'], port['status'])
                except ClientError as ce:
                    if ce.status not in (404, ):
                        raise
                    self.error('Port %s is deleted' % port['id'])

    def main(self, network_id):
        super(self.__class__, self)._run()
        for sid in self['device_id']:
            self._run(network_id=network_id, server_id=sid)
コード例 #22
0
ファイル: astakos.py プロジェクト: dimara/kamaki
class user_list(_AstakosInit, OptionalOutput):
    """List (cached) session users"""

    arguments = dict(
        detail=FlagArgument('Detailed listing', ('-l', '--detail'))
    )

    @errors.Generic.all
    @errors.Astakos.astakosclient
    def _run(self):
        self.print_([u if self['detail'] else (dict(
            id=u['id'], name=u['name'])) for u in self.astakos.list_users()])

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #23
0
ファイル: network.py プロジェクト: vgerak/kamaki
class ip_attach(_port_create):
    """Attach an IP on a virtual server"""

    arguments = dict(name=ValueArgument('A human readable name for the port',
                                        '--name'),
                     security_group_id=RepeatableArgument(
                         'Add a security group id (can be repeated)',
                         ('-g', '--security-group')),
                     subnet_id=ValueArgument('Subnet id', '--subnet-id'),
                     wait=FlagArgument('Wait IP to be attached',
                                       ('-w', '--wait')),
                     server_id=ValueArgument('Server to attach to this IP',
                                             '--server-id'))
    required = ('server_id', )

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self, ip_or_ip_id):
        netid = None
        for ip in self.client.list_floatingips():
            if ip_or_ip_id in (ip['floating_ip_address'], ip['id']):
                netid = ip['floating_network_id']
                iparg = ValueArgument(parsed_name='--ip')
                iparg.value = ip['floating_ip_address']
                self.arguments['ip_address'] = iparg
                break
        if netid:
            server_id = self['server_id']
            self.error('Creating a port to attach IP %s to server %s' %
                       (ip_or_ip_id, server_id))
            try:
                self.connect(netid, server_id)
            except ClientError as ce:
                self.error('Failed to connect network %s with server %s' %
                           (netid, server_id))
                if ce.status in (400, 404):
                    self._server_exists(server_id=server_id)
                    self._network_exists(network_id=netid)
                raise
        else:
            raiseCLIError('%s does not match any reserved IPs or IP ids' %
                          ip_or_ip_id,
                          details=errors.Cyclades.about_ips)

    def main(self, ip_or_ip_id):
        super(self.__class__, self)._run()
        self._run(ip_or_ip_id=ip_or_ip_id)
コード例 #24
0
ファイル: cyclades.py プロジェクト: dimara/kamaki
class server_shutdown(_CycladesInit, _ServerWait):
    """Shutdown an active virtual server"""

    arguments = dict(
        wait=FlagArgument('Wait server to be destroyed', ('-w', '--wait')))

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.server_id
    def _run(self, server_id):
        status = self.assert_not_in_status(server_id, 'STOPPED')
        self.client.shutdown_server(int(server_id))
        if self['wait']:
            self.wait(server_id, status)

    def main(self, server_id):
        super(self.__class__, self)._run()
        self._run(server_id=server_id)
コード例 #25
0
class server_start(_CycladesInit, _ServerWait):
    """Start an existing virtual server"""

    arguments = dict(
        wait=FlagArgument('Wait server to start', ('-w', '--wait'))
    )

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.server_id
    def _run(self, server_id):
        status = self.assert_not_in_status(server_id, 'ACTIVE')
        self.client.start_server(int(server_id))
        if self['wait']:
            self.wait_while(server_id, status)

    def main(self, server_id):
        super(self.__class__, self)._run()
        self._run(server_id=server_id)
コード例 #26
0
class keypair_list(_CycladesInit, OptionalOutput, NameFilter):
    """List all keypairs"""

    arguments = dict(
        detail=FlagArgument('show detailed output', ('-l', '--detail')),
    )

    @errors.Generic.all
    @errors.Keypair.connection
    def _run(self):
        keypairs = self.client.list_keypairs()
        keypairs = [k['keypair'] for k in keypairs]
        if not self['detail']:
            remove_from_items(keypairs, 'public_key')
        keypairs = self._filter_by_name(keypairs)
        self.print_(keypairs)

    def main(self):
        super(self.__class__, self)._run()
        self._run()
コード例 #27
0
ファイル: network.py プロジェクト: vgerak/kamaki
class port_delete(_NetworkInit, _PortWait):
    """Delete a port (== disconnect server from network)"""

    arguments = dict(
        wait=FlagArgument('Wait port to be deleted', ('-w', '--wait')))

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.port_id
    def _run(self, port_id):
        if self['wait']:
            status = self.client.get_port_details(port_id)['status']
        self.client.delete_port(port_id)
        if self['wait']:
            try:
                self.wait_while(port_id, status)
            except ClientError as ce:
                if ce.status not in (404, ):
                    raise
                self.error('Port %s is deleted' % port_id)

    def main(self, port_id):
        super(self.__class__, self)._run()
        self._run(port_id=port_id)
コード例 #28
0
ファイル: astakos.py プロジェクト: vgerak/kamaki
class project_modify(_AstakosInit, OptionalOutput):
    """Modify properties of a project"""

    __doc__ += _project_specs
    arguments = dict(
        specs_path=ValueArgument('Specification file (contents in json)',
                                 '--spec-file'),
        project_name=ValueArgument('Name the project', '--name'),
        owner_uuid=ValueArgument('Project owner', '--owner'),
        homepage_url=ValueArgument('Project homepage', '--homepage'),
        description=ValueArgument('Describe the project', '--description'),
        max_members=IntArgument('Maximum subscribers', '--max-members'),
        private=FlagArgument('Make the project private', '--private'),
        public=FlagArgument('Make the project public', '--public'),
        start_date=DateArgument('When to start the project', '--start-date'),
        end_date=DateArgument('When to end the project', '--end-date'),
        join_policy=PolicyArgument(
            'Set join policy (%s)' % ', '.join(PolicyArgument.policies),
            '--join-policy'),
        leave_policy=PolicyArgument(
            'Set leave policy (%s)' % ', '.join(PolicyArgument.policies),
            '--leave-policy'),
        resource_capacities=ProjectResourceArgument(
            'Set the member and project capacities for resources (repeatable) '
            'e.g., --resource cyclades.cpu=1,5    means "members will have at '
            'most 1 cpu but the project will have at most 5"       To see all '
            'resources:   kamaki resource list', '--resource'))
    required = [
        'specs_path', 'owner_uuid', 'homepage_url', 'description', 'public',
        'private', 'project_name', 'start_date', 'end_date', 'join_policy',
        'leave_policy', 'resource_capacities', 'max_members'
    ]

    @errors.Generic.all
    @errors.Astakos.astakosclient
    @errors.Astakos.project_id
    @apply_notification
    def _run(self, project_id):
        specs = dict()
        if self['specs_path']:
            with open(abspath(self['specs_path'])) as f:
                specs = load(f)
        for key, arg in (('name', self['project_name']),
                         ('owner', self['owner_uuid']), ('homepage',
                                                         self['homepage_url']),
                         ('description',
                          self['description']), ('max_members',
                                                 self['max_members']),
                         ('start_date',
                          self.arguments['start_date'].isoformat),
                         ('end_date', self.arguments['end_date'].isoformat),
                         ('join_policy',
                          self['join_policy']), ('leave_policy',
                                                 self['leave_policy']),
                         ('resources', self['resource_capacities'])):
            if arg:
                specs[key] = arg
        private = self['private'] or (False if self['public'] else None)
        if private is not None:
            self['private'] = private

        self.print_(self.client.modify_project(project_id, specs),
                    self.print_dict)

    def main(self, project_id):
        super(self.__class__, self)._run()
        if self['private'] and self['public']:
            a = self.arguments
            raise CLIInvalidArgument(
                'Invalid argument combination',
                details=[
                    'Arguments %s and %s are mutually exclussive' %
                    (a['private'].lvalue, a['public'].lvalue)
                ])
        self._run(project_id=project_id)
コード例 #29
0
class server_create(_CycladesInit, OptionalOutput, _ServerWait):
    """Create a server (aka Virtual Machine)"""

    arguments = dict(
        server_name=ValueArgument('The name of the new server', '--name'),
        flavor_id=IntArgument('The ID of the flavor', '--flavor-id'),
        image_id=ValueArgument('The ID of the image', '--image-id'),
        key_name=ValueArgument('The name of the ssh key to add the server',
                               '--key-name'),
        personality=PersonalityArgument(
            (80 * ' ').join(howto_personality), ('-p', '--personality')),
        wait=FlagArgument('Wait server to build', ('-w', '--wait')),
        cluster_size=IntArgument(
            'Create a cluster of servers of this size. In this case, the name'
            'parameter is the prefix of each server in the cluster (e.g.,'
            'srv1, srv2, etc.',
            '--cluster-size'),
        max_threads=IntArgument(
            'Max threads in cluster mode (default 1)', '--threads'),
        network_configuration=NetworkArgument(
            'Connect server to network: [id=]NETWORK_ID[,[ip=]IP]        . '
            'Use only NETWORK_ID for private networks.        . '
            'Use NETWORK_ID,[ip=]IP for networks with IP.        . '
            'Can be repeated, mutually exclussive with --no-network',
            '--network'),
        no_network=FlagArgument(
            'Do not create any network NICs on the server.        . '
            'Mutually exclusive to --network        . '
            'If neither --network or --no-network are used, the default '
            'network policy is applied. These policies are set on the cloud, '
            'so kamaki is oblivious to them',
            '--no-network'),
        project_id=ValueArgument('Assign server to project', '--project-id'),
        metadata=KeyValueArgument(
            'Add custom metadata in key=value form (can be repeated). '
            'Overwrites metadata defined otherwise (i.e., image).',
            ('-m', '--metadata'))
    )
    required = ('server_name', 'flavor_id', 'image_id')

    @errors.Cyclades.cluster_size
    def _create_cluster(self, prefix, flavor_id, image_id, size):
        networks = self['network_configuration'] or (
            [] if self['no_network'] else None)
        servers = [dict(
            name='%s%s' % (prefix, i if size > 1 else ''),
            flavor_id=flavor_id,
            image_id=image_id,
            key_name=self['key_name'],
            project_id=self['project_id'],
            personality=self['personality'],
            metadata=self['metadata'],
            networks=networks) for i in range(1, 1 + size)]
        if size == 1:
            return [self.client.create_server(**servers[0])]
        self.client.MAX_THREADS = int(self['max_threads'] or 1)
        try:
            r = self.client.async_run(self.client.create_server, servers)
            return r
        except Exception as e:
            if size == 1:
                raise e
            try:
                requested_names = [s['name'] for s in servers]
                spawned_servers = [dict(
                    name=s['name'],
                    id=s['id']) for s in self.client.list_servers() if (
                        s['name'] in requested_names)]
                self.error('Failed to build %s servers' % size)
                self.error('Found %s matching servers:' % len(spawned_servers))
                self.print_(spawned_servers, out=self._err)
                self.error('Check if any of these servers should be removed')
            except Exception as ne:
                self.error('Error (%s) while notifying about errors' % ne)
            finally:
                raise e

    def _get_network_client(self):
        network = getattr(self, '_network_client', None)
        if not network:
            net_URL = self.astakos.get_endpoint_url(
                CycladesNetworkClient.service_type)
            network = CycladesNetworkClient(net_URL, self.client.token)
            self._network_client = network
        return network

    @errors.Image.id
    def _image_exists(self, image_id):
        self.client.get_image_details(image_id)

    @errors.Cyclades.network_id
    def _network_exists(self, network_id):
        network = self._get_network_client()
        network.get_network_details(network_id)

    def _ip_ready(self, ip, network_id, cerror):
        network = self._get_network_client()
        ips = [fip for fip in network.list_floatingips() if (
            fip['floating_ip_address'] == ip)]
        if not ips:
            msg = 'IP %s not available for current user' % ip
            raise CLIError(cerror, details=[msg] + errors.Cyclades.about_ips)
        ipnet, ipvm = ips[0]['floating_network_id'], ips[0]['instance_id']
        if getattr(cerror, 'status', 0) in (409, ):
            msg = ''
            if ipnet != network_id:
                msg = 'IP %s belong to network %s, not %s' % (
                    ip, ipnet, network_id)
            elif ipvm:
                msg = 'IP %s is already used by device %s' % (ip, ipvm)
            if msg:
                raise CLIError(cerror, details=[
                    msg,
                    'To get details on IP',
                    '  kamaki ip info %s' % ip] + errors.Cyclades.about_ips)

    @errors.Generic.all
    @errors.Cyclades.connection
    def _run(self):
        try:
            for r in self._create_cluster(
                    self['server_name'], self['flavor_id'], self['image_id'],
                    size=self['cluster_size'] or 1):
                if not r:
                    self.error('Create %s: server response was %s' % (
                        self['server_name'], r))
                    continue
                self.print_(r, self.print_dict)
                if self['wait']:
                    self.wait_while(r['id'], r['status'] or 'BUILD')
                self.writeln(' ')
        except ClientError as ce:
            if ce.status in (404, 400):
                self._flavor_exists(flavor_id=self['flavor_id'])
                self._image_exists(image_id=self['image_id'])
            if ce.status in (404, 400, 409):
                for net in self['network_configuration'] or []:
                    self._network_exists(network_id=net['uuid'])
                    if 'fixed_ip' in net:
                        self._ip_ready(net['fixed_ip'], net['uuid'], ce)
            if self['project_id'] and ce.status in (400, 403, 404):
                self._project_id_exists(project_id=self['project_id'])
            raise

    def main(self):
        super(self.__class__, self)._run()
        if self['no_network'] and self['network_configuration']:
            raise CLIInvalidArgument(
                'Invalid argument combination', importance=2, details=[
                    'Arguments %s and %s are mutually exclusive' % (
                        self.arguments['no_network'].lvalue,
                        self.arguments['network_configuration'].lvalue)])
        self._run()
コード例 #30
0
class server_list(_CycladesInit, OptionalOutput, NameFilter, IDFilter):
    """List virtual servers accessible by user
    Use filtering arguments (e.g., --name-like) to manage long server lists
    """

    arguments = dict(
        detail=FlagArgument('show detailed output', ('-l', '--details')),
        since=DateArgument(
            'show only items modified since date (\'H:M:S YYYY-mm-dd\') '
            'Can look back up to a limit (POLL_TIME) defined on service-side',
            '--since'),
        limit=IntArgument(
            'limit number of listed virtual servers', ('-n', '--number')),
        more=FlagArgument(
            'output results in pages (-n to set items per page, default 10)',
            '--more'),
        enum=FlagArgument('Enumerate results', '--enumerate'),
        flavor_id=ValueArgument('filter by flavor id', ('--flavor-id')),
        image_id=ValueArgument('filter by image id', ('--image-id')),
        user_id=ValueArgument('filter by user id', ('--user-id')),
        user_name=ValueArgument('filter by user name', ('--user-name')),
        status=ValueArgument(
            'filter by status (ACTIVE, STOPPED, REBOOT, ERROR, etc.)',
            ('--status')),
        meta=KeyValueArgument('filter by metadata key=values', ('--metadata')),
        meta_like=KeyValueArgument(
            'print only if in key=value, the value is part of actual value',
            ('--metadata-like')),
    )

    def _add_user_name(self, servers):
        uuids = self._uuids2usernames(list(set(
            [srv['user_id'] for srv in servers])))
        for srv in servers:
            srv['user_id'] += ' (%s)' % uuids[srv['user_id']]
        return servers

    def _apply_common_filters(self, servers):
        common_filters = dict()
        if self['status']:
            common_filters['status'] = self['status']
        if self['user_id'] or self['user_name']:
            uuid = self['user_id'] or self._username2uuid(self['user_name'])
            common_filters['user_id'] = uuid
        return filter_dicts_by_dict(servers, common_filters)

    def _filter_by_image(self, servers):
        iid = self['image_id']
        return [srv for srv in servers if srv['image']['id'] == iid]

    def _filter_by_flavor(self, servers):
        fid = self['flavor_id']
        return [srv for srv in servers if (
            '%s' % srv['flavor']['id'] == '%s' % fid)]

    def _filter_by_metadata(self, servers):
        new_servers = []
        for srv in servers:
            if 'metadata' not in srv:
                continue
            meta = [dict(srv['metadata'])]
            if self['meta']:
                meta = filter_dicts_by_dict(meta, self['meta'])
            if meta and self['meta_like']:
                meta = filter_dicts_by_dict(
                    meta, self['meta_like'], exact_match=False)
            if meta:
                new_servers.append(srv)
        return new_servers

    @errors.Generic.all
    @errors.Cyclades.connection
    @errors.Cyclades.date
    def _run(self):
        withimage = bool(self['image_id'])
        withflavor = bool(self['flavor_id'])
        withmeta = bool(self['meta'] or self['meta_like'])
        withcommons = bool(
            self['status'] or self['user_id'] or self['user_name'])
        detail = self['detail'] or (
            withimage or withflavor or withmeta or withcommons)
        ch_since = self.arguments['since'].isoformat if self['since'] else None
        servers = list(self.client.list_servers(detail, ch_since) or [])

        servers = self._filter_by_name(servers)
        servers = self._filter_by_id(servers)
        servers = self._apply_common_filters(servers)
        if withimage:
            servers = self._filter_by_image(servers)
        if withflavor:
            servers = self._filter_by_flavor(servers)
        if withmeta:
            servers = self._filter_by_metadata(servers)

        if detail and self['detail']:
            pass
        else:
            for srv in servers:
                for key in set(srv).difference(['id', 'name']):
                    srv.pop(key)

        kwargs = dict(with_enumeration=self['enum'])
        if self['more']:
            codecinfo = codecs.lookup('utf-8')
            kwargs['out'] = codecs.StreamReaderWriter(
                cStringIO.StringIO(),
                codecinfo.streamreader,
                codecinfo.streamwriter)
            kwargs['title'] = ()
        if self['limit']:
            servers = servers[:self['limit']]
        self.print_(servers, **kwargs)
        if self['more']:
            pager(kwargs['out'].getvalue())

    def main(self):
        super(self.__class__, self)._run()
        self._run()