Add HashiCorp Nomad provider (#483)

* provider: adding Nomad provider

* updating CONTRIBUTING.md with Nomad provider

* updated README.md by adding the Nomad provider

* fix typo

* adding nomad/api and nomad/testutil deps

* adding Nomad binary dependency for provider tests

* fixed the nomad binary download command step and added tolerations to the nomad provider.

* adding nomad provider demo gif

* adding my name to authors

* adding two missing go-rootcerts files after dep ensure

* delete pod comment
This commit is contained in:
Anubhav Mishra
2019-01-08 01:18:11 +05:30
committed by Robbie Zhang
parent 5796be449b
commit a46e1dd2ce
332 changed files with 126455 additions and 2 deletions

28
vendor/github.com/hashicorp/nomad/helper/args/args.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
package args
import "regexp"
var (
envRe = regexp.MustCompile(`\${[a-zA-Z0-9_\-\.]+}`)
)
// ReplaceEnv takes an arg and replaces all occurrences of environment variables.
// If the variable is found in the passed map it is replaced, otherwise the
// original string is returned.
func ReplaceEnv(arg string, environments ...map[string]string) string {
return envRe.ReplaceAllStringFunc(arg, func(arg string) string {
stripped := arg[2 : len(arg)-1]
for _, env := range environments {
if value, ok := env[stripped]; ok {
return value
}
}
return arg
})
}
// ReplaceEnvWithPlaceHolder replaces all occurrences of environment variables with the placeholder string.
func ReplaceEnvWithPlaceHolder(arg string, placeholder string) string {
return envRe.ReplaceAllString(arg, placeholder)
}

View File

@@ -0,0 +1,66 @@
package discover
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
)
// Checks the current executable, then $GOPATH/bin, and finally the CWD, in that
// order. If it can't be found, an error is returned.
func NomadExecutable() (string, error) {
nomadExe := "nomad"
if runtime.GOOS == "windows" {
nomadExe = "nomad.exe"
}
// Check the current executable.
bin, err := os.Executable()
if err != nil {
return "", fmt.Errorf("Failed to determine the nomad executable: %v", err)
}
if _, err := os.Stat(bin); err == nil && isNomad(bin, nomadExe) {
return bin, nil
}
// Check the $PATH
if bin, err := exec.LookPath(nomadExe); err == nil {
return bin, nil
}
// Check the $GOPATH.
bin = filepath.Join(os.Getenv("GOPATH"), "bin", nomadExe)
if _, err := os.Stat(bin); err == nil {
return bin, nil
}
// Check the CWD.
pwd, err := os.Getwd()
if err != nil {
return "", fmt.Errorf("Could not find Nomad executable (%v): %v", nomadExe, err)
}
bin = filepath.Join(pwd, nomadExe)
if _, err := os.Stat(bin); err == nil {
return bin, nil
}
// Check CWD/bin
bin = filepath.Join(pwd, "bin", nomadExe)
if _, err := os.Stat(bin); err == nil {
return bin, nil
}
return "", fmt.Errorf("Could not find Nomad executable (%v)", nomadExe)
}
func isNomad(path, nomadExe string) bool {
if strings.HasSuffix(path, ".test") || strings.HasSuffix(path, ".test.exe") {
return false
}
return true
}

View File

