Skip to content

Commit

Permalink
Merge pull request #237 from vshn/add/providerconfig_management
Browse files Browse the repository at this point in the history
Add providerConfig management
  • Loading branch information
Kidswiss authored Oct 2, 2024
2 parents 85930ea + b45fc37 commit 29089fe
Show file tree
Hide file tree
Showing 11 changed files with 290 additions and 13 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,10 @@ install-proxy:
kubectl apply -f hack/functionproxy

.PHONY: render-diff
DEBUG=""
render-diff: export IMG_TAG=$(shell git rev-parse --abbrev-ref HEAD | sed 's/\//_/g')
render-diff: ## Render diff between the cluster in KUBECONF and the local branch
# We check if the image is pullable, if so we pull it, otherwise we build the image
# this will speed up the compare in CI/CD environments.
if ! docker pull $(IMG); then $(MAKE) docker-build-branchtag; fi
hack/diff/compare.sh
hack/diff/compare.sh $(DEBUG)
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ This will:
* Run `crank` again with the state already downloaded, to avoid any unintended diffs
* Use `dyff` to generate the diffs between both results

### Generate diff against live version with debugger

If you want to print the diff while using the debugger you can simply do this:

* Start the local debugging session as described
* Run `make render-diff -e DEBUG=Development`

NOTE: `crank render` has a 60s timeout, so you might run into it, if your debugging takes longer

# Run API Server locally
To run the API server on your local machine you need to register the IDE running instance with kind cluster.
This can be achieved with the following guide.
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
* xref:explanations/disable-billing.adoc[]
* xref:explanations/webhook-protection.adoc[]
* xref:explanations/ordered-deletion.adoc[]
* xref:explanations/providerconfig-management.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
= ProviderConfig Management

AppCat is able to inject a given `ProviderConfig` reference into all managed resources.

That can be controlled by setting the `appcat.vshn.io/provider-config` label on any given claim or composite. The value of this label will be injected as the `ProviderConfig` name.

There are managed resources that should have the `ProviderConfig` overwritten. In such cases it's possible to deploy them with the `appcat.vshn.io/ignore-provider-config` and then no overwrite will happen.

The `ProviderConfig` objects have to be provisioned beforehand, via `component-appcat` for example.

If no labels are given, AppCat will use the hardcoded default `ProviderConfigs` for each provider. These also have to be provided by external means like `component-appcat`.
14 changes: 9 additions & 5 deletions hack/diff/compare.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

set -e

debug=$1

[ -z "${KUBECONFIG}" ] && echo "Please export KUBECONFIG" && exit 1

# get the state and all objects from each composite
Expand All @@ -14,10 +16,11 @@ function get_state() {

mkdir -p "$dir_name"

while read -r res_type res_name
while read -r res_type res_name api_version
do
kubectl get "$res_type" "$res_name" -oyaml > "$dir_name/$res_type-$res_name.yaml"
done <<< "$(kubectl get "$type" "$name" -oyaml | yq -r '.spec.resourceRefs | .[] | .kind + " " + .name')"
group=$(echo "$api_version" | cut -d "/" -f1)
kubectl get "$res_type"."$group" "$res_name" -oyaml > "$dir_name/$res_type-$res_name.yaml"
done <<< "$(kubectl get "$type" "$name" -oyaml | yq -r '.spec.resourceRefs | .[] | .kind + " " + .name + " " + .apiVersion')"

}

