1
0
mirror of synced 2026-02-13 13:06:56 +00:00

Recursively build and diff Kustomizations

Signed-off-by: Boris Kreitchman <bkreitch@gmail.com>
This commit is contained in:
Boris Kreitchman
2024-08-09 18:11:28 +03:00
parent 1b4de026dd
commit 2d37544b06
14 changed files with 600 additions and 29 deletions

View File

@@ -26,6 +26,7 @@ import (
"github.com/fluxcd/pkg/apis/meta"
"github.com/google/go-cmp/cmp"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -361,3 +362,242 @@ func Test_ResolveKustomization(t *testing.T) {
})
}
}
func Test_isKustomization(t *testing.T) {
tests := []struct {
name string
expected bool
object *unstructured.Unstructured
}{
{
name: "flux kustomization",
object: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "kustomize.toolkit.fluxcd.io/v1",
"kind": "Kustomization",
},
},
expected: true,
},
{
name: "other kustomization",
object: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "kustomize.config.k8s.io/v1beta1",
"kind": "Kustomization",
},
},
expected: false,
},
{
name: "wrong kind",
object: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "kustomize.toolkit.fluxcd.io/v1",
"kind": "ConfigMap",
},
},
expected: false,
},
{
name: "wrong object",
object: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
},
},
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := isKustomization(tt.object)
if actual != tt.expected {
t.Fatalf("got '%v', want '%v'", actual, tt.expected)
}
})
}
}
func Test_kustomizationsEqual(t *testing.T) {
tests := []struct {
name string
kustomization1 *kustomizev1.Kustomization
kustomization2 *kustomizev1.Kustomization
expected bool
}{
{
name: "equal",
kustomization1: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Namespace: "flux-system",
},
},
kustomization2: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Namespace: "flux-system",
},
},
expected: true,
},
{
name: "wrong name",
kustomization1: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Namespace: "flux-system",
},
},
kustomization2: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "my-app",
Namespace: "flux-system",
},
},
expected: false,
},
{
name: "wrong namespace",
kustomization1: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Namespace: "flux-system",
},
},
kustomization2: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Namespace: "my-ns",
},
},
expected: false,
},
{
name: "wrong name and namespace",
kustomization1: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo",
Namespace: "flux-system",
},
},
kustomization2: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "my-app",
Namespace: "my-ns",
},
},
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := kustomizationsEqual(tt.kustomization1, tt.kustomization2)
if actual != tt.expected {
t.Fatalf("got '%v', want '%v'", actual, tt.expected)
}
})
}
}
func Test_kustomizationPath(t *testing.T) {
tests := []struct {
name string
kustomization *kustomizev1.Kustomization
expected string
wantErr bool
errString string
}{
{
name: "full repo",
kustomization: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "my-app",
Namespace: "flux-system",
},
Spec: kustomizev1.KustomizationSpec{
Path: "my-path",
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: "GitRepository",
Name: "my-repo",
Namespace: "flux-system",
},
},
},
expected: "path/to/local/git/my-path",
},
{
name: "repo without namespace",
kustomization: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "my-app",
Namespace: "flux-system",
},
Spec: kustomizev1.KustomizationSpec{
Path: "my-path",
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: "GitRepository",
Name: "my-repo",
Namespace: "",
},
},
},
expected: "path/to/local/git/my-path",
},
{
name: "repo not found",
kustomization: &kustomizev1.Kustomization{
ObjectMeta: metav1.ObjectMeta{
Name: "my-app",
Namespace: "flux-system",
},
Spec: kustomizev1.KustomizationSpec{
Path: "my-path",
SourceRef: kustomizev1.CrossNamespaceSourceReference{
Kind: "GitRepository",
Name: "my-repo",
Namespace: "my-ns",
},
},
},
wantErr: true,
errString: "cannot get local path",
},
}
b := &Builder{
name: "podinfo",
namespace: "flux-system",
localSources: map[string]string{
"GitRepository/flux-system/my-repo": "./path/to/local/git",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual, err := b.kustomizationPath(tt.kustomization)
if !tt.wantErr {
if err != nil {
t.Fatalf("unexpected err '%s'", err)
}
if actual != tt.expected {
t.Errorf("got '%v', want '%v'", actual, tt.expected)
}
} else {
if err == nil {
t.Fatal("expected error but got nil")
}
if !strings.Contains(err.Error(), tt.errString) {
t.Errorf("expected error '%s' to contain string '%s'", err.Error(), tt.errString)
}
}
})
}
}