Skip to content

Commit

Permalink
Added support for ServiceMonitors
Browse files Browse the repository at this point in the history
Signed-off-by: Juraci Paixão Kröhling <[email protected]>
  • Loading branch information
jpkrohling committed Oct 21, 2019
1 parent 1f41d1e commit e3c6e1e
Show file tree
Hide file tree
Showing 23 changed files with 496 additions and 90 deletions.
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ clean:

.PHONY: crd
crd:
@kubectl create -f deploy/crds/opentelemetry_v1alpha1_opentelemetrycollector_crd.yaml 2>&1 | grep -v "already exists" || true
@kubectl create -f deploy/crds/opentelemetry.io_opentelemetrycollectors_crd.yaml 2>&1 | grep -v "already exists" || true

.PHONY: generate
generate:
Expand All @@ -94,3 +94,8 @@ ci: install-tools ensure-generate-is-noop all
install-tools:
@curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b ${GOPATH}/bin 2.0.0
@go install golang.org/x/tools/cmd/goimports

.PHONY: install-prometheus-operator
install-prometheus-operator:
@echo Installing Prometheus Operator bundle
@kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/master/bundle.yaml
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ At this point, it has [OpenTelemetry Collector](https://github.com/open-telemetr

To install the operator, run:
```
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/crds/opentelemetry_v1alpha1_opentelemetrycollector_crd.yaml
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/crds/opentelemetry.io_opentelemetrycollectors_crd.yaml
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/service_account.yaml
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/role.yaml
kubectl create -f https://raw.githubusercontent.com/jpkrohling/opentelemetry-operator/master/deploy/role_binding.yaml
Expand Down Expand Up @@ -54,6 +54,27 @@ At this point, the Operator does *not* validate the contents of the configuratio

The `CustomResource` for the `OpenTelemetryCollector` exposes a property named `.Spec.Mode`, which can be used to specify whether the collector should run as a `DaemonSet` or as a `Deployment` (default). Look at the `examples/daemonset.yaml` for reference.

## Prometheus ServiceMonitor objects

When the Prometheus Operator is available in the same cluster as the OpenTelemetry Operator, the OpenTelemetry Operator will automatically create the relevant `ServiceMonitor` objects:

* One set for the OpenTelemetry Operator itself
* One set for each managed OpenTelemetry instance

Refer to the Prometheus Operator for complete instructions on how to do a production-quality installation. For development purposes, the following will do:

```console
$ kubectl apply -f https://raw.githubusercontent.com/coreos/prometheus-operator/v0.33.0/bundle.yaml
```

When deploying the example `simplest.yaml`, the following `ServiceMonitor` will be created once the Prometheus Operator is available:

```console
$ kubectl get servicemonitors simplest-collector
NAME AGE
simplest-collector 103s
```

## Contributing and Developing

Please see [CONTRIBUTING.md](CONTRIBUTING.md).
Expand Down
7 changes: 6 additions & 1 deletion cmd/manager/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/operator-framework/operator-sdk/pkg/metrics"
"github.com/operator-framework/operator-sdk/pkg/restmapper"
"github.com/spf13/pflag"
"github.com/spf13/viper"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/controller-runtime/pkg/client/config"
Expand Down Expand Up @@ -54,6 +55,8 @@ func printVersion() {
}

func main() {
ctx := context.Background()

// Add the zap logger flag set to the CLI. The flag set must
// be added before calling pflag.Parse().
pflag.CommandLine.AddFlagSet(zap.FlagSet())
Expand Down Expand Up @@ -92,7 +95,6 @@ func main() {
os.Exit(1)
}

ctx := context.Background()
// Become the leader before proceeding
err = leader.Become(ctx, "opentelemetry-operator-lock")
if err != nil {
Expand Down Expand Up @@ -148,15 +150,18 @@ func main() {
// CreateServiceMonitors will automatically create the prometheus-operator ServiceMonitor resources
// necessary to configure Prometheus to scrape metrics from this operator.
services := []*v1.Service{service}
svcMonitorAvail := true
_, err = metrics.CreateServiceMonitors(cfg, namespace, services)
if err != nil {
log.Info("Could not create ServiceMonitor object", "error", err.Error())
// If this operator is deployed to a cluster without the prometheus-operator running, it will return
// ErrServiceMonitorNotPresent, which can be used to safely skip ServiceMonitor creation.
if err == metrics.ErrServiceMonitorNotPresent {
svcMonitorAvail = false
log.Info("Install prometheus-operator in your cluster to create ServiceMonitor objects", "error", err.Error())
}
}
viper.Set(opentelemetry.SvcMonitorAvailable, svcMonitorAvail)

log.Info("Starting the Cmd.")

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module github.com/open-telemetry/opentelemetry-operator

require (
github.com/Azure/go-autorest v13.0.1+incompatible // indirect
github.com/coreos/prometheus-operator v0.29.0
github.com/go-logr/logr v0.1.0
github.com/go-openapi/spec v0.19.0
github.com/golang/protobuf v1.3.2 // indirect
Expand All @@ -20,6 +21,7 @@ require (
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gotest.tools v2.2.0+incompatible
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f
k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
k8s.io/client-go v11.0.1-0.20190409021438-1a26190bd76a+incompatible
k8s.io/kube-openapi v0.0.0-20190401085232-94e1e7b7574c
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,7 @@ k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbu
k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apiextensions-apiserver v0.0.0-20190228180357-d002e88f6236 h1:JfFtjaElBIgYKCWEtYQkcNrTpW+lMO4GJy8NP6SVQmM=
k8s.io/apiextensions-apiserver v0.0.0-20190228180357-d002e88f6236/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8 h1:q1Qvjzs/iEdXF6A1a8H3AKVFDzJNcJn3nXMs6R6qFtA=
k8s.io/apiextensions-apiserver v0.0.0-20190409022649-727a075fdec8/go.mod h1:IxkesAMoaCRoLrPJdZNZUQp9NfZnzqaVzLhb2VEQzXE=
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628 h1:UYfHH+KEF88OTg+GojQUwFTNxbxwmoktLwutUzR0GPg=
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
Expand Down Expand Up @@ -919,7 +920,9 @@ sigs.k8s.io/controller-runtime v0.2.0/go.mod h1:ZHqrRDZi3f6BzONcvlUxkqCKgwasGk5F
sigs.k8s.io/controller-tools v0.1.10/go.mod h1:6g08p9m9G/So3sBc1AOQifHfhxH/mb6Sc4z0LMI8XMw=
sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde h1:ZkaHf5rNYzIB6CB82keKMQNv7xxkqT0ylOBdfJPfi+k=
sigs.k8s.io/controller-tools v0.1.11-0.20190411181648-9d55346c2bde/go.mod h1:ATWLRP3WGxuAN9HcT2LaKHReXIH+EZGzRuMHuxjXfhQ=
sigs.k8s.io/controller-tools v0.2.0 h1:AmQ/0JKBJAjyAiPAkrAf9QW06jkx2lc5hpxMjamsFpw=
sigs.k8s.io/controller-tools v0.2.0/go.mod h1:8t/X+FVWvk6TaBcsa+UKUBbn7GMtvyBKX30SGl4em6Y=
sigs.k8s.io/controller-tools v0.2.1 h1:HoCik83vXOpPi7KSJWdPRmiGntyOzK0v0BTV4U+pl8o=
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs=
Expand Down
3 changes: 3 additions & 0 deletions pkg/apis/opentelemetry/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ const (

// OtelColImageConfigKey represents the key to override the OpenTelemetry Collector container image
OtelColImageConfigKey = "otelcol-image"

// SvcMonitorAvailable represents the key that indicates whether a ServiceMonitor CRD is known to the cluster
SvcMonitorAvailable = "svc-monitor-avail"
)
10 changes: 7 additions & 3 deletions pkg/controller/opentelemetrycollector/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ import (
// commonLabels return the common labels to all objects that are part of a managed OpenTelemetryCollector
func commonLabels(ctx context.Context) map[string]string {
instance := ctx.Value(opentelemetry.ContextInstance).(*v1alpha1.OpenTelemetryCollector)
base := instance.Labels
if nil == base {
base = map[string]string{}

// new map every time, so that we don't touch the instance's label
base := map[string]string{}
if nil != instance.Labels {
for k, v := range instance.Labels {
base[k] = v
}
}

base["app.kubernetes.io/managed-by"] = "opentelemetry-operator"
Expand Down
13 changes: 3 additions & 10 deletions pkg/controller/opentelemetrycollector/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,16 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"

"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry/v1alpha1"
)

var (
instance *v1alpha1.OpenTelemetryCollector
ctx context.Context
reconciler *ReconcileOpenTelemetryCollector
schem *runtime.Scheme
cl client.Client
instance *v1alpha1.OpenTelemetryCollector
ctx context.Context
schem *runtime.Scheme
)

// TestMain ensures that all tests in this package have a fresh and sane instance of the common resources
Expand Down Expand Up @@ -49,8 +45,5 @@ func TestMain(m *testing.M) {
ctx = context.WithValue(context.Background(), opentelemetry.ContextInstance, instance)
ctx = context.WithValue(ctx, opentelemetry.ContextLogger, logf.Log.WithName("unit-tests"))

cl = fake.NewFakeClient(instance)
reconciler = New(cl, schem)

os.Exit(m.Run())
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ var log = logf.Log.WithName("controller_opentelemetrycollector")
// Add creates a new OpenTelemetryCollector Controller and adds it to the Manager. The Manager will set fields on the Controller
// and Start it when the Manager is Started.
func Add(mgr manager.Manager) error {
return add(mgr, newReconciler(mgr))
}

// newReconciler returns a new reconcile.Reconciler
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
return New(mgr.GetClient(), mgr.GetScheme())
return add(mgr, WithManager(mgr))
}

// add adds a new Controller to mgr with r as the reconcile.Reconciler
Expand Down
38 changes: 31 additions & 7 deletions pkg/controller/opentelemetrycollector/reconcile.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import (
"fmt"
"time"

monclientv1 "github.com/coreos/prometheus-operator/pkg/client/versioned/typed/monitoring/v1"
"k8s.io/apimachinery/pkg/api/errors"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

"github.com/open-telemetry/opentelemetry-operator/pkg/apis/opentelemetry"
Expand All @@ -23,24 +25,46 @@ var _ reconcile.Reconciler = &ReconcileOpenTelemetryCollector{}
type ReconcileOpenTelemetryCollector struct {
// This client, initialized using mgr.Client() above, is a split client
// that reads objects from the cache and writes to the apiserver
client client.Client
scheme *runtime.Scheme

// the clients that compose this reconciler
clients *Clients

// the list of reconciliation functions to execute
reconcileFuncs []func(context.Context) error
}

// Clients holds all the clients that the reconciler might need to hold
type Clients struct {
client client.Client

// some places are using the rich REST client
monclient monclientv1.MonitoringV1Interface
}

// WithManager creates a new reconciler based on the manager information
func WithManager(manager manager.Manager) *ReconcileOpenTelemetryCollector {
monclient := monclientv1.NewForConfigOrDie(manager.GetConfig())
clients := &Clients{
client: manager.GetClient(),
monclient: monclient,
}

return New(manager.GetScheme(), clients)
}

// New constructs a ReconcileOpenTelemetryCollector based on the client and scheme, with the default reconciliation functions
func New(client client.Client, scheme *runtime.Scheme) *ReconcileOpenTelemetryCollector {
func New(scheme *runtime.Scheme, clients *Clients) *ReconcileOpenTelemetryCollector {
r := &ReconcileOpenTelemetryCollector{
client: client,
scheme: scheme,
scheme: scheme,
clients: clients,
}
r.reconcileFuncs = []func(context.Context) error{
r.reconcileConfigMap,
r.reconcileService,
r.reconcileDeployment,
r.reconcileDaemonSet,
r.reconcileServiceMonitor,
}

return r
Expand All @@ -58,7 +82,7 @@ func (r *ReconcileOpenTelemetryCollector) Reconcile(request reconcile.Request) (

// Fetch the OpenTelemetryCollector instance
instance := &v1alpha1.OpenTelemetryCollector{}
err := r.client.Get(context.Background(), request.NamespacedName, instance)
err := r.clients.client.Get(context.Background(), request.NamespacedName, instance)
if err != nil {
if errors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
Expand Down Expand Up @@ -86,13 +110,13 @@ func (r *ReconcileOpenTelemetryCollector) Reconcile(request reconcile.Request) (
}

// update the status object, which might have also been updated
if err := r.client.Status().Update(ctx, instance); err != nil {
if err := r.clients.client.Status().Update(ctx, instance); err != nil {
reqLogger.Error(err, "failed to store the custom resource's status")
return reconcile.Result{}, err
}

// apply it back, as it might have been updated
if err := r.client.Update(ctx, instance); err != nil {
if err := r.clients.client.Update(ctx, instance); err != nil {
reqLogger.Error(err, "failed to store back the custom resource")
return reconcile.Result{}, err
}
Expand Down
10 changes: 5 additions & 5 deletions pkg/controller/opentelemetrycollector/reconcile_configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ func (r *ReconcileOpenTelemetryCollector) reconcileExpectedConfigMaps(ctx contex
r.setControllerReference(ctx, desired)

existing := &corev1.ConfigMap{}
err := r.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: desired.Namespace}, existing)
err := r.clients.client.Get(ctx, types.NamespacedName{Name: desired.Name, Namespace: desired.Namespace}, existing)
if err != nil && errors.IsNotFound(err) {
if err := r.client.Create(ctx, desired); err != nil {
if err := r.clients.client.Create(ctx, desired); err != nil {
return fmt.Errorf("failed to create: %v", err)
}

Expand Down Expand Up @@ -93,7 +93,7 @@ func (r *ReconcileOpenTelemetryCollector) reconcileExpectedConfigMaps(ctx contex
updated.ObjectMeta.Labels[k] = v
}

if err := r.client.Update(ctx, updated); err != nil {
if err := r.clients.client.Update(ctx, updated); err != nil {
return fmt.Errorf("failed to apply changes: %v", err)
}
logger.V(2).Info("applied", "configmap.name", desired.Name, "configmap.namespace", desired.Namespace)
Expand All @@ -114,7 +114,7 @@ func (r *ReconcileOpenTelemetryCollector) deleteConfigMaps(ctx context.Context,
}),
}
list := &corev1.ConfigMapList{}
if err := r.client.List(ctx, list, opts...); err != nil {
if err := r.clients.client.List(ctx, list, opts...); err != nil {
return fmt.Errorf("failed to list: %v", err)
}

Expand All @@ -127,7 +127,7 @@ func (r *ReconcileOpenTelemetryCollector) deleteConfigMaps(ctx context.Context,
}

if del {
if err := r.client.Delete(ctx, &existing); err != nil {
if err := r.clients.client.Delete(ctx, &existing); err != nil {
return fmt.Errorf("failed to delete: %v", err)
}
logger.V(2).Info("deleted", "configmap.name", existing.Name, "configmap.namespace", existing.Namespace)
Expand Down
Loading

0 comments on commit e3c6e1e

Please sign in to comment.