Skip to content

Commit

Permalink
feat: added manifests boilerplate
Browse files Browse the repository at this point in the history
Signed-off-by: Mateusz Urbanek <[email protected]>
  • Loading branch information
shanduur committed Dec 2, 2024
1 parent fb1b564 commit 786f1f9
Show file tree
Hide file tree
Showing 20 changed files with 635 additions and 25 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

[license]: https://github.com/registry-operator/registry-operator/blob/main/LICENSE
[license]: https://github.com/anza-labs/scribe/blob/main/LICENSE
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.23.0
toolchain go1.23.3

require (
dario.cat/mergo v1.0.1
github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.78.2
github.com/stretchr/testify v1.10.0
k8s.io/api v0.31.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8=
github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0=
Expand Down
1 change: 1 addition & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"k8s.io/apimachinery/pkg/runtime/schema"
yaml "sigs.k8s.io/yaml/goyaml.v3"
)
Expand Down
31 changes: 29 additions & 2 deletions internal/controller/pod_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ package controller

import (
"context"
"fmt"

monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -38,9 +41,33 @@ type PodReconciler struct {

// Reconcile
func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
log := log.FromContext(ctx,
"pod", klog.KRef(req.Namespace, req.Name),
)

ok, err := r.PrometheusScope.autoDetect.PrometheusCRsAvailability()
if err != nil {
return ctrl.Result{}, err
} else if !ok {
return ctrl.Result{}, ErrPrometheusCRsNotAvailable
}

log.V(2).Info("Reconciling")

pod := &corev1.Pod{}
if err := r.Get(ctx, req.NamespacedName, pod); err != nil {
return ctrl.Result{}, fmt.Errorf("unable to get pod: %w", err)
}

// TODO: check if has monitoring enabled
// TODO: get all annotation

isMarkedToBeDeleted := pod.GetDeletionTimestamp() != nil

Check failure on line 65 in internal/controller/pod_controller.go

View workflow job for this annotation

GitHub Actions / lint

SA4006: this value of `isMarkedToBeDeleted` is never used (staticcheck)
if isMarkedToBeDeleted {

Check failure on line 66 in internal/controller/pod_controller.go

View workflow job for this annotation

GitHub Actions / lint

SA9003: empty branch (staticcheck)
// TODO: handle deletion of the adjacent resources
}

// TODO(user): your logic here
// TODO: handle creation/update of the resources

return ctrl.Result{}, nil
}
Expand Down
21 changes: 14 additions & 7 deletions internal/controller/prometheusscope.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ limitations under the License.
package controller

import (
"errors"

"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -25,10 +27,15 @@ import (
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=servicemonitors,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=monitoring.coreos.com,resources=podmonitors,verbs=get;list;watch;create;update;patch;delete

var ErrPrometheusCRsNotAvailable = errors.New("prometheus custom resources cannot be found on cluster")

const (
PrometheusScrapeAnnotation = "prometheus.io/scrape"
PrometheusPortAnnotation = "prometheus.io/port"
PrometheusPathAnnotation = "prometheus.io/path"
prometheusScrapeAnnotation = "prometheus.io/scrape"

Check failure on line 33 in internal/controller/prometheusscope.go

View workflow job for this annotation

GitHub Actions / lint

const `prometheusScrapeAnnotation` is unused (unused)
prometheusPortAnnotation = "prometheus.io/port"

Check failure on line 34 in internal/controller/prometheusscope.go

View workflow job for this annotation

GitHub Actions / lint

const `prometheusPortAnnotation` is unused (unused)
prometheusPathAnnotation = "prometheus.io/path"

Check failure on line 35 in internal/controller/prometheusscope.go

View workflow job for this annotation

GitHub Actions / lint

const `prometheusPathAnnotation` is unused (unused)

monitorsAnnotation = "scribe.anza-labs.dev/monitors"

Check failure on line 37 in internal/controller/prometheusscope.go

View workflow job for this annotation

GitHub Actions / lint

const `monitorsAnnotation` is unused (unused)
monitorsAnnotationDisabled = "disabled"

Check failure on line 38 in internal/controller/prometheusscope.go

View workflow job for this annotation

GitHub Actions / lint

const `monitorsAnnotationDisabled` is unused (unused)
)

type PrometheusScope struct {
Expand All @@ -45,17 +52,17 @@ func NewPrometheusScope(c client.Client, cfg *rest.Config) (*PrometheusScope, er
return &PrometheusScope{
Client: c,
autoDetect: autoDetect{
dcl: dcl,
DiscoveryInterface: dcl,
},
}, nil
}

type autoDetect struct {
dcl discovery.DiscoveryInterface
discovery.DiscoveryInterface
}

func (a *autoDetect) PrometheusCRsAvailability() (bool, error) {
apiList, err := a.dcl.ServerGroups()
apiList, err := a.ServerGroups()
if err != nil {
return false, err
}
Expand All @@ -66,7 +73,7 @@ func (a *autoDetect) PrometheusCRsAvailability() (bool, error) {
for i := 0; i < len(apiGroups); i++ {
if apiGroups[i].Name == "monitoring.coreos.com" {
for _, version := range apiGroups[i].Versions {
resources, err := a.dcl.ServerResourcesForGroupVersion(version.GroupVersion)
resources, err := a.ServerResourcesForGroupVersion(version.GroupVersion)
if err != nil {
return false, err
}
Expand Down
31 changes: 29 additions & 2 deletions internal/controller/service_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ package controller

import (
"context"
"fmt"

monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand All @@ -38,9 +41,33 @@ type ServiceReconciler struct {

// Reconcile
func (r *ServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
log := log.FromContext(ctx,
"service", klog.KRef(req.Namespace, req.Name),
)

ok, err := r.PrometheusScope.autoDetect.PrometheusCRsAvailability()
if err != nil {
return ctrl.Result{}, err
} else if !ok {
return ctrl.Result{}, ErrPrometheusCRsNotAvailable
}

log.V(2).Info("Reconciling")

svc := &corev1.Service{}
if err := r.Get(ctx, req.NamespacedName, svc); err != nil {
return ctrl.Result{}, fmt.Errorf("unable to get pod: %w", err)
}

// TODO: check if has monitoring enabled
// TODO: get all annotation

isMarkedToBeDeleted := svc.GetDeletionTimestamp() != nil

Check failure on line 65 in internal/controller/service_controller.go

View workflow job for this annotation

GitHub Actions / lint

SA4006: this value of `isMarkedToBeDeleted` is never used (staticcheck)
if isMarkedToBeDeleted {

Check failure on line 66 in internal/controller/service_controller.go

View workflow job for this annotation

GitHub Actions / lint

SA9003: empty branch (staticcheck)
// TODO: handle deletion of the adjacent resources
}

// TODO(user): your logic here
// TODO: handle creation/update of the resources

return ctrl.Result{}, nil
}
Expand Down
44 changes: 44 additions & 0 deletions internal/manifests/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright 2024 anza-labs contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Additional copyrights:
// Copyright The OpenTelemetry Authors

package manifests

import (
"reflect"

"sigs.k8s.io/controller-runtime/pkg/client"
)

type Builder[Params any] func(params Params) ([]client.Object, error)

type ManifestFactory[T client.Object, Params any] func(params Params) (T, error)
type K8sManifestFactory[Params any] ManifestFactory[client.Object, Params]

func Factory[T client.Object, Params any](f ManifestFactory[T, Params]) K8sManifestFactory[Params] {
return func(params Params) (client.Object, error) {
return f(params)
}
}

// ObjectIsNotNil ensures that we only create an object IFF it isn't nil,
// and it's concrete type isn't nil either. This works around the Go type system
// by using reflection to verify its concrete type isn't nil.
func ObjectIsNotNil(obj client.Object) bool {
return obj != nil && !reflect.ValueOf(obj).IsNil()
}
38 changes: 38 additions & 0 deletions internal/manifests/manifestutils/annotations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
Copyright 2024 anza-labs contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Additional copyrights:
// Copyright The OpenTelemetry Authors

package manifestutils

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

// Annotations return the annotations for the resources.
func Annotations(instance metav1.ObjectMeta, filterAnnotations []string) (map[string]string, error) {
// new map every time, so that we don't touch the instance's annotations
annotations := map[string]string{}

if nil != instance.Annotations {
for k, v := range instance.Annotations {
if !IsFilteredSet(k, filterAnnotations) {
annotations[k] = v
}
}
}

return annotations, nil
}
60 changes: 60 additions & 0 deletions internal/manifests/manifestutils/annotations_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
Copyright 2024 anza-labs contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package manifestutils

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestAnnotationsPropagateDown(t *testing.T) {
// prepare
meta := metav1.ObjectMeta{
Annotations: map[string]string{"myapp": "mycomponent"},
}

// test
annotations, err := Annotations(meta, []string{})
require.NoError(t, err)

// verify
assert.Len(t, annotations, 1)
assert.Equal(t, "mycomponent", annotations["myapp"])
}

func TestAnnotationsFilter(t *testing.T) {
meta := metav1.ObjectMeta{
Annotations: map[string]string{
"test.bar.io": "foo",
"test.io/port": "1234",
"test.io/path": "/test",
},
}

// This requires the filter to be in regex match form and not the other simpler wildcard one.
annotations, err := Annotations(meta, []string{".*\\.bar\\.io"})

// verify
require.NoError(t, err)
assert.Len(t, annotations, 2)
assert.NotContains(t, annotations, "test.bar.io")
assert.Equal(t, "1234", annotations["test.io/port"])
}
Loading

0 comments on commit 786f1f9

Please sign in to comment.