Skip to content

Commit 024da25

Browse files
authored
[ISV-2659] operator_name check in hosted pipeline (#401)
added a check for whether the project has a different name already reserved for given association
1 parent 1727a81 commit 024da25

File tree

3 files changed

+129
-6
lines changed

3 files changed

+129
-6
lines changed

ansible/roles/operator-pipeline/templates/openshift/tasks/reserve-operator-name.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ spec:
77
params:
88
- name: pipeline_image
99
- name: association
10-
description: The assocation that the operator belongs in, usually the isv_pid.
10+
description: The association that the operator belongs in, usually the isv_pid.
1111
- name: operator_name
1212
description: The operator name to be reserved.
1313
- name: source
@@ -46,7 +46,7 @@ spec:
4646
#! /usr/bin/env bash
4747
set -xe
4848
49-
echo "Attempting to reserve operator name for assocation $ASSOCIATION"
49+
echo "Attempting to reserve operator name for association $ASSOCIATION"
5050
5151
reserve-operator-name \
5252
--association $ASSOCIATION \

operator-pipeline-images/operatorcert/entrypoints/reserve_operator_name.py

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import argparse
22
import logging
33
import sys
4+
from typing import Any
45
from urllib.parse import urljoin
56

67
from operatorcert import pyxis
@@ -32,7 +33,49 @@ def setup_argparser() -> argparse.ArgumentParser: # pragma: no cover
3233
return parser
3334

3435

35-
def check_operator_name(args) -> None:
36+
def check_operator_name_registered_for_association(args: Any) -> None:
37+
"""
38+
Check if for given association/isv_pid operatorPackage already exist
39+
and validates that the package name match operator name requested.
40+
"""
41+
rsp = pyxis.get(
42+
urljoin(
43+
args.pyxis_url,
44+
f"v1/operators/packages?filter=association=={args.association}",
45+
)
46+
)
47+
48+
rsp.raise_for_status()
49+
50+
packages = rsp.json().get("data")
51+
52+
if packages:
53+
# there should only be 1 package for given association/isv_pid
54+
package = packages[0]
55+
if package["package_name"] != args.operator_name:
56+
LOGGER.error(
57+
f"Requested operator name {args.operator_name} "
58+
f"does not match operator name {package['package_name']} "
59+
f"already reserved for certification project."
60+
)
61+
sys.exit(1)
62+
else:
63+
LOGGER.info(
64+
f"Requested operator name {args.operator_name} match "
65+
f"with operator name already reserved."
66+
)
67+
else:
68+
LOGGER.info(
69+
f"There isn't any operator name registered for project "
70+
f"with association/isv_pid {args.association}."
71+
)
72+
73+
74+
def check_operator_name(args: Any) -> None:
75+
"""
76+
Check if operator name already exist and if yes,
77+
validates if it match with the operator name requested.
78+
"""
3679
rsp = pyxis.get(
3780
urljoin(
3881
args.pyxis_url,
@@ -63,7 +106,11 @@ def check_operator_name(args) -> None:
63106
LOGGER.info(f"Operator name {args.operator_name} is available.")
64107

65108

66-
def reserve_operator_name(args) -> None:
109+
def reserve_operator_name(args: Any) -> None:
110+
"""
111+
Reserve operator name for given combination
112+
of association and operator name
113+
"""
67114
post_data = {
68115
"association": args.association,
69116
"package_name": args.operator_name,
@@ -80,7 +127,7 @@ def reserve_operator_name(args) -> None:
80127
)
81128

82129

83-
def main() -> None: # pragma: no cover
130+
def main() -> None:
84131
parser = setup_argparser()
85132
args = parser.parse_args()
86133

@@ -89,6 +136,7 @@ def main() -> None: # pragma: no cover
89136
log_level = "DEBUG"
90137
setup_logger(level=log_level)
91138

139+
check_operator_name_registered_for_association(args)
92140
check_operator_name(args)
93141
reserve_operator_name(args)
94142

operator-pipeline-images/tests/entrypoints/test_reserve_operator_name.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,90 @@
66

77
@patch("operatorcert.entrypoints.reserve_operator_name.setup_argparser")
88
@patch("operatorcert.entrypoints.reserve_operator_name.reserve_operator_name")
9+
@patch(
10+
"operatorcert.entrypoints.reserve_operator_name.check_operator_name_registered_for_association"
11+
)
912
@patch("operatorcert.entrypoints.reserve_operator_name.check_operator_name")
1013
def test_main(
11-
mock_check: MagicMock, mock_reserve: MagicMock, mock_arg_parser: MagicMock
14+
mock_check: MagicMock,
15+
mock_check_association: MagicMock,
16+
mock_reserve: MagicMock,
17+
mock_arg_parser: MagicMock,
1218
) -> None:
1319
reserve_operator_name.main()
20+
mock_check_association.assert_called_once()
1421
mock_check.assert_called_once()
1522
mock_reserve.assert_called_once()
1623

1724

25+
@patch("sys.exit")
26+
@patch("operatorcert.entrypoints.reserve_operator_name.pyxis.get")
27+
def test_check_operator_name_registered_for_association_same_name(
28+
mock_get: MagicMock, mock_exit: MagicMock
29+
) -> None:
30+
args = MagicMock()
31+
args.pyxis_url = "http://foo.com/"
32+
args.key_path = "key.path"
33+
args.association = "ospid-123"
34+
args.operator_name = "operator-equal"
35+
36+
mock_get.status_code = 200
37+
mock_get.return_value.json.return_value = {
38+
"data": [
39+
{
40+
"association": "ospid-123",
41+
"package_name": "operator-equal",
42+
}
43+
]
44+
}
45+
46+
reserve_operator_name.check_operator_name_registered_for_association(args)
47+
mock_exit.assert_not_called()
48+
49+
50+
@patch("sys.exit")
51+
@patch("operatorcert.entrypoints.reserve_operator_name.pyxis.get")
52+
def test_check_operator_name_registered_for_association_name_different(
53+
mock_get: MagicMock, mock_exit: MagicMock
54+
) -> None:
55+
args = MagicMock()
56+
args.pyxis_url = "http://foo.com/"
57+
args.key_path = "key.path"
58+
args.association = "ospid-123"
59+
args.operator_name = "operator-x"
60+
61+
mock_get.status_code = 200
62+
mock_get.return_value.json.return_value = {
63+
"data": [
64+
{
65+
"association": "ospid-123",
66+
"package_name": "operator-y",
67+
}
68+
]
69+
}
70+
71+
reserve_operator_name.check_operator_name_registered_for_association(args)
72+
mock_exit.assert_called_once_with(1)
73+
74+
75+
@patch("sys.exit")
76+
@patch("operatorcert.entrypoints.reserve_operator_name.pyxis.get")
77+
def test_check_operator_name_registered_for_association_not_registered(
78+
mock_get: MagicMock, mock_exit: MagicMock
79+
) -> None:
80+
args = MagicMock()
81+
args.pyxis_url = "http://foo.com/"
82+
args.key_path = "key.path"
83+
args.association = "ospid-123"
84+
args.operator_name = "operator-available"
85+
86+
mock_get.return_value.status_code = 404
87+
mock_get.return_value.json.return_value = {}
88+
89+
reserve_operator_name.check_operator_name_registered_for_association(args)
90+
mock_exit.assert_not_called()
91+
92+
1893
@patch("sys.exit")
1994
@patch("operatorcert.entrypoints.reserve_operator_name.pyxis.get")
2095
def test_check_operator_name_taken(mock_get: MagicMock, mock_exit: MagicMock) -> None:

0 commit comments

Comments
 (0)