mirror of
https://github.com/rancher/os.git
synced 2025-06-24 22:11:33 +00:00
Read files cloud-config.d in alphanumeric order, then cloud-config.yml `ros config` writes to cloud-config.yml (and cloud-config.d/private.yml - only private keys) Add (c *CloudConfig) Save() method, use it to save the changed config Read and apply metadata as part of LoadConfig() Simplify ros config export logic
339 lines
6.8 KiB
Go
339 lines
6.8 KiB
Go
package util
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
|
"reflect"
|
|
)
|
|
|
|
var (
|
|
ErrNoNetwork = errors.New("Networking not available to load resource")
|
|
ErrNotFound = errors.New("Failed to find resource")
|
|
)
|
|
|
|
type AnyMap map[interface{}]interface{}
|
|
|
|
func Contains(values []string, value string) bool {
|
|
if len(value) == 0 {
|
|
return false
|
|
}
|
|
|
|
for _, i := range values {
|
|
if i == value {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
type ReturnsErr func() error
|
|
|
|
func FileCopy(src, dest string) (err error) {
|
|
in, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { err = in.Close() }()
|
|
|
|
out, err := os.Create(dest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { err = out.Close() }()
|
|
|
|
if _, err := io.Copy(out, in); err != nil {
|
|
return err
|
|
}
|
|
return
|
|
}
|
|
|
|
func Convert(from, to interface{}) error {
|
|
bytes, err := yaml.Marshal(from)
|
|
if err != nil {
|
|
log.WithFields(log.Fields{"from": from, "err": err}).Warn("Error serializing to YML")
|
|
return err
|
|
}
|
|
|
|
return yaml.Unmarshal(bytes, to)
|
|
}
|
|
|
|
func Copy(d interface{}) interface{} {
|
|
switch d := d.(type) {
|
|
case map[interface{}]interface{}:
|
|
return MapCopy(d)
|
|
case []interface{}:
|
|
return SliceCopy(d)
|
|
default:
|
|
return d
|
|
}
|
|
}
|
|
|
|
func Replace(l, r interface{}) interface{} {
|
|
return r
|
|
}
|
|
|
|
func Equal(l, r interface{}) interface{} {
|
|
if reflect.DeepEqual(l, r) {
|
|
return l
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Filter(xs []interface{}, p func(x interface{}) bool) []interface{} {
|
|
return FlatMap(xs, func(x interface{}) []interface{} {
|
|
if p(x) {
|
|
return []interface{}{x}
|
|
}
|
|
return []interface{}{}
|
|
})
|
|
}
|
|
|
|
func FilterStrings(xs []string, p func(x string) bool) []string {
|
|
return FlatMapStrings(xs, func(x string) []string {
|
|
if p(x) {
|
|
return []string{x}
|
|
}
|
|
return []string{}
|
|
})
|
|
}
|
|
|
|
func Map(xs []interface{}, f func(x interface{}) interface{}) []interface{} {
|
|
return FlatMap(xs, func(x interface{}) []interface{} { return []interface{}{f(x)} })
|
|
}
|
|
|
|
func FlatMap(xs []interface{}, f func(x interface{}) []interface{}) []interface{} {
|
|
result := []interface{}{}
|
|
for _, x := range xs {
|
|
result = append(result, f(x)...)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func FlatMapStrings(xs []string, f func(x string) []string) []string {
|
|
result := []string{}
|
|
for _, x := range xs {
|
|
result = append(result, f(x)...)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func MapsUnion(left, right map[interface{}]interface{}) map[interface{}]interface{} {
|
|
result := MapCopy(left)
|
|
|
|
for k, r := range right {
|
|
if l, ok := left[k]; ok {
|
|
switch l := l.(type) {
|
|
case map[interface{}]interface{}:
|
|
switch r := r.(type) {
|
|
case map[interface{}]interface{}:
|
|
result[k] = MapsUnion(l, r)
|
|
default:
|
|
result[k] = Replace(l, r)
|
|
}
|
|
default:
|
|
result[k] = Replace(l, r)
|
|
}
|
|
} else {
|
|
result[k] = Copy(r)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func MapsDifference(left, right map[interface{}]interface{}) map[interface{}]interface{} {
|
|
result := map[interface{}]interface{}{}
|
|
|
|
for k, l := range left {
|
|
if r, ok := right[k]; ok {
|
|
switch l := l.(type) {
|
|
case map[interface{}]interface{}:
|
|
switch r := r.(type) {
|
|
case map[interface{}]interface{}:
|
|
if len(l) == 0 && len(r) == 0 {
|
|
continue
|
|
} else if len(l) == 0 {
|
|
result[k] = l
|
|
} else if v := MapsDifference(l, r); len(v) > 0 {
|
|
result[k] = v
|
|
}
|
|
default:
|
|
if v := Equal(l, r); v == nil {
|
|
result[k] = l
|
|
}
|
|
}
|
|
default:
|
|
if v := Equal(l, r); v == nil {
|
|
result[k] = l
|
|
}
|
|
}
|
|
} else {
|
|
result[k] = l
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func MapsIntersection(left, right map[interface{}]interface{}) map[interface{}]interface{} {
|
|
result := map[interface{}]interface{}{}
|
|
|
|
for k, l := range left {
|
|
if r, ok := right[k]; ok {
|
|
switch l := l.(type) {
|
|
case map[interface{}]interface{}:
|
|
switch r := r.(type) {
|
|
case map[interface{}]interface{}:
|
|
result[k] = MapsIntersection(l, r)
|
|
default:
|
|
if v := Equal(l, r); v != nil {
|
|
result[k] = v
|
|
}
|
|
}
|
|
default:
|
|
if v := Equal(l, r); v != nil {
|
|
result[k] = v
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func MapCopy(data map[interface{}]interface{}) map[interface{}]interface{} {
|
|
result := map[interface{}]interface{}{}
|
|
for k, v := range data {
|
|
result[k] = Copy(v)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func SliceCopy(data []interface{}) []interface{} {
|
|
result := make([]interface{}, len(data), len(data))
|
|
for k, v := range data {
|
|
result[k] = Copy(v)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func ToStrings(data []interface{}) []string {
|
|
result := make([]string, len(data), len(data))
|
|
for k, v := range data {
|
|
result[k] = v.(string)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func GetServices(urls []string) ([]string, error) {
|
|
result := []string{}
|
|
|
|
for _, url := range urls {
|
|
indexUrl := fmt.Sprintf("%s/index.yml", url)
|
|
content, err := LoadResource(indexUrl, true, []string{})
|
|
if err != nil {
|
|
log.Errorf("Failed to load %s: %v", indexUrl, err)
|
|
continue
|
|
}
|
|
|
|
services := make(map[string][]string)
|
|
err = yaml.Unmarshal(content, &services)
|
|
if err != nil {
|
|
log.Errorf("Failed to unmarshal %s: %v", indexUrl, err)
|
|
continue
|
|
}
|
|
|
|
if list, ok := services["services"]; ok {
|
|
result = append(result, list...)
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func DirLs(dir string) ([]interface{}, error) {
|
|
result := []interface{}{}
|
|
files, err := ioutil.ReadDir(dir)
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
for _, f := range files {
|
|
result = append(result, f)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func LoadResource(location string, network bool, urls []string) ([]byte, error) {
|
|
var bytes []byte
|
|
err := ErrNotFound
|
|
|
|
if strings.HasPrefix(location, "http:/") || strings.HasPrefix(location, "https:/") {
|
|
if !network {
|
|
return nil, ErrNoNetwork
|
|
}
|
|
resp, err := http.Get(location)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("non-200 http response: %d", resp.StatusCode)
|
|
}
|
|
defer resp.Body.Close()
|
|
return ioutil.ReadAll(resp.Body)
|
|
} else if strings.HasPrefix(location, "/") {
|
|
return ioutil.ReadFile(location)
|
|
} else if len(location) > 0 {
|
|
for _, url := range urls {
|
|
ymlUrl := fmt.Sprintf("%s/%s/%s.yml", url, location[0:1], location)
|
|
bytes, err = LoadResource(ymlUrl, network, []string{})
|
|
if err == nil {
|
|
log.Debugf("Loaded %s from %s", location, ymlUrl)
|
|
return bytes, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil, err
|
|
}
|
|
|
|
func Map2KVPairs(m map[string]string) []string {
|
|
r := make([]string, 0, len(m))
|
|
for k, v := range m {
|
|
r = append(r, k+"="+v)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func KVPairs2Map(kvs []string) map[string]string {
|
|
r := make(map[string]string, len(kvs))
|
|
for _, kv := range kvs {
|
|
s := strings.SplitN(kv, "=", 2)
|
|
r[s[0]] = s[1]
|
|
}
|
|
return r
|
|
}
|
|
|
|
func TrimSplitN(str, sep string, count int) []string {
|
|
result := []string{}
|
|
for _, part := range strings.SplitN(strings.TrimSpace(str), sep, count) {
|
|
result = append(result, strings.TrimSpace(part))
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func TrimSplit(str, sep string) []string {
|
|
return TrimSplitN(str, sep, -1)
|
|
}
|