Skip to content

Commit

Permalink
Merge pull request #80 from kubescape/fix-ns
Browse files Browse the repository at this point in the history
add support for include/exclude ns config
  • Loading branch information
matthyx authored Jul 24, 2024
2 parents d96398f + 98d29d4 commit f72c82a
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 33 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pr-created.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
pr-created:
uses: kubescape/workflows/.github/workflows/incluster-comp-pr-created.yaml@main
with:
GO_VERSION: "1.21"
GO_VERSION: "1.22"
CGO_ENABLED: 0
secrets: inherit

Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
CGO_ENABLED: 0
uses: actions/setup-go@v4
with:
go-version: "1.21"
go-version: "1.22"

- name: Run test
run: |
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pr-merged.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: build
on:
pull_request_target:
types: [closed]
branches:
branches:
- 'main'
paths-ignore:
- '**.md' ### Ignore running when README.MD changed.
- '.github/workflows/*' ### Ignore running when files under path: .github/workflows/* changed.

jobs:
pr-merged:
if: ${{ github.event.pull_request.merged == true }} ## Skip if not merged
if: ${{ github.event.pull_request.merged == true }} ## Skip if not merged
uses: kubescape/workflows/.github/workflows/incluster-comp-pr-merged.yaml@main
with:
IMAGE_NAME: quay.io/${{ github.repository_owner }}/synchronizer
Expand All @@ -19,7 +19,7 @@ jobs:
CGO_ENABLED: 0
GO111MODULE: "on"
BUILD_PLATFORM: linux/amd64,linux/arm64
GO_VERSION: "1.21"
GO_VERSION: "1.22"
REQUIRED_TESTS: '[]'
COSIGN: true
HELM_E2E_TEST: false # TODO: Enable this when helm e2e test is ready
Expand Down
51 changes: 42 additions & 9 deletions adapters/incluster/v1/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (

"github.com/cenkalti/backoff/v4"
"go.uber.org/multierr"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/pager"

mapset "github.com/deckarep/golang-set/v2"
jsonpatch "github.com/evanphx/json-patch"
Expand Down Expand Up @@ -55,6 +57,8 @@ type Client struct {
client dynamic.Interface
account string
cluster string
excludeNamespaces []string
includeNamespaces []string
operatorNamespace string // the namespace where the kubescape operator is running
kind *domain.Kind
multiplier int
Expand All @@ -74,6 +78,8 @@ func NewClient(client dynamic.Interface, cfg config.InCluster, r config.Resource
return &Client{
account: cfg.Account,
client: client,
excludeNamespaces: cfg.ExcludeNamespaces,
includeNamespaces: cfg.IncludeNamespaces,
operatorNamespace: cfg.Namespace,
cluster: cfg.ClusterName,
kind: &domain.Kind{
Expand Down Expand Up @@ -268,9 +274,15 @@ func (c *Client) isFiltered(workload *unstructured.Unstructured) bool {
if workload == nil {
return false
}
// workload is not filtered if it is in the kubescape-operator namespace
if c.operatorNamespace != "" && workload.GetNamespace() == c.operatorNamespace {
return false
if namespace := workload.GetNamespace(); namespace != "" {
// workload is not filtered if it is in the kubescape-operator namespace
if namespace == c.operatorNamespace {
return false
}
// workload is filtered if it is in a skipped namespace
if c.skipNamespace(namespace) {
return true
}
}
// for all other workloads, we filter out those that have a parent
return hasParent(workload)
Expand Down Expand Up @@ -478,6 +490,8 @@ func (c *Client) verifyObject(id domain.KindName, newChecksum string) ([]byte, e

func (c *Client) getExistingStorageObjects(ctx context.Context) (string, error) {
logger.L().Debug("getting existing objects from storage", helpers.String("resource", c.res.Resource))
// no need for pager since list returns only metadatas
// no need for skip ns since these are our CRDs
list, err := c.client.Resource(c.res).Namespace("").List(context.Background(), metav1.ListOptions{})
if err != nil {
return "", fmt.Errorf("list resources: %w", err)
Expand Down Expand Up @@ -570,16 +584,18 @@ func reconcileBatchProcessingFunc(ctx context.Context, c *Client, items domain.B
}

// create a map of resources from the client
list, err := c.client.Resource(c.res).Namespace("").List(context.Background(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("reconciliation: list resources: %w", err)
}
clientItems := map[string]unstructured.Unstructured{}
clientItemsSet := mapset.NewSet[string]()
for _, item := range list.Items {
if err := pager.New(func(ctx context.Context, opts metav1.ListOptions) (runtime.Object, error) {
return c.client.Resource(c.res).Namespace("").List(ctx, opts)
}).EachListItem(context.Background(), metav1.ListOptions{}, func(obj runtime.Object) error {
item := obj.(*unstructured.Unstructured)
k := fmt.Sprintf("%s/%s", item.GetNamespace(), item.GetName())
clientItems[k] = item
clientItems[k] = *item
clientItemsSet.Add(k)
return nil
}); err != nil {
return fmt.Errorf("reconciliation: list resources: %w", err)
}

// create a map of resources from the server
Expand All @@ -591,6 +607,8 @@ func reconcileBatchProcessingFunc(ctx context.Context, c *Client, items domain.B
serverItemsSet.Add(k)
}

var err error

// resources that should not be in server, send delete
for _, k := range serverItemsSet.Difference(clientItemsSet).ToSlice() {
item := serverItems[k]
Expand Down Expand Up @@ -745,6 +763,21 @@ func (c *Client) getResource(namespace string, name string) (*unstructured.Unstr
return c.client.Resource(c.res).Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{})
}

func (c *Client) skipNamespace(ns string) bool {
if includeNamespaces := c.includeNamespaces; len(includeNamespaces) > 0 {
if !slices.Contains(includeNamespaces, ns) {
// skip ns not in IncludeNamespaces
return true
}
} else if excludeNamespaces := c.excludeNamespaces; len(excludeNamespaces) > 0 {
if slices.Contains(excludeNamespaces, ns) {
// skip ns in ExcludeNamespaces
return true
}
}
return false
}

func stripSuffix(name string) string {
lastHyphen := strings.LastIndex(name, "-")
if lastHyphen != -1 && strings.HasPrefix(name[lastHyphen:], "-") {
Expand Down
62 changes: 62 additions & 0 deletions adapters/incluster/v1/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,65 @@ func TestClient_filterAndMarshal(t *testing.T) {
})
}
}

func TestClient_isFiltered(t *testing.T) {
tests := []struct {
name string
workload *unstructured.Unstructured
filtered bool
}{
{
name: "nil workload",
filtered: false,
},
{
name: "pod",
workload: &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Pod",
"metadata": map[string]interface{}{"namespace": "default"}}},
filtered: false,
},
{
name: "pod with ownerReferences",
workload: &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Pod",
"metadata": map[string]interface{}{
"ownerReferences": []interface{}{map[string]interface{}{
"apiVersion": "batch/v1"}}}}},
filtered: true,
},
{
name: "pod with pod-template-hash",
workload: &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Pod",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"pod-template-hash": "12345"}}}},
filtered: true,
},
{
name: "pod from kubescape namespace", // special case, never filter out
workload: &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Pod",
"metadata": map[string]interface{}{"namespace": "default"}}},
filtered: false,
},
{
name: "pod from filtered namespace",
workload: &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Pod",
"metadata": map[string]interface{}{"namespace": "kube-system"}}},
filtered: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Client{
excludeNamespaces: []string{"kube-system", "kubescape"},
includeNamespaces: []string{},
operatorNamespace: "kubescape",
}
assert.Equalf(t, tt.filtered, c.isFiltered(tt.workload), "isFiltered(%v)", tt.workload)
})
}
}
2 changes: 1 addition & 1 deletion build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=$BUILDPLATFORM golang:1.21-bullseye as builder
FROM --platform=$BUILDPLATFORM golang:1.22-bullseye AS builder

ENV GO111MODULE=on CGO_ENABLED=0
WORKDIR /work
Expand Down
14 changes: 8 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ type Backend struct {
}

type InCluster struct {
ServerUrl string `mapstructure:"serverUrl"`
Namespace string `mapstructure:"namespace"`
ClusterName string `mapstructure:"clusterName"`
Account string `mapstructure:"account"`
AccessKey string `mapstructure:"accessKey"`
Resources []Resource `mapstructure:"resources"`
ServerUrl string `mapstructure:"serverUrl"`
Namespace string `mapstructure:"namespace"`
ClusterName string `mapstructure:"clusterName"`
ExcludeNamespaces []string `mapstructure:"excludeNamespaces"`
IncludeNamespaces []string `mapstructure:"includeNamespaces"`
Account string `mapstructure:"account"`
AccessKey string `mapstructure:"accessKey"`
Resources []Resource `mapstructure:"resources"`
}

type HTTPEndpoint struct {
Expand Down
11 changes: 7 additions & 4 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,13 @@ func TestLoadConfig(t *testing.T) {
path: "../configuration/client",
want: Config{
InCluster: InCluster{
ServerUrl: "ws://127.0.0.1:8080/",
ClusterName: "cluster-1",
Account: "11111111-2222-3333-4444-11111111",
AccessKey: "xxxxxxxx-1111-1111-1111-xxxxxxxx",
ServerUrl: "ws://127.0.0.1:8080/",
Namespace: "kubescape",
ClusterName: "cluster-1",
ExcludeNamespaces: []string{"kube-system", "kubescape"},
IncludeNamespaces: []string{},
Account: "11111111-2222-3333-4444-11111111",
AccessKey: "xxxxxxxx-1111-1111-1111-xxxxxxxx",
Resources: []Resource{
{Group: "", Version: "v1", Resource: "pods", Strategy: "patch"},
{Group: "", Version: "v1", Resource: "nodes", Strategy: "patch"},
Expand Down
5 changes: 4 additions & 1 deletion configuration/client/config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"inCluster": {
"serverUrl": "ws://127.0.0.1:8080/",
"namespace": "kubescape",
"clusterName": "cluster-1",
"excludeNamespaces": "kube-system,kubescape",
"includeNamespaces": "",
"account": "11111111-2222-3333-4444-11111111",
"accessKey": "xxxxxxxx-1111-1111-1111-xxxxxxxx",
"resources": [
Expand Down Expand Up @@ -48,4 +51,4 @@
}
]
}
}
}
4 changes: 1 addition & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/kubescape/synchronizer

go 1.21.3

toolchain go1.21.5
go 1.22.5

require (
github.com/SergJa/jsonhash v0.0.0-20210531165746-fc45f346aa74
Expand Down
4 changes: 1 addition & 3 deletions tests/go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
module github.com/kubescape/synchronizer/tests

go 1.21.3

toolchain go1.21.5
go 1.22.5

require (
github.com/apache/pulsar-client-go v0.12.1
Expand Down
2 changes: 2 additions & 0 deletions tests/synchronizer_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,8 @@ func createAndStartSynchronizerClient(t *testing.T, cluster *TestKubernetesClust
// set cluster config
clientCfg.InCluster.Namespace = kubescapeNamespace
clientCfg.InCluster.ClusterName = cluster.cluster
clientCfg.InCluster.ExcludeNamespaces = []string{"kube-system", "kubescape"}
clientCfg.InCluster.IncludeNamespaces = []string{}
clientCfg.InCluster.Account = cluster.account
clientCfg.InCluster.ServerUrl = syncServer.serverUrl
if watchDefaults {
Expand Down

0 comments on commit f72c82a

Please sign in to comment.