Exemplo n.º 1
0
class BranchesConfig(object):

    def __init__(self, tmp_dir):
        self.__tmp_dir = tmp_dir
        self.__working_dir = os.path.join(self.__tmp_dir, ".mincid")
        self.__logger = MLogger("BranchesConfig", "BC", self.__working_dir)

        with open(os.path.join(self.__working_dir, "project_config.json"), "r") as fd:
            self.__config = json.load(fd)
        with open(os.path.join(self.__working_dir, "mincid_master.json"), "r") as fd:
            self.__master_config = json.load(fd)

        self.__logger.info("Init branches config")

    def process(self):
        self.__logger.info("Start branches config")

        self.__logger.debug("Get branch config")
        stdouterr_filename = os.path.join(self.__working_dir,
                                          "docker_build_branches.stdouterr")
        with open(stdouterr_filename, "w") as fd_stdouterr:
            p = subprocess.Popen(["docker", "run", "--rm=true", "-i",
                                  "-v", "%s:/working:rw" % self.__working_dir,
                                  self.__master_config['worker_image'],
                                  "/bin/bash"], stdin=subprocess.PIPE,
                                 stdout=fd_stdouterr, stderr=fd_stdouterr)
        p.stdin.write(bytes(
"""%s
su - builder --command "%s"
su - builder --command 'git clone %s %s'
""" % ("\n".join(self.__master_config['imagedef'][self.__master_config['worker_image']]['setup_image_minimalistic']),
       self.__config['vcs']['authcmd'], self.__config['vcs']['url'],
       self.__config['dest']), "UTF-8"))

        for branch_name in self.__config['branches']:
            name_for_fs = branch_name.replace("/", "_")

            p.stdin.write(bytes(
"""su - builder --command 'cd %s && git checkout %s && mkdir -p /working/%s && cp %s /working/%s/mincid.json && chmod -R a+rwX /working/%s'
""" %(self.__config['dest'], branch_name, name_for_fs, self.__config['config'], name_for_fs,
      name_for_fs), 'UTF-8'))

        p.stdin.close()
        p.wait()
        self.__logger.debug("Docker process return value [%d]" % p.returncode)

        if p.returncode != 0:
            # Exit with the result of the docker (script) if not successfull
            sys.exit(p.returncode)

        # At this point for each branch there is a directory (in the tmp dir)
        # that contains the configuration for the appropriate branch.
        # Now start up the jobs (one for each branch) to handle these.
        for branch_name in self.__config['branches']:
            # Create Branch dir
            dirname = os.path.join(self.__working_dir,
                                   branch_name.replace("/", "_"))
            stdouterr_filename = os.path.join(dirname, "sbatch.stdouterr")
            with open(stdouterr_filename, "w") as fd_stdouterr:
                p = subprocess.Popen(
                    ["sbatch", "--job-name=Branch_%s" % branch_name,
                     "--output=%s" % os.path.join(self.__working_dir,
                                                  "slurm_build_branch_%j.out"),
                     "--export=PYTHONPATH",
                     os.path.join(self.__master_config['mincid_install_dir'],
                                  "build_branch.py"), branch_name,
                     self.__tmp_dir],
                    stdout=fd_stdouterr, stderr=fd_stdouterr)
                p.wait()
            self.__logger.info("sbatch process return value [%d]" %
                               p.returncode)
            self.__logger.info("Finished branch startup [%s]" % branch_name)
        self.__logger.info("Finished complete branch startup")
