晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
|
Server : Apache System : Linux srv.rainic.com 4.18.0-553.47.1.el8_10.x86_64 #1 SMP Wed Apr 2 05:45:37 EDT 2025 x86_64 User : rainic ( 1014) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /lib/python3.6/site-packages/sos/collector/transports/ |
Upload File : |
# Copyright Red Hat 2021, Jake Hunsaker <jhunsake@redhat.com>
# This file is part of the sos project: https://github.com/sosreport/sos
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions of
# version 2 of the GNU General Public License.
#
# See the LICENSE file in the source distribution for further information.
import json
import tempfile
import os
from sos.collector.transports import RemoteTransport
from sos.utilities import (is_executable, sos_get_command_output,
SoSTimeoutError)
class OCTransport(RemoteTransport):
"""
This transport leverages the execution of commands via a locally
available and configured ``oc`` binary for OCPv4 environments.
The location of the oc binary MUST be in the $PATH used by the locally
loaded SoS policy. Specifically this means that the binary cannot be in the
running user's home directory, such as ~/.local/bin.
OCPv4 clusters generally discourage the use of SSH, so this transport may
be used to remove our use of SSH in favor of the environment provided
method of connecting to nodes and executing commands via debug pods.
The debug pod created will be a privileged pod that mounts the host's
filesystem internally so that sos report collections reflect the host, and
not the container in which it runs.
This transport will execute within a temporary 'sos-collect-tmp' project
created by the OCP cluster profile. The project will be removed at the end
of execution.
In the event of failures due to a misbehaving OCP API or oc binary, it is
recommended to fallback to the control_persist transport by manually
setting the --transport option.
"""
name = 'oc'
project = 'sos-collect-tmp'
def run_oc(self, cmd, **kwargs):
"""Format and run a command with `oc` in the project defined for our
execution
"""
return sos_get_command_output(
f"oc -n {self.project} {cmd}",
**kwargs
)
@property
def connected(self):
up = self.run_oc(
f"wait --timeout=0s --for=condition=ready pod/{self.pod_name}"
)
return up['status'] == 0
def get_node_pod_config(self):
"""Based on our template for the debug container, add the node-specific
items so that we can deploy one of these on each node we're collecting
from
"""
return {
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": f"{self.address.split('.')[0]}-sos-collector",
"namespace": self.project
},
"priorityClassName": "system-cluster-critical",
"spec": {
"volumes": [
{
"name": "host",
"hostPath": {
"path": "/",
"type": "Directory"
}
},
{
"name": "run",
"hostPath": {
"path": "/run",
"type": "Directory"
}
},
{
"name": "varlog",
"hostPath": {
"path": "/var/log",
"type": "Directory"
}
},
{
"name": "machine-id",
"hostPath": {
"path": "/etc/machine-id",
"type": "File"
}
}
],
"containers": [
{
"name": "sos-collector-tmp",
"image": "registry.redhat.io/rhel8/support-tools"
if not self.opts.image else self.opts.image,
"command": [
"/bin/bash"
],
"env": [
{
"name": "HOST",
"value": "/host"
}
],
"resources": {},
"volumeMounts": [
{
"name": "host",
"mountPath": "/host"
},
{
"name": "run",
"mountPath": "/run"
},
{
"name": "varlog",
"mountPath": "/var/log"
},
{
"name": "machine-id",
"mountPath": "/etc/machine-id"
}
],
"securityContext": {
"privileged": True,
"runAsUser": 0
},
"stdin": True,
"stdinOnce": True,
"tty": True
}
],
"imagePullPolicy":
"Always" if self.opts.force_pull_image else "IfNotPresent",
"restartPolicy": "Never",
"nodeName": self.address,
"hostNetwork": True,
"hostPID": True,
"hostIPC": True
}
}
def _connect(self, password):
# the oc binary must be _locally_ available for this to work
if not is_executable('oc'):
return False
# deploy the debug container we'll exec into
podconf = self.get_node_pod_config()
self.pod_name = podconf['metadata']['name']
fd, self.pod_tmp_conf = tempfile.mkstemp(dir=self.tmpdir)
with open(fd, 'w', encoding='utf-8') as cfile:
json.dump(podconf, cfile)
self.log_debug(f"Starting sos collector container '{self.pod_name}'")
# this specifically does not need to run with a project definition
out = sos_get_command_output(
f"oc create -f {self.pod_tmp_conf}"
)
if (out['status'] != 0 or f"pod/{self.pod_name} created" not in
out['output']):
self.log_error("Unable to deploy sos collect pod")
self.log_debug(f"Debug pod deployment failed: {out['output']}")
return False
self.log_debug(f"Pod '{self.pod_name}' successfully deployed, waiting "
"for pod to enter ready state")
# wait for the pod to report as running
try:
up = self.run_oc(f"wait --for=condition=Ready pod/{self.pod_name} "
"--timeout=30s",
# timeout is for local safety, not oc
timeout=40)
if not up['status'] == 0:
self.log_error("Pod not available after 30 seconds")
return False
except SoSTimeoutError:
self.log_error("Timeout while polling for pod readiness")
return False
except Exception as err:
self.log_error(f"Error while waiting for pod to be ready: {err}")
return False
return True
def _format_cmd_for_exec(self, cmd):
if cmd.startswith('oc'):
return (f"oc -n {self.project} exec --request-timeout=0 "
f"{self.pod_name} -- chroot /host {cmd}")
return super()._format_cmd_for_exec(cmd)
def run_command(self, cmd, timeout=180, need_root=False, env=None,
use_shell=False):
# debug pod setup is slow, extend all timeouts to account for this
if timeout:
timeout += 10
# since we always execute within a bash shell, force disable use_shell
# to avoid double-quoting
return super().run_command(cmd, timeout, need_root,
env, use_shell=False)
def _disconnect(self):
if os.path.exists(self.pod_tmp_conf):
os.unlink(self.pod_tmp_conf)
removed = self.run_oc(f"delete pod {self.pod_name}")
if "deleted" not in removed['output']:
self.log_debug(f"Calling delete on pod '{self.pod_name}' failed: "
f"{removed}")
return False
return True
@property
def remote_exec(self):
return (f"oc -n {self.project} exec --request-timeout=0 "
f"{self.pod_name} -- /bin/bash -c")
def _copy_file_to_remote(self, fname, dest):
result = self.run_oc("cp --retries", stderr=True)
flags = '' if "unknown flag" in result["output"] else '--retries=5'
cmd = self.run_oc(f"cp {flags} {fname} {self.pod_name}:{dest}",
timeout=15)
return cmd['status'] == 0
def _retrieve_file(self, fname, dest):
# check if --retries flag is available for given version of oc
result = self.run_oc("cp --retries", stderr=True)
flags = '' if "unknown flag" in result["output"] else '--retries=5'
cmd = self.run_oc(f"cp {flags} {self.pod_name}:{fname} {dest}")
return cmd['status'] == 0