Skip to content

Commit

Permalink
Added ignore_list_functionality (#252)
Browse files Browse the repository at this point in the history
* Added ignore_list_functionality

* Fixed typo found by lint

* Add nil check in filter

* Add test cases for chartIgnoreList

* update documentation

* Address logic comments
  • Loading branch information
RohitKochhar authored Sep 12, 2023
1 parent 8505305 commit 38212b4
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 13 deletions.
14 changes: 13 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ func init() {
klog.Exitf("Failed to bind show-old flag: %v", err)
}

findCmd.Flags().StringSlice("release-ignore-list", []string{}, "List of Helm release names to ignore")
err = viper.BindPFlag("release-ignore-list", findCmd.Flags().Lookup("release-ignore-list"))
if err != nil {
klog.Exitf("Failed to bind release-ignore-list flag: %v", err)
}

findCmd.Flags().StringSlice("chart-ignore-list", []string{}, "List of Helm chart names to ignore")
err = viper.BindPFlag("chart-ignore-list", findCmd.Flags().Lookup("chart-ignore-list"))
if err != nil {
klog.Exitf("Failed to bind chart-ignore-list flag: %v", err)
}

klog.InitFlags(nil)
_ = flag.Set("alsologtostderr", "true")
_ = flag.Set("logtostderr", "true")
Expand Down Expand Up @@ -365,7 +377,7 @@ func handleHelm(kubeContext string) (*output.Output, error) {
} else {
klog.V(3).Infof("Scanning whole cluster")
}
releases, _, err := h.GetReleaseOutput(namespace)
releases, _, err := h.GetReleaseOutput(namespace, viper.GetStringSlice("release-ignore-list"), viper.GetStringSlice("chart-ignore-list"))
if err != nil {
return nil, fmt.Errorf("error getting helm releases: %s", err)
}
Expand Down
19 changes: 11 additions & 8 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,27 @@ nova find --wide
## Options
```
Flags:
--containers Show old container image versions. There will be no helm output unless the --helm flag is set as well
--helm Show old helm releases. You can combine this flag with `--containers` to have both output in a single run.
-h, --help help for find
--show-errored-containers When finding container images, show errors encountered when scanning.
--show-non-semver When finding container images, show all containers even if they don't follow semver.
-t, --timeout uint16 When finding container images, the time in seconds before canceling the operation. (default 10)
--chart-ignore-list strings List of Helm chart names to ignore
--containers Show old container image versions instead of helm chart versions. There will be no helm output if this flag is set.
--helm Show old helm chart versions. You can combine this flag with --containers to have both output in a single run.
-h, --help help for find
--release-ignore-list strings List of Helm release names to ignore
--show-errored-containers When finding container images, show errors encountered when scanning.
--show-non-semver When finding container images, show all containers even if they don't follow semver.
-t, --timeout uint16 When finding container images, the time in seconds before canceling the operation. (default 10)
Global Flags:
--alsologtostderr log to standard error as well as files (default true)
--alsologtostderr log to standard error as well as files (no effect when -logtostderr=true) (default true)
--config string Config file to use. If empty, flags will be used instead
--context string A context to use in the kubeconfig.
-d, --desired-versions stringToString A map of chart=override_version to override the helm repository when checking. (default [])
--format string An output format (table, json) (default "json")
-a, --include-all Show all charts even if no latest version is found.
--logtostderr log to standard error instead of files (default true)
-n, --namespace string Namespace to look in. If empty, scan will be cluster-wide
--output-file string Path on local filesystem to write file output to
--poll-artifacthub When true, polls artifacthub to match against helm releases in the cluster. If false, you must provide a url list via --url/-u. Default is true. (default true)
--show-old Only output charts that are not on the latest version
--show-old Only show charts that are not on the latest version
-u, --url strings URL for a helm chart repo
-v, --v Level number for the log level verbosity
--wide Output chart name and namespace
Expand Down
42 changes: 38 additions & 4 deletions pkg/helm/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ func NewHelm(kubeContext string) *Helm {
}

// GetReleaseOutput returns releases and chart names
func (h *Helm) GetReleaseOutput(namespace string) ([]*release.Release, []string, error) {
func (h *Helm) GetReleaseOutput(namespace string, releaseIgnoreList []string, chartIgnoreList []string) ([]*release.Release, []string, error) {
var chartNames = []string{}
outputObjects, err := h.GetHelmReleases(namespace)
outputObjects, err := h.GetHelmReleases(namespace, releaseIgnoreList, chartIgnoreList)
if err != nil {
err = fmt.Errorf("could not detect helm 3 charts: %v", err)
}
Expand All @@ -62,15 +62,17 @@ func (h *Helm) GetReleaseOutput(namespace string) ([]*release.Release, []string,
}

// GetHelmReleases returns a list of helm releases from the cluster
func (h *Helm) GetHelmReleases(namespace string) ([]*release.Release, error) {
func (h *Helm) GetHelmReleases(namespace string, releaseIgnoreList []string, chartIgnoreList []string) ([]*release.Release, error) {
hs := helmdriver.NewSecrets(h.Kube.Client.CoreV1().Secrets(namespace))
helmClient := helmstorage.Init(hs)
deployed, err := helmClient.ListDeployed()

filteredDeployed := filterIgnoredReleases(deployed, releaseIgnoreList, chartIgnoreList)

if err != nil {
return nil, err
}
return deployed, nil
return filteredDeployed, nil
}

// OverrideDesiredVersion accepts a list of releases and overrides the version stored in the helm struct where required
Expand All @@ -87,3 +89,35 @@ func (h *Helm) OverrideDesiredVersion(rls *output.ReleaseOutput) {
}
}
}

// filterIgnoredReleases is a helper function that removes charts that match a release name or chart name
// provided by the user at runtime from the list of found charts in the cluster
func filterIgnoredReleases(deployed []*release.Release, releaseIgnoreList []string, chartIgnoreList []string) []*release.Release {
// Filter out any ignored releases
filteredDeployed := []*release.Release{}

for _, release := range deployed {
isIgnoredRelease := false
isIgnoredChart := false
for _, ignoreListedRelease := range releaseIgnoreList {
if release.Name == ignoreListedRelease {
isIgnoredRelease = true
break
}
}
for _, ignoreListedChart := range chartIgnoreList {
// Check for nil to avoid a potential nil pointer exception
if release.Chart != nil {
if release.Chart.Name() == ignoreListedChart {
isIgnoredChart = true
break
}
}
}
if !isIgnoredChart && !isIgnoredRelease {
filteredDeployed = append(filteredDeployed, release)
}
}

return filteredDeployed
}
183 changes: 183 additions & 0 deletions pkg/helm/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (

"github.com/fairwindsops/nova/pkg/output"
"github.com/stretchr/testify/assert"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/release"
)

func TestHelm_OverrideDesiredVersion(t *testing.T) {
Expand Down Expand Up @@ -82,3 +84,184 @@ func TestHelm_OverrideDesiredVersion(t *testing.T) {
})
}
}

func TestHelm_filterIgnoredReleases(t *testing.T) {
tests := []struct {
name string // Name of test case
releaseIgnoreList []string // List of release names to be ignored
chartIgnoreList []string // List of charts to be ignored
input []*release.Release // Input to filtering function
want []*release.Release // Output from filtering function
}{
{
name: "EmptyInput",
releaseIgnoreList: []string{},
chartIgnoreList: []string{},
input: []*release.Release{},
want: []*release.Release{},
},
{
name: "NoIgnoredReleasesOrCharts",
releaseIgnoreList: []string{},
chartIgnoreList: []string{},
input: []*release.Release{
{
Name: "foo",
},
},
want: []*release.Release{
{
Name: "foo",
},
},
},
{
name: "AllIgnoredReleases",
releaseIgnoreList: []string{
"foo",
},
chartIgnoreList: []string{},
input: []*release.Release{
{
Name: "foo",
},
},
want: []*release.Release{},
},
{
name: "SomeIgnoredReleases",
releaseIgnoreList: []string{
"foo",
},
chartIgnoreList: []string{},
input: []*release.Release{
{
Name: "foo",
},
{
Name: "bar",
},
},
want: []*release.Release{{
Name: "bar",
}},
},
{
name: "AllIgnoredCharts",
releaseIgnoreList: []string{},
chartIgnoreList: []string{"foo"},
input: []*release.Release{
{
Name: "bar",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
},
},
},
},
want: []*release.Release{},
},
{
name: "SomeIgnoredCharts",
releaseIgnoreList: []string{},
chartIgnoreList: []string{
"foo",
},
input: []*release.Release{
{
Name: "foo1",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
},
},
},
{
Name: "foo2",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "bar",
},
},
},
},
want: []*release.Release{{
Name: "foo2",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "bar",
},
},
}},
},
{
name: "SomeIgnoredReleasesAndCharts",
releaseIgnoreList: []string{
"bar",
},
chartIgnoreList: []string{
"foo",
},
input: []*release.Release{
{
Name: "foo1",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
},
},
},
{
Name: "foo2",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "bar",
},
},
},
{
Name: "bar",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "foo",
},
},
},
{
Name: "foo3",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "bar",
},
},
},
},
want: []*release.Release{{
Name: "foo2",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "bar",
},
},
},
{
Name: "foo3",
Chart: &chart.Chart{
Metadata: &chart.Metadata{
Name: "bar",
},
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
output := filterIgnoredReleases(tt.input, tt.releaseIgnoreList, tt.chartIgnoreList)
if len(output) != len(tt.want) {
t.Fatalf("filtering did not catch all cases, expected %d releases, instead got %d", len(tt.want), len(output))
}
})
}
}

0 comments on commit 38212b4

Please sign in to comment.