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

bugfix: yaml.v2 unmarshal json content, make metadata type map[interface{}]interface{} #99

Merged
merged 1 commit into from
Jul 18, 2022
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
91 changes: 45 additions & 46 deletions pkg/engine/runtime/kubernetes_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"

jsonpatch "github.com/evanphx/json-patch"
yamlv2 "gopkg.in/yaml.v2"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -24,7 +25,6 @@ import (
"kusionstack.io/kusion/pkg/status"
"kusionstack.io/kusion/pkg/util/json"
"kusionstack.io/kusion/pkg/util/kube/config"
"kusionstack.io/kusion/pkg/util/yaml"
)

var _ Runtime = (*KubernetesRuntime)(nil)
Expand Down Expand Up @@ -62,66 +62,63 @@ func (k *KubernetesRuntime) Apply(ctx context.Context, request *ApplyRequest) *A
if err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}

// Get live state
response := k.Read(ctx, &ReadRequest{planState})
if status.IsErr(response.Status) {
return &ApplyResponse{nil, response.Status}
}
liveState := response.Resource
s := response.Status
if status.IsErr(s) {
return &ApplyResponse{nil, s}

// Original equals to last-applied from annotation, kusion store it in kusion_state.json
original := ""
if priorState != nil {
original = json.MustMarshal2String(priorState.Attributes)
}
// Modified equals to input content
modified := json.MustMarshal2String(planState.Attributes)
// Current equals to live manifest
current := ""
if liveState != nil {
current = json.MustMarshal2String(liveState.Attributes)
}

// LiveState is nil, fall back to create planObj directly
if liveState == nil {
// Patch options
createOptions := metav1.CreateOptions{}
if request.DryRun {
createOptions.DryRun = []string{metav1.DryRunAll}
}
createdObj, err := resource.Create(ctx, planObj, createOptions)
// Create patch body
patchBody, err := jsonmergepatch.CreateThreeWayJSONMergePatch([]byte(original), []byte(modified), []byte(current))
if err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}

// Final result, dry-run to diff, otherwise to save in states
var res *unstructured.Unstructured
if request.DryRun {
// Use client dry-run here to be compatible with server dry-run not supported
mergedPatch, err := jsonpatch.MergePatch([]byte(current), patchBody)
if err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}
if request.DryRun {
planObj = createdObj
res = &unstructured.Unstructured{}
if err = res.UnmarshalJSON(mergedPatch); err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}
} else {
// Original equals to last-applied from annotation, kusion store it in kusion_state.json
original := ""
if priorState != nil {
original = json.MustMarshal2String(priorState.Attributes)
if liveState == nil {
// LiveState is nil, fall back to create planObj
_, err = resource.Create(ctx, planObj, metav1.CreateOptions{})
} else {
// LiveState isn't nil, continue to patch liveObj
_, err = resource.Patch(ctx, planObj.GetName(), types.MergePatchType, patchBody, metav1.PatchOptions{FieldManager: "kusion"})
}
// Modified equals input content
modified := json.MustMarshal2String(planState.Attributes)
// Current equals live manifest
current := json.MustMarshal2String(liveState.Attributes)
// 3-way json merge patch
patchBody, err := jsonmergepatch.CreateThreeWayJSONMergePatch([]byte(original), []byte(modified), []byte(current))
if err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}
if request.DryRun {
// Use client dry-run here to be compatible with server dry-run not supported
mergedPatch, err := jsonpatch.MergePatch([]byte(current), patchBody)
if err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}
dryRunObj := &unstructured.Unstructured{}
if err = dryRunObj.UnmarshalJSON(mergedPatch); err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}
planObj = dryRunObj
} else {
// Apply patch
_, err = resource.Patch(ctx, planObj.GetName(), types.MergePatchType, patchBody, metav1.PatchOptions{FieldManager: "kusion"})
if err != nil {
return &ApplyResponse{nil, status.NewErrorStatus(err)}
}
}
// Save modified
res = planObj
}

return &ApplyResponse{&models.Resource{
ID: planState.ResourceKey(),
Attributes: planObj.Object,
Attributes: res.Object,
DependsOn: planState.DependsOn,
}, nil}
}
Expand Down Expand Up @@ -217,10 +214,12 @@ func getKubernetesClient() (dynamic.Interface, *restmapper.DeferredDiscoveryREST
// buildKubernetesResourceByState get resource by attribute
func (k *KubernetesRuntime) buildKubernetesResourceByState(resourceState *models.Resource) (*unstructured.Unstructured, dynamic.ResourceInterface, error) {
// Convert interface{} to unstructured
attribute := resourceState.Attributes
rYaml := yaml.MergeToOneYAML(attribute)
rYaml, err := yamlv2.Marshal(resourceState.Attributes)
if err != nil {
return nil, nil, err
}

obj, gvk, err := convertString2Unstructured([]byte(rYaml))
obj, gvk, err := convertString2Unstructured(rYaml)
if err != nil {
return nil, nil, err
}
Expand Down
6 changes: 2 additions & 4 deletions pkg/engine/states/local/filesystem_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import (
"os"
"time"

"kusionstack.io/kusion/pkg/engine/states"

"gopkg.in/yaml.v2"

"github.com/zclconf/go-cty/cty"
"gopkg.in/yaml.v3"

"kusionstack.io/kusion/pkg/engine/states"
"kusionstack.io/kusion/pkg/log"
)

Expand Down
15 changes: 6 additions & 9 deletions pkg/engine/states/remote/db_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,19 @@ import (
"net/url"
"sort"

"kusionstack.io/kusion/pkg/engine/states"

"kusionstack.io/kusion/pkg/engine/models"

"github.com/didi/gendry/manager"
"github.com/didi/gendry/scanner"
_ "github.com/go-sql-driver/mysql"
"github.com/jinzhu/copier"
"gopkg.in/yaml.v2"
"github.com/zclconf/go-cty/cty"
"gopkg.in/yaml.v3"

"kusionstack.io/kusion/pkg/engine/dal/mapper"
"kusionstack.io/kusion/pkg/engine/models"
"kusionstack.io/kusion/pkg/engine/states"
"kusionstack.io/kusion/pkg/log"
"kusionstack.io/kusion/pkg/util"
jsonutil "kusionstack.io/kusion/pkg/util/json"

"github.com/didi/gendry/manager"
_ "github.com/go-sql-driver/mysql"
"github.com/zclconf/go-cty/cty"
)

func init() {
Expand Down
1 change: 1 addition & 0 deletions pkg/util/yaml/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func MustGetByPath(doc io.Reader, path *yaml.Path) string {
return expectNode.String()
}

// TODO: yamlv3.Marshal will reduce leading "/n" character
// Merge multiple yaml documents into a single string,
// separate yaml documents with '---'
func MergeToOneYAML(yamlList ...interface{}) string {
Expand Down