// addRelation causes the unit agent to join the supplied relation, and to // store persistent state in the supplied dir. func (u *Uniter) addRelation(rel *state.Relation, dir *relation.StateDir) error { log.Infof("worker/uniter: joining relation %q", rel) ru, err := rel.Unit(u.unit) if err != nil { return err } r := NewRelationer(ru, dir, u.relationHooks) w := u.unit.Watch() defer watcher.Stop(w, &u.tomb) for { select { case <-u.tomb.Dying(): return tomb.ErrDying case _, ok := <-w.Changes(): if !ok { return watcher.MustErr(w) } if err := r.Join(); err == state.ErrCannotEnterScopeYet { log.Infof("worker/uniter: cannot enter scope for relation %q; waiting for subordinate to be removed", rel) continue } else if err != nil { return err } log.Infof("worker/uniter: joined relation %q", rel) u.relationers[rel.Id()] = r return nil } } panic("unreachable") }
func (c *AddMachineCommand) Run(_ *cmd.Context) error { conn, err := juju.NewConnFromName(c.EnvName) if err != nil { return err } defer conn.Close() series := c.Series if series == "" { conf, err := conn.State.EnvironConfig() if err != nil { return err } series = conf.DefaultSeries() } params := state.AddMachineParams{ ParentId: c.MachineId, ContainerType: c.ContainerType, Series: series, Constraints: c.Constraints, Jobs: []state.MachineJob{state.JobHostUnits}, } m, err := conn.State.AddMachineWithConstraints(¶ms) if err == nil { if c.ContainerType == "" { log.Infof("created machine %v", m) } else { log.Infof("created %q container on machine %v", c.ContainerType, m) } } return err }
// ModeInit is the initial Uniter mode. func ModeInit(u *Uniter) (next Mode, err error) { defer modeContext("ModeInit", &err)() log.Infof("worker/uniter: updating unit addresses") cfg, err := u.st.EnvironConfig() if err != nil { return nil, err } provider, err := environs.Provider(cfg.Type()) if err != nil { return nil, err } if private, err := provider.PrivateAddress(); err != nil { return nil, err } else if err = u.unit.SetPrivateAddress(private); err != nil { return nil, err } if public, err := provider.PublicAddress(); err != nil { return nil, err } else if err = u.unit.SetPublicAddress(public); err != nil { return nil, err } log.Infof("reconciling relation state") if err := u.restoreRelations(); err != nil { return nil, err } return ModeContinue, nil }
// upgrade pulls from current into target. If target has local changes, but // no conflicts, it will be snapshotted before any changes are made. func (d *Deployer) upgrade(target *GitDir) error { log.Infof("worker/uniter/charm: preparing charm upgrade") url, err := ReadCharmURL(d.current) if err != nil { return err } if err := target.Init(); err != nil { return err } if dirty, err := target.Dirty(); err != nil { return err } else if dirty { if conflicted, err := target.Conflicted(); err != nil { return err } else if !conflicted { log.Infof("worker/uniter/charm: snapshotting dirty charm before upgrade") if err = target.Snapshotf("Pre-upgrade snapshot."); err != nil { return err } } } log.Infof("worker/uniter/charm: deploying charm") if err := target.Pull(d.current); err != nil { return err } return target.Snapshotf("Upgraded charm to %q.", url) }
// flushGlobalPorts opens and closes global ports in the environment. // It keeps a reference count for ports so that only 0-to-1 and 1-to-0 events // modify the environment. func (fw *Firewaller) flushGlobalPorts(rawOpen, rawClose []instance.Port) error { // Filter which ports are really to open or close. var toOpen, toClose []instance.Port for _, port := range rawOpen { if fw.globalPortRef[port] == 0 { toOpen = append(toOpen, port) } fw.globalPortRef[port]++ } for _, port := range rawClose { fw.globalPortRef[port]-- if fw.globalPortRef[port] == 0 { toClose = append(toClose, port) delete(fw.globalPortRef, port) } } // Open and close the ports. if len(toOpen) > 0 { if err := fw.environ.OpenPorts(toOpen); err != nil { // TODO(mue) Add local retry logic. return err } state.SortPorts(toOpen) log.Infof("worker/firewaller: opened ports %v in environment", toOpen) } if len(toClose) > 0 { if err := fw.environ.ClosePorts(toClose); err != nil { // TODO(mue) Add local retry logic. return err } state.SortPorts(toClose) log.Infof("worker/firewaller: closed ports %v in environment", toClose) } return nil }
func (conn *Conn) addCharm(curl *charm.URL, ch charm.Charm) (*state.Charm, error) { var f *os.File name := charm.Quote(curl.String()) switch ch := ch.(type) { case *charm.Dir: var err error if f, err = ioutil.TempFile("", name); err != nil { return nil, err } defer os.Remove(f.Name()) defer f.Close() err = ch.BundleTo(f) if err != nil { return nil, fmt.Errorf("cannot bundle charm: %v", err) } if _, err := f.Seek(0, 0); err != nil { return nil, err } case *charm.Bundle: var err error if f, err = os.Open(ch.Path); err != nil { return nil, fmt.Errorf("cannot read charm bundle: %v", err) } defer f.Close() default: return nil, fmt.Errorf("unknown charm type %T", ch) } h := sha256.New() size, err := io.Copy(h, f) if err != nil { return nil, err } digest := hex.EncodeToString(h.Sum(nil)) if _, err := f.Seek(0, 0); err != nil { return nil, err } storage := conn.Environ.Storage() log.Infof("writing charm to storage [%d bytes]", size) if err := storage.Put(name, f, size); err != nil { return nil, fmt.Errorf("cannot put charm: %v", err) } ustr, err := storage.URL(name) if err != nil { return nil, fmt.Errorf("cannot get storage URL for charm: %v", err) } u, err := url.Parse(ustr) if err != nil { return nil, fmt.Errorf("cannot parse storage URL: %v", err) } log.Infof("adding charm to state") sch, err := conn.State.AddCharm(ch, curl, u, digest) if err != nil { return nil, fmt.Errorf("cannot add charm: %v", err) } return sch, nil }
// FindAvailableTools returns a tools.List containing all tools with a given // major version number available in the environment. // If *any* tools are present in private storage, *only* tools from private // storage are available. // If *no* tools are present in private storage, *only* tools from public // storage are available. // If no *available* tools have the supplied major version number, the function // returns a *NotFoundError. func FindAvailableTools(environ Environ, majorVersion int) (list tools.List, err error) { log.Infof("environs: reading tools with major version %d", majorVersion) defer convertToolsError(&err) list, err = tools.ReadList(environ.Storage(), majorVersion) if err == tools.ErrNoTools { log.Infof("environs: falling back to public bucket") list, err = tools.ReadList(environ.PublicStorage(), majorVersion) } return list, err }
// Run changes the version proposed for the juju tools. func (c *UpgradeJujuCommand) Run(_ *cmd.Context) (err error) { conn, err := juju.NewConnFromName(c.EnvName) if err != nil { return err } defer conn.Close() defer func() { if err == errUpToDate { log.Noticef(err.Error()) err = nil } }() // Determine the version to upgrade to, uploading tools if necessary. env := conn.Environ cfg, err := conn.State.EnvironConfig() if err != nil { return err } v, err := c.initVersions(cfg, env) if err != nil { return err } if c.UploadTools { series := getUploadSeries(cfg, c.Series) if err := v.uploadTools(env.Storage(), series); err != nil { return err } } if err := v.validate(); err != nil { return err } log.Infof("upgrade version chosen: %s", v.chosen) // TODO(fwereade): this list may be incomplete, pending tools.Upload change. log.Infof("available tools: %s", v.tools) // Write updated config back to state if necessary. Note that this is // crackful and racy, because we have no idea what incompatible agent- // version might be set by another administrator in the meantime. If // this happens, tough: I'm not going to pretend to do it right when // I'm not. // TODO(fwereade): Do this right. Warning: scope unclear. cfg, err = cfg.Apply(map[string]interface{}{ "agent-version": v.chosen.String(), }) if err != nil { return err } if err := conn.State.SetEnvironConfig(cfg); err != nil { return err } log.Noticef("started upgrade to %s", v.chosen) return nil }
func Open(info *Info, opts DialOpts) (*State, error) { // TODO Select a random address from info.Addrs // and only fail when we've tried all the addresses. // TODO what does "origin" really mean, and is localhost always ok? cfg, err := websocket.NewConfig("wss://"+info.Addrs[0]+"/", "http://localhost/") if err != nil { return nil, err } pool := x509.NewCertPool() xcert, err := cert.ParseCert(info.CACert) if err != nil { return nil, err } pool.AddCert(xcert) cfg.TlsConfig = &tls.Config{ RootCAs: pool, ServerName: "anything", } var conn *websocket.Conn openAttempt := utils.AttemptStrategy{ Total: opts.Timeout, Delay: opts.RetryDelay, } for a := openAttempt.Start(); a.Next(); { log.Infof("state/api: dialing %q", cfg.Location) conn, err = websocket.DialConfig(cfg) if err == nil { break } log.Errorf("state/api: %v", err) } if err != nil { return nil, err } log.Infof("state/api: connection established") client := rpc.NewConn(jsoncodec.NewWebsocket(conn)) client.Start() st := &State{ client: client, conn: conn, } if info.Tag != "" || info.Password != "" { if err := st.Login(info.Tag, info.Password, info.Nonce); err != nil { conn.Close() return nil, err } } st.broken = make(chan struct{}) go st.heartbeatMonitor() return st, nil }
// downloadToolsRaw downloads the supplied tools and returns the raw bytes. func downloadToolsRaw(c *C, t *state.Tools) []byte { log.Infof("dtr1") resp, err := http.Get(t.URL) c.Assert(err, IsNil) defer resp.Body.Close() log.Infof("dtr5") c.Assert(resp.StatusCode, Equals, http.StatusOK) var buf bytes.Buffer _, err = io.Copy(&buf, resp.Body) c.Assert(err, IsNil) log.Infof("dtr9") return buf.Bytes() }
// reconcileInstances compares the initially started watcher for machines, // units and services with the opened and closed ports of the instances and // opens and closes the appropriate ports for each instance. func (fw *Firewaller) reconcileInstances() error { for _, machined := range fw.machineds { m, err := machined.machine() if errors.IsNotFoundError(err) { if err := fw.forgetMachine(machined); err != nil { return err } continue } else if err != nil { return err } instanceId, err := m.InstanceId() if err != nil { return err } instances, err := fw.environ.Instances([]instance.Id{instanceId}) if err == environs.ErrNoInstances { return nil } else if err != nil { return err } initialPorts, err := instances[0].Ports(machined.id) if err != nil { return err } // Check which ports to open or to close. toOpen := Diff(machined.ports, initialPorts) toClose := Diff(initialPorts, machined.ports) if len(toOpen) > 0 { log.Infof("worker/firewaller: opening instance ports %v for machine %s", toOpen, machined.id) if err := instances[0].OpenPorts(machined.id, toOpen); err != nil { // TODO(mue) Add local retry logic. return err } state.SortPorts(toOpen) } if len(toClose) > 0 { log.Infof("worker/firewaller: closing instance ports %v for machine %s", toClose, machined.id) if err := instances[0].ClosePorts(machined.id, toClose); err != nil { // TODO(mue) Add local retry logic. return err } state.SortPorts(toClose) } } return nil }
// Main runs the Command specified by req, and fills in resp. A single command // is run at a time. func (j *Jujuc) Main(req Request, resp *Response) error { if req.CommandName == "" { return badReqErrorf("command not specified") } if !filepath.IsAbs(req.Dir) { return badReqErrorf("Dir is not absolute") } c, err := j.getCmd(req.ContextId, req.CommandName) if err != nil { return badReqErrorf("%s", err) } var stdin, stdout, stderr bytes.Buffer ctx := &cmd.Context{ Dir: req.Dir, Stdin: &stdin, Stdout: &stdout, Stderr: &stderr, } j.mu.Lock() defer j.mu.Unlock() log.Infof("worker/uniter/jujuc: running hook tool %q %q", req.CommandName, req.Args) log.Debugf("worker/uniter/jujuc: hook context id %q; dir %q", req.ContextId, req.Dir) resp.Code = cmd.Main(c, ctx, req.Args) resp.Stdout = stdout.Bytes() resp.Stderr = stderr.Bytes() return nil }
// realTimeSlot disables the hardcoding introduced by fakeTimeSlot. func realTimeSlot() { fakeMutex.Lock() fakeNow = time.Time{} fakeOffset = 0 fakeMutex.Unlock() log.Infof("state/presence: Not faking presence time. Real time slot in use.") }
func (e *environ) Destroy(ensureInsts []instance.Instance) error { log.Infof("environs/openstack: destroying environment %q", e.name) insts, err := e.AllInstances() if err != nil { return fmt.Errorf("cannot get instances: %v", err) } found := make(map[instance.Id]bool) var ids []instance.Id for _, inst := range insts { ids = append(ids, inst.Id()) found[inst.Id()] = true } // Add any instances we've been told about but haven't yet shown // up in the instance list. for _, inst := range ensureInsts { id := instance.Id(inst.(*openstackInstance).Id()) if !found[id] { ids = append(ids, id) found[id] = true } } err = e.terminateInstances(ids) if err != nil { return err } return e.Storage().RemoveAll() }
// Close closes the connection and its underlying codec; it returns when // all requests have been terminated. // // If the connection is serving requests, and the root value implements // the Killer interface, its Kill method will be called. The codec will // then be closed only when all its outstanding server calls have // completed. func (conn *Conn) Close() error { conn.mutex.Lock() if conn.closing { conn.mutex.Unlock() return errors.New("already closed") } conn.closing = true // Kill server requests if appropriate. Client requests will be // terminated when the input loop finishes. if conn.rootValue.IsValid() { if killer, ok := conn.rootValue.Interface().(Killer); ok { killer.Kill() } } conn.mutex.Unlock() // Wait for any outstanding server requests to complete // and write their replies before closing the codec. conn.srvPending.Wait() // Closing the codec should cause the input loop to terminate. if err := conn.codec.Close(); err != nil { log.Infof("rpc: error closing codec: %v", err) } <-conn.dead return conn.inputLoopError }
// Run executes the subcommand that was selected in Init. func (c *SuperCommand) Run(ctx *Context) error { if c.showDescription { if c.Purpose != "" { fmt.Fprintf(ctx.Stdout, "%s\n", c.Purpose) } else { fmt.Fprintf(ctx.Stdout, "%s: no description available\n", c.Info().Name) } return nil } if c.subcmd == nil { panic("Run: missing subcommand; Init failed or not called") } if c.Log != nil { if err := c.Log.Start(ctx); err != nil { return err } } err := c.subcmd.Run(ctx) if err != nil && err != ErrSilent { log.Errorf("command failed: %v", err) } else { log.Infof("command finished") } return err }
func copyOne( tool *state.Tools, source environs.StorageReader, target environs.Storage, ctx *cmd.Context, ) error { toolsName := tools.StorageName(tool.Binary) fmt.Fprintf(ctx.Stderr, "copying %v", toolsName) srcFile, err := source.Get(toolsName) if err != nil { return err } defer srcFile.Close() // We have to buffer the content, because Put requires the content // length, but Get only returns us a ReadCloser buf := &bytes.Buffer{} nBytes, err := io.Copy(buf, srcFile) if err != nil { return err } log.Infof("downloaded %v (%dkB), uploading", toolsName, (nBytes+512)/1024) fmt.Fprintf(ctx.Stderr, ", download %dkB, uploading\n", (nBytes+512)/1024) if err := target.Put(toolsName, buf, nBytes); err != nil { return err } return nil }
// Open connects to the server described by the given // info, waits for it to be initialized, and returns a new State // representing the environment connected to. // It returns unauthorizedError if access is unauthorized. func Open(info *Info, opts DialOpts) (*State, error) { log.Infof("state: opening state; mongo addresses: %q; entity %q", info.Addrs, info.Tag) if len(info.Addrs) == 0 { return nil, stderrors.New("no mongo addresses") } if len(info.CACert) == 0 { return nil, stderrors.New("missing CA certificate") } xcert, err := cert.ParseCert(info.CACert) if err != nil { return nil, fmt.Errorf("cannot parse CA certificate: %v", err) } pool := x509.NewCertPool() pool.AddCert(xcert) tlsConfig := &tls.Config{ RootCAs: pool, ServerName: "anything", } dial := func(addr net.Addr) (net.Conn, error) { c, err := net.Dial("tcp", addr.String()) if err != nil { log.Errorf("state: connection failed, will retry: %v", err) return nil, err } cc := tls.Client(c, tlsConfig) if err := cc.Handshake(); err != nil { log.Errorf("state: TLS handshake failed: %v", err) return nil, err } return cc, nil } session, err := mgo.DialWithInfo(&mgo.DialInfo{ Addrs: info.Addrs, Timeout: opts.Timeout, Dial: dial, }) if err != nil { return nil, err } log.Infof("state: connection established") st, err := newState(session, info) if err != nil { session.Close() return nil, err } return st, nil }
// CharmPublisher returns a new CharmPublisher for importing a charm that // will be made available in the store at all of the provided URLs. // The digest parameter must contain the unique identifier that // represents the charm data being imported (e.g. the VCS revision sha1). // ErrRedundantUpdate is returned if all of the provided urls are // already associated to that digest. func (s *Store) CharmPublisher(urls []*charm.URL, digest string) (p *CharmPublisher, err error) { log.Infof("store: Trying to add charms %v with key %q...", urls, digest) if err = mustLackRevision("CharmPublisher", urls...); err != nil { return } session := s.session.Copy() defer session.Close() maxRev := -1 newKey := false charms := session.Charms() doc := charmDoc{} for i := range urls { urlStr := urls[i].String() err = charms.Find(bson.D{{"urls", urlStr}}).Sort("-revision").One(&doc) if err == mgo.ErrNotFound { log.Infof("store: Charm %s not yet in the store.", urls[i]) newKey = true continue } if doc.Digest != digest { log.Infof("store: Charm %s is out of date with revision key %q.", urlStr, digest) newKey = true } if err != nil { log.Errorf("store: Unknown error looking for charm %s: %s", urlStr, err) return } if doc.Revision > maxRev { maxRev = doc.Revision } } if !newKey { log.Infof("store: All charms have revision key %q. Nothing to update.", digest) err = ErrRedundantUpdate return } revision := maxRev + 1 log.Infof("store: Preparing writer to add charms with revision %d.", revision) w := &charmWriter{ store: s, urls: urls, revision: revision, digest: digest, } return &CharmPublisher{revision, w}, nil }
// methods returns information on the RPC methods // implemented by the given type. func methods(rootType reflect.Type) (*serverMethods, error) { typeMutex.RLock() methods := methodsByType[rootType] typeMutex.RUnlock() if methods != nil { return methods, nil } typeMutex.Lock() defer typeMutex.Unlock() methods = methodsByType[rootType] if methods != nil { return methods, nil } methods = &serverMethods{ obtain: make(map[string]*obtainer), action: make(map[reflect.Type]map[string]*action), } for i := 0; i < rootType.NumMethod(); i++ { rootMethod := rootType.Method(i) obtain := methodToObtainer(rootMethod) if obtain == nil { log.Infof("rpc: discarding obtainer method %#v", rootMethod) continue } actions := make(map[string]*action) for i := 0; i < obtain.ret.NumMethod(); i++ { obtainMethod := obtain.ret.Method(i) if act := methodToAction(obtainMethod); act != nil { actions[obtainMethod.Name] = act } else { log.Infof("rpc: discarding action method %#v", obtainMethod) } } if len(actions) > 0 { methods.action[obtain.ret] = actions methods.obtain[rootMethod.Name] = obtain } else { log.Infof("rpc: discarding obtainer %v because its result has no methods", rootMethod.Name) } } if len(methods.obtain) == 0 { return nil, fmt.Errorf("no RPC methods found on %s", rootType) } methodsByType[rootType] = methods return methods, nil }
func (s *LogSuite) TestStderr(c *C) { l := &cmd.Log{Verbose: true, Config: "<root>=INFO"} ctx := testing.Context(c) err := l.Start(ctx) c.Assert(err, IsNil) log.Infof("hello") c.Assert(bufferString(ctx.Stderr), Matches, `^.* INFO .* hello\n`) }
// FindBootstrapTools returns a ToolsList containing only those tools with // which it would be reasonable to launch an environment's first machine, // given the supplied constraints. // If the environment was not already configured to use a specific agent // version, the newest available version will be chosen and set in the // environment's configuration. func FindBootstrapTools(environ Environ, cons constraints.Value) (list tools.List, err error) { defer convertToolsError(&err) // Collect all possible compatible tools. cliVersion := version.Current.Number if list, err = FindAvailableTools(environ, cliVersion.Major); err != nil { return nil, err } // Discard all that are known to be irrelevant. cfg := environ.Config() series := cfg.DefaultSeries() log.Infof("environs: filtering tools by series: %s", series) filter := tools.Filter{Series: series} if cons.Arch != nil && *cons.Arch != "" { log.Infof("environs: filtering tools by architecture: %s", *cons.Arch) filter.Arch = *cons.Arch } if agentVersion, ok := cfg.AgentVersion(); ok { // If we already have an explicit agent version set, we're done. log.Infof("environs: filtering tools by version: %s", agentVersion) filter.Number = agentVersion return list.Match(filter) } if dev := cliVersion.IsDev() || cfg.Development(); !dev { log.Infof("environs: filtering tools by released version") filter.Released = true } if list, err = list.Match(filter); err != nil { return nil, err } // We probably still have a mix of versions available; discard older ones // and update environment configuration to use only those remaining. agentVersion, list := list.Newest() log.Infof("environs: picked newest version: %s", agentVersion) cfg, err = cfg.Apply(map[string]interface{}{ "agent-version": agentVersion.String(), }) if err == nil { err = environ.SetConfig(cfg) } if err != nil { return nil, fmt.Errorf("failed to update environment configuration: %v", err) } return list, nil }
// ChangeAgentTools does the actual agent upgrade. func (e *UpgradeReadyError) ChangeAgentTools() error { tools, err := tools.ChangeAgentTools(e.DataDir, e.AgentName, e.NewTools.Binary) if err != nil { return err } log.Infof("upgrader upgraded from %v to %v (%q)", e.OldTools.Binary, tools.Binary, tools.URL) return nil }
// Run runs a machine agent. func (a *MachineAgent) Run(_ *cmd.Context) error { defer a.tomb.Done() log.Infof("machine agent %v start", a.Tag()) if err := a.Conf.read(a.Tag()); err != nil { return err } if err := EnsureWeHaveLXC(a.Conf.DataDir, a.Tag()); err != nil { log.Errorf("we were unable to install the lxc package, unable to continue: %v", err) return err } charm.CacheDir = filepath.Join(a.Conf.DataDir, "charmcache") // ensureStateWorker ensures that there is a worker that // connects to the state that runs within itself all the workers // that need a state connection Unless we're bootstrapping, we // need to connect to the API server to find out if we need to // call this, so we make the APIWorker call it when necessary if // the machine requires it. Note that ensureStateWorker can be // called many times - StartWorker does nothing if there is // already a worker started with the given name. ensureStateWorker := func() { a.runner.StartWorker("state", func() (worker.Worker, error) { // TODO(rog) go1.1: use method expression return a.StateWorker() }) } if a.MachineId == bootstrapMachineId { // If we're bootstrapping, we don't have an API // server to connect to, so start the state worker regardless. // TODO(rog) When we have HA, we only want to do this // when we really are bootstrapping - once other // instances of the API server have been started, we // should follow the normal course of things and ignore // the fact that this was once the bootstrap machine. log.Infof("Starting StateWorker for machine-0") ensureStateWorker() } a.runner.StartWorker("api", func() (worker.Worker, error) { // TODO(rog) go1.1: use method expression return a.APIWorker(ensureStateWorker) }) err := agentDone(a.runner.Wait()) a.tomb.Kill(err) return err }
// runWorker starts the given worker after waiting for the given delay. func (runner *Runner) runWorker(delay time.Duration, id string, start func() (Worker, error)) { if delay > 0 { log.Infof("worker: restarting %q in %v", id, delay) select { case <-runner.tomb.Dying(): runner.donec <- doneInfo{id, nil} return case <-time.After(delay): } } log.Infof("worker: start %q", id) worker, err := start() if err == nil { runner.startedc <- startInfo{id, worker} err = worker.Wait() } runner.donec <- doneInfo{id, err} }
func (e *environ) Bootstrap(cons constraints.Value) error { defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return err } password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return fmt.Errorf("no CA certificate in environment configuration") } possibleTools, err := environs.FindBootstrapTools(e, cons) if err != nil { return err } log.Infof("environs/dummy: would pick tools from %s", possibleTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } e.state.mu.Lock() defer e.state.mu.Unlock() if e.state.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } if e.ecfg().stateServer() { // TODO(rog) factor out relevant code from cmd/jujud/bootstrap.go // so that we can call it here. info := stateInfo() st, err := state.Initialize(info, cfg, state.DefaultDialOpts()) if err != nil { panic(err) } if err := st.SetEnvironConstraints(cons); err != nil { panic(err) } if err := st.SetAdminMongoPassword(utils.PasswordHash(password)); err != nil { panic(err) } _, err = st.AddUser("admin", password) if err != nil { panic(err) } e.state.apiServer, err = apiserver.NewServer(st, "localhost:0", []byte(testing.ServerCert), []byte(testing.ServerKey)) if err != nil { panic(err) } e.state.apiState = st } e.state.bootstrapped = true e.state.ops <- OpBootstrap{Env: e.state.name, Constraints: cons} return nil }
// fakeTimeSlot hardcodes the slot time returned by the timeSlot // function for testing purposes. The offset parameter is the slot // position to return: offsets +1 and -1 are +period and -period // seconds from slot 0, respectively. func fakeTimeSlot(offset int) { fakeMutex.Lock() if fakeNow.IsZero() { fakeNow = time.Now() } fakeOffset = offset fakeMutex.Unlock() log.Infof("state/presence: Faking presence to time slot %d", offset) }
// PublishCharmsDistro publishes all branch tips found in // the /charms distribution in Launchpad onto store under // the "cs:" scheme. // apiBase specifies the Launchpad base API URL, such // as lpad.Production or lpad.Staging. // Errors found while processing one or more branches are // all returned as a PublishBranchErrors value. func PublishCharmsDistro(store *Store, apiBase lpad.APIBase) error { oauth := &lpad.OAuth{Anonymous: true, Consumer: "juju"} root, err := lpad.Login(apiBase, oauth) if err != nil { return err } distro, err := root.Distro("charms") if err != nil { return err } tips, err := distro.BranchTips(time.Time{}) if err != nil { return err } var errs PublishBranchErrors for _, tip := range tips { if !strings.HasSuffix(tip.UniqueName, "/trunk") { continue } burl, curl, err := uniqueNameURLs(tip.UniqueName) if err != nil { errs = append(errs, PublishBranchError{tip.UniqueName, err}) log.Errorf("%v\n", err) continue } log.Infof("----- %s\n", burl) if tip.Revision == "" { errs = append(errs, PublishBranchError{burl, fmt.Errorf("branch has no revisions")}) log.Errorf("branch has no revisions\n") continue } // Charm is published in the personal URL and in any explicitly // assigned official series. urls := []*charm.URL{curl} schema, name := curl.Schema, curl.Name for _, series := range tip.OfficialSeries { curl = &charm.URL{Schema: schema, Name: name, Series: series, Revision: -1} curl.Series = series curl.User = "" urls = append(urls, curl) } err = PublishBazaarBranch(store, urls, burl, tip.Revision) if err == ErrRedundantUpdate { continue } if err != nil { errs = append(errs, PublishBranchError{burl, err}) log.Errorf("%v\n", err) } } if errs != nil { return errs } return nil }
func (c *testCodec) ReadBody(r interface{}, isRequest bool) error { if v := reflect.ValueOf(r); v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { panic(fmt.Errorf("ReadResponseBody bad destination; want *struct got %T", r)) } if c.role != roleBoth && isRequest == (c.role == roleClient) { panic(fmt.Errorf("codec role %v; read wrong body type %#v", c.role, r)) } // Note: this will need to change if we want to test a non-JSON codec. var m json.RawMessage err := c.Codec.ReadBody(&m, isRequest) if err != nil { return err } log.Infof("got response body: %q", m) err = json.Unmarshal(m, r) log.Infof("unmarshalled into %#v", r) return err }
func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) { log.Infof("environs/openstack: opening environment %q", cfg.Name()) e := new(environ) err := e.SetConfig(cfg) if err != nil { return nil, err } e.name = cfg.Name() return e, nil }