Skip to content

Commit e7d65e1

Browse files
committed
Add PulpException for ssl CA verification error in replication
1 parent 0d3fa50 commit e7d65e1

File tree

3 files changed

+111
-78
lines changed

3 files changed

+111
-78
lines changed

pulpcore/app/tasks/replica.py

Lines changed: 89 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import platform
33
import sys
4+
45
from tempfile import NamedTemporaryFile
56

67
from django.db.models import Min
@@ -9,6 +10,9 @@
910
from pulpcore.app.apps import pulp_plugin_configs, PulpAppConfig
1011
from pulpcore.app.models import UpstreamPulp, Task, TaskGroup
1112
from pulpcore.app.replica import ReplicaContext
13+
from pulpcore.exceptions.base import (
14+
SSLCertificateVerificationError,
15+
)
1216
from pulpcore.tasking.tasks import dispatch
1317

1418
from pulp_glue.common import __version__ as pulp_glue_version
@@ -27,84 +31,91 @@ def user_agent():
2731

2832

2933
def replicate_distributions(server_pk):
30-
server = UpstreamPulp.objects.get(pk=server_pk)
31-
32-
# Write out temporary files related to SSL
33-
ssl_files = {}
34-
for key in ["ca_cert", "client_cert", "client_key"]:
35-
if value := getattr(server, key):
36-
f = NamedTemporaryFile(dir=".")
37-
f.write(bytes(value, "utf-8"))
38-
f.flush()
39-
ssl_files[key] = f.name
40-
41-
if "ca_cert" in ssl_files:
42-
os.environ["PULP_CA_BUNDLE"] = ssl_files["ca_cert"]
43-
44-
api_kwargs = dict(
45-
base_url=server.base_url,
46-
username=server.username,
47-
password=server.password,
48-
user_agent=user_agent(),
49-
validate_certs=server.tls_validation,
50-
cert=ssl_files.get("client_cert"),
51-
key=ssl_files.get("client_key"),
52-
)
53-
54-
ctx = ReplicaContext(
55-
api_root=server.api_root,
56-
api_kwargs=api_kwargs,
57-
background_tasks=True,
58-
timeout=0,
59-
domain=server.domain,
60-
)
61-
62-
tls_settings = {
63-
"ca_cert": server.ca_cert,
64-
"tls_validation": server.tls_validation,
65-
"client_cert": server.client_cert,
66-
"client_key": server.client_key,
67-
}
68-
69-
task_group = TaskGroup.current()
70-
supported_replicators = []
71-
# Load all the available replicators
72-
for config in pulp_plugin_configs():
73-
if config.replicator_classes:
74-
for replicator_class in config.replicator_classes:
75-
req = PluginRequirement(config.label, specifier=replicator_class.required_version)
76-
if ctx.has_plugin(req):
77-
replicator = replicator_class(ctx, task_group, tls_settings, server)
78-
supported_replicators.append(replicator)
79-
80-
for replicator in supported_replicators:
81-
distros = replicator.upstream_distributions(q=server.q_select)
82-
distro_names = []
83-
for distro in distros:
84-
# Create remote
85-
remote = replicator.create_or_update_remote(upstream_distribution=distro)
86-
if not remote:
87-
# The upstream distribution is not serving any content,
88-
# let if fall through the cracks and be cleanup below.
89-
continue
90-
# Check if there is already a repository
91-
repository = replicator.create_or_update_repository(remote=remote)
92-
if not repository:
93-
# No update occured because server.policy==LABELED and there was
94-
# an already existing local repository with the same name
95-
continue
96-
97-
# Dispatch a sync task if needed
98-
if replicator.requires_syncing(distro):
99-
replicator.sync(repository, remote)
100-
101-
# Get or create a distribution
102-
replicator.create_or_update_distribution(repository, distro)
103-
104-
# Add name to the list of known distribution names
105-
distro_names.append(distro["name"])
106-
107-
replicator.remove_missing(distro_names)
34+
try:
35+
server = UpstreamPulp.objects.get(pk=server_pk)
36+
37+
# Write out temporary files related to SSL
38+
ssl_files = {}
39+
for key in ["ca_cert", "client_cert", "client_key"]:
40+
if value := getattr(server, key):
41+
f = NamedTemporaryFile(dir=".")
42+
f.write(bytes(value, "utf-8"))
43+
f.flush()
44+
ssl_files[key] = f.name
45+
46+
if "ca_cert" in ssl_files:
47+
os.environ["PULP_CA_BUNDLE"] = ssl_files["ca_cert"]
48+
49+
api_kwargs = dict(
50+
base_url=server.base_url,
51+
username=server.username,
52+
password=server.password,
53+
user_agent=user_agent(),
54+
validate_certs=server.tls_validation,
55+
cert=ssl_files.get("client_cert"),
56+
key=ssl_files.get("client_key"),
57+
)
58+
59+
ctx = ReplicaContext(
60+
api_root=server.api_root,
61+
api_kwargs=api_kwargs,
62+
background_tasks=True,
63+
timeout=0,
64+
domain=server.domain,
65+
)
66+
67+
tls_settings = {
68+
"ca_cert": server.ca_cert,
69+
"tls_validation": server.tls_validation,
70+
"client_cert": server.client_cert,
71+
"client_key": server.client_key,
72+
}
73+
74+
task_group = TaskGroup.current()
75+
supported_replicators = []
76+
# Load all the available replicators
77+
for config in pulp_plugin_configs():
78+
if config.replicator_classes:
79+
for replicator_class in config.replicator_classes:
80+
req = PluginRequirement(
81+
config.label, specifier=replicator_class.required_version
82+
)
83+
if ctx.has_plugin(req):
84+
replicator = replicator_class(ctx, task_group, tls_settings, server)
85+
supported_replicators.append(replicator)
86+
87+
for replicator in supported_replicators:
88+
distros = replicator.upstream_distributions(q=server.q_select)
89+
distro_names = []
90+
for distro in distros:
91+
# Create remote
92+
remote = replicator.create_or_update_remote(upstream_distribution=distro)
93+
if not remote:
94+
# The upstream distribution is not serving any content,
95+
# let if fall through the cracks and be cleanup below.
96+
continue
97+
# Check if there is already a repository
98+
repository = replicator.create_or_update_repository(remote=remote)
99+
if not repository:
100+
# No update occured because server.policy==LABELED and there was
101+
# an already existing local repository with the same name
102+
continue
103+
104+
# Dispatch a sync task if needed
105+
if replicator.requires_syncing(distro):
106+
replicator.sync(repository, remote)
107+
108+
# Get or create a distribution
109+
replicator.create_or_update_distribution(repository, distro)
110+
111+
# Add name to the list of known distribution names
112+
distro_names.append(distro["name"])
113+
114+
replicator.remove_missing(distro_names)
115+
116+
except Exception as e:
117+
full_name = f"{e.__class__.__module__}.{e.__class__.__name__}"
118+
raise SSLCertificateVerificationError(f"\n\nEXCEPTION FULL NAME: {full_name}\n\n")
108119

109120
dispatch(
110121
finalize_replication,

pulpcore/exceptions/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
UrlSchemeNotSupportedError,
99
ProxyAuthenticationRequiredError,
1010
RepositoryVersionDeleteError,
11+
SSLCertificateVerificationError,
1112
)
1213
from .validation import (
1314
DigestValidationError,

pulpcore/exceptions/base.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,24 @@ def __str__(self):
166166
"Cannot delete repository version. Repositories must have at least one "
167167
"repository version."
168168
)
169+
170+
171+
class SSLCertificateVerificationError(PulpException):
172+
"""
173+
Exception raised when SSL certificate verification fails due to incorrect
174+
CA certificate configuration by the user.
175+
"""
176+
177+
def __init__(self, url):
178+
"""
179+
:param url: The URL where certificate verification failed.
180+
:type url: str
181+
"""
182+
super().__init__("PLP0012")
183+
self.url = url
184+
185+
def __str__(self):
186+
return _(
187+
"SSL certificate verification failed for {url}. "
188+
"The configured CA certificate does not match the server's certificate. "
189+
).format(url=self.url)

0 commit comments

Comments
 (0)