Skip to content

Commit 199985a

Browse files
committed
fixup
2 parents d793ec9 + bc87e20 commit 199985a

4 files changed

Lines changed: 138 additions & 36 deletions

File tree

rootfs/helmbroker/broker.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
import shutil
33
from typing import Union, List
44
from openbrokerapi import api
5-
from openbrokerapi.api import ServiceBroker, ErrInstanceAlreadyExists, ErrAsyncRequired, ErrInstanceDoesNotExist
5+
from openbrokerapi.api import ServiceBroker
6+
from openbrokerapi.errors import ErrInstanceAlreadyExists, ErrAsyncRequired, \
7+
ErrBindingAlreadyExists, ErrBadRequest, ErrInstanceDoesNotExist
68
from openbrokerapi.service_broker import *
79

8-
from .meta import InstanceMeta, load_instance_meta
10+
from .meta import load_instance_meta
911
from .utils import get_instance_path, get_chart_path, get_plan_path, \
1012
get_addon_path, get_addon_name
1113
from .tasks import provision, bind, deprovision
@@ -37,7 +39,7 @@ def provision(self,
3739
shutil.copy(addon_plan_path, plan_path)
3840
provision.delay(instance_id, details)
3941
return ProvisionedServiceSpec(state=ProvisionState.IS_ASYNC)
40-
42+
4143

4244
def get_binding(self,
4345
instance_id: str,
@@ -53,16 +55,16 @@ def bind(self,
5355
async_allowed: bool,
5456
**kwargs
5557
) -> Binding:
56-
57-
if not (InstanceMeta.load(instance_id) and
58-
InstanceMeta.load(instance_id)['last_operation']['state'] == 'Ready'):
59-
return Binding(state="status error: this instance is not ready")
58+
instance_meta = load_instance_meta(instance_id)
59+
if not (instance_meta and
60+
instance_meta['last_operation']['state'] == 'Ready'):
61+
raise ErrBadRequest(msg="This instance %s is not ready" % instance_id)
6062
if not async_allowed:
6163
raise ErrAsyncRequired()
6264
instance_path = get_instance_path(instance_id)
6365
if os.path.exists(f'{instance_path}/bind.yaml'):
64-
return Binding(state=BindState.IDENTICAL_ALREADY_EXISTS)
65-
chart_path, plan_path =get_chart_path(instance_id), get_plan_path(instance_id)
66+
raise ErrBindingAlreadyExists()
67+
chart_path, plan_path = get_chart_path(instance_id), get_plan_path(instance_id)
6668
addon_name = get_addon_name(details.service_id)
6769
shutil.copy(f'{plan_path}/bind.yaml', f'{chart_path}/{addon_name}/templates')
6870
bind.delay(instance_id, binding_id, details, async_allowed, **kwargs)
@@ -100,7 +102,6 @@ def deprovision(self,
100102
deprovision.delay(instance_id, details)
101103
return DeprovisionServiceSpec(state=ProvisionState.IS_ASYNC)
102104

103-
104105
def last_operation(self,
105106
instance_id: str,
106107
operation_data: Optional[str],
@@ -111,3 +112,22 @@ def last_operation(self,
111112
data["last_operation"]["state"],
112113
data["last_operation"]["description"]
113114
)
115+
116+
117+
def last_binding_operation(self,
118+
instance_id: str,
119+
binding_id: str,
120+
operation_data: Optional[str],
121+
**kwargs
122+
) -> LastOperation:
123+
"""
124+
Further readings `CF Broker API#LastOperationForBindings <https://github.com/openservicebrokerapi/servicebroker/blob/v2.14/spec.md#polling-last-operation-for-service-bindings>`_
125+
Must be implemented if `Provision`, `Update`, or `Deprovision` are async.
126+
127+
:param instance_id: Instance id provided by the platform
128+
:param binding_id: Binding id provided by the platform
129+
:param operation_data: Operation data received from async operation
130+
:param kwargs: May contain additional information, improves compatibility with upstream versions
131+
:rtype: LastOperation
132+
"""
133+
raise NotImplementedError()

rootfs/helmbroker/meta.py

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@
44
from .config import INSTANCES_PATH
55

66
INSTANCE_META_FILE = os.path.join(INSTANCES_PATH, "instance.json")
7+
BINDING_META_FILE = os.path.join(INSTANCES_PATH, "binding.yaml")
8+
79
INSTANCE_META_SCHEMA = {
8-
"type" : "object",
9-
"properties" : {
10-
"id" : {"type" : "string"},
11-
"details" : {
12-
"type" : "object",
10+
"type": "object",
11+
"properties": {
12+
"id": {"type": "string"},
13+
"details": {
14+
"type": "object",
1315
"properties": {
14-
"service_id": {"type" : "string"},
15-
"plan_id" : {"type" : "string"},
16-
"context" : {"type" : "object"},
17-
"parameters": {"type" : "object"},
16+
"service_id": {"type": "string"},
17+
"plan_id": {"type": "string"},
18+
"context": {"type": "object"},
19+
"parameters": {"type": "object"},
1820
}
1921
},
2022
"last_operation": {
21-
"type" : "object",
23+
"type": "object",
2224
"properties": {
23-
"state": {"type" : "string"},
24-
"description": {"type" : "string"}
25+
"state": {"type": "string"},
26+
"description": {"type": "string"}
2527
}
2628
}
2729
},
@@ -38,4 +40,35 @@ def load_instance_meta(file=INSTANCE_META_FILE):
3840
def dump_instance_meta(data, file=INSTANCE_META_FILE):
3941
validate(instance=data, schema=INSTANCE_META_SCHEMA)
4042
with open(file, "w") as f:
41-
json.dump(f, data)
43+
json.dump(f, data)
44+
45+
46+
BINDING_META_SCHEMA = {
47+
"type": "object",
48+
"properties": {
49+
"id": {"type": "string"},
50+
"credentials": {
51+
"type": "object",
52+
},
53+
"last_operation": {
54+
"type": "object",
55+
"properties": {
56+
"state": {"type": "string"},
57+
"description": {"type": "string"}
58+
}
59+
}
60+
}
61+
}
62+
63+
64+
def load_binding_meta(file=BINDING_META_FILE):
65+
with open(file, 'r') as f:
66+
data = json.loads(f.read())
67+
validate(instance=data, schema=INSTANCE_META_SCHEMA)
68+
return data
69+
70+
71+
def dump_binding_meta(data, file=BINDING_META_FILE):
72+
validate(instance=data, schema=INSTANCE_META_SCHEMA)
73+
with open(file, "w") as f:
74+
f.write(json.dumps(data))

rootfs/helmbroker/tasks.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
import time
3-
from .utils import command, get_plan_path, get_chart_path, get_or_create_binding_meta
3+
import yaml
4+
5+
from .utils import command, get_plan_path, get_chart_path, get_cred_value
46
from .meta import dump_instance_meta
57
from openbrokerapi.service_broker import *
68

@@ -49,6 +51,17 @@ def bind(instance_id: str,
4951
details: BindDetails,
5052
async_allowed: bool,
5153
**kwargs) -> Binding:
54+
data = {
55+
"binding_id": binding_id,
56+
"credential": {
57+
},
58+
"last_operation": {
59+
"state": OperationState.IN_PROGRESS,
60+
"description": "%s in progress at %s" % (binding_id, time.time())
61+
}
62+
}
63+
dump_instance_meta(data)
64+
5265
chart_path = get_chart_path(instance_id)
5366
values_file = os.path.join(get_plan_path(instance_id), "values.yaml")
5467
args = [
@@ -58,16 +71,29 @@ def bind(instance_id: str,
5871
"-f",
5972
values_file
6073
]
61-
status, output = command("helm", *args) # templates.yaml
74+
status, templates = command("helm", *args) # output: templates.yaml
6275
if status != 0:
63-
return Binding(state="status error: %s" % status, operation=output)
76+
data["last_operation"]["state"] = OperationState.FAILED
77+
data["last_operation"]["description"] = templates
78+
79+
credential_template = yaml.load(templates.split('bind.yaml')[1], Loader=yaml.Loader)
80+
success_flag = True
81+
for _ in credential_template['credential']:
82+
status, val = get_cred_value(details.context["namespace"], _['ValueFrom'])
83+
if status != 0:
84+
success_flag = False
85+
data[_['name']] = val
86+
if success_flag:
87+
data['last_operation'] = {
88+
'state': OperationState.SUCCEEDED,
89+
'description': OperationState.SUCCESSFUL_BOUND,
90+
}
6491
else:
65-
config = get_or_create_binding_meta(binding_id, output.split('bind.yaml')[1])
66-
return Binding(
67-
credentials=config.get("credential", None),
68-
state=ProvisionState.SUCCESSFUL_CREATED,
69-
operation=config.get("operation", None),
70-
)
92+
data['last_operation'] = {
93+
'state': OperationState.FAILED,
94+
'description': OperationState.FAILED,
95+
}
96+
dump_instance_meta(data)
7197

7298

7399
def deprovision(instance_id: str, details: DeprovisionDetails):

rootfs/helmbroker/utils.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,32 @@ def get_addon_name(service_id):
4040
return service['name']
4141

4242

43-
def get_or_create_instance_meta(instance_id):
44-
pass
43+
def get_cred_value(ns, source):
44+
if source.get('serviceRef'):
45+
return get_service_key_value(ns, source['serviceRef'])
46+
if source.get('configMapRef'):
47+
return get_config_map_key_value(ns, source['configMapRef'])
48+
if source.get('secretKeyRef'):
49+
return get_secret_key_value(ns, source['secretKeyRef'])
50+
return -1, 'invalid ValueFrom'
4551

4652

47-
def get_or_create_binding_meta(binding_id, credential):
48-
pass
53+
def get_service_key_value(ns, service_ref):
54+
args = [
55+
"get", "svc", service_ref['name'], "-n", ns, '-o', f'jsonpath="{service_ref["jsonpath"]}"',
56+
]
57+
return command("kubectl", *args)
58+
59+
60+
def get_config_map_key_value(ns, config_map_ref):
61+
args = [
62+
"get", "cm", config_map_ref['name'], "-n", ns, '-o', f'jsonpath="{config_map_ref["jsonpath"]}"',
63+
]
64+
return command("kubectl", *args)
65+
66+
67+
def get_secret_key_value(ns, secret_ref):
68+
args = [
69+
"get", "secret", secret_ref['name'], "-n", ns, '-o', f'jsonpath="{secret_ref["jsonpath"]}"',
70+
]
71+
return command("kubectl", *args)

0 commit comments

Comments
 (0)