func (w *collect) do() error { logger.Tracef("recording metrics") config := w.agent.CurrentConfig() tag := config.Tag() unitTag, ok := tag.(names.UnitTag) if !ok { return errors.Errorf("expected a unit tag, got %v", tag) } paths := uniter.NewWorkerPaths(config.DataDir(), unitTag, "metrics-collect") recorder, err := newRecorder(unitTag, paths, w.unitCharmLookup, w.metricFactory) if errors.Cause(err) == errMetricsNotDefined { logger.Tracef("%v", err) return nil } else if err != nil { return errors.Annotate(err, "failed to instantiate metric recorder") } ctx := newHookContext(unitTag.String(), recorder) err = ctx.addJujuUnitsMetric() if err != nil { return errors.Annotatef(err, "error adding 'juju-units' metric") } r := runner.NewRunner(ctx, paths) err = r.RunHook(string(hooks.CollectMetrics)) if err != nil { return errors.Annotatef(err, "error running 'collect-metrics' hook") } return nil }
func (s *RunHookSuite) TestRunHook(c *gc.C) { uuid, err := utils.NewUUID() c.Assert(err, jc.ErrorIsNil) for i, t := range runHookTests { c.Logf("\ntest %d: %s; perm %v", i, t.summary, t.spec.perm) ctx := s.getHookContext(c, uuid.String(), t.relid, t.remote, noProxies) paths := NewRealPaths(c) rnr := runner.NewRunner(ctx, paths) var hookExists bool if t.spec.perm != 0 { spec := t.spec spec.dir = "hooks" spec.name = hookName c.Logf("makeCharm %#v", spec) makeCharm(c, spec, paths.charm) hookExists = true } t0 := time.Now() err := rnr.RunHook("something-happened") if t.err == "" && hookExists { c.Assert(err, jc.ErrorIsNil) } else if !hookExists { c.Assert(runner.IsMissingHookError(err), jc.IsTrue) } else { c.Assert(err, gc.ErrorMatches, t.err) } if t.spec.background != "" && time.Now().Sub(t0) > 5*time.Second { c.Errorf("background process holding up hook execution") } } }
func (s *RunCommandSuite) TestRunCommandsEnvStdOutAndErrAndRC(c *gc.C) { // TODO(bogdanteleaga): powershell throws another exit status code when // outputting to stderr using Write-Error. Either find another way to // output to stderr or change the checks if runtime.GOOS == "windows" { c.Skip("bug 1403084: Have to figure out a good way to output to stderr from powershell") } ctx, err := s.contextFactory.HookContext(hook.Info{Kind: hooks.ConfigChanged}) c.Assert(err, jc.ErrorIsNil) paths := runnertesting.NewRealPaths(c) runner := runner.NewRunner(ctx, paths) commands := ` echo $JUJU_CHARM_DIR echo this is standard err >&2 exit 42 ` result, err := runner.RunCommands(commands) c.Assert(err, jc.ErrorIsNil) c.Assert(result.Code, gc.Equals, 42) c.Assert(strings.TrimRight(string(result.Stdout), "\r\n"), gc.Equals, paths.GetCharmDir()) c.Assert(strings.TrimRight(string(result.Stderr), "\r\n"), gc.Equals, "this is standard err") c.Assert(ctx.GetProcess(), gc.NotNil) }
func (s *RunHookSuite) TestRunHook(c *gc.C) { for i, t := range runHookTests { c.Logf("\ntest %d: %s; perm %v", i, t.summary, t.spec.perm) ctx, err := s.contextFactory.HookContext(hook.Info{Kind: hooks.ConfigChanged}) c.Assert(err, jc.ErrorIsNil) paths := runnertesting.NewRealPaths(c) rnr := runner.NewRunner(ctx, paths) var hookExists bool if t.spec.perm != 0 { spec := t.spec spec.dir = "hooks" spec.name = hookName c.Logf("makeCharm %#v", spec) makeCharm(c, spec, paths.GetCharmDir()) hookExists = true } t0 := time.Now() err = rnr.RunHook("something-happened") if t.err == "" && hookExists { c.Assert(err, jc.ErrorIsNil) } else if !hookExists { c.Assert(context.IsMissingHookError(err), jc.IsTrue) } else { c.Assert(err, gc.ErrorMatches, t.err) } if t.spec.background != "" && time.Now().Sub(t0) > 5*time.Second { c.Errorf("background process holding up hook execution") } } }
func (s *RunMockContextSuite) TestRunActionParamsFailure(c *gc.C) { expectErr := errors.New("stork") ctx := &MockContext{ actionData: &context.ActionData{}, actionParamsErr: expectErr, } actualErr := runner.NewRunner(ctx, s.paths).RunAction("juju-run") c.Assert(errors.Cause(actualErr), gc.Equals, expectErr) }
func (s *RunMockContextSuite) TestRunCommandsFlushFailure(c *gc.C) { expectErr := errors.New("pew pew pew") ctx := &MockContext{ flushResult: expectErr, } _, actualErr := runner.NewRunner(ctx, s.paths).RunCommands(echoPidScript + "; exit 123") c.Assert(actualErr, gc.Equals, expectErr) c.Assert(ctx.flushBadge, gc.Equals, "run commands") c.Assert(ctx.flushFailure, gc.IsNil) // exit code in _ result, as tested elsewhere s.assertRecordedPid(c, ctx.expectPid) }
func (s *RunMockContextSuite) TestRunCommandsFlushSuccess(c *gc.C) { expectErr := errors.New("pew pew pew") ctx := &MockContext{ flushResult: expectErr, } _, actualErr := runner.NewRunner(ctx, s.paths).RunCommands(echoPidScript) c.Assert(actualErr, gc.Equals, expectErr) c.Assert(ctx.flushBadge, gc.Equals, "run commands") c.Assert(ctx.flushFailure, gc.IsNil) s.assertRecordedPid(c, ctx.expectPid) }
func (s *RunMockContextSuite) TestRunHookFlushSuccess(c *gc.C) { expectErr := errors.New("pew pew pew") ctx := &MockContext{ flushResult: expectErr, } makeCharm(c, hookSpec{ dir: "hooks", name: hookName, perm: 0700, }, s.paths.GetCharmDir()) actualErr := runner.NewRunner(ctx, s.paths).RunHook("something-happened") c.Assert(actualErr, gc.Equals, expectErr) c.Assert(ctx.flushBadge, gc.Equals, "something-happened") c.Assert(ctx.flushFailure, gc.IsNil) s.assertRecordedPid(c, ctx.expectPid) }
func (s *RunMockContextSuite) TestRunHookFlushFailure(c *gc.C) { expectErr := errors.New("pew pew pew") ctx := &MockContext{ flushResult: expectErr, } makeCharm(c, hookSpec{ dir: "hooks", name: hookName, perm: 0700, code: 123, }, s.paths.charm) actualErr := runner.NewRunner(ctx, s.paths).RunHook("something-happened") c.Assert(actualErr, gc.Equals, expectErr) c.Assert(ctx.flushBadge, gc.Equals, "something-happened") c.Assert(ctx.flushFailure, gc.ErrorMatches, "exit status 123") s.assertRecordedPid(c, ctx.expectPid) }
func (s *RunMockContextSuite) TestRunActionSuccessful(c *gc.C) { ctx := &MockContext{ actionData: &context.ActionData{}, actionParams: map[string]interface{}{ "command": "echo 1", "timeout": 0, }, actionResults: map[string]interface{}{}, } err := runner.NewRunner(ctx, s.paths).RunAction("juju-run") c.Assert(err, jc.ErrorIsNil) c.Assert(ctx.flushBadge, gc.Equals, "juju-run") c.Assert(ctx.flushFailure, gc.IsNil) c.Assert(ctx.actionResults["Code"], gc.Equals, "0") c.Assert(strings.TrimRight(ctx.actionResults["Stdout"].(string), "\r\n"), gc.Equals, "1") c.Assert(ctx.actionResults["Stderr"], gc.Equals, "") }
func (w *hookRunner) RunHook(code, info string, interrupt <-chan struct{}) (runErr error) { unitTag := w.tag paths := uniter.NewPaths(w.config.DataDir(), unitTag) ctx := NewLimitedContext(unitTag.String()) ctx.SetEnvVars(map[string]string{ "JUJU_METER_STATUS": code, "JUJU_METER_INFO": info, }) r := runner.NewRunner(ctx, paths) releaser, err := w.acquireExecutionLock(interrupt) if err != nil { return errors.Annotate(err, "failed to acquire machine lock") } // Defer the logging first so it is executed after the Release. LIFO. defer logger.Debugf("release lock %q for meter status hook execution", w.machineLockName) defer releaser.Release() return r.RunHook(string(hooks.MeterStatusChanged)) }
func (h *hookRunner) do(recorder spool.MetricRecorder) error { h.m.Lock() defer h.m.Unlock() logger.Tracef("recording metrics") ctx := newHookContext(h.unitTag, recorder) err := ctx.addJujuUnitsMetric() if err != nil { return errors.Annotatef(err, "error adding 'juju-units' metric") } r := runner.NewRunner(ctx, h.paths) err = r.RunHook(string(hooks.CollectMetrics)) if err != nil { return errors.Annotatef(err, "error running 'collect-metrics' hook") } return nil }
func (s *RunMockContextSuite) TestRunActionCancelled(c *gc.C) { timeout := 1 * time.Nanosecond ctx := &MockContext{ actionData: &context.ActionData{}, actionParams: map[string]interface{}{ "command": "sleep 10", "timeout": float64(timeout.Nanoseconds()), }, actionResults: map[string]interface{}{}, } err := runner.NewRunner(ctx, s.paths).RunAction("juju-run") c.Assert(err, jc.ErrorIsNil) c.Assert(ctx.flushBadge, gc.Equals, "juju-run") c.Assert(ctx.flushFailure, gc.Equals, exec.ErrCancelled) c.Assert(ctx.actionResults["Code"], gc.Equals, nil) c.Assert(ctx.actionResults["Stdout"], gc.Equals, nil) c.Assert(ctx.actionResults["Stderr"], gc.Equals, nil) }
func (w *hookRunner) RunHook(code, info string, interrupt <-chan struct{}) (runErr error) { unitTag := w.tag paths := uniter.NewPaths(w.config.DataDir(), unitTag) ctx := NewLimitedContext(unitTag.String()) ctx.SetEnvVars(map[string]string{ "JUJU_METER_STATUS": code, "JUJU_METER_INFO": info, }) r := runner.NewRunner(ctx, paths) unlock, err := w.acquireExecutionLock(interrupt) if err != nil { return errors.Annotate(err, "failed to acquire machine lock") } defer func() { unlockErr := unlock() if unlockErr != nil { logger.Criticalf("hook run resulted in error %v; unlock failure error: %v", runErr, unlockErr) } }() return r.RunHook(string(hooks.MeterStatusChanged)) }