Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
Merge pull request #5 from vshn/add/user-alerting
Browse files Browse the repository at this point in the history
Add/user alerting
  • Loading branch information
Kidswiss authored Apr 6, 2023
2 parents 87bca94 + 490b2b8 commit b6117d5
Show file tree
Hide file tree
Showing 17 changed files with 838 additions and 65 deletions.
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
FROM docker.io/library/alpine:3.17 as runtime

RUN \
apk add --update --no-cache \
bash \
curl \
ca-certificates \
tzdata
apk add --update --no-cache \
bash \
curl \
ca-certificates \
tzdata

ENTRYPOINT ["appcat-comp-functions"]
CMD ["--log-level", "1"]
Expand Down
157 changes: 157 additions & 0 deletions functions/vshn-postgres-func/alerting.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package vshnpostgres

import (
"context"
"fmt"

xkube "github.com/crossplane-contrib/provider-kubernetes/apis/object/v1alpha1"
"github.com/go-logr/logr"
alertmanagerv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
"github.com/vshn/appcat-comp-functions/runtime"
vshnv1 "github.com/vshn/component-appcat/apis/vshn/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/pointer"
)

// AddUserAlerting adds user alerting to the PostgreSQL instance.
func AddUserAlerting(ctx context.Context, log logr.Logger, iof *runtime.Runtime, comp *vshnv1.VSHNPostgreSQL) (*vshnv1.VSHNPostgreSQL, error) {

log.Info("Check if alerting references are set")

log.V(1).Info("Tranfsorming", "obj", iof)

err := runtime.AddToScheme(alertmanagerv1alpha1.SchemeBuilder)
if err != nil {
return comp, err
}

monitoringSpec := comp.Spec.Parameters.Monitoring

if monitoringSpec.AlertmanagerConfigRef != "" {

if monitoringSpec.AlertmanagerConfigSecretRef == "" {
log.Info("Found AlertmanagerConfigRef but no AlertmanagerConfigSecretRef")
return comp, fmt.Errorf("found AlertmanagerConfigRef but no AlertmanagerConfigSecretRef, please specify as well")
}

refName := comp.Spec.Parameters.Monitoring.AlertmanagerConfigRef
log.Info("Found an AlertmanagerConfigRef, deploying...", "refName", refName)

err := deployAlertmanagerFromRef(comp, iof)
if err != nil {
return comp, err
}

}

if monitoringSpec.AlertmanagerConfigSpecTemplate != nil {

if monitoringSpec.AlertmanagerConfigSecretRef == "" {
log.Info("Found AlertmanagerConfigTemplate but no AlertmanagerConfigSecretRef")
return comp, fmt.Errorf("found AlertmanagerConfigTemplate but no AlertmanagerConfigSecretRef, please specify as well")
}

log.Info("Found an AlertmanagerConfigTemplate, deploying...")

err := deployAlertmanagerFromTemplate(comp, iof)
if err != nil {
return comp, err
}
}

if monitoringSpec.AlertmanagerConfigSecretRef != "" {
refName := comp.Spec.Parameters.Monitoring.AlertmanagerConfigSecretRef
log.Info("Found an AlertmanagerConfigSecretRef, deploying...", "refName", refName)

err := deploySecretRef(comp, iof)
if err != nil {
return comp, err
}
}

return comp, nil
}

func deployAlertmanagerFromRef(comp *vshnv1.VSHNPostgreSQL, iof *runtime.Runtime) error {
ac := &alertmanagerv1alpha1.AlertmanagerConfig{
ObjectMeta: metav1.ObjectMeta{
Name: "postgresql-alertmanagerconfig",
Namespace: comp.Status.InstanceNamespace,
},
}

xkobj, err := runtime.AddObjectToXKube(comp.Name+"-alertmanagerconfig", ac)
if err != nil {
return err
}

xkobj.Spec.References = []xkube.Reference{
{
PatchesFrom: &xkube.PatchesFrom{
DependsOn: xkube.DependsOn{
APIVersion: "monitoring.coreos.com/v1alpha1",
Kind: "AlertmanagerConfig",
Namespace: comp.ObjectMeta.Labels["crossplane.io/claim-namespace"],
Name: comp.Spec.Parameters.Monitoring.AlertmanagerConfigRef,
},
FieldPath: pointer.String("spec"),
},
ToFieldPath: pointer.String("spec"),
},
}

err = iof.PutManagedRessource(xkobj)
if err != nil {
return err
}
return nil
}

