Skip to content

Commit

Permalink
feat: adding helmchart gatherer
Browse files Browse the repository at this point in the history
  • Loading branch information
Ricardo Lüders committed Nov 27, 2023
1 parent ca5ff4f commit e57a5c1
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 144 deletions.
5 changes: 4 additions & 1 deletion pkg/gather/gather.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"strings"
"time"

"github.com/openshift/insights-operator/pkg/gatherers/helmcharts"

"k8s.io/client-go/rest"
"k8s.io/klog/v2"

Expand Down Expand Up @@ -72,8 +74,9 @@ func CreateAllGatherers(
conditionalGatherer := conditional.New(
gatherProtoKubeConfig, metricsGatherKubeConfig, gatherKubeConfig, configObserver, insightsClient,
)
helmChartsGatherer := helmcharts.New(gatherKubeConfig, gatherProtoKubeConfig)

return []gatherers.Interface{clusterConfigGatherer, workloadsGatherer, conditionalGatherer}
return []gatherers.Interface{clusterConfigGatherer, workloadsGatherer, conditionalGatherer, helmChartsGatherer}
}

// CollectAndRecordGatherer gathers enabled functions of the provided gatherer and records the results to the recorder
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package workloads
package helmcharts

import (
"context"
Expand All @@ -20,49 +20,6 @@ import (

const LabelChartNameKey = "helm.sh/chart"

type HelmChartInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Resources map[string]int `json:"resources"`
}

type HelmChartInfoList struct {
Namespaces map[string][]HelmChartInfo
}

func newHelmChartInfoList() HelmChartInfoList {
return HelmChartInfoList{
Namespaces: make(map[string][]HelmChartInfo),
}
}

func (h *HelmChartInfoList) addItem(ns string, resourceType string, info HelmChartInfo) {
if _, ok := h.Namespaces[ns]; !ok {
h.Namespaces[ns] = make([]HelmChartInfo, 0)
}

var helmIdx int
var found bool
for i, n := range h.Namespaces[ns] {
if n.Name == info.Name && n.Version == info.Version {
helmIdx = i
found = true
break
}
}

if !found {
info.Resources = map[string]int{resourceType: 1}
h.Namespaces[ns] = append(h.Namespaces[ns], info)
return
}

if h.Namespaces[ns][helmIdx].Resources == nil {
h.Namespaces[ns][helmIdx].Resources = make(map[string]int)
}
h.Namespaces[ns][helmIdx].Resources[resourceType]++
}

// GatherHelmInfo Collects summarized info about the helm usage on a cluster
// in a generic fashion
//
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package workloads
package helmcharts

import (
"context"
Expand Down Expand Up @@ -148,104 +148,6 @@ func TestGatherHelmInfo(t *testing.T) {
}
}

func TestAddItem(t *testing.T) {
tests := []struct {
name string
info map[string]map[string][]HelmChartInfo
expectedList map[string][]HelmChartInfo
}{
{
name: "two namespaces, two charts and multiple resources",
info: map[string]map[string][]HelmChartInfo{
"mynamespace": {
"deployments": {
{Name: "mychart1", Version: "1.0.0"},
},
"statefulsets": {
{Name: "mychart2", Version: "2.0.0"},
},
},
"mynamespace2": {
"deployments": {
{Name: "mychart1", Version: "1.0.0"},
{Name: "mychart1", Version: "1.0.0"},
},
"statefulsets": {
{Name: "mychart1", Version: "1.0.0"},
{Name: "mychart1", Version: "2.0.0"},
},
},
},
expectedList: map[string][]HelmChartInfo{
"mynamespace": {
{
Name: "mychart1",
Version: "1.0.0",
Resources: map[string]int{"deployments": 1},
},
{
Name: "mychart2",
Version: "2.0.0",
Resources: map[string]int{"statefulsets": 1},
},
},
"mynamespace2": {
{
Name: "mychart1",
Version: "1.0.0",
Resources: map[string]int{"deployments": 2, "statefulsets": 1},
},
{
Name: "mychart1",
Version: "2.0.0",
Resources: map[string]int{"statefulsets": 1},
},
},
},
},
{
name: "one namespace, two resources for the same chart",
info: map[string]map[string][]HelmChartInfo{
"mynamespace": {
"deployments": {
{Name: "mychart1", Version: "1.0.0"},
},
"statefulsets": {
{Name: "mychart1", Version: "1.0.0"},
},
},
},
expectedList: map[string][]HelmChartInfo{
"mynamespace": {
{
Name: "mychart1",
Version: "1.0.0",
Resources: map[string]int{"deployments": 1, "statefulsets": 1},
},
},
},
},
}

for _, testCase := range tests {
tt := testCase
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

helmList := newHelmChartInfoList()
for namespace, resources := range tt.info {
for resource, charts := range resources {
for _, chartInfo := range charts {
helmList.addItem(namespace, resource, chartInfo)
}
}
}

assert.Equal(t, tt.expectedList, helmList.Namespaces, "expected '%v', got '%v'", tt.expectedList, helmList.Namespaces)
})
}
}

