def basic_containers(deployment_type): base_inventory = { 'rgws': [], 'mgrs': [], 'mdss': [], 'clients': [], 'osds': [], 'mons': [] } label_map = { 'OSD': 'osds', 'OSD_CEPH_VOLUME_ACTIVATE': 'osds', 'MON': 'mons', 'MGR': 'mgrs', 'MDS': 'mdss', 'RGW': 'rgws', } metal_hosts = set() for nodes in config.nodes.values(): for node in nodes: metal_hosts.add(node['host']) for host in metal_hosts: logger.debug("listing containers for host %s", host) cmd = [ deployment_type, 'container', 'ls', '--format', 'json', '--no-trunc' ] conn = ceph_medic.connection.get_connection(host, deployment_type='ssh') out, err, code = process.check(conn, cmd) if code: terminal.error("Unable to list containers on host %s" % host) continue container_list = json.loads(''.join(out)) if not container_list: terminal.warning("Host %s had no containers" % host) continue for container in container_list: cmd = [deployment_type, 'container', 'inspect', container['Names']] out, err, code = process.check(conn, cmd) if code: terminal.error("Unable to inspect container %s on host %s" % (container['Names'], host)) continue detail = json.loads(''.join(out))[0] env = dict([s.split('=', 1) for s in detail['Config']['Env']]) if 'CEPH_DAEMON' not in env: continue if env.get('CLUSTER') != config.cluster_name: continue role = env['CEPH_DAEMON'] if role not in label_map: continue base_inventory[label_map[role]].append({ 'host': host, 'container': detail['Name'], 'group': None }) return base_inventory
def wrapper(*args): if docstring: self.logger.debug(docstring) if len(args): source = self._module_source + dump_template % (name, repr(args)) else: source = self._module_source + dump_template % (name, '()') # check python interpreter if self.python_executable is None: self.python_executable = get_python_executable(self.conn) out, err, code = check(self.conn, [self.python_executable], stdin=source.encode('utf-8')) if not out: if not err: err = [ 'Traceback (most recent call last):', ' File "<stdin>", in <module>', 'Exception: error calling "%s"' % name ] if code: raise Exception('Unexpected remote exception: \n%s\n%s' % ('\n'.join(out), '\n'.join(err))) # at this point, there was no stdout, and the exit code was 0, # we must return so that we don't fail trying to serialize back # the JSON return response = json.loads(out[0]) if response['exception']: raise Exception(response['exception']) return response['return']
def wrapper(*args): if docstring: self.logger.debug(docstring) if len(args): source = self._module_source + dump_template % (name, repr(args)) else: source = self._module_source + dump_template % (name, '()') # check python interpreter if self.python_executable is None: self.python_executable = get_python_executable(self.conn) out, err, code = check(self.conn, [self.python_executable], stdin=source.encode('utf-8')) if not out: if not err: err = [ 'Traceback (most recent call last):', ' File "<stdin>", in <module>', 'Exception: error calling "%s"' % name ] if code: raise Exception('Unexpected remote exception: \n%s\n%s' % ('\n'.join(out), '\n'.join(err))) # at this point, there was no stdout, and the exit code was 0, # we must return so that we don't fail trying to serialize back # the JSON return response = json.loads(out[0]) if response['exception']: raise Exception(response['exception']) return response['return']
def get_python_executable(conn): """ Try to determine the remote Python version so that it can be used when executing. Avoids the problem of different Python versions, or distros that do not use ``python`` but do ``python3`` """ # executables in order of preference: executables = ['python3', 'python', 'python2.7'] for executable in executables: conn.logger.debug( 'trying to determine remote python executable with %s' % executable) out, err, code = check(conn, ['which', executable]) if code: conn.logger.warning('skipping %s, was not found in path' % executable) else: try: return out[0].strip() except IndexError: conn.logger.warning('could not parse stdout: %s' % out) # if all fails, we just return whatever the main connection had conn.logger.info('Falling back to using interpreter: %s' % conn.interpreter) return conn.interpreter
def ceph_is_installed(conn): try: stdout, stderr, exit_code = check(conn, ['which', 'ceph']) except RuntimeError: conn.logger.exception('failed to check if ceph is available in the path') # XXX this might be incorrect return False if exit_code != 0: return False return True
def ceph_version(conn): try: output, _, exit_code = check(conn, ['ceph', '--version']) if exit_code != 0: conn.logger.error( 'Non zero exit status received, unable to retrieve information' ) return return output[0] except RuntimeError: conn.logger.exception('failed to fetch ceph version')
def ceph_socket_version(conn, socket): try: output, _, _ = check(conn, ['ceph', '--admin-daemon', socket, 'version']) result = dict() try: result = json.loads(output[0]) except ValueError: conn.logger.exception( "failed to fetch ceph socket version, invalid json: %s" % output[0]) return result except RuntimeError: conn.logger.exception('failed to fetch ceph socket version')
def ceph_status(conn): try: # collects information using ceph -s stdout, stderr, exit_code = check( conn, ['sudo', 'ceph', '-s', '--format', 'json']) result = dict() try: result = json.loads(''.join(stdout)) except ValueError: conn.logger.exception( "failed to fetch ceph status, invalid json: %s" % ''.join(stdout)) if exit_code == 0: return result else: return {} except RuntimeError: conn.logger.exception('failed to fetch ceph status')
def daemon_socket_config(conn, socket): """ Capture daemon-based config from the socket """ try: output, _, _ = check(conn, [ 'ceph', '--admin-daemon', socket, 'config', 'show', '--format', 'json' ]) result = dict() try: result = json.loads(output[0]) except ValueError: conn.logger.exception( "failed to fetch ceph configuration via socket, invalid json: %s" % output[0]) return result except RuntimeError: conn.logger.exception('failed to fetch ceph configuration via socket')
def ceph_socket_version(conn, socket): try: result = dict() output, _, exit_code = check( conn, ['ceph', '--admin-daemon', socket, 'version']) if exit_code != 0: conn.logger.error( 'Non zero exit status received, unable to retrieve information' ) return result try: result = json.loads(output[0]) except ValueError: conn.logger.exception( "failed to fetch ceph socket version, invalid json: %s" % output[0]) return result except RuntimeError: conn.logger.exception('failed to fetch ceph socket version')
def ceph_osd_dump(conn): try: stdout, stderr, exit_code = check( conn, ['sudo', 'ceph', 'osd', 'dump', '--format', 'json']) result = dict() if exit_code != 0: conn.logger.error('could not get osd dump from ceph') if stderr: for line in stderr: conn.logger.error(line) return result try: result = json.loads(''.join(stdout)) except ValueError: conn.logger.exception( "failed to fetch osd dump, invalid json: %s" % ''.join(stdout)) return result except RuntimeError: conn.logger.exception('failed to fetch ceph osd dump')
def get_python_executable(conn): """ Try to determine the remote Python version so that it can be used when executing. Avoids the problem of different Python versions, or distros that do not use ``python`` but do ``python3`` """ # executables in order of preference: executables = ['python3', 'python', 'python2.7'] for executable in executables: conn.logger.debug('trying to determine remote python executable with %s' % executable) out, err, code = check(conn, ['which', executable]) if code: conn.logger.warning('skipping %s, was not found in path' % executable) else: try: return out[0].strip() except IndexError: conn.logger.warning('could not parse stdout: %s' % out) # if all fails, we just return whatever the main connection had conn.logger.info('Falling back to using interpreter: %s' % conn.interpreter) return conn.interpreter
def daemon_socket_config(conn, socket): """ Capture daemon-based config from the socket """ try: output, _, exit_code = check(conn, [ 'ceph', '--admin-daemon', socket, 'config', 'show', '--format', 'json' ]) if exit_code != 0: conn.logger.error( 'Non zero exit status received, unable to retrieve information' ) return result = dict() try: result = json.loads(output[0]) except ValueError: conn.logger.exception( "failed to fetch ceph configuration via socket, invalid json: %s" % output[0]) return result except RuntimeError: conn.logger.exception('failed to fetch ceph configuration via socket')
def remote_cmd_list(conn, cmd_str): stdout, stderr, status = check(conn, cmd_str, shell=True) if status != 0: raise FailedExecError(cmd_str, 'exit code: %d, error msg: %s' % (status, '\n'.join(stderr))) return stdout
def ceph_version(conn): try: output, _, _ = check(conn, ['ceph', '--version']) return output[0] except RuntimeError: conn.logger.exception('failed to fetch ceph version')
# https://pypi.org/project/remoto/ import remoto from remoto.process import check, run conn = remoto.Connection('localhost') print(check(conn, ['ls', '/nonexistent/path'])) conn = remoto.connection.get('ssh')('localhost') print(check(conn, ['sh', '-c', 'source ~/.bashrc'])) run(conn, ['whoami'])
def container_platform(platform='openshift'): """ Connect to a container platform (kubernetes or openshift), retrieve all the available pods that match the namespace (defaults to 'rook-ceph'), and return a dictionary including them, regardless of state. """ local_conn = connection.get('local')() options = _platform_options(platform) context = options.get('context') namespace = options.get('namespace') executable = 'oc' if platform == 'openshift' else 'kubectl' if context: cmd = [executable, '--context', context] else: cmd = [executable] cmd.extend(['--request-timeout=5', 'get', '-n', namespace, 'pods', '-o', 'json']) try: out, err, code = process.check(local_conn, cmd) except RuntimeError: out = "{}" terminal.error('Unable to retrieve the pods using command: %s' % ' '.join(cmd)) else: if code: output = out + err for line in output: terminal.error(line) try: pods = json.loads(''.join(out)) except Exception: # Python3 has JSONDecodeError which doesn't exist in Python2 # Python2 just raises ValueError stdout = ''.join(out) stderr = ''.join(err) logger.exception('Invalid JSON from stdout') terminal.error('Unable to load JSON from stdout') if stdout: logger.error('stdout: %s', stdout) terminal.error('stdout: %s' % stdout) if stderr: logger.error('stderr: %s', stderr) terminal.error('stderr: %s' % stderr) raise SystemExit(1) base_inventory = { 'rgws': [], 'mgrs': [], 'mdss': [], 'clients': [], 'osds': [], 'mons': [] } label_map = { 'rook-ceph-mgr': 'mgrs', 'rook-ceph-mon': 'mons', 'rook-ceph-osd': 'osds', 'rook-ceph-mds': 'mdss', 'rook-ceph-rgw': 'rgws', 'rook-ceph-client': 'clients', } for item in pods.get('items', {}): label_name = item['metadata'].get('labels', {}).get('app') if not label_name: continue if label_name in label_map: inventory_key = label_map[label_name] base_inventory[inventory_key].append( {'host': item['metadata']['name'], 'group': None} ) for key, value in dict(base_inventory).items(): if not value: base_inventory.pop(key) return base_inventory