Example #1
0
func (*DebugHooksClientSuite) TestClientScript(c *C) {
	ctx := debug.NewHooksContext("foo/8")

	// Test the variable substitutions.
	result := debug.ClientScript(ctx, nil)
	// No variables left behind.
	c.Assert(result, Matches, "[^{}]*")
	// tmux new-session -d -s {unit_name}
	c.Assert(result, Matches, fmt.Sprintf("(.|\n)*tmux new-session -s %s(.|\n)*", regexp.QuoteMeta(ctx.Unit)))
	//) 9>{exit_flock}
	c.Assert(result, Matches, fmt.Sprintf("(.|\n)*\\) 9>%s(.|\n)*", regexp.QuoteMeta(ctx.ClientExitFileLock())))
	//) 8>{entry_flock}
	c.Assert(result, Matches, fmt.Sprintf("(.|\n)*\\) 8>%s(.|\n)*", regexp.QuoteMeta(ctx.ClientFileLock())))

	// nil is the same as empty slice is the same as "*".
	// Also, if "*" is present as well as a named hook,
	// it is equivalent to "*".
	c.Assert(debug.ClientScript(ctx, nil), Equals, debug.ClientScript(ctx, []string{}))
	c.Assert(debug.ClientScript(ctx, []string{"*"}), Equals, debug.ClientScript(ctx, nil))
	c.Assert(debug.ClientScript(ctx, []string{"*", "something"}), Equals, debug.ClientScript(ctx, []string{"*"}))

	// debug.ClientScript does not validate hook names, as it doesn't have
	// a full state API connection to determine valid relation hooks.
	expected := fmt.Sprintf(
		`(.|\n)*echo "aG9va3M6Ci0gc29tZXRoaW5nIHNvbWV0aGluZ2Vsc2UK" | base64 -d > %s(.|\n)*`,
		regexp.QuoteMeta(ctx.ClientFileLock()),
	)
	c.Assert(debug.ClientScript(ctx, []string{"something somethingelse"}), Matches, expected)
}
Example #2
0
// RunHook executes a hook in an environment which allows it to to call back
// into ctx to execute jujuc tools.
func (ctx *HookContext) RunHook(hookName, charmDir, toolsDir, socketPath string) error {
	var err error
	env := ctx.hookVars(charmDir, toolsDir, socketPath)
	debugctx := unitdebug.NewHooksContext(ctx.unit.Name())
	if session, _ := debugctx.FindSession(); session != nil && session.MatchHook(hookName) {
		logger.Infof("executing %s via debug-hooks", hookName)
		err = session.RunHook(hookName, charmDir, env)
	} else {
		err = runCharmHook(hookName, charmDir, env)
	}
	write := err == nil
	for id, rctx := range ctx.relations {
		if write {
			if e := rctx.WriteSettings(); e != nil {
				e = fmt.Errorf(
					"could not write settings from %q to relation %d: %v",
					hookName, id, e,
				)
				logger.Errorf("%v", e)
				if err == nil {
					err = e
				}
			}
		}
		rctx.ClearCache()
	}
	return err
}
Example #3
0
// TestCommonScript tests the behaviour of HooksContext.
func (*DebugHooksCommonSuite) TestHooksContext(c *C) {
	ctx := debug.NewHooksContext("foo/8")
	c.Assert(ctx.Unit, Equals, "foo/8")
	c.Assert(ctx.FlockDir, Equals, "/tmp")
	ctx.FlockDir = "/var/lib/juju"
	c.Assert(ctx.ClientFileLock(), Equals, "/var/lib/juju/juju-unit-foo-8-debug-hooks")
	c.Assert(ctx.ClientExitFileLock(), Equals, "/var/lib/juju/juju-unit-foo-8-debug-hooks-exit")
}
Example #4
0
func (s *DebugHooksServerSuite) SetUpTest(c *C) {
	s.fakebin = c.MkDir()
	s.tmpdir = c.MkDir()
	s.setenv("PATH", s.fakebin+":"+os.Getenv("PATH"))
	s.setenv("TMPDIR", s.tmpdir)
	s.setenv("TEST_RESULT", "")
	for _, name := range fakecommands {
		err := ioutil.WriteFile(filepath.Join(s.fakebin, name), []byte(echocommand), 0777)
		c.Assert(err, IsNil)
	}
	s.ctx = debug.NewHooksContext("foo/8")
	s.ctx.FlockDir = s.tmpdir
	s.setenv("JUJU_UNIT_NAME", s.ctx.Unit)
}
Example #5
0
// Run ensures c.Target is a unit, and resolves its address,
// and connects to it via SSH to execute the debug-hooks
// script.
func (c *DebugHooksCommand) Run(ctx *cmd.Context) error {
	conn, err := c.initConn()
	if err != nil {
		return err
	}
	defer conn.Close()
	unit, err := conn.State.Unit(c.Target)
	if err != nil {
		return err
	}
	err = c.validateHooks(unit)
	if err != nil {
		return err
	}
	debugctx := unitdebug.NewHooksContext(c.Target)
	script := base64.StdEncoding.EncodeToString([]byte(unitdebug.ClientScript(debugctx, c.hooks)))
	innercmd := fmt.Sprintf(`F=$(mktemp); echo %s | base64 -d > $F; . $F`, script)
	args := []string{"--", fmt.Sprintf("sudo /bin/bash -c '%s'", innercmd)}
	c.Args = args
	return c.SSHCommand.Run(ctx)
}