func TestHelmChartNameAndVersion(t *testing.T) {
type args struct {
chart string
Expand Down
49 changes: 49 additions & 0 deletions pkg/gatherers/helmcharts/helmcharts_gatherer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package helmcharts

import (
"context"
"time"

"github.com/openshift/insights-operator/pkg/gatherers"
"github.com/openshift/insights-operator/pkg/record"
"github.com/openshift/insights-operator/pkg/utils"
"k8s.io/client-go/rest"
)

var helmChartsGathererPeriod = time.Hour * 24

type Gatherer struct {
gatherKubeConfig *rest.Config
gatherProtoKubeConfig *rest.Config
lastProcessingTime time.Time
}

func New(gatherKubeConfig, gatherProtoKubeConfig *rest.Config) *Gatherer {
return &Gatherer{
gatherKubeConfig: gatherKubeConfig,
gatherProtoKubeConfig: gatherProtoKubeConfig,
lastProcessingTime: time.Unix(0, 0),
}
}

func (g *Gatherer) GetName() string {
return "helmcharts"
}

func (g *Gatherer) GetGatheringFunctions(context.Context) (map[string]gatherers.GatheringClosure, error) {
return map[string]gatherers.GatheringClosure{
"helm_info": {
Run: func(ctx context.Context) ([]record.Record, []error) {
return g.GatherHelmInfo(ctx)
},
},
}, nil
}

func (g *Gatherer) ShouldBeProcessedNow() bool {
return utils.ShouldBeProcessedNow(g.lastProcessingTime, helmChartsGathererPeriod)
}

func (g *Gatherer) UpdateLastProcessingTime() {
g.lastProcessingTime = time.Now()
}
20 changes: 20 additions & 0 deletions pkg/gatherers/helmcharts/helmcharts_gatherer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package helmcharts

import (
"context"
"testing"

"github.com/openshift/insights-operator/pkg/gatherers"
"github.com/stretchr/testify/assert"
)

func Test_Gatherer_Basic(t *testing.T) {
gatherer := New(nil, nil)
assert.Equal(t, "helmcharts", gatherer.GetName())
gatheringFunctions, err := gatherer.GetGatheringFunctions(context.TODO())
assert.NoError(t, err)
assert.Greater(t, len(gatheringFunctions), 0)

assert.Implements(t, (*gatherers.Interface)(nil), gatherer)
assert.Implements(t, (*gatherers.CustomPeriodGatherer)(nil), gatherer)
}
44 changes: 44 additions & 0 deletions pkg/gatherers/helmcharts/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package helmcharts

type HelmChartInfo struct {
Name string `json:"name"`
Version string `json:"version"`
Resources map[string]int `json:"resources"`
}

type HelmChartInfoList struct {
Namespaces map[string][]HelmChartInfo
}

func newHelmChartInfoList() HelmChartInfoList {
return HelmChartInfoList{
Namespaces: make(map[string][]HelmChartInfo),
}
}

func (h *HelmChartInfoList) addItem(ns string, resourceType string, info HelmChartInfo) {
if _, ok := h.Namespaces[ns]; !ok {
h.Namespaces[ns] = make([]HelmChartInfo, 0)
}

var helmIdx int
var found bool
for i, n := range h.Namespaces[ns] {
if n.Name == info.Name && n.Version == info.Version {
helmIdx = i
found = true
break
}
}

if !found {
info.Resources = map[string]int{resourceType: 1}
h.Namespaces[ns] = append(h.Namespaces[ns], info)
return
}

if h.Namespaces[ns][helmIdx].Resources == nil {
h.Namespaces[ns][helmIdx].Resources = make(map[string]int)
}
h.Namespaces[ns][helmIdx].Resources[resourceType]++
}

0 comments on commit e57a5c1

Please sign in to comment.