diff options
Diffstat (limited to '')
-rw-r--r-- | test_container/Dockerfile | 28 | ||||
-rw-r--r-- | test_container/behave-agent.socket | 9 | ||||
-rw-r--r-- | test_container/behave-agent@.service | 9 | ||||
-rwxr-xr-x | test_container/behave_agent.py | 131 |
4 files changed, 177 insertions, 0 deletions
diff --git a/test_container/Dockerfile b/test_container/Dockerfile new file mode 100644 index 0000000..c099d31 --- /dev/null +++ b/test_container/Dockerfile @@ -0,0 +1,28 @@ +FROM opensuse/leap:15.5 +MAINTAINER Xin Liang <XLiang@suse.com> + +CMD ["/usr/lib/systemd/systemd", "--system"] + +RUN zypper refresh && \ + zypper -n install systemd \ + make autoconf automake vim which libxslt-tools mailx iproute2 iputils bzip2 openssh tar file glibc-locale-base firewalld libopenssl1_1 dos2unix iptables \ + python3 python3-pip python3-lxml python3-python-dateutil python3-setuptools python3-PyYAML python3-curses python3-behave \ + csync2 libglue-devel corosync corosync-qdevice pacemaker booth corosync-qnetd +RUN zypper --non-interactive up zypper && \ + zypper ar -f -G https://download.opensuse.org/repositories/network:/ha-clustering:/Factory/SLE_15_SP4 repo_nhf && \ + zypper --non-interactive refresh && \ + zypper --non-interactive up --allow-vendor-change -y resource-agents libqb100 pacemaker + +RUN ssh-keygen -t rsa -f /root/.ssh/id_rsa -N '' && \ + cp /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys && \ + chmod 0600 /root/.ssh/authorized_keys + + +RUN python3 -m pip install coverage + +RUN mkdir -p /var/log/crmsh + +COPY behave_agent.py /opt +COPY behave-agent.socket /etc/systemd/system +COPY behave-agent@.service /etc/systemd/system +RUN systemctl enable behave-agent.socket diff --git a/test_container/behave-agent.socket b/test_container/behave-agent.socket new file mode 100644 index 0000000..1212d30 --- /dev/null +++ b/test_container/behave-agent.socket @@ -0,0 +1,9 @@ +[Unit] +Description=behave test agent + +[Socket] +ListenStream=1122 +Accept=yes + +[Install] +WantedBy=sockets.target diff --git a/test_container/behave-agent@.service b/test_container/behave-agent@.service new file mode 100644 index 0000000..eadc420 --- /dev/null +++ b/test_container/behave-agent@.service @@ -0,0 +1,9 @@ +[Unit] +Description=behave test agent +CollectMode=inactive-or-failed + +[Service] +ExecStart=/opt/behave_agent.py +StandardInput=socket +StandardOutput=socket +StandardError=journal diff --git a/test_container/behave_agent.py b/test_container/behave_agent.py new file mode 100755 index 0000000..49d32d4 --- /dev/null +++ b/test_container/behave_agent.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 +import io +import os +import pwd +import socket +import struct +import subprocess + + +MSG_EOF = 0 +MSG_USER = 1 +MSG_CMD = 2 +MSG_OUT = 4 +MSG_ERR = 5 +MSG_RC = 6 + + +class Message: + @staticmethod + def write(output, type: int, data: bytes): + output.write(struct.pack('!ii', type, len(data))) + output.write(data) + + @staticmethod + def read(input): + buf = input.read(8) + type, length = struct.unpack('!ii', buf) + if length > 0: + buf = input.read(length) + else: + buf = b'' + return type, buf + + +class SocketIO(io.RawIOBase): + def __init__(self, s: socket.socket): + self._socket = s + + def readable(self) -> bool: + return True + + def writable(self) -> bool: + return True + + def read(self, __size: int = -1) -> bytes: + return self._socket.recv(__size) + + def readinto(self, __buffer) -> int: + return self._socket.recv_into(__buffer) + + def readall(self) -> bytes: + raise NotImplementedError + + def write(self, __b) -> int: + return self._socket.send(__b) + + +def call(host: str, port: int, cmdline: str): + family, type, proto, _, sockaddr = socket.getaddrinfo(host, port, type=socket.SOCK_STREAM)[0] + with socket.socket(family, type, proto) as s: + s.connect(sockaddr) + sout = io.BufferedWriter(SocketIO(s), 4096) + Message.write(sout, MSG_USER, _getuser().encode('utf-8')) + Message.write(sout, MSG_CMD, cmdline.encode('utf-8')) + Message.write(sout, MSG_EOF, b'') + sout.flush() + s.shutdown(socket.SHUT_WR) + rc = None + stdout = [] + stderr = [] + sin = io.BufferedReader(SocketIO(s), 4096) + while True: + type, buf = Message.read(sin) + if type == MSG_OUT: + stdout.append(buf) + elif type == MSG_ERR: + stderr.append(buf) + elif type == MSG_RC: + rc, = struct.unpack('!i', buf) + elif type == MSG_EOF: + s.shutdown(socket.SHUT_RD) + assert rc is not None + return rc, b''.join(stdout), b''.join(stderr) + else: + raise ValueError(f"Unknown message type: {type}") + + +def serve(stdin, stdout, stderr): + assert os.geteuid() == 0 + user = None + cmd = None + sin = io.BufferedReader(stdin) + while True: + type, buf = Message.read(sin) + if type == MSG_USER: + user = buf.decode('utf-8') + elif type == MSG_CMD: + cmd = buf.decode('utf-8') + elif type == MSG_EOF: + assert user is not None + assert cmd is not None + break + else: + raise ValueError(f"Unknown message type: {type}") + if user == 'root': + args = ['/bin/sh'] + else: + args = ['/bin/su', '-', user, '-c', '/bin/sh'] + result = subprocess.run( + args, + input=cmd.encode('utf-8'), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + sout = io.BufferedWriter(stdout) + Message.write(sout, MSG_RC, struct.pack('!i', result.returncode)) + Message.write(sout, MSG_OUT, result.stdout) + Message.write(sout, MSG_ERR, result.stderr) + Message.write(sout, MSG_EOF, b'') + stdout.flush() + + +def _getuser(): + return pwd.getpwuid(os.geteuid()).pw_name + + +if __name__ == '__main__': + with open(0, 'rb') as stdin, \ + open(1, 'wb') as stdout, \ + open(2, 'wb') as stderr: + serve(stdin, stdout, stderr) |