Exemplo n.º 2
0
class Variant(object):

    def __init__(self, cfgfile):
        with open(cfgfile, "r") as fd:
            self.__lconfig = json.load(fd)
        self.__name = self.__lconfig['name']
        self.__tmp_dir = self.__lconfig['global_tmp_dir']
        self.__artifacts_dir = os.path.join(self.__tmp_dir, "artifacts")
        os.makedirs(self.__artifacts_dir, exist_ok=True)
        self.__working_dir = os.path.join(self.__tmp_dir, ".mincid")
        with open(
                os.path.join(self.__working_dir,
                             'project_config.json'), "r") as fd:
            self.__global_config = json.load(fd)
        with open(os.path.join(self.__working_dir,
                               "mincid_master.json"), "r") as fd:
            self.__master_config = json.load(fd)

        self.__config = Config(self.__working_dir,
                               self.__lconfig['branch_name'])
            
        self.__name = self.__lconfig['name']
        self.__variant_dir = self.__lconfig['directory']
        self.__logger = MLogger("Variant", self.__name, self.__variant_dir)
        self.__logger.info("Init variant [%s]" % self.__lconfig['name'])

        self.__cmds = []
        self.__build_pre_cmds = [r'true']
        self.__cmds_post = [r'true']

    def __variant_cmds(self, variant_flat):
        # Check if re matches
        for vcfg in self.__master_config['imagedef'][self.__lconfig['base']]['variant_cmds']:
            vre = vcfg[0]
            vcmd = vcfg[1]
            self.__logger.debug("RE search [%s] [%s]" % (vre, variant_flat))
            result = re.search(vre, variant_flat)
            if not result:
                continue
            for icmd in vcmd:
                self.__logger.info("Calling Sub [%s] [%s] [%s]" %
                                   (vre, icmd, variant_flat))
                nsub = re.sub(vre, icmd, variant_flat)
                self.__logger.info("Add cmd [%s]" % nsub)
                self.__cmds.append(nsub)

            if len(vcfg)>2:
                vpreb = vcfg[2]
                for ipreb in vpreb:
                    self.__logger.info("Calling Sub [%s] [%s] [%s]"
                                       % (vre, ipreb, variant_flat))
                    nsub = re.sub(vre, ipreb, variant_flat)
                    self.__logger.info("Add pre cmd [%s]" % nsub)
                    self.__build_pre_cmds.append(nsub)

    def __variant_install_pkgs(self, install_dict):
        # Add other packages...
        pkgs=[]
        if not 'pkgs' in install_dict:
            return

        rpkgs = self.__config.expand(install_dict['pkgs'])

        install_pkg_names = self.__master_config['imagedef'][self.__lconfig['base']]['pkg_names']
        for ipkg in rpkgs:
            if not ipkg in install_pkg_names:
                self.__logger.warning(
                    "Package with symolic name [%s] " % ipkg
                    + "has no name mapping")
                pkgs.append(ipkg)
            else:
                pkgs.extend(install_pkg_names[ipkg])
        if len(pkgs)>0:
            self.__cmds.append(
                "%s %s" % (
                    self.__master_config['imagedef'][self.__lconfig['base']]['install_pkg_cmd'],
                    (" ".join(pkgs))))

    def __variant_cmds_post(self, install_dict):
        # Add packages from the control file
        # Please note that this can happen AFTER the checkout!
        if not 'control_files' in install_dict:
            self.__logger.info("No control files given")
            return
            
        for cf in install_dict['control_files']:
            self.__logger.info("Control file [%s]" % cf)
            self.__cmds_post.append(
                "cd ~builder && mk-build-deps "
                + "--tool='apt-get -y --no-install-recommends' "
                + "--install %s" % cf)

    def __image_prepare(self):
        if not 'prepare' in self.__lconfig:
            self.__logger.info("No prepare given")
            return
        self.__cmds.extend(self.__lconfig['prepare'])

    def __image_build_prepare(self):
        if not 'build_prepare' in self.__lconfig:
            self.__logger.info("No build prepare given")
            return
        self.__cmds_post.extend(self.__lconfig['build_prepare'])
            
    def __handle_variant(self):
        variant_flat = ":" + ":".join(self.__lconfig['variant_list']) + ":"
        self.__logger.info("Flat variant [%s]" % variant_flat)

        self.__variant_cmds(variant_flat)

    def __global_build_pre_cmds(self):
        if "build_preparation_cmds" in self.__master_config:
            self.__build_pre_cmds.extend(self.__master_config["build_preparation_cmds"])
        
    def process(self):
        self.__logger.info("Start variant [%s]" % self.__name)

        self.__image_prepare()
        self.__image_build_prepare()
        self.__global_build_pre_cmds()
        if 'variant_list' in self.__lconfig:
            self.__handle_variant()
        if 'install' in self.__lconfig:
            self.__variant_install_pkgs(self.__lconfig['install'])
            self.__variant_cmds_post(self.__lconfig['install'])
                
        stdouterr_filename = os.path.join(
            self.__tmp_dir, self.__name + ".log")
        rm_docker_image = "true"
        if "remove_docker_image" in self.__master_config['imagedef'][self.__lconfig['base']]:
            rm_docker_image =  self.__master_config['imagedef'][self.__lconfig['base']]['remove_docker_image']
        setup_minimalistic=""
        if 'setup_image_minimalistic' in self.__master_config['imagedef'][self.__lconfig['base']]:
            setup_minimalistic="\n".join(self.__master_config['imagedef'][self.__lconfig['base']]['setup_image_minimalistic'])

        # Log all commands that are executed
        complete_docker_cmd = ["docker", "run", "--rm=%s" % rm_docker_image, "-i",
                               "-v", "%s:/working:rw" % self.__working_dir,
                               "-v", "%s:/artifacts:rw" % self.__artifacts_dir,
                               "-v", "%s:/resources:ro" % self.__master_config["resource_dir"],
                               self.__lconfig['base'],
                               "/bin/bash", "-x", "-e"]
        complete_build_cmds = """%s
%s
%s
su - builder --command "%s"
su - builder --command 'git clone %s --branch %s --single-branch %s'
%s
su - builder --command '%s && %s'
""" % \
            (setup_minimalistic,
             "\n".join(self.__master_config['imagedef'][self.__lconfig['base']]['setup_image']),
             "\n".join(self.__cmds),
             self.__global_config['vcs']['authcmd'],

             self.__global_config['vcs']['url'],
             self.__lconfig['branch_name'],
             self.__global_config['dest'],

             " && ".join(self.__cmds_post),
             "\n".join(self.__build_pre_cmds),
             self.__lconfig['run'] if 'run' in self.__lconfig else "")
        with open(os.path.join(self.__tmp_dir, self.__name + ".sh"), "w") as shlog:
            shlog.write("# %s\n" % " ".join(complete_docker_cmd))
            shlog.write(complete_build_cmds)
            
        with open(stdouterr_filename, "w") as fd_stdouterr:
            p = subprocess.Popen(complete_docker_cmd,
                                 stdin=subprocess.PIPE,
                                 stdout=fd_stdouterr, stderr=fd_stdouterr)
        p.stdin.write(bytes(complete_build_cmds, 'UTF-8'))
        
        p.stdin.close()
        p.wait()
        self.__logger.info("Docker process return value [%d]" % p.returncode)
        self.__logger.info("Finished variant [%s]" % (self.__name))

        with open(os.path.join(self.__tmp_dir, "results.txt"), "a") as fd:
            fd.write("%s: %s\n" % (self.__name, "success" if p.returncode == 0 else "failure"))
        
        # Exit with the result of the docker (script)
        sys.exit(p.returncode)