From: Melissa Date: Wed, 21 Jul 2021 03:12:21 +0000 (-0400) Subject: mgr/cephadm: use _remote_connection (ssh.py), _execute_command, _check_execute_comman... X-Git-Tag: v17.1.0~1051^2~5 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=25c989c1afde389a969888feaa1e3b1cd214c424;p=ceph-ci.git mgr/cephadm: use _remote_connection (ssh.py), _execute_command, _check_execute_command in _run_cephadm remove _get_connection from module.py and _remote_connection in serve.py, replacing with _remote_connection in ssh.py. also, replace remoto.process.check with _execute_command and _check_execute_command in ssh.py Fixes: https://tracker.ceph.com/issues/44676 Signed-off-by: Melissa Li --- diff --git a/src/pybind/mgr/cephadm/module.py b/src/pybind/mgr/cephadm/module.py index 87a76debfab..b278cc54b87 100644 --- a/src/pybind/mgr/cephadm/module.py +++ b/src/pybind/mgr/cephadm/module.py @@ -1244,35 +1244,6 @@ class CephadmOrchestrator(orchestrator.Orchestrator, MgrModule, self._kick_serve_loop() return HandleCommandResult() - def _get_connection(self, host: str) -> Tuple['remoto.backends.BaseConnection', - 'remoto.backends.LegacyModuleExecute']: - """ - Setup a connection for running commands on remote host. - """ - conn, r = self._cons.get(host, (None, None)) - if conn: - if conn.has_connection(): - self.log.debug('Have connection to %s' % host) - return conn, r - else: - self._reset_con(host) - assert self.ssh_user - n = self.ssh_user + '@' + host - self.log.debug("Opening connection to {} with ssh options '{}'".format( - n, self._ssh_options)) - child_logger = self.log.getChild(n) - child_logger.setLevel('WARNING') - conn = remoto.Connection( - n, - logger=child_logger, - ssh_options=self._ssh_options, - sudo=True if self.ssh_user != 'root' else False) - - r = conn.import_module(remotes) - self._cons[host] = conn, r - - return conn, r - def _get_container_image(self, daemon_name: str) -> Optional[str]: daemon_type = daemon_name.split('.', 1)[0] # type: ignore image: Optional[str] = None diff --git a/src/pybind/mgr/cephadm/serve.py b/src/pybind/mgr/cephadm/serve.py index f09e8a033a6..8cc13076c7b 100644 --- a/src/pybind/mgr/cephadm/serve.py +++ b/src/pybind/mgr/cephadm/serve.py @@ -3,7 +3,6 @@ import json import logging import uuid from collections import defaultdict -from contextlib import contextmanager from typing import TYPE_CHECKING, Optional, List, cast, Dict, Any, Union, Tuple, Iterator try: import remoto @@ -1161,97 +1160,88 @@ class CephadmServe: :env_vars: in format -> [KEY=VALUE, ..] """ + + self.mgr.ssh.remote_connection(host, addr) + self.log.debug(f"_run_cephadm : command = {command}") self.log.debug(f"_run_cephadm : args = {args}") bypass_image = ('cephadm-exporter',) - with self._remote_connection(host, addr) as tpl: - conn, connr = tpl - assert image or entity - # Skip the image check for daemons deployed that are not ceph containers - if not str(entity).startswith(bypass_image): - if not image and entity is not cephadmNoImage: - image = self.mgr._get_container_image(entity) + assert image or entity + # Skip the image check for daemons deployed that are not ceph containers + if not str(entity).startswith(bypass_image): + if not image and entity is not cephadmNoImage: + image = self.mgr._get_container_image(entity) - final_args = [] + final_args = [] - # global args - if env_vars: - for env_var_pair in env_vars: - final_args.extend(['--env', env_var_pair]) + # global args + if env_vars: + for env_var_pair in env_vars: + final_args.extend(['--env', env_var_pair]) - if image: - final_args.extend(['--image', image]) + if image: + final_args.extend(['--image', image]) - if not self.mgr.container_init: - final_args += ['--no-container-init'] + if not self.mgr.container_init: + final_args += ['--no-container-init'] - # subcommand - final_args.append(command) + # subcommand + final_args.append(command) - # subcommand args - if not no_fsid: - final_args += ['--fsid', self.mgr._cluster_fsid] + # subcommand args + if not no_fsid: + final_args += ['--fsid', self.mgr._cluster_fsid] - final_args += args + final_args += args - # exec - self.log.debug('args: %s' % (' '.join(final_args))) - if self.mgr.mode == 'root': - if stdin: - self.log.debug('stdin: %s' % stdin) + # exec + self.log.debug('args: %s' % (' '.join(final_args))) + if self.mgr.mode == 'root': + if stdin: + self.log.debug('stdin: %s' % stdin) - python = connr.choose_python() - if not python: - raise RuntimeError( - 'unable to find python on %s (tried %s in %s)' % ( - host, remotes.PYTHONS, remotes.PATH)) - try: - out, err, code = remoto.process.check( - conn, - [python, self.mgr.cephadm_binary_path] + final_args, - stdin=stdin.encode('utf-8') if stdin is not None else None) - if code == 2: - out_ls, err_ls, code_ls = remoto.process.check( - conn, ['ls', self.mgr.cephadm_binary_path]) - if code_ls == 2: - self._deploy_cephadm_binary_conn(conn, host) - out, err, code = remoto.process.check( - conn, - [python, self.mgr.cephadm_binary_path] + final_args, - stdin=stdin.encode('utf-8') if stdin is not None else None) - - except RuntimeError as e: - self.mgr._reset_con(host) - if error_ok: - return [], [str(e)], 1 - raise + cmd = ['which', 'python3'] + python = self.mgr.ssh.check_execute_command(host, cmd, addr=addr) + cmd = [python, self.mgr.cephadm_binary_path] + final_args - elif self.mgr.mode == 'cephadm-package': - try: - out, err, code = remoto.process.check( - conn, - ['sudo', '/usr/bin/cephadm'] + final_args, - stdin=stdin) - except RuntimeError as e: - self.mgr._reset_con(host) - if error_ok: - return [], [str(e)], 1 - raise - else: - assert False, 'unsupported mode' - - self.log.debug('code: %d' % code) - if out: - self.log.debug('out: %s' % '\n'.join(out)) - if err: - self.log.debug('err: %s' % '\n'.join(err)) - if code and not error_ok: - raise OrchestratorError( - 'cephadm exited with an error code: %d, stderr:%s' % ( - code, '\n'.join(err))) - return out, err, code + try: + out, err, code = self.mgr.ssh.execute_command(host, cmd, stdin=stdin.encode('utf-8') if stdin else None, addr=addr) + if code == 2: + ls_cmd = ['ls', self.mgr.cephadm_binary_path] + out_ls, err_ls, code_ls = self.mgr.ssh.execute_command(host, ls_cmd, addr=addr) + if code_ls == 2: + self._deploy_cephadm_binary(host, addr) + out, err, code = self.mgr.ssh.execute_command(host, cmd, stdin=stdin.encode('utf-8') if stdin else None, addr=addr) + + except Exception as e: + self.mgr.ssh._reset_con(host) + if error_ok: + return [], [str(e)], 1 + raise + + elif self.mgr.mode == 'cephadm-package': + try: + cmd = ['/usr/bin/cephadm'] + final_args + out, err, code = self.mgr.ssh.execute_command(host, cmd, stdin=stdin.encode('utf-8') if stdin else None, addr=addr) + except Exception as e: + self.mgr.ssh._reset_con(host) + if error_ok: + return [], [str(e)], 1 + raise + else: + assert False, 'unsupported mode' + + self.log.debug(f'code: {code}') + if out: + self.log.debug(f'out: {out}') + if err: + self.log.debug(f'err: {err}') + if code and not error_ok: + raise OrchestratorError( + f'cephadm exited with an error code: {code}, stderr: {err}') + return [out], [err], code def _get_container_image_info(self, image_name: str) -> ContainerInspectInfo: # pick a random host... @@ -1314,55 +1304,3 @@ class CephadmServe: msg = f"Unable to deploy the cephadm binary to {host}: {_err}" self.log.warning(msg) raise OrchestratorError(msg) - @contextmanager - def _remote_connection(self, - host: str, - addr: Optional[str] = None, - ) -> Iterator[Tuple["BaseConnection", Any]]: - if not addr and host in self.mgr.inventory: - addr = self.mgr.inventory.get_addr(host) - - self.mgr.offline_hosts_remove(host) - - try: - try: - if not addr: - raise OrchestratorError("host address is empty") - conn, connr = self.mgr._get_connection(addr) - except OSError as e: - self.mgr._reset_con(host) - msg = f"Can't communicate with remote host `{addr}`, possibly because python3 is not installed there: {str(e)}" - raise execnet.gateway_bootstrap.HostNotFound(msg) - - yield (conn, connr) - - except execnet.gateway_bootstrap.HostNotFound as e: - # this is a misleading exception as it seems to be thrown for - # any sort of connection failure, even those having nothing to - # do with "host not found" (e.g., ssh key permission denied). - self.mgr.offline_hosts.add(host) - self.mgr._reset_con(host) - - user = self.mgr.ssh_user if self.mgr.mode == 'root' else 'cephadm' - if str(e).startswith("Can't communicate"): - msg = str(e) - else: - msg = f'''Failed to connect to {host} ({addr}). -Please make sure that the host is reachable and accepts connections using the cephadm SSH key - -To add the cephadm SSH key to the host: -> ceph cephadm get-pub-key > ~/ceph.pub -> ssh-copy-id -f -i ~/ceph.pub {user}@{addr} - -To check that the host is reachable open a new shell with the --no-hosts flag: -> cephadm shell --no-hosts - -Then run the following: -> ceph cephadm get-ssh-config > ssh_config -> ceph config-key get mgr/cephadm/ssh_identity_key > ~/cephadm_private_key -> chmod 0600 ~/cephadm_private_key -> ssh -F ssh_config -i ~/cephadm_private_key {user}@{addr}''' - raise OrchestratorError(msg) from e - except Exception as ex: - self.log.exception(ex) - raise