Пример #1
0
// NewPaths returns the set of filesystem paths that the supplied unit should
// use, given the supplied root juju data directory path.
func NewPaths(dataDir string, unitTag names.UnitTag) Paths {

	join := filepath.Join
	baseDir := join(dataDir, "agents", unitTag.String())
	stateDir := join(baseDir, "state")

	socket := func(name string, abstract bool) string {
		if version.Current.OS == version.Windows {
			return fmt.Sprintf(`\\.\pipe\%s-%s`, unitTag, name)
		}
		path := join(baseDir, name+".socket")
		if abstract {
			path = "@" + path
		}
		return path
	}

	toolsDir := tools.ToolsDir(dataDir, unitTag.String())
	return Paths{
		ToolsDir: filepath.FromSlash(toolsDir),
		Runtime: RuntimePaths{
			JujuRunSocket:     socket("run", false),
			JujucServerSocket: socket("agent", true),
		},
		State: StatePaths{
			CharmDir:        join(baseDir, "charm"),
			OperationsFile:  join(stateDir, "uniter"),
			RelationsDir:    join(stateDir, "relations"),
			BundlesDir:      join(stateDir, "bundles"),
			DeployerDir:     join(stateDir, "deployer"),
			StorageDir:      join(stateDir, "storage"),
			MetricsSpoolDir: join(stateDir, "spool", "metrics"),
		},
	}
}
Пример #2
0
func (ctx *SimpleContext) RecallUnit(unitName string) error {
	svc, err := ctx.findInitSystemJob(unitName)
	if err != nil {
		return errors.Trace(err)
	}
	installed, err := svc.Installed()
	if err != nil {
		return errors.Trace(err)
	}
	if !installed {
		return errors.Errorf("unit %q is not deployed", unitName)
	}
	if err := svc.Stop(); err != nil {
		return err
	}
	if err := svc.Remove(); err != nil {
		return err
	}
	tag := names.NewUnitTag(unitName)
	dataDir := ctx.agentConfig.DataDir()
	agentDir := agent.Dir(dataDir, tag)
	// Recursivley change mode to 777 on windows to avoid
	// Operation not permitted errors when deleting the agentDir
	err = recursiveChmod(agentDir, os.FileMode(0777))
	if err != nil {
		return err
	}
	if err := os.RemoveAll(agentDir); err != nil {
		return err
	}
	// TODO(dfc) should take a Tag
	toolsDir := tools.ToolsDir(dataDir, tag.String())
	return os.Remove(toolsDir)
}
Пример #3
0
func (fix *SimpleToolsFixture) paths(tag string) (confPath, agentDir, toolsDir string) {
	confName := fmt.Sprintf("jujud-%s.conf", tag)
	confPath = filepath.Join(fix.initDir, confName)
	agentDir = agent.Dir(fix.dataDir, tag)
	toolsDir = tools.ToolsDir(fix.dataDir, tag)
	return
}
Пример #4
0
func (s *ToolsSuite) SetUpTest(c *gc.C) {
	s.dataDir = c.MkDir()
	s.toolsDir = tools.SharedToolsDir(s.dataDir, version.Current)
	err := os.MkdirAll(s.toolsDir, 0755)
	c.Assert(err, gc.IsNil)
	err = symlink.New(s.toolsDir, tools.ToolsDir(s.dataDir, "unit-u-123"))
	c.Assert(err, gc.IsNil)
}
Пример #5
0
func (t *ToolsSuite) TestChangeAgentTools(c *gc.C) {
	files := []*testing.TarFile{
		testing.NewTarFile("jujuc", agenttools.DirPerm, "juju executable"),
		testing.NewTarFile("jujud", agenttools.DirPerm, "jujuc executable"),
	}
	data, checksum := testing.TarGz(files...)
	testTools := &coretest.Tools{
		URL:     "http://foo/bar1",
		Version: version.MustParseBinary("1.2.3-quantal-amd64"),
		Size:    int64(len(data)),
		SHA256:  checksum,
	}
	err := agenttools.UnpackTools(t.dataDir, testTools, bytes.NewReader(data))
	c.Assert(err, jc.ErrorIsNil)

	gotTools, err := agenttools.ChangeAgentTools(t.dataDir, "testagent", testTools.Version)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(*gotTools, gc.Equals, *testTools)

	assertDirNames(c, t.toolsDir(), []string{"1.2.3-quantal-amd64", "testagent"})
	assertDirNames(c, agenttools.ToolsDir(t.dataDir, "testagent"), []string{"jujuc", "jujud", agenttools.ToolsFile})

	// Upgrade again to check that the link replacement logic works ok.
	files2 := []*testing.TarFile{
		testing.NewTarFile("quantal", agenttools.DirPerm, "foo content"),
		testing.NewTarFile("amd64", agenttools.DirPerm, "bar content"),
	}
	data2, checksum2 := testing.TarGz(files2...)
	tools2 := &coretest.Tools{
		URL:     "http://foo/bar2",
		Version: version.MustParseBinary("1.2.4-quantal-amd64"),
		Size:    int64(len(data2)),
		SHA256:  checksum2,
	}
	err = agenttools.UnpackTools(t.dataDir, tools2, bytes.NewReader(data2))
	c.Assert(err, jc.ErrorIsNil)

	gotTools, err = agenttools.ChangeAgentTools(t.dataDir, "testagent", tools2.Version)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(*gotTools, gc.Equals, *tools2)

	assertDirNames(c, t.toolsDir(), []string{"1.2.3-quantal-amd64", "1.2.4-quantal-amd64", "testagent"})
	assertDirNames(c, agenttools.ToolsDir(t.dataDir, "testagent"), []string{"quantal", "amd64", agenttools.ToolsFile})
}
Пример #6
0
func (a *MachineAgent) createJujudSymlinks(dataDir string) error {
	jujud := filepath.Join(tools.ToolsDir(dataDir, a.Tag().String()), jujunames.Jujud)
	for _, link := range []string{jujuRun, jujuDumpLogs} {
		err := a.createSymlink(jujud, link)
		if err != nil {
			return errors.Annotatef(err, "failed to create %s symlink", link)
		}
	}
	return nil
}
Пример #7
0
// updateBackupMachineTag updates the paths that are stored in the backup
// to the current machine. This path is tied, among other factors, to the
// machine tag.
// Eventually this will change: when backups hold relative paths.
func updateBackupMachineTag(oldTag, newTag names.Tag) error {
	oldTagString := oldTag.String()
	newTagString := newTag.String()

	if oldTagString == newTagString {
		return nil
	}
	oldTagPath := path.Join(agent.DefaultPaths.DataDir, oldTagString)
	newTagPath := path.Join(agent.DefaultPaths.DataDir, newTagString)

	oldToolsDir := tools.ToolsDir(agent.DefaultPaths.DataDir, oldTagString)
	oldLink, err := filepath.EvalSymlinks(oldToolsDir)

	os.Rename(oldTagPath, newTagPath)
	newToolsDir := tools.ToolsDir(agent.DefaultPaths.DataDir, newTagString)
	newToolsPath := strings.Replace(oldLink, oldTagPath, newTagPath, -1)
	err = symlink.Replace(newToolsDir, newToolsPath)
	return errors.Annotatef(err, "cannot set the new tools path")
}
Пример #8
0
func (s *ToolsSuite) SetUpTest(c *gc.C) {
	s.dataDir = c.MkDir()
	s.toolsDir = tools.SharedToolsDir(s.dataDir, version.Binary{
		Number: version.Current,
		Arch:   arch.HostArch(),
		Series: series.HostSeries(),
	})
	err := os.MkdirAll(s.toolsDir, 0755)
	c.Assert(err, jc.ErrorIsNil)
	err = symlink.New(s.toolsDir, tools.ToolsDir(s.dataDir, "unit-u-123"))
	c.Assert(err, jc.ErrorIsNil)
}
Пример #9
0
func (s *UpgraderSuite) TestChangeAgentTools(c *gc.C) {
	oldTools := &coretools.Tools{
		Version: version.MustParseBinary("1.2.3-quantal-amd64"),
	}
	stor := s.DefaultToolsStorage
	newToolsBinary := "5.4.3-precise-amd64"
	newTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary(newToolsBinary))
	s.PatchValue(&version.Current, newTools.Version)
	err := envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{newTools}, envtools.DoNotWriteMirrors)
	c.Assert(err, jc.ErrorIsNil)
	ugErr := &upgrader.UpgradeReadyError{
		AgentName: "anAgent",
		OldTools:  oldTools.Version,
		NewTools:  newTools.Version,
		DataDir:   s.DataDir(),
	}
	err = ugErr.ChangeAgentTools()
	c.Assert(err, jc.ErrorIsNil)
	target := agenttools.ToolsDir(s.DataDir(), newToolsBinary)
	link, err := symlink.Read(agenttools.ToolsDir(s.DataDir(), "anAgent"))
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(link, jc.SamePath, target)
}
Пример #10
0
func (w *windowsConfigure) addMachineAgentToBoot(tag string) error {
	// Make the agent run via a symbolic link to the actual tools
	// directory, so it can upgrade itself without needing to change
	// the upstart script.
	toolsDir := tools.ToolsDir(w.mcfg.DataDir, tag)
	w.conf.AddScripts(
		fmt.Sprintf(
			`cmd.exe /C mklink /D %s %v`,
			w.renderer.FromSlash(toolsDir),
			w.mcfg.Tools.Version),
	)
	name := w.mcfg.MachineAgentServiceName
	cmds := w.machineAgentWindowsService(name, toolsDir)
	w.conf.AddScripts(cmds...)
	return nil
}
Пример #11
0
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.StopAndRemove(); err != nil {
		return err
	}
	tag := names.NewUnitTag(unitName).String()
	dataDir := ctx.agentConfig.DataDir()
	agentDir := agent.Dir(dataDir, tag)
	if err := os.RemoveAll(agentDir); err != nil {
		return err
	}
	toolsDir := tools.ToolsDir(dataDir, tag)
	return os.Remove(toolsDir)
}
Пример #12
0
func (cfg *MachineConfig) addMachineAgentToBoot(c *cloudinit.Config, tag, machineId string) error {
	// Make the agent run via a symbolic link to the actual tools
	// directory, so it can upgrade itself without needing to change
	// the upstart script.
	toolsDir := agenttools.ToolsDir(cfg.DataDir, tag)
	// TODO(dfc) ln -nfs, so it doesn't fail if for some reason that the target already exists
	c.AddScripts(fmt.Sprintf("ln -s %v %s", cfg.Tools.Version, shquote(toolsDir)))

	name := cfg.MachineAgentServiceName
	conf := upstart.MachineAgentUpstartService(name, toolsDir, cfg.DataDir, cfg.LogDir, tag, machineId, nil)
	cmds, err := conf.InstallCommands()
	if err != nil {
		return errors.Annotatef(err, "cannot make cloud-init upstart script for the %s agent", tag)
	}
	c.AddRunCmd(cloudinit.LogProgressCmd("Starting Juju machine agent (%s)", name))
	c.AddScripts(cmds...)
	return nil
}
Пример #13
0
func (s *UpgraderSuite) TestChangeAgentTools(c *gc.C) {
	oldTools := &coretools.Tools{
		Version: version.MustParseBinary("1.2.3-quantal-amd64"),
	}
	stor := s.Conn.Environ.Storage()
	newTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64"))
	s.PatchValue(&version.Current, newTools.Version)
	err := envtools.MergeAndWriteMetadata(stor, coretools.List{newTools}, envtools.DoNotWriteMirrors)
	c.Assert(err, gc.IsNil)
	ugErr := &upgrader.UpgradeReadyError{
		AgentName: "anAgent",
		OldTools:  oldTools.Version,
		NewTools:  newTools.Version,
		DataDir:   s.DataDir(),
	}
	err = ugErr.ChangeAgentTools()
	c.Assert(err, gc.IsNil)
	link, err := symlink.Read(agenttools.ToolsDir(s.DataDir(), "anAgent"))
	c.Assert(err, gc.IsNil)
	c.Assert(link, gc.Equals, newTools.Version.String())
}
Пример #14
0
func (ctx *SimpleContext) DeployUnit(unitName, initialPassword string) (err error) {
	// Check sanity.
	renderer, err := shell.NewRenderer("")
	if err != nil {
		return errors.Trace(err)
	}
	svc, err := ctx.service(unitName, renderer)
	if err != nil {
		return errors.Trace(err)
	}
	installed, err := svc.Installed()
	if err != nil {
		return errors.Trace(err)
	}
	if installed {
		return fmt.Errorf("unit %q is already deployed", unitName)
	}

	// Link the current tools for use by the new agent.
	tag := names.NewUnitTag(unitName)
	dataDir := ctx.agentConfig.DataDir()
	logDir := ctx.agentConfig.LogDir()
	current := version.Binary{
		Number: version.Current,
		Arch:   arch.HostArch(),
		Series: series.HostSeries(),
	}
	toolsDir := tools.ToolsDir(dataDir, tag.String())
	defer removeOnErr(&err, toolsDir)
	_, err = tools.ChangeAgentTools(dataDir, tag.String(), current)
	if err != nil {
		return errors.Trace(err)
	}

	result, err := ctx.api.ConnectionInfo()
	if err != nil {
		return errors.Trace(err)
	}
	logger.Debugf("state addresses: %q", result.StateAddresses)
	logger.Debugf("API addresses: %q", result.APIAddresses)
	containerType := ctx.agentConfig.Value(agent.ContainerType)
	namespace := ctx.agentConfig.Value(agent.Namespace)
	conf, err := agent.NewAgentConfig(
		agent.AgentConfigParams{
			Paths: agent.Paths{
				DataDir:         dataDir,
				LogDir:          logDir,
				MetricsSpoolDir: agent.DefaultPaths.MetricsSpoolDir,
			},
			UpgradedToVersion: version.Current,
			Tag:               tag,
			Password:          initialPassword,
			Nonce:             "unused",
			Model:             ctx.agentConfig.Model(),
			// TODO: remove the state addresses here and test when api only.
			StateAddresses: result.StateAddresses,
			APIAddresses:   result.APIAddresses,
			CACert:         ctx.agentConfig.CACert(),
			Values: map[string]string{
				agent.ContainerType: containerType,
				agent.Namespace:     namespace,
			},
		})
	if err != nil {
		return errors.Trace(err)
	}
	if err := conf.Write(); err != nil {
		return err
	}
	defer removeOnErr(&err, conf.Dir())

	// Install an init service that runs the unit agent.
	if err := service.InstallAndStart(svc); err != nil {
		return errors.Trace(err)
	}
	return nil
}
Пример #15
0
func (fix *SimpleToolsFixture) paths(tag names.Tag) (agentDir, toolsDir string) {
	agentDir = agent.Dir(fix.dataDir, tag)
	toolsDir = tools.ToolsDir(fix.dataDir, tag.String())
	return
}
Пример #16
0
// ToolsDir returns the path to the agent's tools dir.
func (ai AgentInfo) ToolsDir(renderer shell.Renderer) string {
	return renderer.FromSlash(tools.ToolsDir(ai.DataDir, ai.name))
}
Пример #17
0
func (p *collectPaths) GetToolsDir() string {
	return filepath.FromSlash(tools.ToolsDir(p.dataDir, p.unitTag.String()))
}
Пример #18
0
func (u *Uniter) init(unitTag string) (err error) {
	tag, err := names.ParseUnitTag(unitTag)
	if err != nil {
		return err
	}
	u.unit, err = u.st.Unit(tag)
	if err != nil {
		return err
	}
	if u.unit.Life() == params.Dead {
		// If we started up already dead, we should not progress further. If we
		// become Dead immediately after starting up, we may well complete any
		// operations in progress before detecting it; but that race is fundamental
		// and inescapable, whereas this one is not.
		return worker.ErrTerminateAgent
	}
	if err = u.setupLocks(); err != nil {
		return err
	}
	u.toolsDir = tools.ToolsDir(u.dataDir, unitTag)
	if err := EnsureJujucSymlinks(u.toolsDir); err != nil {
		return err
	}
	u.baseDir = filepath.Join(u.dataDir, "agents", unitTag)
	u.relationsDir = filepath.Join(u.baseDir, "state", "relations")
	if err := os.MkdirAll(u.relationsDir, 0755); err != nil {
		return err
	}
	serviceTag, err := names.ParseServiceTag(u.unit.ServiceTag())
	if err != nil {
		return err
	}
	u.service, err = u.st.Service(serviceTag)
	if err != nil {
		return err
	}
	var env *uniter.Environment
	env, err = u.st.Environment()
	if err != nil {
		return err
	}
	u.uuid = env.UUID()
	u.envName = env.Name()

	u.relationers = map[int]*Relationer{}
	u.relationHooks = make(chan hook.Info)
	u.charmPath = filepath.Join(u.baseDir, "charm")
	deployerPath := filepath.Join(u.baseDir, "state", "deployer")
	bundles := charm.NewBundlesDir(filepath.Join(u.baseDir, "state", "bundles"))
	u.deployer, err = charm.NewDeployer(u.charmPath, deployerPath, bundles)
	if err != nil {
		return fmt.Errorf("cannot create deployer: %v", err)
	}
	u.sf = NewStateFile(filepath.Join(u.baseDir, "state", "uniter"))
	u.rand = rand.New(rand.NewSource(time.Now().Unix()))

	// If we start trying to listen for juju-run commands before we have valid
	// relation state, surprising things will come to pass.
	if err := u.restoreRelations(); err != nil {
		return err
	}
	runListenerSocketPath := filepath.Join(u.baseDir, RunListenerFile)
	logger.Debugf("starting juju-run listener on unix:%s", runListenerSocketPath)
	u.runListener, err = NewRunListener(u, runListenerSocketPath)
	if err != nil {
		return err
	}
	// The socket needs to have permissions 777 in order for other users to use it.
	return os.Chmod(runListenerSocketPath, 0777)
}
Пример #19
0
func (ctx *SimpleContext) DeployUnit(unitName, initialPassword string) (err error) {
	// Check sanity.
	svc := ctx.service(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.NewUnitTag(unitName)
	dataDir := ctx.agentConfig.DataDir()
	logDir := ctx.agentConfig.LogDir()
	// TODO(dfc)
	_, err = tools.ChangeAgentTools(dataDir, tag.String(), version.Current)
	// TODO(dfc)
	toolsDir := tools.ToolsDir(dataDir, tag.String())
	defer removeOnErr(&err, toolsDir)

	result, err := ctx.api.ConnectionInfo()
	if err != nil {
		return err
	}
	logger.Debugf("state addresses: %q", result.StateAddresses)
	logger.Debugf("API addresses: %q", result.APIAddresses)
	containerType := ctx.agentConfig.Value(agent.ContainerType)
	namespace := ctx.agentConfig.Value(agent.Namespace)
	conf, err := agent.NewAgentConfig(
		agent.AgentConfigParams{
			DataDir:           dataDir,
			LogDir:            logDir,
			UpgradedToVersion: version.Current.Number,
			Tag:               tag,
			Password:          initialPassword,
			Nonce:             "unused",
			// TODO: remove the state addresses here and test when api only.
			StateAddresses: result.StateAddresses,
			APIAddresses:   result.APIAddresses,
			CACert:         ctx.agentConfig.CACert(),
			Values: map[string]string{
				agent.ContainerType: containerType,
				agent.Namespace:     namespace,
			},
		})
	if err != nil {
		return err
	}
	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(logDir, tag.String()+".log")
	cmd := strings.Join([]string{
		filepath.FromSlash(path.Join(toolsDir, jujunames.Jujud)), "unit",
		"--data-dir", dataDir,
		"--unit-name", unitName,
		"--debug", // TODO: propagate debug state sensibly
	}, " ")
	// TODO(thumper): 2013-09-02 bug 1219630
	// As much as I'd like to remove JujuContainerType now, it is still
	// needed as MAAS still needs it at this stage, and we can't fix
	// everything at once.
	sconf := common.Conf{
		Desc: "juju unit agent for " + unitName,
		Cmd:  cmd,
		Out:  logPath,
		Env: map[string]string{
			osenv.JujuContainerTypeEnvKey: containerType,
		},
		InitDir: ctx.initDir,
	}
	svc.UpdateConfig(sconf)
	return svc.Install()
}