Beispiel #1
0
// 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")
}
Beispiel #2
0
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(&params)
	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
}
Beispiel #3
0
// 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
}
Beispiel #4
0
// 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)
}
Beispiel #5
0
// 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
}
Beispiel #6
0
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
}
Beispiel #7
0
// 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
}
Beispiel #8
0
// 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
}
Beispiel #9
0
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
}
Beispiel #10
0
// 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()
}
Beispiel #11
0
// 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
}
Beispiel #12
0
// 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
}
Beispiel #13
0
// 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.")
}
Beispiel #14
0
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()
}
Beispiel #15
0
// 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
}
Beispiel #16
0
// 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
}
Beispiel #17
0
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
}
Beispiel #18
0
// 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
}
Beispiel #19
0
// 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
}
Beispiel #20
0
// 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`)
}
Beispiel #22
0
// 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
}
Beispiel #23
0
// 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
}
Beispiel #24
0
// 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
}
Beispiel #25
0
// 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}
}
Beispiel #26
0
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
}
Beispiel #27
0
// 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)
}
Beispiel #28
0
// 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
}
Beispiel #29
0
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
}
Beispiel #30
0
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
}