def test_multistage_dockerfiles(name, inherited_user, dockerfile, expect_cleanup_lines, base_from_scratch, tmpdir): # expect repo ADD instructions where indicated in the content, and RUN rm at the end. # begin by splitting on "### ADD HERE" so we know where to expect changes. segments = re.split(r'^.*ADD HERE.*$\n?', dockerfile, flags=re.M) segment_lines = [seg.splitlines(True) for seg in segments] # build expected contents by manually inserting expected ADD lines between the segments for lines in segment_lines[:-1]: lines.append("ADD %s* '/etc/yum.repos.d/'\n" % RELATIVE_REPOS_PATH) expected_lines = list(itertools.chain.from_iterable(segment_lines)) # flatten lines # now run the plugin to transform the given dockerfile df = df_parser(str(tmpdir)) df.content = ''.join(segments) # dockerfile without the "### ADD HERE" lines tasker, workflow = prepare(df.dockerfile_path, inherited_user) workflow.builder.set_base_from_scratch(base_from_scratch) repo_file = 'myrepo.repo' repo_path = os.path.join(YUM_REPOS_DIR, repo_file) workflow.files[repo_path] = repocontent runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': InjectYumRepoPlugin.key, 'args': {}}]) runner.run() # assert the Dockerfile has changed as expected up to the cleanup lines new_df = df.lines assert new_df[:len(expected_lines)] == expected_lines # the rest of the lines should be cleanup lines cleanup_lines = new_df[len(expected_lines):] assert remove_lines_match(cleanup_lines, expect_cleanup_lines, [repo_file])
def test_add_labels_equal_aliases(tmpdir, docker_tasker, caplog, base_l, df_l, expected, expected_log, reactor_config_map): if MOCK: mock_docker() df_content = "FROM fedora\n" plugin_labels = {} if df_l[0]: df_content += 'LABEL description="{0}"\n'.format(df_l[0]) if df_l[1]: df_content += 'LABEL io.k8s.description="{0}"\n'.format(df_l[1]) base_labels = {INSPECT_CONFIG: {"Labels": {}}} if base_l[0]: base_labels[INSPECT_CONFIG]["Labels"]["description"] = base_l[0] if base_l[1]: base_labels[INSPECT_CONFIG]["Labels"]["io.k8s.description"] = base_l[1] df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X()) setattr(workflow.builder, 'df_path', df.dockerfile_path) setattr(workflow.builder, 'base_image_inspect', base_labels) if reactor_config_map: make_and_store_reactor_config_map( workflow, { 'image_labels': plugin_labels, 'image_equal_labels': [['description', 'io.k8s.description']]}) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': { 'labels': plugin_labels, 'dont_overwrite': [], 'auto_labels': [], 'aliases': {}, 'equal_labels': [['description', 'io.k8s.description']] } }] ) runner.run() assert AddLabelsPlugin.key is not None result_fst = df.labels.get("description") or \ base_labels[INSPECT_CONFIG]["Labels"].get("description") result_snd = df.labels.get("io.k8s.description") or \ base_labels[INSPECT_CONFIG]["Labels"].get("io.k8s.description") assert result_fst == expected[0] assert result_snd == expected[1] if expected_log: assert expected_log in caplog.text
def test_flatpak_create_dockerfile(tmpdir, docker_tasker): workflow = mock_workflow(tmpdir) args = { 'base_image': "registry.fedoraproject.org/fedora:latest", } mmd = ModuleMetadata() mmd.loads(FLATPAK_APP_MODULEMD) base_module = ModuleInfo(MODULE_NAME, MODULE_STREAM, LATEST_VERSION, mmd, FLATPAK_APP_RPMS) repo_url = 'http://odcs.example/composes/latest-odcs-42-1/compose/Temporary/$basearch/os/' compose_info = ComposeInfo(MODULE_STREAM + '-' + MODULE_STREAM, 42, base_module, {'eog': base_module}, repo_url) set_compose_info(workflow, compose_info) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FlatpakCreateDockerfilePlugin.key, 'args': args }] ) runner.run() assert os.path.exists(workflow.builder.df_path) assert os.path.exists(os.path.join(workflow.builder.df_dir, 'cleanup.sh'))
def test_retry_pull_base_image(exc, failures, should_succeed): if MOCK: mock_docker(remember_images=True) tasker = DockerTasker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = MockBuilder() workflow.builder.base_image = ImageName.parse('parent-image') class MockResponse(object): content = '' expectation = flexmock(tasker).should_receive('tag_image') for _ in range(failures): expectation = expectation.and_raise(exc('', MockResponse())) expectation.and_return('foo') expectation.and_return('parent-image') runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': PullBaseImagePlugin.key, 'args': {'parent_registry': 'registry.example.com', 'parent_registry_insecure': True}, }], ) if should_succeed: runner.run() else: with pytest.raises(Exception): runner.run()
def test_add_labels_plugin_generated(tmpdir, docker_tasker, auto_label, value_re_part): df = df_parser(str(tmpdir)) df.content = DF_CONTENT if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) flexmock(workflow, source=MockSource()) flexmock(workflow, base_image_inspect=LABELS_CONF_BASE) setattr(workflow.builder, 'df_path', df.dockerfile_path) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': {'labels': {}, "dont_overwrite": [], "auto_labels": [auto_label], 'aliases': {'Build_Host': 'com.redhat.build-host'}} }] ) runner.run() if value_re_part: assert re.match(value_re_part, df.labels[auto_label]) if auto_label == "build-date": utc_dt = datetime.datetime.utcfromtimestamp(atomic_reactor_start_time).isoformat() assert df.labels[auto_label] == utc_dt
def test_assertlabels_plugin(tmpdir, df_content, req_labels, expected): df = DockerfileParser(str(tmpdir)) df.content = df_content tasker = DockerTasker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': AssertLabelsPlugin.key, 'args': {'required_labels': req_labels} }] ) assert AssertLabelsPlugin.key is not None if isinstance(expected, PluginFailedException): with pytest.raises(PluginFailedException): runner.run() else: runner.run()
def test_adddockerfile_nvr_from_labels(tmpdir, docker_tasker): df_content = """ FROM fedora RUN yum install -y python-django LABEL Name="jboss-eap-6-docker" "Version"="6.4" "Release"=77 CMD blabla""" df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddDockerfilePlugin.key }] ) runner.run() assert AddDockerfilePlugin.key is not None assert "ADD Dockerfile-jboss-eap-6-docker-6.4-77 /root/buildinfo/Dockerfile-jboss-eap-6-docker-6.4-77" in df.content
def test_returndockerfile_plugin(tmpdir): df_content = """ FROM fedora RUN yum install -y python-django CMD blabla""" df = DockerfileParser(str(tmpdir)) df.content = df_content tasker = DockerTasker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': CpDockerfilePlugin.key }] ) runner.run() assert CpDockerfilePlugin.key is not None assert workflow.prebuild_results.get(CpDockerfilePlugin.key, "") == df_content
def test_adddockerfile_plugin(tmpdir, docker_tasker): df_content = """ FROM fedora RUN yum install -y python-django CMD blabla""" df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddDockerfilePlugin.key, 'args': {'nvr': 'rhel-server-docker-7.1-20'} }] ) runner.run() assert AddDockerfilePlugin.key is not None expected_output = """ FROM fedora RUN yum install -y python-django ADD Dockerfile-rhel-server-docker-7.1-20 /root/buildinfo/Dockerfile-rhel-server-docker-7.1-20 CMD blabla""" assert df.content == expected_output
def test_adddockerfile_nvr_from_labels2(tmpdir, docker_tasker): df_content = """ FROM fedora RUN yum install -y python-django CMD blabla""" df = df_parser(str(tmpdir)) df.content = df_content if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') flexmock(workflow, base_image_inspect={INSPECT_CONFIG: {"Labels": {}}}) workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': {'labels': {'Name': 'jboss-eap-6-docker', 'Version': '6.4', 'Release': '77'}, 'auto_labels': []} }, { 'name': AddDockerfilePlugin.key }] ) runner.run() assert AddDockerfilePlugin.key is not None assert "ADD Dockerfile-jboss-eap-6-docker-6.4-77 /root/buildinfo/Dockerfile-jboss-eap-6-docker-6.4-77" in df.content
def test_adddockerfile_todest(tmpdir, docker_tasker): df_content = """ FROM fedora RUN yum install -y python-django CMD blabla""" df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddDockerfilePlugin.key, 'args': {'nvr': 'jboss-eap-6-docker-6.4-77', 'destdir': '/usr/share/doc/'} }] ) runner.run() assert AddDockerfilePlugin.key is not None expected_output = """ FROM fedora RUN yum install -y python-django ADD Dockerfile-jboss-eap-6-docker-6.4-77 /usr/share/doc/Dockerfile-jboss-eap-6-docker-6.4-77 CMD blabla""" assert df.content == expected_output
def test_fetch_maven_artifacts_url_allowed_domains(tmpdir, docker_tasker, domains, raises, reactor_config_map): """Validate URL domain is allowed when fetching remote file.""" workflow = mock_workflow(tmpdir) mock_koji_session() mock_fetch_artifacts_by_url(str(tmpdir)) mock_url_downloads() if reactor_config_map: make_and_store_reactor_config_map(workflow, {'artifacts_allowed_domains': domains}) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FetchMavenArtifactsPlugin.key, 'args': { 'koji_hub': KOJI_HUB, 'koji_root': KOJI_ROOT, 'allowed_domains': domains, } }] ) if raises: with pytest.raises(PluginFailedException) as e: runner.run() assert 'is not in list of allowed domains' in str(e) else: results = runner.run() plugin_result = results[FetchMavenArtifactsPlugin.key] for download in plugin_result: dest = os.path.join(str(tmpdir), FetchMavenArtifactsPlugin.DOWNLOAD_DIR, download.dest) assert os.path.exists(dest)
def test_add_labels_plugin_explicit(tmpdir, docker_tasker, auto_label, labels_docker, labels_base): df = df_parser(str(tmpdir)) df.content = labels_docker if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) flexmock(workflow, source=MockSource()) flexmock(workflow, base_image_inspect=labels_base) setattr(workflow.builder, 'df_path', df.dockerfile_path) prov_labels = {} prov_labels[auto_label] = 'explicit_value' runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': {'labels': prov_labels, "dont_overwrite": [], "auto_labels": [auto_label], 'aliases': {'Build_Host': 'com.redhat.build-host'}} }] ) runner.run() assert df.labels[auto_label] == 'explicit_value'
def test_distgit_fetch_artefacts_failure(tmpdir, docker_tasker): # noqa command = 'fedpkg sources' expected_command = ['fedpkg', 'sources'] workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X() workflow.source = flexmock(path=str(tmpdir)) initial_dir = os.getcwd() assert initial_dir != str(tmpdir) (flexmock(pre_pyrpkg_fetch_artefacts.subprocess) .should_receive('check_call') .with_args(expected_command) .and_raise(RuntimeError) .once()) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': DistgitFetchArtefactsPlugin.key, 'args': {'command': command} }] ) with pytest.raises(PluginFailedException): runner.run() assert os.getcwd() == initial_dir
def test_add_labels_plugin(tmpdir, labels_conf_base, labels_conf, dont_overwrite, expected_output): df = DockerfileParser(str(tmpdir)) df.content = DF_CONTENT tasker = DockerTasker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) flexmock(workflow, base_image_inspect=labels_conf_base) setattr(workflow.builder, 'df_path', df.dockerfile_path) runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': {'labels': labels_conf, "dont_overwrite": dont_overwrite} }] ) if isinstance(expected_output, RuntimeError): with pytest.raises(RuntimeError): runner.run() else: runner.run() assert AddLabelsPlugin.key is not None assert df.content in expected_output
def test_distgit_fetch_artefacts_plugin(tmpdir, docker_tasker): # noqa command = 'fedpkg sources' expected_command = ['fedpkg', 'sources'] workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X() workflow.source = flexmock(path=str(tmpdir)) initial_dir = os.getcwd() assert initial_dir != str(tmpdir) def assert_tmpdir(*args, **kwargs): assert os.getcwd() == str(tmpdir) (flexmock(pre_pyrpkg_fetch_artefacts.subprocess) .should_receive('check_call') .with_args(expected_command) .replace_with(assert_tmpdir) .once()) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': DistgitFetchArtefactsPlugin.key, 'args': {'command': command} }] ) runner.run() assert os.getcwd() == initial_dir
def test_pull_base_image_plugin(df_base, parent_registry, expected_w_reg, expected_wo_reg): if MOCK: mock_docker(remember_images=True) tasker = DockerTasker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = MockBuilder() workflow.builder.base_image = ImageName.parse(df_base) assert not tasker.image_exists(BASE_IMAGE) assert not tasker.image_exists(BASE_IMAGE_W_REGISTRY) runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': PullBaseImagePlugin.key, 'args': {'parent_registry': parent_registry, 'parent_registry_insecure': True} }] ) runner.run() assert tasker.image_exists(BASE_IMAGE) == expected_wo_reg assert tasker.image_exists(BASE_IMAGE_W_REGISTRY) == expected_w_reg try: tasker.remove_image(BASE_IMAGE) tasker.remove_image(BASE_IMAGE_W_REGISTRY) except: pass
def test_yuminject_plugin_notwrapped(tmpdir): df_content = """\ FROM fedora RUN yum install -y python-django CMD blabla""" df = DockerfileParser(str(tmpdir)) df.content = df_content tasker, workflow = prepare(df.dockerfile_path) metalink = 'https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch' workflow.files[os.path.join(YUM_REPOS_DIR, DEFAULT_YUM_REPOFILE_NAME)] = render_yum_repo(OrderedDict( (('name', 'my-repo'), ('metalink', metalink), ('enabled', 1), ('gpgcheck', 0)), )) runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': InjectYumRepoPlugin.key, 'args': { "wrap_commands": False } }]) runner.run() assert InjectYumRepoPlugin.key is not None expected_output = r"""FROM fedora ADD atomic-reactor-repos/* '/etc/yum.repos.d/' RUN yum install -y python-django CMD blabla RUN rm -f '/etc/yum.repos.d/atomic-reactor-injected.repo' """ assert expected_output == df.content
def test_check_and_set_platforms_no_koji(tmpdir, caplog, platforms, platform_only, result): write_container_yaml(tmpdir, platform_only=platform_only) tasker, workflow = prepare(tmpdir) if platforms: set_orchestrator_platforms(workflow, platforms.split()) build_json = {'metadata': {'labels': {}}} flexmock(util).should_receive('get_build_json').and_return(build_json) mock_config = MockConfig(platforms) flexmock(reactor_config).should_receive('get_config').and_return(mock_config) runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': PLUGIN_CHECK_AND_SET_PLATFORMS_KEY, }]) if platforms: plugin_result = runner.run() # Build up the message to avoid wrapping no_koji_msg = "No koji platforms. " platform_msg = "User specified platforms are {0}".format(sorted(platforms.split())) user_msg = no_koji_msg + platform_msg assert user_msg in caplog.text assert plugin_result[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] assert plugin_result[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] == set(result) else: with pytest.raises(Exception) as e: plugin_result = runner.run() assert "no koji target or platform list" in str(e)
def run_plugin_with_args(self, workflow, plugin_args=None, expect_result=None, expect_error=None): plugin_args = plugin_args or {} plugin_args.setdefault('odcs_url', ODCS_URL) plugin_args.setdefault('koji_target', KOJI_TARGET_NAME) plugin_args.setdefault('koji_hub', KOJI_HUB) runner = PreBuildPluginsRunner( workflow.builder.tasker, workflow, [ {'name': ReactorConfigPlugin.key, 'args': {'config_path': str(workflow._tmpdir)}}, {'name': ResolveComposesPlugin.key, 'args': plugin_args}, ] ) if expect_error: with pytest.raises(PluginFailedException) as exc_info: runner.run() assert expect_error in str(exc_info.value) return results = runner.run()[ResolveComposesPlugin.key] if results: assert len(self.get_override_yum_repourls(workflow)) > 0 assert set(results.keys()) == set(['signing_intent', 'signing_intent_overridden', 'composes']) else: assert self.get_override_yum_repourls(workflow) is None assert results is None return results
def test_add_labels_plugin(tmpdir, docker_tasker, df_content, labels_conf_base, labels_conf, dont_overwrite, aliases, expected_output, caplog): df = DockerfileParser(str(tmpdir)) df.content = df_content if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) flexmock(workflow, base_image_inspect=labels_conf_base) setattr(workflow.builder, 'df_path', df.dockerfile_path) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': { 'labels': labels_conf, 'dont_overwrite': dont_overwrite, 'auto_labels': [], 'aliases': aliases, } }] ) runner.run() if isinstance(expected_output, RuntimeError): assert "plugin 'add_labels_in_dockerfile' raised an exception: RuntimeError" in caplog.text() else: assert AddLabelsPlugin.key is not None assert df.content in expected_output
def test_fetch_maven_artifacts_nvr_no_match(tmpdir, docker_tasker, nvr_requests, error_msg, reactor_config_map): """Err when a requested archive is not found in Koji build.""" workflow = mock_workflow(tmpdir) mock_koji_session() mock_fetch_artifacts_by_nvr(str(tmpdir), contents=yaml.safe_dump(nvr_requests)) mock_nvr_downloads() if reactor_config_map: make_and_store_reactor_config_map(workflow) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FetchMavenArtifactsPlugin.key, 'args': {'koji_hub': KOJI_HUB, 'koji_root': KOJI_ROOT} }] ) with pytest.raises(PluginFailedException) as e: runner.run() assert 'failed to find archives' in str(e) assert error_msg in str(e)
def test_fetch_maven_artifacts_nvr_bad_nvr(tmpdir, docker_tasker, reactor_config_map): """Err when given nvr is not a valid build in Koji.""" workflow = mock_workflow(tmpdir) mock_koji_session() contents = dedent("""\ - nvr: where-is-this-build-3.0-2 """) mock_fetch_artifacts_by_nvr(str(tmpdir), contents=contents) mock_nvr_downloads() if reactor_config_map: make_and_store_reactor_config_map(workflow) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FetchMavenArtifactsPlugin.key, 'args': {'koji_hub': KOJI_HUB, 'koji_root': KOJI_ROOT} }] ) with pytest.raises(PluginFailedException) as e: runner.run() assert 'Build where-is-this-build-3.0-2 not found' in str(e)
def build_docker_image(self): """ build docker image :return: BuildResults """ self.builder = InsideBuilder(self.source, self.image) try: # time to run pre-build plugins, so they can access cloned repo logger.info("running pre-build plugins") prebuild_runner = PreBuildPluginsRunner(self.builder.tasker, self, self.prebuild_plugins_conf, plugin_files=self.plugin_files) try: prebuild_runner.run() except PluginFailedException as ex: logger.error("one or more prebuild plugins failed: %s", ex) raise build_result = self.builder.build() self.build_logs = build_result.logs self.build_failed = build_result.is_failed() if not build_result.is_failed(): self.built_image_inspect = self.builder.inspect_built_image() # run prepublish plugins prepublish_runner = PrePublishPluginsRunner(self.builder.tasker, self, self.prepublish_plugins_conf, plugin_files=self.plugin_files) try: prepublish_runner.run() except PluginFailedException as ex: logger.error("one or more prepublish plugins failed: %s", ex) raise if not build_result.is_failed(): for registry in self.push_conf.docker_registries: self.builder.push_built_image(registry.uri, insecure=registry.insecure) postbuild_runner = PostBuildPluginsRunner(self.builder.tasker, self, self.postbuild_plugins_conf, plugin_files=self.plugin_files) try: postbuild_runner.run() except PluginFailedException as ex: logger.error("one or more postbuild plugins failed: %s", ex) raise return build_result finally: self.source.remove_tmpdir() exit_runner = ExitPluginsRunner(self.builder.tasker, self, self.exit_plugins_conf, plugin_files=self.plugin_files) try: exit_runner.run() except PluginFailedException as ex: logger.error("one or more exit plugins failed: %s", ex)
def test_no_repourls(inject_proxy): tasker, workflow = prepare() runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': AddYumRepoByUrlPlugin.key, 'args': {'repourls': [], 'inject_proxy': inject_proxy}}]) runner.run() assert AddYumRepoByUrlPlugin.key is not None assert workflow.files == {}
def test_add_labels_aliases(tmpdir, docker_tasker, caplog, df_old_as_plugin_arg, df_new_as_plugin_arg, base_old, base_new, df_old, df_new, exp_old, exp_new, exp_log): if MOCK: mock_docker() df_content = "FROM fedora\n" plugin_labels = {} if df_old: if df_old_as_plugin_arg: plugin_labels["label_old"] = df_old else: df_content += 'LABEL label_old="{0}"\n'.format(df_old) if df_new: if df_new_as_plugin_arg: plugin_labels["label_new"] = df_new else: df_content += 'LABEL label_new="{0}"\n'.format(df_new) base_labels = {INSPECT_CONFIG: {"Labels": {}}} if base_old: base_labels[INSPECT_CONFIG]["Labels"]["label_old"] = base_old if base_new: base_labels[INSPECT_CONFIG]["Labels"]["label_new"] = base_new df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) flexmock(workflow, base_image_inspect=base_labels) setattr(workflow.builder, 'df_path', df.dockerfile_path) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': { 'labels': plugin_labels, 'dont_overwrite': [], 'auto_labels': [], 'aliases': {"label_old": "label_new"}, } }] ) runner.run() assert AddLabelsPlugin.key is not None result_old = df.labels.get("label_old") or \ base_labels[INSPECT_CONFIG]["Labels"].get("label_old") result_new = df.labels.get("label_new") or \ base_labels[INSPECT_CONFIG]["Labels"].get("label_new") assert result_old == exp_old assert result_new == exp_new if exp_log: assert exp_log in caplog.text()
def test_dont_overwrite_if_in_dockerfile(tmpdir, docker_tasker, label_names, dont_overwrite, parent_val, docker_val, result_val, reactor_config_map): default_value = 'default_value' df_content = "FROM fedora\n" if docker_val: for label_name in label_names: df_content += 'LABEL {0}="{1}"\n'.format(label_name, docker_val) if parent_val: labels_conf_base = {INSPECT_CONFIG: {"Labels": {}}} for label_name in label_names: labels_conf_base[INSPECT_CONFIG]["Labels"][label_name] = parent_val else: labels_conf_base = {INSPECT_CONFIG: {"Labels": {}}} df = df_parser(str(tmpdir)) df.content = df_content if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X()) setattr(workflow.builder, 'df_path', df.dockerfile_path) setattr(workflow.builder, 'base_image_inspect', labels_conf_base) image_labels = {} for label_name in label_names: image_labels[label_name] = default_value wf_args = { 'labels': image_labels, 'auto_labels': [], 'aliases': {}, } if dont_overwrite: wf_args["dont_overwrite_if_in_dockerfile"] = label_names if reactor_config_map: make_and_store_reactor_config_map(workflow, {'image_labels': image_labels}) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': wf_args }] ) runner.run() for label_name in label_names: result = df.labels.get(label_name) assert result == result_val
def test_try_with_library_pull_base_image(library, reactor_config_map): if MOCK: mock_docker(remember_images=True) tasker = DockerTasker(retry_times=0) workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = MockBuilder() if library: base_image = 'library/parent-image' else: base_image = 'parent-image' workflow.builder.base_image = ImageName.parse(base_image) workflow.builder.parent_images = {ImageName.parse(base_image): None} class MockResponse(object): content = '' cr = CommandResult() cr._error = "cmd_error" cr._error_detail = {"message": "error_detail"} if library: call_wait = 1 else: call_wait = 2 (flexmock(atomic_reactor.util) .should_receive('wait_for_command') .times(call_wait) .and_return(cr)) error_message = 'registry.example.com/' + base_image if reactor_config_map: workflow.plugin_workspace[ReactorConfigPlugin.key] = {} workflow.plugin_workspace[ReactorConfigPlugin.key][WORKSPACE_CONF_KEY] =\ ReactorConfig({'version': 1, 'source_registry': {'url': 'registry.example.com', 'insecure': True}}) runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': PullBaseImagePlugin.key, 'args': {'parent_registry': 'registry.example.com', 'parent_registry_insecure': True}, }], ) with pytest.raises(PluginFailedException) as exc: runner.run() assert error_message in exc.value.args[0]
def test_single_repourl(): tasker, workflow = prepare() url = 'http://example.com/example%20repo.repo' filename = 'example repo.repo' runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': AddYumRepoByUrlPlugin.key, 'args': {'repourls': [url]}}]) runner.run() # next(iter(...)) is for py 2/3 compatibility assert next(iter(workflow.files.keys())) == os.path.join(YUM_REPOS_DIR, filename) assert next(iter(workflow.files.values())) == repocontent assert len(workflow.files) == 1
def run_plugin_with_args(self, workflow, plugin_args=None, expect_error=None, reactor_config_map=False, platforms=ODCS_COMPOSE_DEFAULT_ARCH_LIST, is_pulp=None, check_for_default_id=True): plugin_args = plugin_args or {} plugin_args.setdefault('odcs_url', ODCS_URL) plugin_args.setdefault('koji_target', KOJI_TARGET_NAME) plugin_args.setdefault('koji_hub', KOJI_HUB) reactor_conf =\ deepcopy(workflow.plugin_workspace[ReactorConfigPlugin.key][WORKSPACE_CONF_KEY].conf) if reactor_config_map: reactor_conf['koji'] = {'hub_url': KOJI_HUB, 'root_url': '', 'auth': {}} if 'koji_ssl_certs_dir' in plugin_args: reactor_conf['koji']['auth']['ssl_certs_dir'] = plugin_args['koji_ssl_certs_dir'] workflow.plugin_workspace[ReactorConfigPlugin.key][WORKSPACE_CONF_KEY] =\ ReactorConfig(reactor_conf) runner = PreBuildPluginsRunner( workflow.builder.tasker, workflow, [ {'name': ResolveComposesPlugin.key, 'args': plugin_args}, ] ) if expect_error: with pytest.raises(PluginFailedException) as exc_info: runner.run() assert expect_error in str(exc_info.value) return results = runner.run()[ResolveComposesPlugin.key] if results: for platform in platforms or []: yum_repourls = self.get_override_yum_repourls(workflow, platform) # Koji tag compose is present in each one if check_for_default_id: assert ODCS_COMPOSE['result_repofile'] in yum_repourls if is_pulp: pulp_repo = ODCS_COMPOSE_REPO + '/pulp_compose-' + platform assert pulp_repo in yum_repourls yum_repourls = self.get_override_yum_repourls(workflow, None) if platforms: assert yum_repourls is None else: assert ODCS_COMPOSE['result_repofile'] in yum_repourls assert set(results.keys()) == set(['signing_intent', 'signing_intent_overridden', 'composes']) else: assert self.get_override_yum_repourls(workflow) is None assert results is None return results
def test_use_check_and_set_platforms_result(tmpdir, docker_tasker, global_arches, param_arches, expected_arches): """ global_arches: list of architectures returned by check_and_set_platforms plugin param_arches: list of architectures given to add_filesystem plugin as parameter """ if MOCK: mock_docker() workflow = mock_workflow(tmpdir) mock_koji_session(arches=expected_arches) mock_image_build_file(str(tmpdir)) if global_arches: workflow.prebuild_results[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] = set( global_arches) plugin_args = {} if param_arches: plugin_args['architectures'] = param_arches runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': plugin_args }]) results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'base-image-id' in plugin_result assert plugin_result['base-image-id'] is None assert 'filesystem-koji-task-id' in plugin_result
def test_add_filesystem_plugin_legacy(tmpdir, docker_tasker, scratch, reactor_config_map): if MOCK: mock_docker() workflow = mock_workflow(tmpdir) mock_koji_session(scratch=scratch) mock_image_build_file(str(tmpdir)) if reactor_config_map: make_and_store_reactor_config_map(workflow, { 'root_url': '', 'auth': {} }) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': { 'koji_hub': KOJI_HUB, } }]) results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'base-image-id' in plugin_result assert plugin_result['base-image-id'] == IMPORTED_IMAGE_ID assert 'filesystem-koji-task-id' in plugin_result
def test_image_task_failure(tmpdir, raise_error): if MOCK: mock_docker() dockerfile = dedent("""\ FROM koji/image-build RUN dnf install -y python-django """) task_result = 'task-result' def _mockGetTaskResult(task_id): if raise_error: raise RuntimeError(task_result) return task_result workflow = mock_workflow(tmpdir, dockerfile) mock_koji_session(image_task_fail=True, get_task_result_mock=_mockGetTaskResult) mock_image_build_file(str(tmpdir)) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': AddFilesystemPlugin.key, 'args': { 'koji_hub': KOJI_HUB } }]) with pytest.raises(PluginFailedException) as exc: results = runner.run() assert task_result in str(exc) # Also ensure getTaskResult exception message is wrapped properly assert 'image task,' in str(exc)
def test_add_filesystem_plugin_generated(tmpdir, docker_tasker, scratch): if MOCK: mock_docker() dockerfile = dedent("""\ FROM koji/image-build RUN dnf install -y python-django """) workflow = mock_workflow(tmpdir, dockerfile) mock_koji_session(scratch=scratch) mock_image_build_file(str(tmpdir)) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': AddFilesystemPlugin.key, 'args': { 'koji_hub': KOJI_HUB } }]) results = runner.run() plugin_result = results[AddFilesystemPlugin.key] assert 'base-image-id' in plugin_result assert plugin_result['base-image-id'] == IMPORTED_IMAGE_ID assert 'filesystem-koji-task-id' in plugin_result
def test_add_filesystem_plugin_legacy(workflow, build_dir, scratch, caplog): mock_workflow(workflow, build_dir, scratch=scratch) workflow.data.prebuild_results[PLUGIN_RESOLVE_COMPOSES_KEY] = { 'composes': [] } mock_koji_session(scratch=scratch) mock_image_build_file(workflow) image_name = 'fedora-23-1.0.x86_64.tar.gz' expected_dockerfile_content = dedent(f"""\ FROM scratch ADD {image_name} / RUN dnf install -y python-django """) make_and_store_reactor_config_map(workflow, {'root_url': '', 'auth': {}}) runner = PreBuildPluginsRunner(workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': {} }]) results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'filesystem-koji-task-id' in plugin_result assert workflow.data.labels[ 'filesystem-koji-task-id'] == FILESYSTEM_TASK_ID msg = f'added "{image_name}" as image filesystem' assert msg in caplog.text assert workflow.build_dir.any_platform.dockerfile.content == expected_dockerfile_content
def test_no_base_image_in_dockerfile(tmpdir): dockerfile = tmpdir.join('Dockerfile') dockerfile.write_text('', encoding='utf8') tasker, workflow = prepare(str(dockerfile)) workflow.files = {'/etc/yum.repos.d/foo.repo': 'repo'} runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': InjectYumRepoPlugin.key, 'args': {}, }]) with pytest.raises(PluginFailedException) as exc: runner.run() assert "No FROM line in Dockerfile" in str(exc.value)
def test_image_download(tmpdir, docker_tasker, architecture, architectures, download_filesystem): if MOCK: mock_docker() dockerfile = dedent("""\ FROM koji/image-build RUN dnf install -y python-django """) workflow = mock_workflow(tmpdir, dockerfile) mock_koji_session(download_filesystem=download_filesystem) mock_image_build_file(str(tmpdir)) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': { 'koji_hub': KOJI_HUB, 'architecture': architecture, 'architectures': architectures, } }]) results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'base-image-id' in plugin_result assert 'filesystem-koji-task-id' in plugin_result if download_filesystem: assert plugin_result['base-image-id'] == IMPORTED_IMAGE_ID assert plugin_result['filesystem-koji-task-id'] == FILESYSTEM_TASK_ID else: assert plugin_result['base-image-id'] is None assert plugin_result['filesystem-koji-task-id'] is None
def test_no_repourls(tmpdir): for df_content in DOCKERFILES.values(): df = df_parser(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 run_plugin_with_args(self, workflow, plugin_args=None, expect_result=True, # noqa reactor_config_map=False): plugin_args = plugin_args or {} plugin_args.setdefault('koji_hub', KOJI_HUB) plugin_args.setdefault('poll_interval', 0.01) plugin_args.setdefault('poll_timeout', 1) if reactor_config_map: koji_map = { 'hub_url': KOJI_HUB, 'root_url': '', 'auth': {} } if 'koji_ssl_certs_dir' in plugin_args: koji_map['auth']['ssl_certs_dir'] = plugin_args['koji_ssl_certs_dir'] workflow.plugin_workspace[ReactorConfigPlugin.key] = {} workflow.plugin_workspace[ReactorConfigPlugin.key][WORKSPACE_CONF_KEY] =\ ReactorConfig({'version': 1, 'koji': koji_map}) runner = PreBuildPluginsRunner( workflow.builder.tasker, workflow, [{'name': KojiParentPlugin.key, 'args': plugin_args}] ) result = runner.run() if expect_result is True: expected_result = {BASE_IMAGE_KOJI_BUILD: KOJI_BUILD} elif expect_result is False: expected_result = None else: # param provided the expected result expected_result = expect_result assert result[KojiParentPlugin.key] == expected_result
def test_platforms_from_cluster_config(tmpdir, platforms, platform_only, cluster_platforms, result): write_container_yaml(tmpdir, platform_only=platform_only) tasker, workflow = prepare(tmpdir) if platforms: set_orchestrator_platforms(workflow, platforms.split()) build_json = {'metadata': {'labels': {}}} flexmock(util).should_receive('get_build_json').and_return(build_json) mock_config = MockConfig(cluster_platforms) flexmock(reactor_config).should_receive('get_config').and_return( mock_config) runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': PLUGIN_CHECK_AND_SET_PLATFORMS_KEY, }]) plugin_result = runner.run() if platforms: assert plugin_result[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] assert plugin_result[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] == set(result) else: assert plugin_result[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] is None
def test_add_filesystem_plugin_generated(tmpdir, docker_tasker, scratch, reactor_config_map): if MOCK: mock_docker() workflow = mock_workflow(tmpdir, scratch=scratch) task_id = FILESYSTEM_TASK_ID mock_koji_session(scratch=scratch) mock_image_build_file(str(tmpdir)) if reactor_config_map: make_and_store_reactor_config_map(workflow, { 'root_url': '', 'auth': {} }) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': { 'koji_hub': KOJI_HUB, 'from_task_id': task_id, 'architecture': 'x86_64' } }]) expected_results = { 'base-image-id': IMPORTED_IMAGE_ID, 'filesystem-koji-task-id': FILESYSTEM_TASK_ID, } results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'base-image-id' in plugin_result assert 'filesystem-koji-task-id' in plugin_result assert plugin_result == expected_results
def test_add_help_no_help_file(request, tmpdir, docker_tasker, filename): df_content = "FROM fedora" df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': AddHelpPlugin.key, 'args': { 'help_file': filename } }]) # Runner should not crash if no help.md found result = runner.run() assert result == { 'add_help': { 'status': AddHelpPlugin.NO_HELP_FILE_FOUND, 'help_file': filename } }
def test_add_filesystem_plugin_generated(workflow, build_dir, scratch, dockerfile, expected_dockerfile, caplog): mock_workflow(workflow, build_dir, scratch=scratch, dockerfile=dockerfile) mock_koji_session(scratch=scratch) mock_image_build_file(workflow) image_name = 'fedora-23-1.0.x86_64.tar.gz' expected_dockerfile = expected_dockerfile.replace( 'ADD {} {}\n', f'ADD {image_name} ' '/\n') make_and_store_reactor_config_map(workflow, {'root_url': '', 'auth': {}}) runner = PreBuildPluginsRunner(workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': {} }]) expected_results = { 'filesystem-koji-task-id': FILESYSTEM_TASK_ID, } results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'filesystem-koji-task-id' in plugin_result assert plugin_result == expected_results assert workflow.data.labels[ 'filesystem-koji-task-id'] == FILESYSTEM_TASK_ID msg = f'added "{image_name}" as image filesystem' assert msg in caplog.text assert workflow.build_dir.any_platform.dockerfile.content == expected_dockerfile
def test_add_filesystem_plugin_generated(tmpdir, docker_tasker, scratch): if MOCK: mock_docker() dockerfile = dedent("""\ FROM koji/image-build RUN dnf install -y python-django """) workflow = mock_workflow(tmpdir, dockerfile) task_id = FILESYSTEM_TASK_ID mock_koji_session(scratch=scratch) mock_image_build_file(str(tmpdir)) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': { 'koji_hub': KOJI_HUB, 'from_task_id': task_id, 'architecture': 'x86_64' } }]) expected_results = { 'base-image-id': IMPORTED_IMAGE_ID, 'filesystem-koji-task-id': FILESYSTEM_TASK_ID, } results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] assert 'base-image-id' in plugin_result assert 'filesystem-koji-task-id' in plugin_result assert plugin_result == expected_results
def run_plugin_with_args( self, workflow, plugin_args=None, reactor_config_map=False, # noqa organization=None, base_from_scratch=False, custom_base_image=False): plugin_args = plugin_args or {} plugin_args.setdefault('koji_parent_build', KOJI_BUILD_ID) plugin_args.setdefault('koji_hub', KOJI_HUB) if reactor_config_map: koji_map = {'hub_url': KOJI_HUB, 'root_url': '', 'auth': {}} if 'koji_ssl_certs_dir' in plugin_args: koji_map['auth']['ssl_certs_dir'] = plugin_args[ 'koji_ssl_certs_dir'] workflow.plugin_workspace[ReactorConfigPlugin.key] = {} workflow.plugin_workspace[ReactorConfigPlugin.key][WORKSPACE_CONF_KEY] =\ ReactorConfig({'version': 1, 'koji': koji_map, 'registries_organization': organization}) runner = PreBuildPluginsRunner(workflow.builder.tasker, workflow, [{ 'name': InjectParentImage.key, 'args': plugin_args }]) result = runner.run() if base_from_scratch or custom_base_image: assert result[InjectParentImage.key] is None else: # Koji build ID is always used, even when NVR is given. assert result[InjectParentImage.key] == KOJI_BUILD_ID self.assert_images_to_remove(workflow)
def test_fetch_maven_artifacts_nvr_filtering(tmpdir, docker_tasker, nvr_requests, expected): """Test filtering of archives in a Koji build.""" workflow = mock_workflow(tmpdir) mock_koji_session() mock_fetch_artifacts_by_nvr(str(tmpdir), contents=yaml.safe_dump(nvr_requests)) mock_nvr_downloads(archives=expected) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FetchMavenArtifactsPlugin.key, 'args': {'koji_hub': KOJI_HUB, 'koji_root': KOJI_ROOT} }] ) results = runner.run() plugin_result = results[FetchMavenArtifactsPlugin.key] assert len(plugin_result) == len(expected) for download in plugin_result: assert len(download.checksums.values()) == 1 assert (set(list(download.checksums.values())[0] for download in plugin_result) == set(expectation['checksum'] for expectation in expected)) for download in plugin_result: dest = os.path.join(str(tmpdir), FetchMavenArtifactsPlugin.DOWNLOAD_DIR, download.dest) assert os.path.exists(dest)
def test_fetch_maven_artifacts_url_with_target(tmpdir, docker_tasker): """Remote file is downloaded into specified filename.""" workflow = mock_workflow(tmpdir) mock_koji_session() remote_files = [REMOTE_FILE_WITH_TARGET] mock_fetch_artifacts_by_url(str(tmpdir), contents=yaml.safe_dump(remote_files)) mock_url_downloads(remote_files) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FetchMavenArtifactsPlugin.key, 'args': {'koji_hub': KOJI_HUB, 'koji_root': KOJI_ROOT} }] ) results = runner.run() plugin_result = results[FetchMavenArtifactsPlugin.key] assert len(plugin_result) == len(remote_files) download = plugin_result[0] dest = os.path.join(str(tmpdir), FetchMavenArtifactsPlugin.DOWNLOAD_DIR, download.dest) assert os.path.exists(dest) assert download.dest == REMOTE_FILE_WITH_TARGET['target'] assert not REMOTE_FILE_WITH_TARGET['url'].endswith(download.dest)
def test_fetch_maven_artifacts(tmpdir, docker_tasker, reactor_config_map): workflow = mock_workflow(tmpdir) mock_koji_session() mock_fetch_artifacts_by_nvr(str(tmpdir)) mock_fetch_artifacts_by_url(str(tmpdir)) mock_nvr_downloads() mock_url_downloads() if reactor_config_map: make_and_store_reactor_config_map(workflow) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': FetchMavenArtifactsPlugin.key, 'args': { 'koji_hub': KOJI_HUB, 'koji_root': KOJI_ROOT } }]) results = runner.run() plugin_result = results[FetchMavenArtifactsPlugin.key] assert len( plugin_result) == len(DEFAULT_ARCHIVES) + len(DEFAULT_REMOTE_FILES) for download in plugin_result: dest = os.path.join(str(tmpdir), FetchMavenArtifactsPlugin.DOWNLOAD_DIR, download.dest) assert os.path.exists(dest)
def test_add_labels_plugin(tmpdir, docker_tasker, df_content, labels_conf_base, labels_conf, eq_conf, dont_overwrite, aliases, expected_output, caplog, reactor_config_map): df = df_parser(str(tmpdir)) df.content = df_content if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) setattr(workflow.builder, 'df_path', df.dockerfile_path) setattr(workflow.builder, 'base_image_inspect', labels_conf_base) if reactor_config_map: # reactor_config should not return json if isinstance(labels_conf, str): image_labels = json.loads(labels_conf) else: image_labels = deepcopy(labels_conf) make_and_store_reactor_config_map(workflow, { 'image_labels': image_labels, 'image_equal_labels': eq_conf, }) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': { 'labels': labels_conf, 'dont_overwrite': dont_overwrite, 'auto_labels': [], 'aliases': aliases, 'equal_labels': eq_conf, } }]) if isinstance(expected_output, RuntimeError): with pytest.raises(PluginFailedException): runner.run() assert "plugin 'add_labels_in_dockerfile' raised an exception: RuntimeError" \ in caplog.text() else: runner.run() assert AddLabelsPlugin.key is not None assert df.content in expected_output
def test_add_help_plugin(tmpdir, docker_tasker, filename): df_content = dedent(""" FROM fedora RUN yum install -y python-django CMD blabla""") df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = X workflow.builder.df_path = df.dockerfile_path workflow.builder.df_dir = str(tmpdir) help_markdown_path = os.path.join(workflow.builder.df_dir, filename) generate_a_file(help_markdown_path, "foo") help_man_path = os.path.join(workflow.builder.df_dir, AddHelpPlugin.man_filename) generate_a_file(help_man_path, "bar") cmd = [ 'go-md2man', '-in={}'.format(help_markdown_path), '-out={}'.format(help_man_path) ] def check_popen(*args, **kwargs): assert args[0] == cmd return MockedPopen() (flexmock(subprocess).should_receive("Popen").once().replace_with( check_popen)) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': AddHelpPlugin.key, 'args': { 'help_file': filename } }]) runner.run() assert df.content == dedent( """ FROM fedora RUN yum install -y python-django ADD %s /%s CMD blabla""" % (AddHelpPlugin.man_filename, AddHelpPlugin.man_filename))
def test_try_with_library_pull_base_image(library): if MOCK: mock_docker(remember_images=True) tasker = DockerTasker(retry_times=0) workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') workflow.builder = MockBuilder() if library: base_image = 'library/parent-image' else: base_image = 'parent-image' workflow.builder.base_image = ImageName.parse(base_image) class MockResponse(object): content = '' cr = CommandResult() cr._error = "cmd_error" cr._error_detail = {"message": "error_detail"} if library: call_wait = 1 else: call_wait = 2 (flexmock(atomic_reactor.util) .should_receive('wait_for_command') .times(call_wait) .and_return(cr)) error_message = 'registry.example.com/' + base_image runner = PreBuildPluginsRunner( tasker, workflow, [{ 'name': PullBaseImagePlugin.key, 'args': {'parent_registry': 'registry.example.com', 'parent_registry_insecure': True}, }], ) with pytest.raises(PluginFailedException) as exc: runner.run() assert error_message in exc.value.args[0]
def test_add_labels_arrangement6(tmpdir, docker_tasker, workflow, release, use_reactor): # explicitly test arrangement 6's handling of reactor config df = df_parser(str(tmpdir)) df.content = DF_CONTENT if MOCK: mock_docker() setattr(workflow, 'builder', X()) setattr(workflow.builder, 'base_image_inspect', LABELS_CONF_BASE) setattr(workflow.builder, 'df_path', df.dockerfile_path) flexmock(workflow, source=MockSource()) if use_reactor: make_and_store_reactor_config_map(workflow, {'image_labels': LABELS_CONF}) if release is not None: labels = {'release': release} else: labels = None else: labels = LABELS_CONF if release is not None: labels.update({'release': release}) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': { 'labels': labels, 'dont_overwrite': [], 'auto_labels': [], 'aliases': [], 'equal_labels': [], } }] ) runner.run() assert AddLabelsPlugin.key is not None assert 'label1' in df.content if release: assert 'release' in df.content assert release in df.content else: assert 'release' not in df.content
def test_single_repourl(tmpdir): for df_content in DOCKERFILES.values(): df = df_parser(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-ccece.repo' unique_filename = 'test-ccece.repo' repo_path = os.path.join(YUM_REPOS_DIR, filename) workflow.files[repo_path] = repocontent runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': InjectYumRepoPlugin.key, 'args': {}}]) runner.run() # Was it written correctly? repos_dir = os.path.join(str(tmpdir), RELATIVE_REPOS_PATH) repofile = os.path.join(repos_dir, unique_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])
def test_adddockerfile_fails(tmpdir, docker_tasker, caplog): # noqa df_content = """ FROM fedora RUN yum install -y python-django CMD blabla""" df = df_parser(str(tmpdir)) df.content = df_content workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') prepare(workflow, df.dockerfile_path) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': AddDockerfilePlugin.key }]) runner.run() assert "plugin 'add_dockerfile' raised an exception: ValueError" in caplog.text
def test_add_labels_base_image(tmpdir, docker_tasker, parent, should_fail, caplog, reactor_config_map): df = df_parser(str(tmpdir)) df.content = "FROM {}\n".format(parent) if MOCK: mock_docker() workflow = DockerBuildWorkflow(MOCK_SOURCE, 'test-image') setattr(workflow, 'builder', X) flexmock(workflow, source=MockSource()) setattr(workflow.builder, 'tasker', docker_tasker) setattr(workflow.builder, 'df_path', df.dockerfile_path) setattr(workflow.builder, 'base_image_inspect', {}) # When a 'release' label is provided by parameter and used to # configure the plugin, it should be set in the Dockerfile even # when processing base images. prov_labels = {'release': '5'} if reactor_config_map: make_and_store_reactor_config_map(workflow, {'image_labels': prov_labels}) runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': AddLabelsPlugin.key, 'args': { 'labels': prov_labels, "dont_overwrite": [], 'aliases': { 'Build_Host': 'com.redhat.build-host' } } }]) if should_fail: with caplog.atLevel(logging.ERROR): with pytest.raises(PluginFailedException): runner.run() msg = "base image was not inspected" assert msg in [x.message for x in caplog.records()] else: runner.run() assert df.labels['release'] == '5'
def test_koji_plugin(): tasker, workflow = prepare() runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': KojiPlugin.key, 'args': { "target": KOJI_TARGET, "hub": "", "root": ROOT, } }]) runner.run() assert list(workflow.files.keys())[0] == "/etc/yum.repos.d/target.repo" assert list(workflow.files.values())[0].startswith("[atomic-reactor-koji-plugin-target]\n") assert "gpgcheck=0\n" in list(workflow.files.values())[0] assert "enabled=1\n" in list(workflow.files.values())[0] assert "name=atomic-reactor-koji-plugin-target\n" in list(workflow.files.values())[0] assert "baseurl=http://example.com/repos/tag/2/$basearch\n" in list(workflow.files.values())[0]
def test_single_repourl(): tasker, workflow = prepare() url = 'http://example.com/example%20repo.repo' filename = 'example repo.repo' runner = PreBuildPluginsRunner(tasker, workflow, [{ 'name': AddYumRepoByUrlPlugin.key, 'args': { 'repourls': [url] } }]) runner.run() # next(iter(...)) is for py 2/3 compatibility assert next(iter(workflow.files.keys())) == os.path.join( YUM_REPOS_DIR, filename) assert next(iter(workflow.files.values())) == repocontent assert len(workflow.files) == 1
def test_non_buildstep_phase_raises_InappropriateBuildStepError( caplog, tmpdir, docker_tasker): # noqa """ tests that exception is raised if no buildstep_phase but raises InappropriateBuildStepError """ workflow = mock_workflow(tmpdir) flexmock(PluginsRunner, load_plugins=lambda x: {MyPreBuildPlugin.key: MyPreBuildPlugin}) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ "name": MyPreBuildPlugin.key }]) # flexmock(MyBsPlugin1).should_call('run').and_raise(InappropriateBuildStepError).once() with pytest.raises(Exception): runner.run()
def test_image_download(tmpdir, docker_tasker, parents, skip_plugin, architecture, architectures, download_filesystem, reactor_config_map, caplog): if MOCK: mock_docker() workflow = mock_workflow(tmpdir, for_orchestrator=architectures is not None) if not skip_plugin: mock_koji_session(download_filesystem=download_filesystem) mock_image_build_file(str(tmpdir)) workflow.builder.base_image = ImageName.parse(parents[-1]) workflow.builder.parents_ordered = parents workflow.builder.custom_parent_image = 'koji/image-build' in parents workflow.builder.custom_base_image = 'koji/image-build' == parents[-1] workflow.builder.parent_images = {} for image in parents: if image == 'scratch': continue workflow.builder.parent_images[ImageName.parse(image)] = None if architectures: workflow.prebuild_results[PLUGIN_CHECK_AND_SET_PLATFORMS_KEY] = set( architectures) if reactor_config_map: make_and_store_reactor_config_map(workflow, { 'root_url': '', 'auth': {} }) runner = PreBuildPluginsRunner(docker_tasker, workflow, [{ 'name': PLUGIN_ADD_FILESYSTEM_KEY, 'args': { 'koji_hub': KOJI_HUB, 'architecture': architecture, } }]) results = runner.run() plugin_result = results[PLUGIN_ADD_FILESYSTEM_KEY] if skip_plugin: message = 'Nothing to do for non-custom base images' assert message in caplog.text assert plugin_result is None return assert 'base-image-id' in plugin_result assert 'filesystem-koji-task-id' in plugin_result if download_filesystem: assert plugin_result['base-image-id'] == IMPORTED_IMAGE_ID assert plugin_result['filesystem-koji-task-id'] == FILESYSTEM_TASK_ID else: assert plugin_result['base-image-id'] is None assert plugin_result['filesystem-koji-task-id'] is None
def test_flatpak_create_dockerfile(tmpdir, docker_tasker, config_name, breakage): config = CONFIGS[config_name] workflow = mock_workflow(tmpdir, config['container_yaml']) compose = setup_flatpak_compose_info(workflow, config) if breakage == 'branch_mismatch': compose.base_module.mmd.xmd['flatpak']['branch'] = 'MISMATCH' expected_exception = "Mismatch for 'branch'" else: assert breakage is None expected_exception = None args = { 'base_image': "registry.fedoraproject.org/fedora:latest", } runner = PreBuildPluginsRunner( docker_tasker, workflow, [{ 'name': FlatpakCreateDockerfilePlugin.key, 'args': args }]) if expected_exception: with pytest.raises(PluginFailedException) as ex: runner.run() assert expected_exception in str(ex) else: runner.run() assert os.path.exists(workflow.builder.df_path) includepkgs_path = os.path.join(workflow.builder.df_dir, 'atomic-reactor-includepkgs') assert os.path.exists(includepkgs_path) with open(includepkgs_path) as f: includepkgs = f.read() assert 'librsvg2' in includepkgs if config_name == 'app': assert 'eog-0:3.24.1-1.module_7b96ed10.x86_64' in includepkgs assert os.path.exists( os.path.join(workflow.builder.df_dir, 'cleanup.sh'))