def test_delete_source_single(self): """Test deleting a source from a repo with only 1 entry""" delete_repo_source(joinpaths(self.tmp_dir, "*.repo"), "single-repo") sources = get_repo_sources(joinpaths(self.tmp_dir, "*.repo")) self.assertTrue("single-repo" not in sources) self.assertTrue( not os.path.exists(joinpaths(self.tmp_dir, "single.repo")))
def test_delete_source_other(self): """Test deleting a source from a repo that doesn't match the source name""" with self.assertRaises(ProjectsError): delete_repo_source(joinpaths(self.tmp_dir, "*.repo"), "unknown-source") sources = get_repo_sources(joinpaths(self.tmp_dir, "*.repo")) self.assertTrue("lorax-1" in sources) self.assertTrue("lorax-2" in sources) self.assertTrue("lorax-4" in sources) self.assertTrue("other-repo" in sources)
def test_delete_source_multiple(self): """Test deleting a source from a repo file with multiple entries""" delete_repo_source(joinpaths(self.tmp_dir, "*.repo"), "lorax-3") sources = get_repo_sources(joinpaths(self.tmp_dir, "*.repo")) self.assertTrue("lorax-3" not in sources)
def test_get_repo_sources(self): """Test getting a list of sources from a repo directory""" sources = get_repo_sources(joinpaths(self.tmp_dir, "*.repo")) self.assertTrue("lorax-1" in sources) self.assertTrue("lorax-2" in sources)
def v1_projects_source_info(source_ids): """Return detailed info about the list of sources **/api/v1/projects/source/info/<source-ids>** Return information about the comma-separated list of source ids. Or all of the sources if '*' is passed. Note that general globbing is not supported, only '*'. Immutable system sources will have the "system" field set to true. User added sources will have it set to false. System sources cannot be changed or deleted. Example:: { "errors": [], "sources": { "fedora": { "check_gpg": true, "check_ssl": true, "gpgkey_urls": [ "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" ], "id": "fedora", "name": "Fedora $releasever - $basearch", "proxy": "http://proxy.brianlane.com:8123", "system": true, "type": "yum-metalink", "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" } } } In v0 the ``name`` field was used for the id (a short name for the repo). In v1 ``name`` changed to ``id`` and ``name`` is now used for the longer descriptive name of the repository. """ if VALID_API_STRING.match(source_ids) is None: return jsonify(status=False, errors=[{ "id": INVALID_CHARS, "msg": "Invalid characters in API path" }]), 400 out_fmt = request.args.get("format", "json") if VALID_API_STRING.match(out_fmt) is None: return jsonify(status=False, errors=[{ "id": INVALID_CHARS, "msg": "Invalid characters in format argument" }]), 400 # Return info on all of the sources if source_ids == "*": with api.config["DNFLOCK"].lock: source_ids = ",".join( r.id for r in api.config["DNFLOCK"].dbo.repos.iter_enabled()) sources = {} errors = [] system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") for source in source_ids.split(","): with api.config["DNFLOCK"].lock: repo = api.config["DNFLOCK"].dbo.repos.get(source, None) if not repo: errors.append({ "id": UNKNOWN_SOURCE, "msg": "%s is not a valid source" % source }) continue sources[repo.id] = repo_to_source(repo, repo.id in system_sources, api=1) 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)
def v1_projects_source_new(): """Add a new package source. Or change an existing one **POST /api/v0/projects/source/new** Add (or change) a source for use when depsolving blueprints and composing images. The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported types for the urls are: * ``yum-baseurl`` is a URL to a yum repository. * ``yum-mirrorlist`` is a URL for a mirrorlist. * ``yum-metalink`` is a URL for a metalink. If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set this to false, or add your Certificate Authority to the host system. If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` should point to it. You can edit an existing source (other than system sources), by doing a POST of the new version of the source. It will overwrite the previous one. Example:: { "id": "custom-source-1", "name": "Custom Package Source #1", "url": "https://url/path/to/repository/", "type": "yum-baseurl", "check_ssl": true, "check_gpg": true, "gpgkey_urls": [ "https://url/path/to/gpg-key" ] } In v0 the ``name`` field was used for the id (a short name for the repo). In v1 ``name`` changed to ``id`` and ``name`` is now used for the longer descriptive name of the repository. """ if request.headers['Content-Type'] == "text/x-toml": source = toml.loads(request.data) else: source = request.get_json(cache=False) # XXX TODO # Check for id in source, return error if not # Add test for that if "id" not in source: return jsonify(status=False, errors=[{ "id": UNKNOWN_SOURCE, "msg": "'id' field is missing from API v1 request." }]), 400 system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") if source["id"] in system_sources: return jsonify(status=False, errors=[{ "id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be changed." % source["id"] }]), 400 try: # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) with api.config["DNFLOCK"].lock: dbo = api.config["DNFLOCK"].dbo # If this repo already exists, delete it and replace it with the new one repos = list(r.id for r in dbo.repos.iter_enabled()) if source["id"] in repos: del dbo.repos[source["id"]] repo = source_to_repo(source, dbo.conf) dbo.repos.add(repo) log.info("Updating repository metadata after adding %s", source["id"]) dbo.fill_sack(load_system_repo=False) dbo.read_comps() # Write the new repo to disk, replacing any existing ones repo_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") # Remove any previous sources with this id, ignore it if it isn't found try: delete_repo_source(joinpaths(repo_dir, "*.repo"), source["id"]) except ProjectsError: pass # Make sure the source id can't contain a path traversal by taking the basename source_path = joinpaths(repo_dir, os.path.basename("%s.repo" % source["id"])) with open(source_path, "w") as f: f.write(dnf_repo_to_file_repo(repo)) except Exception as e: log.error("(v0_projects_source_add) adding %s failed: %s", source["id"], str(e)) # Cleanup the mess, if loading it failed we don't want to leave it in memory repos = list(r.id for r in dbo.repos.iter_enabled()) if source["id"] in repos: with api.config["DNFLOCK"].lock: dbo = api.config["DNFLOCK"].dbo del dbo.repos[source["id"]] log.info("Updating repository metadata after adding %s failed", source["id"]) dbo.fill_sack(load_system_repo=False) dbo.read_comps() return jsonify(status=False, errors=[{ "id": PROJECTS_ERROR, "msg": str(e) }]), 400 return jsonify(status=True)
def v1_projects_source_new(): """Add a new package source. Or change an existing one **POST /api/v1/projects/source/new** Add (or change) a source for use when depsolving blueprints and composing images. The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported types for the urls are: * ``yum-baseurl`` is a URL to a yum repository. * ``yum-mirrorlist`` is a URL for a mirrorlist. * ``yum-metalink`` is a URL for a metalink. If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set this to false, or add your Certificate Authority to the host system. If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` should point to it. You can edit an existing source (other than system sources), by doing a POST of the new version of the source. It will overwrite the previous one. Example:: { "id": "custom-source-1", "name": "Custom Package Source #1", "url": "https://url/path/to/repository/", "type": "yum-baseurl", "check_ssl": true, "check_gpg": true, "gpgkey_urls": [ "https://url/path/to/gpg-key" ] } In v0 the ``name`` field was used for the id (a short name for the repo). In v1 ``name`` changed to ``id`` and ``name`` is now used for the longer descriptive name of the repository. """ if request.headers['Content-Type'] == "text/x-toml": source = toml.loads(request.data) else: source = request.get_json(cache=False) # Check for id in source, return error if not if "id" not in source: return jsonify(status=False, errors=[{ "id": UNKNOWN_SOURCE, "msg": "'id' field is missing from API v1 request." }]), 400 system_sources = get_repo_sources("/etc/yum.repos.d/*.repo") if source["id"] in system_sources: return jsonify(status=False, errors=[{ "id": SYSTEM_SOURCE, "msg": "%s is a system source, it cannot be changed." % source["id"] }]), 400 try: # Remove it from the RepoDict (NOTE that this isn't explicitly supported by the DNF API) with api.config["DNFLOCK"].lock: repo_dir = api.config["COMPOSER_CFG"].get("composer", "repo_dir") new_repo_source(api.config["DNFLOCK"].dbo, source["id"], source, repo_dir) except Exception as e: return jsonify(status=False, errors=[{ "id": PROJECTS_ERROR, "msg": str(e) }]), 400 return jsonify(status=True)