Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.5
name: publishedresources.services.syncagent.kcp.io
name: publishedresources.syncagent.kcp.io
spec:
group: services.syncagent.kcp.io
group: syncagent.kcp.io
names:
kind: PublishedResource
listKind: PublishedResourceList
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The kcp Sync Agent
# Documentation

The Sync Agent is a Kubernetes agent responsible for integrating external Kubernetes clusters.
kcp-api-syncagent is a Kubernetes agent responsible for integrating external Kubernetes clusters.
It runs on a Kubernetes cluster, is configured with credentials to a kcp instance and will then
synchronize data out of kcp (i.e. out of kcp workspaces) onto the local cluster, and vice versa.

Expand Down
14 changes: 7 additions & 7 deletions docs/publish-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ resources that need to be synced down to the service cluster.
In its simplest form (which is rarely practical) a `PublishedResource` looks like this:

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs # name can be freely chosen
Expand All @@ -57,7 +57,7 @@ The Sync Agent can be instructed to only work on a subset of resources in kcp. T
by namespace and/or label selector.

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs # name can be freely chosen
Expand Down Expand Up @@ -96,7 +96,7 @@ It is also possible to change the scope of resources, i.e. turning a namespaced
cluster-wide. This should be used carefully and might require extensive mutations.

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs # name can be freely chosen
Expand Down Expand Up @@ -138,7 +138,7 @@ the platform will create a namespace on the local cluster, with a combination of
name hashes used for the actual resource names.

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs # name can be freely chosen
Expand Down Expand Up @@ -170,7 +170,7 @@ Mutation is always done as a series of steps. Each step does exactly one thing a
be configured per step.

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs # name can be freely chosen
Expand Down Expand Up @@ -262,7 +262,7 @@ and `"jk...."` as the name on the service cluster. Once the object exists with t
originating side, the Sync Agent will begin to sync it to the other side.

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs
Expand Down Expand Up @@ -337,7 +337,7 @@ spec: {}
```

```yaml
apiVersion: services.syncagent.kcp.io/v1alpha1
apiVersion: syncagent.kcp.io/v1alpha1
kind: PublishedResource
metadata:
name: publish-certmanager-certs
Expand Down
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ module github.com/kcp-dev/api-syncagent

go 1.22.0

toolchain go1.22.5

