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