diff --git a/README.md b/README.md index 0e7935e..643600f 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,9 @@ namespace-selectors: # # Will exclude the default, kube-system, and kube-public namespaces exclude: [] + + # If true then namespaces containing 0 pods will be omitted from the report sent to Anchore Enterprise + ignore-empty: false ``` ### Kubernetes API Parameters diff --git a/anchore-k8s-inventory.yaml b/anchore-k8s-inventory.yaml index 22e527e..baef7a8 100644 --- a/anchore-k8s-inventory.yaml +++ b/anchore-k8s-inventory.yaml @@ -41,6 +41,8 @@ namespace-selectors: # Will exclude the default, kube-system, and kube-public namespaces exclude: [] + ignore-empty: false + # Kubernetes API configuration parameters (should not need tuning) kubernetes: # Sets the request timeout for kubernetes API requests diff --git a/internal/config/config.go b/internal/config/config.go index 4bf1c88..cc0dc32 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -63,8 +63,9 @@ type MissingTagConf struct { // NamespaceSelector details the inclusion/exclusion rules for namespaces type NamespaceSelector struct { - Include []string `mapstructure:"include"` - Exclude []string `mapstructure:"exclude"` + Include []string `mapstructure:"include"` + Exclude []string `mapstructure:"exclude"` + IgnoreEmpty bool `mapstructure:"ignore-empty"` } // KubernetesAPI details the configuration for interacting with the k8s api server @@ -128,6 +129,7 @@ func setNonCliDefaultValues(v *viper.Viper) { v.SetDefault("namespaces", []string{}) v.SetDefault("namespace-selectors.include", []string{}) v.SetDefault("namespace-selectors.exclude", []string{}) + v.SetDefault("namespace-selectors.ignore-empty", false) } // Load the Application Configuration from the Viper specifications diff --git a/internal/config/test-fixtures/snapshot/TestDefaultConfigString.golden b/internal/config/test-fixtures/snapshot/TestDefaultConfigString.golden index 5c3fecb..b33a22e 100644 --- a/internal/config/test-fixtures/snapshot/TestDefaultConfigString.golden +++ b/internal/config/test-fixtures/snapshot/TestDefaultConfigString.golden @@ -30,6 +30,7 @@ kubernetesrequesttimeoutseconds: -1 namespaceselectors: include: [] exclude: [] + ignoreempty: false missingtagpolicy: policy: digest tag: UNKNOWN diff --git a/internal/config/test-fixtures/snapshot/TestEmptyConfigString.golden b/internal/config/test-fixtures/snapshot/TestEmptyConfigString.golden index 7ee1586..5f22d47 100644 --- a/internal/config/test-fixtures/snapshot/TestEmptyConfigString.golden +++ b/internal/config/test-fixtures/snapshot/TestEmptyConfigString.golden @@ -30,6 +30,7 @@ kubernetesrequesttimeoutseconds: 0 namespaceselectors: include: [] exclude: [] + ignoreempty: false missingtagpolicy: policy: "" tag: "" diff --git a/internal/config/test-fixtures/snapshot/TestSensitiveConfigString.golden b/internal/config/test-fixtures/snapshot/TestSensitiveConfigString.golden index 7c3b5f2..09a6260 100644 --- a/internal/config/test-fixtures/snapshot/TestSensitiveConfigString.golden +++ b/internal/config/test-fixtures/snapshot/TestSensitiveConfigString.golden @@ -30,6 +30,7 @@ kubernetesrequesttimeoutseconds: -1 namespaceselectors: include: [] exclude: [] + ignoreempty: false missingtagpolicy: policy: digest tag: UNKNOWN diff --git a/pkg/lib.go b/pkg/lib.go index 901701e..db753a9 100644 --- a/pkg/lib.go +++ b/pkg/lib.go @@ -22,6 +22,7 @@ import ( ) type ReportItem struct { + Namespace inventory.Namespace Pods []inventory.Pod Containers []inventory.Container } @@ -169,10 +170,16 @@ func GetInventoryReport(cfg *config.Application) (inventory.Report, error) { results := make([]ReportItem, 0) pods := make([]inventory.Pod, 0) containers := make([]inventory.Container, 0) + processedNamespaces := make([]inventory.Namespace, 0) for len(results) < len(namespaces) { select { case item := <-ch.reportItem: results = append(results, item) + if cfg.NamespaceSelectors.IgnoreEmpty && len(item.Pods) == 0 { + log.Debugf("Ignoring namespace \"%s\" as it has no pods", item.Namespace.Name) + continue + } + processedNamespaces = append(processedNamespaces, item.Namespace) pods = append(pods, item.Pods...) containers = append(containers, item.Containers...) case err := <-ch.errors: @@ -196,12 +203,12 @@ func GetInventoryReport(cfg *config.Application) (inventory.Report, error) { nodes = append(nodes, node) } - log.Infof("Got Inventory Report with %d containers running across %d namespaces", len(containers), len(namespaces)) + log.Infof("Got Inventory Report with %d containers running across %d namespaces", len(containers), len(processedNamespaces)) return inventory.Report{ Timestamp: time.Now().UTC().Format(time.RFC3339), Containers: containers, Pods: pods, - Namespaces: namespaces, + Namespaces: processedNamespaces, Nodes: nodes, ServerVersionMetadata: serverVersion, ClusterName: cfg.KubeConfig.Cluster, @@ -226,6 +233,14 @@ func processNamespace( return } + if len(v1pods) == 0 { + log.Infof("No pods found in namespace \"%s\"", ns.Name) + ch.reportItem <- ReportItem{ + Namespace: ns, + } + return + } + pods := inventory.ProcessPods(v1pods, ns.UID, nodes) containers := inventory.GetContainersFromPods( v1pods, @@ -235,6 +250,7 @@ func processNamespace( ) reportItem := ReportItem{ + Namespace: ns, Pods: pods, Containers: containers, }