diff --git a/src/pylorax/api/projects.py b/src/pylorax/api/projects.py index 40171363..44e6e902 100644 --- a/src/pylorax/api/projects.py +++ b/src/pylorax/api/projects.py @@ -320,6 +320,38 @@ def modules_info(yb, module_names): return modules +def yum_repo_to_file_repo(repo): + """Return a string representation of a YumRepository object suitable for writing to a .repo file + + :param repo: Yum Repository + :type repo: yum.yumRepo.YumRepository + :returns: A string + :rtype: str + + The YumRepo.dump() function does not produce a string that can be used as a + yum .repo file. So do this manually with only the attributes we care about. + """ + repo_str = "[%s]\n" % repo.id + if repo.metalink: + repo_str += "metalink = %s\n" % repo.metalink + elif repo.mirrorlist: + repo_str += "mirrorlist = %s\n" % repo.mirrorlist + elif repo.baseurl: + repo_str += "baseurl = %s\n" % repo.baseurl[0] + else: + raise RuntimeError("Repo has no baseurl, metalink, or mirrorlist") + + # proxy is optional + if repo.proxy: + repo_str += "proxy = %s\n" % repo.proxy + + repo_str += "sslverify = %s\n" % repo.sslverify + repo_str += "gpgcheck = %s\n" % repo.gpgcheck + if repo.gpgkey: + repo_str += "gpgkey = %s\n" % ",".join(repo.gpgkey) + + return repo_str + def repo_to_source(repo, system_source): """Return a Weldr Source dict created from the YumRepository @@ -408,7 +440,7 @@ def source_to_repo(source): repo.skip_if_unavailable = False if source["type"] == "yum-baseurl": - repo.baseurl = [source["url"]] + repo.baseurl = source["url"] elif source["type"] == "yum-metalink": repo.metalink = source["url"] elif source["type"] == "yum-mirrorlist": @@ -428,7 +460,7 @@ def source_to_repo(source): repo.gpgcheck = False if "gpgkey_urls" in source: - repo.gpgkey = source["gpgkey_urls"] + repo.gpgkey = ",".join(source["gpgkey_urls"]) repo.enable() diff --git a/src/pylorax/api/v0.py b/src/pylorax/api/v0.py index 56d850aa..21702446 100644 --- a/src/pylorax/api/v0.py +++ b/src/pylorax/api/v0.py @@ -973,7 +973,7 @@ from pylorax.api.compose import start_build, compose_types from pylorax.api.crossdomain import crossdomain from pylorax.api.projects import projects_list, projects_info, projects_depsolve from pylorax.api.projects import modules_list, modules_info, ProjectsError, repo_to_source -from pylorax.api.projects import get_repo_sources, delete_repo_source, source_to_repo +from pylorax.api.projects import get_repo_sources, delete_repo_source, source_to_repo, yum_repo_to_file_repo from pylorax.api.queue import queue_status, build_status, uuid_delete, uuid_status, uuid_info from pylorax.api.queue import uuid_tar, uuid_image, uuid_cancel, uuid_log from pylorax.api.recipes import list_branch_files, read_recipe_commit, recipe_filename, list_commits @@ -1423,9 +1423,12 @@ def v0_api(api): continue sources[repo.id] = repo_to_source(repo, repo.id in system_sources) - if out_fmt == "toml": + if out_fmt == "toml" and not errors: # With TOML output we just want to dump the raw sources, skipping the errors return toml.dumps(sources) + elif out_fmt == "toml" and errors: + # TOML requested, but there was an error + return jsonify(status=False, errors=errors), 400 else: return jsonify(sources=sources, errors=errors) @@ -1469,7 +1472,7 @@ def v0_api(api): # Make sure the source name can't contain a path traversal by taking the basename source_path = joinpaths(repo_dir, os.path.basename("%s.repo" % source["name"])) with open(source_path, "w") as f: - f.write(str(repo)) + f.write(yum_repo_to_file_repo(repo)) except Exception as e: log.error("(v0_projects_source_add) adding %s failed: %s", source["name"], str(e)) diff --git a/tests/pylorax/source/bad-repo.toml b/tests/pylorax/source/bad-repo.toml new file mode 100644 index 00000000..95f4355f --- /dev/null +++ b/tests/pylorax/source/bad-repo.toml @@ -0,0 +1,6 @@ +name = "bad-repo-1" +url = "file:///tmp/not-a-repo/" +type = "yum-baseurl" +check_ssl = true +check_gpg = true +gpgkey_urls = ["file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch"] diff --git a/tests/pylorax/test_projects.py b/tests/pylorax/test_projects.py index e9a61b0a..a77c0145 100644 --- a/tests/pylorax/test_projects.py +++ b/tests/pylorax/test_projects.py @@ -29,8 +29,9 @@ from pylorax.api.config import configure, make_yum_dirs from pylorax.api.projects import api_time, api_changelog, yaps_to_project, yaps_to_project_info from pylorax.api.projects import tm_to_dep, yaps_to_module, projects_list, projects_info, projects_depsolve from pylorax.api.projects import modules_list, modules_info, ProjectsError, dep_evra, dep_nevra -from pylorax.api.yumbase import get_base_object from pylorax.api.projects import repo_to_source, get_repo_sources, delete_repo_source, source_to_repo +from pylorax.api.projects import yum_repo_to_file_repo +from pylorax.api.yumbase import get_base_object class Yaps(object): @@ -271,6 +272,13 @@ def fakerepo_baseurl(): "url": "https://fake-repo.base.url" } +def fakerepo_baseurl_str(): + return """[fake-repo-baseurl] +baseurl = https://fake-repo.base.url +sslverify = True +gpgcheck = True +""" + class FakeSystemRepo(object): id = "fake-system-repo" baseurl = ["https://fake-repo.base.url"] @@ -310,6 +318,13 @@ def fakerepo_metalink(): "url": "https://fake-repo.metalink" } +def fakerepo_metalink_str(): + return """[fake-repo-metalink] +metalink = https://fake-repo.metalink +sslverify = True +gpgcheck = True +""" + class FakeRepoMirrorlist(object): id = "fake-repo-mirrorlist" baseurl = [] @@ -330,6 +345,13 @@ def fakerepo_mirrorlist(): "url": "https://fake-repo.mirrorlist" } +def fakerepo_mirrorlist_str(): + return """[fake-repo-mirrorlist] +mirrorlist = https://fake-repo.mirrorlist +sslverify = True +gpgcheck = True +""" + class FakeRepoProxy(object): id = "fake-repo-proxy" baseurl = ["https://fake-repo.base.url"] @@ -351,6 +373,14 @@ def fakerepo_proxy(): "url": "https://fake-repo.base.url" } +def fakerepo_proxy_str(): + return """[fake-repo-proxy] +baseurl = https://fake-repo.base.url +proxy = https://fake-repo.proxy +sslverify = True +gpgcheck = True +""" + class FakeRepoGPGKey(object): id = "fake-repo-gpgkey" baseurl = ["https://fake-repo.base.url"] @@ -374,6 +404,14 @@ def fakerepo_gpgkey(): "url": "https://fake-repo.base.url" } +def fakerepo_gpgkey_str(): + return """[fake-repo-gpgkey] +baseurl = https://fake-repo.base.url +sslverify = True +gpgcheck = True +gpgkey = https://fake-repo.gpgkey +""" + class SourceTest(unittest.TestCase): @classmethod def setUpClass(self): @@ -395,19 +433,19 @@ class SourceTest(unittest.TestCase): def test_repo_to_source_metalink(self): """Test a repo with a metalink""" - self.assertEqual(repo_to_source(FakeRepoMetalink, False), fakerepo_metalink()) + self.assertEqual(repo_to_source(FakeRepoMetalink(), False), fakerepo_metalink()) def test_repo_to_source_mirrorlist(self): """Test a repo with a mirrorlist""" - self.assertEqual(repo_to_source(FakeRepoMirrorlist, False), fakerepo_mirrorlist()) + self.assertEqual(repo_to_source(FakeRepoMirrorlist(), False), fakerepo_mirrorlist()) def test_repo_to_source_proxy(self): """Test a repo with a proxy""" - self.assertEqual(repo_to_source(FakeRepoProxy, False), fakerepo_proxy()) + self.assertEqual(repo_to_source(FakeRepoProxy(), False), fakerepo_proxy()) def test_repo_to_source_gpgkey(self): """Test a repo with a GPG key""" - self.assertEqual(repo_to_source(FakeRepoGPGKey, False), fakerepo_gpgkey()) + self.assertEqual(repo_to_source(FakeRepoGPGKey(), False), fakerepo_gpgkey()) def test_get_repo_sources(self): """Test getting a list of sources from a repo directory""" @@ -462,3 +500,23 @@ class SourceTest(unittest.TestCase): """Test creating a yum.yumRepo.YumRepository with a proxy""" repo = source_to_repo(fakerepo_gpgkey()) self.assertEqual(repo.gpgkey, fakerepo_gpgkey()["gpgkey_urls"]) + + def test_drtfr_baseurl(self): + """Test creating a yum .repo file from a baseurl Repo object""" + self.assertEqual(yum_repo_to_file_repo(FakeRepoBaseUrl()), fakerepo_baseurl_str()) + + def test_drtfr_metalink(self): + """Test creating a yum .repo file from a metalink Repo object""" + self.assertEqual(yum_repo_to_file_repo(FakeRepoMetalink()), fakerepo_metalink_str()) + + def test_drtfr_mirrorlist(self): + """Test creating a yum .repo file from a mirrorlist Repo object""" + self.assertEqual(yum_repo_to_file_repo(FakeRepoMirrorlist()), fakerepo_mirrorlist_str()) + + def test_drtfr_proxy(self): + """Test creating a yum .repo file from a baseurl Repo object with proxy""" + self.assertEqual(yum_repo_to_file_repo(FakeRepoProxy()), fakerepo_proxy_str()) + + def test_drtfr_gpgkey(self): + """Test creating a yum .repo file from a baseurl Repo object with gpgkey""" + self.assertEqual(yum_repo_to_file_repo(FakeRepoGPGKey()), fakerepo_gpgkey_str()) diff --git a/tests/pylorax/test_server.py b/tests/pylorax/test_server.py index 24bb1dea..ab2f9f28 100644 --- a/tests/pylorax/test_server.py +++ b/tests/pylorax/test_server.py @@ -549,12 +549,14 @@ class ServerTestCase(unittest.TestCase): resp = self.server.post("/api/v0/projects/source/new", data=toml_source, content_type="text/x-toml") + self.assertEqual(resp.status_code, 400) data = json.loads(resp.data) self.assertEqual(data["status"], False) def test_projects_source_01_delete_system(self): """Test /api/v0/projects/source/delete a system source""" resp = self.server.delete("/api/v0/projects/source/delete/base") + self.assertEqual(resp.status_code, 400) data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False) @@ -581,6 +583,7 @@ class ServerTestCase(unittest.TestCase): def test_projects_source_03_delete_unknown(self): """Test /api/v0/projects/source/delete an unknown source""" resp = self.server.delete("/api/v0/projects/source/delete/unknown-repo") + self.assertEqual(resp.status_code, 400) data = json.loads(resp.data) self.assertNotEqual(data, None) self.assertEqual(data["status"], False)