Exemple #1
0
// Determines if either there is no currently built version of the agent,
// or if the currently built version is out of date.
// Returns whether a new version needs to be built, and an error if any
// of the checks within the function throw an error.
func (self *AgentBasedHostGateway) AgentNeedsBuild() (bool, error) {

	// compute and cache the current hash of the agent package
	agentHash, err := util.CurrentGitHash(self.AgentPackageDir)
	if err != nil {
		return false, fmt.Errorf("error getting git hash of agent package "+
			"at %v: %v", self.AgentPackageDir, err)
	}
	self.currentAgentHash = agentHash

	// if the local directory where the executables live does not exist, then we
	// certainly need to build the agent
	exists, err := util.FileExists(self.ExecutablesDir)
	if err != nil {
		return false, err
	}
	if !exists {
		return true, nil
	}

	// if the most recently built agent hash is different from the current
	// mci hash, then the agent needs to be rebuilt
	lastBuiltRevision, err := db.GetLastAgentBuild()
	if err != nil {
		return false, fmt.Errorf("error getting last agent build hash: %v", err)
	}

	return self.currentAgentHash != lastBuiltRevision, 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)

		})

	})

}