func deployAlertmanagerFromTemplate(comp *vshnv1.VSHNPostgreSQL, iof *runtime.Runtime) error {
ac := &alertmanagerv1alpha1.AlertmanagerConfig{
ObjectMeta: metav1.ObjectMeta{
Name: comp.Spec.Parameters.Monitoring.AlertmanagerConfigSecretRef,
Namespace: comp.Status.InstanceNamespace,
},
Spec: *comp.Spec.Parameters.Monitoring.AlertmanagerConfigSpecTemplate,
}

xkobj, err := runtime.AddObjectToXKube(comp.Name+"-alertmanagerconfig", ac)
if err != nil {
return err
}

return iof.PutManagedRessource(xkobj)
}

func deploySecretRef(comp *vshnv1.VSHNPostgreSQL, iof *runtime.Runtime) error {
secret := &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "postgresql-alertmanagerconfigsecret",
Namespace: comp.Status.InstanceNamespace,
},
}
xkobj, err := runtime.AddObjectToXKube(comp.Name+"-alertmanagerconfigsecret", secret)
if err != nil {
return err
}

xkobj.ObjectMeta.Name = comp.Name + "-alertmanagerconfigsecret"
xkobj.Spec.References = []xkube.Reference{
{
PatchesFrom: &xkube.PatchesFrom{
DependsOn: xkube.DependsOn{
APIVersion: "v1",
Kind: "Secret",
Namespace: comp.ObjectMeta.Labels["crossplane.io/claim-namespace"],
Name: comp.Spec.Parameters.Monitoring.AlertmanagerConfigSecretRef,
},
FieldPath: pointer.String("data"),
},
ToFieldPath: pointer.String("data"),
},
}

return iof.PutManagedRessource(xkobj)
}
116 changes: 116 additions & 0 deletions functions/vshn-postgres-func/alerting_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package vshnpostgres

import (
"context"
"testing"

xkube "github.com/crossplane-contrib/provider-kubernetes/apis/object/v1alpha1"
"github.com/go-logr/logr"
alertmanagerv1alpha1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1alpha1"
"github.com/stretchr/testify/assert"
vshnv1 "github.com/vshn/component-appcat/apis/vshn/v1"
)

func TestAddUserAlerting(t *testing.T) {
type args struct {
expectedFuncIO string
inputFuncIO string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "GivenNoMonitoringParams_ThenExpectNoOutput",
args: args{
expectedFuncIO: "alerting/01-ThenExpectNoOutput.yaml",
inputFuncIO: "alerting/01-GivenNoMonitoringParams.yaml",
},
wantErr: false,
},
{
name: "GivenConfigRefNoSecretRef_ThenExpectError",
wantErr: true,
args: args{
expectedFuncIO: "alerting/02-ThenExpectError.yaml",
inputFuncIO: "alerting/02-GivenConfigRefNoSecretRef.yaml",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
log := logr.FromContextOrDiscard(ctx)

iof := getFunctionFromFile(t, tt.args.inputFuncIO)
comp := &vshnv1.VSHNPostgreSQL{}
inComp := getCompositeFromIO(t, iof, comp)
expIof := getFunctionFromFile(t, tt.args.expectedFuncIO)

_, err := AddUserAlerting(ctx, log, iof, inComp)

if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, expIof, iof)
}

})
}
}

