github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/migrationtarget/migrationtarget.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package migrationtarget
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"gopkg.in/juju/names.v2"
     9  
    10  	"github.com/juju/juju/apiserver/common"
    11  	"github.com/juju/juju/apiserver/facade"
    12  	"github.com/juju/juju/apiserver/params"
    13  	coremigration "github.com/juju/juju/core/migration"
    14  	"github.com/juju/juju/migration"
    15  	"github.com/juju/juju/permission"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  func init() {
    20  	common.RegisterStandardFacade("MigrationTarget", 1, NewAPI)
    21  }
    22  
    23  // API implements the API required for the model migration
    24  // master worker when communicating with the target controller.
    25  type API struct {
    26  	state      *state.State
    27  	authorizer facade.Authorizer
    28  	resources  facade.Resources
    29  }
    30  
    31  // NewAPI returns a new API.
    32  func NewAPI(
    33  	st *state.State,
    34  	resources facade.Resources,
    35  	authorizer facade.Authorizer,
    36  ) (*API, error) {
    37  	if err := checkAuth(authorizer, st); err != nil {
    38  		return nil, errors.Trace(err)
    39  	}
    40  	return &API{
    41  		state:      st,
    42  		authorizer: authorizer,
    43  		resources:  resources,
    44  	}, nil
    45  }
    46  
    47  func checkAuth(authorizer facade.Authorizer, st *state.State) error {
    48  	if !authorizer.AuthClient() {
    49  		return errors.Trace(common.ErrPerm)
    50  	}
    51  
    52  	if isAdmin, err := authorizer.HasPermission(permission.SuperuserAccess, st.ControllerTag()); err != nil {
    53  		return errors.Trace(err)
    54  	} else if !isAdmin {
    55  		// The entire facade is only accessible to controller administrators.
    56  		return errors.Trace(common.ErrPerm)
    57  	}
    58  	return nil
    59  }
    60  
    61  // Prechecks ensure that the target controller is ready to accept a
    62  // model migration.
    63  func (api *API) Prechecks(model params.MigrationModelInfo) error {
    64  	ownerTag, err := names.ParseUserTag(model.OwnerTag)
    65  	if err != nil {
    66  		return errors.Trace(err)
    67  	}
    68  	return migration.TargetPrecheck(
    69  		migration.PrecheckShim(api.state),
    70  		coremigration.ModelInfo{
    71  			UUID:         model.UUID,
    72  			Name:         model.Name,
    73  			Owner:        ownerTag,
    74  			AgentVersion: model.AgentVersion,
    75  		},
    76  	)
    77  }
    78  
    79  // Import takes a serialized Juju model, deserializes it, and
    80  // recreates it in the receiving controller.
    81  func (api *API) Import(serialized params.SerializedModel) error {
    82  	_, st, err := migration.ImportModel(api.state, serialized.Bytes)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	defer st.Close()
    87  	// TODO(mjs) - post import checks
    88  	// NOTE(fwereade) - checks here would be sensible, but we will
    89  	// also need to check after the binaries are imported too.
    90  	return err
    91  }
    92  
    93  func (api *API) getModel(args params.ModelArgs) (*state.Model, error) {
    94  	tag, err := names.ParseModelTag(args.ModelTag)
    95  	if err != nil {
    96  		return nil, errors.Trace(err)
    97  	}
    98  	model, err := api.state.GetModel(tag)
    99  	if err != nil {
   100  		return nil, errors.Trace(err)
   101  	}
   102  	if model.MigrationMode() != state.MigrationModeImporting {
   103  		return nil, errors.New("migration mode for the model is not importing")
   104  	}
   105  	return model, nil
   106  }
   107  
   108  // Abort removes the specified model from the database. It is an error to
   109  // attempt to Abort a model that has a migration mode other than importing.
   110  func (api *API) Abort(args params.ModelArgs) error {
   111  	model, err := api.getModel(args)
   112  	if err != nil {
   113  		return errors.Trace(err)
   114  	}
   115  
   116  	st, err := api.state.ForModel(model.ModelTag())
   117  	if err != nil {
   118  		return errors.Trace(err)
   119  	}
   120  	defer st.Close()
   121  
   122  	return st.RemoveImportingModelDocs()
   123  }
   124  
   125  // Activate sets the migration mode of the model to "active". It is an error to
   126  // attempt to Abort a model that has a migration mode other than importing.
   127  func (api *API) Activate(args params.ModelArgs) error {
   128  	model, err := api.getModel(args)
   129  	if err != nil {
   130  		return errors.Trace(err)
   131  	}
   132  
   133  	// TODO(fwereade) - need to validate binaries here.
   134  	return model.SetMigrationMode(state.MigrationModeNone)
   135  }