Esempio n. 1
0
    def test_constructor_cache(self, tmpdir):
        tmpdir_path = str(tmpdir.realpath())
        df1 = DockerfileParser(tmpdir_path)
        df1.lines = ["From fedora:latest\n", "LABEL a b\n"]

        df2 = DockerfileParser(tmpdir_path, True)
        assert df2.cached_content
    def test_constructor_cache(self, tmpdir):
        tmpdir_path = str(tmpdir.realpath())
        df1 = DockerfileParser(tmpdir_path)
        df1.lines = ["From fedora:latest\n", "LABEL a b\n"]

        df2 = DockerfileParser(tmpdir_path, True)
        assert df2.cached_content
    def run(self):
        """
        run the plugin
        """
        # dict comprehension is syntax error on 2.6
        yum_repos = {}
        for key, value in self.workflow.files.items():
            if key.startswith(YUM_REPOS_DIR):
                yum_repos[key] = value
        if self.wrap_commands:
            wrap_yum_commands(yum_repos, self.workflow.builder.df_path)
        else:
            if not yum_repos:
                return
            # absolute path in containers -> relative path within context
            repos_host_cont_mapping = {}
            host_repos_path = os.path.join(self.workflow.builder.df_dir, RELATIVE_REPOS_PATH)
            self.log.info("creating directory for yum repos: %s", host_repos_path)
            os.mkdir(host_repos_path)

            for repo, repo_content in self.workflow.files.items():
                repo_basename = os.path.basename(repo)
                repo_relative_path = os.path.join(RELATIVE_REPOS_PATH, repo_basename)
                repo_host_path = os.path.join(host_repos_path, repo_basename)
                self.log.info("writing repo to '%s'", repo_host_path)
                with open(repo_host_path, "wb") as fp:
                    fp.write(repo_content.encode("utf-8"))
                repos_host_cont_mapping[repo] = repo_relative_path

            # Find out the USER inherited from the base image
            inspect = self.workflow.builder.inspect_base_image()
            inherited_user = inspect['Config'].get('User', '')
            df = DockerfileParser(self.workflow.builder.df_path)
            df.lines = add_yum_repos_to_dockerfile(repos_host_cont_mapping,
                                                   df, inherited_user)
    def run(self):
        """
        run the plugin
        """
        dockerfile = DockerfileParser(self.workflow.builder.df_path)
        lines = dockerfile.lines

        # correct syntax is:
        #   LABEL "key"="value" "key2"="value2"

        # Make sure to escape '\' and '"' characters.
        try:
            # py3
            env_trans = str.maketrans({'\\': '\\\\', '"': '\\"'})
        except AttributeError:
            # py2
            env_trans = None

        def escape(s):
            if env_trans:
                return s.translate(env_trans)
            return s.replace('\\', '\\\\').replace('"', '\\"')

        labels = []
        for key, value in self.labels.items():
            try:
                base_image_value = self.workflow.base_image_inspect["Config"][
                    "Labels"][key]
            except KeyError:
                self.log.info("label %s not present in base image", repr(key))
            except (AttributeError, TypeError):
                self.log.warning("base image was not inspected")
                break
            else:
                if base_image_value == value:
                    self.log.info("label %s is already set to %s", repr(key),
                                  repr(value))
                    continue
                else:
                    self.log.info("base image has label %s set to %s",
                                  repr(key), repr(base_image_value))
                    if key in self.dont_overwrite:
                        self.log.info("denying overwrite of label %s",
                                      repr(key))
                        continue

            label = '"%s"="%s"' % (escape(key), escape(value))
            self.log.info("setting label %s", label)
            labels.append(label)

        content = ""
        if labels:
            content = 'LABEL ' + " ".join(labels)
            # put it before last instruction
            lines.insert(-1, content + '\n')

            dockerfile.lines = lines

        return content
    def test_get_parent_env_from_scratch(self, tmpdir):
        tmpdir_path = str(tmpdir.realpath())
        p_env = {"bar": "baz"}
        df1 = DockerfileParser(tmpdir_path, env_replace=True, parent_env=p_env)
        df1.lines = [
            "FROM scratch\n",
        ]

        assert not df1.envs
    def test_get_parent_env_from_scratch(self, tmpdir):
        tmpdir_path = str(tmpdir.realpath())
        p_env = {"bar": "baz"}
        df1 = DockerfileParser(tmpdir_path, env_replace=True, parent_env=p_env)
        df1.lines = [
            "FROM scratch\n",
        ]

        assert not df1.envs
    def run(self):
        """
        run the plugin
        """
        dockerfile = DockerfileParser(self.workflow.builder.df_path)
        lines = dockerfile.lines

        # correct syntax is:
        #   LABEL "key"="value" "key2"="value2"

        # Make sure to escape '\' and '"' characters.
        try:
            # py3
            env_trans = str.maketrans({'\\': '\\\\',
                                       '"': '\\"'})
        except AttributeError:
            # py2
            env_trans = None

        def escape(s):
            if env_trans:
                return s.translate(env_trans)
            return s.replace('\\', '\\\\').replace('"', '\\"')

        labels = []
        for key, value in self.labels.items():
            try:
                base_image_value = self.workflow.base_image_inspect["Config"]["Labels"][key]
            except KeyError:
                self.log.info("label %s not present in base image", repr(key))
            except (AttributeError, TypeError):
                self.log.warning("base image was not inspected")
                break
            else:
                if base_image_value == value:
                    self.log.info("label %s is already set to %s", repr(key), repr(value))
                    continue
                else:
                    self.log.info("base image has label %s set to %s", repr(key), repr(base_image_value))
                    if key in self.dont_overwrite:
                        self.log.info("denying overwrite of label %s", repr(key))
                        continue

            label = '"%s"="%s"' % (escape(key), escape(value))
            self.log.info("setting label %s", label)
            labels.append(label)

        content = ""
        if labels:
            content = 'LABEL ' + " ".join(labels)
            # put it before last instruction
            lines.insert(-1, content + '\n')

            dockerfile.lines = lines

        return content