func TestGivenConfigRefAndSecretThenExpectOutput(t *testing.T) {

ctx := context.Background()
log := logr.FromContextOrDiscard(ctx)

t.Run("GivenConfigRefAndSecret_ThenExpectOutput", func(t *testing.T) {

iof := getFunctionFromFile(t, "alerting/03-GivenConfigRefAndSecret.yaml")
comp := &vshnv1.VSHNPostgreSQL{}
inComp := getCompositeFromIO(t, iof, comp)

_, err := AddUserAlerting(ctx, log, iof, inComp)
assert.NoError(t, err)

resName := "psql-alertmanagerconfig"
kubeObject := &xkube.Object{}
assert.NoError(t, iof.GetManagedRessourceFromDesired(resName, kubeObject))

assert.Equal(t, comp.Labels["crossplane.io/claim-namespace"], kubeObject.Spec.References[0].PatchesFrom.Namespace)
assert.Equal(t, comp.Spec.Parameters.Monitoring.AlertmanagerConfigRef, kubeObject.Spec.References[0].PatchesFrom.Name)

alertConfig := &alertmanagerv1alpha1.AlertmanagerConfig{}
assert.NoError(t, iof.GetFromDesiredKubeObject(ctx, alertConfig, resName))
assert.Equal(t, comp.Status.InstanceNamespace, alertConfig.GetNamespace())
})

}

func TestGivenConfigTemplateAndSecretThenExpectOutput(t *testing.T) {
ctx := context.Background()
log := logr.FromContextOrDiscard(ctx)

t.Run("GivenConfigTemplateAndSecret_ThenExpectOutput", func(t *testing.T) {

iof := getFunctionFromFile(t, "alerting/04-GivenConfigTemplateAndSecret.yaml")
comp := &vshnv1.VSHNPostgreSQL{}
inComp := getCompositeFromIO(t, iof, comp)

_, err := AddUserAlerting(ctx, log, iof, inComp)
assert.NoError(t, err)

resName := "psql-alertmanagerconfig"
kubeObject := &xkube.Object{}
assert.NoError(t, iof.GetManagedRessourceFromDesired(resName, kubeObject))

assert.Empty(t, kubeObject.Spec.References)

alertConfig := &alertmanagerv1alpha1.AlertmanagerConfig{}
assert.NoError(t, iof.GetFromDesiredKubeObject(ctx, alertConfig, resName))
assert.Equal(t, comp.Status.InstanceNamespace, alertConfig.GetNamespace())
assert.Equal(t, comp.Spec.Parameters.Monitoring.AlertmanagerConfigSpecTemplate, &alertConfig.Spec)
})
}
32 changes: 32 additions & 0 deletions functions/vshn-postgres-func/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package vshnpostgres

import (
"encoding/json"
"os"
"path/filepath"
"strings"

"github.com/stretchr/testify/assert"
"github.com/vshn/appcat-comp-functions/runtime"
"sigs.k8s.io/yaml"
)

func getFunctionFromFile(t assert.TestingT, file string) *runtime.Runtime {
p, _ := filepath.Abs(".")
before, _, _ := strings.Cut(p, "/functions")
dat, err := os.ReadFile(before + "/test/transforms/vshn-postgres/" + file)
assert.NoError(t, err)

funcIO := runtime.Runtime{}
err = yaml.Unmarshal(dat, &funcIO)
assert.NoError(t, err)

return &funcIO
}

func getCompositeFromIO[T any](t assert.TestingT, io *runtime.Runtime, obj *T) *T {
err := json.Unmarshal(io.Observed.Composite.Resource.Raw, obj)
assert.NoError(t, err)

return obj
}
3 changes: 2 additions & 1 deletion functions/vshn-postgres-func/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vshnpostgres
import (
"context"
"fmt"

"github.com/crossplane/crossplane/apis/apiextensions/fn/io/v1alpha1"
"github.com/go-logr/logr"
"github.com/vshn/appcat-comp-functions/runtime"
Expand Down Expand Up @@ -43,7 +44,7 @@ func Transform(ctx context.Context, log logr.Logger, iof *runtime.Runtime, comp
log.Info("Getting connection secret from managed kubernetes object")
s := &v1.Secret{}

err := iof.GetFromKubeObject(ctx, s, connectionSecretResourceName)
err := iof.GetFromObservedKubeObject(ctx, s, connectionSecretResourceName)
if err != nil {
return nil, fmt.Errorf("cannot get connection secret object: %w", err)
}
Expand Down
Loading

0 comments on commit b6117d5

Please sign in to comment.