Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev: bootstrap: more robust implementation for ssh_merge (bsc#1230530) #1610

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions crmsh/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# simplicity and flexibility.
#
import codecs
import io
import os
import subprocess
import sys
Expand All @@ -33,7 +34,7 @@
from . import tmpfiles
from . import lock
from . import userdir
from .constants import SSH_OPTION, QDEVICE_HELP_INFO, STONITH_TIMEOUT_DEFAULT,\
from .constants import QDEVICE_HELP_INFO, STONITH_TIMEOUT_DEFAULT,\
REJOIN_COUNT, REJOIN_INTERVAL, PCMK_DELAY_MAX, CSYNC2_SERVICE, WAIT_TIMEOUT_MS_DEFAULT
from . import qdevice
from . import parallax
Expand Down Expand Up @@ -890,7 +891,7 @@ def _init_ssh_on_remote_nodes(
public_key_list.append(swap_public_ssh_key(node, local_user, remote_user, local_user, remote_user, add=True))
if len(user_node_list) > 1:
shell = sh.LocalShell()
shell_script = _merge_authorized_keys(public_key_list)
shell_script = _merge_line_into_file('~/.ssh/authorized_keys', public_key_list).encode('utf-8')
for i, (remote_user, node) in enumerate(user_node_list):
result = shell.su_subprocess_run(
local_user,
Expand Down Expand Up @@ -924,16 +925,18 @@ def _init_ssh_for_secondary_user_on_remote_nodes(
authorized_key_manager.add(None, user, key)


def _merge_authorized_keys(keys: typing.List[str]) -> bytes:
shell_script = '''for key in "${keys[@]}"; do
grep -F "$key" ~/.ssh/authorized_keys > /dev/null || sed -i "\\$a $key" ~/.ssh/authorized_keys
done'''
keys_definition = ("keys+=('{}')\n".format(key) for key in keys)
buf = bytearray()
def _merge_line_into_file(path: str, lines: typing.Iterable[str]) -> str:
shell_script = '''[ -e "$path" ] || echo '# created by crmsh' > "$path"
for key in "${keys[@]}"; do
grep -F "$key" "$path" > /dev/null || sed -i "\\$a $key" "$path"
done'''
keys_definition = ("keys+=('{}')\n".format(key) for key in lines)
buf = io.StringIO()
buf.write(f'path={path}\n')
for item in keys_definition:
buf.extend(item.encode('utf-8'))
buf.extend(shell_script.encode('utf-8'))
return buf
buf.write(item)
buf.write(shell_script)
return buf.getvalue()


def _fetch_core_hosts(shell: sh.ClusterShell, remote_host) -> typing.Tuple[typing.List[str], typing.List[str]]:
Expand Down Expand Up @@ -1771,7 +1774,7 @@ def join_ssh_merge(cluster_node, remote_user):
# create local entry in known_hosts
shell.ssh_to_localhost(None, 'true')

known_hosts_new = set()
known_hosts_new: set[str] = set()

cat_cmd = "[ -e ~/.ssh/known_hosts ] && cat ~/.ssh/known_hosts || true"
#logger_utils.log_only_to_file("parallax.call {} : {}".format(hosts, cat_cmd))
Expand All @@ -1781,10 +1784,9 @@ def join_ssh_merge(cluster_node, remote_user):
known_hosts_new.update((utils.to_ascii(known_hosts_content) or "").splitlines())

if known_hosts_new:
hoststxt = "\n".join(sorted(known_hosts_new))
#results = parallax.parallax_copy(hosts, tmpf, known_hosts_path, strict=False)
script = _merge_line_into_file('~/.ssh/known_hosts', known_hosts_new)
for host in hosts:
utils.write_remote_file(hoststxt, "~/.ssh/known_hosts", utils.user_of(host), host)
shell.get_stdout_or_raise_error(script, host)


def setup_passwordless_with_other_nodes(init_node, remote_user):
Expand Down
18 changes: 1 addition & 17 deletions crmsh/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -699,22 +699,6 @@ def str2file(s, fname, mod=0o644):
return False
return True

def write_remote_file(text, tofile, user, remote):
shell_script = f'''cat >> {tofile} << EOF
{text}
EOF
'''
result = sh.cluster_shell().subprocess_run_without_input(
remote,
user,
shell_script,
stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
)
if result.returncode != 0:
raise ValueError("Failed to write to {}@{}/{}: {}".format(user, remote, tofile, result.stdout.decode('utf-8')))


def copy_remote_textfile(remote_user, remote_node, remote_text_file, local_path):
"""
scp might lack permissions to copy the file for a non-root user.
Expand Down Expand Up @@ -2341,7 +2325,7 @@ def get_interfaces_info(self):

def flatten_custom_nic_addr_list(self) -> None:
"""
If NIC or IP is provided by the -i option, convert them to
If NIC or IP is provided by the -i option, convert them to
nic list and address list, and do some validations
"""
for item in self._custom_nic_addr_list:
Expand Down