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

Cluster scoped issues support #211

Merged
merged 10 commits into from
Apr 12, 2023
Merged
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ build: generate fmt vet ## Build manager binary.
run: install manifests generate ## Run a controller from your host.
go run ./main.go -default-plugins-names ${PLUGINS} -worker-image ${WORKER_IMG}

docker-build: test ## Build manager docker image.
docker-build: test ## Build manager Docker image.
docker build -t ${IMG} -f ${DOCKERFILE} .
docker-build-worker: docker-build ## Build Docker images for all components.
docker-build-worker: ## Build worker Docker image.
${MAKE} IMG=${WORKER_IMG} DOCKERFILE=cmd/worker/Dockerfile docker-build


Expand Down
4 changes: 2 additions & 2 deletions charts/zora/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ name: zora
description: Zora scans multiple Kubernetes clusters and reports potential issues.
icon: https://zora-docs.undistro.io/assets/logo.png
type: application
version: 0.5.0
appVersion: "v0.5.0"
version: 0.5.1
appVersion: "v0.5.1"
sources:
- https://github.com/undistro/zora
6 changes: 3 additions & 3 deletions charts/zora/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Zora Helm Chart

![Version: 0.5.0](https://img.shields.io/badge/Version-0.5.0-informational?style=flat-square&color=3CA9DD) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square&color=3CA9DD) ![AppVersion: v0.5.0](https://img.shields.io/badge/AppVersion-v0.5.0-informational?style=flat-square&color=3CA9DD)
![Version: 0.5.1](https://img.shields.io/badge/Version-0.5.1-informational?style=flat-square&color=3CA9DD) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square&color=3CA9DD) ![AppVersion: v0.5.1](https://img.shields.io/badge/AppVersion-v0.5.1-informational?style=flat-square&color=3CA9DD)

Zora scans multiple Kubernetes clusters and reports potential issues.

Expand All @@ -12,7 +12,7 @@ To install the chart with the release name `zora`:
helm repo add undistro https://charts.undistro.io --force-update
helm upgrade --install zora undistro/zora \
-n zora-system \
--version 0.5.0 \
--version 0.5.1 \
--create-namespace --wait
```

Expand Down Expand Up @@ -102,7 +102,7 @@ The following table lists the configurable parameters of the Zora chart and thei
| scan.plugins.popeye.skipInternalResources | bool | `false` | Specifies whether the following resources should be skipped by `popeye` scans. 1. resources from `kube-system`, `kube-public` and `kube-node-lease` namespaces; 2. kubernetes system reserved RBAC (prefixed with `system:`); 3. `kube-root-ca.crt` configmaps; 4. `default` namespace; 5. `default` serviceaccounts; 6. Helm secrets (prefixed with `sh.helm.release`); 7. Zora components. See `popeye` configuration file that is used for this case: https://github.com/undistro/zora/blob/main/charts/zora/templates/plugins/popeye-config.yaml |
| scan.plugins.popeye.resources | object | `{"limits":{"cpu":"500m","memory":"500Mi"},"requests":{"cpu":"250m","memory":"256Mi"}}` | [Resources](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers) to add to `popeye` container |
| scan.plugins.popeye.image.repository | string | `"ghcr.io/undistro/popeye"` | popeye plugin image repository |
| scan.plugins.popeye.image.tag | string | `"v0.11.1-cross"` | popeye plugin image tag |
| scan.plugins.popeye.image.tag | string | `"pr252"` | popeye plugin image tag |

Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

Expand Down
2 changes: 1 addition & 1 deletion charts/zora/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,4 @@ scan:
# -- popeye plugin image repository
repository: ghcr.io/undistro/popeye
# -- popeye plugin image tag
tag: v0.11.1-cross
tag: pr252
2 changes: 1 addition & 1 deletion config/samples/zora_v1alpha1_plugin_popeye.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ kind: Plugin
metadata:
name: popeye
spec:
image: ghcr.io/undistro/popeye:v0.11.1-cross
image: ghcr.io/undistro/popeye:pr252
resources:
limits:
cpu: 500m
Expand Down
2 changes: 0 additions & 2 deletions hack/make/misc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ define addlicense-tool
$(ADDLICENSE) \
-c "Undistro Authors" \
-l "apache" \
-ignore "**/*.png" \
-ignore "**/*.md" \
-ignore "**/*.css" \
-ignore "**/*.html" \
-ignore ".github/**" \
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func main() {
flag.StringVar(&cronJobServiceAccount, "cronjob-serviceaccount-name", "zora-plugins", "Name of ServiceAccount to be configured, appended to ClusterRoleBinding and used by CronJobs")
flag.StringVar(&saasWorkspaceID, "saas-workspace-id", "", "Your workspace ID in Zora SaaS")
flag.StringVar(&saasServer, "saas-server", "http://localhost:3003", "Address for Zora's saas server")
flag.StringVar(&version, "version", "0.5.0", "Zora version")
flag.StringVar(&version, "version", "0.5.1", "Zora version")

opts := zap.Options{
Development: true,
Expand Down
59 changes: 1 addition & 58 deletions pkg/payloads/v1alpha1/clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
package v1alpha1

import (
"strings"

batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -59,16 +57,11 @@ type PluginStatus struct {
Schedule string `json:"schedule"`
}

type NsName struct {
type NamespacedName struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
}

type ResourcedIssue struct {
Issue `json:",inline"`
Resources map[string][]NsName `json:"resources"`
}

type Resources struct {
Discovered bool `json:"discovered"`
Message string `json:"message"`
Expand Down Expand Up @@ -138,27 +131,6 @@ func NewCluster(cluster v1alpha1.Cluster) Cluster {
return cl
}

//NewClusterWithScans returns a Cluster with pluginStatus and without issues
func NewClusterWithScans(cluster v1alpha1.Cluster, scans []v1alpha1.ClusterScan) Cluster {
cl := NewCluster(cluster)
ps, totalIssues := NewScanStatus(scans)
cl.PluginStatus = ps
cl.TotalIssues = totalIssues
return cl
}

//NewClusterWithIssues returns a Cluster with pluginStatus and their issues
func NewClusterWithIssues(cluster v1alpha1.Cluster, scans []v1alpha1.ClusterScan, issues []v1alpha1.ClusterIssue) Cluster {
c := NewClusterWithScans(cluster, scans)
for _, i := range issues {
c.PluginStatus[i.Labels[v1alpha1.LabelPlugin]].Issues = append(
c.PluginStatus[i.Labels[v1alpha1.LabelPlugin]].Issues,
NewResourcedIssue(i),
)
}
return c
}

func NewScanStatus(scans []v1alpha1.ClusterScan) (map[string]*PluginStatus, *int) {
var pluginStatus map[string]*PluginStatus
var totalIssues *int
Expand Down Expand Up @@ -233,32 +205,3 @@ func NewScanStatusWithIssues(scans []v1alpha1.ClusterScan, issues []v1alpha1.Clu
}
return pluginStatus
}

func NewResourcedIssue(i v1alpha1.ClusterIssue) ResourcedIssue {
ri := ResourcedIssue{}
ri.Issue = NewIssue(i)
for r, narr := range i.Spec.Resources {
for _, nspacedn := range narr {
ns := strings.Split(nspacedn, "/")
if len(ns) == 1 {
ns = append([]string{""}, ns[0])
}
if ri.Resources == nil {
ri.Resources = map[string][]NsName{
r: {{
Name: ns[1],
Namespace: ns[0],
}},
}
} else {
ri.Resources[r] = append(ri.Resources[r],
NsName{
Name: ns[1],
Namespace: ns[0],
},
)
}
}
}
return ri
}
127 changes: 37 additions & 90 deletions pkg/payloads/v1alpha1/clusters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,120 +21,79 @@ import (
"testing"

"github.com/google/go-cmp/cmp"
"github.com/undistro/zora/apis/zora/v1alpha1"
"sigs.k8s.io/yaml"

"github.com/undistro/zora/apis/zora/v1alpha1"
)

func TestNewCluster(t *testing.T) {
type args struct {
cluster string
scans []string
}
tests := []struct {
name string
args args
want string
name string
cluster string
want string
}{
{
name: "Cluster and ClusterScan OK",
args: args{
cluster: "ok.yml",
scans: []string{"all_plugins_active.yml"},
},
want: "1.json",
name: "Cluster and ClusterScan OK",
cluster: "ok.yml",
want: "1.json",
},
{
name: "Cluster disconnected since before and ClusterScan with all plugins failed",
args: args{
cluster: "always_disconnected.yml",
scans: []string{"all_plugins_failed.yml"},
},
want: "2.json",
name: "Cluster disconnected since before and ClusterScan with all plugins failed",
cluster: "always_disconnected.yml",
want: "2.json",
},
{
name: "Cluster without metrics and ClusterScan with all plugins active in the 1st scan",
args: args{
cluster: "always_without_metrics.yml",
scans: []string{"all_plugins_active_1st.yml"},
},
want: "3.json",
name: "Cluster without metrics and ClusterScan with all plugins active in the 1st scan",
cluster: "always_without_metrics.yml",
want: "3.json",
},
{
name: "Cluster currently disconnected and ClusterScan with Active and Failed plugins",
args: args{
cluster: "disconnected.yml",
scans: []string{"plugins_active_and_failed.yml"},
},
want: "4.json",
name: "Cluster currently disconnected and ClusterScan with Active and Failed plugins",
cluster: "disconnected.yml",
want: "4.json",
},
{
name: "Cluster currently without metrics and ClusterScan with Active and Complete plugins",
args: args{
cluster: "without_metrics.yml",
scans: []string{"plugins_active_and_complete.yml"},
},
want: "5.json",
name: "Cluster currently without metrics and ClusterScan with Active and Complete plugins",
cluster: "without_metrics.yml",
want: "5.json",
},
{
name: "Cluster without provider/region and ClusterScan OK",
args: args{
cluster: "without_provider.yml",
scans: []string{"ok.yml"},
},
want: "6.json",
name: "Cluster without provider/region and ClusterScan OK",
cluster: "without_provider.yml",
want: "6.json",
},
{
name: "Cluster currently without metrics and two ClusterScans",
args: args{
cluster: "without_metrics.yml",
scans: []string{"plugins_complete_and_failed.yml", "next.yml"},
},
want: "7.json",
name: "Cluster currently without metrics and two ClusterScans",
cluster: "without_metrics.yml",
want: "7.json",
},
{
name: "Cluster currently without metrics, provider, region and ClusterScan",
args: args{
cluster: "without_provider_and_metrics.yml",
scans: []string{},
},
want: "8.json",
name: "Cluster currently without metrics, provider, region and ClusterScan",
cluster: "without_provider_and_metrics.yml",
want: "8.json",
},
{
name: "Cluster currently without metrics and two ClusterScans with issues",
args: args{
cluster: "without_metrics.yml",
scans: []string{"ok.yml", "plugins_active_and_complete.yml"},
},
want: "9.json",
name: "Cluster currently without metrics and two ClusterScans with issues",
cluster: "without_metrics.yml",
want: "9.json",
},
{
name: "Cluster without provider/region and ClusterScan suspended",
args: args{
cluster: "without_provider.yml",
scans: []string{"suspend.yml"},
},
want: "10.json",
name: "Cluster without provider/region and ClusterScan suspended",
cluster: "without_provider.yml",
want: "10.json",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cluster, err := readCluster(tt.args.cluster)
cluster, err := readCluster(tt.cluster)
if err != nil {
t.Errorf("failed to load Cluster testdata: %v", err)
}
scans := make([]v1alpha1.ClusterScan, 0, len(tt.args.scans))
for _, s := range tt.args.scans {
if cs, err := readClusterScan(s); err != nil {
t.Errorf("failed to load ClusterScan testdata: %v", err)
} else {
scans = append(scans, cs)
}
}
payload, err := readClusterPayload(tt.want)
if err != nil {
t.Errorf("failed to load Cluster payload testdata: %v", err)
}
if got := NewClusterWithScans(cluster, scans); !reflect.DeepEqual(got, payload) {
if got := NewCluster(cluster); !reflect.DeepEqual(got, payload) {
t.Errorf("NewCluster() = %s", cmp.Diff(got, payload))
}
})
Expand All @@ -153,18 +112,6 @@ func readCluster(filename string) (v1alpha1.Cluster, error) {
return c, err
}

func readClusterScan(filename string) (v1alpha1.ClusterScan, error) {
b, err := os.ReadFile("testdata/clusterscan/" + filename)
var cs v1alpha1.ClusterScan
if err != nil {
return cs, err
}
if err := yaml.Unmarshal(b, &cs); err != nil {
return cs, err
}
return cs, err
}

func readClusterPayload(filename string) (Cluster, error) {
b, err := os.ReadFile("testdata/payload/" + filename)
var cp Cluster
Expand Down
Loading