github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/systemmanager/systemmanager.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The systemmanager package defines an API end point for functions dealing
     5  // with systems as a whole. Primarily the destruction of systems.
     6  package systemmanager
     7  
     8  import (
     9  	"sort"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	"github.com/juju/names"
    14  	"github.com/juju/utils/set"
    15  
    16  	"github.com/juju/juju/apiserver/common"
    17  	"github.com/juju/juju/apiserver/params"
    18  	"github.com/juju/juju/feature"
    19  	"github.com/juju/juju/state"
    20  )
    21  
    22  var logger = loggo.GetLogger("juju.apiserver.systemmanager")
    23  
    24  func init() {
    25  	common.RegisterStandardFacadeForFeature("SystemManager", 1, NewSystemManagerAPI, feature.JES)
    26  }
    27  
    28  // SystemManager defines the methods on the systemmanager API end point.
    29  type SystemManager interface {
    30  	AllEnvironments() (params.UserEnvironmentList, error)
    31  	DestroySystem(args params.DestroySystemArgs) error
    32  	EnvironmentConfig() (params.EnvironmentConfigResults, error)
    33  	ListBlockedEnvironments() (params.EnvironmentBlockInfoList, error)
    34  	RemoveBlocks(args params.RemoveBlocksArgs) error
    35  	WatchAllEnvs() (params.AllWatcherId, error)
    36  }
    37  
    38  // SystemManagerAPI implements the environment manager interface and is
    39  // the concrete implementation of the api end point.
    40  type SystemManagerAPI struct {
    41  	state      *state.State
    42  	authorizer common.Authorizer
    43  	apiUser    names.UserTag
    44  	resources  *common.Resources
    45  }
    46  
    47  var _ SystemManager = (*SystemManagerAPI)(nil)
    48  
    49  // NewSystemManagerAPI creates a new api server endpoint for managing
    50  // environments.
    51  func NewSystemManagerAPI(
    52  	st *state.State,
    53  	resources *common.Resources,
    54  	authorizer common.Authorizer,
    55  ) (*SystemManagerAPI, error) {
    56  	if !authorizer.AuthClient() {
    57  		return nil, errors.Trace(common.ErrPerm)
    58  	}
    59  
    60  	// Since we know this is a user tag (because AuthClient is true),
    61  	// we just do the type assertion to the UserTag.
    62  	apiUser, _ := authorizer.GetAuthTag().(names.UserTag)
    63  	isAdmin, err := st.IsSystemAdministrator(apiUser)
    64  	if err != nil {
    65  		return nil, errors.Trace(err)
    66  	}
    67  	// The entire end point is only accessible to system administrators.
    68  	if !isAdmin {
    69  		return nil, errors.Trace(common.ErrPerm)
    70  	}
    71  
    72  	return &SystemManagerAPI{
    73  		state:      st,
    74  		authorizer: authorizer,
    75  		apiUser:    apiUser,
    76  		resources:  resources,
    77  	}, nil
    78  }
    79  
    80  // AllEnvironments allows system administrators to get the list of all the
    81  // environments in the system.
    82  func (s *SystemManagerAPI) AllEnvironments() (params.UserEnvironmentList, error) {
    83  	result := params.UserEnvironmentList{}
    84  
    85  	// Get all the environments that the authenticated user can see, and
    86  	// supplement that with the other environments that exist that the user
    87  	// cannot see. The reason we do this is to get the LastConnection time for
    88  	// the environments that the user is able to see, so we have consistent
    89  	// output when listing with or without --all when an admin user.
    90  	environments, err := s.state.EnvironmentsForUser(s.apiUser)
    91  	if err != nil {
    92  		return result, errors.Trace(err)
    93  	}
    94  	visibleEnvironments := set.NewStrings()
    95  	for _, env := range environments {
    96  		lastConn, err := env.LastConnection()
    97  		if err != nil && !state.IsNeverConnectedError(err) {
    98  			return result, errors.Trace(err)
    99  		}
   100  		visibleEnvironments.Add(env.UUID())
   101  		result.UserEnvironments = append(result.UserEnvironments, params.UserEnvironment{
   102  			Environment: params.Environment{
   103  				Name:     env.Name(),
   104  				UUID:     env.UUID(),
   105  				OwnerTag: env.Owner().String(),
   106  			},
   107  			LastConnection: &lastConn,
   108  		})
   109  	}
   110  
   111  	allEnvs, err := s.state.AllEnvironments()
   112  	if err != nil {
   113  		return result, errors.Trace(err)
   114  	}
   115  
   116  	for _, env := range allEnvs {
   117  		if !visibleEnvironments.Contains(env.UUID()) {
   118  			result.UserEnvironments = append(result.UserEnvironments, params.UserEnvironment{
   119  				Environment: params.Environment{
   120  					Name:     env.Name(),
   121  					UUID:     env.UUID(),
   122  					OwnerTag: env.Owner().String(),
   123  				},
   124  				// No LastConnection as this user hasn't.
   125  			})
   126  		}
   127  	}
   128  
   129  	// Sort the resulting sequence by environment name, then owner.
   130  	sort.Sort(orderedUserEnvironments(result.UserEnvironments))
   131  
   132  	return result, nil
   133  }
   134  
   135  // ListBlockedEnvironments returns a list of all environments on the system
   136  // which have a block in place.  The resulting slice is sorted by environment
   137  // name, then owner. Callers must be system administrators to retrieve the
   138  // list.
   139  func (s *SystemManagerAPI) ListBlockedEnvironments() (params.EnvironmentBlockInfoList, error) {
   140  	results := params.EnvironmentBlockInfoList{}
   141  
   142  	blocks, err := s.state.AllBlocksForSystem()
   143  	if err != nil {
   144  		return results, errors.Trace(err)
   145  	}
   146  
   147  	envBlocks := make(map[string][]string)
   148  	for _, block := range blocks {
   149  		uuid := block.EnvUUID()
   150  		types, ok := envBlocks[uuid]
   151  		if !ok {
   152  			types = []string{block.Type().String()}
   153  		} else {
   154  			types = append(types, block.Type().String())
   155  		}
   156  		envBlocks[uuid] = types
   157  	}
   158  
   159  	for uuid, blocks := range envBlocks {
   160  		envInfo, err := s.state.GetEnvironment(names.NewEnvironTag(uuid))
   161  		if err != nil {
   162  			logger.Debugf("Unable to get name for environment: %s", uuid)
   163  			continue
   164  		}
   165  		results.Environments = append(results.Environments, params.EnvironmentBlockInfo{
   166  			UUID:     envInfo.UUID(),
   167  			Name:     envInfo.Name(),
   168  			OwnerTag: envInfo.Owner().String(),
   169  			Blocks:   blocks,
   170  		})
   171  	}
   172  
   173  	// Sort the resulting sequence by environment name, then owner.
   174  	sort.Sort(orderedBlockInfo(results.Environments))
   175  
   176  	return results, nil
   177  }
   178  
   179  // DestroySystem will attempt to destroy the system. If the args specify the
   180  // removal of blocks or the destruction of the environments, this method will
   181  // attempt to do so.
   182  func (s *SystemManagerAPI) DestroySystem(args params.DestroySystemArgs) error {
   183  	// Get list of all environments in the system.
   184  	allEnvs, err := s.state.AllEnvironments()
   185  	if err != nil {
   186  		return errors.Trace(err)
   187  	}
   188  
   189  	// If there are hosted environments and DestroyEnvironments was not
   190  	// specified, don't bother trying to destroy the system, as it will fail.
   191  	if len(allEnvs) > 1 && !args.DestroyEnvironments {
   192  		return errors.Errorf("state server environment cannot be destroyed before all other environments are destroyed")
   193  	}
   194  
   195  	// If there are blocks, and we aren't being told to ignore them, let the
   196  	// user know.
   197  	blocks, err := s.state.AllBlocksForSystem()
   198  	if err != nil {
   199  		logger.Debugf("Unable to get blocks for system: %s", err)
   200  		if !args.IgnoreBlocks {
   201  			return errors.Trace(err)
   202  		}
   203  	}
   204  	if len(blocks) > 0 {
   205  		if !args.IgnoreBlocks {
   206  			return common.ErrOperationBlocked("found blocks in system environments")
   207  		}
   208  
   209  		err := s.state.RemoveAllBlocksForSystem()
   210  		if err != nil {
   211  			return errors.Trace(err)
   212  		}
   213  	}
   214  
   215  	systemEnv, err := s.state.StateServerEnvironment()
   216  	if err != nil {
   217  		return errors.Trace(err)
   218  	}
   219  	systemTag := systemEnv.EnvironTag()
   220  
   221  	if args.DestroyEnvironments {
   222  		for _, env := range allEnvs {
   223  			environTag := env.EnvironTag()
   224  			if environTag != systemTag {
   225  				if err := common.DestroyEnvironment(s.state, environTag); err != nil {
   226  					logger.Errorf("unable to destroy environment %q: %s", env.UUID(), err)
   227  				}
   228  			}
   229  		}
   230  	}
   231  
   232  	return errors.Trace(common.DestroyEnvironment(s.state, systemTag))
   233  }
   234  
   235  // EnvironmentConfig returns the environment config for the system
   236  // environment.  For information on the current environment, use
   237  // client.EnvironmentGet
   238  func (s *SystemManagerAPI) EnvironmentConfig() (params.EnvironmentConfigResults, error) {
   239  	result := params.EnvironmentConfigResults{}
   240  
   241  	stateServerEnv, err := s.state.StateServerEnvironment()
   242  	if err != nil {
   243  		return result, errors.Trace(err)
   244  	}
   245  
   246  	config, err := stateServerEnv.Config()
   247  	if err != nil {
   248  		return result, errors.Trace(err)
   249  	}
   250  
   251  	result.Config = config.AllAttrs()
   252  	return result, nil
   253  }
   254  
   255  // RemoveBlocks removes all the blocks in the system.
   256  func (s *SystemManagerAPI) RemoveBlocks(args params.RemoveBlocksArgs) error {
   257  	if !args.All {
   258  		return errors.New("not supported")
   259  	}
   260  	return errors.Trace(s.state.RemoveAllBlocksForSystem())
   261  }
   262  
   263  // WatchAllEnvs starts watching events for all environments in the
   264  // system. The returned AllWatcherId should be used with Next on the
   265  // AllEnvWatcher endpoint to receive deltas.
   266  func (c *SystemManagerAPI) WatchAllEnvs() (params.AllWatcherId, error) {
   267  	w := c.state.WatchAllEnvs()
   268  	return params.AllWatcherId{
   269  		AllWatcherId: c.resources.Register(w),
   270  	}, nil
   271  }
   272  
   273  type orderedBlockInfo []params.EnvironmentBlockInfo
   274  
   275  func (o orderedBlockInfo) Len() int {
   276  	return len(o)
   277  }
   278  
   279  func (o orderedBlockInfo) Less(i, j int) bool {
   280  	if o[i].Name < o[j].Name {
   281  		return true
   282  	}
   283  	if o[i].Name > o[j].Name {
   284  		return false
   285  	}
   286  
   287  	if o[i].OwnerTag < o[j].OwnerTag {
   288  		return true
   289  	}
   290  	if o[i].OwnerTag > o[j].OwnerTag {
   291  		return false
   292  	}
   293  
   294  	// Unreachable based on the rules of there not being duplicate
   295  	// environments of the same name for the same owner, but return false
   296  	// instead of panicing.
   297  	return false
   298  }
   299  
   300  func (o orderedBlockInfo) Swap(i, j int) {
   301  	o[i], o[j] = o[j], o[i]
   302  }
   303  
   304  type orderedUserEnvironments []params.UserEnvironment
   305  
   306  func (o orderedUserEnvironments) Len() int {
   307  	return len(o)
   308  }
   309  
   310  func (o orderedUserEnvironments) Less(i, j int) bool {
   311  	if o[i].Name < o[j].Name {
   312  		return true
   313  	}
   314  	if o[i].Name > o[j].Name {
   315  		return false
   316  	}
   317  
   318  	if o[i].OwnerTag < o[j].OwnerTag {
   319  		return true
   320  	}
   321  	if o[i].OwnerTag > o[j].OwnerTag {
   322  		return false
   323  	}
   324  
   325  	// Unreachable based on the rules of there not being duplicate
   326  	// environments of the same name for the same owner, but return false
   327  	// instead of panicing.
   328  	return false
   329  }
   330  
   331  func (o orderedUserEnvironments) Swap(i, j int) {
   332  	o[i], o[j] = o[j], o[i]
   333  }