Expand Down Expand Up @@ -67,6 +70,7 @@ function get_pnt_func_version() {
function template_func_file() {
export PNT_VERSION=$1
export APPCAT_VERSION=$2
export DEBUG=$3
cat "$(dirname "$0")/function.yaml.tmpl" | envsubst > "$(dirname "$0")/function.yaml"
}
Expand Down Expand Up @@ -132,12 +136,12 @@ function clean() {
clean
trap clean EXIT
template_func_file "$(get_pnt_func_version)" "$(get_running_func_version)"
template_func_file "$(get_pnt_func_version)" "$(get_running_func_version)" ""
echo "Render live manifests"
first_diff
template_func_file "$(get_pnt_func_version)" "$(git rev-parse --abbrev-ref HEAD | sed 's/\//_/g')"
template_func_file "$(get_pnt_func_version)" "$(git rev-parse --abbrev-ref HEAD | sed 's/\//_/g')" "$debug"
echo "Render against branch"
second_diff
Expand Down
1 change: 1 addition & 0 deletions hack/diff/function.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ metadata:
name: function-appcat
annotations:
render.crossplane.io/runtime-docker-cleanup: Stop
render.crossplane.io/runtime: $DEBUG
spec:
package: ghcr.io/vshn/appcat:$APPCAT_VERSION
---
Expand Down
3 changes: 3 additions & 0 deletions pkg/comp-functions/functions/common/backup/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ func createObjectBucket(ctx context.Context, comp common.InfoGetter, svc *runtim
ob := &appcatv1.XObjectBucket{
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName() + "-backup",
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: appcatv1.XObjectBucketSpec{
Parameters: appcatv1.ObjectBucketParameters{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ func createObjectBucket(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime
xObjectBucket := &appcatv1.XObjectBucket{
ObjectMeta: metav1.ObjectMeta{
Name: comp.GetName(),
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: appcatv1.XObjectBucketSpec{
Parameters: appcatv1.ObjectBucketParameters{
Expand Down
9 changes: 9 additions & 0 deletions pkg/comp-functions/functions/vshnpostgres/user_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ func addUser(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, username
Annotations: map[string]string{
"crossplane.io/external-name": username,
},
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: pgv1alpha1.RoleSpec{
ForProvider: pgv1alpha1.RoleParameters{
Expand Down Expand Up @@ -209,6 +212,9 @@ func addDatabase(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, name
Annotations: map[string]string{
"crossplane.io/external-name": name,
},
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: pgv1alpha1.DatabaseSpec{
ForProvider: pgv1alpha1.DatabaseParameters{},
Expand Down Expand Up @@ -241,6 +247,9 @@ func addGrants(comp *vshnv1.VSHNPostgreSQL, svc *runtime.ServiceRuntime, usernam
grant := &pgv1alpha1.Grant{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s-%s-grants", comp.GetName(), username, dbname),
Labels: map[string]string{
runtime.ProviderConfigIgnoreLabel: "true",
},
},
Spec: pgv1alpha1.GrantSpec{
ForProvider: pgv1alpha1.GrantParameters{
Expand Down
114 changes: 107 additions & 7 deletions pkg/comp-functions/runtime/function_mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,14 @@ var (
)

const (
OwnerKindAnnotation = "appcat.vshn.io/ownerkind"
OwnerVersionAnnotation = "appcat.vshn.io/ownerapiversion"
OwnerGroupAnnotation = "appcat.vshn.io/ownergroup"
ProtectedByAnnotation = "appcat.vshn.io/protectedby"
ProtectsAnnotation = "appcat.vshn.io/protects"
EventForwardAnnotation = "appcat.vshn.io/forward-events-to"
OwnerKindAnnotation = "appcat.vshn.io/ownerkind"
OwnerVersionAnnotation = "appcat.vshn.io/ownerapiversion"
OwnerGroupAnnotation = "appcat.vshn.io/ownergroup"
ProtectedByAnnotation = "appcat.vshn.io/protectedby"
ProtectsAnnotation = "appcat.vshn.io/protects"
EventForwardAnnotation = "appcat.vshn.io/forward-events-to"
providerConfigLabel = "appcat.vshn.io/provider-config"
ProviderConfigIgnoreLabel = "appcat.vshn.io/ignore-provider-config"
)

// Step describes a single change within a service.
Expand Down Expand Up @@ -359,6 +361,11 @@ func (s *ServiceRuntime) GetResponse() (*fnv1beta1.RunFunctionResponse, error) {
return nil, err
}

err = s.setProviderConfigs()
if err != nil {
return nil, err
}

err = response.SetDesiredComposedResources(resp, s.desiredResources)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1104,6 +1111,14 @@ func (s *ServiceRuntime) UsageOfBy(of, by string) error {
ofAPIVersion, ofKind := ofUnstructured.GetObjectKind().GroupVersionKind().ToAPIVersionAndKind()
byAPIVersion, byKind := byUnstructured.GetObjectKind().GroupVersionKind().ToAPIVersionAndKind()

removed, err := s.unwrapUsage(name)
if err != nil {
return fmt.Errorf("cannot remove kube object wrapper from uage: %w", err)
}
if !removed {
return nil
}

usage := &xpapi.Usage{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Expand All @@ -1127,7 +1142,60 @@ func (s *ServiceRuntime) UsageOfBy(of, by string) error {
},
}

return s.SetDesiredKubeObject(usage, name)
composedRes, err := composed.From(usage)
if err != nil {
return fmt.Errorf("cannot convert usage object to managed resource: %w", err)
}

s.desiredResources[resource.Name(name)] = &resource.DesiredComposed{Resource: composedRes}

return nil
}

// unwrapUsage will check if the usage is wrapped into an object.
// It will set the wrapping obect to only observe it. Then on the next reconcile
// after it ensures that the right management policy is set, it will not add it
// to the desired state again. And finally on the third reconcile it will
// return true to indicate that it got removed properly. Allowing Crossplane
// to adopt the Usage objects without wrapping in a kube object.
func (s *ServiceRuntime) unwrapUsage(name string) (bool, error) {
usage := &xkube.Object{}
err := s.GetObservedComposedResource(usage, name)
if err != nil {
if err == ErrNotFound {
return true, nil
}
return false, err
}

resources, err := request.GetObservedComposedResources(s.req)
if err != nil {
return false, err
}
res := resources[resource.Name(name)]
if res.Resource.GetKind() != "Object" {
return true, nil
}

// we need to clean the objectmeta, or Crossplane will struggle with adding
// it to the `resourceRefs` array.
usage.ObjectMeta = metav1.ObjectMeta{
Name: usage.GetName(),
Annotations: usage.Annotations,
Labels: usage.Labels,
OwnerReferences: usage.OwnerReferences,
}

if len(usage.Spec.ManagementPolicies) == 0 || usage.Spec.ManagementPolicies[0] != xpv1.ManagementActionObserve {
usage.Spec.ManagementPolicies = xpv1.ManagementPolicies{
xpv1.ManagementActionObserve,
}
err := s.SetDesiredComposedResourceWithName(usage, name)
if err != nil {
return false, err
}
}
return false, nil
}

func (s *ServiceRuntime) addUsages() error {
Expand Down Expand Up @@ -1222,3 +1290,35 @@ func (s *ServiceRuntime) getCleanGVK() schema.GroupVersionKind {
Kind: kind,
}
}

// setProviderConfigs loops over all desired objects and adds the providerConfigs
// according to the annotations on the claim/composite.
func (s *ServiceRuntime) setProviderConfigs() error {
if val, exists := s.observedComposite.GetLabels()[providerConfigLabel]; !exists || val == "" || val == "local" {
return nil
}

configName := s.observedComposite.GetLabels()[providerConfigLabel]

for i := range s.desiredResources {
if _, exists := s.desiredResources[i].Resource.GetLabels()[ProviderConfigIgnoreLabel]; exists {
continue
}
// we set the providerConfig Ref
err := s.desiredResources[i].Resource.SetString("spec.providerConfigRef.name", configName)
if err != nil {
return fmt.Errorf("cannot set providerConfig for %s: %w", s.desiredResources[i].Resource.GetName(), err)
}

// We also propagate the label, so if the resource is a composite, then
// it will automagically also set the right providerConfigs.
labels := s.desiredResources[i].Resource.GetLabels()
if labels == nil {
labels = map[string]string{}
}
labels[providerConfigLabel] = configName
s.desiredResources[i].Resource.SetLabels(labels)
}

return nil
}
Loading

0 comments on commit 29089fe

Please sign in to comment.