Esempio n. 8
0
def test_multiple_repourls(tmpdir):
    for df_content in DOCKERFILES.values():
        df = DockerfileParser(str(tmpdir))
        df.lines = df_content.lines_before_add + \
                   df_content.lines_before_remove
        tasker, workflow = prepare(df.dockerfile_path,
                                   df_content.inherited_user)
        filename1 = 'myrepo.repo'
        filename2 = 'repo-2.repo'
        repo_path1 = os.path.join(YUM_REPOS_DIR, filename1)
        repo_path2 = os.path.join(YUM_REPOS_DIR, filename2)
        workflow.files[repo_path1] = repocontent
        workflow.files[repo_path2] = repocontent
        runner = PreBuildPluginsRunner(tasker, workflow,
                                       [{
                                           'name': InjectYumRepoPlugin.key,
                                           'args': {
                                               'wrap_commands': False
                                           }
                                       }])
        runner.run()

        # Remove the repos/ directory.
        repos_dir = os.path.join(str(tmpdir), RELATIVE_REPOS_PATH)
        for repofile in [filename1, filename2]:
            os.remove(os.path.join(repos_dir, repofile))

        os.rmdir(repos_dir)

        # Examine the Dockerfile.
        newdf = df.lines
        before_add = len(df_content.lines_before_add)
        before_remove = len(df_content.lines_before_remove)

        # Start of file should be unchanged.
        assert newdf[:before_add] == df_content.lines_before_add

        # Should see a single add line.
        after_add = before_add + 1
        assert (newdf[before_add:after_add] == [
            "ADD %s* '/etc/yum.repos.d/'\n" % RELATIVE_REPOS_PATH
        ])

        # Lines from there up to the remove line should be unchanged.
        before_remove = after_add + len(df_content.lines_before_remove)
        assert (
            newdf[after_add:before_remove] == df_content.lines_before_remove)

        # For the 'rm' line, they could be in either order
        remove = newdf[before_remove:]
        assert remove_lines_match(remove, df_content.remove_lines,
                                  [filename1, filename2])
