Skip to content

Commit

Permalink
update prune to accept of slice of unstrucured
Browse files Browse the repository at this point in the history
  • Loading branch information
Liujingfang1 committed Jul 1, 2019
1 parent d34d1f5 commit 016c4ba
Show file tree
Hide file tree
Showing 12 changed files with 1,045 additions and 244 deletions.
23 changes: 9 additions & 14 deletions internal/pkg/apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import (
"context"
"fmt"
"io"

"k8s.io/apimachinery/pkg/api/errors"
"sigs.k8s.io/cli-experimental/internal/pkg/constants"

"gopkg.in/src-d/go-git.v4/plumbing/object"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/cli-experimental/internal/pkg/client"
"sigs.k8s.io/cli-experimental/internal/pkg/clik8s"
"sigs.k8s.io/cli-experimental/internal/pkg/constants"
"sigs.k8s.io/cli-experimental/internal/pkg/util"
"sigs.k8s.io/kustomize/pkg/inventory"
)

Expand Down Expand Up @@ -58,21 +58,18 @@ func (a *Apply) Do() (Result, error) {
// When the dry-run passes, proceed to the actual apply

for _, u := range normalizeResourceOrdering(a.Resources) {
annotation := u.GetAnnotations()
_, ok := annotation[inventory.ContentAnnotation]

if ok {
if util.HasAnnotation(u, inventory.ContentAnnotation) {
var err error
u, err = a.updateInventoryObject(u)
if err != nil {
fmt.Fprintf(a.Out, "failed to update inventory object %v\n", err)
}
}
if presence, ok := annotation[constants.Presence]; ok {
if presence == constants.EnsureNoExist {
// not applying the resource
continue
}
if util.MatchAnnotations(u, map[string]string{
constants.Presence: constants.EnsureNoExist,
}) {
// not applying the resource
continue
}
err := a.DynamicClient.Apply(context.Background(), u)
if err != nil {
Expand Down Expand Up @@ -131,9 +128,7 @@ func normalizeResourceOrdering(resources clik8s.ResourceConfigs) []*unstructured
var results []*unstructured.Unstructured
index := -1
for i, u := range resources {
annotation := u.GetAnnotations()
_, ok := annotation[inventory.ContentAnnotation]
if ok {
if util.HasAnnotation(u, inventory.ContentAnnotation) {
index = i
} else {
results = append(results, u)
Expand Down
221 changes: 203 additions & 18 deletions internal/pkg/apply/apply_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sigs.k8s.io/cli-experimental/internal/pkg/constants"
"sigs.k8s.io/cli-experimental/internal/pkg/util"
"testing"

"github.com/stretchr/testify/assert"
"gopkg.in/src-d/go-git.v4/plumbing/object"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/cli-experimental/internal/pkg/apply"
"sigs.k8s.io/cli-experimental/internal/pkg/clik8s"
"sigs.k8s.io/cli-experimental/internal/pkg/wirecli/wiretest"
Expand Down Expand Up @@ -83,21 +84,19 @@ inventory:
namespace: default
resources:
- not-apply-service.yaml
- apply-service.yaml
namespace: default
`), 0644)
if err != nil {
return nil, nil, err
}

err = ioutil.WriteFile(filepath.Join(f1, "not-apply-service.yaml"), []byte(`
err = ioutil.WriteFile(filepath.Join(f1, "apply-service.yaml"), []byte(`
apiVersion: v1
kind: Service
metadata:
name: my-service
annotations:
kubectl.kubernetes.io/presence: EnsureDoesNotExist
spec:
selector:
app: MyApp
Expand Down Expand Up @@ -161,41 +160,227 @@ spec:
}, nil
}

/* TestApplyWithPresenceAnnotation take following steps
1. create a Kustomization with
a ConfigMapGenerator
a Service
an inventory ConfigMap
2. apply the kustomization
3. confirm that there are
1 Service
3. update the service to have the annotation EnsureDoesNotExist
4. apply the kustomization again
5. confirm that there are
1 Service
6. confirm that the existing service is not updated
*/
func TestApplyWithPresenceAnnotation(t *testing.T) {
buf := new(bytes.Buffer)

// set up a kustomization
kp := wiretest.InitializConfigProvider()
fs, cleanup, err := InitializeKustomizationWithPresence()
defer cleanup()
assert.NoError(t, err)
assert.Equal(t, len(fs), 2)

// confirm the loaded resources containing a service
// without the annotation for EnsureDoesNotExist
objects, err := kp.GetConfig(fs[0])
assert.NoError(t, err)
service := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "my-service",
"namespace": "default",
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"port": int64(80),
"protocol": "TCP",
"targetPort": int64(9376)},
},
"selector": map[string]interface{}{"app": "MyApp"},
},
},
}
assert.NoError(t, err)
assert.Contains(t, objects, service)

// Initialize the Apply object
a, done, err := wiretest.InitializeApply(objects, &object.Commit{}, buf)
defer done()

serviceList := &unstructured.UnstructuredList{}
serviceList.SetGroupVersionKind(schema.GroupVersionKind{
Kind: "ServiceList",
Version: "v1",
})
err = a.DynamicClient.List(context.Background(), serviceList, "default", nil)
defaultCount := len(serviceList.Items)

assert.NoError(t, err)

// Apply the first kustomization
// Confirm there is one Service object
// Confirm the Service object is the expected one
r, err := a.Do()
assert.NoError(t, err)
assert.Equal(t, apply.Result{objects}, r)
err = a.DynamicClient.List(context.Background(), serviceList, "default", nil)
assert.Equal(t, len(serviceList.Items), defaultCount)
liveService := service.DeepCopy()
exist, err := util.ObjectExist(a.DynamicClient, context.Background(), liveService)
assert.NoError(t, err)
assert.Equal(t, true, exist)
assert.Equal(t, false, util.HasAnnotation(liveService, constants.Presence))

// Update the kustomization
// by adding the annotation EnsureDoesNotExist to the Service object
// Confirm there is a Service resource with the annotation EnsureDoesNotExist
updatedObjects, err := kp.GetConfig(fs[1])
assert.NoError(t, err)
updatedService := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "my-service",
"namespace": "default",
"annotations": map[string]interface{}{
"kubectl.kubernetes.io/presence": "EnsureDoesNotExist",
},
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"port": int64(80),
"protocol": "TCP",
"targetPort": int64(9376)},
},
"selector": map[string]interface{}{"app": "MyApp"},
},
},
}
assert.Contains(t, updatedObjects, updatedService)
assert.NotEqual(t, service, updatedService)

// Apply the second kustomization
// Confirm that the Service object is not updated
a.Resources = updatedObjects
r, err = a.Do()
assert.NoError(t, err)
assert.Equal(t, apply.Result{updatedObjects}, r)
exist, err = util.ObjectExist(a.DynamicClient, context.Background(), liveService)
assert.Equal(t, true, exist)
assert.NoError(t, err)
assert.Equal(t, false, util.HasAnnotation(liveService, constants.Presence))
}

/* TestApplyWithPresenceAnnotationOrder2 take following steps
1. create a Kustomization with
a ConfigMapGenerator
a Service with the annotation EnsureDoesNotExist
an inventory ConfigMap
2. apply the kustomization
3. confirm that there are
0 Service
3. Delete the annotation EnsureDoesNotExist from the service
4. apply the kustomization again
5. confirm that there are
1 Service
*/
func TestApplyWithPresenceAnnotationOrder2(t *testing.T) {
buf := new(bytes.Buffer)

// set up a kustomization
kp := wiretest.InitializConfigProvider()
fs, cleanup, err := InitializeKustomizationWithPresence()
defer cleanup()
assert.NoError(t, err)
assert.Equal(t, len(fs), 2)

// confirm the loaded resources containing a service
// with the annotation for EnsureDoesNotExist
objects, err := kp.GetConfig(fs[1])
assert.NoError(t, err)
service := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "my-service",
"namespace": "default",
"annotations": map[string]interface{}{
"kubectl.kubernetes.io/presence": "EnsureDoesNotExist",
},
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"port": int64(80),
"protocol": "TCP",
"targetPort": int64(9376)},
},
"selector": map[string]interface{}{"app": "MyApp"},
},
},
}
assert.NoError(t, err)
assert.Contains(t, objects, service)

// Initialize the Apply object
a, done, err := wiretest.InitializeApply(objects, &object.Commit{}, buf)
defer done()
assert.NoError(t, err)

// Apply the first kustomization
// Confirm that the Service object is not created
r, err := a.Do()
assert.NoError(t, err)
assert.Equal(t, apply.Result{objects}, r)
liveService := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "my-service",
"namespace": "default",
},
},
}
exist, err := util.ObjectExist(a.DynamicClient, context.Background(), liveService)
assert.NoError(t, err)
assert.Equal(t, false, exist)

// Update the kustomization
// by removing the annotation EnsureDoesNotExist from the Service object
// Confirm there is a Service resource without the annotation EnsureDoesNotExist
updatedObjects, err := kp.GetConfig(fs[0])
assert.NoError(t, err)
updatedService := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "Service",
"metadata": map[string]interface{}{
"name": "my-service",
"namespace": "default",
},
"spec": map[string]interface{}{
"ports": []interface{}{
map[string]interface{}{
"port": int64(80),
"protocol": "TCP",
"targetPort": int64(9376)},
},
"selector": map[string]interface{}{"app": "MyApp"},
},
},
}
assert.Contains(t, updatedObjects, updatedService)
assert.NotEqual(t, service, updatedService)

// Apply the second kustomization
// Confirm that the Service object is created
// and without the annotation
a.Resources = updatedObjects
r, err = a.Do()
assert.NoError(t, err)
assert.Equal(t, apply.Result{updatedObjects}, r)
err = a.DynamicClient.List(context.Background(), serviceList, "default", nil)
assert.Equal(t, len(serviceList.Items), defaultCount)
exist, err = util.ObjectExist(a.DynamicClient, context.Background(), liveService)
assert.Equal(t, true, exist)
assert.NoError(t, err)
assert.Equal(t, false, util.HasAnnotation(liveService, constants.Presence))
}
2 changes: 1 addition & 1 deletion internal/pkg/clik8s/clik8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ type MasterURL string
type ResourceConfigs []*unstructured.Unstructured

// ResourcePruneConfigs is a collection of Resource Config used for pruning
type ResourcePruneConfigs *unstructured.Unstructured
type ResourcePruneConfigs []*unstructured.Unstructured
4 changes: 2 additions & 2 deletions internal/pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ const (
Presence = "kubectl.kubernetes.io/presence"

// Any resource with the annotation
// kubectl.kubernetes.io/presence: EnsureExist
// kubectl.kubernetes.io/presence: PreventDeletion
// will not be pruned or deleted.
//
// It following effect in each command
// - no effect in apply
// - prune skips this resource
// - delete skips this resource

EnsureExist = "EnsureExist"
PreventDeletion = "PreventDeletion"

// Any resource with the annotation
// kubectl.kubernetes.io/presence: EnsureDoesNotExist
Expand Down
Loading

0 comments on commit 016c4ba

Please sign in to comment.