func (s *JujuXDGDataHomeSuite) TestErrorHome(c *gc.C) { // Invalid juju home leads to panic when retrieving. f := func() { _ = osenv.JujuXDGDataHome() } c.Assert(f, gc.PanicMatches, "juju home hasn't been initialized") f = func() { _ = osenv.JujuXDGDataHomePath("current-environment") } c.Assert(f, gc.PanicMatches, "juju home hasn't been initialized") }
func (s *MainSuite) TestNoWarnWithNo1xOr2xData(c *gc.C) { // patch out lookpath to always return a nil error (and thus indicates success). s.PatchValue(&execLookPath, func(s string) (string, error) { c.Assert(s, gc.Equals, "juju-1") return "we ignore this anyway", nil }) // remove the new juju-home. err := os.Remove(osenv.JujuXDGDataHome()) // create fake (empty) old juju home. path := c.MkDir() s.PatchEnvironment("JUJU_HOME", path) outdir := c.MkDir() // dump stderr to a file so we can examine it without any wacky re-running // of the executable (since we need to mock things out.) stderr, err := os.OpenFile(filepath.Join(outdir, "stderr"), os.O_RDWR|os.O_CREATE, 0600) c.Assert(err, jc.ErrorIsNil) defer stderr.Close() // dump stdout to a file so it doesn't spam the test output. stdout, err := os.OpenFile(filepath.Join(outdir, "stdout"), os.O_RDWR|os.O_CREATE, 0600) c.Assert(err, jc.ErrorIsNil) runMain(stderr, stdout, []string{"juju", "version"}) _, err = stderr.Seek(0, 0) c.Assert(err, jc.ErrorIsNil) output, err := ioutil.ReadAll(stderr) c.Assert(err, jc.ErrorIsNil) c.Assert(string(output), gc.Equals, "") }
func (s *store) lock(operation string) (*fslock.Lock, error) { lockName := "controllers.lock" lock, err := fslock.NewLock(osenv.JujuXDGDataHome(), lockName, fslock.Defaults()) if err != nil { return nil, errors.Trace(err) } message := fmt.Sprintf("pid: %d, operation: %s", os.Getpid(), operation) err = lock.LockWithTimeout(lockTimeout, message) if err == nil { return lock, nil } if errors.Cause(err) != fslock.ErrTimeout { return nil, errors.Trace(err) } logger.Warningf("breaking jujuclient lock : %s", lockName) logger.Warningf(" lock holder message: %s", lock.Message()) // If we are unable to acquire the lock within the lockTimeout, // consider it broken for some reason, and break it. err = lock.BreakLock() if err != nil { return nil, errors.Annotatef(err, "unable to break the jujuclient lock %v", lockName) } err = lock.LockWithTimeout(lockTimeout, message) if err != nil { return nil, errors.Trace(err) } return lock, nil }
func (s *fakeHomeSuite) TearDownTest(c *gc.C) { s.FakeJujuXDGDataHomeSuite.TearDownTest(c) // Test that the environment is restored. c.Assert(utils.Home(), gc.Equals, jujuXDGDataHome) c.Assert(os.Getenv("JUJU_DATA"), gc.Equals, jujuXDGDataHome) c.Assert(osenv.JujuXDGDataHome(), gc.Equals, jujuXDGDataHome) }
// BadRun is used to run a command, check the exit code, and return the output. func BadRun(c *gc.C, exit int, args ...string) string { localArgs := append([]string{"-test.run", "TestRunMain", "-run-main", "--"}, args...) ps := exec.Command(os.Args[0], localArgs...) ps.Env = append(os.Environ(), osenv.JujuXDGDataHomeEnvKey+"="+osenv.JujuXDGDataHome()) output, err := ps.CombinedOutput() c.Logf("command output: %q", output) if exit != 0 { c.Assert(err, gc.ErrorMatches, fmt.Sprintf("exit status %d", exit)) } return string(output) }
func (s *MainSuite) TestFirstRun2xFrom1x(c *gc.C) { // patch out lookpath to always return a nil error (and thus indicates success). s.PatchValue(&execLookPath, func(s string) (string, error) { c.Assert(s, gc.Equals, "juju-1") return "we ignore this anyway", nil }) // patch out the exec.Command used to run juju-1 so that it runs our test helper instead. s.PatchValue(&execCommand, func(command string, args ...string) *exec.Cmd { cs := []string{"-test.run=TestFirstRun2xFrom1xHelper", "--", command} cs = append(cs, args...) cmd := exec.Command(os.Args[0], cs...) cmd.Env = []string{"JUJU_WANT_HELPER_PROCESS=1"} return cmd }) // remove the new juju-home and create a fake old juju home. err := os.Remove(osenv.JujuXDGDataHome()) c.Assert(err, jc.ErrorIsNil) oldhome := osenv.OldJujuHomeDir() err = os.MkdirAll(oldhome, 0700) c.Assert(err, jc.ErrorIsNil) err = ioutil.WriteFile(filepath.Join(oldhome, "environments.yaml"), []byte("boo!"), 0600) c.Assert(err, jc.ErrorIsNil) // dump stderr to a file so we can examine it without any wacky re-running // of the executable (since we need to mock things out.) stderr, err := os.OpenFile(filepath.Join(oldhome, "stderr"), os.O_RDWR|os.O_CREATE, 0600) c.Assert(err, jc.ErrorIsNil) defer stderr.Close() // dump stdout to a file so it doesn't spam the test output. stdout, err := os.OpenFile(filepath.Join(oldhome, "stdout"), os.O_RDWR|os.O_CREATE, 0600) c.Assert(err, jc.ErrorIsNil) rc := runMain(stderr, stdout, []string{"juju", "version"}) c.Check(rc, gc.Equals, 0) _, err = stderr.Seek(0, 0) c.Assert(err, jc.ErrorIsNil) output, err := ioutil.ReadAll(stderr) c.Assert(err, jc.ErrorIsNil) c.Check(err, jc.ErrorIsNil) c.Check(string(output), gc.Equals, fmt.Sprintf(` Welcome to Juju %s. If you meant to use Juju 1.25.0 you can continue using it with the command juju-1 e.g. 'juju-1 switch'. See https://jujucharms.com/docs/stable/introducing-2 for more details. `[1:], jujuversion.Current)) }
func acquireEnvironmentLock(operation string) (*fslock.Lock, error) { // NOTE: any reading or writing from the directory should be done with a // fslock to make sure we have a consistent read or write. Also worth // noting, we should use a very short timeout. lock, err := fslock.NewLock(osenv.JujuXDGDataHome(), lockName, fslock.Defaults()) if err != nil { return nil, errors.Trace(err) } err = lock.LockWithTimeout(lockTimeout, operation) if err != nil { return nil, errors.Trace(err) } return lock, nil }
func (s *ToolsMetadataSuite) TestPatchLevels(c *gc.C) { currentVersion := jujuversion.Current currentVersion.Build = 0 versionStrings := []string{ currentVersion.String() + "-precise-amd64", currentVersion.String() + ".1-precise-amd64", } metadataDir := osenv.JujuXDGDataHome() // default metadata dir toolstesting.MakeTools(c, metadataDir, "released", versionStrings) ctx := coretesting.Context(c) code := cmd.Main(newToolsMetadataCommand(), ctx, []string{"--stream", "released"}) c.Assert(code, gc.Equals, 0) output := ctx.Stdout.(*bytes.Buffer).String() expectedOutput := fmt.Sprintf(` Finding tools in .* .*Fetching tools from dir "released" to generate hash: %s .*Fetching tools from dir "released" to generate hash: %s .*Writing tools/streams/v1/index2\.json .*Writing tools/streams/v1/index\.json .*Writing tools/streams/v1/com\.ubuntu\.juju-released-tools\.json `[1:], regexp.QuoteMeta(versionStrings[0]), regexp.QuoteMeta(versionStrings[1])) c.Assert(output, gc.Matches, expectedOutput) metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) c.Assert(metadata, gc.HasLen, 2) filename := fmt.Sprintf("juju-%s-precise-amd64.tgz", currentVersion) size, sha256 := toolstesting.SHA256sum(c, filepath.Join(metadataDir, "tools", "released", filename)) c.Assert(metadata[0], gc.DeepEquals, &tools.ToolsMetadata{ Release: "precise", Version: currentVersion.String(), Arch: "amd64", Size: size, Path: "released/" + filename, FileType: "tar.gz", SHA256: sha256, }) filename = fmt.Sprintf("juju-%s.1-precise-amd64.tgz", currentVersion) size, sha256 = toolstesting.SHA256sum(c, filepath.Join(metadataDir, "tools", "released", filename)) c.Assert(metadata[1], gc.DeepEquals, &tools.ToolsMetadata{ Release: "precise", Version: currentVersion.String() + ".1", Arch: "amd64", Size: size, Path: "released/" + filename, FileType: "tar.gz", SHA256: sha256, }) }
func (c *toolsMetadataCommand) Run(context *cmd.Context) error { loggo.RegisterWriter("toolsmetadata", cmd.NewCommandLogWriter("juju.environs.tools", context.Stdout, context.Stderr), loggo.INFO) defer loggo.RemoveWriter("toolsmetadata") if c.metadataDir == "" { c.metadataDir = osenv.JujuXDGDataHome() } else { c.metadataDir = context.AbsPath(c.metadataDir) } sourceStorage, err := filestorage.NewFileStorageReader(c.metadataDir) if err != nil { return err } // We now store the tools in a directory named after their stream, but the // legacy behaviour is to store all tools in a single "releases" directory. toolsDir := c.stream if c.stream == "" { fmt.Fprintf(context.Stdout, "No stream specified, defaulting to released tools in the releases directory.\n") c.stream = envtools.ReleasedStream toolsDir = envtools.LegacyReleaseDirectory } fmt.Fprintf(context.Stdout, "Finding tools in %s for stream %s.\n", c.metadataDir, c.stream) toolsList, err := envtools.ReadList(sourceStorage, toolsDir, -1, -1) if err == envtools.ErrNoTools { var source string source, err = envtools.ToolsURL(envtools.DefaultBaseURL) if err != nil { return err } sourceDataSource := simplestreams.NewURLDataSource("local source", source, utils.VerifySSLHostnames, simplestreams.CUSTOM_CLOUD_DATA, false) toolsList, err = envtools.FindToolsForCloud( []simplestreams.DataSource{sourceDataSource}, simplestreams.CloudSpec{}, c.stream, -1, -1, coretools.Filter{}) } if err != nil { return err } targetStorage, err := filestorage.NewFileStorageWriter(c.metadataDir) if err != nil { return err } writeMirrors := envtools.DoNotWriteMirrors if c.public { writeMirrors = envtools.WriteMirrors } return mergeAndWriteMetadata(targetStorage, toolsDir, c.stream, c.clean, toolsList, writeMirrors) }
func (s *ToolsMetadataSuite) TestGenerateLegacyRelease(c *gc.C) { metadataDir := osenv.JujuXDGDataHome() // default metadata dir toolstesting.MakeTools(c, metadataDir, "releases", versionStrings) ctx := coretesting.Context(c) code := cmd.Main(newToolsMetadataCommand(), ctx, nil) c.Assert(code, gc.Equals, 0) output := ctx.Stdout.(*bytes.Buffer).String() c.Assert(output, gc.Matches, expectedOutputDirectoryLegacyReleased) metadata := toolstesting.ParseMetadataFromDir(c, metadataDir, "released", false) c.Assert(metadata, gc.HasLen, len(versionStrings)) obtainedVersionStrings := make([]string, len(versionStrings)) for i, metadata := range metadata { s := fmt.Sprintf("%s-%s-%s", metadata.Version, metadata.Release, metadata.Arch) obtainedVersionStrings[i] = s } c.Assert(obtainedVersionStrings, gc.DeepEquals, versionStrings) }
func (c *PluginCommand) Run(ctx *cmd.Context) error { command := exec.Command(c.name, c.args...) command.Env = append(os.Environ(), []string{ osenv.JujuXDGDataHomeEnvKey + "=" + osenv.JujuXDGDataHome(), osenv.JujuModelEnvKey + "=" + c.ConnectionName()}..., ) // Now hook up stdin, stdout, stderr command.Stdin = ctx.Stdin command.Stdout = ctx.Stdout command.Stderr = ctx.Stderr // And run it! err := command.Run() if exitError, ok := err.(*exec.ExitError); ok && exitError != nil { status := exitError.ProcessState.Sys().(syscall.WaitStatus) if status.Exited() { return cmd.NewRcPassthroughError(status.ExitStatus()) } } return err }
func getCurrentControllerFilePath() string { return filepath.Join(osenv.JujuXDGDataHome(), CurrentControllerFilename) }
func (s *JujuXDGDataHomeSuite) TestStandardHome(c *gc.C) { testJujuXDGDataHome := c.MkDir() osenv.SetJujuXDGDataHome(testJujuXDGDataHome) c.Assert(osenv.JujuXDGDataHome(), gc.Equals, testJujuXDGDataHome) }
func (s *fakeHomeSuite) TestFakeHomeSetsConfigJujuXDGDataHome(c *gc.C) { s.PatchEnvironment(osenv.XDGDataHome, "") expected := gitjujutesting.JujuXDGDataHomePath() c.Assert(osenv.JujuXDGDataHome(), gc.Equals, expected) }
func (s *JujuConnSuite) setUpConn(c *gc.C) { if s.RootDir != "" { panic("JujuConnSuite.setUpConn without teardown") } s.RootDir = c.MkDir() s.oldHome = utils.Home() home := filepath.Join(s.RootDir, "/home/ubuntu") err := os.MkdirAll(home, 0777) c.Assert(err, jc.ErrorIsNil) utils.SetHome(home) err = os.MkdirAll(filepath.Join(home, ".local", "share"), 0777) c.Assert(err, jc.ErrorIsNil) s.oldJujuXDGDataHome = osenv.SetJujuXDGDataHome(filepath.Join(home, ".local", "share", "juju")) err = os.MkdirAll(osenv.JujuXDGDataHome(), 0777) c.Assert(err, jc.ErrorIsNil) err = os.MkdirAll(s.DataDir(), 0777) c.Assert(err, jc.ErrorIsNil) s.PatchEnvironment(osenv.JujuModelEnvKey, "") // TODO(rog) remove these files and add them only when // the tests specifically need them (in cmd/juju for example) s.writeSampleConfig(c, osenv.JujuXDGDataHomePath("environments.yaml")) err = ioutil.WriteFile(osenv.JujuXDGDataHomePath("dummymodel-cert.pem"), []byte(testing.CACert), 0666) c.Assert(err, jc.ErrorIsNil) err = ioutil.WriteFile(osenv.JujuXDGDataHomePath("dummymodel-private-key.pem"), []byte(testing.CAKey), 0600) c.Assert(err, jc.ErrorIsNil) store, err := configstore.Default() c.Assert(err, jc.ErrorIsNil) s.ConfigStore = store ctx := testing.Context(c) environ, err := environs.PrepareFromName("dummymodel", modelcmd.BootstrapContext(ctx), s.ConfigStore) c.Assert(err, jc.ErrorIsNil) // sanity check we've got the correct environment. c.Assert(environ.Config().Name(), gc.Equals, "dummymodel") s.PatchValue(&dummy.DataDir, s.DataDir()) s.LogDir = c.MkDir() s.PatchValue(&dummy.LogDir, s.LogDir) versions := PreferredDefaultVersions(environ.Config(), version.Binary{ Number: version.Current, Arch: "amd64", Series: "precise", }) current := version.Binary{ Number: version.Current, Arch: arch.HostArch(), Series: series.HostSeries(), } versions = append(versions, current) // Upload tools for both preferred and fake default series s.DefaultToolsStorageDir = c.MkDir() s.PatchValue(&tools.DefaultBaseURL, s.DefaultToolsStorageDir) stor, err := filestorage.NewFileStorageWriter(s.DefaultToolsStorageDir) c.Assert(err, jc.ErrorIsNil) // Upload tools to both release and devel streams since config will dictate that we // end up looking in both places. envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", versions...) envtesting.AssertUploadFakeToolsVersions(c, stor, "devel", "devel", versions...) s.DefaultToolsStorage = stor s.PatchValue(&simplestreams.SimplestreamsJujuPublicKey, sstesting.SignedMetadataPublicKey) err = bootstrap.Bootstrap(modelcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{}) c.Assert(err, jc.ErrorIsNil) s.BackingState = environ.(GetStater).GetStateInAPIServer() s.State, err = newState(environ, s.BackingState.MongoConnectionInfo()) c.Assert(err, jc.ErrorIsNil) s.APIState, err = juju.NewAPIState(s.AdminUserTag(c), environ, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) err = s.State.SetAPIHostPorts(s.APIState.APIHostPorts()) c.Assert(err, jc.ErrorIsNil) // Make sure the config store has the api endpoint address set info, err := s.ConfigStore.ReadInfo("dummymodel") c.Assert(err, jc.ErrorIsNil) endpoint := info.APIEndpoint() endpoint.Addresses = []string{s.APIState.APIHostPorts()[0][0].String()} info.SetAPIEndpoint(endpoint) err = info.Write() c.Assert(err, jc.ErrorIsNil) // Make sure the jenv file has the local host ports. c.Logf("jenv host ports: %#v", s.APIState.APIHostPorts()) s.Environ = environ // Insert expected values... servingInfo := state.StateServingInfo{ PrivateKey: testing.ServerKey, Cert: testing.ServerCert, CAPrivateKey: testing.CAKey, SharedSecret: "really, really secret", APIPort: 4321, StatePort: 1234, } s.State.SetStateServingInfo(servingInfo) }
func (s *JujuConnSuite) setUpConn(c *gc.C) { if s.RootDir != "" { c.Fatal("JujuConnSuite.setUpConn without teardown") } s.RootDir = c.MkDir() s.oldHome = utils.Home() home := filepath.Join(s.RootDir, "/home/ubuntu") err := os.MkdirAll(home, 0777) c.Assert(err, jc.ErrorIsNil) utils.SetHome(home) err = os.MkdirAll(filepath.Join(home, ".local", "share"), 0777) c.Assert(err, jc.ErrorIsNil) s.oldJujuXDGDataHome = osenv.SetJujuXDGDataHome(filepath.Join(home, ".local", "share", "juju")) err = os.MkdirAll(osenv.JujuXDGDataHome(), 0777) c.Assert(err, jc.ErrorIsNil) err = os.MkdirAll(s.DataDir(), 0777) c.Assert(err, jc.ErrorIsNil) s.PatchEnvironment(osenv.JujuModelEnvKey, "admin") cfg, err := config.New(config.UseDefaults, (map[string]interface{})(s.sampleConfig())) c.Assert(err, jc.ErrorIsNil) s.ControllerStore = jujuclient.NewFileClientStore() ctx := testing.Context(c) environ, err := environs.Prepare( modelcmd.BootstrapContext(ctx), s.ControllerStore, environs.PrepareParams{ BaseConfig: cfg.AllAttrs(), Credential: cloud.NewEmptyCredential(), ControllerName: ControllerName, CloudName: "dummy", }, ) c.Assert(err, jc.ErrorIsNil) // sanity check we've got the correct environment. c.Assert(environ.Config().Name(), gc.Equals, "admin") s.PatchValue(&dummy.DataDir, s.DataDir()) s.LogDir = c.MkDir() s.PatchValue(&dummy.LogDir, s.LogDir) versions := PreferredDefaultVersions(environ.Config(), version.Binary{ Number: jujuversion.Current, Arch: "amd64", Series: "precise", }) current := version.Binary{ Number: jujuversion.Current, Arch: arch.HostArch(), Series: series.HostSeries(), } versions = append(versions, current) // Upload tools for both preferred and fake default series s.DefaultToolsStorageDir = c.MkDir() s.PatchValue(&tools.DefaultBaseURL, s.DefaultToolsStorageDir) stor, err := filestorage.NewFileStorageWriter(s.DefaultToolsStorageDir) c.Assert(err, jc.ErrorIsNil) // Upload tools to both release and devel streams since config will dictate that we // end up looking in both places. envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", versions...) envtesting.AssertUploadFakeToolsVersions(c, stor, "devel", "devel", versions...) s.DefaultToolsStorage = stor s.PatchValue(&juju.JujuPublicKey, sstesting.SignedMetadataPublicKey) err = bootstrap.Bootstrap(modelcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{}) c.Assert(err, jc.ErrorIsNil) s.BackingState = environ.(GetStater).GetStateInAPIServer() s.State, err = newState(environ, s.BackingState.MongoConnectionInfo()) c.Assert(err, jc.ErrorIsNil) apiInfo, err := environs.APIInfo(environ) c.Assert(err, jc.ErrorIsNil) apiInfo.Tag = s.AdminUserTag(c) apiInfo.Password = environ.Config().AdminSecret() s.APIState, err = api.Open(apiInfo, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) err = s.State.SetAPIHostPorts(s.APIState.APIHostPorts()) c.Assert(err, jc.ErrorIsNil) // Make sure the controller store has the controller api endpoint address set controller, err := s.ControllerStore.ControllerByName(ControllerName) c.Assert(err, jc.ErrorIsNil) controller.APIEndpoints = []string{s.APIState.APIHostPorts()[0][0].String()} err = s.ControllerStore.UpdateController(ControllerName, *controller) c.Assert(err, jc.ErrorIsNil) err = modelcmd.WriteCurrentController(ControllerName) c.Assert(err, jc.ErrorIsNil) s.Environ = environ // Insert expected values... servingInfo := state.StateServingInfo{ PrivateKey: testing.ServerKey, Cert: testing.ServerCert, CAPrivateKey: testing.CAKey, SharedSecret: "really, really secret", APIPort: 4321, StatePort: 1234, } s.State.SetStateServingInfo(servingInfo) }
sourceCreated configSource = "created" sourceJenv configSource = "jenv" sourceCache configSource = "cache" sourceMem configSource = "mem" ) // A second should be way more than enough to write or read any files. But // some disks are very slow when under load, so lets give the disk a // reasonable time to get the lock. var lockTimeout = 5 * time.Second // Default returns disk-based environment config storage // rooted at JujuXDGDataHome. var Default = func() (Storage, error) { return NewDisk(osenv.JujuXDGDataHome()) } type diskStore struct { dir string } // EnvironInfoData is the serialisation structure for the original JENV file. type EnvironInfoData struct { User string Password string ModelUUID string `json:"environ-uuid,omitempty" yaml:"environ-uuid,omitempty"` ServerUUID string `json:"server-uuid,omitempty" yaml:"server-uuid,omitempty"` Controllers []string `json:"controllers" yaml:"controllers"` ServerHostnames []string `json:"server-hostnames,omitempty" yaml:"server-hostnames,omitempty"` CACert string `json:"ca-cert" yaml:"ca-cert"`