func TestDownloadAgentMD5Mismatch(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() md5response := &http.Response{} md5sum := "md5sum" tarballResponse := &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(&bytes.Buffer{}), } mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700) mockGetter := NewMockhttpGetter(mockCtrl) mockGetter.EXPECT().Get(config.AgentRemoteTarballMD5()).Return(md5response, nil) mockFS.EXPECT().ReadAll(md5response.Body).Return([]byte(md5sum), nil) mockGetter.EXPECT().Get(config.AgentRemoteTarball()).Return(tarballResponse, nil) tempfile, err := ioutil.TempFile("", "test") if err != nil { t.Fail() } defer tempfile.Close() mockFS.EXPECT().TempFile("", "ecs-agent.tar").Return(tempfile, nil) mockFS.EXPECT().TeeReader(tarballResponse.Body, gomock.Any()) mockFS.EXPECT().Copy(tempfile, gomock.Any()).Return(int64(0), nil) mockFS.EXPECT().Remove(tempfile.Name()) d := &Downloader{ getter: mockGetter, fs: mockFS, } d.DownloadAgent() }
func (c *Client) getContainerConfig() *godocker.Config { // default environment variables envVariables := map[string]string{ "ECS_LOGFILE": logDir + "/" + config.AgentLogFile, "ECS_DATADIR": dataDir, "ECS_AGENT_CONFIG_FILE_PATH": config.AgentJSONConfigFile(), "ECS_UPDATE_DOWNLOAD_DIR": config.CacheDirectory(), "ECS_UPDATES_ENABLED": "true", "ECS_AVAILABLE_LOGGING_DRIVERS": "[\"json-file\",\"syslog\"]", } // merge in user-supplied environment variables for envKey, envValue := range c.loadEnvVariables() { envVariables[envKey] = envValue } var env []string for envKey, envValue := range envVariables { env = append(env, envKey+"="+envValue) } exposedPorts := map[godocker.Port]struct{}{ agentIntrospectionPort + "/tcp": struct{}{}, } return &godocker.Config{ Env: env, ExposedPorts: exposedPorts, Image: config.AgentImageName, } }
func TestDownloadAgentTempFile(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() md5response := &http.Response{} md5sum := "md5sum" tarballResponse := &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(&bytes.Buffer{}), } mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700) mockGetter := NewMockhttpGetter(mockCtrl) mockGetter.EXPECT().Get(config.AgentRemoteTarballMD5()).Return(md5response, nil) mockFS.EXPECT().ReadAll(md5response.Body).Return([]byte(md5sum), nil) mockGetter.EXPECT().Get(config.AgentRemoteTarball()).Return(tarballResponse, nil) mockFS.EXPECT().TempFile("", "ecs-agent.tar").Return(nil, errors.New("test error")) d := &Downloader{ getter: mockGetter, fs: mockFS, } d.DownloadAgent() }
func (d *Downloader) getDesiredImageFile() (string, error) { file, err := d.fs.Open(config.DesiredImageLocatorFile()) if err != nil { return "", err } defer file.Close() reader := bufio.NewReader(file) desiredImageString, err := reader.ReadString('\n') if err != nil { return "", err } desiredImageFile := strings.TrimSpace(config.CacheDirectory() + "/" + d.fs.Base(desiredImageString)) return desiredImageFile, nil }
func (c *Client) getHostConfig() *godocker.HostConfig { binds := []string{ defaultDockerEndpoint + ":" + defaultDockerEndpoint, config.LogDirectory() + ":" + logDir, config.AgentDataDirectory() + ":" + dataDir, config.AgentConfigDirectory() + ":" + config.AgentConfigDirectory(), config.CacheDirectory() + ":" + config.CacheDirectory(), config.CgroupDirectory() + ":" + config.CgroupDirectory() + readOnly, config.ExecDriverDirectory() + ":" + execDriverDir + readOnly, } portBindings := map[godocker.Port][]godocker.PortBinding{ agentIntrospectionPort + "/tcp": []godocker.PortBinding{ godocker.PortBinding{ HostIP: "127.0.0.1", HostPort: agentIntrospectionPort, }, }, } return &godocker.HostConfig{ Binds: binds, PortBindings: portBindings, } }
func TestDownloadAgentMkdirFailure(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700).Return(errors.New("test error")) d := &Downloader{ fs: mockFS, } d.DownloadAgent() }
// DownloadAgent downloads a fresh copy of the Agent and performs an // integrity check on the downloaded image func (d *Downloader) DownloadAgent() error { err := d.fs.MkdirAll(config.CacheDirectory(), os.ModeDir|orwPerm) if err != nil { return err } publishedMd5Sum, err := d.getPublishedMd5Sum() if err != nil { return err } publishedTarballReader, err := d.getPublishedTarball() if err != nil { return err } defer publishedTarballReader.Close() md5hash := md5.New() tempFile, err := d.fs.TempFile("", "ecs-agent.tar") if err != nil { return err } log.Debugf("Temp file %s", tempFile.Name()) defer func() { if err != nil { log.Debugf("Removing temp file %s", tempFile.Name()) d.fs.Remove(tempFile.Name()) } }() defer tempFile.Close() teeReader := d.fs.TeeReader(publishedTarballReader, md5hash) _, err = d.fs.Copy(tempFile, teeReader) if err != nil { return err } calculatedMd5Sum := md5hash.Sum(nil) calculatedMd5SumString := fmt.Sprintf("%x", calculatedMd5Sum) log.Debugf("Expected %s", publishedMd5Sum) log.Debugf("Calculated %s", calculatedMd5SumString) if publishedMd5Sum != calculatedMd5SumString { err = fmt.Errorf("mismatched md5sum while downloading %s", config.AgentRemoteTarball()) return err } log.Debugf("Attempting to rename %s to %s", tempFile.Name(), config.AgentTarball()) return d.fs.Rename(tempFile.Name(), config.AgentTarball()) }
func TestDownloadAgentDownloadMD5Failure(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() mockFS := NewMockfileSystem(mockCtrl) mockGetter := NewMockhttpGetter(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700) mockGetter.EXPECT().Get(config.AgentRemoteTarballMD5()).Return(nil, errors.New("test error")) d := &Downloader{ getter: mockGetter, fs: mockFS, } d.DownloadAgent() }
func TestLoadDesiredAgent(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() desiredImage := "my-new-agent-image" mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().Open(config.DesiredImageLocatorFile()).Return(ioutil.NopCloser(bytes.NewBufferString(desiredImage+"\n")), nil) mockFS.EXPECT().Base(gomock.Any()).Return(desiredImage + "\n") mockFS.EXPECT().Open(config.CacheDirectory() + "/" + desiredImage) d := &Downloader{ fs: mockFS, } d.LoadDesiredAgent() }
func (c *Client) getContainerConfig() *godocker.Config { env := append(c.loadEnvVariables(), "ECS_LOGFILE="+logDir+"/"+config.AgentLogFile, "ECS_DATADIR="+dataDir, "ECS_AGENT_CONFIG_FILE_PATH="+config.AgentJSONConfigFile(), "ECS_UPDATE_DOWNLOAD_DIR="+config.CacheDirectory(), "ECS_UPDATES_ENABLED=true", ) exposedPorts := map[godocker.Port]struct{}{ agentIntrospectionPort + "/tcp": struct{}{}, } return &godocker.Config{ Env: env, ExposedPorts: exposedPorts, Image: config.AgentImageName, } }
func TestDownloadAgentDownloadTarballFailure(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() md5response := &http.Response{} md5sum := "md5sum" mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700) mockGetter := NewMockhttpGetter(mockCtrl) mockGetter.EXPECT().Get(config.AgentRemoteTarballMD5()).Return(md5response, nil) mockFS.EXPECT().ReadAll(md5response.Body).Return([]byte(md5sum), nil) mockGetter.EXPECT().Get(config.AgentRemoteTarball()).Return(nil, errors.New("test error")) d := &Downloader{ getter: mockGetter, fs: mockFS, } d.DownloadAgent() }
func TestDownloadAgentReadPublishedMd5Failure(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() md5response := &http.Response{ Body: ioutil.NopCloser(&bytes.Buffer{}), } mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700) mockGetter := NewMockhttpGetter(mockCtrl) mockGetter.EXPECT().Get(config.AgentRemoteTarballMD5()).Return(md5response, nil) mockFS.EXPECT().ReadAll(md5response.Body).Return(nil, errors.New("test error")) d := &Downloader{ getter: mockGetter, fs: mockFS, } d.DownloadAgent() }
func TestDownloadAgentSuccess(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() tarballContents := "tarball contents" tarballResponse := &http.Response{ StatusCode: 200, Body: ioutil.NopCloser(bytes.NewBufferString(tarballContents)), } expectedMd5Sum := fmt.Sprintf("%x\n", md5.Sum([]byte(tarballContents))) md5response := &http.Response{} mockFS := NewMockfileSystem(mockCtrl) mockFS.EXPECT().MkdirAll(config.CacheDirectory(), os.ModeDir|0700) mockGetter := NewMockhttpGetter(mockCtrl) mockGetter.EXPECT().Get(config.AgentRemoteTarballMD5()).Return(md5response, nil) mockFS.EXPECT().ReadAll(md5response.Body).Return([]byte(expectedMd5Sum), nil) mockGetter.EXPECT().Get(config.AgentRemoteTarball()).Return(tarballResponse, nil) tempfile, err := ioutil.TempFile("", "test") if err != nil { t.Fail() } defer tempfile.Close() mockFS.EXPECT().TempFile("", "ecs-agent.tar").Return(tempfile, nil) mockFS.EXPECT().TeeReader(tarballResponse.Body, gomock.Any()).Do(func(reader io.Reader, writer io.Writer) { _, err = io.Copy(writer, reader) if err != nil { t.Fail() } }) mockFS.EXPECT().Copy(tempfile, gomock.Any()).Return(int64(0), nil) mockFS.EXPECT().Rename(tempfile.Name(), config.AgentTarball()) d := &Downloader{ getter: mockGetter, fs: mockFS, } d.DownloadAgent() }
func validateCommonCreateContainerOptions(opts godocker.CreateContainerOptions, t *testing.T) { if opts.Name != "ecs-agent" { t.Errorf("Expected container Name to be %s but was %s", "ecs-agent", opts.Name) } cfg := opts.Config if len(cfg.Env) < 3 { t.Errorf("Expected at least 3 elements to be in Env, but was %d", len(cfg.Env)) } envVariables := make(map[string]struct{}) for _, envVar := range cfg.Env { envVariables[envVar] = struct{}{} } expectKey("ECS_DATADIR=/data", envVariables, t) expectKey("ECS_LOGFILE=/log/"+config.AgentLogFile, envVariables, t) expectKey("ECS_AGENT_CONFIG_FILE_PATH="+config.AgentJSONConfigFile(), envVariables, t) expectKey("ECS_UPDATE_DOWNLOAD_DIR="+config.CacheDirectory(), envVariables, t) expectKey("ECS_UPDATES_ENABLED=true", envVariables, t) expectKey(`ECS_AVAILABLE_LOGGING_DRIVERS=["json-file","syslog","awslogs"]`, envVariables, t) if len(cfg.ExposedPorts) != 1 { t.Errorf("Expected exactly 1 element to be in ExposedPorts, but was %d", len(cfg.ExposedPorts)) } expectPort("51678/tcp", cfg.ExposedPorts, t) if cfg.Image != config.AgentImageName { t.Errorf("Expected image to be %s", config.AgentImageName) } hostCfg := opts.HostConfig if len(hostCfg.Binds) != 5 { t.Errorf("Expected exactly 5 elements to be in Binds, but was %d", len(hostCfg.Binds)) } binds := make(map[string]struct{}) for _, binding := range hostCfg.Binds { binds[binding] = struct{}{} } defaultDockerSocket, _ := config.DockerUnixSocket() expectKey(defaultDockerSocket+":"+defaultDockerSocket, binds, t) expectKey(config.LogDirectory()+":/log", binds, t) expectKey(config.AgentDataDirectory()+":/data", binds, t) expectKey(config.AgentConfigDirectory()+":"+config.AgentConfigDirectory(), binds, t) expectKey(config.CacheDirectory()+":"+config.CacheDirectory(), binds, t) if len(hostCfg.PortBindings) != 1 { t.Errorf("Expected exactly 1 element to be in PortBindings, but was %d", len(hostCfg.PortBindings)) } if portBindings, ok := hostCfg.PortBindings["51678/tcp"]; ok { if len(portBindings) != 1 { t.Errorf("Expected exactly 1 element to be in portBindings, but was %d", len(portBindings)) } else { portBinding := portBindings[0] if portBinding.HostIP != "127.0.0.1" { t.Errorf("Expected HostIP to be 127.0.0.1, but was %s", portBinding.HostIP) } if portBinding.HostPort != "51678" { t.Errorf("Expected HostPort to be 51678, but was %s", portBinding.HostPort) } } } else { t.Error("Expected 51678/tcp to be defined") } }