Boostrapping an environment When you first start looking at the bootstrap process it all seems to be a convoluted mess. However there is method to our madness. Bootstrapping starts with the CLI command `bootstrap`. That is found in cmd/juju/bootstrap.go The first step of bootstrap is to create an Environ instance which is named. This Environ instance has the environment configuration (the *config.Config instance). Initially this will check in the default config store, which is $JUJU_HOME/environments. This calls through to environs.PrepareForName in environs/open.go. This makes sure the the environment configuration contains an admin secret, a CA cert, and a UUID. It is at this time that the initial .jenv file is written out to $JUJU_HOME/environments. Further checks are then done as part of the bootstrap command: * validating the constaints * checking to make sure the environment is already bootstrapped The code then moves on to the Bootstrap function defined in environs/bootstrap/bootstrap.go. bootstrap.Bootstrap starts with sanity checks: * setting a package global in the network package for prefer IPv6 (not sanity) * there is an admin-secret * that there is at least one authorised SSH key * that there is a CA Cert and CA Key * that the environment storage is writable (by writing the bootstrap-init file) * finds available tools - locate tools available externally (matching constraints) - determine which tools can be built and uploaded to make up shortfall in above - if the best tools are made locally, and we can upload tools, they get uploaded This code then calls into the Bootstrap function on the environ instance (backed by a provider), which returns arch, series, and a finalizer function. Now things diverge here a little: * azure does some initial config around affinity groups and networks, then calls common.Bootstrap. * ec2, joyent, maas, and openstack all fall through to common.Bootstrap * dummy, local and manual all do their own thing Firstly, common.Bootstrap: * creates machine config for the bootstrap machine * starts an instance for the bootstrap machine * writes the instance id (as yaml) into the the "provider-state" file in environ storage - this step will go away soon, or at least become provider specific The finalizer function, is run after the following checks from bootstrap.Bootstrap: * selects tools from the previously calculated set based on the architecture and series of the instance that the provider started * makes sure that the tools are available * creates the machine config struct for the bootstrap machine * sets the tools in that structure to the tools bootstap knows about * then it calls the finalizer function. The common finalizer function does the following: * updates the machine config with the instance id of the new machine * calls environs.FinishMachineConfig * populates the machine config with information from the config object * checks for CA Cert * checks for admin-secret * creates a password hash using the utils.CompatSalt * uses this password hash for both the APIInfo and MongoInfo passwords. * creates the state server cert and key * strips the admin-secret and server ca-private-key from the config * this step is probably not needed any more * calls common.FinishBootstrap * calls ssh with a custom script that first checks the nonce on the cloud instance * calls ConfigureMachine * creates cloud init script from the machine config, this includes the call to jujud bootstrap-state. * the bootstrap config is passed to jujud as base64 encoded yaml * runs said script over ssh jujud bootstrap-state * creates a *config.Config object from the base64 encoded yaml from the command line * sets the package global in the network package for prefer IPv6 * generates and writes out the system SSH identity file * generates a (long) shared secret for mongo * mongo is then started * the database is then initialized (state.Initialize) * copies the tools into environment storage - also clones the tools for each series of the same OS (for the time being at least, while each series' tools are equivalent)