// Compile the agent package into the appropriate binaries. // Returns an error if the compilation fails, or if storing the last built // hash in the db fails func (self *AgentBasedHostGateway) buildAgent() error { // sanity check that we have an available agent compiler if self.Compiler == nil { panic("no AgentCompiler was initialized to cross-compile the agent" + " package") } // compile the agent to the appropriate destination err := self.Compiler.Compile(self.AgentPackageDir, self.ExecutablesDir) if err != nil { return fmt.Errorf("error building agent from %v to %v: %v", self.AgentPackageDir, self.ExecutablesDir, err) } // record the build as successful err = db.StoreLastAgentBuild(self.currentAgentHash) if err != nil { return fmt.Errorf("error saving last built agent hash: %v", err) } return nil }
func TestAgentBasedHostGateway(t *testing.T) { var hostGateway *AgentBasedHostGateway SkipConvey("When checking if the agent needs to be built", t, func() { hostGateway = &AgentBasedHostGateway{} Convey("a non-existent executables directory should cause the agent"+ " to need to be built", func() { hostGateway.ExecutablesDir = "/foo/bar/baz/foo/bar" needsBuild, err := hostGateway.AgentNeedsBuild() So(err, ShouldBeNil) So(needsBuild, ShouldBeTrue) }) Convey("an out-of-date last-built version of the agent should cause"+ " the agent to need to be built", func() { hostGateway.ExecutablesDir = "/" // just needs to exist // store the "last built hash" as something different than the // current one So(db.StoreLastAgentBuild("fedcba"), ShouldBeNil) needsBuild, err := hostGateway.AgentNeedsBuild() So(err, ShouldBeNil) So(needsBuild, ShouldBeTrue) }) Convey("an up-to-date last-built version of the agent should cause"+ " the agent to not need to be built", func() { hostGateway.ExecutablesDir = "/" // just needs to exist // compute and cache the current hash of the agent package agentHash, err := util.CurrentGitHash(hostGateway.AgentPackageDir) So(err, ShouldBeNil) // store the "last built hash" as the same as the current one So(db.StoreLastAgentBuild(agentHash), ShouldBeNil) needsBuild, err := hostGateway.AgentNeedsBuild() So(err, ShouldBeNil) So(needsBuild, ShouldBeFalse) }) }) SkipConvey("When building the agent", t, func() { hostGateway = &AgentBasedHostGateway{} So(db.StoreLastAgentBuild("abcdef"), ShouldBeNil) Convey("a nil AgentCompiler should cause a panic", func() { So(func() { hostGateway.buildAgent() }, ShouldPanic) }) Convey("a failed compilation should error and cause the build to not"+ " be recorded as successful", func() { // attempt to compile hostGateway.currentAgentHash = "fedcba" hostGateway.Compiler = &FailingAgentCompiler{} So(hostGateway.buildAgent(), ShouldNotBeNil) // make sure the last built hash was not updated lastBuiltHash, err := db.GetLastAgentBuild() So(err, ShouldBeNil) So(lastBuiltHash, ShouldEqual, "abcdef") }) Convey("a successful compilation should cause the build to be"+ " recorded as successful", func() { // attempt to compile hostGateway.currentAgentHash = "fedcba" hostGateway.Compiler = &SucceedingAgentCompiler{} So(hostGateway.buildAgent(), ShouldBeNil) // make sure the last built hash was updated lastBuiltHash, err := db.GetLastAgentBuild() So(err, ShouldBeNil) So(lastBuiltHash, ShouldEqual, "fedcba") }) }) Convey("When prepping the remote machine", t, func() { Convey("the remote shell should be created, and the config directory"+ " and agent binaries should be copied over to it", func() { hostGateway = &AgentBasedHostGateway{ Compiler: &SucceedingAgentCompiler{}, } // create a mock config directory, mock executables // directory, and mock remote shell evgHome := evergreen.FindEvergreenHome() tmpBase := filepath.Join(evgHome, "taskrunner/testdata/tmp") mockConfigDir := filepath.Join(tmpBase, "mock_config_dir") hostGatewayTestConf.ConfigDir = mockConfigDir mockExecutablesDir := filepath.Join(tmpBase, "mock_executables_dir") hostGateway.ExecutablesDir = mockExecutablesDir mockExecutable := filepath.Join(mockExecutablesDir, "main") mockRemoteShell := filepath.Join(tmpBase, "mock_remote_shell") evergreen.RemoteShell = mockRemoteShell // prevent permissions issues syscall.Umask(0000) // remove the directories, if they exist (start clean) exists, err := util.FileExists(tmpBase) So(err, ShouldBeNil) if exists { So(os.RemoveAll(tmpBase), ShouldBeNil) } So(os.MkdirAll(tmpBase, 0777), ShouldBeNil) // create the config and executables directories, as well as a // mock executable, to copy over So(os.Mkdir(mockConfigDir, 0777), ShouldBeNil) So(os.Mkdir(mockExecutablesDir, 0777), ShouldBeNil) So(ioutil.WriteFile(mockExecutable, []byte("run me"), 0777), ShouldBeNil) // mock up a host for localhost localhost := host.Host{ Host: command.TestRemote, User: command.TestRemoteUser, } // prep the "remote" host _, err = hostGateway.prepRemoteHost(hostGatewayTestConf, localhost, []string{"-i", command.TestRemoteKey}, "") So(err, ShouldBeNil) // make sure the correct files were created and copied over exists, err = util.FileExists(filepath.Join(mockRemoteShell, "mock_config_dir")) So(err, ShouldBeNil) So(exists, ShouldBeTrue) exists, err = util.FileExists(filepath.Join(mockRemoteShell, "main")) So(err, ShouldBeNil) So(exists, ShouldBeTrue) }) }) }