Take into account the server-side inventory for local diff
If implemented users will be able to use a local kustomization file while retrieving status from the live kustomization file. Signed-off-by: Soule BA <soule@weave.works>
This commit is contained in:
@@ -159,6 +159,7 @@ spec:
|
|||||||
tmpl := map[string]string{
|
tmpl := map[string]string{
|
||||||
"fluxns": allocateNamespace("flux-system"),
|
"fluxns": allocateNamespace("flux-system"),
|
||||||
}
|
}
|
||||||
|
setup(t, tmpl)
|
||||||
|
|
||||||
testEnv.CreateObjectFile("./testdata/build-kustomization/podinfo-source.yaml", tmpl, t)
|
testEnv.CreateObjectFile("./testdata/build-kustomization/podinfo-source.yaml", tmpl, t)
|
||||||
|
|
||||||
|
|||||||
@@ -204,19 +204,36 @@ func NewBuilder(name, resources string, opts ...BuilderOptionFunc) (*Builder, er
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Builder) resolveKustomization(liveKus *kustomizev1.Kustomization) (k *kustomizev1.Kustomization, err error) {
|
||||||
|
// local kustomization file takes precedence over live kustomization
|
||||||
|
if b.kustomizationFile != "" {
|
||||||
|
k, err = b.unMarshallKustomization()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !b.dryRun && liveKus != nil && liveKus.Status.Inventory != nil {
|
||||||
|
// merge the live kustomization status with the local kustomization in order to get the
|
||||||
|
// live resources status
|
||||||
|
k.Status = *liveKus.Status.DeepCopy()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
k = liveKus
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Builder) getKustomization(ctx context.Context) (*kustomizev1.Kustomization, error) {
|
func (b *Builder) getKustomization(ctx context.Context) (*kustomizev1.Kustomization, error) {
|
||||||
|
liveKus := &kustomizev1.Kustomization{}
|
||||||
namespacedName := types.NamespacedName{
|
namespacedName := types.NamespacedName{
|
||||||
Namespace: b.namespace,
|
Namespace: b.namespace,
|
||||||
Name: b.name,
|
Name: b.name,
|
||||||
}
|
}
|
||||||
|
err := b.client.Get(ctx, namespacedName, liveKus)
|
||||||
k := &kustomizev1.Kustomization{}
|
|
||||||
err := b.client.Get(ctx, namespacedName, k)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return k, nil
|
return liveKus, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build builds the yaml manifests from the kustomization object
|
// Build builds the yaml manifests from the kustomization object
|
||||||
@@ -251,19 +268,18 @@ func (b *Builder) build() (m resmap.ResMap, err error) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Get the kustomization object
|
// Get the kustomization object
|
||||||
var k *kustomizev1.Kustomization
|
liveKus := &kustomizev1.Kustomization{}
|
||||||
if b.kustomizationFile != "" {
|
if !b.dryRun {
|
||||||
k, err = b.unMarshallKustomization()
|
liveKus, err = b.getKustomization(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, fmt.Errorf("failed to get kustomization object: %w", err)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
k, err = b.getKustomization(ctx)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("failed to get kustomization object: %w", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
k, err := b.resolveKustomization(liveKus)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to get kustomization object: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// store the kustomization object
|
// store the kustomization object
|
||||||
b.kustomization = k
|
b.kustomization = k
|
||||||
|
|||||||
@@ -17,10 +17,15 @@ limitations under the License.
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
@@ -215,3 +220,135 @@ func Test_unMarshallKustomization(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ResolveKustomization(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
localKsFile string
|
||||||
|
liveKustomization *kustomizev1.Kustomization
|
||||||
|
dryrun bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid kustomization",
|
||||||
|
localKsFile: "testdata/local-kustomization/valid.yaml",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "local and live kustomization",
|
||||||
|
localKsFile: "testdata/local-kustomization/valid.yaml",
|
||||||
|
liveKustomization: &kustomizev1.Kustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "podinfo",
|
||||||
|
Namespace: "flux-system",
|
||||||
|
},
|
||||||
|
Spec: kustomizev1.KustomizationSpec{
|
||||||
|
Interval: metav1.Duration{Duration: time.Minute * 5},
|
||||||
|
Path: "./testdata/local-kustomization/valid.yaml",
|
||||||
|
},
|
||||||
|
Status: kustomizev1.KustomizationStatus{
|
||||||
|
Conditions: []metav1.Condition{
|
||||||
|
{
|
||||||
|
Type: meta.ReadyCondition,
|
||||||
|
Status: metav1.ConditionTrue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Inventory: &kustomizev1.ResourceInventory{
|
||||||
|
Entries: []kustomizev1.ResourceRef{
|
||||||
|
{
|
||||||
|
ID: "flux-system_podinfo_v1_service_podinfo",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "local and live kustomization with dryrun",
|
||||||
|
localKsFile: "testdata/local-kustomization/valid.yaml",
|
||||||
|
liveKustomization: &kustomizev1.Kustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "podinfo",
|
||||||
|
Namespace: "flux-system",
|
||||||
|
},
|
||||||
|
Spec: kustomizev1.KustomizationSpec{
|
||||||
|
Interval: metav1.Duration{Duration: time.Minute * 5},
|
||||||
|
Path: "./testdata/local-kustomization/valid.yaml",
|
||||||
|
},
|
||||||
|
Status: kustomizev1.KustomizationStatus{
|
||||||
|
Conditions: []metav1.Condition{
|
||||||
|
{
|
||||||
|
Type: meta.ReadyCondition,
|
||||||
|
Status: metav1.ConditionTrue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Inventory: &kustomizev1.ResourceInventory{
|
||||||
|
Entries: []kustomizev1.ResourceRef{
|
||||||
|
{
|
||||||
|
ID: "flux-system_podinfo_v1_service_podinfo",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
dryrun: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "live kustomization",
|
||||||
|
liveKustomization: &kustomizev1.Kustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "podinfo",
|
||||||
|
Namespace: "flux-system",
|
||||||
|
},
|
||||||
|
Spec: kustomizev1.KustomizationSpec{
|
||||||
|
Interval: metav1.Duration{Duration: time.Minute * 5},
|
||||||
|
Path: "./testdata/local-kustomization/valid.yaml",
|
||||||
|
},
|
||||||
|
Status: kustomizev1.KustomizationStatus{
|
||||||
|
Conditions: []metav1.Condition{
|
||||||
|
{
|
||||||
|
Type: meta.ReadyCondition,
|
||||||
|
Status: metav1.ConditionTrue,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Inventory: &kustomizev1.ResourceInventory{
|
||||||
|
Entries: []kustomizev1.ResourceRef{
|
||||||
|
{
|
||||||
|
ID: "flux-system_podinfo_v1_service_podinfo",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b := &Builder{}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
b.kustomizationFile = tt.localKsFile
|
||||||
|
b.dryRun = tt.dryrun
|
||||||
|
ks, err := b.resolveKustomization(tt.liveKustomization)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected err '%s'", err)
|
||||||
|
}
|
||||||
|
if !tt.dryrun {
|
||||||
|
if b.kustomizationFile == "" {
|
||||||
|
if cmp.Diff(ks, tt.liveKustomization) != "" {
|
||||||
|
t.Errorf("expected kustomization to match live kustomization")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if tt.liveKustomization != nil && cmp.Diff(ks.Status, tt.liveKustomization.Status) != "" {
|
||||||
|
t.Errorf("expected kustomization status to match live kustomization status")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ks.Status.Inventory != nil {
|
||||||
|
fmt.Println(ks.Status.Inventory)
|
||||||
|
t.Errorf("expected kustomization status to be nil")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -136,11 +136,14 @@ func (b *Builder) Diff() (string, bool, error) {
|
|||||||
if b.kustomization.Spec.Prune && len(diffErrs) == 0 {
|
if b.kustomization.Spec.Prune && len(diffErrs) == 0 {
|
||||||
oldStatus := b.kustomization.Status.DeepCopy()
|
oldStatus := b.kustomization.Status.DeepCopy()
|
||||||
if oldStatus.Inventory != nil {
|
if oldStatus.Inventory != nil {
|
||||||
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
staleObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", createdOrDrifted, err
|
return "", createdOrDrifted, err
|
||||||
}
|
}
|
||||||
for _, object := range diffObjects {
|
if len(staleObjects) > 0 {
|
||||||
|
createdOrDrifted = true
|
||||||
|
}
|
||||||
|
for _, object := range staleObjects {
|
||||||
output.WriteString(writeString(fmt.Sprintf("► %s deleted\n", ssa.FmtUnstructured(object)), bunt.OrangeRed))
|
output.WriteString(writeString(fmt.Sprintf("► %s deleted\n", ssa.FmtUnstructured(object)), bunt.OrangeRed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user