Esempio n. 9
0
def test_single_repourl(tmpdir):
    for df_content in DOCKERFILES.values():
        df = DockerfileParser(str(tmpdir))
        df.lines = df_content.lines_before_add + \
                   df_content.lines_before_remove
        tasker, workflow = prepare(df.dockerfile_path,
                                   df_content.inherited_user)
        filename = 'test.repo'
        repo_path = os.path.join(YUM_REPOS_DIR, filename)
        workflow.files[repo_path] = repocontent
        runner = PreBuildPluginsRunner(tasker, workflow,
                                       [{
                                           'name': InjectYumRepoPlugin.key,
                                           'args': {
                                               'wrap_commands': False
                                           }
                                       }])
        runner.run()

        # Was it written correctly?
        repos_dir = os.path.join(str(tmpdir), RELATIVE_REPOS_PATH)
        repofile = os.path.join(repos_dir, filename)
        with open(repofile, "r") as fp:
            assert fp.read() == repocontent

        # Remove the repos/ directory.
        os.remove(repofile)
        os.rmdir(repos_dir)

        # Examine the Dockerfile.
        newdf = df.lines
        before_add = len(df_content.lines_before_add)
        before_remove = len(df_content.lines_before_remove)

        # Start of file should be unchanged.
        assert newdf[:before_add] == df_content.lines_before_add

        # Should see a single add line.
        after_add = before_add + 1
        assert (newdf[before_add:after_add] == [
            "ADD %s* '/etc/yum.repos.d/'\n" % RELATIVE_REPOS_PATH
        ])

        # Lines from there up to the remove line should be unchanged.
        before_remove = after_add + len(df_content.lines_before_remove)
        assert (
            newdf[after_add:before_remove] == df_content.lines_before_remove)

        # The 'rm' lines should match
        # There should be a final 'rm'
        remove = newdf[before_remove:]
        assert remove_lines_match(remove, df_content.remove_lines, [filename])
Esempio n. 10
0
    def test_get_parent_env(self, tmpdir):
        tmpdir_path = str(tmpdir.realpath())
        p_env = {"bar": "baz"}
        df1 = DockerfileParser(tmpdir_path, env_replace=True, parent_env=p_env)
        df1.lines = [
            "FROM parent\n", "ENV foo=\"$bar\"\n",
            "LABEL label=\"$foo $bar\"\n"
        ]

        # Even though we inherit an ENV, this .envs count should only be for the
        # ENVs defined in *this* Dockerfile as we're parsing the Dockerfile and
        # the parent_env is only to satisfy use of inhereted ENVs.
        assert len(df1.envs) == 1
        assert df1.envs.get('foo') == 'baz'
        assert len(df1.labels) == 1
        assert df1.labels.get('label') == 'baz baz'
Esempio n. 11
0
def test_single_repourl(tmpdir):
    for df_content in DOCKERFILES.values():
        df = DockerfileParser(str(tmpdir))
        df.lines = df_content.lines_before_add + \
                   df_content.lines_before_remove
        tasker, workflow = prepare(df.dockerfile_path,
                                   df_content.inherited_user)
        filename = 'test.repo'
        repo_path = os.path.join(YUM_REPOS_DIR, filename)
        workflow.files[repo_path] = repocontent
        runner = PreBuildPluginsRunner(tasker, workflow, [{
                'name': InjectYumRepoPlugin.key,
                'args': {'wrap_commands': False}}])
        runner.run()

        # Was it written correctly?
        repos_dir = os.path.join(str(tmpdir), RELATIVE_REPOS_PATH)
        repofile = os.path.join(repos_dir, filename)
        with open(repofile, "r") as fp:
            assert fp.read() == repocontent

        # Remove the repos/ directory.
        os.remove(repofile)
        os.rmdir(repos_dir)

        # Examine the Dockerfile.
        newdf = df.lines
        before_add = len(df_content.lines_before_add)
        before_remove = len(df_content.lines_before_remove)

        # Start of file should be unchanged.
        assert newdf[:before_add] == df_content.lines_before_add

        # Should see a single add line.
        after_add = before_add + 1
        assert (newdf[before_add:after_add] ==
                    ["ADD %s* '/etc/yum.repos.d/'\n" % RELATIVE_REPOS_PATH])

        # Lines from there up to the remove line should be unchanged.
        before_remove = after_add + len(df_content.lines_before_remove)
        assert (newdf[after_add:before_remove] ==
                df_content.lines_before_remove)

        # The 'rm' lines should match
        # There should be a final 'rm'
        remove = newdf[before_remove:]
        assert remove_lines_match(remove, df_content.remove_lines, [filename])
