Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return a detailed diff from Diff. #618

Merged
merged 6 commits into from
Jul 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
## 0.25.2 (Unreleased)

### Supported Kubernetes versions

- v1.15.x
- v1.14.x
- v1.13.x

### Improvements

- The Kubernetes provider can now communicate detailed information about the difference between a resource's desired and actual state during a Pulumi update. (https://github.com/pulumi/pulumi-kubernetes/pull/618)

### Bug fixes

- None

## 0.25.1 (July 2, 2019)

### Supported Kubernetes versions
Expand Down
11 changes: 7 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ module github.com/pulumi/pulumi-kubernetes
go 1.12

require (
contrib.go.opencensus.io/exporter/ocagent v0.4.12 // indirect
github.com/Azure/go-autorest v12.0.0+incompatible // indirect
github.com/ahmetb/go-linq v3.0.0+incompatible
github.com/cbroglie/mustache v1.0.1
github.com/docker/docker v1.13.1 // indirect
github.com/evanphx/json-patch v4.1.0+incompatible
github.com/gogo/protobuf v1.2.0 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/protobuf v1.3.1
github.com/google/gofuzz v1.0.0 // indirect
Expand All @@ -17,17 +17,20 @@ require (
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
github.com/json-iterator/go v1.1.6 // indirect
github.com/mitchellh/go-wordwrap v1.0.0
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pkg/errors v0.8.1
github.com/pulumi/pulumi v0.17.15
github.com/stretchr/testify v1.2.2
github.com/pulumi/pulumi v0.17.22-0.20190702234832-f11f4f749898
github.com/stretchr/testify v1.3.0
google.golang.org/grpc v1.20.1
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.0.0-20190313235455-40a48860b5ab
k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1
k8s.io/client-go v11.0.0+incompatible
k8s.io/klog v0.3.0 // indirect
k8s.io/kube-openapi v0.0.0-20190418160015-6b3d3b2d5666
k8s.io/kubernetes v1.14.1
k8s.io/utils v0.0.0-20190308190857-21c4ce38f2a7 // indirect
sigs.k8s.io/yaml v1.1.0 // indirect
)

replace (
Expand Down
494 changes: 77 additions & 417 deletions go.sum

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pkg/await/await.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func Update(c UpdateConfig) (*unstructured.Unstructured, error) {
}

// Create merge patch (prefer strategic merge patch, fall back to JSON merge patch).
patch, patchType, err := openapi.PatchForResourceUpdate(
patch, patchType, _, err := openapi.PatchForResourceUpdate(
c.ClientSet.DiscoveryClientCached, c.Previous, c.Inputs, liveOldObj)
if err != nil {
return nil, err
Expand Down
41 changes: 38 additions & 3 deletions pkg/metadata/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,26 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

const (
managedByLabel = "app.kubernetes.io/managed-by"
)

// SetLabel sets the specified key/value pair as a label on the provided Unstructured object.
func SetLabel(obj *unstructured.Unstructured, key, value string) {
// Note: Cannot use obj.GetLabels() here because it doesn't properly handle computed values from preview.
// During preview, don't set labels if the metadata or label contains a computed value since there's
// no way to insert data into the computed object.
metadataRaw := obj.Object["metadata"]
metadataRaw, ok := obj.Object["metadata"]
if isComputedValue(metadataRaw) {
return
}
metadata := metadataRaw.(map[string]interface{})
var metadata map[string]interface{}
if !ok {
metadata = map[string]interface{}{}
obj.Object["metadata"] = metadata
} else {
metadata = metadataRaw.(map[string]interface{})
}
labelsRaw, ok := metadata["labels"]
if isComputedValue(labelsRaw) {
return
Expand All @@ -43,7 +53,32 @@ func SetLabel(obj *unstructured.Unstructured, key, value string) {
metadata["labels"] = labels
}

// GetLabel gets the value of the specified label from the given object.
func GetLabel(obj *unstructured.Unstructured, key string) interface{} {
metadataRaw := obj.Object["metadata"]
if isComputedValue(metadataRaw) || metadataRaw == nil {
return metadataRaw
}
metadata := metadataRaw.(map[string]interface{})
labelsRaw := metadata["labels"]
if isComputedValue(labelsRaw) || labelsRaw == nil {
return labelsRaw
}
return labelsRaw.(map[string]interface{})[key]
}

// SetManagedByLabel sets the `app.kubernetes.io/managed-by` label to `pulumi`.
func SetManagedByLabel(obj *unstructured.Unstructured) {
SetLabel(obj, "app.kubernetes.io/managed-by", "pulumi")
SetLabel(obj, managedByLabel, "pulumi")
}

// HasManagedByLabel returns true if the object has the `app.kubernetes.io/managed-by` label set to `pulumi`,
// or is a computed value.
func HasManagedByLabel(obj *unstructured.Unstructured) bool {
val := GetLabel(obj, managedByLabel)
if isComputedValue(val) {
return true
}
str, ok := val.(string)
return ok && str == "pulumi"
}
29 changes: 15 additions & 14 deletions pkg/openapi/openapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,26 +79,26 @@ func ValidateAgainstSchema(
// how to generate a strategic merge patch, we fall back to JSON merge patch.
func PatchForResourceUpdate(client discovery.CachedDiscoveryInterface, lastSubmitted, currentSubmitted,
liveOldObj *unstructured.Unstructured,
) ([]byte, types.PatchType, error) {
) ([]byte, types.PatchType, strategicpatch.LookupPatchMeta, error) {
// Create JSON blobs for each of these, preparing to create the three-way merge patch.
lastSubmittedJSON, err := lastSubmitted.MarshalJSON()
if err != nil {
return nil, "", err
return nil, "", nil, err
}

currentSubmittedJSON, err := currentSubmitted.MarshalJSON()
if err != nil {
return nil, "", err
return nil, "", nil, err
}

liveOldJSON, err := liveOldObj.MarshalJSON()
if err != nil {
return nil, "", err
return nil, "", nil, err
}

resources, err := getResourceSchemasForClient(client)
if err != nil {
return nil, "", err
return nil, "", nil, err
}

// Try to build a three-way "strategic" merge.
Expand All @@ -112,7 +112,8 @@ func PatchForResourceUpdate(client discovery.CachedDiscoveryInterface, lastSubmi
// Fall back to three-way JSON merge patch.
glog.V(1).Infof("Attempting to update '%s' '%s/%s' with JSON merge",
gvk.String(), lastSubmitted.GetNamespace(), lastSubmitted.GetName())
return jsonMergePatch(lastSubmittedJSON, currentSubmittedJSON, liveOldJSON)
patch, patchType, err := jsonMergePatch(lastSubmittedJSON, currentSubmittedJSON, liveOldJSON)
return patch, patchType, nil, err
}

// Pluck obtains the property identified by the string components in `path`. For example,
Expand Down Expand Up @@ -150,34 +151,34 @@ func Pluck(obj map[string]interface{}, path ...string) (interface{}, bool) {
func strategicMergePatch(
gvk schema.GroupVersionKind, resourceSchema proto.Schema,
lastSubmittedJSON, currentSubmittedJSON, liveOldJSON []byte,
) ([]byte, types.PatchType, error) {
) ([]byte, types.PatchType, strategicpatch.LookupPatchMeta, error) {
// Attempt to construct patch from OpenAPI spec data.
lookupPatchMeta := strategicpatch.PatchMetaFromOpenAPI{Schema: resourceSchema}
lookupPatchMeta := strategicpatch.LookupPatchMeta(strategicpatch.PatchMetaFromOpenAPI{Schema: resourceSchema})
patch, err := strategicpatch.CreateThreeWayMergePatch(
lastSubmittedJSON, currentSubmittedJSON, liveOldJSON, lookupPatchMeta, true)
if err != nil {
return nil, "", err
return nil, "", nil, err
}

// Fall back to constructing patch from nominal type data.
if patch == nil {
versionedObject, err := scheme.Scheme.New(gvk)
if err != nil {
return nil, "", err
return nil, "", nil, err
}

lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObject)
lookupPatchMeta, err = strategicpatch.NewPatchMetaFromStruct(versionedObject)
if err != nil {
return nil, "", err
return nil, "", nil, err
}
patch, err = strategicpatch.CreateThreeWayMergePatch(
lastSubmittedJSON, currentSubmittedJSON, liveOldJSON, lookupPatchMeta, true)
if err != nil {
return nil, "", err
return nil, "", nil, err
}
}

return patch, types.StrategicMergePatchType, nil
return patch, types.StrategicMergePatchType, lookupPatchMeta, nil
}

// jsonMergePatch allows a Kubernetes resource to be "updated" by creating a three-way JSON merge
Expand Down
6 changes: 2 additions & 4 deletions pkg/provider/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
package provider

import (
"github.com/pulumi/pulumi-kubernetes/pkg/openapi"
"k8s.io/apimachinery/pkg/runtime/schema"
)

func forceNewProperties(patch map[string]interface{}, gvk schema.GroupVersionKind) ([]string, error) {
func forceNewProperties(gvk schema.GroupVersionKind) []string {
props := metadataForceNewProperties(".metadata")
if group, groupExists := forceNew[gvk.Group]; groupExists {
if version, versionExists := group[gvk.Version]; versionExists {
Expand All @@ -28,8 +27,7 @@ func forceNewProperties(patch map[string]interface{}, gvk schema.GroupVersionKin
}
}
}

return openapi.PatchPropertiesChanged(patch, props)
return props
}

type groups map[string]versions
Expand Down
Loading