require (
github.com/Masterminds/sprig/v3 v3.3.0
github.com/evanphx/json-patch/v5 v5.9.0
Expand Down
2 changes: 1 addition & 1 deletion hack/download-tool.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fi
mkdir -p tmp
cd tmp

echo "Downloading $BINARY version $VERSION…" >&2
echo "Downloading $BINARY version $VERSION …" >&2
curl --fail --silent -LO "$URL"
archive="$(ls)"

Expand Down
6 changes: 0 additions & 6 deletions hack/update-codegen-crds.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,6 @@ go run sigs.k8s.io/controller-tools/cmd/controller-gen \
beautify() {
_tools/yq --inplace --no-doc 'del(.metadata.creationTimestamp)' "$1"

# kcp 0.24 added support for conversions, but as long as our integration tests run on <0.24,
# we must remove any possible conversion field or else older kcp versions will not be able to
# load the generated ARS.
# TODO: Remove this hack once everything in this repository is kcp 0.24+.
_tools/yq --inplace --no-doc 'del(.spec.conversion)' "$1"

mv "$1" "$1.bak"
echo -e "# This file has been generated by hack/update-codegen-crds.sh, DO NOT EDIT.\n" > "$1"
cat "$1.bak" >> "$1"
Expand Down
4 changes: 2 additions & 2 deletions hack/update-codegen-sdk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ go run k8s.io/code-generator/cmd/applyconfiguration-gen \
--go-header-file "$BOILERPLATE_HEADER" \
--output-dir $SDK_DIR/applyconfiguration \
--output-pkg $SDK_PKG/applyconfiguration \
$APIS_PKG/services/v1alpha1
$APIS_PKG/syncagent/v1alpha1

go run k8s.io/code-generator/cmd/client-gen \
--input-base "" \
--input $APIS_PKG/services/v1alpha1 \
--input $APIS_PKG/syncagent/v1alpha1 \
--clientset-name versioned \
--go-header-file "$BOILERPLATE_HEADER" \
--output-dir $SDK_DIR/clientset \
Expand Down
10 changes: 5 additions & 5 deletions internal/controller/apiexport/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"github.com/kcp-dev/api-syncagent/internal/controllerutil"
predicateutil "github.com/kcp-dev/api-syncagent/internal/controllerutil/predicate"
"github.com/kcp-dev/api-syncagent/internal/resources/reconciling"
servicesv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/services/v1alpha1"
syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1"

kcpdevv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"

Expand Down Expand Up @@ -82,7 +82,7 @@ func Add(
}

hasARS := predicate.NewPredicateFuncs(func(object ctrlruntimeclient.Object) bool {
publishedResource, ok := object.(*servicesv1alpha1.PublishedResource)
publishedResource, ok := object.(*syncagentv1alpha1.PublishedResource)
if !ok {
return false
}
Expand All @@ -101,7 +101,7 @@ func Add(
// so there is no need here to add an additional filter.
WatchesRawSource(source.Kind(platformCluster.GetCache(), &kcpdevv1alpha1.APIExport{}, controllerutil.EnqueueConst[*kcpdevv1alpha1.APIExport]("dummy"))).
// Watch for changes to PublishedResources on the local service cluster
Watches(&servicesv1alpha1.PublishedResource{}, controllerutil.EnqueueConst[ctrlruntimeclient.Object]("dummy"), builder.WithPredicates(predicateutil.ByLabels(prFilter), hasARS)).
Watches(&syncagentv1alpha1.PublishedResource{}, controllerutil.EnqueueConst[ctrlruntimeclient.Object]("dummy"), builder.WithPredicates(predicateutil.ByLabels(prFilter), hasARS)).
Build(reconciler)
return err
}
Expand All @@ -113,15 +113,15 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (

func (r *Reconciler) reconcile(ctx context.Context) error {
// find all PublishedResources
pubResources := &servicesv1alpha1.PublishedResourceList{}
pubResources := &syncagentv1alpha1.PublishedResourceList{}
if err := r.localClient.List(ctx, pubResources, &ctrlruntimeclient.ListOptions{
LabelSelector: r.prFilter,
}); err != nil {
return fmt.Errorf("failed to list PublishedResources: %w", err)
}

// filter out those PRs that have not yet been processed into an ARS
filteredPubResources := []servicesv1alpha1.PublishedResource{}
filteredPubResources := []syncagentv1alpha1.PublishedResource{}
for i, pubResource := range pubResources.Items {
if pubResource.Status.ResourceSchemaName != "" {
filteredPubResources = append(filteredPubResources, pubResources.Items[i])
Expand Down
4 changes: 2 additions & 2 deletions internal/controller/apiexport/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"slices"

"github.com/kcp-dev/api-syncagent/internal/resources/reconciling"
"github.com/kcp-dev/api-syncagent/sdk/apis/services"
syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1"

kcpdevv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"

Expand All @@ -39,7 +39,7 @@ func (r *Reconciler) createAPIExportReconciler(availableResourceSchemas sets.Set
if existing.Annotations == nil {
existing.Annotations = map[string]string{}
}
existing.Annotations[services.AgentNameAnnotation] = agentName
existing.Annotations[syncagentv1alpha1.AgentNameAnnotation] = agentName

// we only ever add new schemas
result := known.Union(availableResourceSchemas)
Expand Down
17 changes: 8 additions & 9 deletions internal/controller/apiresourceschema/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ import (
"github.com/kcp-dev/api-syncagent/internal/controllerutil/predicate"
"github.com/kcp-dev/api-syncagent/internal/discovery"
"github.com/kcp-dev/api-syncagent/internal/projection"
"github.com/kcp-dev/api-syncagent/sdk/apis/services"
servicesv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/services/v1alpha1"
syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1"

kcpdevv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"

Expand Down Expand Up @@ -90,7 +89,7 @@ func Add(
Named(ControllerName).
WithOptions(controller.Options{MaxConcurrentReconciles: numWorkers}).
// Watch for changes to PublishedResources on the local service cluster
For(&servicesv1alpha1.PublishedResource{}, builder.WithPredicates(predicate.ByLabels(prFilter))).
For(&syncagentv1alpha1.PublishedResource{}, builder.WithPredicates(predicate.ByLabels(prFilter))).
Build(reconciler)
return err
}
Expand All @@ -99,7 +98,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
log := r.log.With("publishedresource", request)
log.Debug("Processing")

pubResource := &servicesv1alpha1.PublishedResource{}
pubResource := &syncagentv1alpha1.PublishedResource{}
if err := r.localClient.Get(ctx, request.NamespacedName, pubResource); err != nil {
return reconcile.Result{}, ctrlruntimeclient.IgnoreNotFound(err)
}
Expand All @@ -123,7 +122,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
return *result, err
}

func (r *Reconciler) reconcile(ctx context.Context, log *zap.SugaredLogger, pubResource *servicesv1alpha1.PublishedResource) (*reconcile.Result, error) {
func (r *Reconciler) reconcile(ctx context.Context, log *zap.SugaredLogger, pubResource *syncagentv1alpha1.PublishedResource) (*reconcile.Result, error) {
// find the resource that the PublishedResource is referring to
localGVK := projection.PublishedResourceSourceGVK(pubResource)

Expand Down Expand Up @@ -180,11 +179,11 @@ func (r *Reconciler) createAPIResourceSchema(ctx context.Context, log *zap.Sugar
ars := &kcpdevv1alpha1.APIResourceSchema{}
ars.Name = arsName
ars.Annotations = map[string]string{
services.SourceGenerationAnnotation: fmt.Sprintf("%d", projectedCRD.Generation),
services.AgentNameAnnotation: r.agentName,
syncagentv1alpha1.SourceGenerationAnnotation: fmt.Sprintf("%d", projectedCRD.Generation),
syncagentv1alpha1.AgentNameAnnotation: r.agentName,
}
ars.Labels = map[string]string{
services.APIGroupLabel: apigroup,
syncagentv1alpha1.APIGroupLabel: apigroup,
}
ars.Spec.Group = converted.Spec.Group
ars.Spec.Names = converted.Spec.Names
Expand All @@ -196,7 +195,7 @@ func (r *Reconciler) createAPIResourceSchema(ctx context.Context, log *zap.Sugar
return r.platformClient.Create(ctx, ars)
}

func (r *Reconciler) projectResourceNames(apiGroup string, crd *apiextensionsv1.CustomResourceDefinition, projection *servicesv1alpha1.ResourceProjection) *apiextensionsv1.CustomResourceDefinition {
func (r *Reconciler) projectResourceNames(apiGroup string, crd *apiextensionsv1.CustomResourceDefinition, projection *syncagentv1alpha1.ResourceProjection) *apiextensionsv1.CustomResourceDefinition {
result := crd.DeepCopy()
result.Spec.Group = apiGroup

Expand Down
4 changes: 2 additions & 2 deletions internal/controller/sync/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
"github.com/kcp-dev/api-syncagent/internal/mutation"
"github.com/kcp-dev/api-syncagent/internal/projection"
"github.com/kcp-dev/api-syncagent/internal/sync"
servicesv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/services/v1alpha1"
syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -59,7 +59,7 @@ func Create(
ctx context.Context,
localManager manager.Manager,
virtualWorkspaceCluster cluster.Cluster,
pubRes *servicesv1alpha1.PublishedResource,
pubRes *syncagentv1alpha1.PublishedResource,
discoveryClient *discovery.Client,
apiExportName string,
log *zap.SugaredLogger,
Expand Down
10 changes: 5 additions & 5 deletions internal/controller/syncmanager/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import (
"github.com/kcp-dev/api-syncagent/internal/controllerutil"
"github.com/kcp-dev/api-syncagent/internal/controllerutil/predicate"
"github.com/kcp-dev/api-syncagent/internal/discovery"
servicesv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/services/v1alpha1"
syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1"

kcpdevv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/apis/v1alpha1"

Expand Down Expand Up @@ -118,7 +118,7 @@ func Add(
// so there is no need here to add an additional filter.
WatchesRawSource(source.Kind(platformCluster.GetCache(), &kcpdevv1alpha1.APIExport{}, controllerutil.EnqueueConst[*kcpdevv1alpha1.APIExport]("dummy"))).
// Watch for changes to the PublishedResources
Watches(&servicesv1alpha1.PublishedResource{}, controllerutil.EnqueueConst[ctrlruntimeclient.Object]("dummy"), builder.WithPredicates(predicate.ByLabels(prFilter))).
Watches(&syncagentv1alpha1.PublishedResource{}, controllerutil.EnqueueConst[ctrlruntimeclient.Object]("dummy"), builder.WithPredicates(predicate.ByLabels(prFilter))).
Build(reconciler)
return err
}
Expand Down Expand Up @@ -169,7 +169,7 @@ func (r *Reconciler) reconcile(ctx context.Context, log *zap.SugaredLogger, apiE
}

// find all PublishedResources
pubResources := &servicesv1alpha1.PublishedResourceList{}
pubResources := &syncagentv1alpha1.PublishedResourceList{}
if err := r.localManager.GetClient().List(ctx, pubResources, &ctrlruntimeclient.ListOptions{
LabelSelector: r.prFilter,
}); err != nil {
Expand Down Expand Up @@ -220,11 +220,11 @@ func (r *Reconciler) stopVirtualWorkspaceCluster(log *zap.SugaredLogger) {
r.vwURL = ""
}

func getPublishedResourceKey(pr *servicesv1alpha1.PublishedResource) string {
func getPublishedResourceKey(pr *syncagentv1alpha1.PublishedResource) string {
return fmt.Sprintf("%s-%s", pr.UID, pr.ResourceVersion)
}

func (r *Reconciler) ensureSyncControllers(ctx context.Context, log *zap.SugaredLogger, publishedResources []servicesv1alpha1.PublishedResource) error {
func (r *Reconciler) ensureSyncControllers(ctx context.Context, log *zap.SugaredLogger, publishedResources []syncagentv1alpha1.PublishedResource) error {
currentPRWorkers := sets.New[string]()
for _, pr := range publishedResources {
currentPRWorkers.Insert(getPublishedResourceKey(&pr))
Expand Down
16 changes: 8 additions & 8 deletions internal/mutation/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ import (
"github.com/tidwall/sjson"
"go.xrstf.de/rudi"

servicesv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/services/v1alpha1"
syncagentv1alpha1 "github.com/kcp-dev/api-syncagent/sdk/apis/syncagent/v1alpha1"
)

func ApplyResourceMutations(value any, mutations []servicesv1alpha1.ResourceMutation, ctx *TemplateMutationContext) (any, error) {
func ApplyResourceMutations(value any, mutations []syncagentv1alpha1.ResourceMutation, ctx *TemplateMutationContext) (any, error) {
for _, mut := range mutations {
var err error
value, err = ApplyResourceMutation(value, mut, ctx)
Expand All @@ -45,7 +45,7 @@ func ApplyResourceMutations(value any, mutations []servicesv1alpha1.ResourceMuta
return value, nil
}

func ApplyResourceMutation(value any, mut servicesv1alpha1.ResourceMutation, ctx *TemplateMutationContext) (any, error) {
func ApplyResourceMutation(value any, mut syncagentv1alpha1.ResourceMutation, ctx *TemplateMutationContext) (any, error) {
// for Rudi scripts we can skip all the JSON encoding/decoding
if mut.Rudi != nil {
return applyResourceRudiMigration(value, *mut.Rudi, ctx)
Expand Down Expand Up @@ -73,7 +73,7 @@ func ApplyResourceMutation(value any, mut servicesv1alpha1.ResourceMutation, ctx
return result, nil
}

func applyResourceMutationToJSON(jsonData string, mut servicesv1alpha1.ResourceMutation, ctx *TemplateMutationContext) (string, error) {
func applyResourceMutationToJSON(jsonData string, mut syncagentv1alpha1.ResourceMutation, ctx *TemplateMutationContext) (string, error) {
switch {
case mut.Delete != nil:
return applyResourceDeleteMutation(jsonData, *mut.Delete)
Expand All @@ -86,7 +86,7 @@ func applyResourceMutationToJSON(jsonData string, mut servicesv1alpha1.ResourceM
}
}

func applyResourceRudiMigration(value any, mut servicesv1alpha1.ResourceRudiMutation, ctx *TemplateMutationContext) (any, error) {
func applyResourceRudiMigration(value any, mut syncagentv1alpha1.ResourceRudiMutation, ctx *TemplateMutationContext) (any, error) {
program, err := rudi.Parse("myscript", mut.Script)
if err != nil {
return nil, fmt.Errorf("invalid script: %w", err)
Expand All @@ -109,7 +109,7 @@ func applyResourceRudiMigration(value any, mut servicesv1alpha1.ResourceRudiMuta
return processed, nil
}

func applyResourceDeleteMutation(jsonData string, mut servicesv1alpha1.ResourceDeleteMutation) (string, error) {
func applyResourceDeleteMutation(jsonData string, mut syncagentv1alpha1.ResourceDeleteMutation) (string, error) {
jsonData, err := sjson.Delete(jsonData, mut.Path)
if err != nil {
return "", fmt.Errorf("failed to delete value @ %s: %w", mut.Path, err)
Expand All @@ -118,7 +118,7 @@ func applyResourceDeleteMutation(jsonData string, mut servicesv1alpha1.ResourceD
return jsonData, nil
}

func applyResourceRegexMutation(jsonData string, mut servicesv1alpha1.ResourceRegexMutation) (string, error) {
func applyResourceRegexMutation(jsonData string, mut syncagentv1alpha1.ResourceRegexMutation) (string, error) {
if mut.Pattern == "" {
return sjson.Set(jsonData, mut.Path, mut.Replacement)
}
Expand Down Expand Up @@ -155,7 +155,7 @@ type TemplateMutationContext struct {
RemoteObject map[string]any
}

func applyResourceTemplateMutation(jsonData string, mut servicesv1alpha1.ResourceTemplateMutation, ctx *TemplateMutationContext) (string, error) {
func applyResourceTemplateMutation(jsonData string, mut syncagentv1alpha1.ResourceTemplateMutation, ctx *TemplateMutationContext) (string, error) {
// get the current value
value := gjson.Get(jsonData, mut.Path)
if !value.Exists() {
Expand Down
Loading
Loading