Esempio n. 12
0
def test_multiple_repourls(tmpdir):
    for df_content in DOCKERFILES.values():
        df = DockerfileParser(str(tmpdir))
        df.lines = df_content.lines_before_add + \
                   df_content.lines_before_remove
        tasker, workflow = prepare(df.dockerfile_path,
                                   df_content.inherited_user)
        filename1 = 'myrepo.repo'
        filename2 = 'repo-2.repo'
        repo_path1 = os.path.join(YUM_REPOS_DIR, filename1)
        repo_path2 = os.path.join(YUM_REPOS_DIR, filename2)
        workflow.files[repo_path1] = repocontent
        workflow.files[repo_path2] = repocontent
        runner = PreBuildPluginsRunner(tasker, workflow, [{
                'name': InjectYumRepoPlugin.key,
                'args': {'wrap_commands': False}}])
        runner.run()

        # Remove the repos/ directory.
        repos_dir = os.path.join(str(tmpdir), RELATIVE_REPOS_PATH)
        for repofile in [filename1, filename2]:
            os.remove(os.path.join(repos_dir, repofile))

        os.rmdir(repos_dir)

        # Examine the Dockerfile.
        newdf = df.lines
        before_add = len(df_content.lines_before_add)
        before_remove = len(df_content.lines_before_remove)

        # Start of file should be unchanged.
        assert newdf[:before_add] == df_content.lines_before_add

        # Should see a single add line.
        after_add = before_add + 1
        assert (newdf[before_add:after_add] ==
                    ["ADD %s* '/etc/yum.repos.d/'\n" % RELATIVE_REPOS_PATH])

        # Lines from there up to the remove line should be unchanged.
        before_remove = after_add + len(df_content.lines_before_remove)
        assert (newdf[after_add:before_remove] ==
                    df_content.lines_before_remove)

        # For the 'rm' line, they could be in either order
        remove = newdf[before_remove:]
        assert remove_lines_match(remove, df_content.remove_lines,
                                  [filename1, filename2])
Esempio n. 13
0
def test_no_repourls(tmpdir):
    for df_content in DOCKERFILES.values():
        df = DockerfileParser(str(tmpdir))
        df.lines = df_content.lines_before_add + \
                   df_content.lines_before_remove

        tasker, workflow = prepare(df.dockerfile_path,
                                   df_content.inherited_user)
        runner = PreBuildPluginsRunner(tasker, workflow, [{
            'name': InjectYumRepoPlugin.key,
        }])
        runner.run()
        assert InjectYumRepoPlugin.key is not None

        # Should be unchanged.
        assert df.lines == df_content.lines_before_add + \
                           df_content.lines_before_remove
    def test_get_parent_env(self, tmpdir):
        tmpdir_path = str(tmpdir.realpath())
        p_env = {"bar": "baz"}
        df1 = DockerfileParser(tmpdir_path, env_replace=True, parent_env=p_env)
        df1.lines = [
            "FROM parent\n",
            "ENV foo=\"$bar\"\n",
            "LABEL label=\"$foo $bar\"\n"
        ]

        # Even though we inherit an ENV, this .envs count should only be for the
        # ENVs defined in *this* Dockerfile as we're parsing the Dockerfile and
        # the parent_env is only to satisfy use of inherited ENVs.
        assert len(df1.envs) == 1
        assert df1.envs.get('foo') == 'baz'
        assert len(df1.labels) == 1
        assert df1.labels.get('label') == 'baz baz'
Esempio n. 15
0
def test_no_repourls(tmpdir):
    for df_content in DOCKERFILES.values():
        df = DockerfileParser(str(tmpdir))
        df.lines = df_content.lines_before_add + \
                   df_content.lines_before_remove

        tasker, workflow = prepare(df.dockerfile_path,
                                   df_content.inherited_user)
        runner = PreBuildPluginsRunner(tasker, workflow,
                                       [{
                                           'name': InjectYumRepoPlugin.key,
                                       }])
        runner.run()
        assert InjectYumRepoPlugin.key is not None

        # Should be unchanged.
        assert df.lines == df_content.lines_before_add + \
                           df_content.lines_before_remove
Esempio n. 16
0
def create_context_archive(context, docker_file, base_image):

    original_dockerfile = open(context + '/' + docker_file, 'r')
    dfp = DockerfileParser()
    dfp.lines = original_dockerfile.readlines()
    original_dockerfile.close()

    dfp.baseimage = base_image

    new_file = tempfile.NamedTemporaryFile()
    new_file.write(dfp.content.encode('utf-8'))
    new_file.flush()

    context_archive = docker.utils.tar(context, dockerfile=docker_file)

    t = tarfile.open(name=context_archive.name, mode='a')
    t.add(new_file.name, arcname=docker_file)
    t.close()

    return context_archive
    def run(self):
        """
        run the plugin
        """
        dockerfile = DockerfileParser(self.workflow.builder.df_path)
        lines = dockerfile.lines

        # when using final dockerfile, we should use DOCKERFILE_FILENAME
        # otherwise we should use the copied version
        if self.use_final_dockerfile:
            content = 'ADD {0} {1}'.format(DOCKERFILE_FILENAME, self.df_path)
        else:
            content = 'ADD {0} {1}'.format(self.df_name, self.df_path)

        # put it before last instruction
        lines.insert(-1, content + '\n')

        dockerfile.lines = lines

        self.log.info("added %s", self.df_path)

        return content
