mirror of
https://github.com/kemko/nomad.git
synced 2026-01-04 01:15:43 +03:00
23
api/tasks.go
23
api/tasks.go
@@ -2,6 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -323,12 +326,30 @@ func (t *Task) Canonicalize(tg *TaskGroup, job *Job) {
|
||||
type TaskArtifact struct {
|
||||
GetterSource *string `mapstructure:"source"`
|
||||
GetterOptions map[string]string `mapstructure:"options"`
|
||||
GetterMode *string `mapstructure:"mode"`
|
||||
RelativeDest *string `mapstructure:"destination"`
|
||||
}
|
||||
|
||||
func (a *TaskArtifact) Canonicalize() {
|
||||
if a.GetterMode == nil {
|
||||
a.GetterMode = helper.StringToPtr("any")
|
||||
}
|
||||
if a.GetterSource == nil {
|
||||
// Shouldn't be possible, but we don't want to panic
|
||||
a.GetterSource = helper.StringToPtr("")
|
||||
}
|
||||
if a.RelativeDest == nil {
|
||||
a.RelativeDest = helper.StringToPtr("local/")
|
||||
switch *a.GetterMode {
|
||||
case "file":
|
||||
// File mode should default to local/filename
|
||||
dest := *a.GetterSource
|
||||
dest = path.Base(dest)
|
||||
dest = filepath.Join("local", dest)
|
||||
a.RelativeDest = &dest
|
||||
default:
|
||||
// Default to a directory
|
||||
a.RelativeDest = helper.StringToPtr("local/")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,3 +219,17 @@ func TestTask_Constrain(t *testing.T) {
|
||||
t.Fatalf("expect: %#v, got: %#v", expect, task.Constraints)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTask_Artifact(t *testing.T) {
|
||||
a := TaskArtifact{
|
||||
GetterSource: helper.StringToPtr("http://localhost/foo.txt"),
|
||||
GetterMode: helper.StringToPtr("file"),
|
||||
}
|
||||
a.Canonicalize()
|
||||
if *a.GetterMode != "file" {
|
||||
t.Errorf("expected file but found %q", *a.GetterMode)
|
||||
}
|
||||
if *a.RelativeDest != "local/foo.txt" {
|
||||
t.Errorf("expected local/foo.txt but found %q", *a.RelativeDest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ type EnvReplacer interface {
|
||||
}
|
||||
|
||||
// getClient returns a client that is suitable for Nomad downloading artifacts.
|
||||
func getClient(src, dst string) *gg.Client {
|
||||
func getClient(src string, mode gg.ClientMode, dst string) *gg.Client {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
@@ -50,7 +50,7 @@ func getClient(src, dst string) *gg.Client {
|
||||
return &gg.Client{
|
||||
Src: src,
|
||||
Dst: dst,
|
||||
Mode: gg.ClientModeAny,
|
||||
Mode: mode,
|
||||
Getters: getters,
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,17 @@ func GetArtifact(taskEnv EnvReplacer, artifact *structs.TaskArtifact, taskDir st
|
||||
|
||||
// Download the artifact
|
||||
dest := filepath.Join(taskDir, artifact.RelativeDest)
|
||||
if err := getClient(url, dest).Get(); err != nil {
|
||||
|
||||
// Convert from string getter mode to go-getter const
|
||||
mode := gg.ClientModeAny
|
||||
switch artifact.GetterMode {
|
||||
case structs.GetterModeFile:
|
||||
mode = gg.ClientModeFile
|
||||
case structs.GetterModeDir:
|
||||
mode = gg.ClientModeDir
|
||||
}
|
||||
|
||||
if err := getClient(url, mode, dest).Get(); err != nil {
|
||||
return newGetError(url, err, true)
|
||||
}
|
||||
|
||||
|
||||
@@ -654,6 +654,7 @@ func ApiTaskToStructsTask(apiTask *api.Task, structsTask *structs.Task) {
|
||||
structsTask.Artifacts[k] = &structs.TaskArtifact{
|
||||
GetterSource: *ta.GetterSource,
|
||||
GetterOptions: ta.GetterOptions,
|
||||
GetterMode: *ta.GetterMode,
|
||||
RelativeDest: *ta.RelativeDest,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,6 +788,7 @@ func parseArtifacts(result *[]*api.TaskArtifact, list *ast.ObjectList) error {
|
||||
valid := []string{
|
||||
"source",
|
||||
"options",
|
||||
"mode",
|
||||
"destination",
|
||||
}
|
||||
if err := checkHCLKeys(o.Val, valid); err != nil {
|
||||
|
||||
@@ -166,6 +166,7 @@ func TestParse(t *testing.T) {
|
||||
GetterOptions: map[string]string{
|
||||
"checksum": "md5:ff1cc0d3432dad54d607c1505fb7245c",
|
||||
},
|
||||
GetterMode: helper.StringToPtr("file"),
|
||||
},
|
||||
},
|
||||
Vault: &api.Vault{
|
||||
|
||||
@@ -140,6 +140,7 @@ job "binstore-storagelocker" {
|
||||
artifact {
|
||||
source = "http://bar.com/artifact"
|
||||
destination = "test/foo/"
|
||||
mode = "file"
|
||||
|
||||
options {
|
||||
checksum = "md5:ff1cc0d3432dad54d607c1505fb7245c"
|
||||
|
||||
@@ -2469,6 +2469,7 @@ func TestTaskDiff(t *testing.T) {
|
||||
GetterOptions: map[string]string{
|
||||
"bar": "baz",
|
||||
},
|
||||
GetterMode: "dir",
|
||||
RelativeDest: "bar",
|
||||
},
|
||||
},
|
||||
@@ -2487,6 +2488,7 @@ func TestTaskDiff(t *testing.T) {
|
||||
GetterOptions: map[string]string{
|
||||
"bam": "baz",
|
||||
},
|
||||
GetterMode: "file",
|
||||
RelativeDest: "bam",
|
||||
},
|
||||
},
|
||||
@@ -2498,6 +2500,12 @@ func TestTaskDiff(t *testing.T) {
|
||||
Type: DiffTypeAdded,
|
||||
Name: "Artifact",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "GetterMode",
|
||||
Old: "",
|
||||
New: "file",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeAdded,
|
||||
Name: "GetterOptions[bam]",
|
||||
@@ -2522,6 +2530,12 @@ func TestTaskDiff(t *testing.T) {
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "Artifact",
|
||||
Fields: []*FieldDiff{
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "GetterMode",
|
||||
Old: "dir",
|
||||
New: "",
|
||||
},
|
||||
{
|
||||
Type: DiffTypeDeleted,
|
||||
Name: "GetterOptions[bar]",
|
||||
|
||||
@@ -78,6 +78,10 @@ const (
|
||||
ProtocolVersion = "protocol"
|
||||
APIMajorVersion = "api.major"
|
||||
APIMinorVersion = "api.minor"
|
||||
|
||||
GetterModeAny = "any"
|
||||
GetterModeFile = "file"
|
||||
GetterModeDir = "dir"
|
||||
)
|
||||
|
||||
// RPCInfo is used to describe common information about query
|
||||
@@ -3405,6 +3409,10 @@ type TaskArtifact struct {
|
||||
// go-getter.
|
||||
GetterOptions map[string]string
|
||||
|
||||
// GetterMode is the go-getter.ClientMode for fetching resources.
|
||||
// Defaults to "any" but can be set to "file" or "dir".
|
||||
GetterMode string
|
||||
|
||||
// RelativeDest is the download destination given relative to the task's
|
||||
// directory.
|
||||
RelativeDest string
|
||||
@@ -3453,6 +3461,17 @@ func (ta *TaskArtifact) Validate() error {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("source must be specified"))
|
||||
}
|
||||
|
||||
switch ta.GetterMode {
|
||||
case "":
|
||||
// Default to any
|
||||
ta.GetterMode = GetterModeAny
|
||||
case GetterModeAny, GetterModeFile, GetterModeDir:
|
||||
// Ok
|
||||
default:
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid artifact mode %q; must be one of: %s, %s, %s",
|
||||
ta.GetterMode, GetterModeAny, GetterModeFile, GetterModeDir))
|
||||
}
|
||||
|
||||
escaped, err := PathEscapesAllocDir("task", ta.RelativeDest)
|
||||
if err != nil {
|
||||
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid destination path: %v", err))
|
||||
|
||||
2
vendor/github.com/hashicorp/go-getter/appveyor.yml
generated
vendored
2
vendor/github.com/hashicorp/go-getter/appveyor.yml
generated
vendored
@@ -1,5 +1,5 @@
|
||||
version: "build-{branch}-{build}"
|
||||
image: Visual Studio 2015
|
||||
image: Visual Studio 2017
|
||||
clone_folder: c:\gopath\github.com\hashicorp\go-getter
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
Reference in New Issue
Block a user