mirror of
https://github.com/kairos-io/kairos-sdk.git
synced 2025-09-24 20:36:59 +00:00
Extract sdk into its own lib
This had some side effects: - Have to add some utils from the kairos/machine modules, which IMHO should not be there, they should be here if the are generic enough - Dropping the sdk dir, just have the modules in the root dir Signed-off-by: Itxaka <itxaka.garcia@spectrocloud.com>
This commit is contained in:
13
unstructured/suite_test.go
Normal file
13
unstructured/suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package unstructured_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestSuite(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Unstructured Test Suite")
|
||||
}
|
142
unstructured/yaml.go
Normal file
142
unstructured/yaml.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package unstructured
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/itchyny/gojq"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func YAMLHasKey(query string, content []byte) (bool, error) {
|
||||
data := map[string]interface{}{}
|
||||
|
||||
err := yaml.Unmarshal([]byte(content), &data)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
c, err := gojq.Parse(fmt.Sprintf(".%s | ..", query))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
code, err := gojq.Compile(c)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
iter := code.Run(data)
|
||||
|
||||
v, _ := iter.Next()
|
||||
|
||||
if err, ok := v.(error); ok {
|
||||
return false, err
|
||||
}
|
||||
if v == nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func lookupKey(command string, data map[string]interface{}) (interface{}, error) {
|
||||
query, err := gojq.Parse(command)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
code, err := gojq.Compile(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iter := code.Run(data)
|
||||
|
||||
v, ok := iter.Next()
|
||||
if !ok {
|
||||
return nil, errors.New("failed getting result from gojq")
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func LookupString(command string, data map[string]interface{}) (string, error) {
|
||||
v, err := lookupKey(command, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if t, ok := v.(string); ok {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("value is not a string: %T", v)
|
||||
}
|
||||
|
||||
func ReplaceValue(command string, data map[string]interface{}) (string, error) {
|
||||
v, err := lookupKey(command, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if _, ok := v.(map[string]interface{}); ok {
|
||||
b, err := yaml.Marshal(v)
|
||||
return string(b), err
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unexpected type: %T", v)
|
||||
}
|
||||
|
||||
// func ReplaceKeyValue(command string, data interface{}) (string, error) {
|
||||
// LookupString(commd
|
||||
// }
|
||||
|
||||
func jq(command string, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
v, err := lookupKey(command, data)
|
||||
if err != nil {
|
||||
return make(map[string]interface{}), err
|
||||
}
|
||||
|
||||
if err, ok := v.(error); ok {
|
||||
return nil, err
|
||||
}
|
||||
if t, ok := v.(map[string]interface{}); ok {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
return make(map[string]interface{}), nil
|
||||
}
|
||||
|
||||
func ToYAML(v map[string]interface{}) ([]byte, error) {
|
||||
data := map[string]interface{}{}
|
||||
var errs error
|
||||
|
||||
for k, value := range v {
|
||||
tmpl := ".%s=\"%s\""
|
||||
// support boolean types
|
||||
if value == "true" || value == "false" {
|
||||
tmpl = ".%s=%s"
|
||||
}
|
||||
newData, err := jq(fmt.Sprintf(tmpl, k, value), data)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
data = newData
|
||||
}
|
||||
|
||||
out, err := yaml.Marshal(&data)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
}
|
||||
return out, errs
|
||||
}
|
||||
|
||||
// ToYAMLMap turns a map string interface which describes a yaml file in 'dot.yaml' format to a fully deep marshalled yaml.
|
||||
func ToYAMLMap(v map[string]interface{}) (map[string]interface{}, error) {
|
||||
result := map[string]interface{}{}
|
||||
tempData, err := ToYAML(v)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
err = yaml.Unmarshal(tempData, &result)
|
||||
|
||||
return result, err
|
||||
}
|
105
unstructured/yaml_test.go
Normal file
105
unstructured/yaml_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package unstructured_test
|
||||
|
||||
import (
|
||||
. "github.com/kairos-io/kairos-sdk/unstructured"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var _ = Describe("unstructured", Label("unstructured-test"), func() {
|
||||
var content []byte
|
||||
var data map[string]interface{}
|
||||
|
||||
BeforeEach(func() {
|
||||
content = []byte(`
|
||||
a:
|
||||
b:
|
||||
c:
|
||||
d: 1
|
||||
e: "some_string"
|
||||
`)
|
||||
|
||||
data = map[string]interface{}{}
|
||||
err := yaml.Unmarshal(content, &data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Describe("YAMLHasKey", func() {
|
||||
It("returns true if the key exists in the yaml", func() {
|
||||
r, err := YAMLHasKey("a.b", content)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).To(BeTrue())
|
||||
})
|
||||
|
||||
It("returns false if the key doesn't exist in the yaml", func() {
|
||||
r, err := YAMLHasKey("a.z", content)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).To(BeFalse())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("LookupString", func() {
|
||||
When("key exists", func() {
|
||||
When("key is a string", func() {
|
||||
It("returns the value", func() {
|
||||
r, err := LookupString(".a.b.c.e", data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).To(Equal("some_string"))
|
||||
})
|
||||
})
|
||||
|
||||
When("key isn't a string", func() {
|
||||
It("returns an error", func() {
|
||||
_, err := LookupString(".a.b.c.d", data)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(MatchRegexp("value is not a string"))
|
||||
})
|
||||
})
|
||||
})
|
||||
When("key doesn't exist", func() {
|
||||
It("returns an error", func() {
|
||||
_, err := LookupString(".a.b.c.z", data)
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(MatchRegexp("value is not a string"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("ReplaceValue", func() {
|
||||
When("key exists", func() {
|
||||
When("value is a map", func() {
|
||||
It("can replace with a string", func() {
|
||||
r, err := ReplaceValue(".a=\"test\"", data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).To(Equal("a: test\n"))
|
||||
})
|
||||
})
|
||||
When("value is a string", func() {
|
||||
It("can replace with a string", func() {
|
||||
r, err := ReplaceValue(".a.b.c.e=\"test\"", data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).To(Equal(`a:
|
||||
b:
|
||||
c:
|
||||
d: 1
|
||||
e: test
|
||||
`))
|
||||
})
|
||||
})
|
||||
})
|
||||
When("key doesn't exist", func() {
|
||||
It("creates the key", func() {
|
||||
r, err := ReplaceValue(".a.b.c.z=\"test\"", data)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(r).To(Equal(`a:
|
||||
b:
|
||||
c:
|
||||
d: 1
|
||||
e: some_string
|
||||
z: test
|
||||
`), r)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user