Esempio n. 18
0
    def run(self):
        """
        run the plugin
        """
        try:
            config = self.workflow.base_image_inspect[INSPECT_CONFIG]
        except (AttributeError, TypeError):
            message = "base image was not inspected"
            self.log.error(message)
            raise RuntimeError(message)
        else:
            base_image_labels = config["Labels"] or {}

        dockerfile = DockerfileParser(self.workflow.builder.df_path)
        lines = dockerfile.lines

        # changing dockerfile.labels writes out modified Dockerfile - err on
        # the safe side and make a copy
        self.add_aliases(base_image_labels.copy(), dockerfile.labels.copy(),
                         self.labels.copy())

        # correct syntax is:
        #   LABEL "key"="value" "key2"="value2"

        # Make sure to escape '\' and '"' characters.
        try:
            # py3
            env_trans = str.maketrans({'\\': '\\\\', '"': '\\"'})
        except AttributeError:
            # py2
            env_trans = None

        def escape(s):
            if env_trans:
                return s.translate(env_trans)
            return s.replace('\\', '\\\\').replace('"', '\\"')

        labels = []
        for key, value in self.labels.items():
            try:
                base_image_value = base_image_labels[key]
            except KeyError:
                self.log.info("label %r not present in base image", key)
            else:
                if base_image_value == value:
                    self.log.info("label %r is already set to %r", key, value)
                    continue
                else:
                    self.log.info("base image has label %r set to %r", key,
                                  base_image_value)
                    if key in self.dont_overwrite:
                        self.log.info("denying overwrite of label %r", key)
                        continue

            label = '"%s"="%s"' % (escape(key), escape(value))
            self.log.info("setting label %r", label)
            labels.append(label)

        content = ""
        if labels:
            content = 'LABEL ' + " ".join(labels)
            # put labels at the end of dockerfile (since they change metadata and do not interact
            # with FS, this should cause no harm)
            lines.append('\n' + content + '\n')
            dockerfile.lines = lines

        return content
    def run(self):
        """
        run the plugin
        """
        try:
            config = self.workflow.base_image_inspect[INSPECT_CONFIG]
        except (AttributeError, TypeError):
            message = "base image was not inspected"
            self.log.error(message)
            raise RuntimeError(message)
        else:
            base_image_labels = config["Labels"] or {}

        dockerfile = DockerfileParser(self.workflow.builder.df_path)
        lines = dockerfile.lines

        # changing dockerfile.labels writes out modified Dockerfile - err on
        # the safe side and make a copy
        self.add_aliases(base_image_labels.copy(), dockerfile.labels.copy(), self.labels.copy())

        # correct syntax is:
        #   LABEL "key"="value" "key2"="value2"

        # Make sure to escape '\' and '"' characters.
        try:
            # py3
            env_trans = str.maketrans({'\\': '\\\\',
                                       '"': '\\"'})
        except AttributeError:
            # py2
            env_trans = None

        def escape(s):
            if env_trans:
                return s.translate(env_trans)
            return s.replace('\\', '\\\\').replace('"', '\\"')

        labels = []
        for key, value in self.labels.items():
            try:
                base_image_value = base_image_labels[key]
            except KeyError:
                self.log.info("label %r not present in base image", key)
            else:
                if base_image_value == value:
                    self.log.info("label %r is already set to %r", key, value)
                    continue
                else:
                    self.log.info("base image has label %r set to %r", key, base_image_value)
                    if key in self.dont_overwrite:
                        self.log.info("denying overwrite of label %r", key)
                        continue

            label = '"%s"="%s"' % (escape(key), escape(value))
            self.log.info("setting label %r", label)
            labels.append(label)

        content = ""
        if labels:
            content = 'LABEL ' + " ".join(labels)
            # put labels at the end of dockerfile (since they change metadata and do not interact
            # with FS, this should cause no harm)
            lines.append('\n' + content + '\n')
            dockerfile.lines = lines

        return content