github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/state/environ.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names"
     9  	"gopkg.in/mgo.v2"
    10  	"gopkg.in/mgo.v2/bson"
    11  	"gopkg.in/mgo.v2/txn"
    12  
    13  	"github.com/juju/juju/environs/config"
    14  )
    15  
    16  // environGlobalKey is the key for the environment, its
    17  // settings and constraints.
    18  const environGlobalKey = "e"
    19  
    20  // Environment represents the state of an environment.
    21  type Environment struct {
    22  	st  *State
    23  	doc environmentDoc
    24  }
    25  
    26  // environmentDoc represents the internal state of the environment in MongoDB.
    27  type environmentDoc struct {
    28  	UUID       string `bson:"_id"`
    29  	Name       string
    30  	Life       Life
    31  	Owner      string `bson:"owner"`
    32  	ServerUUID string `bson:"server-uuid"`
    33  }
    34  
    35  // StateServerEnvironment returns the environment that was bootstrapped.
    36  // This is the only environment that can have state server machines.
    37  // The owner of this environment is also considered "special", in that
    38  // they are the only user that is able to create other users (until we
    39  // have more fine grained permissions), and they cannot be disabled.
    40  func (st *State) StateServerEnvironment() (*Environment, error) {
    41  	ssinfo, err := st.StateServerInfo()
    42  	if err != nil {
    43  		return nil, errors.Annotate(err, "could not get state server info")
    44  	}
    45  
    46  	environments, closer := st.getCollection(environmentsC)
    47  	defer closer()
    48  
    49  	env := &Environment{st: st}
    50  	uuid := ssinfo.EnvironmentTag.Id()
    51  	if err := env.refresh(environments.FindId(uuid)); err != nil {
    52  		return nil, errors.Trace(err)
    53  	}
    54  	return env, nil
    55  }
    56  
    57  // Environment returns the environment entity.
    58  func (st *State) Environment() (*Environment, error) {
    59  	environments, closer := st.getCollection(environmentsC)
    60  	defer closer()
    61  
    62  	env := &Environment{st: st}
    63  	uuid := st.environTag.Id()
    64  	if err := env.refresh(environments.FindId(uuid)); err != nil {
    65  		return nil, errors.Trace(err)
    66  	}
    67  	return env, nil
    68  }
    69  
    70  // GetEnvironment looks for the environment identified by the uuid passed in.
    71  func (st *State) GetEnvironment(tag names.EnvironTag) (*Environment, error) {
    72  	environments, closer := st.getCollection(environmentsC)
    73  	defer closer()
    74  
    75  	env := &Environment{st: st}
    76  	if err := env.refresh(environments.FindId(tag.Id())); err != nil {
    77  		return nil, errors.Trace(err)
    78  	}
    79  	return env, nil
    80  }
    81  
    82  // NewEnvironment creates a new environment with its own UUID and
    83  // prepares it for use. Environment and State instances for the new
    84  // environment are returned.
    85  //
    86  // The state server environment's UUID is attached to the new
    87  // environment's document. Having the server UUIDs stored with each
    88  // environment document means that we have a way to represent external
    89  // environments, perhaps for future use around cross environment
    90  // relations.
    91  func (st *State) NewEnvironment(cfg *config.Config, owner names.UserTag) (_ *Environment, _ *State, err error) {
    92  	if owner.IsLocal() {
    93  		if _, err := st.User(owner); err != nil {
    94  			return nil, nil, errors.Annotate(err, "cannot create environment")
    95  		}
    96  	}
    97  
    98  	ssEnv, err := st.StateServerEnvironment()
    99  	if err != nil {
   100  		return nil, nil, errors.Annotate(err, "could not load state server environment")
   101  	}
   102  
   103  	uuid, ok := cfg.UUID()
   104  	if !ok {
   105  		return nil, nil, errors.Errorf("environment uuid was not supplied")
   106  	}
   107  	newState, err := st.ForEnviron(names.NewEnvironTag(uuid))
   108  	if err != nil {
   109  		return nil, nil, errors.Annotate(err, "could not create state for new environment")
   110  	}
   111  	defer func() {
   112  		if err != nil {
   113  			newState.Close()
   114  		}
   115  	}()
   116  
   117  	ops, err := newState.envSetupOps(cfg, uuid, ssEnv.UUID(), owner)
   118  	if err != nil {
   119  		return nil, nil, errors.Annotate(err, "failed to create new environment")
   120  	}
   121  	err = newState.runTransactionNoEnvAliveAssert(ops)
   122  	if err == txn.ErrAborted {
   123  		err = errors.New("environment already exists")
   124  	}
   125  	if err != nil {
   126  		return nil, nil, errors.Trace(err)
   127  	}
   128  
   129  	newEnv, err := newState.Environment()
   130  	if err != nil {
   131  		return nil, nil, errors.Annotate(err, "could not load new environment")
   132  	}
   133  
   134  	return newEnv, newState, nil
   135  }
   136  
   137  // Tag returns a name identifying the environment.
   138  // The returned name will be different from other Tag values returned
   139  // by any other entities from the same state.
   140  func (e *Environment) Tag() names.Tag {
   141  	return e.EnvironTag()
   142  }
   143  
   144  // EnvironTag is the concrete environ tag for this environment.
   145  func (e *Environment) EnvironTag() names.EnvironTag {
   146  	return names.NewEnvironTag(e.doc.UUID)
   147  }
   148  
   149  // ServerTag is the environ tag for the server that the environment is running
   150  // within.
   151  func (e *Environment) ServerTag() names.EnvironTag {
   152  	return names.NewEnvironTag(e.doc.ServerUUID)
   153  }
   154  
   155  // UUID returns the universally unique identifier of the environment.
   156  func (e *Environment) UUID() string {
   157  	return e.doc.UUID
   158  }
   159  
   160  // Name returns the human friendly name of the environment.
   161  func (e *Environment) Name() string {
   162  	return e.doc.Name
   163  }
   164  
   165  // Life returns whether the environment is Alive, Dying or Dead.
   166  func (e *Environment) Life() Life {
   167  	return e.doc.Life
   168  }
   169  
   170  // Owner returns tag representing the owner of the environment.
   171  // The owner is the user that created the environment.
   172  func (e *Environment) Owner() names.UserTag {
   173  	return names.NewUserTag(e.doc.Owner)
   174  }
   175  
   176  // Config returns the config for the environment.
   177  func (e *Environment) Config() (*config.Config, error) {
   178  	if e.st.environTag.Id() == e.UUID() {
   179  		return e.st.EnvironConfig()
   180  	}
   181  	// The active environment isn't the same as the environment
   182  	// we are querying.
   183  	envState, err := e.st.ForEnviron(e.ServerTag())
   184  	if err != nil {
   185  		return nil, errors.Trace(err)
   186  	}
   187  	defer envState.Close()
   188  	return envState.EnvironConfig()
   189  }
   190  
   191  // globalKey returns the global database key for the environment.
   192  func (e *Environment) globalKey() string {
   193  	return environGlobalKey
   194  }
   195  
   196  func (e *Environment) Refresh() error {
   197  	environments, closer := e.st.getCollection(environmentsC)
   198  	defer closer()
   199  
   200  	return e.refresh(environments.FindId(e.UUID()))
   201  }
   202  
   203  func (e *Environment) refresh(query *mgo.Query) error {
   204  	err := query.One(&e.doc)
   205  	if err == mgo.ErrNotFound {
   206  		return errors.NotFoundf("environment")
   207  	}
   208  	return err
   209  }
   210  
   211  // Destroy sets the environment's lifecycle to Dying, preventing
   212  // addition of services or machines to state.
   213  func (e *Environment) Destroy() error {
   214  	if e.Life() != Alive {
   215  		return nil
   216  	}
   217  	// TODO(axw) 2013-12-11 #1218688
   218  	// Resolve the race between checking for manual machines and
   219  	// destroying the environment. We can set Environment to Dying
   220  	// to resolve the race, but that puts the environment into an
   221  	// unusable state.
   222  	//
   223  	// We add a cleanup for services, but not for machines;
   224  	// machines are destroyed via the provider interface. The
   225  	// exception to this rule is manual machines; the API prevents
   226  	// destroy-environment from succeeding if any non-manager
   227  	// manual machines exist.
   228  	ops := []txn.Op{{
   229  		C:      environmentsC,
   230  		Id:     e.doc.UUID,
   231  		Update: bson.D{{"$set", bson.D{{"life", Dying}}}},
   232  		Assert: isEnvAliveDoc,
   233  	}, e.st.newCleanupOp(cleanupServicesForDyingEnvironment, "")}
   234  	err := e.st.runTransaction(ops)
   235  	switch err {
   236  	case nil, txn.ErrAborted:
   237  		// If the transaction aborted, the environment is either
   238  		// Dying or Dead; neither case is an error. If it's Dead,
   239  		// reporting it as Dying is not incorrect; the user thought
   240  		// it was Alive, so we've progressed towards Dead. If the
   241  		// user then calls Refresh they'll get the true value.
   242  		e.doc.Life = Dying
   243  	}
   244  	return err
   245  }
   246  
   247  // createEnvironmentOp returns the operation needed to create
   248  // an environment document with the given name and UUID.
   249  func createEnvironmentOp(st *State, owner names.UserTag, name, uuid, server string) txn.Op {
   250  	doc := &environmentDoc{
   251  		UUID:       uuid,
   252  		Name:       name,
   253  		Life:       Alive,
   254  		Owner:      owner.Username(),
   255  		ServerUUID: server,
   256  	}
   257  	return txn.Op{
   258  		C:      environmentsC,
   259  		Id:     uuid,
   260  		Assert: txn.DocMissing,
   261  		Insert: doc,
   262  	}
   263  }
   264  
   265  // assertAliveOp returns a txn.Op that asserts the environment is alive.
   266  func (e *Environment) assertAliveOp() txn.Op {
   267  	return txn.Op{
   268  		C:      environmentsC,
   269  		Id:     e.UUID(),
   270  		Assert: isEnvAliveDoc,
   271  	}
   272  }
   273  
   274  // isEnvAlive is an Environment-specific versio nof isAliveDoc.
   275  //
   276  // Environment documents from versions of Juju prior to 1.17
   277  // do not have the life field; if it does not exist, it should
   278  // be considered to have the value Alive.
   279  var isEnvAliveDoc = bson.D{
   280  	{"life", bson.D{{"$in", []interface{}{Alive, nil}}}},
   281  }