@@ -226,25 +226,42 @@ Likewise it's possible for auxiliary resources having to be created by the user,
226
226
the user has to provide credentials.
227
227
228
228
To handle these cases, a `PublishedResource` can define multiple "related resources". Each related
229
- resource currently represents exactly one object to synchronize between user workspace and service
230
- cluster (i.e. you cannot express "sync all Secrets"). While the main published resource sync is
231
- always workspace->service cluster, related resources can originate on either side and so either can
232
- work as the source of truth.
229
+ resource represents usually one, but can be multiple objects to synchronize between user workspace
230
+ and service cluster. While the main published resource sync is always workspace->service cluster,
231
+ related resources can originate on either side and so either can work as the source of truth.
233
232
234
233
At the moment, only `ConfigMaps` and `Secrets` are allowed related resource kinds.
235
234
236
- For each related resource, the Sync Agent needs to be told their name/namespace. This is done by
237
- selecting a field in the main resource (for a `Certificate` this would mean `spec.secretName`). Both
238
- name and namespace need to be part of the main object (or be fixed values, like a hardcoded
239
- ` kube-system` namespace).
235
+ For each related resource, the Sync Agent needs to be told how to find the object on the origin side
236
+ and where to create it on the destination side. There are multiple options that you can choose from.
240
237
241
- The path expressions for name and namespace are evaluated against the main object on either side
242
- to determine their values. So if you had a `Certificate` in your workspace with
243
- ` spec.secretName = "my-cert"` and after syncing it down, the copy on the service cluster has a
244
- rewritten/mutated `spec.secretName = "jk23h4wz47329rz2r72r92-cert"` (e.g. to prevent naming
245
- collisions), the expression `spec.secretName` would yield `"my-cert"` for the name in the workspace
246
- and `"jk...."` as the name on the service cluster. Once the object exists with that name on the
247
- originating side, the Sync Agent will begin to sync it to the other side.
238
+ By default all related objects live in the same namespace as the primary object (their owner/parent).
239
+ If the primary object is cluster scoped, admins must configure additional rules to specify what
240
+ namespace the ConfigMap/Secret shall be read from and created in.
241
+
242
+ Related resources are always optional. Even if references (see below) are used and their path
243
+ expression points to a non-existing field in the primary object (e.g. `spec.secretName` is configured,
244
+ but that field does not exist in Certificate object), this will simply be treated as "not _yet_
245
+ existing" and not create an error.
246
+
247
+ # ### References
248
+
249
+ A reference is a JSONPath-like expression that are evaluated on both sides of the synchronization.
250
+ You configure a single path expression (like `spec.secretName`) and the sync agent will evaluate it
251
+ in the original primary object (in kcp) and again in the copied primary object (on the service
252
+ cluster). Since the primary object has already been mutated, the `spec.secretName` is already
253
+ rewritten/adjusted to work on the service cluster (for example it was changed from `my-secret` to
254
+ ` jk23h4wz47329rz2r72r92-secret` on the service cluster side). By doing it this way, admins only have
255
+ to think about mutations and rewrites once (when configuring the primary object in the
256
+ PublishedResource) and the path will yield 2 ready to use values (`my-secret` and the computed value).
257
+
258
+ The value selected by the path expression must be a string (or number, but it will be coalesced into
259
+ a string) and can then be further adjusted by applying a regular expression to it.
260
+
261
+ References can only ever select 1 related object. Their upside is that they are simple to understand
262
+ and easy to use, but require a "link" in the primary object that would point to the related object.
263
+
264
+ Here's an example on how to use references to locate the related object.
248
265
249
266
` ` ` yaml
250
267
apiVersion: syncagent.kcp.io/v1alpha1
@@ -277,10 +294,11 @@ spec:
277
294
# there is no GVK projection for related resources
278
295
kind: Secret
279
296
280
- # configure where in the parent object we can find
281
- # the name/namespace of the related resource (the child)
282
- reference:
283
- name:
297
+ # configure where in the parent object we can find the child object
298
+ object:
299
+ # Object can use either reference, labelSelector or expressions. In this
300
+ # example we use references.
301
+ reference:
284
302
# This path is evaluated in both the local and remote objects, to figure out
285
303
# the local and remote names for the related object. This saves us from having
286
304
# to remember mutated fields before their mutation (similar to the last-known
@@ -289,22 +307,115 @@ spec:
289
307
290
308
# namespace part is optional; if not configured,
291
309
# Sync Agent assumes the same namespace as the owning resource
292
- #
293
310
# namespace:
294
- # path: spec.secretName
295
- # regex:
296
- # pattern: '...'
297
- # replacement: '...'
298
- #
299
- # to inject static values, select a meaningless string value
300
- # and leave the pattern empty
301
- #
311
+ # reference:
312
+ # path: spec.secretName
313
+ # regex:
314
+ # pattern: '...'
315
+ # replacement: '...'
316
+ ` ` `
317
+
318
+ # ### Label Selectors
319
+
320
+ In some cases, the primary object does not have a link to its child/children objects. In these cases,
321
+ a label selector can be used. This allows to configure the labels that any related object must have
322
+ to be included.
323
+
324
+ Notably, this allows for _multiple_ objects that are synced for a single configured related resource.
325
+ The sync agent will not prevent misconfigurations, so great care must be taken when configuring
326
+ selectors to not accidentally include too many objects.
327
+
328
+ Additionally, it is assumed that
329
+
330
+ * Primary objects synced from kcp to a service cluster will be renamed, to prevent naming collisions.
331
+ * The renamed objects on the service cluster might contain private, sensitive information that should
332
+ not be leaked into kcp workspaces.
333
+ * When there is no explicit name being requested (like by setting `spec.secretName`), it can be
334
+ assumed that the operator on the service cluster that is actually processing the primary object
335
+ will use the primary object's name (at least in parts) to construct the names of related objects,
336
+ for example a Certificate `yaddasupersecretyadda` might automatically get a Secret created named
337
+ ` yaddasupersecretyadda-secret` .
338
+
339
+ Since the name of the related object must not leak into a kcp workspace, admins who configure a
340
+ label selector also always have to provide a naming scheme for the copies of the related objects on
341
+ the destination side.
342
+
343
+ Namespaces work the same as with references, i.e. by default the same namespace as the primary object
344
+ is assumed. However you can actually also use label selectors to find the origin _namespaces_
345
+ dynamically. So you can configure two label selectors, and then agent will first use the namespace
346
+ selector to find all applicable namespaces, and then use the other label selector _in each of the
347
+ applicable namespaces_ to finally locate the related objects. How useful this is depends a lot on
348
+ how crazy the underlying operators on the service clusters are.
349
+
350
+ Here is an example on how to use label selectors :
351
+
352
+ ` ` ` yaml
353
+ apiVersion: syncagent.kcp.io/v1alpha1
354
+ kind: PublishedResource
355
+ metadata:
356
+ name: publish-certmanager-certs
357
+ spec:
358
+ resource:
359
+ kind: Certificate
360
+ apiGroup: cert-manager.io
361
+ version: v1
362
+
363
+ naming:
364
+ namespace: kube-system
365
+ name: "$remoteClusterName-$remoteNamespaceHash-$remoteNameHash"
366
+
367
+ related:
368
+ - identifier: tls-secrets
369
+
370
+ # "service" or "kcp"
371
+ origin: service
372
+
373
+ # for now, only "Secret" and "ConfigMap" are supported;
374
+ # there is no GVK projection for related resources
375
+ kind: Secret
376
+
377
+ # configure where in the parent object we can find the child object
378
+ object:
379
+ # A selector is a standard Kubernetes label selector, supporting
380
+ # matchLabels and matchExpressions.
381
+ selector:
382
+ matchLabels:
383
+ my-key: my-value
384
+ another: pair
385
+
386
+ # You also need to provide rules on how objects found by this selector
387
+ # should be named on the destination side of the sync.
388
+ # Rewrites are either using regular expressions or templated strings,
389
+ # never both.
390
+ # The rewrite config is applied to each individual found object.
391
+ rewrite:
392
+ regex:
393
+ pattern: "foo-(.+)"
394
+ replacement: "bar-\\ 1"
395
+
396
+ # or
397
+ template:
398
+ template: "{{ .Name }}-foo"
399
+
400
+ # Like with references, the namespace can (or must) be configured explicitly.
401
+ # You do not need to also use label selectors here, you can mix and match
402
+ # freely.
302
403
# namespace:
303
- # path: metadata.uid
304
- # regex:
305
- # replacement: kube-system
404
+ # reference:
405
+ # path: metadata.namespace
406
+ # regex:
407
+ # pattern: '...'
408
+ # replacement: '...'
306
409
` ` `
307
410
411
+ # ### Templates
412
+
413
+ The third option to configure how to find/create related objects are templates. These are simple
414
+ Go template strings (like `{{ .Variable }}`) that allow to easily configure static values with a
415
+ sprinkling of dynamic values.
416
+
417
+ This feature has not been fully implemented yet.
418
+
308
419
# # Examples
309
420
310
421
# ## Provide Certificates
0 commit comments