Skip to content

Commit c806f29

Browse files
committed
chore(helmbroker): support validate plan schema
1 parent 1bc5efb commit c806f29

3 files changed

Lines changed: 63 additions & 1 deletion

File tree

rootfs/helmbroker/broker.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
UpdateDetails, UpdateServiceSpec, DeprovisionDetails, \
1414
DeprovisionServiceSpec, LastOperation, OperationState
1515

16-
from .utils import verify_parameters, new_instance_lock
16+
from .utils import verify_parameters, new_instance_lock, verify_parameters_by_plan
1717
from .database.fetch import fetch_chart_plan
1818
from .database.query import get_instance_path, get_chart_path, get_plan_path, \
1919
get_addon_updateable, get_addon_bindable, get_addon_allow_params, \
@@ -64,6 +64,10 @@ def provision(self,
6464
os.makedirs(instance_path, exist_ok=True)
6565
chart_path, plan_path = get_chart_path(instance_id), get_plan_path(instance_id)
6666
fetch_chart_plan(details.service_id, chart_path, details.plan_id, plan_path)
67+
# verify instance-schema
68+
msg = verify_parameters_by_plan(instance_id, details.parameters)
69+
if msg:
70+
raise ErrBadRequest(msg)
6771
provision.delay(instance_id, details)
6872
return ProvisionedServiceSpec(state=ProvisionState.IS_ASYNC)
6973

@@ -146,6 +150,10 @@ def update(self,
146150
if details.plan_id is not None:
147151
chart_path, plan_path = get_chart_path(instance_id), get_plan_path(instance_id)
148152
fetch_chart_plan(details.service_id, chart_path, details.plan_id, plan_path)
153+
# verify instance-schema
154+
msg = verify_parameters_by_plan(instance_id, details.parameters)
155+
if msg:
156+
raise ErrBadRequest(msg)
149157
data = load_instance_meta(instance_id)
150158
data['last_operation']["state"] = OperationState.IN_PROGRESS.value
151159
data['last_operation']["description"] = (

rootfs/helmbroker/database/query.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ def get_plan_path(instance_id):
2222
return os.path.join(get_instance_path(instance_id), "plan")
2323

2424

25+
def get_plan_schema_path(instance_id):
26+
return os.path.join(get_instance_path(instance_id), "plan", "instance-schema.json")
27+
28+
2529
def get_hooks_path(instance_id):
2630
return os.path.join(get_plan_path(instance_id), "hooks")
2731

rootfs/helmbroker/utils.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import base64
66
import copy
77
import logging
8+
import jsonschema
89
from urllib.parse import urlparse, parse_qs
910
from contextlib import contextmanager
1011
from redis.client import Redis
@@ -168,3 +169,52 @@ def _verify_required_parameters(allow_parameters, parameters):
168169
if error:
169170
error_parameters.add(allow_parameter["name"])
170171
return error_parameters
172+
173+
174+
def verify_parameters_by_plan(instance_id, parameters):
175+
"""verify parameters allowed or not"""
176+
if not parameters:
177+
return ""
178+
# read schema file
179+
from .database.query import get_plan_schema_path
180+
schema_file = get_plan_schema_path(instance_id)
181+
try:
182+
with open(schema_file, 'r') as f:
183+
schema = json.load(f)
184+
except (FileNotFoundError, json.JSONDecodeError):
185+
return ""
186+
if not schema:
187+
return ""
188+
# get parameters
189+
if "rawValues" in parameters:
190+
params = yaml.safe_load(base64.b64decode(parameters["rawValues"]))
191+
else:
192+
params = _convert_to_nested_dict(parameters)
193+
# validate schema
194+
try:
195+
jsonschema.validate(params, schema)
196+
except jsonschema.ValidationError as e:
197+
return f"could not validate: {e.message}"
198+
return ""
199+
200+
201+
def _convert_to_nested_dict(assignments):
202+
"""
203+
{"a.b.c": "1Gi", "a.b.d": "2Gi"}
204+
->
205+
{'a': {'b': {'c': '1Gi', 'd': '2Gi'}}}
206+
"""
207+
def set_nested_value(d, keys, value):
208+
if len(keys) == 1:
209+
d[keys[0]] = value
210+
else:
211+
if keys[0] not in d:
212+
d[keys[0]] = {}
213+
set_nested_value(d[keys[0]], keys[1:], value)
214+
result = {}
215+
if isinstance(assignments, dict):
216+
# dict format: {"a.b.c": "1Gi"}
217+
for key_path, value in assignments.items():
218+
keys = key_path.split('.')
219+
set_nested_value(result, keys, value)
220+
return result

0 commit comments

Comments
 (0)