def test_raiseCLIError(self): from kamaki.cli.errors import raiseCLIError, CLIError for err, message, importance, details in ((Exception('msg'), '', 0, []), (Exception('msg'), 'orther msg', 0, []), (Exception('msg'), 'orther msg', 0, ['d1', 'd2']), (Exception('msg'), '', 10, []), (Exception('msg'), '', None, []), (CLIError('some msg'), '', None, ['d1', 'd2'])): try: raiseCLIError(err, message, importance, details) except CLIError as clie: exp_msg = '%s' % (message or err) exp_msg += '' if exp_msg.endswith('\n') else '\n' self.assertEqual('%s' % clie, exp_msg) self.assertEqual(clie.importance, importance or 0) exp_d = list(details) if isinstance( details, list) else ['%s' % (details or '')] base_msg = '%s' % err if message and base_msg != message: exp_d.append(base_msg) self.assertEqual(clie.details, exp_d)
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 _raise(self, *args, **kwargs): local_path = kwargs.get('local_path', None) try: return func(self, *args, **kwargs) except IOError as ioe: msg = 'Failed to access file %s' % local_path, raiseCLIError(ioe, msg, importance=2)
def _run(self, errmsg='', importance=0, index=0): l = [1, 2] try: l[int(index)] except Exception as err: raiseCLIError(err, errmsg, importance) raiseCLIError(None, errmsg, importance)
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 _calculate_limit(self, user_input): limit = 0 try: limit = int(user_input) except ValueError: index = 0 digits = ['%s' % num for num in range(0, 10)] + ['.'] while user_input[index] in digits: index += 1 limit = user_input[:index] format = user_input[index:] try: return to_bytes(limit, format) except Exception as qe: msg = 'Failed to convert %s to bytes' % user_input, raiseCLIError( qe, msg, details=[ 'Syntax: containerlimit set <limit>[format] [container]', 'e.g.,: containerlimit set 2.3GB mycontainer', 'Valid formats:', '(*1024): B, KiB, MiB, GiB, TiB', '(*1000): B, KB, MB, GB, TB' ]) return limit
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 _server_is_stopped(self, server_id, cerror): vm = self.client.get_server_details(server_id) if vm['status'].lower() not in ('stopped'): raiseCLIError(cerror, details=[ 'To resize a virtual server, it must be STOPPED', 'Server %s status is %s' % (server_id, vm['status']), 'To stop the server', ' kamaki server shutdown %s -w' % server_id])
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except Exception as e: if _debug: print_stack() print_exc(e) if isinstance(e, CLIError) or isinstance(e, ClientError): raiseCLIError(e) raiseCLIError(e, details=['%s, -d for debug info' % type(e)])
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except ClientError as ce: if ce.status == 403: raiseCLIError( ce, 'Invalid account credentials for this operation', details=['Check user account settings']) raise
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except IndexError as ie: nic_id = kwargs.get('nic_id', None) msg = 'Invalid format for network interface (nic) %s' % nic_id raiseCLIError(ie, msg, importance=1, details=[ 'nid_id format: nic-<server id>-<nic id>', '* get nics of a network: /network info <net id>', ' (listed the "attachments" section)'])
def format_date(self, datestr): for format in self.INPUT_FORMATS: try: t = dtm.strptime(datestr, format) except ValueError: continue return t # .strftime(self.DATE_FORMAT) raiseCLIError(None, 'Date Argument Error', details=[ '%s not a valid date' % datestr, 'Correct formats:\n\t%s' % self.INPUT_FORMATS])
def assert_not_in_status(self, server_id, status): """ :returns: current server status :raises CLIError: if server is already in this status :raises ClientError: (404) if server not found """ current = self.client.get_server_details(server_id).get('status', None) if current in (status, ): raiseCLIError('Server %s is already %s' % (server_id, status)) return current
def _server_is_stopped(self, server_id, cerror): vm = self.client.get_server_details(server_id) if vm['status'].lower() not in ('stopped'): raiseCLIError(cerror, details=[ 'To resize a virtual server, it must be STOPPED', 'Server %s status is %s' % (server_id, vm['status']), 'To stop the server', ' kamaki server shutdown %s -w' % server_id ])
def value(self, config_file): if config_file: if not os.path.exists(config_file): raiseCLIError('Config file "%s" does not exist' % config_file, importance=3) self._value = Config(config_file) self.file_path = config_file elif self.file_path: self._value = Config(self.file_path) else: self._value = Config()
def _raise(self, *args, **kwargs): key = kwargs.get('key', None) try: func(self, *args, **kwargs) except ClientError as ce: if key and ce.status == 404 and ( 'metadata' in ('%s' % ce).lower() ): raiseCLIError( ce, 'No virtual server metadata with key %s' % key) raise
def _raise(self, *args, **kwargs): key = kwargs.get('key', None) try: return func(self, *args, **kwargs) except ClientError as ce: ce_msg = ('%s' % ce).lower() if ce.status == 404 or ( ce.status == 400 and 'metadata' in ce_msg): msg = 'No properties with key %s in this image' % key raiseCLIError(ce, msg) raise
def _ip_exists(self, ip, network_id, error): for ip_item in self.client.list_floatingips(): if ip_item['floating_ip_address'] == ip: if network_id and ip_item['floating_network_id'] != network_id: raiseCLIError(error, details=[ 'Floating IP %s does not belong to network %s ,' % ( ip, network_id), 'To get information on IP %s' % ip, ' kamaki ip info %s' % ip_item['id']]) return raiseCLIError(error, details=[ 'Floating IP %s not found' % ip] + errors.Cyclades.about_ips)
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except (ClientError, AstakosClientException) as ce: if ce.status == 401: token = kwargs.get('custom_token', 0) or self.client.token msg = ('Authorization failed for token %s' % token) if ( token) else 'No token provided', details = [] if token else this._token_details raiseCLIError(ce, msg, details=details) raise ce self._raise = func
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except ClientError as ce: if ce.status == 413: msg = 'Cannot create another network', details = [ 'Maximum number of networks reached', '* to get a list of networks: /network list', '* to delete a network: /network delete <net id>'] raiseCLIError(ce, msg, details=details) raise
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except IOError as ioe: msg = 'Failed to access a local file', raiseCLIError(ioe, msg, importance=2, details=[ 'Check if the file exists. Also check if the remote', 'directories exist. All directories in a remote path', 'must exist to succesfully download a container or a', 'directory.', 'To create a remote directory:', ' [kamaki] file mkdir REMOTE_DIRECTORY_PATH'])
def value(self, config_file): if config_file: if not os.path.exists(config_file): raiseCLIError( 'Config file "%s" does not exist' % config_file, importance=3) self._value = Config(config_file) self.file_path = config_file elif self.file_path: self._value = Config(self.file_path) else: self._value = Config()
def _raise(self, *args, **kwargs): dst_cont = kwargs.get('dst_cont', None) try: return func(self, *args, **kwargs) except ClientError as ce: if ce.status == 404 and 'container' in ('%s' % ce).lower(): cont = ('%s or %s' % ( self.container, dst_cont)) if dst_cont else self.container msg = 'Is container %s in current account?' % (cont), raiseCLIError(ce, msg, details=this.container_howto) raise
def value(self, newvalue): if newvalue == self.default: return self.value self._value, input_dict = [], {} for i, terms in enumerate(newvalue): termlist = terms.split(',') if len(termlist) > len(self.terms): msg = 'Wrong number of terms (1<=terms<=%s)' % len(self.terms) raiseCLIError(CLISyntaxError(msg), details=howto_personality) for k, v in self.terms: prefix = '%s=' % k for item in termlist: if item.lower().startswith(prefix): input_dict[k] = item[len(k) + 1:] break item = None if item: termlist.remove(item) try: path = input_dict['local-path'] except KeyError: path = termlist.pop(0) if not path: raise CLIInvalidArgument( '--personality: No local path specified', details=howto_personality) if not exists(path): raise CLIInvalidArgument( '--personality: File %s does not exist' % path, details=howto_personality) self._value.append(dict(path=path)) with open(expanduser(path)) as f: self._value[i]['contents'] = b64encode(f.read()) for k, v in self.terms[1:]: try: self._value[i][v] = input_dict[k] except KeyError: try: self._value[i][v] = termlist.pop(0) except IndexError: continue if k in ('mode', ) and self._value[i][v]: try: self._value[i][v] = int(self._value[i][v], 8) except ValueError as ve: raise CLIInvalidArgument( 'Personality mode must be in octal', details=[ '%s' % ve])
def value(self, newvalue): if newvalue == self.default: return self.value self._value, input_dict = [], {} for i, terms in enumerate(newvalue): termlist = terms.split(',') if len(termlist) > len(self.terms): msg = 'Wrong number of terms (1<=terms<=%s)' % len(self.terms) raiseCLIError(CLISyntaxError(msg), details=howto_personality) for k, v in self.terms: prefix = '%s=' % k for item in termlist: if item.lower().startswith(prefix): input_dict[k] = item[len(k) + 1:] break item = None if item: termlist.remove(item) try: path = input_dict['local-path'] except KeyError: path = termlist.pop(0) if not path: raise CLIInvalidArgument( '--personality: No local path specified', details=howto_personality) if not exists(path): raise CLIInvalidArgument( '--personality: File %s does not exist' % path, details=howto_personality) self._value.append(dict(path=path)) with open(expanduser(path)) as f: self._value[i]['contents'] = b64encode(f.read()) for k, v in self.terms[1:]: try: self._value[i][v] = input_dict[k] except KeyError: try: self._value[i][v] = termlist.pop(0) except IndexError: continue if k in ('mode', ) and self._value[i][v]: try: self._value[i][v] = int(self._value[i][v], 8) except ValueError as ve: raise CLIInvalidArgument( 'Personality mode must be in octal', details=['%s' % ve])
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except ClientError as ce: if ce.status == 413: raiseCLIError(ce, 'User quota exceeded', details=[ '* get quotas:', ' * upper total limit: /file quota', ' * container limit:', ' /file containerlimit get <container>', '* set a higher container limit:', ' /file containerlimit set <limit> <container>']) raise
def value(self, newvalue): if newvalue == self.default: self._value = newvalue return try: if int(newvalue) == float(newvalue): self._value = int(newvalue) else: raise ValueError('Raise int argument error') except ValueError: raiseCLIError( CLISyntaxError('IntArgument Error', details=['Value %s not an int' % newvalue]))
def value(self, newvalue): if newvalue == self.default: self._value = newvalue return try: if int(newvalue) == float(newvalue): self._value = int(newvalue) else: raise ValueError('Raise int argument error') except ValueError: raiseCLIError(CLISyntaxError( 'IntArgument Error', details=['Value %s not an int' % newvalue]))
def _raise(self, *args, **kwargs): try: return func(self, *args, **kwargs) except ClientError as ce: err_msg = ('%s' % ce).lower() if ( ce.status == 404 or ce.status == 500 ) and 'object' in err_msg and 'not' in err_msg: msg = 'No object %s in container %s' % ( self.path, self.container) raiseCLIError(ce, msg, details=this.container_howto) raise
def value(self, keyvalue_pairs): """ :param keyvalue_pairs: (str) ['key1=val1', 'key2=val2', ...] """ if keyvalue_pairs: self._value = self.value try: for pair in keyvalue_pairs: key, sep, val = pair.partition('=') assert sep, ' %s misses a "=" (usage: key1=val1 )\n' % ( pair) self._value[key] = val except Exception as e: raiseCLIError(e, 'KeyValueArgument Syntax Error')
def _raise(self, *args, **kwargs): image_id = kwargs.get('image_id', None) try: func(self, *args, **kwargs) except ClientError as ce: if image_id and ( ce.status == 404 or ( ce.status == 400 and 'image not found' in ('%s' % ce).lower()) or ce.status == 411 ): msg = 'No image with id %s found' % image_id raiseCLIError(ce, msg, details=this.about_image_id) raise
def _assert_remote_file_not_exist(self, pithos, path): if pithos and not self['force_upload']: try: pithos.get_object_info(path) raiseCLIError( 'Remote file /%s/%s already exists' % ( pithos.container, path), importance=2, details=[ 'Registration ABORTED', 'Use %s to force upload' % self.arguments[ 'force_upload'].lvalue]) except ClientError as ce: if ce.status != 404: raise
def _raise(self, *args, **kwargs): profile = kwargs.get('profile', None) try: return func(self, *args, **kwargs) except ClientError as ce: if ce.status == 400 and profile and ( 'firewall' in ('%s' % ce).lower() ): msg = '%s is an invalid firewall profile term' % profile raiseCLIError(ce, msg, details=[ 'Try one of the following:', '* DISABLED: Shutdown firewall', '* ENABLED: Firewall in normal mode', '* PROTECTED: Firewall in secure mode']) raise
def _raise(self, *args, **kwargs): size = kwargs.get('size', None) try: size = int(size) assert size > 0, 'Cluster size must be a positive integer' return func(self, *args, **kwargs) except ValueError as ve: msg = 'Invalid cluster size value %s' % size raiseCLIError(ve, msg, importance=1, details=[ 'Cluster size must be a positive integer']) except AssertionError as ae: raiseCLIError( ae, 'Invalid cluster size %s' % size, importance=1) except ClientError: raise
def _ip_exists(self, ip, network_id, error): for ip_item in self.client.list_floatingips(): if ip_item['floating_ip_address'] == ip: if network_id and ip_item['floating_network_id'] != network_id: raiseCLIError( error, details=[ 'Floating IP %s does not belong to network %s ,' % (ip, network_id), 'To get information on IP %s' % ip, ' kamaki ip info %s' % ip_item['id'] ]) return raiseCLIError(error, details=['Floating IP %s not found' % ip] + errors.Cyclades.about_ips)
def _raise(self, *args, **kwargs): flavor_id = kwargs.get('flavor_id', None) try: flavor_id = int(flavor_id) return func(self, *args, **kwargs) except ValueError as ve: msg = 'Invalid flavor id %s ' % flavor_id, details = 'Flavor id must be a positive integer' raiseCLIError(ve, msg, details=details, importance=1) except ClientError as ce: if flavor_id and ce.status == 404 and ( 'flavor' in ('%s' % ce).lower() ): msg = 'No flavor with id %s found' % flavor_id, raiseCLIError(ce, msg, details=this.about_flavor_id) raise
def _raise(self, *args, **kwargs): network_id = kwargs.get('network_id', None) try: return func(self, *args, **kwargs) except ClientError as ce: if network_id and ce.status in (400, ): msg = 'Network with id %s does not exist' % network_id, raiseCLIError(ce, msg, details=this.about_network_id) elif network_id or ce.status in (421, ): msg = 'Network with id %s is in use' % network_id, raiseCLIError(ce, msg, details=[ 'Disconnect all nics/servers of this network first', '* to get nics: /network info %s' % network_id, '. (under "attachments" section)', '* to disconnect: /network disconnect <nic id>']) raise
def _raise(self, *args, **kwargs): network_id = kwargs.get('network_id', None) try: network_id = int(network_id) return func(self, *args, **kwargs) except ValueError as ve: msg = 'Invalid network id %s ' % network_id details = 'network id must be a positive integer' raiseCLIError(ve, msg, details=details, importance=1) except ClientError as ce: if network_id and ce.status == 404 and ( 'network' in ('%s' % ce).lower() ): msg = 'No network with id %s found' % network_id, raiseCLIError(ce, msg, details=this.about_network_id) raise
def format_date(self, datestr): for fmt in self.DATE_FORMATS: try: return dtm.strptime(datestr, fmt) except ValueError as ve: continue raise raiseCLIError(ve, 'Failed to format date', details=[ '%s could not be formated for HTTP headers' % datestr])
def parse(self, new_args=None): """Parse user input""" try: pkargs = (new_args,) if new_args else () self._parsed, unparsed = self.parser.parse_known_args(*pkargs) parsed_args = [ k for k, v in vars(self._parsed).items() if v not in (None, )] if not self._parse_required_arguments(self.required, parsed_args): self.print_help() raise CLISyntaxError('Missing required arguments') except SystemExit: raiseCLIError(CLISyntaxError('Argument Syntax Error')) for name, arg in self.arguments.items(): arg.value = getattr(self._parsed, name, arg.default) self._unparsed = [] for term in unparsed: self._unparsed += split_input(' \'%s\' ' % term) self._parser_modified = False
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 _set_firewall_profile(self, server_id): vm = self._restruct_server_info( self.client.get_server_details(server_id)) ports = [p for p in vm['ports'] if 'firewallProfile' in p] pick_port = self.arguments['public_network_port_id'] if pick_port.value: ports = [ p for p in ports if pick_port.value in ('*', '%s' % p['id']) ] elif len(ports) > 1: port_strings = ['Server %s ports to public networks:' % server_id] for p in ports: port_strings.append(' %s' % p['id']) for k in ('network_id', 'ipv4', 'ipv6', 'firewallProfile'): v = p.get(k) if v: port_strings.append('\t%s: %s' % (k, v)) raiseCLIError('Multiple public connections on server %s' % (server_id), details=port_strings + [ 'To select one:', ' %s PORT_ID' % pick_port.lvalue, 'To set all:', ' %s *' % pick_port.lvalue, ]) if not ports: pp = pick_port.value raiseCLIError( 'No public networks attached on server %s%s' % (server_id, ' through port %s' % pp if pp else ''), details=[ 'To see all networks:', ' kamaki network list', 'To see all connections:', ' kamaki server info %s --nics' % server_id, 'To connect to a network:', ' kamaki network connect NETWORK_ID --device-id %s' % (server_id) ]) for port in ports: self.error('Set port %s firewall to %s' % (port['id'], self['firewall_profile'])) self.client.set_firewall_profile(server_id=server_id, profile=self['firewall_profile'], port_id=port['id'])
def value(self, options): if options == self.default: return if not isinstance(options, list): options = ['%s' % options] for option in options: keypath, sep, val = option.partition('=') if not sep: raiseCLIError(CLISyntaxError('Argument Syntax Error '), details=[ '%s is missing a "="', ' (usage: -o section.key=val)' % option ]) section, sep, key = keypath.partition('.') if not sep: key = section section = 'global' self._config_arg.value.override(section.strip(), key.strip(), val.strip())
def format_size(size, decimal_factors=False): units = ('B', 'KB', 'MB', 'GB', 'TB') if decimal_factors else ('B', 'KiB', 'MiB', 'GiB', 'TiB') step = 1000 if decimal_factors else 1024 fstep = float(step) try: size = float(size) except (ValueError, TypeError) as err: raiseCLIError( err, 'Cannot format %s in bytes' % (','.join(size) if isinstance(size, tuple) else size)) for i, unit in enumerate(units): if size < step or i + 1 == len(units): break size /= fstep s = ('%.2f' % size) s = s.replace('%s' % step, '%s.99' % (step - 1)) if size <= fstep else s while '.' in s and s[-1] in ('0', '.'): s = s[:-1] return s + unit
def _load_params_from_file(self, location): params, properties = dict(), dict() pfile = self['metafile'] if pfile: try: for k, v in load_image_meta(pfile).items(): key = k.lower().replace('-', '_') if key == 'properties': for pk, pv in v.items(): properties[pk.upper().replace('-', '_')] = pv elif key == 'name': continue elif key == 'location': if location: continue location = v else: params[key] = v except Exception as e: raiseCLIError(e, 'Invalid json metadata config file') return params, properties, location
def value(self, uuid_or_name): if uuid_or_name and self.account_client: r = self.account_client.uuids2usernames([uuid_or_name, ]) if r: self._value = uuid_or_name else: r = self.account_client.usernames2uuids([uuid_or_name]) self._value = r.get(uuid_or_name) if r else None if not self._value: raise raiseCLIError('User name or UUID not found', details=[ '%s is not a known username or UUID' % uuid_or_name, 'Usage: %s <USER_UUID | USERNAME>' % self.lvalue])
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 raiseCLIError(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: raiseCLIError(cerror, details=[ msg, 'To get details on IP', ' kamaki ip info %s' % ip ] + errors.Cyclades.about_ips)