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:
@@ -204,19 +204,36 @@ func NewBuilder(name, resources string, opts ...BuilderOptionFunc) (*Builder, er
|
||||
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) {
|
||||
liveKus := &kustomizev1.Kustomization{}
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: b.namespace,
|
||||
Name: b.name,
|
||||
}
|
||||
|
||||
k := &kustomizev1.Kustomization{}
|
||||
err := b.client.Get(ctx, namespacedName, k)
|
||||
err := b.client.Get(ctx, namespacedName, liveKus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return k, nil
|
||||
return liveKus, nil
|
||||
}
|
||||
|
||||
// Build builds the yaml manifests from the kustomization object
|
||||
@@ -251,19 +268,18 @@ func (b *Builder) build() (m resmap.ResMap, err error) {
|
||||
defer cancel()
|
||||
|
||||
// Get the kustomization object
|
||||
var k *kustomizev1.Kustomization
|
||||
if b.kustomizationFile != "" {
|
||||
k, err = b.unMarshallKustomization()
|
||||
liveKus := &kustomizev1.Kustomization{}
|
||||
if !b.dryRun {
|
||||
liveKus, err = b.getKustomization(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
k, err = b.getKustomization(ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to get kustomization object: %w", err)
|
||||
return
|
||||
return nil, fmt.Errorf("failed to get kustomization object: %w", err)
|
||||
}
|
||||
}
|
||||
k, err := b.resolveKustomization(liveKus)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to get kustomization object: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// store the kustomization object
|
||||
b.kustomization = k
|
||||
|
||||
@@ -17,10 +17,15 @@ limitations under the License.
|
||||
package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"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 {
|
||||
oldStatus := b.kustomization.Status.DeepCopy()
|
||||
if oldStatus.Inventory != nil {
|
||||
diffObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
||||
staleObjects, err := diffInventory(oldStatus.Inventory, newInventory)
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user