2015-02-09 04:38:37 +00:00
|
|
|
package util
|
|
|
|
|
|
|
|
import (
|
|
|
|
"archive/tar"
|
2015-03-25 22:27:33 +00:00
|
|
|
"bufio"
|
2015-04-16 06:16:23 +00:00
|
|
|
"errors"
|
2015-02-09 04:38:37 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2015-03-29 09:57:15 +00:00
|
|
|
"io/ioutil"
|
2015-02-14 16:35:12 +00:00
|
|
|
"math/rand"
|
2015-03-29 09:57:15 +00:00
|
|
|
"net/http"
|
2015-02-09 04:38:37 +00:00
|
|
|
"os"
|
|
|
|
"path"
|
2015-03-29 09:57:15 +00:00
|
|
|
"strings"
|
2015-02-09 04:38:37 +00:00
|
|
|
|
2015-03-25 22:27:33 +00:00
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
|
2015-04-16 05:57:59 +00:00
|
|
|
log "github.com/Sirupsen/logrus"
|
|
|
|
|
2015-02-09 04:38:37 +00:00
|
|
|
"github.com/docker/docker/pkg/mount"
|
2015-07-29 06:52:15 +00:00
|
|
|
"reflect"
|
2015-02-09 04:38:37 +00:00
|
|
|
)
|
|
|
|
|
2015-02-14 16:35:12 +00:00
|
|
|
var (
|
2015-04-16 06:16:23 +00:00
|
|
|
letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|
|
|
ErrNoNetwork = errors.New("Networking not available to load resource")
|
2015-04-16 05:57:59 +00:00
|
|
|
ErrNotFound = errors.New("Failed to find resource")
|
2015-02-14 16:35:12 +00:00
|
|
|
)
|
|
|
|
|
2015-03-25 22:27:33 +00:00
|
|
|
func GetOSType() string {
|
|
|
|
f, err := os.Open("/etc/os-release")
|
|
|
|
defer f.Close()
|
|
|
|
if err != nil {
|
|
|
|
return "busybox"
|
|
|
|
}
|
|
|
|
scanner := bufio.NewScanner(f)
|
|
|
|
for scanner.Scan() {
|
|
|
|
line := scanner.Text()
|
|
|
|
if len(line) > 8 && line[:8] == "ID_LIKE=" {
|
|
|
|
return line[8:]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "busybox"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-02-09 04:38:37 +00:00
|
|
|
func Remount(directory, options string) error {
|
|
|
|
return mount.Mount("", directory, "", fmt.Sprintf("remount,%s", options))
|
|
|
|
}
|
|
|
|
|
|
|
|
func ExtractTar(archive string, dest string) error {
|
|
|
|
f, err := os.Open(archive)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
input := tar.NewReader(f)
|
|
|
|
|
|
|
|
for {
|
|
|
|
header, err := input.Next()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if header == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
fileInfo := header.FileInfo()
|
|
|
|
fileName := path.Join(dest, header.Name)
|
|
|
|
if fileInfo.IsDir() {
|
|
|
|
//log.Debugf("DIR : %s", fileName)
|
|
|
|
err = os.MkdirAll(fileName, fileInfo.Mode())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//log.Debugf("FILE: %s", fileName)
|
|
|
|
destFile, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileInfo.Mode())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = io.Copy(destFile, input)
|
|
|
|
// Not deferring, concerned about holding open too many files
|
|
|
|
destFile.Close()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2015-02-14 16:35:12 +00:00
|
|
|
|
|
|
|
func Contains(values []string, value string) bool {
|
|
|
|
if len(value) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2015-02-16 23:38:49 +00:00
|
|
|
for _, i := range values {
|
|
|
|
if i == value {
|
2015-02-14 16:35:12 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
type ReturnsErr func() error
|
|
|
|
|
|
|
|
func ShortCircuit(funcs ...ReturnsErr) error {
|
|
|
|
for _, f := range funcs {
|
|
|
|
err := f()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type ErrWriter struct {
|
|
|
|
w io.Writer
|
|
|
|
Err error
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewErrorWriter(w io.Writer) *ErrWriter {
|
|
|
|
return &ErrWriter{
|
|
|
|
w: w,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e *ErrWriter) Write(buf []byte) *ErrWriter {
|
|
|
|
if e.Err != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
_, e.Err = e.w.Write(buf)
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
func RandSeq(n int) string {
|
|
|
|
b := make([]rune, n)
|
|
|
|
for i := range b {
|
|
|
|
b[i] = letters[rand.Intn(len(letters))]
|
|
|
|
}
|
|
|
|
return string(b)
|
|
|
|
}
|
2015-03-15 04:27:04 +00:00
|
|
|
|
|
|
|
func Convert(from, to interface{}) error {
|
|
|
|
bytes, err := yaml.Marshal(from)
|
|
|
|
if err != nil {
|
2015-08-20 13:06:48 +00:00
|
|
|
log.WithFields(log.Fields{"from": from, "err": err}).Warn("Error serializing to YML")
|
2015-03-15 04:27:04 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return yaml.Unmarshal(bytes, to)
|
|
|
|
}
|
2015-03-18 13:22:19 +00:00
|
|
|
|
2015-04-16 06:16:23 +00:00
|
|
|
func MergeBytes(left, right []byte) ([]byte, error) {
|
|
|
|
leftMap := make(map[interface{}]interface{})
|
|
|
|
rightMap := make(map[interface{}]interface{})
|
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
if err := yaml.Unmarshal(left, &leftMap); err != nil {
|
2015-04-16 06:16:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
if err := yaml.Unmarshal(right, &rightMap); err != nil {
|
2015-04-16 06:16:23 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
return yaml.Marshal(MapsUnion(leftMap, rightMap, Replace))
|
|
|
|
}
|
|
|
|
|
|
|
|
func Copy(d interface{}) interface{} {
|
|
|
|
switch d := d.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
return MapCopy(d)
|
2015-08-21 08:24:55 +00:00
|
|
|
case []interface{}:
|
|
|
|
return SliceCopy(d)
|
2015-07-29 06:52:15 +00:00
|
|
|
default:
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
}
|
2015-04-16 06:16:23 +00:00
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
func Replace(l, r interface{}) interface{} {
|
|
|
|
return r
|
2015-04-16 06:16:23 +00:00
|
|
|
}
|
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
func Equal(l, r interface{}) interface{} {
|
|
|
|
if reflect.DeepEqual(l, r) {
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-08-21 08:24:55 +00:00
|
|
|
func ExistsIn(x interface{}, s []interface{}) bool {
|
|
|
|
for _, y := range s {
|
|
|
|
if reflect.DeepEqual(x, y) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func SlicesUnion(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
|
|
|
|
result := SliceCopy(left)
|
|
|
|
for _, r := range right {
|
|
|
|
if !ExistsIn(r, result) {
|
|
|
|
result = append(result, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func SlicesIntersection(left, right []interface{}, op func(interface{}, interface{}) interface{}) []interface{} {
|
|
|
|
result := []interface{}{}
|
|
|
|
for _, r := range right {
|
|
|
|
if ExistsIn(r, left) {
|
|
|
|
result = append(result, r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
func MapsUnion(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} {
|
|
|
|
result := MapCopy(left)
|
|
|
|
|
|
|
|
for k, r := range right {
|
2015-08-21 08:24:55 +00:00
|
|
|
if l, ok := left[k]; ok {
|
2015-07-29 06:52:15 +00:00
|
|
|
switch l := l.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
switch r := r.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
result[k] = MapsUnion(l, r, op)
|
|
|
|
default:
|
|
|
|
result[k] = op(l, r)
|
2015-03-18 13:22:19 +00:00
|
|
|
}
|
2015-08-21 08:24:55 +00:00
|
|
|
case []interface{}:
|
|
|
|
switch r := r.(type) {
|
|
|
|
case []interface{}:
|
|
|
|
result[k] = SlicesUnion(l, r, op)
|
|
|
|
default:
|
|
|
|
result[k] = op(l, r)
|
|
|
|
}
|
2015-07-29 06:52:15 +00:00
|
|
|
default:
|
|
|
|
result[k] = op(l, r)
|
2015-03-18 13:22:19 +00:00
|
|
|
}
|
2015-07-29 06:52:15 +00:00
|
|
|
} else {
|
|
|
|
result[k] = Copy(r)
|
2015-03-18 13:22:19 +00:00
|
|
|
}
|
2015-07-29 06:52:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
2015-03-18 13:22:19 +00:00
|
|
|
|
2015-07-29 06:52:15 +00:00
|
|
|
func MapsIntersection(left, right map[interface{}]interface{}, op func(interface{}, interface{}) interface{}) map[interface{}]interface{} {
|
|
|
|
result := map[interface{}]interface{}{}
|
|
|
|
|
|
|
|
for k, l := range left {
|
|
|
|
if r, ok := right[k]; ok {
|
2015-08-21 08:24:55 +00:00
|
|
|
switch l := l.(type) {
|
2015-07-29 06:52:15 +00:00
|
|
|
case map[interface{}]interface{}:
|
2015-08-21 08:24:55 +00:00
|
|
|
switch r := r.(type) {
|
2015-07-29 06:52:15 +00:00
|
|
|
case map[interface{}]interface{}:
|
|
|
|
result[k] = MapsIntersection(l, r, op)
|
|
|
|
default:
|
2015-08-21 08:24:55 +00:00
|
|
|
if v := op(l, r); v != nil {
|
|
|
|
result[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case []interface{}:
|
|
|
|
switch r := r.(type) {
|
|
|
|
case []interface{}:
|
|
|
|
result[k] = SlicesIntersection(l, r, op)
|
|
|
|
default:
|
|
|
|
if v := op(l, r); v != nil {
|
|
|
|
result[k] = v
|
2015-07-29 06:52:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
2015-08-21 08:24:55 +00:00
|
|
|
if v := op(l, r); v != nil {
|
|
|
|
result[k] = v
|
2015-07-29 06:52:15 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-18 13:22:19 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-29 06:52:15 +00:00
|
|
|
|
|
|
|
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
|
2015-03-18 13:22:19 +00:00
|
|
|
}
|
2015-03-29 09:57:15 +00:00
|
|
|
|
2015-08-21 08:24:55 +00:00
|
|
|
func SliceCopy(data []interface{}) []interface{} {
|
|
|
|
result := make([]interface{}, len(data), len(data))
|
|
|
|
for k, v := range data {
|
|
|
|
result[k] = Copy(v)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2015-04-16 05:57:59 +00:00
|
|
|
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...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-26 21:00:18 +00:00
|
|
|
return result, nil
|
2015-04-16 05:57:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func LoadResource(location string, network bool, urls []string) ([]byte, error) {
|
|
|
|
var bytes []byte
|
|
|
|
err := ErrNotFound
|
|
|
|
|
2015-03-29 09:57:15 +00:00
|
|
|
if strings.HasPrefix(location, "http:/") || strings.HasPrefix(location, "https:/") {
|
2015-04-16 06:16:23 +00:00
|
|
|
if !network {
|
|
|
|
return nil, ErrNoNetwork
|
|
|
|
}
|
2015-03-29 09:57:15 +00:00
|
|
|
resp, err := http.Get(location)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-04-16 05:57:59 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return nil, fmt.Errorf("non-200 http response: %d", resp.StatusCode)
|
|
|
|
}
|
2015-03-29 09:57:15 +00:00
|
|
|
defer resp.Body.Close()
|
|
|
|
return ioutil.ReadAll(resp.Body)
|
2015-04-16 05:57:59 +00:00
|
|
|
} else if strings.HasPrefix(location, "/") {
|
2015-03-29 09:57:15 +00:00
|
|
|
return ioutil.ReadFile(location)
|
2015-04-16 05:57:59 +00:00
|
|
|
} 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 {
|
2015-04-17 13:31:38 +00:00
|
|
|
log.Debugf("Loaded %s from %s", location, ymlUrl)
|
2015-04-16 05:57:59 +00:00
|
|
|
return bytes, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetValue(kvPairs []string, key string) string {
|
|
|
|
if kvPairs == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
prefix := key + "="
|
|
|
|
for _, i := range kvPairs {
|
|
|
|
if strings.HasPrefix(i, prefix) {
|
|
|
|
return strings.TrimPrefix(i, prefix)
|
|
|
|
}
|
2015-03-29 09:57:15 +00:00
|
|
|
}
|
2015-04-16 05:57:59 +00:00
|
|
|
|
|
|
|
return ""
|
2015-03-29 09:57:15 +00:00
|
|
|
}
|
2015-04-29 10:32:12 +00:00
|
|
|
|
|
|
|
func Map2KVPairs(m map[string]string) []string {
|
|
|
|
r := make([]string, 0, len(m))
|
|
|
|
for k, v := range m {
|
2015-06-15 20:58:16 +00:00
|
|
|
r = append(r, k+"="+v)
|
2015-04-29 10:32:12 +00:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func KVPairs2Map(kvs []string) map[string]string {
|
|
|
|
r := make(map[string]string, len(kvs))
|
|
|
|
for _, kv := range kvs {
|
2015-04-30 08:43:45 +00:00
|
|
|
s := strings.SplitN(kv, "=", 2)
|
|
|
|
r[s[0]] = s[1]
|
2015-04-29 10:32:12 +00:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|
2015-08-04 21:45:38 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|