@@ -0,0 +1,129 @@
package flatmap
import (
"fmt"
"reflect"
)
// Flatten takes an object and returns a flat map of the object. The keys of the
// map is the path of the field names until a primitive field is reached and the
// value is a string representation of the terminal field.
func Flatten(obj interface{}, filter []string, primitiveOnly bool) map[string]string {
flat := make(map[string]string)
v := reflect.ValueOf(obj)
if !v.IsValid() {
return nil
}
flatten("", v, primitiveOnly, false, flat)
for _, f := range filter {
if _, ok := flat[f]; ok {
delete(flat, f)
}
}
return flat
}
// flatten recursively calls itself to create a flatmap representation of the
// passed value. The results are stored into the output map and the keys are
// the fields prepended with the passed prefix.
// XXX: A current restriction is that maps only support string keys.
func flatten(prefix string, v reflect.Value, primitiveOnly, enteredStruct bool, output map[string]string) {
switch v.Kind() {
case reflect.Bool:
output[prefix] = fmt.Sprintf("%v", v.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
output[prefix] = fmt.Sprintf("%v", v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
output[prefix] = fmt.Sprintf("%v", v.Uint())
case reflect.Float32, reflect.Float64:
output[prefix] = fmt.Sprintf("%v", v.Float())
case reflect.Complex64, reflect.Complex128:
output[prefix] = fmt.Sprintf("%v", v.Complex())
case reflect.String:
output[prefix] = fmt.Sprintf("%v", v.String())
case reflect.Invalid:
output[prefix] = "nil"
case reflect.Ptr:
if primitiveOnly && enteredStruct {
return
}
e := v.Elem()
if !e.IsValid() {
output[prefix] = "nil"
}
flatten(prefix, e, primitiveOnly, enteredStruct, output)
case reflect.Map:
for _, k := range v.MapKeys() {
if k.Kind() == reflect.Interface {
k = k.Elem()
}
if k.Kind() != reflect.String {
panic(fmt.Sprintf("%q: map key is not string: %s", prefix, k))
}
flatten(getSubKeyPrefix(prefix, k.String()), v.MapIndex(k), primitiveOnly, enteredStruct, output)
}
case reflect.Struct:
if primitiveOnly && enteredStruct {
return
}
enteredStruct = true
t := v.Type()
for i := 0; i < v.NumField(); i++ {
name := t.Field(i).Name
val := v.Field(i)
if val.Kind() == reflect.Interface && !val.IsNil() {
val = val.Elem()
}
flatten(getSubPrefix(prefix, name), val, primitiveOnly, enteredStruct, output)
}
case reflect.Interface:
if primitiveOnly {
return
}
e := v.Elem()
if !e.IsValid() {
output[prefix] = "nil"
return
}
flatten(prefix, e, primitiveOnly, enteredStruct, output)
case reflect.Array, reflect.Slice:
if primitiveOnly {
return
}
if v.Kind() == reflect.Slice && v.IsNil() {
output[prefix] = "nil"
return
}
for i := 0; i < v.Len(); i++ {
flatten(fmt.Sprintf("%s[%d]", prefix, i), v.Index(i), primitiveOnly, enteredStruct, output)
}
default:
panic(fmt.Sprintf("prefix %q; unsupported type %v", prefix, v.Kind()))
}
}
// getSubPrefix takes the current prefix and the next subfield and returns an
// appropriate prefix.
func getSubPrefix(curPrefix, subField string) string {
if curPrefix != "" {
return fmt.Sprintf("%s.%s", curPrefix, subField)
}
return fmt.Sprintf("%s", subField)
}
// getSubKeyPrefix takes the current prefix and the next subfield and returns an
// appropriate prefix for a map field.
func getSubKeyPrefix(curPrefix, subField string) string {
if curPrefix != "" {
return fmt.Sprintf("%s[%s]", curPrefix, subField)
}
return fmt.Sprintf("%s", subField)
}

304
vendor/github.com/hashicorp/nomad/helper/funcs.go generated vendored Normal file
View File

@@ -0,0 +1,304 @@
package helper
import (
"crypto/sha512"
"fmt"
"regexp"
"time"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl/hcl/ast"
)
// validUUID is used to check if a given string looks like a UUID
var validUUID = regexp.MustCompile(`(?i)^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$`)
// IsUUID returns true if the given string is a valid UUID.
func IsUUID(str string) bool {
const uuidLen = 36
if len(str) != uuidLen {
return false
}
return validUUID.MatchString(str)
}
// HashUUID takes an input UUID and returns a hashed version of the UUID to
// ensure it is well distributed.
func HashUUID(input string) (output string, hashed bool) {
if !IsUUID(input) {
return "", false
}
// Hash the input
buf := sha512.Sum512([]byte(input))
output = fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
buf[0:4],
buf[4:6],
buf[6:8],
buf[8:10],
buf[10:16])
return output, true
}
// boolToPtr returns the pointer to a boolean
func BoolToPtr(b bool) *bool {
return &b
}
// IntToPtr returns the pointer to an int
func IntToPtr(i int) *int {
return &i
}
// Int64ToPtr returns the pointer to an int
func Int64ToPtr(i int64) *int64 {
return &i
}
// UintToPtr returns the pointer to an uint
func Uint64ToPtr(u uint64) *uint64 {
return &u
}
// StringToPtr returns the pointer to a string
func StringToPtr(str string) *string {
return &str
}
// TimeToPtr returns the pointer to a time stamp
func TimeToPtr(t time.Duration) *time.Duration {
return &t
}
func IntMin(a, b int) int {
if a < b {
return a
}
return b
}
func IntMax(a, b int) int {
if a > b {
return a
}
return b
}
func Uint64Max(a, b uint64) uint64 {
if a > b {
return a
}
return b
}
// MapStringStringSliceValueSet returns the set of values in a map[string][]string
func MapStringStringSliceValueSet(m map[string][]string) []string {
set := make(map[string]struct{})
for _, slice := range m {
for _, v := range slice {
set[v] = struct{}{}
}
}
flat := make([]string, 0, len(set))
for k := range set {
flat = append(flat, k)
}
return flat
}
func SliceStringToSet(s []string) map[string]struct{} {
m := make(map[string]struct{}, (len(s)+1)/2)
for _, k := range s {
m[k] = struct{}{}
}
return m
}
// SliceStringIsSubset returns whether the smaller set of strings is a subset of
// the larger. If the smaller slice is not a subset, the offending elements are
// returned.
func SliceStringIsSubset(larger, smaller []string) (bool, []string) {
largerSet := make(map[string]struct{}, len(larger))
for _, l := range larger {
largerSet[l] = struct{}{}
}
subset := true
var offending []string
for _, s := range smaller {
if _, ok := largerSet[s]; !ok {
subset = false
offending = append(offending, s)
}
}
return subset, offending
}
func SliceSetDisjoint(first, second []string) (bool, []string) {
contained := make(map[string]struct{}, len(first))
for _, k := range first {
contained[k] = struct{}{}
}
offending := make(map[string]struct{})
for _, k := range second {
if _, ok := contained[k]; ok {
offending[k] = struct{}{}
}
}
if len(offending) == 0 {
return true, nil
}
flattened := make([]string, 0, len(offending))
for k := range offending {
flattened = append(flattened, k)
}
return false, flattened
}
// Helpers for copying generic structures.
func CopyMapStringString(m map[string]string) map[string]string {
l := len(m)
if l == 0 {
return nil
}
c := make(map[string]string, l)
for k, v := range m {
c[k] = v
}
return c
}
func CopyMapStringStruct(m map[string]struct{}) map[string]struct{} {
l := len(m)
if l == 0 {
return nil
}
c := make(map[string]struct{}, l)
for k := range m {
c[k] = struct{}{}
}
return c
}
func CopyMapStringInt(m map[string]int) map[string]int {
l := len(m)
if l == 0 {
return nil
}
c := make(map[string]int, l)
for k, v := range m {
c[k] = v
}
return c
}
func CopyMapStringFloat64(m map[string]float64) map[string]float64 {
l := len(m)
if l == 0 {
return nil
}
c := make(map[string]float64, l)
for k, v := range m {
c[k] = v
}
return c
}
// CopyMapStringSliceString copies a map of strings to string slices such as
// http.Header
func CopyMapStringSliceString(m map[string][]string) map[string][]string {
l := len(m)
if l == 0 {
return nil
}
c := make(map[string][]string, l)
for k, v := range m {
c[k] = CopySliceString(v)
}
return c
}
func CopySliceString(s []string) []string {
l := len(s)
if l == 0 {
return nil
}
c := make([]string, l)
for i, v := range s {
c[i] = v
}
return c
}
func CopySliceInt(s []int) []int {
l := len(s)
if l == 0 {
return nil
}
c := make([]int, l)
for i, v := range s {
c[i] = v
}
return c
}
// CleanEnvVar replaces all occurrences of illegal characters in an environment
// variable with the specified byte.
func CleanEnvVar(s string, r byte) string {
b := []byte(s)
for i, c := range b {
switch {
case c == '_':
case c == '.':
case c >= 'a' && c <= 'z':
case c >= 'A' && c <= 'Z':
case i > 0 && c >= '0' && c <= '9':
default:
// Replace!
b[i] = r
}
}
return string(b)
}
func CheckHCLKeys(node ast.Node, valid []string) error {
var list *ast.ObjectList
switch n := node.(type) {
case *ast.ObjectList:
list = n
case *ast.ObjectType:
list = n.List
default:
return fmt.Errorf("cannot check HCL keys of type %T", n)
}
validMap := make(map[string]struct{}, len(valid))
for _, v := range valid {
validMap[v] = struct{}{}
}
var result error
for _, item := range list.Items {
key := item.Keys[0].Token.Value().(string)
if _, ok := validMap[key]; !ok {
result = multierror.Append(result, fmt.Errorf(
"invalid key: %s", key))
}
}
return result
}

View File

@@ -0,0 +1,58 @@
// Package testlog creates a *log.Logger backed by *testing.T to ease logging
// in tests. This allows logs from components being tested to only be printed
// if the test fails (or the verbose flag is specified).
package testlog
import (
"io"
"log"
"os"
)
// UseStdout returns true if NOMAD_TEST_STDOUT=1 and sends logs to stdout.
func UseStdout() bool {
return os.Getenv("NOMAD_TEST_STDOUT") == "1"
}
// LogPrinter is the methods of testing.T (or testing.B) needed by the test
// logger.
type LogPrinter interface {
Logf(format string, args ...interface{})
}
// writer implements io.Writer on top of a Logger.
type writer struct {
t LogPrinter
}
// Write to an underlying Logger. Never returns an error.
func (w *writer) Write(p []byte) (n int, err error) {
w.t.Logf(string(p))
return len(p), nil
}
// NewWriter creates a new io.Writer backed by a Logger.
func NewWriter(t LogPrinter) io.Writer {
if UseStdout() {
return os.Stdout
}
return &writer{t}
}
// New returns a new test logger. See https://golang.org/pkg/log/#New
func New(t LogPrinter, prefix string, flag int) *log.Logger {
if UseStdout() {
return log.New(os.Stdout, prefix, flag)
}
return log.New(&writer{t}, prefix, flag)
}
// WithPrefix returns a new test logger with the Lmicroseconds flag set.
func WithPrefix(t LogPrinter, prefix string) *log.Logger {
return New(t, prefix, log.Lmicroseconds)
}
// NewLog logger with "TEST" prefix and the Lmicroseconds flag.
func Logger(t LogPrinter) *log.Logger {
return WithPrefix(t, "")
}

21
vendor/github.com/hashicorp/nomad/helper/uuid/uuid.go generated vendored Normal file
View File

@@ -0,0 +1,21 @@
package uuid
import (
crand "crypto/rand"
"fmt"
)
// Generate is used to generate a random UUID
func Generate() string {
buf := make([]byte, 16)
if _, err := crand.Read(buf); err != nil {
panic(fmt.Errorf("failed to read random bytes: %v", err))
}
return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
buf[0:4],
buf[4:6],
buf[6:8],
buf[8:10],
buf[10:16])
}