// upstartService returns an upstart.Service corresponding to the specified // unit. func (ctx *SimpleContext) upstartService(unitName string) *upstart.Service { tag := names.UnitTag(unitName) svcName := "jujud-" + tag svc := upstart.NewService(svcName) svc.InitDir = ctx.initDir return svc }
// NewDeployerAPI creates a new client-side DeployerAPI facade. func NewDeployerAPI( st *state.State, resources *common.Resources, authorizer common.Authorizer, ) (*DeployerAPI, error) { if !authorizer.AuthMachineAgent() { return nil, common.ErrPerm } getAuthFunc := func() (common.AuthFunc, error) { // Get all units of the machine and cache them. thisMachineTag := authorizer.GetAuthTag() units, err := getAllUnits(st, thisMachineTag) if err != nil { return nil, err } // Then we just check if the unit is already known. return func(tag string) bool { for _, unit := range units { if names.UnitTag(unit) == tag { return true } } return false }, nil } return &DeployerAPI{ Remover: common.NewRemover(st, getAuthFunc), PasswordChanger: common.NewPasswordChanger(st, getAuthFunc), LifeGetter: common.NewLifeGetter(st, getAuthFunc), st: st, resources: resources, authorizer: authorizer, }, nil }
// changed ensures that the named unit is deployed, recalled, or removed, as // indicated by its state. func (d *Deployer) changed(unitName string) error { unitTag := names.UnitTag(unitName) // Determine unit life state, and whether we're responsible for it. logger.Infof("checking unit %q", unitName) var life params.Life unit, err := d.st.Unit(unitTag) if isNotFoundOrUnauthorized(err) { life = params.Dead } else if err != nil { return err } else { life = unit.Life() } // Deployed units must be removed if they're Dead, or if the deployer // is no longer responsible for them. if d.deployed.Contains(unitName) { if life == params.Dead { if err := d.recall(unitName); err != nil { return err } } } // The only units that should be deployed are those that (1) we are responsible // for and (2) are Alive -- if we're responsible for a Dying unit that is not // yet deployed, we should remove it immediately rather than undergo the hassle // of deploying a unit agent purely so it can set itself to Dead. if !d.deployed.Contains(unitName) { if life == params.Alive { return d.deploy(unit) } else if unit != nil { return d.remove(unit) } } return nil }
func (ctx *SimpleContext) RecallUnit(unitName string) error { svc := ctx.findUpstartJob(unitName) if svc == nil || !svc.Installed() { return fmt.Errorf("unit %q is not deployed", unitName) } if err := svc.Remove(); err != nil { return err } tag := names.UnitTag(unitName) agentDir := tools.Dir(ctx.dataDir, tag) if err := os.RemoveAll(agentDir); err != nil { return err } if err := os.Remove(ctx.syslogConfigPath); err != nil && !os.IsNotExist(err) { logger.Warningf("installer: cannot remove %q: %v", ctx.syslogConfigPath, err) } // Defer this so a failure here does not impede the cleanup (as in tests). defer func() { if err := syslog.Restart(); err != nil { logger.Warningf("installer: cannot restart syslog daemon: %v", err) } }() toolsDir := tools.ToolsDir(ctx.dataDir, tag) return os.Remove(toolsDir) }
func (fix *SimpleToolsFixture) checkUnitInstalled(c *C, name, password string) { tag := names.UnitTag(name) uconfPath, _, toolsDir, syslogConfPath := fix.paths(tag) uconfData, err := ioutil.ReadFile(uconfPath) c.Assert(err, IsNil) uconf := string(uconfData) var execLine string for _, line := range strings.Split(uconf, "\n") { if strings.HasPrefix(line, "exec ") { execLine = line break } } if execLine == "" { c.Fatalf("no command found in %s:\n%s", uconfPath, uconf) } logPath := filepath.Join(fix.logDir, tag+".log") jujudPath := filepath.Join(toolsDir, "jujud") for _, pat := range []string{ "^exec " + jujudPath + " unit ", " --unit-name " + name + " ", " >> " + logPath + " 2>&1$", } { match, err := regexp.MatchString(pat, execLine) c.Assert(err, IsNil) if !match { c.Fatalf("failed to match:\n%s\nin:\n%s", pat, execLine) } } conf, err := agent.ReadConf(fix.dataDir, tag) c.Assert(err, IsNil) c.Assert(conf, DeepEquals, &agent.Conf{ DataDir: fix.dataDir, OldPassword: password, StateInfo: &state.Info{ Addrs: []string{"s1:123", "s2:123"}, CACert: []byte("test-cert"), Tag: tag, }, APIInfo: &api.Info{ Addrs: []string{"a1:123", "a2:123"}, CACert: []byte("test-cert"), Tag: tag, }, }) jujudData, err := ioutil.ReadFile(jujudPath) c.Assert(err, IsNil) c.Assert(string(jujudData), Equals, fakeJujud) syslogConfData, err := ioutil.ReadFile(syslogConfPath) c.Assert(err, IsNil) parts := strings.SplitN(name, "/", 2) unitTag := fmt.Sprintf("unit-%s-%s", parts[0], parts[1]) expectedSyslogConfReplaced := fmt.Sprintf(expectedSyslogConf, unitTag, unitTag, unitTag, unitTag) c.Assert(string(syslogConfData), Equals, expectedSyslogConfReplaced) }
// DeployerTag returns the tag of the agent responsible for deploying // the unit. If no such entity can be determined, false is returned. func (u *Unit) DeployerTag() (string, bool) { if u.doc.Principal != "" { return names.UnitTag(u.doc.Principal), true } else if u.doc.MachineId != "" { return names.MachineTag(u.doc.MachineId), true } return "", false }
func (s *unitSuite) TestInvalidUnitTagFormats(c *gc.C) { for i, test := range unitNameTests { if !test.valid { c.Logf("test %d: %q", i, test.pattern) expect := fmt.Sprintf("%q is not a valid unit name", test.pattern) testUnitTag := func() { names.UnitTag(test.pattern) } c.Assert(testUnitTag, gc.PanicMatches, expect) } } }
func (fix *SimpleToolsFixture) checkUnitRemoved(c *C, name string) { tag := names.UnitTag(name) confPath, agentDir, toolsDir, syslogConfPath := fix.paths(tag) for _, path := range []string{confPath, agentDir, toolsDir, syslogConfPath} { _, err := ioutil.ReadFile(path) if err == nil { c.Log("Warning: %q not removed as expected", path) } else { c.Assert(err, checkers.Satisfies, os.IsNotExist) } } }
func (a *UnitAgent) Tag() string { return names.UnitTag(a.UnitName) }
func (ctx *SimpleContext) DeployUnit(unitName, initialPassword string) (err error) { // Check sanity. svc := ctx.upstartService(unitName) if svc.Installed() { return fmt.Errorf("unit %q is already deployed", unitName) } // Link the current tools for use by the new agent. tag := names.UnitTag(unitName) _, err = tools.ChangeAgentTools(ctx.dataDir, tag, version.Current) toolsDir := tools.ToolsDir(ctx.dataDir, tag) defer removeOnErr(&err, toolsDir) // Retrieve the state addresses. stateAddrs, err := ctx.addresser.StateAddresses() if err != nil { return err } apiAddrs, err := ctx.addresser.APIAddresses() if err != nil { return err } stateInfo := state.Info{ Addrs: stateAddrs, Tag: tag, CACert: ctx.caCert, } logger.Debugf("state addresses: %q", stateAddrs) apiInfo := api.Info{ Addrs: apiAddrs, Tag: tag, CACert: ctx.caCert, } logger.Debugf("API addresses: %q", apiAddrs) // Prepare the agent's configuration data. conf := &agent.Conf{ DataDir: ctx.dataDir, OldPassword: initialPassword, StateInfo: &stateInfo, APIInfo: &apiInfo, } if err := conf.Write(); err != nil { return err } defer removeOnErr(&err, conf.Dir()) // Install an upstart job that runs the unit agent. logPath := path.Join(ctx.logDir, tag+".log") syslogConfigRenderer := syslog.NewForwardConfig(tag, stateAddrs) syslogConfigRenderer.ConfigDir = ctx.syslogConfigDir syslogConfigRenderer.ConfigFileName = fmt.Sprintf("26-juju-%s.conf", tag) if err := syslogConfigRenderer.Write(); err != nil { return err } ctx.syslogConfigPath = syslogConfigRenderer.ConfigFilePath() if err := syslog.Restart(); err != nil { logger.Warningf("installer: cannot restart syslog daemon: %v", err) } defer removeOnErr(&err, ctx.syslogConfigPath) cmd := strings.Join([]string{ path.Join(toolsDir, "jujud"), "unit", "--data-dir", conf.DataDir, "--unit-name", unitName, "--debug", // TODO: propagate debug state sensibly }, " ") uconf := &upstart.Conf{ Service: *svc, Desc: "juju unit agent for " + unitName, Cmd: cmd, Out: logPath, // Propagate the provider type enviroment variable. Env: map[string]string{ osenv.JujuProviderType: os.Getenv(osenv.JujuProviderType), }, } return uconf.Install() }
func (s *unitSuite) TestUnitTag(c *gc.C) { c.Assert(names.UnitTag("wordpress/2"), gc.Equals, "unit-wordpress-2") }
func (c *HooksContext) ClientFileLock() string { basename := fmt.Sprintf("juju-%s-debug-hooks", names.UnitTag(c.Unit)) return filepath.Join(c.FlockDir, basename) }
// Tag returns a name identifying the unit that is safe to use // as a file name. The returned name will be different from other // Tag values returned by any other entities from the same state. func (u *Unit) Tag() string { return names.UnitTag(u.Name()) }