Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introducing short-lived cache #62

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion artifacts/settings/settings.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
enableNamespaceByDefault: false
monitorNamespacesByDefault: false
serviceAnnotations: []
serviceRegistry:
etcd:
Expand Down
48 changes: 24 additions & 24 deletions controllers/namespace_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"strings"
"sync"

"github.com/CloudNativeSDWAN/cnwan-operator/internal/utils"
sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry"
"github.com/go-logr/logr"
corev1 "k8s.io/api/core/v1"
Expand All @@ -32,18 +31,19 @@ import (
)

const (
enabledLabel string = "operator.cnwan.io/enabled"
monitorLabel string = "operator.cnwan.io/monitor"
)

// NamespaceReconciler reconciles a Namespace object
type NamespaceReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
EnableNamespaceByDefault bool
nsLastConf map[string]bool
lock sync.Mutex
ServRegBroker *sr.Broker
Log logr.Logger
Scheme *runtime.Scheme
MonitorNamespacesByDefault bool
AllowedAnnotations []string
nsLastConf map[string]bool
lock sync.Mutex
ServRegBroker *sr.Broker
}

// +kubebuilder:rbac:groups=core,resources=namespaces,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -95,27 +95,27 @@ func (r *NamespaceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
return ctrl.Result{}, nil
}

