Skip to content

Commit a38c822

Browse files
authored
Merge pull request #218 from rbikar/create-repo
Add Client.create_repository() [RHELDST-22483]
2 parents dfe6dd8 + fd915a0 commit a38c822

File tree

22 files changed

+436
-30
lines changed

22 files changed

+436
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- n/a
10+
- Added `Client.create_repository()` method
1111

1212
## [2.38.1] - 2023-12-14
1313

docs/api/files.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Repository
1414
.. autoclass:: pubtools.pulplib.FileSyncOptions()
1515
:members:
1616

17+
.. autoclass:: pubtools.pulplib.FileImporter()
18+
:members:
1719

1820
Units
1921
-----

docs/api/pulpcore.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ Repository
2727
.. autoclass:: pubtools.pulplib.SyncOptions()
2828
:members:
2929

30+
.. autoclass:: pubtools.pulplib.Importer()
31+
:members:
3032

3133
Units
3234
-----

docs/api/yum.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Repository
1414
.. autoclass:: pubtools.pulplib.YumSyncOptions()
1515
:members:
1616

17+
.. autoclass:: pubtools.pulplib.YumImporter()
18+
:members:
1719

1820
Units: RPM
1921
----------

pubtools/pulplib/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,8 @@
3131
Task,
3232
MaintenanceReport,
3333
MaintenanceEntry,
34+
Importer,
35+
YumImporter,
36+
FileImporter,
3437
)
3538
from ._impl.fake import FakeController

pubtools/pulplib/_impl/client/client.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ def search_repository(self, criteria=None):
278278
Each page will contain a collection of
279279
:class:`~pubtools.pulplib.Repository` objects.
280280
"""
281-
search_options = {"distributors": True}
281+
search_options = {"distributors": True, "importers": True}
282282
return self._search(
283283
Repository, "repositories", criteria=criteria, search_options=search_options
284284
)
@@ -1054,3 +1054,80 @@ def _do_sync(self, repo_id, sync_options):
10541054
return self._task_executor.submit(
10551055
self._do_request, method="POST", url=url, json=body
10561056
)
1057+
1058+
def create_repository(self, repo):
1059+
"""Create a repository with initial data provided in the
1060+
argument. Importer for repository is automatically associated
1061+
if available. If repository already exists, warning is logged.
1062+
After repository has been successfully created or if repository already exists,
1063+
it is checked if expected and current repository configuration values are
1064+
correct.
1065+
1066+
Args:
1067+
repo (:class:`~pubtools.pulplib.Repository`)
1068+
A repository object used for creation.
1069+
1070+
Returns:
1071+
Future[Repository]
1072+
A future which is resolved with a value of ``Repository`` once the
1073+
repository has been created.
1074+
1075+
.. versionadded:: 2.39.0
1076+
"""
1077+
url = os.path.join(self._url, "pulp/api/v2/repositories/")
1078+
1079+
body = repo._to_data()
1080+
repo_id = body["id"]
1081+
1082+
importer = body.pop("importers", [])
1083+
body["importer_type_id"] = importer[0]["importer_type_id"] if importer else None
1084+
body["importer_config"] = importer[0]["config"] if importer else None
1085+
1086+
def log_existing_repo(exception):
1087+
if (
1088+
getattr(exception, "response", None) is not None
1089+
and exception.response.status_code == 409
1090+
):
1091+
LOG.warning("Repository %s already exists", repo_id)
1092+
return None
1093+
1094+
raise exception
1095+
1096+
def check_repo(repo_on_server):
1097+
try:
1098+
assert (
1099+
repo_on_server == repo
1100+
), "Repo exists on server with unexpected values"
1101+
except AssertionError:
1102+
if importer:
1103+
for attr in ["type_id", "config"]:
1104+
expected = getattr(repo.importer, attr)
1105+
current = getattr(repo_on_server.importer, attr)
1106+
if expected != current:
1107+
LOG.error(
1108+
"Repository %s contains wrong importer %s\n"
1109+
"\t expected: %s\n"
1110+
"\t current: %s\n",
1111+
repo_id,
1112+
attr,
1113+
expected,
1114+
current,
1115+
)
1116+
LOG.exception(
1117+
"Repository %s exists on server and contains unexpected values",
1118+
repo_id,
1119+
)
1120+
raise
1121+
1122+
return f_return(repo_on_server)
1123+
1124+
LOG.debug("Creating repository %s", repo_id)
1125+
out = self._request_executor.submit(
1126+
self._do_request, method="POST", url=url, json=body
1127+
)
1128+
1129+
out = f_map(out, error_fn=log_existing_repo)
1130+
out = f_flat_map(out, lambda _: self.get_repository(repo_id))
1131+
out = f_flat_map(out, check_repo)
1132+
1133+
return f_proxy(out)

pubtools/pulplib/_impl/client/retry.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ def should_retry(self, attempt, future):
2929

3030
exception = future.exception()
3131
if exception and getattr(exception, "response", None) is not None:
32-
# if returned status code is 404, never retry on that
33-
if exception.response.status_code == 404:
32+
# if returned status code is 404 or 409, never retry on that
33+
if exception.response.status_code in (404, 409):
3434
return False
3535

3636
if exception and retry:

pubtools/pulplib/_impl/fake/client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,12 @@ def _do_sync(self, repo_id, sync_config): # pylint:disable = unused-argument
651651
self._state.sync_history.append(Sync(repo_f.result(), [task], sync_config))
652652

653653
return f_return([task])
654+
655+
def create_repository(self, repo):
656+
with self._state.lock:
657+
if repo.id not in [
658+
existing_repo.id for existing_repo in self._state.repositories
659+
]:
660+
self._state.repositories.append(repo)
661+
662+
return self.get_repository(repo.id)

pubtools/pulplib/_impl/model/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
FileSyncOptions,
1010
ContainerSyncOptions,
1111
YumSyncOptions,
12+
Importer,
13+
FileImporter,
14+
YumImporter,
1215
)
1316
from .unit import (
1417
Unit,

pubtools/pulplib/_impl/model/common.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,15 @@ def _delete(self, resource_type, resource_id):
234234
delete_f = client._delete_resource(resource_type, resource_id)
235235
delete_f = f_map(delete_f, self.__detach)
236236
return f_proxy(delete_f)
237+
238+
239+
def schemaless_init(cls, data):
240+
# Construct and return an instance of (attrs-using) cls from
241+
# pulp data, where data in pulp has no schema at all (and hence
242+
# every field could possibly be missing).
243+
kwargs = {}
244+
for key in [fld.name for fld in attr.fields(cls)]:
245+
if key in data:
246+
kwargs[key] = data[key]
247+
248+
return cls(**kwargs)

0 commit comments

Comments
 (0)