func (s *RunHookSuite) TestRunHook(c *C) { uuid, err := utils.NewUUID() c.Assert(err, IsNil) for i, t := range runHookTests { c.Logf("test %d: %s; perm %v", i, t.summary, t.spec.perm) ctx := s.GetHookContext(c, uuid.String(), t.relid, t.remote) var charmDir, outPath string if t.spec.perm == 0 { charmDir = c.MkDir() } else { spec := t.spec spec.name = "something-happened" c.Logf("makeCharm %#v", spec) charmDir, outPath = makeCharm(c, spec) } toolsDir := c.MkDir() t0 := time.Now() err := ctx.RunHook("something-happened", charmDir, toolsDir, "/path/to/socket") if t.err == "" { c.Assert(err, IsNil) } else { c.Assert(err, ErrorMatches, t.err) } if t.env != nil { env := map[string]string{"PATH": toolsDir + ":" + os.Getenv("PATH")} for k, v := range t.env { env[k] = v } AssertEnv(c, outPath, charmDir, env, uuid.String()) } if t.spec.background != "" && time.Now().Sub(t0) > 5*time.Second { c.Errorf("background process holding up hook execution") } } }
func (uuidSuite) TestUUID(c *C) { uuid, err := utils.NewUUID() c.Assert(err, IsNil) uuidCopy := uuid.Copy() uuidRaw := uuid.Raw() uuidStr := uuid.String() c.Assert(uuidRaw, HasLen, 16) c.Assert(uuidStr, checkers.Satisfies, utils.IsValidUUIDString) uuid[0] = 0x00 uuidCopy[0] = 0xFF c.Assert(uuid, Not(DeepEquals), uuidCopy) uuidRaw[0] = 0xFF c.Assert(uuid, Not(DeepEquals), uuidRaw) nextUUID, err := utils.NewUUID() c.Assert(err, IsNil) c.Assert(uuid, Not(DeepEquals), nextUUID) }
func (p *Provisioner) startMachine(m *state.Machine) error { // TODO(dfc) the state.Info passed to environ.StartInstance remains contentious // however as the PA only knows one state.Info, and that info is used by MAs and // UAs to locate the state for this environment, it is logical to use the same // state.Info as the PA. stateInfo, apiInfo, err := p.setupAuthentication(m) if err != nil { return err } cons, err := m.Constraints() if err != nil { return err } // Generate a unique nonce for the new instance. uuid, err := utils.NewUUID() if err != nil { return err } // Generated nonce has the format: "machine-#:UUID". The first // part is a badge, specifying the tag of the machine the provisioner // is running on, while the second part is a random UUID. nonce := fmt.Sprintf("%s:%s", state.MachineTag(p.machineId), uuid.String()) inst, err := p.environ.StartInstance(m.Id(), nonce, m.Series(), cons, stateInfo, apiInfo) if err != nil { // Set the state to error, so the machine will be skipped next // time until the error is resolved, but don't return an // error; just keep going with the other machines. log.Errorf("worker/provisioner: cannot start instance for machine %q: %v", m, err) if err1 := m.SetStatus(params.StatusError, err.Error()); err1 != nil { // Something is wrong with this machine, better report it back. log.Errorf("worker/provisioner: cannot set error status for machine %q: %v", m, err1) return err1 } return nil } if err := m.SetProvisioned(inst.Id(), nonce); err != nil { // The machine is started, but we can't record the mapping in // state. It'll keep running while we fail out and restart, // but will then be detected by findUnknownInstances and // killed again. // // TODO(dimitern) Stop the instance right away here. // // Multiple instantiations of a given machine (with the same // machine ID) cannot coexist, because findUnknownInstances is // called before startMachines. However, if the first machine // had started to do work before being replaced, we may // encounter surprising problems. return err } // populate the local cache p.instances[m.Id()] = inst p.machines[inst.Id()] = m.Id() log.Noticef("worker/provisioner: started machine %s as instance %s", m, inst.Id()) return nil }
func (task *provisionerTask) startMachine(machine *state.Machine) error { stateInfo, apiInfo, err := task.auth.SetupAuthentication(machine) if err != nil { logger.Errorf("failed to setup authentication: %v", err) return err } cons, err := machine.Constraints() if err != nil { return err } // Generate a unique nonce for the new instance. uuid, err := utils.NewUUID() if err != nil { return err } // Generated nonce has the format: "machine-#:UUID". The first // part is a badge, specifying the tag of the machine the provisioner // is running on, while the second part is a random UUID. nonce := fmt.Sprintf("%s:%s", names.MachineTag(task.machineId), uuid.String()) inst, metadata, err := task.broker.StartInstance(machine.Id(), nonce, machine.Series(), cons, stateInfo, apiInfo) if err != nil { // Set the state to error, so the machine will be skipped next // time until the error is resolved, but don't return an // error; just keep going with the other machines. logger.Errorf("cannot start instance for machine %q: %v", machine, err) if err1 := machine.SetStatus(params.StatusError, err.Error()); err1 != nil { // Something is wrong with this machine, better report it back. logger.Errorf("cannot set error status for machine %q: %v", machine, err1) return err1 } return nil } if err := machine.SetProvisioned(inst.Id(), nonce, metadata); err != nil { logger.Errorf("cannot register instance for machine %v: %v", machine, err) // The machine is started, but we can't record the mapping in // state. It'll keep running while we fail out and restart, // but will then be detected by findUnknownInstances and // killed again. // // TODO(dimitern) Stop the instance right away here. // // Multiple instantiations of a given machine (with the same // machine ID) cannot coexist, because findUnknownInstances is // called before startMachines. However, if the first machine // had started to do work before being replaced, we may // encounter surprising problems. return err } logger.Infof("started machine %s as instance %s with hardware %q", machine, inst.Id(), metadata) return nil }
// NewLock returns a new lock with the given name within the given lock // directory, without acquiring it. The lock name must match the regular // expression defined by NameRegexp. func NewLock(lockDir, name string) (*Lock, error) { if !validName.MatchString(name) { return nil, fmt.Errorf("Invalid lock name %q. Names must match %q", name, NameRegexp) } nonce, err := utils.NewUUID() if err != nil { return nil, err } lock := &Lock{ name: name, parent: lockDir, nonce: nonce[:], } // Ensure the parent exists. if err := os.MkdirAll(lock.parent, 0755); err != nil { return nil, err } return lock, nil }
// Initialize sets up an initial empty state and returns it. // This needs to be performed only once for a given environment. // It returns unauthorizedError if access is unauthorized. func Initialize(info *Info, cfg *config.Config, opts DialOpts) (rst *State, err error) { st, err := Open(info, opts) if err != nil { return nil, err } defer func() { if err != nil { st.Close() } }() // A valid environment is used as a signal that the // state has already been initalized. If this is the case // do nothing. if _, err := st.Environment(); err == nil { return st, nil } else if !errors.IsNotFoundError(err) { return nil, err } log.Infof("state: initializing environment") if err := checkEnvironConfig(cfg); err != nil { return nil, err } uuid, err := utils.NewUUID() if err != nil { return nil, fmt.Errorf("environment UUID cannot be created: %v", err) } ops := []txn.Op{ createConstraintsOp(st, environGlobalKey, constraints.Value{}), createSettingsOp(st, environGlobalKey, cfg.AllAttrs()), createEnvironmentOp(st, cfg.Name(), uuid.String()), } if err := st.runTransaction(ops); err == txn.ErrAborted { // The config was created in the meantime. return st, nil } else if err != nil { return nil, err } return st, nil }
func (s *InterfaceSuite) GetContext(c *C, relId int, remoteName string) jujuc.Context { uuid, err := utils.NewUUID() c.Assert(err, IsNil) return s.HookContextSuite.GetHookContext(c, uuid.String(), relId, remoteName) }
func (s *RunHookSuite) TestRunHookRelationFlushing(c *C) { // Create a charm with a breaking hook. uuid, err := utils.NewUUID() c.Assert(err, IsNil) ctx := s.GetHookContext(c, uuid.String(), -1, "") charmDir, _ := makeCharm(c, hookSpec{ name: "something-happened", perm: 0700, code: 123, }) // Mess with multiple relation settings. node0, err := s.relctxs[0].Settings() node0.Set("foo", 1) node1, err := s.relctxs[1].Settings() node1.Set("bar", 2) // Run the failing hook. err = ctx.RunHook("something-happened", charmDir, c.MkDir(), "/path/to/socket") c.Assert(err, ErrorMatches, "exit status 123") // Check that the changes to the local settings nodes have been discarded. node0, err = s.relctxs[0].Settings() c.Assert(err, IsNil) c.Assert(node0.Map(), DeepEquals, map[string]interface{}{"relation-name": "db0"}) node1, err = s.relctxs[1].Settings() c.Assert(err, IsNil) c.Assert(node1.Map(), DeepEquals, map[string]interface{}{"relation-name": "db1"}) // Check that the changes have been written to state. settings0, err := s.relunits[0].ReadSettings("u/0") c.Assert(err, IsNil) c.Assert(settings0, DeepEquals, node0.Map()) settings1, err := s.relunits[1].ReadSettings("u/0") c.Assert(err, IsNil) c.Assert(settings1, DeepEquals, node1.Map()) // Create a charm with a working hook, and mess with settings again. charmDir, _ = makeCharm(c, hookSpec{ name: "something-happened", perm: 0700, }) node0.Set("baz", 3) node1.Set("qux", 4) // Run the hook. err = ctx.RunHook("something-happened", charmDir, c.MkDir(), "/path/to/socket") c.Assert(err, IsNil) // Check that the changes to the local settings nodes are still there. node0, err = s.relctxs[0].Settings() c.Assert(err, IsNil) c.Assert(node0.Map(), DeepEquals, map[string]interface{}{ "relation-name": "db0", "baz": 3, }) node1, err = s.relctxs[1].Settings() c.Assert(err, IsNil) c.Assert(node1.Map(), DeepEquals, map[string]interface{}{ "relation-name": "db1", "qux": 4, }) // Check that the changes have been written to state. settings0, err = s.relunits[0].ReadSettings("u/0") c.Assert(err, IsNil) c.Assert(settings0, DeepEquals, node0.Map()) settings1, err = s.relunits[1].ReadSettings("u/0") c.Assert(err, IsNil) c.Assert(settings1, DeepEquals, node1.Map()) }