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()
class IDFilter(object): if_arguments = dict( id=ValueArgument('filter by id', '--id'), id_pref=ValueArgument('filter by id prefix (case insensitive)', '--id-prefix'), id_suff=ValueArgument('filter by id suffix (case insensitive)', '--id-suffix'), id_like=ValueArgument( 'print only if id contains this (case insensitive)', '--id-like')) def _non_exact_id_filter(self, items): np, ns, nl = self['id_pref'], self['id_suff'], self['id_like'] return [ item for item in items if ((not np) or ('%s' % item['id']).lower().startswith(np.lower())) and ((not ns) or ('%s' % item['id']).lower().endswith(ns.lower())) and ((not nl) or nl.lower() in ('%s' % item['id']).lower()) ] def _exact_id_filter(self, items): return filter_dicts_by_dict(items, dict( id=self['id'])) if (self['id']) else items def _filter_by_id(self, items): return self._non_exact_id_filter(self._exact_id_filter(items))
class NameFilter(object): nf_arguments = dict( name=ValueArgument('filter by name', '--name'), name_pref=ValueArgument('filter by name prefix (case insensitive)', '--name-prefix'), name_suff=ValueArgument('filter by name suffix (case insensitive)', '--name-suffix'), name_like=ValueArgument( 'print only if name contains this (case insensitive)', '--name-like')) def _non_exact_name_filter(self, items): np, ns, nl = self['name_pref'], self['name_suff'], self['name_like'] return [ item for item in items if ((not np) or (item['name'] or '').lower().startswith(np.lower()) ) and ((not ns) or ( item['name'] or '').lower().endswith(ns.lower())) and ( (not nl) or nl.lower() in (item['name'] or '').lower()) ] def _exact_name_filter(self, items): return filter_dicts_by_dict(items, dict( name=self['name'] or '')) if (self['name']) else items def _filter_by_name(self, items): return self._non_exact_name_filter(self._exact_name_filter(items))
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()
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)
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()
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()
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)
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)
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()
class user_add(_AstakosInit, OptionalOutput): """Authenticate a user by token and add to session user list (cache)""" arguments = dict(token=ValueArgument('Token of user to add', '--token'), ) required = ('token', ) @errors.Generic.all @errors.Astakos.astakosclient def _run(self): ask = self['token'] and self['token'] not in self.astakos._uuids try: self.print_(self.astakos.authenticate(self['token']), self.print_dict) except ClientError as ce: if ce.status in (401, ): raise CLIError('Token %s was not authenticated' % self['token'], details=['%s' % ce]) if ask and self.ask_user( 'Token is temporarily stored in memory. Append it in ' 'configuration file as an alternative token?'): tokens = self.astakos._uuids.keys() tokens.remove(self.astakos.token) self['config'].set_cloud(self.cloud, 'token', ' '.join([self.astakos.token] + tokens)) self['config'].write() def main(self): super(self.__class__, self)._run() self._run()
class history_show(_HistoryInit): """Show history Featutes: - slice notation (cmd numbers --> N or :N or N: or N1:N2) - text matching (--match) """ arguments = dict(match=ValueArgument('Show lines matching this', '--match'), ) @errors.Generic.all def _run(self, cmd_slice): c = self.history.counter lines = [ '%s. %s' % (i + c, l) for i, l in enumerate(self.history[:]) ][cmd_slice] if not isinstance(cmd_slice, slice): lines = [ lines, ] if self['match']: lines = [l for l in lines if self.history._match(l, self['match'])] self.print_items([l[:-1] for l in lines]) def main(self, cmd_numbers=''): super(self.__class__, self)._run() sl_args = [int(x) if x else None for x in cmd_numbers.split(':') ] if (cmd_numbers) else [None, None] slice_cmds = slice(*sl_args) if len(sl_args) > 1 else sl_args[0] self._run(slice_cmds)
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)
class service_quotas(_AstakosInit, OptionalOutput): """Get service quotas""" arguments = dict(service_token=ValueArgument('Authenticate service', '--service-token'), uuid=ValueArgument('A user uuid to get quotas for', '--uuid')) required = ('service_token') @errors.Generic.all @errors.Astakos.astakosclient @with_temp_token def _run(self): self.print_(self.client.service_get_quotas(self['uuid'])) def main(self): super(self.__class__, self)._run() self._run(token=self['service_token'])
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'), no_gateway=FlagArgument('Do not assign a gateway IP', '--no-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): gateway = '' if self['no_gateway'] else self['gateway'] try: net = self.client.create_subnet(self['network_id'], self['cidr'], self['name'], self['allocation_pools'], 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() if self['gateway'] and self['no_gateway']: raise CLIInvalidArgument( 'Conflicting arguments', details=[ 'Arguments %s and %s cannot be used together' % (self.arguments['gateway'].lvalue, self.arguments['no_gateway'].lvalue) ]) self._run()
class _ApplicationAction(_AstakosInit): action = '' arguments = dict( app_id=ValueArgument('The application ID', '--app-id'), reason=ValueArgument('Quote a reason for this action', '--reason'), ) required = ('app_id', ) @errors.Generic.all @errors.Astakos.astakosclient @errors.Astakos.project_id def _run(self, project_id): self.client.application_action(project_id, self['app_id'], self.action, self['reason'] or '') def main(self, project_id): super(_ApplicationAction, self)._run() self._run(project_id=project_id)
class _MembershipAction(_AstakosInit, OptionalOutput): action = '' arguments = dict(reason=ValueArgument('Reason for the action', '--reason')) @errors.Generic.all @errors.Astakos.astakosclient @errors.Astakos.membership_id def _run(self, membership_id): self.print_(self.client.membership_action( membership_id, self.action, self['reason'] or '')) def main(self, membership_id): super(_MembershipAction, self)._run() self._run(membership_id=membership_id)
class membership_list(_AstakosInit, OptionalOutput): """List all memberships""" arguments = dict( project_id=ValueArgument('Filter by project id', '--project-id')) @errors.Generic.all @errors.Astakos.astakosclient @errors.Astakos.project_id def _run(self, project_id): self.print_(self.client.get_memberships(project_id)) def main(self): super(self.__class__, self)._run() self._run(project_id=self['project_id'])
class project_enroll(_AstakosInit): """Enroll a user to a project""" arguments = dict(email=ValueArgument('User e-mail', '--email')) required = ('email', ) @errors.Generic.all @errors.Astakos.astakosclient @errors.Astakos.project_id def _run(self, project_id): self.writeln(self.client.enroll_member(project_id, self['email'])) def main(self, project_id): super(project_enroll, self)._run() self._run(project_id=project_id)
class _ProjectAction(_AstakosInit): action = '' arguments = dict(reason=ValueArgument('Quote a reason for this action', '--reason'), ) @errors.Generic.all @errors.Astakos.astakosclient @errors.Astakos.project_id def _run(self, project_id): self.client.project_action(project_id, self.action, self['reason'] or '') def main(self, project_id): super(_ProjectAction, self)._run() self._run(project_id=project_id)
class endpoint_list(_AstakosInit, OptionalOutput, NameFilter): """Get endpoints service endpoints""" arguments = dict(endpoint_type=ValueArgument('Filter by type', '--type')) @errors.Generic.all @errors.Astakos.astakosclient def _run(self): r = self.client.get_endpoints()['access']['serviceCatalog'] r = self._filter_by_name(r) if self['endpoint_type']: r = filter_dicts_by_dict(r, dict(type=self['endpoint_type'])) self.print_(r) def main(self): super(self.__class__, self)._run() self._run()
class subnet_modify(_NetworkInit, OptionalOutput): """Modify the attributes of a subnet""" arguments = dict( new_name=ValueArgument('New name of the subnet', '--name')) required = ['new_name'] @errors.Generic.all @errors.Cyclades.connection @errors.Cyclades.subnet_permissions @errors.Cyclades.subnet_id def _run(self, subnet_id): r = self.client.update_subnet(subnet_id, name=self['new_name']) self.print_(r, self.print_dict) def main(self, subnet_id): super(self.__class__, self)._run() self._run(subnet_id=subnet_id)
class network_modify(_NetworkInit, OptionalOutput): """Modify network attributes""" arguments = dict(new_name=ValueArgument('Rename the network', '--name')) required = [ 'new_name', ] @errors.Generic.all @errors.Cyclades.connection @errors.Cyclades.network_permissions @errors.Cyclades.network_id def _run(self, network_id): r = self.client.update_network(network_id, name=self['new_name']) self.print_(r, self.print_dict) def main(self, network_id): super(self.__class__, self)._run() self._run(network_id=network_id)
class server_attach(_CycladesInit, OptionalOutput): """Attach a volume on a VM""" arguments = dict( volume_id=ValueArgument('The volume to be attached', '--volume-id') ) required = ('volume_id', ) @errors.Generic.all @errors.Cyclades.connection @errors.Cyclades.server_id @errors.Cyclades.endpoint def _run(self, server_id): r = self.client.attach_volume(server_id, self['volume_id']) self.print_(r, self.print_dict) def main(self, server_id): super(self.__class__, self)._run() self._run(server_id=server_id)
class server_rescue(_CycladesInit): """Rescue an existing virtual server""" arguments = dict( rescue_image_ref=ValueArgument('The rescue image ID to use', '--rescue-image-ref') ) @errors.Generic.all @errors.Cyclades.connection @errors.Cyclades.server_id def _run(self, server_id): rescue_image_ref = None if self['rescue_image_ref']: rescue_image_ref = int(self['rescue_image_ref']) self.client.rescue_server(int(server_id), rescue_image_ref) def main(self, server_id): super(self.__class__, self)._run() self._run(server_id=server_id)
class ip_reassign(_NetworkInit): """Assign a floating IP to a different project""" arguments = dict(project_id=ValueArgument('Assign the IP to project', '--project-id'), ) required = ('project_id', ) @errors.Generic.all @errors.Cyclades.connection def _run(self, ip): try: self.client.reassign_floating_ip(ip, self['project_id']) except ClientError as ce: if ce.status in (400, 404): self._ip_exists(ip=ip, network_id=None, error=ce) raise def main(self, IP): super(self.__class__, self)._run() self._run(ip=IP)
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()
class port_modify(_NetworkInit, OptionalOutput): """Modify the attributes of a port""" arguments = dict(new_name=ValueArgument('New name of the port', '--name')) required = [ 'new_name', ] @errors.Generic.all @errors.Cyclades.connection @errors.Cyclades.port_id def _run(self, port_id): r = self.client.get_port_details(port_id) r = self.client.update_port(port_id, r['network_id'], name=self['new_name']) self.print_(r, self.print_dict) def main(self, port_id): super(self.__class__, self)._run() self._run(port_id=port_id)
class server_reassign(_CycladesInit, OptionalOutput): """Assign a virtual server to a different project""" arguments = dict( project_id=ValueArgument('The project to assign', '--project-id')) required = ('project_id', ) @errors.Generic.all @errors.Cyclades.connection @errors.Cyclades.server_id def _run(self, server_id): try: self.client.reassign_server(server_id, self['project_id']) except ClientError as ce: if ce.status in (400, 403, 404): self._project_id_exists(project_id=self['project_id']) raise def main(self, server_id): super(self.__class__, self)._run() self._run(server_id=server_id)
class service_username2uuid(_AstakosInit, OptionalOutput): """Get service uuid(s) from username(s)""" arguments = dict(service_token=ValueArgument('Authenticate service', '--service-token'), username=RepeatableArgument('Username (can be repeated)', '--username')) required = ('service_token', 'username') @errors.Generic.all @errors.Astakos.astakosclient @with_temp_token def _run(self): if 1 == len(self['username']): self.print_(self.client.service_get_uuid(self['username'][0])) else: self.print_(self.client.service_get_uuids(self['username']), self.print_dict) def main(self): super(self.__class__, self)._run() self._run(token=self['service_token'])