Skip to content

Commit 9e7930d

Browse files
authored
Support install operator using iib (index image) (#222) (#225)
Support install operator using iib (index image) (#222) * Support install operator using iib (index image) * use generic catalog name * fix icsp to mirror registry.redhat.io
1 parent 5223dff commit 9e7930d

File tree

1 file changed

+136
-6
lines changed

1 file changed

+136
-6
lines changed

ocp_utilities/operators.py

Lines changed: 136 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
from pprint import pformat
22

33
from kubernetes.dynamic.exceptions import ResourceNotFoundError
4+
from ocp_resources.catalog_source import CatalogSource
45
from ocp_resources.cluster_service_version import ClusterServiceVersion
6+
from ocp_resources.image_content_source_policy import ImageContentSourcePolicy
57
from ocp_resources.installplan import InstallPlan
68
from ocp_resources.namespace import Namespace
79
from ocp_resources.operator import Operator
810
from ocp_resources.operator_group import OperatorGroup
11+
from ocp_resources.resource import ResourceEditor
912
from ocp_resources.subscription import Subscription
1013
from ocp_resources.utils import TimeoutExpiredError, TimeoutSampler
14+
from ocp_resources.validating_webhook_config import ValidatingWebhookConfiguration
1115
from simple_logger.logger import get_logger
1216

13-
from ocp_utilities.infra import cluster_resource
17+
from ocp_utilities.infra import cluster_resource, create_icsp, create_update_secret
1418

1519

1620
LOGGER = get_logger(name=__name__)
@@ -125,10 +129,12 @@ def install_operator(
125129
admin_client,
126130
name,
127131
channel,
128-
source,
132+
source=None,
129133
target_namespaces=None,
130134
timeout=TIMEOUT_30MIN,
131135
operator_namespace=None,
136+
iib_index_image=None,
137+
brew_token=None,
132138
):
133139
"""
134140
Install operator on cluster.
@@ -137,12 +143,30 @@ def install_operator(
137143
admin_client (DynamicClient): Cluster client.
138144
name (str): Name of the operator to install.
139145
channel (str): Channel to install operator from.
140-
source (str): CatalogSource name.
146+
source (str, optional): CatalogSource name.
141147
target_namespaces (list, optional): Target namespaces for the operator install process.
142148
If not provided, a namespace with te operator name will be created and used.
143149
timeout (int): Timeout in seconds to wait for operator to be ready.
144-
operator_namespace (str, optional): Operator namespace, if not provided, operator name will be used
150+
operator_namespace (str, optional): Operator namespace, if not provided, operator name will be used.
151+
iib_index_image (str, optional): iib index image url, If provided install operator from iib index image.
152+
brew_token (str, optional): Token to access iib index image registry.
145153
"""
154+
catalog_source = None
155+
operator_market_namespace = "openshift-marketplace"
156+
157+
if iib_index_image:
158+
if not brew_token:
159+
raise ValueError("brew_token must be provided for iib_index_image")
160+
161+
catalog_source = create_catalog_source_for_iib_install(
162+
name="iib-catalog",
163+
iib_index_image=iib_index_image,
164+
brew_token=brew_token,
165+
operator_market_namespace=operator_market_namespace,
166+
)
167+
else:
168+
if not source:
169+
raise ValueError("source must be provided if not using iib_index_image")
146170

147171
operator_namespace = operator_namespace or name
148172
if target_namespaces:
@@ -170,8 +194,8 @@ def install_operator(
170194
name=name,
171195
namespace=operator_namespace,
172196
channel=channel,
173-
source=source,
174-
source_namespace="openshift-marketplace",
197+
source=catalog_source.name if catalog_source else source,
198+
source_namespace=operator_market_namespace,
175199
install_plan_approval="Automatic",
176200
)
177201
subscription.deploy(wait=True)
@@ -231,3 +255,109 @@ def uninstall_operator(
231255
)
232256

233257
csv.wait_deleted(timeout=timeout)
258+
259+
260+
def create_catalog_source_for_iib_install(
261+
name, iib_index_image, brew_token, operator_market_namespace
262+
):
263+
"""
264+
Create ICSP and catalog source for given iib index image
265+
266+
Args:
267+
name (str): Name for the catalog source (used in 'name, display_name and publisher').
268+
iib_index_image (str): iib index image url.
269+
brew_token (str): Token to access iib index image registry.
270+
operator_market_namespace (str): Namespace of the marketplace.
271+
272+
Returns:
273+
CatalogSource: catalog source object.
274+
"""
275+
276+
def _manipulate_validating_webhook_configuration(_validating_webhook_configuration):
277+
_resource_name = "imagecontentsourcepolicies"
278+
_validating_webhook_configuration_dict = (
279+
_validating_webhook_configuration.instance.to_dict()
280+
)
281+
for webhook in _validating_webhook_configuration_dict["webhooks"]:
282+
for rule in webhook["rules"]:
283+
all_resources = rule["resources"]
284+
for _resources in all_resources:
285+
if _resource_name in _resources:
286+
all_resources[all_resources.index(_resource_name)] = "nonexists"
287+
break
288+
289+
return _validating_webhook_configuration_dict
290+
291+
def _icsp(_repository_digest_mirrors):
292+
if icsp.exists:
293+
ResourceEditor(
294+
patches={
295+
icsp: {
296+
"spec:": {
297+
"repository_digest_mirrors": _repository_digest_mirrors
298+
}
299+
}
300+
}
301+
).update()
302+
else:
303+
create_icsp(
304+
icsp_name="brew-registry",
305+
repository_digest_mirrors=_repository_digest_mirrors,
306+
)
307+
308+
brew_registry = "brew.registry.redhat.io"
309+
source_iib_registry = iib_index_image.split("/")[0]
310+
_iib_index_image = iib_index_image.replace(source_iib_registry, brew_registry)
311+
icsp = ImageContentSourcePolicy(name="brew-registry")
312+
validating_webhook_configuration = ValidatingWebhookConfiguration(
313+
name="sre-imagecontentpolicies-validation"
314+
)
315+
repository_digest_mirrors = [
316+
{
317+
"source": source_iib_registry,
318+
"mirrors": [brew_registry],
319+
},
320+
{
321+
"source": "registry.redhat.io",
322+
"mirrors": [brew_registry],
323+
},
324+
]
325+
326+
if validating_webhook_configuration.exists:
327+
# This is managed cluster, we need to disable ValidatingWebhookConfiguration rule
328+
# for 'imagecontentsourcepolicies'
329+
validating_webhook_configuration_dict = (
330+
_manipulate_validating_webhook_configuration(
331+
_validating_webhook_configuration=validating_webhook_configuration
332+
)
333+
)
334+
335+
with ResourceEditor(
336+
patches={
337+
validating_webhook_configuration: {
338+
"webhooks": validating_webhook_configuration_dict["webhooks"]
339+
}
340+
}
341+
):
342+
_icsp(_repository_digest_mirrors=repository_digest_mirrors)
343+
else:
344+
_icsp(_repository_digest_mirrors=repository_digest_mirrors)
345+
346+
secret_data_dict = {"auths": {brew_registry: {"auth": brew_token}}}
347+
create_update_secret(
348+
secret_data_dict=secret_data_dict,
349+
name="pull-secret", # pragma: allowlist secret
350+
namespace="openshift-config",
351+
)
352+
353+
catalog_source = CatalogSource(
354+
name=name,
355+
namespace=operator_market_namespace,
356+
display_name=name,
357+
image=_iib_index_image,
358+
publisher=name,
359+
source_type="grpc",
360+
update_strategy_registry_poll_interval="30m",
361+
)
362+
catalog_source.deploy(wait=True)
363+
return catalog_source

0 commit comments

Comments
 (0)