Merge "Add filtering method for document bundle"

This commit is contained in:
Zuul 2020-03-25 13:29:14 +00:00 committed by Gerrit Code Review
commit 14f52863e0
2 changed files with 107 additions and 9 deletions

View File

@ -1,6 +1,7 @@
package document
import (
"errors"
"fmt"
"io"
@ -12,6 +13,7 @@ import (
"sigs.k8s.io/kustomize/v3/pkg/resmap"
"sigs.k8s.io/kustomize/v3/pkg/resource"
"sigs.k8s.io/kustomize/v3/pkg/target"
"sigs.k8s.io/kustomize/v3/pkg/types"
docplugins "opendev.org/airship/airshipctl/pkg/document/plugins"
"opendev.org/airship/airshipctl/pkg/log"
@ -46,6 +48,7 @@ type Bundle interface {
GetFileSystem() FileSystem
Select(selector Selector) ([]Document, error)
SelectBundle(selector Selector) (Bundle, error)
SelectByFieldValue(string, func(interface{}) bool) (Bundle, error)
GetByGvk(string, string, string) ([]Document, error)
GetByName(string) (Document, error)
GetByAnnotation(annotationSelector string) ([]Document, error)
@ -241,6 +244,89 @@ func (b *BundleFactory) SelectBundle(selector Selector) (Bundle, error) {
}, nil
}
// SelectByFieldValue returns new Bundle with filtered resource documents.
// Method iterates over all resources in the bundle. If resource has field
// (i.e. key) specified in JSON path, and the comparison function returns
// 'true' for value referenced by JSON path, then resource is added to
// resulting bundle.
// Example:
// The bundle contains 3 documents
//
// ---
// apiVersion: v1
// kind: DocKind1
// metadata:
// name: doc1
// spec:
// somekey:
// somefield: "someValue"
// ---
// apiVersion: v1
// kind: DocKind2
// metadata:
// name: doc2
// spec:
// somekey:
// somefield: "someValue"
// ---
// apiVersion: v1
// kind: DocKind1
// metadata:
// name: doc3
// spec:
// somekey:
// somefield: "someOtherValue"
//
// Execution of bundleInstance.SelectByFieldValue(
// "spec.somekey.somefield",
// func(v interface{}) { return v == "someValue" })
// will return a new Bundle instance containing 2 documents:
// ---
// apiVersion: v1
// kind: DocKind1
// metadata:
// name: doc1
// spec:
// somekey:
// somefield: "someValue"
// ---
// apiVersion: v1
// kind: DocKind2
// metadata:
// name: doc2
// spec:
// somekey:
// somefield: "someValue"
func (b *BundleFactory) SelectByFieldValue(path string, condition func(interface{}) bool) (Bundle, error) {
result := &BundleFactory{
KustomizeBuildOptions: b.KustomizeBuildOptions,
FileSystem: b.FileSystem,
}
resourceMap := resmap.New()
for _, res := range b.Resources() {
val, err := res.GetFieldValue(path)
if err != nil {
if errors.As(err, &types.NoFieldError{}) {
// this resource doesn't have the specified field - skip it
continue
} else {
return nil, err
}
}
if condition(val) {
if err = resourceMap.Append(res); err != nil {
return nil, err
}
}
}
if err := result.SetKustomizeResourceMap(resourceMap); err != nil {
return nil, err
}
return result, nil
}
// GetByAnnotation is a convenience method to get documents for a particular annotation
func (b *BundleFactory) GetByAnnotation(annotationSelector string) ([]Document, error) {
// Construct kustomize annotation selector

View File

@ -28,21 +28,21 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.GetByGvk("apps", "v1", "Deployment")
require.NoError(err)
assert.Len(docs, 3, "GetGvk returned the wrong number of resources")
assert.Len(docs, 3)
})
t.Run("GetByAnnotation", func(t *testing.T) {
docs, err := bundle.GetByAnnotation("airshipit.org/clustertype=ephemeral")
require.NoError(err, "Error trying to GetByAnnotation")
assert.Len(docs, 4, "GetByAnnotation returned wrong number of resources")
assert.Len(docs, 4)
})
t.Run("GetByLabel", func(t *testing.T) {
docs, err := bundle.GetByLabel("app=workflow-controller")
require.NoError(err, "Error trying to GetByLabel")
assert.Len(docs, 1, "GetByLabel returned wrong number of resources")
assert.Len(docs, 1)
})
t.Run("SelectGvk", func(t *testing.T) {
@ -53,7 +53,7 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.Select(selector)
require.NoError(err, "Error trying to select resources")
assert.Len(docs, 3, "SelectGvk returned wrong number of resources")
assert.Len(docs, 3)
})
t.Run("SelectAnnotations", func(t *testing.T) {
@ -62,7 +62,7 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.Select(selector)
require.NoError(err, "Error trying to select annotated resources")
assert.Len(docs, 4, "SelectAnnotations returned wrong number of resources")
assert.Len(docs, 4)
})
t.Run("SelectLabels", func(t *testing.T) {
@ -73,7 +73,7 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.Select(selector)
require.NoError(err, "Error trying to select labeled resources")
assert.Len(docs, 1, "SelectLabels returned wrong number of resources")
assert.Len(docs, 1)
})
t.Run("SelectByLabelAndName", func(t *testing.T) {
@ -83,7 +83,7 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.Select(selector)
require.NoError(err, "Error trying to select labeled with name resources")
assert.Len(docs, 1, "SelectByLabelAndName returned wrong number of resources")
assert.Len(docs, 1)
})
t.Run("SelectByTwoLabels", func(t *testing.T) {
@ -94,7 +94,7 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.Select(selector)
require.NoError(err, "Error trying to select by two labels")
assert.Len(docs, 1, "SelectByTwoLabels returned wrong number of resources")
assert.Len(docs, 1)
assert.Equal("workflow-controller", docs[0].GetName())
})
@ -107,10 +107,22 @@ func TestBundleDocumentFiltering(t *testing.T) {
docs, err := bundle.Select(selector)
require.NoError(err, "Error trying to select by two annotations")
assert.Len(docs, 1, "SelectByTwoAnnotations returned wrong number of resources")
assert.Len(docs, 1)
assert.Equal("argo-ui", docs[0].GetName())
})
t.Run("SelectByFieldValue", func(t *testing.T) {
// Find documents with a particular value referenced by JSON path
filter := func(val interface{}) bool { return val == "01:3b:8b:0c:ec:8b" }
filteredBundle, err := bundle.SelectByFieldValue("spec.bootMACAddress", filter)
require.NoError(err, "Error trying to filter resources")
docs, err := filteredBundle.GetAllDocuments()
require.NoError(err)
assert.Len(docs, 1)
assert.Equal(docs[0].GetKind(), "BareMetalHost")
assert.Equal(docs[0].GetName(), "master-1")
})
t.Run("Write", func(t *testing.T) {
// Ensure we can write out a bundle
//