Files
nomad/client/allocrunner/taskrunner/getter/params_test.go
Seth Hoenig f1ce127524 jobspec: add a chown option to artifact block (#24157)
* jobspec: add a chown option to artifact block

This PR adds a boolean 'chown' field to the artifact block.

It indicates whether the Nomad client should chown the downloaded files
and directories to be owned by the task.user. This is useful for drivers
like raw_exec and exec2 which are subject to the host filesystem user
permissions structure. Before, these drivers might not be able to use or
manage the downloaded artifacts since they would be owned by the root
user on a typical Nomad client configuration.

* api: no need for pointer of chown field
2024-10-11 11:30:27 -05:00

164 lines
4.1 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package getter
import (
"context"
"io"
"strings"
"testing"
"time"
"github.com/hashicorp/go-getter"
"github.com/shoenig/test/must"
)
const paramsAsJSON = `
{
"http_read_timeout": 1000000000,
"http_max_bytes": 2000,
"gcs_timeout": 2000000000,
"git_timeout": 3000000000,
"hg_timeout": 4000000000,
"s3_timeout": 5000000000,
"decompression_limit_file_count": 3,
"decompression_limit_size": 98765,
"disable_filesystem_isolation": true,
"filesystem_isolation_extra_paths": [
"f:r:/dev/urandom",
"d:rx:/opt/bin",
"d:r:/tmp/stash"
],
"set_environment_variables": "",
"artifact_mode": 2,
"artifact_insecure": false,
"artifact_source": "https://example.com/file.txt",
"artifact_destination": "local/out.txt",
"artifact_headers": {
"X-Nomad-Artifact": ["hi"]
},
"alloc_dir": "/path/to/alloc",
"task_dir": "/path/to/alloc/task",
"chown": true,
"user":"nobody"
}`
var paramsAsStruct = &parameters{
HTTPReadTimeout: 1 * time.Second,
HTTPMaxBytes: 2000,
GCSTimeout: 2 * time.Second,
GitTimeout: 3 * time.Second,
HgTimeout: 4 * time.Second,
S3Timeout: 5 * time.Second,
DecompressionLimitFileCount: 3,
DecompressionLimitSize: 98765,
DisableFilesystemIsolation: true,
FilesystemIsolationExtraPaths: []string{
"f:r:/dev/urandom",
"d:rx:/opt/bin",
"d:r:/tmp/stash",
},
Mode: getter.ClientModeFile,
Source: "https://example.com/file.txt",
Destination: "local/out.txt",
AllocDir: "/path/to/alloc",
TaskDir: "/path/to/alloc/task",
Headers: map[string][]string{
"X-Nomad-Artifact": {"hi"},
},
User: "nobody",
Chown: true,
}
func TestParameters_reader(t *testing.T) {
p := paramsAsStruct
reader := p.reader()
b, err := io.ReadAll(reader)
must.NoError(t, err)
must.EqJSON(t, paramsAsJSON, string(b))
}
func TestParameters_read(t *testing.T) {
reader := strings.NewReader(paramsAsJSON)
p := new(parameters)
err := p.read(reader)
must.NoError(t, err)
must.Equal(t, paramsAsStruct, p)
}
func TestParameters_deadline(t *testing.T) {
t.Run("typical", func(t *testing.T) {
dur := paramsAsStruct.deadline()
must.Eq(t, 31*time.Minute, dur)
})
t.Run("long", func(t *testing.T) {
params := &parameters{
HTTPReadTimeout: 1 * time.Hour,
GCSTimeout: 2 * time.Hour,
GitTimeout: 3 * time.Hour,
HgTimeout: 4 * time.Hour,
S3Timeout: 5 * time.Hour,
}
dur := params.deadline()
must.Eq(t, 5*time.Hour+1*time.Minute, dur)
})
}
func TestParameters_client(t *testing.T) {
ctx := context.Background()
c := paramsAsStruct.client(ctx)
must.NotNil(t, c)
// security options
must.False(t, c.Insecure)
must.True(t, c.DisableSymlinks)
must.Eq(t, umask, c.Umask)
// artifact options
must.Eq(t, "https://example.com/file.txt", c.Src)
must.Eq(t, "local/out.txt", c.Dst)
// decompression limits
const fileCountLimit = 3
const fileSizeLimit = 98765
must.Eq(t, fileSizeLimit, c.Decompressors["zip"].(*getter.ZipDecompressor).FileSizeLimit)
must.Eq(t, fileCountLimit, c.Decompressors["zip"].(*getter.ZipDecompressor).FilesLimit)
must.Eq(t, fileSizeLimit, c.Decompressors["tar.gz"].(*getter.TarGzipDecompressor).FileSizeLimit)
must.Eq(t, fileCountLimit, c.Decompressors["tar.gz"].(*getter.TarGzipDecompressor).FilesLimit)
must.Eq(t, fileSizeLimit, c.Decompressors["xz"].(*getter.XzDecompressor).FileSizeLimit)
// xz does not support files count limit
}
func TestParameters_Equal_headers(t *testing.T) {
p1 := &parameters{
Headers: map[string][]string{
"East": []string{"New York", "Florida"},
"West": []string{"California"},
},
}
p2 := &parameters{
Headers: map[string][]string{
"East": []string{"New York", "Florida"},
"West": []string{"California"},
},
}
// equal
must.Equal(t, p1, p2)
// equal
must.Equal(t, p1, &parameters{
Headers: map[string][]string{
"West": {"California"},
"East": {"Florida", "New York"},
},
})
// not equal
p2.Headers["East"] = []string{"New York"}
must.NotEqual(t, p1, p2)
}