Example #1
0
File: agent.go Project: kat-co/juju
// MongoVersion implements Config.
func (c *configInternal) MongoVersion() mongo.Version {
	v, err := mongo.NewVersion(c.mongoVersion)
	if err != nil {
		return mongo.Mongo24
	}
	return v
}
Example #2
0
File: create.go Project: bac/juju
// Create is the API method that requests juju to create a new backup
// of its state.  It returns the metadata for that backup.
func (a *API) Create(args params.BackupsCreateArgs) (p params.BackupsMetadataResult, err error) {
	backupsMethods, closer := newBackups(a.backend)
	defer closer.Close()

	session := a.backend.MongoSession().Copy()
	defer session.Close()

	// Don't go if HA isn't ready.
	err = waitUntilReady(session, 60)
	if err != nil {
		return p, errors.Annotatef(err, "HA not ready; try again later")
	}

	mgoInfo := a.backend.MongoConnectionInfo()
	v, err := a.backend.MongoVersion()
	if err != nil {
		return p, errors.Annotatef(err, "discovering mongo version")
	}
	mongoVersion, err := mongo.NewVersion(v)
	if err != nil {
		return p, errors.Trace(err)
	}
	dbInfo, err := backups.NewDBInfo(mgoInfo, session, mongoVersion)
	if err != nil {
		return p, errors.Trace(err)
	}
	mSeries, err := a.backend.MachineSeries(a.machineID)
	if err != nil {
		return p, errors.Trace(err)
	}

	meta, err := backups.NewMetadataState(a.backend, a.machineID, mSeries)
	if err != nil {
		return p, errors.Trace(err)
	}
	meta.Notes = args.Notes

	err = backupsMethods.Create(meta, a.paths, dbInfo)
	if err != nil {
		return p, errors.Trace(err)
	}

	return ResultFromMetadata(meta), nil
}
Example #3
0
File: restore.go Project: bac/juju
// Restore implements the server side of Backups.Restore.
func (a *API) Restore(p params.RestoreArgs) error {
	logger.Infof("Starting server side restore")

	// Get hold of a backup file Reader
	backup, closer := newBackups(a.backend)
	defer closer.Close()

	// Obtain the address of current machine, where we will be performing restore.
	machine, err := a.backend.Machine(a.machineID)
	if err != nil {
		return errors.Trace(err)
	}

	addr, err := machine.PrivateAddress()
	if err != nil {
		return errors.Annotatef(err, "error fetching internal address for machine %q", machine)

	}

	publicAddress, err := machine.PublicAddress()
	if err != nil {
		return errors.Annotatef(err, "error fetching public address for machine %q", machine)

	}

	info := a.backend.RestoreInfo()
	// Signal to current state and api server that restore will begin
	err = info.SetStatus(state.RestoreInProgress)
	if err != nil {
		return errors.Annotatef(err, "cannot set the server to %q mode", state.RestoreInProgress)
	}
	// Any abnormal termination of this function will mark restore as failed,
	// succesful termination will call Exit and never run this.
	defer info.SetStatus(state.RestoreFailed)

	instanceId, err := machine.InstanceId()
	if err != nil {
		return errors.Annotate(err, "cannot obtain instance id for machine to be restored")
	}

	logger.Infof("beginning server side restore of backup %q", p.BackupId)
	// Restore
	restoreArgs := backups.RestoreArgs{
		PrivateAddress: addr.Value,
		PublicAddress:  publicAddress.Value,
		NewInstId:      instanceId,
		NewInstTag:     machine.Tag(),
		NewInstSeries:  machine.Series(),
	}

	session := a.backend.MongoSession().Copy()
	defer session.Close()

	// Don't go if HA isn't ready.
	err = waitUntilReady(session, 60)
	if err != nil {
		return errors.Annotatef(err, "HA not ready; try again later")
	}

	mgoInfo := a.backend.MongoConnectionInfo()
	logger.Debugf("mongo info from state %+v", mgoInfo)
	v, err := a.backend.MongoVersion()
	if err != nil {
		return errors.Annotatef(err, "discovering mongo version")
	}
	mongoVersion, err := mongo.NewVersion(v)
	if err != nil {
		return errors.Trace(err)
	}

	dbInfo, err := backups.NewDBInfo(mgoInfo, session, mongoVersion)
	if err != nil {
		return errors.Trace(err)
	}

	oldTagString, err := backup.Restore(p.BackupId, dbInfo, restoreArgs)
	if err != nil {
		return errors.Annotate(err, "restore failed")
	}

	// A backup can be made of any component of an ha array.
	// The files in a backup don't contain purely relativized paths.
	// If the backup is made of the bootstrap node (machine 0) the
	// recently created machine will have the same paths and therefore
	// the startup scripts will fit the new juju. If the backup belongs
	// to a different machine, we need to create a new set of startup
	// scripts and exit with 0 (so that the current script does not try
	// to restart the old juju, which will no longer be there).
	if oldTagString != nil && oldTagString != bootstrapNode {
		srvName := fmt.Sprintf("jujud-%s", oldTagString)
		srv, err := service.DiscoverService(srvName, common.Conf{})
		if err != nil {
			return errors.Annotatef(err, "cannot find %q service", srvName)
		}
		if err := srv.Start(); err != nil {
			return errors.Annotatef(err, "cannot start %q service", srvName)
		}
		// We dont want machine-0 to restart since the new one has a different tag.
		// We started the new one above.
		os.Exit(0)
	}

	// After restoring, the api server needs a forced restart, tomb will not work
	// this is because we change all of juju configuration files and mongo too.
	// Exiting with 0 would prevent upstart to respawn the process

	// NOTE(fwereade): the apiserver needs to be restarted, yes, but
	// this approach is completely broken. The only place it's ever
	// ok to use os.Exit is in a main() func that's *so* simple as to
	// be reasonably left untested.
	//
	// And passing os.Exit in wouldn't make this any better either,
	// just using it subverts the expectations of *everything* else
	// running in the process.
	os.Exit(1)
	return nil
}