func (s *BundlesDirSuite) TestGet(c *gc.C) { basedir := c.MkDir() bunsdir := filepath.Join(basedir, "random", "bundles") d := charm.NewBundlesDir(bunsdir) // Check it doesn't get created until it's needed. _, err := os.Stat(bunsdir) c.Assert(err, jc.Satisfies, os.IsNotExist) // Add a charm to state that we can try to get. apiCharm, sch, bundata := s.AddCharm(c) // Try to get the charm when the content doesn't match. gitjujutesting.Server.Response(200, nil, []byte("roflcopter")) archiveURLs, err := apiCharm.ArchiveURLs() c.Assert(err, gc.IsNil) _, err = d.Read(apiCharm, nil) prefix := regexp.QuoteMeta(fmt.Sprintf(`failed to download charm "cs:quantal/dummy-1" from %q: `, archiveURLs)) c.Assert(err, gc.ErrorMatches, prefix+fmt.Sprintf(`expected sha256 %q, got ".*"`, sch.BundleSha256())) // Try to get a charm whose bundle doesn't exist. gitjujutesting.Server.Responses(2, 404, nil, nil) _, err = d.Read(apiCharm, nil) c.Assert(err, gc.ErrorMatches, prefix+`.* 404 Not Found`) // Get a charm whose bundle exists and whose content matches. gitjujutesting.Server.Response(404, nil, nil) gitjujutesting.Server.Response(200, nil, bundata) ch, err := d.Read(apiCharm, nil) c.Assert(err, jc.ErrorIsNil) assertCharm(c, ch, sch) // Get the same charm again, without preparing a response from the server. ch, err = d.Read(apiCharm, nil) c.Assert(err, jc.ErrorIsNil) assertCharm(c, ch, sch) // Abort a download. err = os.RemoveAll(bunsdir) c.Assert(err, jc.ErrorIsNil) abort := make(chan struct{}) done := make(chan bool) go func() { ch, err := d.Read(apiCharm, abort) c.Assert(ch, gc.IsNil) c.Assert(err, gc.ErrorMatches, prefix+"aborted") close(done) }() close(abort) gitjujutesting.Server.Response(500, nil, nil) select { case <-done: case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for abort") } }
func (s *BundlesDirSuite) TestGet(c *gc.C) { basedir := c.MkDir() bunsDir := filepath.Join(basedir, "random", "bundles") downloader := api.NewCharmDownloader(s.st.Client()) d := charm.NewBundlesDir(bunsDir, downloader) checkDownloadsEmpty := func() { files, err := ioutil.ReadDir(filepath.Join(bunsDir, "downloads")) c.Assert(err, jc.ErrorIsNil) c.Check(files, gc.HasLen, 0) } // Check it doesn't get created until it's needed. _, err := os.Stat(bunsDir) c.Assert(err, jc.Satisfies, os.IsNotExist) // Add a charm to state that we can try to get. apiCharm, sch := s.AddCharm(c) // Try to get the charm when the content doesn't match. _, err = d.Read(&fakeBundleInfo{apiCharm, nil, "..."}, nil) c.Check(err, gc.ErrorMatches, regexp.QuoteMeta(`failed to download charm "cs:quantal/dummy-1" from API server: `)+`expected sha256 "...", got ".*"`) checkDownloadsEmpty() // Try to get a charm whose bundle doesn't exist. otherURL := corecharm.MustParseURL("cs:quantal/spam-1") _, err = d.Read(&fakeBundleInfo{apiCharm, otherURL, ""}, nil) c.Check(err, gc.ErrorMatches, regexp.QuoteMeta(`failed to download charm "cs:quantal/spam-1" from API server: `)+`.* not found`) checkDownloadsEmpty() // Get a charm whose bundle exists and whose content matches. ch, err := d.Read(apiCharm, nil) c.Assert(err, jc.ErrorIsNil) assertCharm(c, ch, sch) checkDownloadsEmpty() // Get the same charm again, without preparing a response from the server. ch, err = d.Read(apiCharm, nil) c.Assert(err, jc.ErrorIsNil) assertCharm(c, ch, sch) checkDownloadsEmpty() // Check the abort chan is honoured. err = os.RemoveAll(bunsDir) c.Assert(err, jc.ErrorIsNil) abort := make(chan struct{}) close(abort) ch, err = d.Read(apiCharm, abort) c.Check(ch, gc.IsNil) c.Check(err, gc.ErrorMatches, regexp.QuoteMeta(`failed to download charm "cs:quantal/dummy-1" from API server: download aborted`)) checkDownloadsEmpty() }
func (s *BundlesDirSuite) TestGet(c *gc.C) { basedir := c.MkDir() bunsdir := filepath.Join(basedir, "random", "bundles") downloader := api.NewCharmDownloader(s.st.Client()) d := charm.NewBundlesDir(bunsdir, downloader) // Check it doesn't get created until it's needed. _, err := os.Stat(bunsdir) c.Assert(err, jc.Satisfies, os.IsNotExist) // Add a charm to state that we can try to get. apiCharm, sch := s.AddCharm(c) // Try to get the charm when the content doesn't match. _, err = d.Read(&fakeBundleInfo{apiCharm, nil, "..."}, nil) c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`failed to download charm "cs:quantal/dummy-1" from API server: `)+`expected sha256 "...", got ".*"`) // Try to get a charm whose bundle doesn't exist. otherURL := corecharm.MustParseURL("cs:quantal/spam-1") _, err = d.Read(&fakeBundleInfo{apiCharm, otherURL, ""}, nil) c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`failed to download charm "cs:quantal/spam-1" from API server: `)+`.* not found`) // Get a charm whose bundle exists and whose content matches. ch, err := d.Read(apiCharm, nil) c.Assert(err, jc.ErrorIsNil) assertCharm(c, ch, sch) // Get the same charm again, without preparing a response from the server. ch, err = d.Read(apiCharm, nil) c.Assert(err, jc.ErrorIsNil) assertCharm(c, ch, sch) // Abort a download. err = os.RemoveAll(bunsdir) c.Assert(err, jc.ErrorIsNil) abort := make(chan struct{}) done := make(chan bool) go func() { ch, err := d.Read(apiCharm, abort) c.Assert(ch, gc.IsNil) c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`failed to download charm "cs:quantal/dummy-1" from API server: aborted`)) close(done) }() close(abort) gitjujutesting.Server.Response(500, nil, nil) select { case <-done: case <-time.After(coretesting.LongWait): c.Fatalf("timed out waiting for abort") } }
func (u *Uniter) init(unitTag names.UnitTag) (err error) { u.unit, err = u.st.Unit(unitTag) 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 } if err := jujuc.EnsureSymlinks(u.paths.ToolsDir); err != nil { return err } if err := os.MkdirAll(u.paths.State.RelationsDir, 0755); err != nil { return errors.Trace(err) } relations, err := relation.NewRelations( u.st, unitTag, u.paths.State.CharmDir, u.paths.State.RelationsDir, u.catacomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create relations") } u.relations = relations storageAttachments, err := storage.NewAttachments( u.st, unitTag, u.paths.State.StorageDir, u.catacomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create storage hook source") } u.storage = storageAttachments u.commands = runcommands.NewCommands() u.commandChannel = make(chan string) deployer, err := charm.NewDeployer( u.paths.State.CharmDir, u.paths.State.DeployerDir, charm.NewBundlesDir(u.paths.State.BundlesDir, u.downloader), ) if err != nil { return errors.Annotatef(err, "cannot create deployer") } u.deployer = &deployerProxy{deployer} contextFactory, err := context.NewContextFactory( u.st, unitTag, u.leadershipTracker, u.relations.GetInfo, u.storage, u.paths, u.clock, ) if err != nil { return err } runnerFactory, err := runner.NewFactory( u.st, u.paths, contextFactory, ) if err != nil { return errors.Trace(err) } u.operationFactory = operation.NewFactory(operation.FactoryParams{ Deployer: u.deployer, RunnerFactory: runnerFactory, Callbacks: &operationCallbacks{u}, Abort: u.catacomb.Dying(), MetricSpoolDir: u.paths.GetMetricsSpoolDir(), }) operationExecutor, err := u.newOperationExecutor(u.paths.State.OperationsFile, u.getServiceCharmURL, u.acquireExecutionLock) if err != nil { return errors.Trace(err) } u.operationExecutor = operationExecutor logger.Debugf("starting juju-run listener on unix:%s", u.paths.Runtime.JujuRunSocket) commandRunner, err := NewChannelCommandRunner(ChannelCommandRunnerConfig{ Abort: u.catacomb.Dying(), Commands: u.commands, CommandChannel: u.commandChannel, }) if err != nil { return errors.Annotate(err, "creating command runner") } u.runListener, err = NewRunListener(RunListenerConfig{ SocketPath: u.paths.Runtime.JujuRunSocket, CommandRunner: commandRunner, }) if err != nil { return errors.Trace(err) } rlw := newRunListenerWrapper(u.runListener) if err := u.catacomb.Add(rlw); err != nil { return errors.Trace(err) } // The socket needs to have permissions 777 in order for other users to use it. if jujuos.HostOS() != jujuos.Windows { return os.Chmod(u.paths.Runtime.JujuRunSocket, 0777) } return nil }
func (u *Uniter) init(unitTag names.UnitTag) (err error) { u.unit, err = u.st.Unit(unitTag) 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 } if err := jujuc.EnsureSymlinks(u.paths.ToolsDir); err != nil { return err } if err := os.MkdirAll(u.paths.State.RelationsDir, 0755); err != nil { return errors.Trace(err) } relations, err := newRelations(u.st, unitTag, u.paths, u.tomb.Dying()) if err != nil { return errors.Annotatef(err, "cannot create relations") } u.relations = relations storageAttachments, err := storage.NewAttachments( u.st, unitTag, u.paths.State.StorageDir, u.tomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create storage hook source") } u.storage = storageAttachments u.addCleanup(storageAttachments.Stop) deployer, err := charm.NewDeployer( u.paths.State.CharmDir, u.paths.State.DeployerDir, charm.NewBundlesDir(u.paths.State.BundlesDir), ) if err != nil { return errors.Annotatef(err, "cannot create deployer") } u.deployer = &deployerProxy{deployer} contextFactory, err := runner.NewContextFactory( u.st, unitTag, u.leadershipTracker, u.relations.GetInfo, u.storage, u.paths, ) if err != nil { return err } runnerFactory, err := runner.NewFactory( u.st, u.paths, contextFactory, ) if err != nil { return err } u.operationFactory = operation.NewFactory(operation.FactoryParams{ Deployer: u.deployer, RunnerFactory: runnerFactory, Callbacks: &operationCallbacks{u}, StorageUpdater: u.storage, Abort: u.tomb.Dying(), MetricSender: u.unit, MetricSpoolDir: u.paths.GetMetricsSpoolDir(), }) operationExecutor, err := u.newOperationExecutor(u.paths.State.OperationsFile, u.getServiceCharmURL, u.acquireExecutionLock) if err != nil { return err } u.operationExecutor = operationExecutor logger.Debugf("starting juju-run listener on unix:%s", u.paths.Runtime.JujuRunSocket) u.runListener, err = NewRunListener(u, u.paths.Runtime.JujuRunSocket) if err != nil { return err } u.addCleanup(func() error { // TODO(fwereade): RunListener returns no error on Close. This seems wrong. u.runListener.Close() return nil }) // The socket needs to have permissions 777 in order for other users to use it. if version.Current.OS != version.Windows { return os.Chmod(u.paths.Runtime.JujuRunSocket, 0777) } return nil }
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) }
func (u *Uniter) init(unitTag names.UnitTag) (err error) { u.unit, err = u.st.Unit(unitTag) 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 initialising for the first time after deploying, update the status. currentStatus, err := u.unit.UnitStatus() if err != nil { return err } // TODO(fwereade/wallyworld): we should have an explicit place in the model // to tell us when we've hit this point, instead of piggybacking on top of // status and/or status history. // If the previous status was waiting for machine, we transition to the next step. if currentStatus.Status == string(status.Waiting) && (currentStatus.Info == status.MessageWaitForMachine || currentStatus.Info == status.MessageInstallingAgent) { if err := u.unit.SetUnitStatus(status.Waiting, status.MessageInitializingAgent, nil); err != nil { return errors.Trace(err) } } if err := jujuc.EnsureSymlinks(u.paths.ToolsDir); err != nil { return err } if err := os.MkdirAll(u.paths.State.RelationsDir, 0755); err != nil { return errors.Trace(err) } relations, err := relation.NewRelations( u.st, unitTag, u.paths.State.CharmDir, u.paths.State.RelationsDir, u.catacomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create relations") } u.relations = relations storageAttachments, err := storage.NewAttachments( u.st, unitTag, u.paths.State.StorageDir, u.catacomb.Dying(), ) if err != nil { return errors.Annotatef(err, "cannot create storage hook source") } u.storage = storageAttachments u.commands = runcommands.NewCommands() u.commandChannel = make(chan string) deployer, err := charm.NewDeployer( u.paths.State.CharmDir, u.paths.State.DeployerDir, charm.NewBundlesDir(u.paths.State.BundlesDir, u.downloader), ) if err != nil { return errors.Annotatef(err, "cannot create deployer") } contextFactory, err := context.NewContextFactory( u.st, unitTag, u.leadershipTracker, u.relations.GetInfo, u.storage, u.paths, u.clock, ) if err != nil { return err } runnerFactory, err := runner.NewFactory( u.st, u.paths, contextFactory, ) if err != nil { return errors.Trace(err) } u.operationFactory = operation.NewFactory(operation.FactoryParams{ Deployer: deployer, RunnerFactory: runnerFactory, Callbacks: &operationCallbacks{u}, Abort: u.catacomb.Dying(), MetricSpoolDir: u.paths.GetMetricsSpoolDir(), }) operationExecutor, err := u.newOperationExecutor(u.paths.State.OperationsFile, u.getServiceCharmURL, u.acquireExecutionLock) if err != nil { return errors.Trace(err) } u.operationExecutor = operationExecutor logger.Debugf("starting juju-run listener on unix:%s", u.paths.Runtime.JujuRunSocket) commandRunner, err := NewChannelCommandRunner(ChannelCommandRunnerConfig{ Abort: u.catacomb.Dying(), Commands: u.commands, CommandChannel: u.commandChannel, }) if err != nil { return errors.Annotate(err, "creating command runner") } u.runListener, err = NewRunListener(RunListenerConfig{ SocketPath: u.paths.Runtime.JujuRunSocket, CommandRunner: commandRunner, }) if err != nil { return errors.Trace(err) } rlw := newRunListenerWrapper(u.runListener) if err := u.catacomb.Add(rlw); err != nil { return errors.Trace(err) } // The socket needs to have permissions 777 in order for other users to use it. if jujuos.HostOS() != jujuos.Windows { return os.Chmod(u.paths.Runtime.JujuRunSocket, 0777) } return nil }