// UntarFiles will extract the contents of tarFile using // outputFolder as root func UntarFiles(tarFile io.Reader, outputFolder string) error { tr := tar.NewReader(tarFile) for { hdr, err := tr.Next() if err == io.EOF { // end of tar archive return nil } if err != nil { return fmt.Errorf("failed while reading tar header: %v", err) } fullPath := filepath.Join(outputFolder, hdr.Name) switch hdr.Typeflag { case tar.TypeDir: if err = os.MkdirAll(fullPath, os.FileMode(hdr.Mode)); err != nil { return fmt.Errorf("cannot extract directory %q: %v", fullPath, err) } case tar.TypeSymlink: if err = symlink.New(hdr.Linkname, fullPath); err != nil { return fmt.Errorf("cannot extract symlink %q to %q: %v", hdr.Linkname, fullPath, err) } continue case tar.TypeReg, tar.TypeRegA: if err = createAndFill(fullPath, hdr.Mode, tr); err != nil { return fmt.Errorf("cannot extract file %q: %v", fullPath, err) } } } return nil }
func (s *prereqsSuite) SetUpTest(c *gc.C) { s.BaseSuite.SetUpTest(c) s.tmpdir = c.MkDir() s.testMongodPath = filepath.Join(s.tmpdir, "mongod") s.PatchEnvironment("PATH", s.tmpdir) s.PatchValue(&mongo.JujuMongodPath, "/somewhere/that/wont/exist") os.Setenv("JUJUTEST_LSB_RELEASE_ID", "Ubuntu") err := ioutil.WriteFile(filepath.Join(s.tmpdir, "lsb_release"), []byte(lsbrelease), 0777) c.Assert(err, jc.ErrorIsNil) // symlink $temp/dpkg-query to /bin/true, to // simulate package installation query responses. pm, err := testing.GetPackageManager() c.Assert(err, jc.ErrorIsNil) err = symlink.New("/bin/true", filepath.Join(s.tmpdir, pm.PackageQuery)) c.Assert(err, jc.ErrorIsNil) s.PatchValue(&isPackageInstalled, func(pack string) bool { pacman, err := manager.NewPackageManager(series.HostSeries()) c.Assert(err, jc.ErrorIsNil) return pacman.IsInstalled(pack) }) }
func (*SymlinkSuite) TestReplace(c *gc.C) { target, err := symlink.GetLongPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) target_second, err := symlink.GetLongPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) link := filepath.Join(target, "link") _, err = os.Stat(target) c.Assert(err, gc.IsNil) _, err = os.Stat(target_second) c.Assert(err, gc.IsNil) err = symlink.New(target, link) c.Assert(err, gc.IsNil) link_target, err := symlink.Read(link) c.Assert(err, gc.IsNil) c.Assert(link_target, gc.Equals, filepath.FromSlash(target)) err = symlink.Replace(link, target_second) c.Assert(err, gc.IsNil) link_target, err = symlink.Read(link) c.Assert(err, gc.IsNil) c.Assert(link_target, gc.Equals, filepath.FromSlash(target_second)) }
func (s *MachineSuite) TestMachineAgentSymlinkJujuRunExists(c *gc.C) { if runtime.GOOS == "windows" { // Cannot make symlink to nonexistent file on windows or // create a file point a symlink to it then remove it c.Skip("Cannot test this on windows") } stm, _, _ := s.primeAgent(c, state.JobManageModel) a := s.newAgent(c, stm) defer a.Stop() // Pre-create the symlinks, but pointing to the incorrect location. links := []string{jujuRun, jujuDumpLogs} a.rootDir = c.MkDir() for _, link := range links { fullLink := utils.EnsureBaseDir(a.rootDir, link) c.Assert(os.MkdirAll(filepath.Dir(fullLink), os.FileMode(0755)), jc.ErrorIsNil) c.Assert(symlink.New("/nowhere/special", fullLink), jc.ErrorIsNil, gc.Commentf(link)) } // Start the agent and wait for it be running. _, done := s.waitForOpenState(c, a) // juju-run symlink should have been recreated. for _, link := range links { fullLink := utils.EnsureBaseDir(a.rootDir, link) linkTarget, err := symlink.Read(fullLink) c.Assert(err, jc.ErrorIsNil) c.Assert(linkTarget, gc.Not(gc.Equals), "/nowhere/special", gc.Commentf(link)) } s.waitStopped(c, state.JobManageModel, a, done) }
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) }
func (a *MachineAgent) createJujuRun(dataDir string) error { // TODO do not remove the symlink if it already points // to the right place. if err := os.Remove(jujuRun); err != nil && !os.IsNotExist(err) { return err } jujud := filepath.Join(dataDir, "tools", a.Tag().String(), jujunames.Jujud) return symlink.New(jujud, jujuRun) }
func (s *prereqsSuite) TestJujuLocalPrereq(c *gc.C) { err := os.Remove(filepath.Join(s.tmpdir, "dpkg-query")) c.Assert(err, gc.IsNil) err = symlink.New("/bin/false", filepath.Join(s.tmpdir, "dpkg-query")) c.Assert(err, gc.IsNil) err = VerifyPrerequisites(instance.LXC) c.Assert(err, gc.ErrorMatches, "(.|\n)*juju-local must be installed to enable the local provider(.|\n)*") c.Assert(err, gc.ErrorMatches, "(.|\n)*apt-get install juju-local(.|\n)*") }
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) }
func (s *prereqsSuite) TestJujuLocalPrereq(c *gc.C) { pm, err := testing.GetPackageManager() c.Assert(err, jc.ErrorIsNil) err = os.Remove(filepath.Join(s.tmpdir, pm.PackageQuery)) c.Assert(err, jc.ErrorIsNil) err = symlink.New("/bin/false", filepath.Join(s.tmpdir, pm.PackageQuery)) c.Assert(err, jc.ErrorIsNil) err = VerifyPrerequisites(instance.LXC) c.Assert(err, gc.ErrorMatches, "(.|\n)*juju-local must be installed to enable the local provider(.|\n)*") c.Assert(err, gc.ErrorMatches, "(.|\n)*apt-get install juju-local(.|\n)*") }
func (s *MachineSuite) TestMachineAgentSymlinkJujuRunExists(c *gc.C) { err := symlink.New("/nowhere/special", jujuRun) c.Assert(err, gc.IsNil) _, err = os.Stat(jujuRun) c.Assert(err, jc.Satisfies, os.IsNotExist) s.assertJobWithAPI(c, state.JobManageEnviron, func(conf agent.Config, st *api.State) { // juju-run should have been recreated _, err := os.Stat(jujuRun) c.Assert(err, gc.IsNil) link, err := symlink.Read(jujuRun) c.Assert(err, gc.IsNil) c.Assert(link, gc.Not(gc.Equals), "/nowhere/special") }) }
func (*SymlinkSuite) TestCreateSymLink(c *gc.C) { target, err := symlink.GetLongPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) link := filepath.Join(target, "link") _, err = os.Stat(target) c.Assert(err, gc.IsNil) err = symlink.New(target, link) c.Assert(err, gc.IsNil) link, err = symlink.Read(link) c.Assert(err, gc.IsNil) c.Assert(link, gc.Equals, filepath.FromSlash(target)) }
// EnsureJujucSymlinks creates a symbolic link to jujuc within dir for each // hook command. If the commands already exist, this operation does nothing. func EnsureJujucSymlinks(dir string) (err error) { for _, name := range jujuc.CommandNames() { // The link operation fails when the target already exists, // so this is a no-op when the command names already // exist. err := symlink.New("./jujud", filepath.Join(dir, name)) if err == nil { continue } // TODO(rog) drop LinkError check when fix is released (see http://codereview.appspot.com/6442080/) if e, ok := err.(*os.LinkError); !ok || !os.IsExist(e.Err) { return fmt.Errorf("cannot initialize hook commands in %q: %v", dir, err) } } return nil }
func (s *BaseRepoSuite) SetUpTest(c *gc.C) { // Set up a local repository. s.RepoPath = os.Getenv("JUJU_REPOSITORY") repoPath := c.MkDir() os.Setenv("JUJU_REPOSITORY", repoPath) s.SeriesPath = filepath.Join(repoPath, config.LatestLtsSeries()) c.Assert(os.Mkdir(s.SeriesPath, 0777), jc.ErrorIsNil) // Create a symlink "quantal" -> "precise", because most charms // and machines are written with hard-coded "quantal" series, // hence they interact badly with a local repository that assumes // only "precise" charms are available. err := symlink.New(s.SeriesPath, filepath.Join(repoPath, "quantal")) c.Assert(err, jc.ErrorIsNil) s.BundlesPath = filepath.Join(repoPath, "bundle") c.Assert(os.Mkdir(s.BundlesPath, 0777), jc.ErrorIsNil) }
func (*SymlinkSuite) TestIsSymlinkFolder(c *gc.C) { target, err := symlink.GetLongPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) link := filepath.Join(target, "link") _, err = os.Stat(target) c.Assert(err, gc.IsNil) err = symlink.New(target, link) c.Assert(err, gc.IsNil) isSymlink, err := symlink.IsSymlink(link) c.Assert(err, gc.IsNil) c.Assert(isSymlink, jc.IsTrue) }
// ChangeAgentTools atomically replaces the agent-specific symlink // under dataDir so it points to the previously unpacked // version vers. It returns the new tools read. func ChangeAgentTools(dataDir string, agentName string, vers version.Binary) (*coretools.Tools, error) { tools, err := ReadTools(dataDir, vers) if err != nil { return nil, err } tmpName := ToolsDir(dataDir, "tmplink-"+agentName) err = symlink.New(tools.Version.String(), tmpName) if err != nil { return nil, fmt.Errorf("cannot create tools symlink: %v", err) } err = os.Rename(tmpName, ToolsDir(dataDir, agentName)) if err != nil { return nil, fmt.Errorf("cannot update tools symlink: %v", err) } return tools, nil }
func (s *GitDeployerSuite) TestUpgrade(c *gc.C) { // Install. info1 := s.bundles.AddCustomBundle(c, corecharm.MustParseURL("cs:s/c-1"), func(path string) { err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644) c.Assert(err, jc.ErrorIsNil) err = symlink.New("./some-file", filepath.Join(path, "a-symlink")) c.Assert(err, jc.ErrorIsNil) }) err := s.deployer.Stage(info1, nil) c.Assert(err, jc.ErrorIsNil) err = s.deployer.Deploy() c.Assert(err, jc.ErrorIsNil) // Upgrade. info2 := s.bundles.AddCustomBundle(c, corecharm.MustParseURL("cs:s/c-2"), func(path string) { err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("goodbye"), 0644) c.Assert(err, jc.ErrorIsNil) err = ioutil.WriteFile(filepath.Join(path, "a-symlink"), []byte("not any more!"), 0644) c.Assert(err, jc.ErrorIsNil) }) err = s.deployer.Stage(info2, nil) c.Assert(err, jc.ErrorIsNil) checkCleanup(c, s.deployer) err = s.deployer.Deploy() c.Assert(err, jc.ErrorIsNil) checkCleanup(c, s.deployer) // Check content. data, err := ioutil.ReadFile(filepath.Join(s.targetPath, "some-file")) c.Assert(err, jc.ErrorIsNil) c.Assert(string(data), gc.Equals, "goodbye") data, err = ioutil.ReadFile(filepath.Join(s.targetPath, "a-symlink")) c.Assert(err, jc.ErrorIsNil) c.Assert(string(data), gc.Equals, "not any more!") target := charm.NewGitDir(s.targetPath) url, err := target.ReadCharmURL() c.Assert(err, jc.ErrorIsNil) c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-2")) lines, err := target.Log() c.Assert(err, jc.ErrorIsNil) c.Assert(lines, gc.HasLen, 5) c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Upgraded charm to "cs:s/c-2".`) }
func (s *prereqsSuite) SetUpTest(c *gc.C) { s.BaseSuite.SetUpTest(c) s.tmpdir = c.MkDir() s.testMongodPath = filepath.Join(s.tmpdir, "mongod") s.PatchEnvironment("PATH", s.tmpdir) s.PatchValue(&mongo.JujuMongodPath, "/somewhere/that/wont/exist") os.Setenv("JUJUTEST_LSB_RELEASE_ID", "Ubuntu") err := ioutil.WriteFile(filepath.Join(s.tmpdir, "lsb_release"), []byte(lsbrelease), 0777) c.Assert(err, gc.IsNil) // symlink $temp/dpkg-query to /bin/true, to // simulate package installation query responses. err = symlink.New("/bin/true", filepath.Join(s.tmpdir, "dpkg-query")) c.Assert(err, gc.IsNil) s.PatchValue(&isPackageInstalled, apt.IsPackageInstalled) }
func autostartContainer(name string) error { // Now symlink the config file into the restart directory, if it exists. // This is for backwards compatiblity. From Trusty onwards, the auto start // option should be set in the LXC config file, this is done in the networkConfigTemplate // function below. if useRestartDir() { if err := symlink.New( containerConfigFilename(name), restartSymlink(name), ); err != nil { return err } logger.Tracef("auto-restart link created") } else { logger.Tracef("Setting auto start to true in lxc config.") return appendToContainerConfig(name, "lxc.start.auto = 1\n") } return nil }
func (*SymlinkSuite) TestIsSymlinkFile(c *gc.C) { dir, err := symlink.GetLongPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) target := filepath.Join(dir, "file") err = ioutil.WriteFile(target, []byte("TOP SECRET"), 0644) c.Assert(err, gc.IsNil) link := filepath.Join(dir, "link") _, err = os.Stat(target) c.Assert(err, gc.IsNil) err = symlink.New(target, link) c.Assert(err, gc.IsNil) isSymlink, err := symlink.IsSymlink(link) c.Assert(err, gc.IsNil) c.Assert(isSymlink, jc.IsTrue) }
func (s *RepoSuite) SetUpTest(c *gc.C) { s.JujuConnSuite.SetUpTest(c) // Change the environ's config to ensure we're using the one in state, // not the one in the local environments.yaml updateAttrs := map[string]interface{}{"default-series": config.LatestLtsSeries()} err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) c.Assert(err, jc.ErrorIsNil) s.RepoPath = os.Getenv("JUJU_REPOSITORY") repoPath := c.MkDir() os.Setenv("JUJU_REPOSITORY", repoPath) s.SeriesPath = filepath.Join(repoPath, config.LatestLtsSeries()) err = os.Mkdir(s.SeriesPath, 0777) c.Assert(err, jc.ErrorIsNil) // Create a symlink "quantal" -> "precise", because most charms // and machines are written with hard-coded "quantal" series, // hence they interact badly with a local repository that assumes // only "precise" charms are available. err = symlink.New(s.SeriesPath, filepath.Join(repoPath, "quantal")) c.Assert(err, jc.ErrorIsNil) }
func (s *UpstartSuite) TestInstallAlreadyRunning(c *gc.C) { pathTo := func(name string) string { return filepath.Join(s.testPath, name) } s.MakeTool(c, "status-stopped", `echo "some-service stop/waiting"`) s.MakeTool(c, "status-started", `echo "some-service start/running, process 123"`) s.MakeTool(c, "stop", fmt.Sprintf( "rm %s; ln -s %s %s", pathTo("status"), pathTo("status-stopped"), pathTo("status"), )) s.MakeTool(c, "start", fmt.Sprintf( "rm %s; ln -s %s %s", pathTo("status"), pathTo("status-started"), pathTo("status"), )) err := symlink.New(pathTo("status-started"), pathTo("status")) c.Assert(err, gc.IsNil) conf := s.dummyConf(c) err = conf.Install() c.Assert(err, gc.IsNil) c.Assert(&conf.Service, jc.Satisfies, (*upstart.Service).Running) }
func (*SymlinkSuite) TestReadData(c *gc.C) { dir := c.MkDir() sub := filepath.Join(dir, "sub") err := os.Mkdir(sub, 0700) c.Assert(err, gc.IsNil) oldname := filepath.Join(sub, "foo") data := []byte("data") err = ioutil.WriteFile(oldname, data, 0644) c.Assert(err, gc.IsNil) newname := filepath.Join(dir, "bar") err = symlink.New(oldname, newname) c.Assert(err, gc.IsNil) b, err := ioutil.ReadFile(newname) c.Assert(err, gc.IsNil) c.Assert(string(b), gc.Equals, string(data)) }
func (a *MachineAgent) createSymlink(target, link string) error { fullLink := utils.EnsureBaseDir(a.rootDir, link) currentTarget, err := symlink.Read(fullLink) if err != nil && !os.IsNotExist(err) { return err } else if err == nil { // Link already in place - check it. if currentTarget == target { // Link already points to the right place - nothing to do. return nil } // Link points to the wrong place - delete it. if err := os.Remove(fullLink); err != nil { return err } } if err := os.MkdirAll(filepath.Dir(fullLink), os.FileMode(0755)); err != nil { return err } return symlink.New(target, fullLink) }
// EnsureSymlinks creates a symbolic link to jujuc within dir for each // hook command. If the commands already exist, this operation does nothing. // If dir is a symbolic link, it will be dereferenced first. func EnsureSymlinks(dir string) (err error) { logger.Infof("ensure jujuc symlinks in %s", dir) defer func() { if err != nil { err = errors.Annotatef(err, "cannot initialize hook commands in %q", dir) } }() isSymlink, err := symlink.IsSymlink(dir) if err != nil { return err } if isSymlink { link, err := symlink.Read(dir) if err != nil { return err } if !filepath.IsAbs(link) { logger.Infof("%s is relative", link) link = filepath.Join(filepath.Dir(dir), link) } dir = link logger.Infof("was a symlink, now looking at %s", dir) } jujudPath := filepath.Join(dir, names.Jujud) logger.Debugf("jujud path %s", jujudPath) for _, name := range CommandNames() { // The link operation fails when the target already exists, // so this is a no-op when the command names already // exist. err := symlink.New(jujudPath, filepath.Join(dir, name)) if err != nil && !os.IsExist(err) { return err } } return nil }
func (s *UpstartSuite) TestInstallAlreadyRunning(c *gc.C) { pathTo := func(name string) string { return filepath.Join(s.testPath, name) } s.MakeTool(c, "status-stopped", `echo "some-application stop/waiting"`) s.MakeTool(c, "status-started", `echo "some-application start/running, process 123"`) s.MakeTool(c, "stop", fmt.Sprintf( "rm %s; ln -s %s %s", pathTo("status"), pathTo("status-stopped"), pathTo("status"), )) s.MakeTool(c, "start", fmt.Sprintf( "rm %s; ln -s %s %s", pathTo("status"), pathTo("status-started"), pathTo("status"), )) err := symlink.New(pathTo("status-started"), pathTo("status")) c.Assert(err, jc.ErrorIsNil) svc := upstart.NewService("some-application", s.dummyConf(c)) err = svc.Install() c.Assert(err, jc.ErrorIsNil) installed, err := svc.Running() c.Assert(err, jc.ErrorIsNil) c.Check(installed, jc.IsTrue) }
func (d *gitDeployer) Stage(info BundleInfo, abort <-chan struct{}) error { // Make sure we've got an actual bundle available. bundle, err := d.bundles.Read(info, abort) if err != nil { return err } // Read present state of current. if err := os.MkdirAll(d.dataPath, 0755); err != nil { return err } defer collectGitOrphans(d.dataPath) srcExists, err := d.current.Exists() if err != nil { return err } url := info.URL() if srcExists { prevURL, err := d.current.ReadCharmURL() if err != nil { return err } if *url == *prevURL { return nil } } // Prepare a fresh repository for the update, using current's history // if it exists. updatePath, err := d.newDir(gitUpdatePrefix) if err != nil { return err } var repo *GitDir if srcExists { repo, err = d.current.Clone(updatePath) } else { repo = NewGitDir(updatePath) err = repo.Init() } if err != nil { return err } // Write the desired new state and commit. if err = bundle.ExpandTo(updatePath); err != nil { return err } if err = repo.WriteCharmURL(url); err != nil { return err } if err = repo.Snapshotf("Imported charm %q.", url); err != nil { return err } // Atomically rename fresh repository to current. tmplink := filepath.Join(updatePath, "tmplink") if err = symlink.New(updatePath, tmplink); err != nil { return err } return os.Rename(tmplink, d.current.Path()) }
// finishBootstrap converts the machine config to cloud-config, // converts that to a script, and then executes it locally. func (env *localEnviron) finishBootstrap(ctx environs.BootstrapContext, icfg *instancecfg.InstanceConfig) error { icfg.InstanceId = bootstrapInstanceId icfg.DataDir = env.config.rootDir() icfg.LogDir = fmt.Sprintf("/var/log/juju-%s", env.config.namespace()) icfg.CloudInitOutputLog = filepath.Join(icfg.DataDir, "cloud-init-output.log") // No JobManageNetworking added in order not to change the network // configuration of the user's machine. icfg.Jobs = []multiwatcher.MachineJob{multiwatcher.JobManageEnviron} icfg.MachineAgentServiceName = env.machineAgentServiceName() icfg.AgentEnvironment = map[string]string{ agent.Namespace: env.config.namespace(), agent.LxcBridge: env.config.networkBridge(), // The local provider only supports a single state server, // so we make the oplog size to a small value. This makes // the preallocation faster with no disadvantage. agent.MongoOplogSize: "1", // 1MB } if err := instancecfg.FinishInstanceConfig(icfg, env.Config()); err != nil { return errors.Trace(err) } // Since Juju's state machine is currently the host machine // for local providers, don't stomp on it. cfgAttrs := env.config.AllAttrs() if val, ok := cfgAttrs["enable-os-refresh-update"].(bool); !ok { logger.Infof("local provider; disabling refreshing OS updates.") icfg.EnableOSRefreshUpdate = false } else { icfg.EnableOSRefreshUpdate = val } if val, ok := cfgAttrs["enable-os-upgrade"].(bool); !ok { logger.Infof("local provider; disabling OS upgrades.") icfg.EnableOSUpgrade = false } else { icfg.EnableOSUpgrade = val } // don't write proxy or mirror settings for local machine icfg.AptProxySettings = proxy.Settings{} icfg.ProxySettings = proxy.Settings{} icfg.AptMirror = "" cloudcfg, err := cloudinit.New(icfg.Series) if err != nil { return errors.Trace(err) } cloudcfg.SetSystemUpdate(icfg.EnableOSRefreshUpdate) cloudcfg.SetSystemUpgrade(icfg.EnableOSUpgrade) localLogDir := filepath.Join(icfg.DataDir, "log") if err := os.RemoveAll(localLogDir); err != nil { return errors.Trace(err) } if err := symlink.New(icfg.LogDir, localLogDir); err != nil { return errors.Trace(err) } if err := os.Remove(icfg.CloudInitOutputLog); err != nil && !os.IsNotExist(err) { return errors.Trace(err) } cloudcfg.AddScripts( fmt.Sprintf("rm -fr %s", icfg.LogDir), ) udata, err := cloudconfig.NewUserdataConfig(icfg, cloudcfg) if err != nil { return errors.Trace(err) } if err := udata.ConfigureJuju(); err != nil { return errors.Trace(err) } return executeCloudConfig(ctx, icfg, cloudcfg) }
func migrateLocalProviderAgentConfig(context Context) error { st := context.State() if st == nil { logger.Debugf("no state connection, no migration required") // We're running on a different node than the state server. return nil } envConfig, err := st.EnvironConfig() if err != nil { return fmt.Errorf("failed to read current config: %v", err) } if !isLocalEnviron(envConfig) { logger.Debugf("not a local environment, no migration required") return nil } attrs := envConfig.AllAttrs() rootDir, _ := attrs["root-dir"].(string) sharedStorageDir := filepath.Join(rootDir, "shared-storage") // In case these two are empty we need to set them and update the // environment config. namespace, _ := attrs["namespace"].(string) container, _ := attrs["container"].(string) if namespace == "" { username := os.Getenv("USER") if username == "root" { // sudo was probably called, get the original user. username = os.Getenv("SUDO_USER") } if username == "" { return fmt.Errorf("cannot get current user from the environment: %v", os.Environ()) } namespace = username + "-" + envConfig.Name() } if container == "" { container = "lxc" } dataDir := rootDir localLogDir := filepath.Join(rootDir, "log") metricSpoolDir := filepath.Join(rootDir, "metricspool") uniterStateDir := filepath.Join(rootDir, "uniter", "state") // rsyslogd is restricted to write to /var/log logDir := fmt.Sprintf("%s/juju-%s", rootLogDir, namespace) jobs := []multiwatcher.MachineJob{multiwatcher.JobManageEnviron} values := map[string]string{ agent.Namespace: namespace, // ContainerType is empty on the bootstrap node. agent.ContainerType: "", agent.AgentServiceName: "juju-agent-" + namespace, } deprecatedValues := []string{ "SHARED_STORAGE_ADDR", "SHARED_STORAGE_DIR", } // Remove shared-storage dir if there. if err := os.RemoveAll(sharedStorageDir); err != nil { return fmt.Errorf("cannot remove deprecated %q: %v", sharedStorageDir, err) } // We need to create the dirs if they don't exist. if err := os.MkdirAll(dataDir, 0755); err != nil { return fmt.Errorf("cannot create dataDir %q: %v", dataDir, err) } // We always recreate the logDir to make sure it's empty. if err := os.RemoveAll(logDir); err != nil { return fmt.Errorf("cannot remove logDir %q: %v", logDir, err) } if err := os.MkdirAll(logDir, 0755); err != nil { return fmt.Errorf("cannot create logDir %q: %v", logDir, err) } if err := os.MkdirAll(metricSpoolDir, 0755); err != nil { return fmt.Errorf("cannot create metricSpoolDir %q: %v", metricSpoolDir, err) } if err := os.MkdirAll(uniterStateDir, 0755); err != nil { return fmt.Errorf("cannot create uniterStateDir %q: %v", uniterStateDir, err) } // Reconfigure rsyslog as needed: // 1. logDir must be owned by syslog:adm // 2. Remove old rsyslog spool config // 3. Relink logs to the new logDir if err := chownPath(logDir, "syslog"); err != nil { return err } spoolConfig := fmt.Sprintf("%s/machine-0-%s", rootSpoolDir, namespace) if err := os.RemoveAll(spoolConfig); err != nil { return fmt.Errorf("cannot remove %q: %v", spoolConfig, err) } allMachinesLog := filepath.Join(logDir, "all-machines.log") if err := symlink.New(allMachinesLog, localLogDir+"/"); err != nil && !os.IsExist(err) { return fmt.Errorf("cannot symlink %q to %q: %v", allMachinesLog, localLogDir, err) } machine0Log := filepath.Join(localLogDir, "machine-0.log") if err := symlink.New(machine0Log, logDir+"/"); err != nil && !os.IsExist(err) { return fmt.Errorf("cannot symlink %q to %q: %v", machine0Log, logDir, err) } newCfg := map[string]interface{}{ "namespace": namespace, "container": container, } if err := st.UpdateEnvironConfig(newCfg, nil, nil); err != nil { return fmt.Errorf("cannot update environment config: %v", err) } return context.AgentConfig().Migrate(agent.MigrateParams{ Paths: agent.Paths{ DataDir: dataDir, LogDir: logDir, MetricsSpoolDir: metricSpoolDir, }, Jobs: jobs, Values: values, DeleteValues: deprecatedValues, }) }
func (s *ToolsSuite) TestEnsureSymlinksSymlinkedDir(c *gc.C) { toolsDirSymlink := filepath.Join(c.MkDir(), "unit-ubuntu-0") err := symlink.New(s.toolsDir, toolsDirSymlink) c.Assert(err, jc.ErrorIsNil) s.testEnsureSymlinks(c, toolsDirSymlink) }