You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[An example when a Kubernetes `ConfigMap` created based on a Kubernetes Service](#an-example-when-a-kubernetes-configmap-created-based-on-a-kubernetes-service)
10
+
-[An example of Service.ibmcloud.ibm.com](#an-example-of-serviceibmcloudibmcom)
11
+
-[getValueFrom elements](#getvaluefrom-elements)
12
+
-[Format transformers](#format-transformers)
8
13
-[Namespaces](#namespaces)
14
+
-[Deletion](#deletion)
9
15
-[Field path discovery](#field-path-discovery)
10
16
-[Limitations](#limitations)
11
-
-[Data formatting roles](#data-formatting-roles)
12
-
-[Deletion](#deletion)
13
-
-[TODO](#todo)
14
-
-[Questions](#questions)
15
17
16
18
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
17
19
18
20
# Composable Operator
19
21
20
-
Composable is an overlay operator that can wrap any resource (native Kubernetes or CRD instance) and allows it to be dynamically configurable. Any field of the underlying resource can be specified with a reference to a secret or a configmap.
22
+
Composable is an overlay operator that can wrap any resource (native Kubernetes or CRD instance) and allows it to be
23
+
dynamically configurable. Any field of the underlying resource can be specified with a reference to any field of other
24
+
Kubernetes objects.
21
25
22
26
The Composable Operator enables the complete declarative executable specification of collections of inter-dependent resources.
Here we provide several examples of Composable usage, of course its possible usage is not restricted by the provided use
47
+
cases. More other can be added later.
48
+
49
+
File with all examples can be found in [samples](./config/samples)
50
+
51
+
### An example when a Kubernetes `ConfigMap` created based on a Kubernetes Service
52
+
Let's assume that we have a Kubernetes `Service`, which is part of another deployment, but we would like to create an automatic
53
+
binding of our deployment objects with this `Service`. With help of `Composable` we can automatically create a `ConfigMap`
54
+
with a `Service` parameter(s), e.g. the port number, whose name is `http`
55
+
56
+
The `Service` yaml [file](./config/samples/myService.yaml) might looks like:
57
+
58
+
```yaml
59
+
apiVersion: v1
60
+
kind: Service
61
+
metadata:
62
+
name: myservice
63
+
namespace: default
64
+
spec:
65
+
sessionAffinity: None
66
+
type: ClusterIP
67
+
selector:
68
+
app: MyApp
69
+
ports:
70
+
- name: http
71
+
protocol: TCP
72
+
port: 80
73
+
targetPort: 9376
74
+
```
75
+
76
+
The following [file](./config/samples/compCM.yaml) contains the `Composable` definition:
77
+
78
+
```yaml
79
+
apiVersion: ibmcloud.ibm.com/v1alpha1
80
+
kind: Composable
81
+
metadata:
82
+
name: to-cm
83
+
spec:
84
+
template:
85
+
apiVersion: "v1"
86
+
kind: ConfigMap
87
+
metadata:
88
+
name: myconfigmap
89
+
data:
90
+
servicePort:
91
+
getValueFrom:
92
+
kind: Service
93
+
name: myservice
94
+
namespace: default
95
+
path: '{.spec.ports[?(@.name=="http")].port}}'
96
+
format-transformers:
97
+
- ToString
98
+
```
99
+
You can see the detail explanation of the `getValueForm` fields below, but the purpose of the object is to create a
100
+
`ConfigMap`named `myconfigmap` and set `servicePort` to be equal to the port named `http` in the `Service` object named
101
+
`myservice`in the `default` namespace.
102
+
A Composable and a created object (`myconfigmap`) will be in teh same namespace, but input objects can be in any namespaces.
103
+
104
+
### An example of Service.ibmcloud.ibm.com
105
+
106
+
Composable-operator project works tightly with 2 other related projects: (SolSA - Solution Service Architecture)[https://github.com/IBM/solsa]
107
+
and (cloud-operators)[https://github.com/IBM/cloud-operators]. The [samples](./config/samples) directory has 3 different
108
+
examples of creation/configuration of `Service.ibmcloud.ibm.com` from the `cloud-opertors` project.
109
+
110
+
Here is one of them
111
+
42
112
```yaml
43
113
apiVersion: ibmcloud.ibm.com/v1alpha1
44
114
kind: Composable
@@ -53,42 +123,14 @@ spec:
53
123
spec:
54
124
instancename: mymessagehub
55
125
service: Event Streams
56
-
plan:
57
-
getValueFrom:
58
-
# any Kubernetes or CRD Kind
59
-
kind: Service
60
-
61
-
# The discovered object name
62
-
name: myservice
63
-
64
-
# The jsonpath style path to the field
65
-
# Example: get value of nodePort from a service ports array, when the port name is "http"
66
-
path: {.spec.ports[?(@.name==“http”)].port}}
67
-
68
-
# [Optional] the discovered object's namespace, if doesn't present, the Composable object namespace will be used
69
-
# namespace: my-namespace
70
-
71
-
# [Optional] the desire object version, e.g. "v1", "v1alpha1", "v1beta1"
72
-
# version: v1
73
-
74
-
# [Optional] if present, and the destination value cannot resolved, if for example a checking object does not .
75
-
# or the field is not set, the default value will be used instead.
76
-
# defaultValue: "value"
77
-
78
-
# [Optional] format-transformers, array of the available values, which are:
79
-
# ToString - transforms interface to string
80
-
# StringToInt - transforms string to integer
81
-
# Base64ToString - decodes a base64 encoded string to a plain one
82
-
# StringToBase64 - encodes a plain string to a base 64 encoded string
83
-
# StringToFloat - transforms string to float
84
-
# ArrayToCSString - transforms arrays of objects to a comma-separated string
85
-
# StringToBool - transforms a string to boolean
86
-
# JsonToObject - transforms a JSON string to an object
87
-
# if presents, the operator will transform discovered data to the wished format
88
-
# Example: transform data from base64 encoded string to an integer
89
-
# format-transformers:
90
-
# - base64ToString
91
-
# - stringToInt
126
+
plan:
127
+
getValueFrom:
128
+
kind: Secret
129
+
name: mysecret
130
+
path: '{.data.plan}'
131
+
format-transformers:
132
+
- "Base64ToString"
133
+
92
134
```
93
135
94
136
In this example, the field `plan` of the `Service.ibmcloud` instance is specified by referring to a secret. When the composable operator is created, its controller tries to read the secret and obtains the data needed for this field. If the secret is available, it then creates the `Service.ibmcloud` resource with the proper configuration. If the secret does not exist, the Composable controller keeps re-trying until it becomes available.
@@ -108,103 +150,105 @@ spec:
108
150
getValueFrom:
109
151
kind: ConfigMap
110
152
name: myconfigmap
111
-
namespace: kube-public
112
-
version: v1
153
+
namespace: default
113
154
path: {.data.name}
114
155
spec:
115
156
instancename:
116
157
getValueFrom:
117
158
kind: ConfigMap
118
159
name: myconfigmap
160
+
namespace: default
119
161
path: {.data.name}
120
162
service: Event Streams
121
163
plan:
122
164
getValueFrom:
123
165
kind: Secret
124
166
name: mysecret
167
+
namespace: default
125
168
path: {.data.planKey}
126
169
```
127
-
128
-
In the above example, the name of the underlying `Service.ibmcloud` instance is obtained from a `configmap` and the same
170
+
In this example, the name of the underlying `Service.ibmcloud` instance is obtained from a `configmap` and the same
129
171
name is used for the field `instancename`. This allows flexibility in defining configurations, and promotes the reuse
130
172
of yamls by alleviating hard-wired information.
131
173
Moreover, it can be used to configure with data that is computed dynamically as a result of the deployment of some other
132
174
resource.
175
+
133
176
The `getValueFrom` element can point to any K8s and its extensions object. The kind of the object is defined by the`kind`
134
177
element; the object name is defined by the `name` elements, and finally, the path to the data is defined by the value of
135
178
the `path` element, which is a string with dots as a delimiter.
136
179
137
-
138
-
## Namespaces
139
-
140
-
The `getValueFrom` section can have a field for the `namespace`. In this case, the specified namespace is used
141
-
to look up the object that is being referenced. If the `namespace` field is absent then the namespace of
142
-
the Composable object itself is used instead.
143
-
144
-
The template object should be created in the same namespaces as the `Composable` object. Therefore, we recommend do not
145
-
define `namespace` in the template. If the namespace field is defined and its value does not equal to the `Composable`
146
-
object namespace, no objects will be created, and `Composable` object status will contain an errro.
147
-
148
-
## Field path discovery
149
-
150
-
We use a `jsonpath` parser from `go-client` to define path to the resolving files. Here some examples:
151
-
152
-
* `{.data.key-name}` - returns a path to the key named `key-name` from a `ConfigMap` or from a `Secret`
153
-
* `{.spec.ports[?(@.name==“http”)].port}}` - takes port value from a port named `http` from the `ports` array
154
-
155
-
### Limitations
156
-
157
-
Due to
158
-
[issue #72220](https://github.com/kubernetes/kubernetes/issues/72220), `jsonpath` doesn't support regular expressions
159
-
in json-path
160
-
161
-
## Data formatting roles
162
-
163
-
Frequently data retrieved from another object needs to be transformed to another format. `format-transformers` help to
164
-
do it. Here are the data transformation roles:
165
-
180
+
## getValueFrom elements
181
+
The `getValueFrom` element should be a single child of the parent element and can contain the following sub-fileds:
0 commit comments