| |
@@ -4,12 +4,12 @@
|
| |
from subprocess import Popen
|
| |
import time
|
| |
from urlparse import urlparse
|
| |
+ import paramiko
|
| |
|
| |
- from ansible.runner import Runner
|
| |
from backend.vm_manage import PUBSUB_INTERRUPT_BUILDER
|
| |
from ..helpers import get_redis_connection, ensure_dir_exists
|
| |
|
| |
- from ..exceptions import BuilderError, BuilderTimeOutError, AnsibleCallError, AnsibleResponseError, VmError
|
| |
+ from ..exceptions import BuilderError, BuilderTimeOutError, RemoteCmdError, VmError
|
| |
|
| |
from ..constants import mockchain, rsync, DEF_BUILD_TIMEOUT
|
| |
|
| |
@@ -35,8 +35,8 @@
|
| |
self.remote_pkg_name = None
|
| |
|
| |
# if we're at this point we've connected and done stuff on the host
|
| |
- self.conn = self._create_ans_conn()
|
| |
- self.root_conn = self._create_ans_conn(username="root")
|
| |
+ self.conn = self._create_ssh_conn()
|
| |
+ self.root_conn = self._create_ssh_conn(username="root")
|
| |
|
| |
self.module_dist_tag = self._load_module_dist_tag()
|
| |
|
| |
@@ -70,19 +70,14 @@
|
| |
create_tmpdir_cmd = "/bin/mktemp -d {0}/{1}-XXXXX".format(
|
| |
self._remote_basedir, "mockremote")
|
| |
|
| |
- results = self._run_ansible(create_tmpdir_cmd)
|
| |
-
|
| |
- tempdir = None
|
| |
- # TODO: use check_for_ans_error
|
| |
- for _, resdict in results["contacted"].items():
|
| |
- tempdir = resdict["stdout"]
|
| |
+ tempdir = self._run_ssh_cmd(create_tmpdir_cmd)[0].strip()
|
| |
|
| |
# if still nothing then we"ve broken
|
| |
if not tempdir:
|
| |
raise BuilderError("Could not make tmpdir on {0}".format(
|
| |
self.hostname))
|
| |
|
| |
- self._run_ansible("/bin/chmod 755 {0}".format(tempdir))
|
| |
+ self._run_ssh_cmd("/bin/chmod 755 {0}".format(tempdir))
|
| |
self._remote_tempdir = tempdir
|
| |
|
| |
return self._remote_tempdir
|
| |
@@ -91,50 +86,36 @@
|
| |
def tempdir(self, value):
|
| |
self._remote_tempdir = value
|
| |
|
| |
- def _create_ans_conn(self, username=None):
|
| |
- ans_conn = Runner(remote_user=username or self.opts.build_user,
|
| |
- host_list=self.hostname + ",",
|
| |
- pattern=self.hostname,
|
| |
- forks=1,
|
| |
- transport=self.opts.ssh.transport,
|
| |
- timeout=self.timeout)
|
| |
- return ans_conn
|
| |
-
|
| |
- def run_ansible_with_check(self, cmd, module_name=None, as_root=False,
|
| |
- err_codes=None, success_codes=None):
|
| |
-
|
| |
- results = self._run_ansible(cmd, module_name, as_root)
|
| |
-
|
| |
- try:
|
| |
- check_for_ans_error(
|
| |
- results, self.hostname, err_codes, success_codes)
|
| |
- except AnsibleResponseError as response_error:
|
| |
- raise AnsibleCallError(
|
| |
- msg="Failed to execute ansible command",
|
| |
- cmd=cmd, module_name=module_name, as_root=as_root,
|
| |
- return_code=response_error.return_code,
|
| |
- stdout=response_error.stdout, stderr=response_error.stderr
|
| |
- )
|
| |
-
|
| |
- return results
|
| |
+ def _create_ssh_conn(self, username=None):
|
| |
+ conn = paramiko.SSHClient()
|
| |
+ conn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
| |
+ conn.connect(hostname=self.hostname, port=self.opts.ssh.port,
|
| |
+ username=username or self.opts.build_user)
|
| |
+ return conn
|
| |
|
| |
- def _run_ansible(self, cmd, module_name=None, as_root=False):
|
| |
+ def _run_ssh_cmd(self, cmd, as_root=False):
|
| |
"""
|
| |
- Executes single ansible module
|
| |
+ Executes single shell command remotely
|
| |
|
| |
- :param str cmd: module command
|
| |
- :param str module_name: name of the invoked module
|
| |
+ :param str cmd: shell command
|
| |
:param bool as_root:
|
| |
- :return: ansible command result
|
| |
+ :return: stdout, stderr as strings
|
| |
"""
|
| |
if as_root:
|
| |
conn = self.root_conn
|
| |
else:
|
| |
conn = self.conn
|
| |
|
| |
- conn.module_name = module_name or "shell"
|
| |
- conn.module_args = str(cmd)
|
| |
- return conn.run()
|
| |
+ self.log.info("BUILDER CMD: "+cmd)
|
| |
+
|
| |
+ stdin, stdout, stderr = conn.exec_command(cmd)
|
| |
+ rc = stdout.channel.recv_exit_status() # blocks
|
| |
+ out, err = stdout.read(), stderr.read()
|
| |
+
|
| |
+ if rc != 0:
|
| |
+ raise RemoteCmdError("Error running remote ssh command.",
|
| |
+ cmd, rc, as_root, err, out)
|
| |
+ return out, err
|
| |
|
| |
def _get_remote_results_dir(self):
|
| |
if any(x is None for x in [self.remote_build_dir,
|
| |
@@ -156,13 +137,8 @@
|
| |
Packages in buildroot_pkgs are added to minimal buildroot.
|
| |
"""
|
| |
cfg_path = self.get_chroot_config_path(self.job.chroot)
|
| |
-
|
| |
- try:
|
| |
- copy_cmd = "cp /etc/mock/{chroot}.cfg {dest}".format(chroot=self.job.chroot, dest=cfg_path)
|
| |
- self.run_ansible_with_check(copy_cmd, module_name="shell")
|
| |
- except BuilderError as err:
|
| |
- self.log.exception(err)
|
| |
- raise err
|
| |
+ copy_cmd = "cp /etc/mock/{chroot}.cfg {dest}".format(chroot=self.job.chroot, dest=cfg_path)
|
| |
+ self._run_ssh_cmd(copy_cmd)
|
| |
|
| |
if ("'{0} '".format(self.buildroot_pkgs) !=
|
| |
pipes.quote(str(self.buildroot_pkgs) + ' ')):
|
| |
@@ -171,79 +147,53 @@
|
| |
# allowed in packages name
|
| |
raise BuilderError("Do not try this kind of attack on me")
|
| |
|
| |
- self.log.info("putting {0} into minimal buildroot of {1}"
|
| |
- .format(self.buildroot_pkgs, self.job.chroot))
|
| |
-
|
| |
- kwargs = {
|
| |
- "cfg_path": cfg_path,
|
| |
- "chroot": self.job.chroot,
|
| |
- "pkgs": self.buildroot_pkgs,
|
| |
- "net_enabled": "True" if self.job.enable_net else "False",
|
| |
- }
|
| |
- buildroot_cmd = (
|
| |
- "dest={cfg_path}"
|
| |
- " line=\"config_opts['chroot_setup_cmd'] = 'install \\1 {pkgs}'\""
|
| |
- " regexp=\"^.*chroot_setup_cmd.*(@buildsys-build|@build|buildsys-build buildsys-macros).*$\""
|
| |
- " backrefs=yes"
|
| |
- )
|
| |
- buildroot_custom_cmd = (
|
| |
- "dest={cfg_path}"
|
| |
- " line=\"config_opts['chroot_setup_cmd'] = 'install {pkgs}'\""
|
| |
- " regexp=\"config_opts\\['chroot_setup_cmd'\\] = ''$\""
|
| |
- )
|
| |
- set_networking_cmd = (
|
| |
- "dest={cfg_path}"
|
| |
- " line=\"config_opts['use_host_resolv'] = {net_enabled}\""
|
| |
- " regexp=\"^.*use_host_resolv.*$\""
|
| |
+ set_networking_cmd = "echo \"config_opts['use_host_resolv'] = {net_enabled}\" >> {path}".format(
|
| |
+ net_enabled=("True" if self.job.enable_net else "False"), path=cfg_path
|
| |
)
|
| |
-
|
| |
- try:
|
| |
- self.run_ansible_with_check(set_networking_cmd.format(**kwargs),
|
| |
- module_name="lineinfile")
|
| |
- if self.buildroot_pkgs:
|
| |
- if 'custom' in self.job.chroot:
|
| |
- self.run_ansible_with_check(buildroot_custom_cmd.format(**kwargs),
|
| |
- module_name="lineinfile")
|
| |
- else:
|
| |
- self.run_ansible_with_check(buildroot_cmd.format(**kwargs),
|
| |
- module_name="lineinfile")
|
| |
-
|
| |
- if self.module_dist_tag:
|
| |
- set_dist_tag_cmd = (
|
| |
- "dest={cfg_path}"
|
| |
- " line=\"config_opts['macros']['%dist'] = '{dist_tag}'\""
|
| |
- " regexp=\"^.*config_opts['macros']['%dist'].*$\""
|
| |
+ self._run_ssh_cmd(set_networking_cmd)
|
| |
+
|
| |
+ if self.buildroot_pkgs:
|
| |
+ if 'custom' in self.job.chroot:
|
| |
+ pattern = "^config_opts\['chroot_setup_cmd'\] = ''$"
|
| |
+ replace_by = "config_opts['chroot_setup_cmd'] = 'install {pkgs}'".format(pkgs=self.buildroot_pkgs)
|
| |
+ buildroot_custom_cmd = "sed -i \"s+{pattern}+{replace_by}+\" {path}".format(
|
| |
+ pattern=pattern, replace_by=replace_by, path=cfg_path
|
| |
)
|
| |
- self.run_ansible_with_check(set_dist_tag_cmd.format(
|
| |
- cfg_path=cfg_path, dist_tag=self.module_dist_tag), module_name="lineinfile")
|
| |
+ self._run_ssh_cmd(buildroot_custom_cmd)
|
| |
+ else:
|
| |
+ pattern = "^.*chroot_setup_cmd.*\(@buildsys-build\|@build\|buildsys-build buildsys-macros\).*$"
|
| |
+ replace_by = "config_opts['chroot_setup_cmd'] = 'install \\1 {pkgs}'".format(pkgs=self.buildroot_pkgs)
|
| |
+ buildroot_cmd = "sed -i \"s+{pattern}+{replace_by}+\" {path}".format(
|
| |
+ pattern=pattern, replace_by=replace_by, path=cfg_path
|
| |
+ )
|
| |
+ self._run_ssh_cmd(buildroot_cmd)
|
| |
|
| |
- except Exception as err:
|
| |
- self.log.exception(err)
|
| |
- raise
|
| |
+ if self.module_dist_tag:
|
| |
+ dist_tag_cmd = "echo \"config_opts['macros']['%dist'] = '{dist_tag}'\" >> {path}".format(
|
| |
+ dist_tag=self.module_dist_tag, path=cfg_path
|
| |
+ )
|
| |
+ self._run_ssh_cmd(dist_tag_cmd)
|
| |
|
| |
def collect_built_packages(self):
|
| |
self.log.info("Listing built binary packages")
|
| |
- results = self._run_ansible(
|
| |
+ built_packages = self._run_ssh_cmd(
|
| |
"cd {0} && "
|
| |
"for f in `ls *.rpm |grep -v \"src.rpm$\"`; do"
|
| |
" rpm -qp --qf \"%{{NAME}} %{{VERSION}}\n\" $f; "
|
| |
"done".format(pipes.quote(self._get_remote_results_dir()))
|
| |
- )
|
| |
-
|
| |
- built_packages = list(results["contacted"].values())[0][u"stdout"]
|
| |
+ )[0].strip()
|
| |
self.log.info("Built packages:\n{}".format(built_packages))
|
| |
return built_packages
|
| |
|
| |
def check_build_success(self):
|
| |
successfile = os.path.join(self._get_remote_results_dir(), "success")
|
| |
- ansible_test_results = self._run_ansible("/usr/bin/test -f {0}".format(successfile))
|
| |
- check_for_ans_error(ansible_test_results, self.hostname)
|
| |
+ self._run_ssh_cmd("/usr/bin/test -f {0}".format(successfile))
|
| |
|
| |
def download_job_pkg_to_builder(self):
|
| |
repo_url = "{}/{}.git".format(self.opts.dist_git_url, self.job.git_repo)
|
| |
self.log.info("Cloning Dist Git repo {}, branch {}, hash {}".format(
|
| |
self.job.git_repo, self.job.git_branch, self.job.git_hash))
|
| |
- results = self._run_ansible(
|
| |
+ stdout, stderr = self._run_ssh_cmd(
|
| |
"rm -rf /tmp/build_package_repo && "
|
| |
"mkdir /tmp/build_package_repo && "
|
| |
"cd /tmp/build_package_repo && "
|
| |
@@ -261,11 +211,11 @@
|
| |
# Wrote: /tmp/.../copr-ping/copr-ping-1-1.fc21.src.rpm
|
| |
|
| |
try:
|
| |
- self.remote_pkg_path = list(results["contacted"].values())[0][u"stdout"].split("Wrote: ")[1]
|
| |
- self.remote_pkg_name = os.path.basename(self.remote_pkg_path).replace(".src.rpm", "")
|
| |
+ self.remote_pkg_path = stdout.split("Wrote: ")[1]
|
| |
+ self.remote_pkg_name = os.path.basename(self.remote_pkg_path).replace(".src.rpm", "").strip()
|
| |
except Exception:
|
| |
self.log.exception("Failed to obtain srpm from dist-git")
|
| |
- raise BuilderError("Failed to obtain srpm from dist-git: ansible results {}".format(results))
|
| |
+ raise BuilderError("Failed to obtain srpm from dist-git: stdout: {}, stderr: {}".format(stdout, stderr))
|
| |
|
| |
self.log.info("Got srpm to build: {}".format(self.remote_pkg_path))
|
| |
|
| |
@@ -307,10 +257,6 @@
|
| |
buildcmd += self.remote_pkg_path
|
| |
return buildcmd
|
| |
|
| |
- def run_build(self, buildcmd):
|
| |
- self.log.info("executing: {0}".format(buildcmd))
|
| |
- return self._run_ansible(buildcmd)
|
| |
-
|
| |
def setup_pubsub_handler(self):
|
| |
|
| |
self.rc = get_redis_connection(self.opts)
|
| |
@@ -352,14 +298,14 @@
|
| |
|
| |
# construct the mockchain command
|
| |
buildcmd = self.gen_mockchain_command()
|
| |
- # run the mockchain command async
|
| |
- ansible_build_results = self.run_build(buildcmd)
|
| |
- check_for_ans_error(ansible_build_results, self.hostname) # on error raises AnsibleResponseError
|
| |
+ # run the mockchain command
|
| |
+ stdout, stderr = self._run_ssh_cmd(buildcmd)
|
| |
|
| |
# we know the command ended successfully but not if the pkg built
|
| |
# successfully
|
| |
self.check_build_success()
|
| |
- return get_ans_results(ansible_build_results, self.hostname).get("stdout", "")
|
| |
+
|
| |
+ return stdout
|
| |
|
| |
def rsync_call(self, source_path, target_path):
|
| |
ensure_dir_exists(target_path, self.log)
|
| |
@@ -391,7 +337,7 @@
|
| |
if cmd.returncode != 0:
|
| |
err_msg = "Failed to download data from builder due to rsync error, see the rsync log file for details."
|
| |
self.log.error(err_msg)
|
| |
- raise BuilderError(err_msg, return_code=cmd.returncode)
|
| |
+ raise BuilderError(err_msg)
|
| |
|
| |
def download_results(self, target_path):
|
| |
if self._get_remote_results_dir():
|
| |
@@ -409,80 +355,21 @@
|
| |
raise BuilderError("{0} could not be resolved".format(self.hostname))
|
| |
|
| |
try:
|
| |
- # check_for_ans_error(res, self.hostname)
|
| |
- self.run_ansible_with_check("/bin/rpm -q mock rsync")
|
| |
- except AnsibleCallError:
|
| |
+ self._run_ssh_cmd("/bin/rpm -q mock rsync")
|
| |
+ except RemoteCmdError:
|
| |
raise BuilderError(msg="Build host `{0}` does not have mock or rsync installed"
|
| |
.format(self.hostname))
|
| |
|
| |
# test for path existence for mockchain and chroot config for this chroot
|
| |
try:
|
| |
- self.run_ansible_with_check("/usr/bin/test -f {0}".format(mockchain))
|
| |
- except AnsibleCallError:
|
| |
+ self._run_ssh_cmd("/usr/bin/test -f {0}".format(mockchain))
|
| |
+ except RemoteCmdError:
|
| |
raise BuilderError(msg="Build host `{}` missing mockchain binary `{}`"
|
| |
.format(self.hostname, mockchain))
|
| |
|
| |
try:
|
| |
- self.run_ansible_with_check("/usr/bin/test -f /etc/mock/{}.cfg"
|
| |
- .format(self.job.chroot))
|
| |
- except AnsibleCallError:
|
| |
+ self._run_ssh_cmd("/usr/bin/test -f /etc/mock/{}.cfg"
|
| |
+ .format(self.job.chroot))
|
| |
+ except RemoteCmdError:
|
| |
raise BuilderError(msg="Build host `{}` missing mock config for chroot `{}`"
|
| |
.format(self.hostname, self.job.chroot))
|
| |
-
|
| |
-
|
| |
- def get_ans_results(results, hostname):
|
| |
- if hostname in results["dark"]:
|
| |
- return results["dark"][hostname]
|
| |
- if hostname in results["contacted"]:
|
| |
- return results["contacted"][hostname]
|
| |
-
|
| |
- return {}
|
| |
-
|
| |
-
|
| |
- def check_for_ans_error(results, hostname, err_codes=None, success_codes=None):
|
| |
- """
|
| |
- dict includes 'msg'
|
| |
- may include 'rc', 'stderr', 'stdout' and any other requested result codes
|
| |
-
|
| |
- :raises AnsibleResponseError:
|
| |
- :raises VmError:
|
| |
- """
|
| |
-
|
| |
- if err_codes is None:
|
| |
- err_codes = []
|
| |
- if success_codes is None:
|
| |
- success_codes = [0]
|
| |
-
|
| |
- if ("dark" in results and hostname in results["dark"]) or \
|
| |
- "contacted" not in results or hostname not in results["contacted"]:
|
| |
-
|
| |
- raise VmError(msg="Error: Could not contact/connect to {}. raw results: {}".format(hostname, results))
|
| |
-
|
| |
- error = False
|
| |
- err_results = {}
|
| |
- if err_codes or success_codes:
|
| |
- if hostname in results["contacted"]:
|
| |
- if "rc" in results["contacted"][hostname]:
|
| |
- rc = int(results["contacted"][hostname]["rc"])
|
| |
- err_results["return_code"] = rc
|
| |
- # check for err codes first
|
| |
- if rc in err_codes:
|
| |
- error = True
|
| |
- err_results["msg"] = "rc {0} matched err_codes".format(rc)
|
| |
- elif rc not in success_codes:
|
| |
- error = True
|
| |
- err_results["msg"] = "rc {0} not in success_codes".format(rc)
|
| |
-
|
| |
- elif ("failed" in results["contacted"][hostname] and
|
| |
- results["contacted"][hostname]["failed"]):
|
| |
-
|
| |
- error = True
|
| |
- err_results["msg"] = "results included failed as true"
|
| |
-
|
| |
- if error:
|
| |
- for item in ["stdout", "stderr"]:
|
| |
- if item in results["contacted"][hostname]:
|
| |
- err_results[item] = results["contacted"][hostname][item]
|
| |
-
|
| |
- if error:
|
| |
- raise AnsibleResponseError(**err_results)
|
| |
Please take a look.
Regression tests are running atm so I'll add fixes later if any.