diff --git a/go.mod b/go.mod index ba1e47a12..4dad646cd 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( k8s.io/utils v0.0.0-20230726121419-3b25d923346b sigs.k8s.io/cluster-api v1.6.3 sigs.k8s.io/controller-runtime v0.17.2 + sigs.k8s.io/yaml v1.4.0 ) require ( @@ -161,5 +162,4 @@ require ( sigs.k8s.io/cli-utils v0.28.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/pkg/util/util.go b/pkg/util/util.go index 8afcc847d..e311fec40 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -19,17 +19,18 @@ package util import ( "context" "crypto/sha256" - "encoding/json" + "errors" "fmt" "net/url" "strings" managementv3 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3" - "gopkg.in/yaml.v3" + "github.com/rancher/yip/pkg/schema" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" "github.com/rancher/elemental-operator/pkg/log" ) @@ -51,30 +52,33 @@ func MarshalCloudConfig(cloudConfig map[string]runtime.RawExtension) ([]byte, er return []byte{}, nil } - var err error - bytes := []byte("#cloud-config\n") - - for k, v := range cloudConfig { - var jsonData []byte - if jsonData, err = v.MarshalJSON(); err != nil { - return nil, fmt.Errorf("%s: %w", k, err) - } + // This creates a parent "root" key to facilitate parsing the schemaless map + mapSlice := yaml.JSONObjectToYAMLObject(map[string]interface{}{"root": cloudConfig}) + if len(mapSlice) <= 0 { + return nil, errors.New("Could not convert json cloudConfig object to yaml") + } - var structData interface{} - if err := json.Unmarshal(jsonData, &structData); err != nil { - log.Debugf("failed to decode %s (%s): %s", k, string(jsonData), err.Error()) - return nil, fmt.Errorf("%s: %w", k, err) - } + // Just marshal the value of the "root" key + yamlData, err := yaml.Marshal(mapSlice[0].Value) + if err != nil { + return nil, fmt.Errorf("marshalling yaml: %w", err) + } - var yamlData []byte - if yamlData, err = yaml.Marshal(structData); err != nil { - return nil, err + // Determine whether this is a yip config or a cloud-init one. + // Since all fields are optional in yip, we test whether any stage has been defined, + // as an indication that this is indeed a yip config. + yipConfig := &schema.YipConfig{} + if err := yaml.Unmarshal(yamlData, yipConfig); err == nil { + if len(yipConfig.Stages) > 0 { + return yamlData, nil } - - bytes = append(bytes, append([]byte(fmt.Sprintf("%s:\n", k)), yamlData...)...) } - return bytes, nil + // If it is not a yip config, then assume it's cloud-init. + cloudConfigBytes := []byte("#cloud-config\n") + cloudConfigBytes = append(cloudConfigBytes, yamlData...) + + return cloudConfigBytes, nil } // GetSettingsValue find the given name in Rancher settings and returns its value if found diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go index e187e8c61..17027eee9 100644 --- a/pkg/util/util_test.go +++ b/pkg/util/util_test.go @@ -21,7 +21,6 @@ import ( . "github.com/onsi/gomega" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" elementalv1 "github.com/rancher/elemental-operator/api/v1beta1" "github.com/rancher/elemental-operator/pkg/test" @@ -81,25 +80,20 @@ var _ = Describe("MarshalCloudConfig", func() { It("should marshal an example cloud-init file correctly", func() { data, err := MarshalCloudConfig(map[string]runtime.RawExtension{ - "write_files": {Object: WriteFiles{}}, + "write_files": {Raw: []byte(`{}`)}, }) Expect(err).To(BeNil()) - Expect(data).To(Equal([]byte("#cloud-config\nwrite_files:\n{}\n"))) + Expect(string(data)).To(Equal("#cloud-config\nwrite_files: {}\n")) + }) + It("should marshal a yip file correctly", func() { + data, err := MarshalCloudConfig(map[string]runtime.RawExtension{ + "stages": {Raw: []byte(`{"network":[{"name":"test","commands":["foo","bar"]}]}`)}, + }) + Expect(err).To(BeNil()) + Expect(string(data)).To(Equal("stages:\n network:\n - commands:\n - foo\n - bar\n name: test\n")) }) }) -type WriteFiles struct { -} - -func (w WriteFiles) GetObjectKind() schema.ObjectKind { - return nil -} -func (w WriteFiles) DeepCopyObject() runtime.Object { - return nil -} - -var _ runtime.Object = WriteFiles{} - var _ = Describe("IsObjectOwned", func() { obj := metav1.ObjectMeta{ OwnerReferences: []metav1.OwnerReference{