@@ -226,25 +226,42 @@ Likewise it's possible for auxiliary resources having to be created by the user,
226226the user has to provide credentials.
227227
228228To 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.
233232
234233At the moment, only `ConfigMaps` and `Secrets` are allowed related resource kinds.
235234
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.
240237
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.
248265
249266` ` ` yaml
250267apiVersion: syncagent.kcp.io/v1alpha1
@@ -277,10 +294,11 @@ spec:
277294 # there is no GVK projection for related resources
278295 kind: Secret
279296
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:
284302 # This path is evaluated in both the local and remote objects, to figure out
285303 # the local and remote names for the related object. This saves us from having
286304 # to remember mutated fields before their mutation (similar to the last-known
@@ -289,22 +307,115 @@ spec:
289307
290308 # namespace part is optional; if not configured,
291309 # Sync Agent assumes the same namespace as the owning resource
292- #
293310 # 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.
302403 # namespace:
303- # path: metadata.uid
304- # regex:
305- # replacement: kube-system
404+ # reference:
405+ # path: metadata.namespace
406+ # regex:
407+ # pattern: '...'
408+ # replacement: '...'
306409` ` `
307410
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+
308419# # Examples
309420
310421# ## Provide Certificates
0 commit comments