Skip to content

Commit

Permalink
chore: added tests, move logic to separate package
Browse files Browse the repository at this point in the history
  • Loading branch information
raffis committed Oct 7, 2022
1 parent 6e1da4b commit 2c8f346
Show file tree
Hide file tree
Showing 9 changed files with 377 additions and 57 deletions.
8 changes: 0 additions & 8 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,3 @@ jobs:
args: release --rm-dist --skip-validate
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish formula
run: |
mkdir -p Formula
cp dist/gitops-zombies.rb Formula/
git add Formula/*
git commit Formula -m "publish formula"
git push
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fmt:
go fmt ./...

test:
go test ./...
go test -v ./...

vet:
go vet ./...
Expand Down
6 changes: 1 addition & 5 deletions cmd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,9 @@ type stderrLogger struct {
stderr io.Writer
}

func (l stderrLogger) Infof(format string, a ...interface{}) {
fmt.Fprintln(l.stderr, `►`, fmt.Sprintf(format, a...))
}

func (l stderrLogger) Debugf(format string, a ...interface{}) {
if l.verbose {
fmt.Fprintln(l.stderr, ``, fmt.Sprintf(format, a...))
fmt.Fprintln(l.stderr, `>`, fmt.Sprintf(format, a...))
}
}

Expand Down
93 changes: 54 additions & 39 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"sync"

"gihub.com/raffis/flux-zombies/pkg/collector"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -83,6 +84,11 @@ func main() {
os.Exit(1)
}

var (
helmReleases []unstructured.Unstructured
kustomizations []unstructured.Unstructured
)

func run(cmd *cobra.Command, args []string) error {
if flags.version {
fmt.Printf(`{"version":"%s","sha":"%s","date":"%s"}`+"\n", version, commit, date)
Expand Down Expand Up @@ -114,9 +120,38 @@ func run(cmd *cobra.Command, args []string) error {
return err
}

helmReleases, err = listResources(context.TODO(), client.Resource(schema.GroupVersionResource{
Group: "helm.toolkit.fluxcd.io",
Version: "v2beta1",
Resource: "helmreleases",
}))

if err != nil {
return fmt.Errorf("failed to get helmreleases: %w", err)
}

kustomizations, err = listResources(context.TODO(), client.Resource(schema.GroupVersionResource{
Group: "kustomize.toolkit.fluxcd.io",
Version: "v1beta2",
Resource: "kustomizations",
}))

if err != nil {
return fmt.Errorf("failed to get kustomizations: %w", err)
}

ch := make(chan unstructured.Unstructured)
var wgProducer, wgConsumer sync.WaitGroup

discover := collector.NewDiscovery(
logger,
collector.IgnoreOwnedResource(),
collector.IgnoreServiceAccountSecret(),
collector.IgnoreHelmSecret(),
collector.IgnoreIfHelmReleaseFound(helmReleases),
collector.IgnoreIfKustomizationFound(kustomizations),
)

for _, group := range list {
logger.Debugf("discover resource group %#v", group.GroupVersion)
gv, err := schema.ParseGroupVersion(group.GroupVersion)
Expand Down Expand Up @@ -144,6 +179,7 @@ func run(cmd *cobra.Command, args []string) error {

resAPI := client.Resource(gvr)

// Skip APIS which do not support list
if !slices.Contains(resource.Verbs, "list") {
continue
}
Expand All @@ -152,7 +188,10 @@ func run(cmd *cobra.Command, args []string) error {

go func(resAPI dynamic.ResourceInterface) {
defer wgProducer.Done()
handleResource(context.TODO(), resAPI, ch)

if err := handleResource(context.TODO(), discover, resAPI, ch); err != nil {
logger.Failuref("could not hanlder resource: %s", err)
}
}(resAPI)
}
}
Expand All @@ -170,6 +209,18 @@ func run(cmd *cobra.Command, args []string) error {
return nil
}

func listResources(ctx context.Context, resAPI dynamic.ResourceInterface) (items []unstructured.Unstructured, err error) {
list, err := resAPI.List(ctx, metav1.ListOptions{
LabelSelector: getLabelSelector(),
})

if err != nil {
return items, err
}

return list.Items, err
}

func getLabelSelector() string {
selector := ""
if !flags.includeAll {
Expand All @@ -183,7 +234,7 @@ func getLabelSelector() string {
return selector
}

func handleResource(ctx context.Context, resAPI dynamic.ResourceInterface, ch chan unstructured.Unstructured) error {
func handleResource(ctx context.Context, discover collector.Interface, resAPI dynamic.ResourceInterface, ch chan unstructured.Unstructured) error {
list, err := resAPI.List(ctx, metav1.ListOptions{
LabelSelector: getLabelSelector(),
})
Expand All @@ -192,43 +243,7 @@ func handleResource(ctx context.Context, resAPI dynamic.ResourceInterface, ch ch
return err
}

for _, res := range list.Items {
logger.Debugf("validate resource %s %s %s", res.GetName(), res.GetNamespace(), res.GetAPIVersion())

if refs := res.GetOwnerReferences(); len(refs) > 0 {
logger.Debugf("ignore resource owned by parent %s %s %s", res.GetName(), res.GetNamespace(), res.GetAPIVersion())
continue
}

labels := res.GetLabels()
if helmName, ok := labels[FLUX_HELM_NAME_LABEL]; ok {
if helmNamespace, ok := labels[FLUX_HELM_NAMESPACE_LABEL]; ok {
logger.Debugf("helm %s %s\n", helmName, helmNamespace)
continue
}
}

if ksName, ok := labels[FLUX_KUSTOMIZE_NAME_LABEL]; ok {
if ksNamespace, ok := labels[FLUX_KUSTOMIZE_NAMESPACE_LABEL]; ok {
logger.Debugf("ks %s %s\n", ksName, ksNamespace)
continue
}
}

if res.GetKind() == "Secret" && res.GetAPIVersion() == "v1" {
if _, ok := res.GetAnnotations()["kubernetes.io/service-account.name"]; ok {
continue
}

if v, ok := res.GetLabels()["owner"]; ok && v == "helm" {
continue
}
}

ch <- res
}

return nil
return discover.Discover(ctx, list, ch)
}

func printer(ch chan unstructured.Unstructured) error {
Expand Down
4 changes: 0 additions & 4 deletions cosign.pub

This file was deleted.

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.18
require (
github.com/spf13/cobra v1.5.0
golang.org/x/exp v0.0.0-20221004215720-b9f4876ce741
gotest.tools/v3 v3.0.3
k8s.io/apimachinery v0.25.2
k8s.io/cli-runtime v0.25.2
k8s.io/client-go v0.25.2
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down
132 changes: 132 additions & 0 deletions pkg/collector/resource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package collector

import (
"context"

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

const (
FLUX_HELM_NAME_LABEL = "helm.toolkit.fluxcd.io/name"
FLUX_HELM_NAMESPACE_LABEL = "helm.toolkit.fluxcd.io/namespace"
FLUX_KUSTOMIZE_NAME_LABEL = "kustomize.toolkit.fluxcd.io/name"
FLUX_KUSTOMIZE_NAMESPACE_LABEL = "kustomize.toolkit.fluxcd.io/namespace"
)

type FilterFunc func(res unstructured.Unstructured, logger logger) bool

type Interface interface {
Discover(ctx context.Context, list *unstructured.UnstructuredList, ch chan unstructured.Unstructured) error
}

type logger interface {
Debugf(format string, a ...interface{})
}

type discovery struct {
filters []FilterFunc
logger logger
}

func NewDiscovery(logger logger, filters ...FilterFunc) Interface {
return &discovery{
logger: logger,
filters: filters,
}
}

func (d *discovery) Discover(ctx context.Context, list *unstructured.UnstructuredList, ch chan unstructured.Unstructured) error {
RESOURCES:
for _, res := range list.Items {
d.logger.Debugf("validate resource %s %s %s", res.GetName(), res.GetNamespace(), res.GetAPIVersion())

for _, filter := range d.filters {
if filter(res, d.logger) {
continue RESOURCES
}
}

ch <- res
}

return nil
}

func IgnoreOwnedResource() FilterFunc {
return func(res unstructured.Unstructured, logger logger) bool {
if refs := res.GetOwnerReferences(); len(refs) > 0 {
logger.Debugf("ignore resource owned by parent %s %s %s", res.GetName(), res.GetNamespace(), res.GetAPIVersion())
return true
}

return false
}
}

func IgnoreServiceAccountSecret() FilterFunc {
return func(res unstructured.Unstructured, logger logger) bool {
if res.GetKind() == "Secret" && res.GetAPIVersion() == "v1" {
if _, ok := res.GetAnnotations()["kubernetes.io/service-account.name"]; ok {
return true
}
}

return false
}
}

func IgnoreHelmSecret() FilterFunc {
return func(res unstructured.Unstructured, logger logger) bool {
if res.GetKind() == "Secret" && res.GetAPIVersion() == "v1" {
if v, ok := res.GetLabels()["owner"]; ok && v == "helm" {
return true
}
}

return false
}
}

func IgnoreIfHelmReleaseFound(helmReleases []unstructured.Unstructured) FilterFunc {
return func(res unstructured.Unstructured, logger logger) bool {
labels := res.GetLabels()
if helmName, ok := labels[FLUX_HELM_NAME_LABEL]; ok {
if helmNamespace, ok := labels[FLUX_HELM_NAMESPACE_LABEL]; ok {
if hasResource(helmReleases, helmName, helmNamespace) {
return true
} else {
logger.Debugf("helmrelease [%s.%s] not found from resource %s %s %s\n", helmName, helmNamespace, res.GetName(), res.GetNamespace(), res.GetAPIVersion())
}
}
}

return false
}
}

func IgnoreIfKustomizationFound(kustomizations []unstructured.Unstructured) FilterFunc {
return func(res unstructured.Unstructured, logger logger) bool {
labels := res.GetLabels()
if ksName, ok := labels[FLUX_KUSTOMIZE_NAME_LABEL]; ok {
if ksNamespace, ok := labels[FLUX_KUSTOMIZE_NAMESPACE_LABEL]; ok {
if hasResource(kustomizations, ksName, ksNamespace) {
return true
} else {
logger.Debugf("kustomization [%s.%s] not found from resource %s %s %s\n", ksName, ksNamespace, res.GetName(), res.GetNamespace(), res.GetAPIVersion())
}
}
}

return false
}
}

func hasResource(pool []unstructured.Unstructured, name, namespace string) bool {
for _, res := range pool {
if res.GetName() == name && res.GetNamespace() == namespace {
return true
}
}

return false
}
Loading

0 comments on commit 2c8f346

Please sign in to comment.