Skip to content

Commit 4266fe5

Browse files
authored
Sync change from Klutch upstream (#35)
* Update Makefile with crossplane upstream * Fix provider health check timeout preventing status patch Our confighealth reconciler performs a health check HTTP request to the anynines service broker and writes the result to the providerconfig's status field. Previously, one Golang context with a timeout was used for both the health check and the subsequent patching of providerconfig's status. However, if the health check request exceeded the timeout, the patching of the status field could never succeed. client-go's Patch() method would error with a "context deadline exceeded" error message. This commit introduces a separate sub-context for the health check request, which has an explicit timeout, while using the parent context (which does not time out) for patching the status field. * Add documentation for dynamic kubernetes clients * Add makefiles for internal pipelines * Replace native patch&transform with composite functions * Update pg e2e test with latest service plans * Update changelog * Update provider-anynines and klutch dataservices to v1.3.1 * Update Klutch-Bind to v1.3.1
1 parent 397b2b1 commit 4266fe5

59 files changed

Lines changed: 1610 additions & 1316 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
## Unreleased
44

5+
## [1.3.1] - 2025-01-14
6+
7+
### Added
8+
9+
- Added documentation for dynamic Kubernetes clients, providing guidance on usage and best practices.
10+
11+
### Changed
12+
13+
- Aligned PostgreSQL plan names with a9s-dataservices for improved consistency and integration.
14+
15+
- Adjusted health check timeouts for provider-anynines to improve reliability and reduce errors.
16+
17+
- Enhanced internal processes by updating the Makefile for optimized pipeline management.
18+
19+
- Replaced native patch and transform functionality with composite functions from Crossplane, ensuring better modularity and maintainability.
20+
521
## [1.3.0] - 2025-01-14
622

723
### Changed
@@ -34,7 +50,7 @@
3450

3551
- Crossplane Provider named `provider-anynines` for leveraging a9s Data Services.
3652
- Health checks and readinessProbe for ProviderConfigs.
37-
- Klunch-bind for cross-cluster service management.
53+
- Klutch-bind for cross-cluster service management.
3854
- Crossplane APIs for a9s Data services (provider-anynines), a8s Data Services (provider-kubernetes) and AWS s3 buckets (provider-aws-s3).
3955
- Documentation content for the Docusaurus-powered Klutchio website.
4056
- End-to-end tests for Klutch.

bind/docs/dynamic-client.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Dynamic Client
2+
3+
Klutch Bind uses client-go's `dynamic` client, a dynamic client is a kubernetes client that does not
4+
have an associated type. Klutch-bind uses it in the Konnector to sync arbitrary resources between
5+
clusters. The resources to be synced are configured at runtime by the APIs that the user has bound,
6+
so they cannot be pre-compiled.
7+
8+
Instead of working on objects of a struct, it takes and returns `map[string]interface{}`. The string
9+
key is the field name, and the interface is the value of the field. For example: `obj["spec"]` will
10+
return the spec, which will be another `map[string]interface{}`. Because the client does not have an
11+
associated type, it needs to be parameterized with the `GroupVersionKind` for operations.
12+
13+
Inside the Konnector, klutch-bind automatically configures and starts new controllers for each
14+
resource to be synchronized based on dynamic client-go clients. To learn more about how controllers
15+
are constructed using client-go you can check out the following resources:
16+
17+
- [kubernetes sample controller using
18+
client-go](https://github.com/kubernetes/sample-controller/blob/master/docs/controller-client-go.md)
19+
- [client-go dynamic](https://github.com/kubernetes/client-go/tree/master/examples/dynamic-create-update-delete-deployment)
20+
- [kubecon talk about client-go controllers](https://www.youtube.com/watch?v=_BuqPMlXfpE)

crossplane-api/Makefile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ providerconfig:
66
ifdef postgresInstanceName
77
@export PG_SERVICE_INSTANCE_NAME=$$postgresInstanceName; \
88
if [[ $$GET_BROKER_IP == "true" ]]; then \
9-
export PG_SERVICEBROKER_IP=$$(ssh aws-s1-inception ". /var/vcap/store/jumpbox/home/a9s/bosh/envs/dsf2;bosh -d $$PG_SERVICE_INSTANCE_NAME instances" | grep "broker/" | sed 's/\t/ /g' | tr -s " " | cut -d " " -f4); \
9+
if [[ $$PG_SERVICE_INSTANCE_NAME == "" ]]; then \
10+
echo "ERROR: postgresInstanceName must not be empty!"; \
11+
exit 1; \
12+
fi; \
13+
export PG_SERVICEBROKER_IP=$$(ssh aws-s1-inception ". /var/vcap/store/jumpbox/home/a9s/bosh/envs/dsf2;bosh -d $$PG_SERVICE_INSTANCE_NAME instances" --json | yq -p=json '.Tables.0.Rows.[] | select ( .instance == "broker/*") | .ips'); \
1014
export PG_SERVICEBROKER_HOST="http://$$PG_SERVICEBROKER_IP:3000"; \
11-
export PG_BACKUP_MANAGER_IP=$$(ssh aws-s1-inception ". /var/vcap/store/jumpbox/home/a9s/bosh/envs/dsf2;bosh -d $$PG_SERVICE_INSTANCE_NAME instances" | grep "backup-manager/" | sed 's/\t/ /g' | tr -s " " | cut -d " " -f4); \
15+
export PG_BACKUP_MANAGER_IP=$$(ssh aws-s1-inception ". /var/vcap/store/jumpbox/home/a9s/bosh/envs/dsf2;bosh -d $$PG_SERVICE_INSTANCE_NAME instances" --json | yq -p=json '.Tables.0.Rows.[] | select ( .instance == "backup-manager/*") | .ips'); \
1216
export PG_BACKUP_MANAGER_HOST="http://$$PG_BACKUP_MANAGER_IP:3000"; \
1317
echo "Backup Manager IP: $$PG_BACKUP_MANAGER_IP"; \
1418
echo "Service Broker IP: $$PG_SERVICEBROKER_IP"; \

crossplane-api/README.md

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ To install the configuration package (containing definitions and compositions),
285285
1. Install the package via crossplane:
286286
287287
```bash
288-
crossplane xpkg install configuration public.ecr.aws/w5n9a2g2/klutch/dataservices:v1.3.0
288+
crossplane xpkg install configuration public.ecr.aws/w5n9a2g2/klutch/dataservices:v1.3.1
289289
```
290290
291291
2. Install files directly:
@@ -308,6 +308,21 @@ Crossplane won't be able to manage RBAC dynamically. As a result, Compositions
308308
will not be able to configure the provider-anynines managed resources due to
309309
authorization issues.
310310
311+
### Install Crossplane Functions
312+
313+
Additionally, we install composition functions. Composition functions (or simply “functions”) are Crossplane extensions that template Crossplane resources. Crossplane uses these functions to determine which resources to create when a composite resource (XR) is created. To verify that the composition functions are correctly installed, use the following command:
314+
315+
```bash
316+
kubectl get function
317+
```
318+
319+
Expected output:
320+
321+
```text
322+
NAME INSTALLED HEALTHY PACKAGE AGE
323+
function-patch-and-transform True True xpkg.upbound.io/crossplane-contrib/function-patch-and-transform:v0.1.4
324+
```
325+
311326
#### Install ProviderConfig for provider-anynines
312327
313328
To configure the provider, based on your development environment, make sure to
@@ -394,10 +409,10 @@ to refer to a valid service and plan.
394409
| postgresql-single-nano | 1 | 3Gi | 2 | 1 Gi |
395410
| postgresql-single-small | 1 | 10Gi | 2 | 2 Gi |
396411
| postgresql-single-medium | 1 | 50Gi | 2 | 4 Gi |
397-
| postgresql-single-large | 1 | 200Gi | 4 | 16 Gi |
398-
| postgresql-cluster-small | 3 | 10Gi | 2 | 2 Gi |
399-
| postgresql-cluster-medium | 3 | 50Gi | 2 | 4 Gi |
400-
| postgresql-cluster-large | 3 | 200Gi | 4 | 16 Gi |
412+
| postgresql-single-big | 1 | 200Gi | 4 | 16 Gi |
413+
| postgresql-replicas-small | 3 | 10Gi | 2 | 2 Gi |
414+
| postgresql-replicas-medium | 3 | 50Gi | 2 | 4 Gi |
415+
| postgresql-replicas-big | 3 | 200Gi | 4 | 16 Gi |
401416
402417
```bash
403418
kubectl apply -f ./crossplane-api/examples/a8s/postgresql-claim.yaml
@@ -560,23 +575,23 @@ field in [definition.yaml](https://github.com/anynines/klutchio/blob/main/crossp
560575
Within this field you can see a list of supported Plans:
561576

562577
```yaml
563-
plans: &pgPlans ["postgresql-cluster-small",
564-
"postgresql-cluster-medium", "postgresql-cluster-large",
578+
plans: &pgPlans ["postgresql-replicas-small",
579+
"postgresql-replicas-medium", "postgresql-replicas-big",
565580
"postgresql-single-nano","postgresql-single-small",
566-
"postgresql-single-medium", "postgresql-single-large"]
581+
"postgresql-single-medium", "postgresql-single-big"]
567582
```
568583

569584
3. Update the "plans" list with the new Plan to be supported.
570585

571-
For example, suppose the new plan "postgresql-single-extralarge" is
586+
For example, suppose the new plan "postgresql-single-huge" is
572587
introduced, so the list will be updated to:
573588

574589
```yaml
575-
plans: &pgPlans ["postgresql-cluster-small",
576-
"postgresql-cluster-medium", "postgresql-cluster-large",
590+
plans: &pgPlans ["postgresql-replicas-small",
591+
"postgresql-replicas-medium", "postgresql-replicas-big",
577592
"postgresql-single-nano","postgresql-single-small",
578-
"postgresql-single-medium", "postgresql-single-large",
579-
"postgresql-single-extralarge"]
593+
"postgresql-single-medium", "postgresql-single-big",
594+
"postgresql-single-huge"]
580595
```
581596

582597
4. Update the validation rules.
@@ -586,7 +601,7 @@ Within this field you can see a list of supported Plans:
586601
[definition.yaml](https://github.com/anynines/klutchio/blob/main/crossplane-api/api/common/postgresql_definition.yaml#L30)
587602
file under the x-kubernetes-validations.rule field.
588603

589-
Continuing the example with the "postgresql-single-extralarge", the
604+
Continuing the example with the "postgresql-single-huge", the
590605
validation in this case should be updated with the following rules that
591606
prohibit the transition from extralarge to smaller dataservice instances.
592607

@@ -600,21 +615,21 @@ Within this field you can see a list of supported Plans:
600615
field in the [composition file](https://github.com/anynines/klutchio/blob/main/crossplane-api/api/a8s/postgresql/composition.yaml)
601616
should also be updated.
602617

603-
For the "postgresql-single-extralarge" example, we could add something
618+
For the "postgresql-single-huge" example, we could add something
604619
similar to:
605620

606621
```yaml
607-
volumeSizeExtraLarge: &volumeSizeExtraLarge "1000Gi"
608-
CPUExtraLarge: &CPUExtraLarge "8"
609-
MemoryExtraLarge: &MemoryExtraLarge "32Gi"
622+
volumeSizeHuge: &volumeSizeHuge "1000Gi"
623+
CPUHuge: &CPUHuge "8"
624+
MemoryHuge: &MemoryHuge "32Gi"
610625
```
611626

612627
6. Finally, the [maps](https://github.com/anynines/klutchio/blob/main/crossplane-api/api/a8s/postgresql/composition.yaml#L53)
613628
used for patching the disk, cpu and memory resources in the
614629
[composition file](https://github.com/anynines/klutchio/blob/main/crossplane-api/api/a8s/postgresql/composition.yaml)
615630
should also be updated.
616631

617-
For our favorite "postgresql-single-extralarge" example this could mean
632+
For our favorite "postgresql-single-huge" example this could mean
618633
adding to the maps something like:
619634

620635
```yaml
@@ -624,26 +639,26 @@ Within this field you can see a list of supported Plans:
624639
nano: *volumeSizeNano
625640
small: *volumeSizeSmall
626641
medium: *volumeSizeMedium
627-
large: *volumeSizeLarge
628-
extralarge: *volumeSizeExtraLarge
642+
big: *volumeSizeLarge
643+
huge: *volumeSizeHuge
629644
630645
...
631646
- type: map
632647
map:
633648
nano: *CPUNano
634649
small: *CPUSmall
635650
medium: *CPUMedium
636-
large: *CPULarge
637-
extralarge: *CPUExtraLarge
651+
big: *CPULarge
652+
huge: *CPUHuge
638653
639654
...
640655
- type: map
641656
map:
642657
nano: *MemoryNano
643658
small: *MemorySmall
644659
medium: *MemoryMedium
645-
large: *MemoryLarge
646-
extralarge: *MemoryExtraLarge
660+
big: *MemoryLarge
661+
huge: *MemoryHuge
647662
...
648663
```
649664

crossplane-api/api/a8s/backup/composition.yaml

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,60 @@ spec:
66
compositeTypeRef:
77
apiVersion: anynines.com/v1
88
kind: XBackup
9-
resources:
10-
- name: a8s-backup
11-
base:
12-
apiVersion: kubernetes.crossplane.io/v1alpha1
13-
kind: Object
14-
spec:
15-
forProvider:
16-
manifest:
17-
apiVersion: backups.anynines.com/v1beta3
18-
kind: Backup
19-
providerConfigRef:
20-
name: kubernetes-provider
21-
patches:
22-
- fromFieldPath: metadata.labels[crossplane.io/claim-namespace]
23-
toFieldPath: spec.forProvider.manifest.metadata.namespace
24-
- fromFieldPath: metadata.labels[crossplane.io/claim-name]
25-
toFieldPath: spec.forProvider.manifest.metadata.name
26-
- fromFieldPath: spec.serviceInstanceType
27-
toFieldPath: spec.forProvider.manifest.spec.serviceInstance.apiGroup
28-
transforms:
29-
- type: map
30-
map:
31-
postgresql: postgresql.anynines.com
32-
- fromFieldPath: spec.serviceInstanceType
33-
toFieldPath: spec.forProvider.manifest.spec.serviceInstance.kind
34-
transforms:
35-
- type: map
36-
map:
37-
postgresql: PostgreSQL
38-
- fromFieldPath: spec.instanceRef
39-
toFieldPath: spec.forProvider.manifest.spec.serviceInstance.name
40-
- type: ToCompositeFieldPath
41-
fromFieldPath: status.atProvider.manifest.status.backupID
42-
toFieldPath: status.managed.backupID
43-
- type: ToCompositeFieldPath
44-
fromFieldPath: status.atProvider.manifest.status.conditions
45-
toFieldPath: status.managed.conditions
46-
- type: ToCompositeFieldPath
47-
fromFieldPath: status.atProvider.manifest.status.lastObservationTime
48-
toFieldPath: status.managed.lastObservationTime
49-
- type: ToCompositeFieldPath
50-
fromFieldPath: status.atProvider.manifest.status.podUsedNamespacedName
51-
toFieldPath: status.managed.podUsedNamespacedName
52-
- type: ToCompositeFieldPath
53-
fromFieldPath: status.atProvider.manifest.status.podUsedUID
54-
toFieldPath: status.managed.podUsedUID
55-
- type: ToCompositeFieldPath
56-
fromFieldPath: status.atProvider.manifest.status.retries
57-
toFieldPath: status.managed.retries
58-
9+
mode: Pipeline
10+
pipeline:
11+
- step: patch-and-transform
12+
functionRef:
13+
name: function-patch-and-transform
14+
input:
15+
apiVersion: pt.fn.crossplane.io/v1beta1
16+
kind: Resources
17+
resources:
18+
- name: a8s-backup
19+
base:
20+
apiVersion: kubernetes.crossplane.io/v1alpha1
21+
kind: Object
22+
spec:
23+
forProvider:
24+
manifest:
25+
apiVersion: backups.anynines.com/v1beta3
26+
kind: Backup
27+
providerConfigRef:
28+
name: kubernetes-provider
29+
patches:
30+
- fromFieldPath: metadata.labels[crossplane.io/claim-namespace]
31+
toFieldPath: spec.forProvider.manifest.metadata.namespace
32+
- fromFieldPath: metadata.labels[crossplane.io/claim-name]
33+
toFieldPath: spec.forProvider.manifest.metadata.name
34+
- fromFieldPath: spec.serviceInstanceType
35+
toFieldPath: spec.forProvider.manifest.spec.serviceInstance.apiGroup
36+
transforms:
37+
- type: map
38+
map:
39+
postgresql: postgresql.anynines.com
40+
- fromFieldPath: spec.serviceInstanceType
41+
toFieldPath: spec.forProvider.manifest.spec.serviceInstance.kind
42+
transforms:
43+
- type: map
44+
map:
45+
postgresql: PostgreSQL
46+
- fromFieldPath: spec.instanceRef
47+
toFieldPath: spec.forProvider.manifest.spec.serviceInstance.name
48+
- type: ToCompositeFieldPath
49+
fromFieldPath: status.atProvider.manifest.status.backupID
50+
toFieldPath: status.managed.backupID
51+
- type: ToCompositeFieldPath
52+
fromFieldPath: status.atProvider.manifest.status.conditions
53+
toFieldPath: status.managed.conditions
54+
- type: ToCompositeFieldPath
55+
fromFieldPath: status.atProvider.manifest.status.lastObservationTime
56+
toFieldPath: status.managed.lastObservationTime
57+
- type: ToCompositeFieldPath
58+
fromFieldPath: status.atProvider.manifest.status.podUsedNamespacedName
59+
toFieldPath: status.managed.podUsedNamespacedName
60+
- type: ToCompositeFieldPath
61+
fromFieldPath: status.atProvider.manifest.status.podUsedUID
62+
toFieldPath: status.managed.podUsedUID
63+
- type: ToCompositeFieldPath
64+
fromFieldPath: status.atProvider.manifest.status.retries
65+
toFieldPath: status.managed.retries

0 commit comments

Comments
 (0)