github.com/taylorchu/nomad@v0.5.3-rc1.0.20170407200202-db11e7dd7b55/client/getter/getter_test.go (about)

     1  package getter
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/hashicorp/nomad/client/driver/env"
    15  	"github.com/hashicorp/nomad/nomad/mock"
    16  	"github.com/hashicorp/nomad/nomad/structs"
    17  )
    18  
    19  func TestGetArtifact_FileAndChecksum(t *testing.T) {
    20  	// Create the test server hosting the file to download
    21  	ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir("./test-fixtures/"))))
    22  	defer ts.Close()
    23  
    24  	// Create a temp directory to download into
    25  	taskDir, err := ioutil.TempDir("", "nomad-test")
    26  	if err != nil {
    27  		t.Fatalf("failed to make temp directory: %v", err)
    28  	}
    29  	defer os.RemoveAll(taskDir)
    30  
    31  	// Create the artifact
    32  	file := "test.sh"
    33  	artifact := &structs.TaskArtifact{
    34  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, file),
    35  		GetterOptions: map[string]string{
    36  			"checksum": "md5:bce963762aa2dbfed13caf492a45fb72",
    37  		},
    38  	}
    39  
    40  	// Download the artifact
    41  	taskEnv := env.NewTaskEnvironment(mock.Node())
    42  	if err := GetArtifact(taskEnv, artifact, taskDir); err != nil {
    43  		t.Fatalf("GetArtifact failed: %v", err)
    44  	}
    45  
    46  	// Verify artifact exists
    47  	if _, err := os.Stat(filepath.Join(taskDir, file)); err != nil {
    48  		t.Fatalf("file not found: %s", err)
    49  	}
    50  }
    51  
    52  func TestGetArtifact_File_RelativeDest(t *testing.T) {
    53  	// Create the test server hosting the file to download
    54  	ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir("./test-fixtures/"))))
    55  	defer ts.Close()
    56  
    57  	// Create a temp directory to download into
    58  	taskDir, err := ioutil.TempDir("", "nomad-test")
    59  	if err != nil {
    60  		t.Fatalf("failed to make temp directory: %v", err)
    61  	}
    62  	defer os.RemoveAll(taskDir)
    63  
    64  	// Create the artifact
    65  	file := "test.sh"
    66  	relative := "foo/"
    67  	artifact := &structs.TaskArtifact{
    68  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, file),
    69  		GetterOptions: map[string]string{
    70  			"checksum": "md5:bce963762aa2dbfed13caf492a45fb72",
    71  		},
    72  		RelativeDest: relative,
    73  	}
    74  
    75  	// Download the artifact
    76  	taskEnv := env.NewTaskEnvironment(mock.Node())
    77  	if err := GetArtifact(taskEnv, artifact, taskDir); err != nil {
    78  		t.Fatalf("GetArtifact failed: %v", err)
    79  	}
    80  
    81  	// Verify artifact was downloaded to the correct path
    82  	if _, err := os.Stat(filepath.Join(taskDir, relative, file)); err != nil {
    83  		t.Fatalf("file not found: %s", err)
    84  	}
    85  }
    86  
    87  func TestGetGetterUrl_Interprolation(t *testing.T) {
    88  	// Create the artifact
    89  	artifact := &structs.TaskArtifact{
    90  		GetterSource: "${NOMAD_META_ARTIFACT}",
    91  	}
    92  
    93  	url := "foo.com"
    94  	taskEnv := env.NewTaskEnvironment(mock.Node()).SetTaskMeta(map[string]string{"artifact": url})
    95  	act, err := getGetterUrl(taskEnv, artifact)
    96  	if err != nil {
    97  		t.Fatalf("getGetterUrl() failed: %v", err)
    98  	}
    99  
   100  	if act != url {
   101  		t.Fatalf("getGetterUrl() returned %q; want %q", act, url)
   102  	}
   103  }
   104  
   105  func TestGetArtifact_InvalidChecksum(t *testing.T) {
   106  	// Create the test server hosting the file to download
   107  	ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir("./test-fixtures/"))))
   108  	defer ts.Close()
   109  
   110  	// Create a temp directory to download into
   111  	taskDir, err := ioutil.TempDir("", "nomad-test")
   112  	if err != nil {
   113  		t.Fatalf("failed to make temp directory: %v", err)
   114  	}
   115  	defer os.RemoveAll(taskDir)
   116  
   117  	// Create the artifact with an incorrect checksum
   118  	file := "test.sh"
   119  	artifact := &structs.TaskArtifact{
   120  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, file),
   121  		GetterOptions: map[string]string{
   122  			"checksum": "md5:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
   123  		},
   124  	}
   125  
   126  	// Download the artifact and expect an error
   127  	taskEnv := env.NewTaskEnvironment(mock.Node())
   128  	if err := GetArtifact(taskEnv, artifact, taskDir); err == nil {
   129  		t.Fatalf("GetArtifact should have failed")
   130  	}
   131  }
   132  
   133  func createContents(basedir string, fileContents map[string]string, t *testing.T) {
   134  	for relPath, content := range fileContents {
   135  		folder := basedir
   136  		if strings.Index(relPath, "/") != -1 {
   137  			// Create the folder.
   138  			folder = filepath.Join(basedir, filepath.Dir(relPath))
   139  			if err := os.Mkdir(folder, 0777); err != nil {
   140  				t.Fatalf("failed to make directory: %v", err)
   141  			}
   142  		}
   143  
   144  		// Create a file in the existing folder.
   145  		file := filepath.Join(folder, filepath.Base(relPath))
   146  		if err := ioutil.WriteFile(file, []byte(content), 0777); err != nil {
   147  			t.Fatalf("failed to write data to file %v: %v", file, err)
   148  		}
   149  	}
   150  }
   151  
   152  func checkContents(basedir string, fileContents map[string]string, t *testing.T) {
   153  	for relPath, content := range fileContents {
   154  		path := filepath.Join(basedir, relPath)
   155  		actual, err := ioutil.ReadFile(path)
   156  		if err != nil {
   157  			t.Fatalf("failed to read file %q: %v", path, err)
   158  		}
   159  
   160  		if !reflect.DeepEqual(actual, []byte(content)) {
   161  			t.Fatalf("%q: expected %q; got %q", path, content, string(actual))
   162  		}
   163  	}
   164  }
   165  
   166  func TestGetArtifact_Archive(t *testing.T) {
   167  	// Create the test server hosting the file to download
   168  	ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir("./test-fixtures/"))))
   169  	defer ts.Close()
   170  
   171  	// Create a temp directory to download into and create some of the same
   172  	// files that exist in the artifact to ensure they are overridden
   173  	taskDir, err := ioutil.TempDir("", "nomad-test")
   174  	if err != nil {
   175  		t.Fatalf("failed to make temp directory: %v", err)
   176  	}
   177  	defer os.RemoveAll(taskDir)
   178  
   179  	create := map[string]string{
   180  		"exist/my.config": "to be replaced",
   181  		"untouched":       "existing top-level",
   182  	}
   183  	createContents(taskDir, create, t)
   184  
   185  	file := "archive.tar.gz"
   186  	artifact := &structs.TaskArtifact{
   187  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, file),
   188  		GetterOptions: map[string]string{
   189  			"checksum": "sha1:20bab73c72c56490856f913cf594bad9a4d730f6",
   190  		},
   191  	}
   192  
   193  	taskEnv := env.NewTaskEnvironment(mock.Node())
   194  	if err := GetArtifact(taskEnv, artifact, taskDir); err != nil {
   195  		t.Fatalf("GetArtifact failed: %v", err)
   196  	}
   197  
   198  	// Verify the unarchiving overrode files properly.
   199  	expected := map[string]string{
   200  		"untouched":       "existing top-level",
   201  		"exist/my.config": "hello world\n",
   202  		"new/my.config":   "hello world\n",
   203  		"test.sh":         "sleep 1\n",
   204  	}
   205  	checkContents(taskDir, expected, t)
   206  }
   207  
   208  func TestGetGetterUrl_Queries(t *testing.T) {
   209  	taskEnv := env.NewTaskEnvironment(mock.Node())
   210  	cases := []struct {
   211  		name     string
   212  		artifact *structs.TaskArtifact
   213  		output   string
   214  	}{
   215  		{
   216  			name: "adds query parameters",
   217  			artifact: &structs.TaskArtifact{
   218  				GetterSource: "https://foo.com?test=1",
   219  				GetterOptions: map[string]string{
   220  					"foo": "bar",
   221  					"bam": "boom",
   222  				},
   223  			},
   224  			output: "https://foo.com?bam=boom&foo=bar&test=1",
   225  		},
   226  		{
   227  			name: "git without http",
   228  			artifact: &structs.TaskArtifact{
   229  				GetterSource: "github.com/hashicorp/nomad",
   230  				GetterOptions: map[string]string{
   231  					"ref": "abcd1234",
   232  				},
   233  			},
   234  			output: "github.com/hashicorp/nomad?ref=abcd1234",
   235  		},
   236  		{
   237  			name: "git using ssh",
   238  			artifact: &structs.TaskArtifact{
   239  				GetterSource: "git@github.com:hashicorp/nomad?sshkey=1",
   240  				GetterOptions: map[string]string{
   241  					"ref": "abcd1234",
   242  				},
   243  			},
   244  			output: "git@github.com:hashicorp/nomad?ref=abcd1234&sshkey=1",
   245  		},
   246  		{
   247  			name: "s3 scheme 1",
   248  			artifact: &structs.TaskArtifact{
   249  				GetterSource: "s3::https://s3.amazonaws.com/bucket/foo",
   250  				GetterOptions: map[string]string{
   251  					"aws_access_key_id": "abcd1234",
   252  				},
   253  			},
   254  			output: "s3::https://s3.amazonaws.com/bucket/foo?aws_access_key_id=abcd1234",
   255  		},
   256  		{
   257  			name: "s3 scheme 2",
   258  			artifact: &structs.TaskArtifact{
   259  				GetterSource: "s3::https://s3-eu-west-1.amazonaws.com/bucket/foo",
   260  				GetterOptions: map[string]string{
   261  					"aws_access_key_id": "abcd1234",
   262  				},
   263  			},
   264  			output: "s3::https://s3-eu-west-1.amazonaws.com/bucket/foo?aws_access_key_id=abcd1234",
   265  		},
   266  		{
   267  			name: "s3 scheme 3",
   268  			artifact: &structs.TaskArtifact{
   269  				GetterSource: "bucket.s3.amazonaws.com/foo",
   270  				GetterOptions: map[string]string{
   271  					"aws_access_key_id": "abcd1234",
   272  				},
   273  			},
   274  			output: "bucket.s3.amazonaws.com/foo?aws_access_key_id=abcd1234",
   275  		},
   276  		{
   277  			name: "s3 scheme 4",
   278  			artifact: &structs.TaskArtifact{
   279  				GetterSource: "bucket.s3-eu-west-1.amazonaws.com/foo/bar",
   280  				GetterOptions: map[string]string{
   281  					"aws_access_key_id": "abcd1234",
   282  				},
   283  			},
   284  			output: "bucket.s3-eu-west-1.amazonaws.com/foo/bar?aws_access_key_id=abcd1234",
   285  		},
   286  		{
   287  			name: "local file",
   288  			artifact: &structs.TaskArtifact{
   289  				GetterSource: "/foo/bar",
   290  			},
   291  			output: "/foo/bar",
   292  		},
   293  	}
   294  
   295  	for _, c := range cases {
   296  		t.Run(c.name, func(t *testing.T) {
   297  			act, err := getGetterUrl(taskEnv, c.artifact)
   298  			if err != nil {
   299  				t.Fatalf("want %q; got err %v", c.output, err)
   300  			} else if act != c.output {
   301  				t.Fatalf("want %q; got %q", c.output, act)
   302  			}
   303  		})
   304  	}
   305  }