change, nsIsEnabled := func() (bool, bool) {
var currentlyEnabled bool
switch strings.ToLower(ns.Labels[enabledLabel]) {
case "yes":
currentlyEnabled = true
case "no":
currentlyEnabled = false
change, nsIsMonitored := func() (bool, bool) {
var currentlyMonitored bool
switch strings.ToLower(ns.Labels[monitorLabel]) {
case "true":
currentlyMonitored = true
case "false":
currentlyMonitored = false
default:
currentlyEnabled = r.EnableNamespaceByDefault
currentlyMonitored = r.MonitorNamespacesByDefault
}

r.lock.Lock()
defer r.lock.Unlock()
previouslyEnabled, existed := r.nsLastConf[ns.Name]
previouslyMonitored, existed := r.nsLastConf[ns.Name]
if !existed {
previouslyEnabled = r.EnableNamespaceByDefault
previouslyMonitored = r.MonitorNamespacesByDefault
}

changed := currentlyEnabled != previouslyEnabled
r.nsLastConf[ns.Name] = currentlyEnabled
return changed, currentlyEnabled
changed := currentlyMonitored != previouslyMonitored
r.nsLastConf[ns.Name] = currentlyMonitored
return changed, currentlyMonitored
}()
if !change {
return ctrl.Result{}, nil
Expand All @@ -129,14 +129,14 @@ func (r *NamespaceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {

// First, check the services
for _, serv := range servList.Items {
if !nsIsEnabled {
if !nsIsMonitored {
if err := r.ServRegBroker.RemoveServ(serv.Namespace, serv.Name, true); err != nil {
l.Error(err, "error while deleting service")
}
} else {
// Get the data in our simpler format
// Note: as of now, we are not copying any annotations from a namespace
serv.Annotations = utils.FilterAnnotations(serv.Annotations)
serv.Annotations = filterAnnotations(serv.Annotations, r.AllowedAnnotations)
nsData, servData, endpList, err := r.ServRegBroker.Reg.ExtractData(&ns, &serv)
if err != nil {
l.WithValues("serv-name", servData.Name).Error(err, "error while extracting data from the namespace and service")
Expand All @@ -161,7 +161,7 @@ func (r *NamespaceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}
}

if !nsIsEnabled {
if !nsIsMonitored {
if err := r.ServRegBroker.RemoveNs(ns.Name, true); err != nil {
l.Error(err, "error while deleting service")
}
Expand Down
20 changes: 10 additions & 10 deletions controllers/service_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"fmt"
"strings"

"github.com/CloudNativeSDWAN/cnwan-operator/internal/utils"
sr "github.com/CloudNativeSDWAN/cnwan-operator/pkg/servregistry"

"github.com/go-logr/logr"
Expand All @@ -35,10 +34,11 @@ import (
// ServiceReconciler reconciles a Service object
type ServiceReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
ServRegBroker *sr.Broker
EnableNamespaceByDefault bool
Log logr.Logger
Scheme *runtime.Scheme
ServRegBroker *sr.Broker
MonitorNamespacesByDefault bool
AllowedAnnotations []string
}

// +kubebuilder:rbac:groups=core,resources=services,verbs=get;list;watch;create;update;patch;delete
Expand Down Expand Up @@ -82,13 +82,13 @@ func (r *ServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
}

var shouldWatchNs bool
switch strings.ToLower(ns.Labels[enabledLabel]) {
case "yes":
switch strings.ToLower(ns.Labels[monitorLabel]) {
case "true":
shouldWatchNs = true
case "no":
case "false":
shouldWatchNs = false
default:
shouldWatchNs = r.EnableNamespaceByDefault
shouldWatchNs = r.MonitorNamespacesByDefault
}

if !shouldWatchNs {
Expand All @@ -98,7 +98,7 @@ func (r *ServiceReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {

// Get the data in our simpler format
// Note: as of now, we are not copying any annotations from a namespace
service.Annotations = utils.FilterAnnotations(service.Annotations)
service.Annotations = filterAnnotations(service.Annotations, r.AllowedAnnotations)
nsData, servData, endpList, err := r.ServRegBroker.Reg.ExtractData(&ns, &service)
if err != nil {
l.Error(err, "error while getting data from the namespace and service")
Expand Down
64 changes: 64 additions & 0 deletions controllers/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright © 2021 Cisco
//
// 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.
//
// All rights reserved.

package controllers

import (
"fmt"
"strings"
)

// filterAnnotations is used to remove annotations that should be ignored
// by the operator
func filterAnnotations(currentAnnotations map[string]string, filter []string) map[string]string {
filterMap := map[string]bool{}
for _, ann := range filter {
filterMap[ann] = true
}

if _, exists := filterMap["*/*"]; exists {
return currentAnnotations
}

filtered := map[string]string{}
for key, val := range currentAnnotations {

// Check this key specifically
if _, exists := filterMap[key]; exists {
filtered[key] = val
continue
}

prefixName := strings.Split(key, "/")
if len(prefixName) != 2 {
// This key is not in prefix/name format
continue
}

prefixWildcard := fmt.Sprintf("%s/*", prefixName[0])
if _, exists := filterMap[prefixWildcard]; exists {
filtered[key] = val
continue
}

wildcardName := fmt.Sprintf("*/%s", prefixName[1])
if _, exists := filterMap[wildcardName]; exists {
filtered[key] = val
}
}

return filtered
}
75 changes: 75 additions & 0 deletions controllers/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright © 2021 Cisco
//
// 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.
//
// All rights reserved.

package controllers

import (
"testing"

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

func TestFilterAnnotations(t *testing.T) {
annotations := map[string]string{
"stand-alone": "alone",
"another-stand-alone": "another-alone",
"prefix.io/one": "one",
"prefix.io/two": "two",
"another.io/first": "another-first",
"another.io/second": "another-second",
"yet-another.io/first": "yet-first",
"yet-another.io/second": "yet-second",
}

cases := []struct {
annotations map[string]string
filter []string
expRes map[string]string
}{
{
annotations: map[string]string{},
filter: []string{"whatever"},
expRes: map[string]string{},
},
{
annotations: map[string]string{"whatever": "whatever"},
filter: []string{},
expRes: map[string]string{},
},
{
annotations: annotations,
filter: []string{"*/*"},
expRes: annotations,
},
{
annotations: annotations,
filter: []string{"stand-alone", "prefix.io/*", "*/first"},
expRes: map[string]string{
"stand-alone": "alone",
"prefix.io/one": "one",
"prefix.io/two": "two",
"another.io/first": "another-first",
"yet-another.io/first": "yet-first",
},
},
}

a := assert.New(t)
for _, currCase := range cases {
res := filterAnnotations(currCase.annotations, currCase.filter)
a.Equal(currCase.expRes, res)
}
}
18 changes: 9 additions & 9 deletions docs/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* [Metadata](#metadata)
* [Annotations vs Labels](#annotations-vs-labels)
* [Ownership](#ownership)
* [Enable namespaces](#enable-namespaces)
* [Monitor namespaces](#monitor-namespaces)
* [Allowed Annotations](#allowed-annotations)
* [Cloud Metadata](#cloud-metadata)
* [Deploy](#deploy)
Expand Down Expand Up @@ -80,28 +80,28 @@ That being said, the operator will still insert child resources even if the pare

Finally, if you wish the operator to manage your pre-existing resources on your service registry, please update all the necessary resources by inserting `owner: cnwan-operator` among their metadata.

## Enable namespaces
## Monitor namespaces

The CN-WAN Operator watches service updates only on *enabled* namespaces. To do so, you need to label a namespace with our reserved label key `operator.cnwan.io/enabled`.
The CN-WAN Operator watches service updates only on *monitored* namespaces. To do so, you need to label a namespace with our reserved label key `operator.cnwan.io/monitor`.

If a namespace is labeled as `operator.cnwan.io/enabled=yes` then the operator will watch service updates happening on that namespace. On the contrary, `operator.cnwan.io/enabled=no` will instruct the operator to stay away from that namespace.
If a namespace is labeled as `operator.cnwan.io/monitor=true` then the operator will watch service updates happening on that namespace. On the contrary, `operator.cnwan.io/monitor=false` will instruct the operator to stay away from that namespace.

This being said, you don't need to rush labelling all namespaces as `operator.cnwan.io/enabled=no` in fear of potentially exposing sensitive data on the service registry: namespaces that do not have such label will be ignored by default, as the operator will pretend it is seeing `operator.cnwan.io/enabled=no`. This is useful in case you think you have few namespaces you want to enable or if you prefer to retain control, even have lots of namespaces to enable.
This being said, you don't need to rush labelling all namespaces as `operator.cnwan.io/monitor=false` in fear of potentially exposing sensitive data on the service registry: namespaces that do not have such label will be ignored by default, as the operator will pretend it is seeing `operator.cnwan.io/monitor=false`. This is useful in case you think you have few namespaces you want to monitor or if you prefer to retain control, even have lots of namespaces to monitor.

Instead, if you have many namespaces to enable and/or find it tedious to manually do so for every single one of them, you can override this behavior via `enableNamespaceByDefault: true` on the [operator settings](./configuration.md#enable-namespace-by-default): this means that the operator will pretend it is seeing `operator.cnwan.io/enabled=yes` and thus watch events in the namespace by default, unless instructed otherwise. This is the opposite scenario from above: now you will need to manually *disable* them.
Instead, if you have many namespaces to monitor and/or find it tedious to manually do so for every single one of them, you can override this behavior via `monitorNamespacesByDefault: true` on the [operator settings](./configuration.md#monitor-namespaces-by-default): this means that the operator will pretend it is seeing `operator.cnwan.io/monitor=true` and thus watch events in the namespace by default, unless instructed otherwise. This is the opposite scenario from above: now you will need to manually *disable* them.

Let's see some examples.

To _enable_ monitoring on namespace `hr`, do the following:
To _monitor_ monitoring on namespace `hr`, do the following:

```bash
kubectl label ns hr operator.cnwan.io/enabled=yes
kubectl label ns hr operator.cnwan.io/monitor=true
```

To _disable_ monitoring on namespace `hr`:

```bash
kubectl label ns hr operator.cnwan.io/enabled=no
kubectl label ns hr operator.cnwan.io/monitor=false
```

Note: append `--overwrite` in case the label already exists.
Expand Down
12 changes: 6 additions & 6 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This section will guide you through the steps you need to take to configure the
## Table of Contents

* [Format](#format)
* [Enable namespace by default](#enable-namespace-by-default)
* [Monitor namespaces by default](#monitor-namespace-by-default)
* [Allow Annotations](#allow-annotations)
* [Cloud Metadata](#cloud-metadata)
* [Service registry settings](#service-registry-settings)
Expand All @@ -17,7 +17,7 @@ This section will guide you through the steps you need to take to configure the
The CN-WAN Operator can be configured with the following YAML format.

```yaml
enableNamespaceByDefault: false
monitorNamespacesByDefault: false
serviceAnnotations: []
serviceRegistry:
etcd:
Expand All @@ -36,13 +36,13 @@ cloudMetadata:
subNetwork: auto
```

## Enable namespace by default
## Monitor namespace by default

The operator will watch service events only on namespaces that are *enabled*, and to do so you need to explicitly label namespaces with the reserved `operator.cnwan.io/enabled` label key.
The operator will watch service events only on namespaces that are *monitored*, and to do so you need to explicitly label namespaces with the reserved `operator.cnwan.io/monitor` label key.

`enableNamespaceByDefault` will tell the operator what to do when such label is not found: if it does not exist or is false, then the operator will ignore the namespace by default. Otherwise it will watch events inside it.
`monitorNamespacesByDefault` will tell the operator what to do when such label is not found: if it does not exist or is false, then the operator will ignore the namespace by default. Otherwise it will watch events inside it.

if you haven't already, please take a look at [this section](./concepts.md#enable-namespaces) to learn more about this concept.
if you haven't already, please take a look at [this section](./concepts.md#monitor-namespaces) to learn more about this concept.

## Allow Annotations

Expand Down
4 changes: 2 additions & 2 deletions docs/etcd/operator_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The included directory `deploy/settings` contains a `settings.yaml` for you to m
For your convenience, here is how the settings for the CN-WAN Operator looks like:

```yaml
enableNamespaceByDefault: false
monitorNamespacesByDefault: false
serviceAnnotations: []
serviceRegistry:
etcd:
Expand All @@ -28,7 +28,7 @@ serviceRegistry:
We will only cover etcd settings here, so you can go ahead and remove the whole `gcpServiceDirectory` settings:

```yaml
enableNamespaceByDefault: false
monitorNamespacesByDefault: false
serviceAnnotations: []
serviceRegistry:
etcd:
Expand Down
Loading