def get_parser(self, prog_name): parser = super(Stop, self).get_parser(prog_name) parser.add_argument('--hosts', nargs='?', metavar='<host_list>', help=u._('Stop host list')) parser.add_argument('--services', nargs='?', metavar='<service_list>', help=u._('Stop service list')) return parser
def get_parser(self, prog_name): parser = super(HostDestroy, self).get_parser(prog_name) parser.add_argument('hostname', metavar='<hostname | all>', help=u._('Host name or ip address or "all"')) parser.add_argument('--stop', action='store_true', help=u._('Stop rather than kill')) parser.add_argument('--includedata', action='store_true', help=u._('Destroy data containers')) parser.add_argument('--removeimages', action='store_true', help=u._('Remove docker images')) return parser
def get_parser(self, prog_name): parser = super(PasswordSetKey, self).get_parser(prog_name) parser.add_argument('passwordname', metavar='<passwordname>', help=u._('Password name')) parser.add_argument('privatekeypath', metavar='<privatekeypath>', help=u._('Path to private key file')) parser.add_argument('publickeypath', metavar='<publickeypath>', help=u._('Path to public key file')) return parser
def take_action(self, parsed_args): hosts = None serial_flag = False verbose_level = self.app.options.verbose_level timeout_target = 0 services = None try: if parsed_args.hosts: host_list = parsed_args.hosts.strip() hosts = host_list.split(',') if parsed_args.serial: serial_flag = True if parsed_args.timeout: try: timeout = float(parsed_args.timeout[0]) except Exception: raise CommandError(u._('Timeout value is not a number.')) timeout_target = time.time() + (60 * timeout) if parsed_args.services: service_list = parsed_args.services.strip() services = service_list.split(',') # if we are doing a targeted host deploy make sure we are doing it # to only compute nodes if hosts: invalid_host_list = [] compute_group = CLIENT.group_get(['compute'])[0] compute_hosts = compute_group.get_hosts() for host in hosts: if host not in compute_hosts: invalid_host_list.append(host) if len(invalid_host_list) > 0: raise CommandError( u._('Invalid hosts for host targeted deploy. ' 'Hosts must be in the compute group only.' 'Invalid hosts: {hosts}').format( hosts=invalid_host_list)) job = CLIENT.deploy(hosts, serial_flag, verbose_level, services) # wait for job to complete status = None while status is None: if timeout_target and time.time() > timeout_target: job.kill() raise CommandError(u._('Job timed out and was killed.')) time.sleep(1) status = job.get_status() # job is done handers_action_result(job, status, verbose_level) except Exception: raise Exception(traceback.format_exc())
def take_action(self, parsed_args): try: password_names = CLIENT.password_get_names() password_names = sorted(password_names) data = [] for password_name in password_names: data.append((password_name, '-')) return ((u._('Password Name'), u._('Password')), data) except Exception: raise Exception(traceback.format_exc())
def _get_yml_data(self, yml_path): if not os.path.isfile(yml_path): raise CommandError( u._('No file exists at {path}. An absolute file path is ' 'required.').format(path=yml_path)) with open(yml_path, 'r') as hosts_file: file_data = hosts_file.read() hosts_info = yaml.safe_load(file_data) if not hosts_info: raise CommandError(u._('{path} is empty.').format(path=yml_path)) return hosts_info
def validate_servicenames(self, servicenames, client_filter=False): if not servicenames: raise MissingArgument(u._('Service name(s)')) invalid_services = [] if client_filter: services = self._client_filtered_service_dict() else: services = self._services for service_name in servicenames: if service_name not in services: invalid_services.append(service_name) if invalid_services: raise NotInInventory(u._('Service'), invalid_services)
def get_parser(self, prog_name): parser = super(Deploy, self).get_parser(prog_name) parser.add_argument('--hosts', nargs='?', metavar='<host_list>', help=u._('Deployment host list')) parser.add_argument('--serial', action='store_true', help=u._('Deploy serially')) parser.add_argument('--timeout', nargs=1, metavar='<timeout>', help=u._('timeout (in minutes)')) return parser
def get_parser(self, prog_name): parser = super(PropertyClear, self).get_parser(prog_name) parser.add_argument('propertyname', metavar='<propertyname>', help=u._('Property name')) parser.add_argument('--hosts', nargs=1, metavar='<host_list>', help=u._('Property host list')) parser.add_argument('--groups', nargs=1, metavar='<group_list>', help=u._('Property group list')) return parser
def take_action(self, parsed_args): try: hostname = parsed_args.hostname.strip() hostnames = [hostname] if hostname == 'all': hostnames = _get_all_hostnames() destroy_type = 'kill' if parsed_args.stop: destroy_type = 'stop' include_data = False if parsed_args.includedata: include_data = True remove_images = False if parsed_args.removeimages: remove_images = True if not include_data: question = ('This will delete all containers and data' ', are you sure? (y/n)') answer = raw_input(question) while answer != 'y' and answer != 'n': answer = raw_input(question) if answer is 'n': LOG.info('Aborting destroy') return verbose_level = self.app.options.verbose_level job = CLIENT.host_destroy(hostnames, destroy_type, verbose_level, include_data, remove_images) status = job.wait() if verbose_level > 2: LOG.info('\n\n' + 80 * '=') LOG.info(u._('DEBUG command output:\n{out}') .format(out=job.get_console_output())) if status != 0: raise CommandError(u._('Job failed:\n{msg}') .format(msg=job.get_error_message())) elif verbose_level > 1: # log any ansible warnings msg = job.get_error_message() if msg: LOG.warn(msg) except ClientException as e: raise CommandError(str(e)) except Exception as e: raise Exception(traceback.format_exc())
def property_set(self, property_dict, property_type=GLOBAL_TYPE, change_set=None): # type: (Dict[str,str], str, List[str]) -> None """Set a property :param property_dict: property dictionary containing key / values :type property_dict: dictionary :param property_type: one of 'global', 'group' or 'host' :type property_type: string :param change_set: for group or host sets this is the list of groups or hosts to set the property for :type change_set: list of strings """ ansible_properties = AnsibleProperties() for key, value in property_dict.items(): check_arg(key, u._('Property Key'), str) current_property = ansible_properties.get_property(key) if current_property is not None: current_property_type = current_property.value_type if current_property_type is not str: value = yaml.safe_load(value) if current_property.value is None: current_property_type = None check_arg(value, u._('Property Value'), current_property_type, empty_ok=True) property_dict[key] = value else: check_arg(value, u._('Property Value'), str, empty_ok=True) if type(value) is str and '"' in value: raise InvalidArgument( u._('Cannot use double quotes in ' 'a property value.')) self._check_type(property_type) if property_type is not GLOBAL_TYPE: check_arg(change_set, u._('Change Set'), list, none_ok=True) change_set = safe_decode(change_set) if property_type == GLOBAL_TYPE: ansible_properties.set_property(property_dict) elif property_type == GROUP_TYPE: ansible_properties.set_group_property(property_dict, change_set) else: ansible_properties.set_host_property(property_dict, change_set)
def take_action(self, parsed_args): try: data = [('', '')] groups = CLIENT.group_get_all() if groups: data = [] for group in groups: data.append((group.get_name(), sorted(group.get_services()))) data = convert_lists_to_string(data, parsed_args) return ((u._('Group'), u._('Services')), sorted(data)) except ClientException as e: raise CommandError(str(e)) except Exception as e: raise Exception(traceback.format_exc())
def password_set_sshkey(self, name, private_key, public_key): # type: (str, str, str) -> None """Set password to an ssh key :param name: name of the password :type name: string :param private_key: ssh private key :type value: string :param public_key: ssh public key :type value: string """ check_arg(name, u._('Password name'), str) check_arg(private_key, u._('Private key'), str, display_param=False) check_arg(public_key, u._('Public key'), str, display_param=False) set_password_sshkey(name, private_key, public_key)
def take_action(self, parsed_args): try: hostname = parsed_args.hostname.strip() hostnames = [hostname] if hostname == 'all': hostnames = _get_all_hostnames() # if there are no hosts, don't bother doing anything if not hostnames: return destroy_type = 'kill' if parsed_args.stop: destroy_type = 'stop' include_data = False if parsed_args.includedata: include_data = True remove_images = False if parsed_args.removeimages: remove_images = True if include_data and not self._is_ok_to_delete_data(): LOG.info('Aborting destroy') return verbose_level = self.app.options.verbose_level job = CLIENT.host_destroy(hostnames, destroy_type, verbose_level, include_data, remove_images) status = job.wait() if verbose_level > 2: LOG.info('\n\n' + 80 * '=') LOG.info(u._('DEBUG command output:\n{out}') .format(out=job.get_console_output())) if status != 0: raise CommandError(u._('Job failed:\n{msg}') .format(msg=job.get_error_message())) elif verbose_level > 1: # log any ansible warnings msg = job.get_error_message() if msg: LOG.warn(msg) except ClientException as e: raise CommandError(str(e)) except Exception as e: raise Exception(traceback.format_exc())
def run_cmd(cmd, print_output=True): """run a system command return: - err_msg: empty string=command succeeded not None=command failed - output: string: all the output of the run command """ output = None try: process = subprocess.Popen( cmd, shell=True, # nosec stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, err = process.communicate() except Exception as e: err = str(e) err = safe_decode(err) output = safe_decode(output) if process is not None and process.returncode != 0: err = (u._('Command failed. : {error}').format(error=err)) if print_output: LOG.info(output) return err, output
def handers_action_result(job, status, verbose_level): if verbose_level > 2: LOG.info('\n\n' + 80 * '=') LOG.info( u._('DEBUG command output:\n{out}').format( out=job.get_console_output())) if status == 0: if verbose_level > 1: # log any ansible warnings msg = job.get_error_message() if msg: LOG.warn(msg) LOG.info(u._('Success')) else: raise CommandError( u._('Job failed:\n{msg}').format(msg=job.get_error_message()))
def is_owned_by_me(self): """Returns True if we own the lock or False otherwise""" try: if self.use_flock: raise Exception( u._('Invalid use of is_owned_by_me while' 'using flock')) if not os.path.exists(self.lockpath): # lock doesn't exist, just return return False fd = os.open(self.lockpath, os.O_RDONLY) with os.fdopen(fd, 'r') as f: contents = f.read(2048).strip().split('\n') if len(contents) > 0: self.current_pid = contents[0] if len(contents) > 1: self.current_owner = contents[1] if contents[0] == str(self.pid): return True else: return False except Exception as e: # it is ok to fail to acquire, we just return that we failed LOG.debug('Exception in is_owned_by_me lock check. ' 'path: %s pid: %s owner: %s error: %s' % (self.lockpath, self.pid, self.owner, str(e))) return False
def take_action(self, parsed_args): try: property_name = parsed_args.propertyname.strip() property_value = parsed_args.propertyvalue.strip() property_dict = {} property_dict[property_name] = property_value if parsed_args.hosts: if parsed_args.groups: raise CommandError( u._('Invalid to use both hosts and groups arguments ' 'together.')) host_names = _get_names(parsed_args.hosts) CLIENT.property_set(property_dict, 'host', host_names) elif parsed_args.groups: group_names = _get_names(parsed_args.groups) CLIENT.property_set(property_dict, 'group', group_names) else: CLIENT.property_set(property_dict, 'global') except Exception: raise Exception(traceback.format_exc())
def remove_host(self, hostname, groupname=None): """remove host if groupname is none, delete host if group name is not none, remove host from group """ changed = False if groupname and groupname not in self._groups: raise NotInInventory(u._('Group'), groupname) if hostname not in self._hosts: return changed changed = True host = self._hosts[hostname] groups = self.get_groups(host) for group in groups: if not groupname or groupname == group.name: group.remove_host(host) host_vars = os.path.join(get_host_vars_dir(), hostname) if os.path.exists(host_vars): os.remove(host_vars) if not groupname: del self._hosts[hostname] return changed
def take_action(self, parsed_args): try: data = [('', '')] services = CLIENT.service_get_all() if services: data = [] for service in services: groupnames = sorted(service.get_groups()) data.append((service.name, groupnames)) data = convert_lists_to_string(data, parsed_args) return (u._('Service'), u._('Groups')), sorted(data) except ClientException as e: raise CommandError(str(e)) except Exception as e: raise Exception(traceback.format_exc())
def get_parser(self, prog_name): parser = super(Upgrade, self).get_parser(prog_name) parser.add_argument('--services', nargs='?', metavar='<service_list>', help=u._('Upgrade service list')) return parser
def _configure_logging(self): global LOG root_logger = logging.getLogger('') root_logger.setLevel(logging.DEBUG) handler_found = False handlers = root_logger.handlers for handler in handlers: if isinstance(handler, RotatingFileHandler): handler_found = True break if not handler_found: # logger has not been set up try: rotate_handler = RotatingFileHandler( os.path.join(os.path.abspath(os.sep), 'var', 'log', 'kolla-cli', 'kolla.log'), maxBytes=self._get_kolla_log_file_size(), backupCount=4) except IOError as e: # most likely the caller is not part of the kolla group raise IOError( u._('Permission denied to run the kolla client.' '\nPlease add user to the kolla group and ' 'then log out and back in. {error}').format( error=str(e))) formatter = logging.Formatter(LOG_FILE_MESSAGE_FORMAT) rotate_handler.setFormatter(formatter) rotate_handler.setLevel(get_log_level()) root_logger.addHandler(rotate_handler) LOG = logging.getLogger(__name__)
def get_ansible_command(playbook=False): """get a python2 ansible command Ansible cannot run yet with python3. If the current default python is py3, prefix the ansible command with a py2 interpreter. """ cmd = 'ansible' if playbook: cmd = 'ansible-playbook' if sys.version_info[0] >= 3: # running with py3, find a py2 interpreter for ansible py2_path = None usr_bin = os.path.join('/', 'usr', 'bin') for fname in os.listdir(usr_bin): if (fname.startswith('python2.') and os.path.isfile(os.path.join(usr_bin, fname))): suffix = fname.split('.')[1] if suffix.isdigit(): py2_path = os.path.join(usr_bin, fname) break if py2_path is None: raise Exception( u._('ansible-playbook requires python2 and no ' 'python2 interpreter found in {path}.').format( path=usr_bin)) cmd = '%s %s' % (py2_path, os.path.join(usr_bin, cmd)) return cmd
def run(self): try: locked = self._ansible_lock.wait_acquire() if not locked: raise Exception( u._('unable to get lock: {lock}, to run ' 'ansible job: {cmd} ') .format(lock=get_ansible_lock_path(), cmd=self._command)) LOG.debug('playbook command: %s' % self._command) # ansible 2.2 and later introduced an issue where if # the playbook is executed from within a directory without # read / write permission (which can happen when you, # for example, execute via sudo) it will fail. the # workaround will be to run the ansible command from /tmp # and then change back to the original directory at the end current_dir = os.getcwd() # nosec os.chdir('/tmp') # nosec self._process = subprocess.Popen(self._command, # nosec shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # setup stdout to be read without blocking LOG.debug('process pid: %s' % self._process.pid) flags = fcntl.fcntl(self._process.stdout, fcntl.F_GETFL) fcntl.fcntl(self._process.stdout, fcntl.F_SETFL, (flags | os.O_NONBLOCK)) # this is also part of the fix for ansible 2.2 and later os.chdir(current_dir) except Exception as e: self._cleanup() raise e
def config_import_inventory(self, file_path): # type: (str) -> None """Config Import Inventory Import groups and child associations from the provided inventory file. This currently does not import hosts, group vars, or host vars that may also exist in the inventory file. :param file_path: path to inventory file to import :type file_path: string """ check_arg(file_path, u._('File path'), str) if not os.path.isfile(file_path): raise InvalidArgument( u._('File {path} is not valid.').format(path=file_path)) inventory = Inventory(file_path) Inventory.save(inventory)
def set_deploy_mode(self, remote_flag): if not remote_flag and len(self._hosts) > 1: raise InvalidConfiguration( u._('Cannot set local deploy mode when multiple hosts exist.')) self.remote_mode = remote_flag for group in self.get_groups(): group.set_remote(remote_flag)
def get_parser(self, prog_name): parser = super(PropertyList, self).get_parser(prog_name) parser.add_argument('--all', action='store_true', help=u._('List all properties')) parser.add_argument('--long', action='store_true', help=u._('Show all property attributes')) parser.add_argument('--hosts', nargs=1, metavar='<host_list>', help=u._('Property host list')) parser.add_argument('--groups', nargs=1, metavar='<group_list>', help=u._('Property group list')) return parser
def set_password_sshkey(pwd_key, private_key, public_key): cmd = '%s -k %s -r "%s" -u "%s"' % (_get_cmd_prefix(), pwd_key, private_key, public_key) err_msg, output = utils.run_cmd(cmd, print_output=False) if err_msg: raise FailedOperation( u._('Password ssh key set failed. {error} {message}').format( error=err_msg, message=output))
def take_action(self, parsed_args): try: verbose_level = self.app.options.verbose_level job = CLIENT.reconfigure(verbose_level) status = job.wait() if verbose_level > 2: LOG.info('\n\n' + 80 * '=') LOG.info(u._('DEBUG command output:\n{out}') .format(out=job.get_console_output())) if status == 0: LOG.info(u._('Success')) else: raise CommandError(u._('Job failed:\n{msg}') .format(msg=job.get_error_message())) except Exception: raise Exception(traceback.format_exc())
def password_set(self, name, value): # type: (str, str) -> None """Set password :param name: name of the password :type name: string :param value: value of the password :type value: string """ check_arg(name, u._('Password name'), str) check_arg(value, u._('Password value'), str, display_param=False, empty_ok=True, none_ok=True) set_password(name, value)