github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/modelmanagerinterface.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/description/v5"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/names/v5"
    13  
    14  	apiservererrors "github.com/juju/juju/apiserver/errors"
    15  	"github.com/juju/juju/cloud"
    16  	"github.com/juju/juju/controller"
    17  	"github.com/juju/juju/core/network"
    18  	"github.com/juju/juju/core/permission"
    19  	"github.com/juju/juju/core/secrets"
    20  	"github.com/juju/juju/core/status"
    21  	"github.com/juju/juju/environs"
    22  	environscloudspec "github.com/juju/juju/environs/cloudspec"
    23  	"github.com/juju/juju/environs/config"
    24  	"github.com/juju/juju/state"
    25  )
    26  
    27  // ModelManagerBackend defines methods provided by a state
    28  // instance used by the model manager apiserver implementation.
    29  // All the interface methods are defined directly on state.State
    30  // and are reproduced here for use in tests.
    31  type ModelManagerBackend interface {
    32  	APIHostPortsForAgentsGetter
    33  	ToolsStorageGetter
    34  	BlockGetter
    35  	state.CloudAccessor
    36  
    37  	ModelUUID() string
    38  	ModelBasicInfoForUser(user names.UserTag, isSuperuser bool) ([]state.ModelAccessInfo, error)
    39  	ModelSummariesForUser(user names.UserTag, isSupersser bool) ([]state.ModelSummary, error)
    40  	IsControllerAdmin(user names.UserTag) (bool, error)
    41  	NewModel(state.ModelArgs) (Model, ModelManagerBackend, error)
    42  	Model() (Model, error)
    43  	AllModelUUIDs() ([]string, error)
    44  	GetModel(string) (Model, func() bool, error)
    45  	GetBackend(string) (ModelManagerBackend, func() bool, error)
    46  
    47  	ComposeNewModelConfig(modelAttr map[string]interface{}, regionSpec *environscloudspec.CloudRegionSpec) (map[string]interface{}, error)
    48  	ControllerModelUUID() string
    49  	ControllerModelTag() names.ModelTag
    50  	IsController() bool
    51  	ControllerConfig() (controller.Config, error)
    52  	ControllerNodes() ([]ControllerNode, error)
    53  	ModelConfigDefaultValues(cloudName string) (config.ModelDefaultAttributes, error)
    54  	UpdateModelConfigDefaultValues(update map[string]interface{}, remove []string, regionSpec *environscloudspec.CloudRegionSpec) error
    55  	Unit(name string) (*state.Unit, error)
    56  	Name() string
    57  	ModelTag() names.ModelTag
    58  	ModelConfig() (*config.Config, error)
    59  	AddControllerUser(state.UserAccessSpec) (permission.UserAccess, error)
    60  	RemoveUserAccess(names.UserTag, names.Tag) error
    61  	UserAccess(names.UserTag, names.Tag) (permission.UserAccess, error)
    62  	GetCloudAccess(cloud string, user names.UserTag) (permission.Access, error)
    63  	AllMachines() (machines []Machine, err error)
    64  	AllApplications() (applications []Application, err error)
    65  	AllFilesystems() ([]state.Filesystem, error)
    66  	AllVolumes() ([]state.Volume, error)
    67  	ControllerUUID() string
    68  	ControllerTag() names.ControllerTag
    69  	Export(leaders map[string]string) (description.Model, error)
    70  	ExportPartial(state.ExportConfig) (description.Model, error)
    71  	SetUserAccess(subject names.UserTag, target names.Tag, access permission.Access) (permission.UserAccess, error)
    72  	SetModelMeterStatus(string, string) error
    73  	AllSpaces() ([]*state.Space, error)
    74  	AddSpace(string, network.Id, []string, bool) (*state.Space, error)
    75  	AllEndpointBindingsSpaceNames() (set.Strings, error)
    76  	ConstraintsBySpaceName(string) ([]*state.Constraints, error)
    77  	DefaultEndpointBindingSpace() (string, error)
    78  	SaveProviderSubnets([]network.SubnetInfo, string) error
    79  	LatestMigration() (state.ModelMigration, error)
    80  	DumpAll() (map[string]interface{}, error)
    81  	Close() error
    82  	HAPrimaryMachine() (names.MachineTag, error)
    83  
    84  	// Secrets methods.
    85  	ListModelSecrets(bool) (map[string]set.Strings, error)
    86  	ListSecretBackends() ([]*secrets.SecretBackend, error)
    87  	GetSecretBackendByID(string) (*secrets.SecretBackend, error)
    88  
    89  	// Methods required by the metricsender package.
    90  	MetricsManager() (*state.MetricsManager, error)
    91  	MetricsToSend(batchSize int) ([]*state.MetricBatch, error)
    92  	SetMetricBatchesSent(batchUUIDs []string) error
    93  	CountOfUnsentMetrics() (int, error)
    94  	CountOfSentMetrics() (int, error)
    95  	CleanupOldMetrics() error
    96  }
    97  
    98  // Model defines methods provided by a state.Model instance.
    99  // All the interface methods are defined directly on state.Model
   100  // and are reproduced here for use in tests.
   101  type Model interface {
   102  	Type() state.ModelType
   103  	Config() (*config.Config, error)
   104  	Life() state.Life
   105  	ModelTag() names.ModelTag
   106  	Owner() names.UserTag
   107  	Status() (status.StatusInfo, error)
   108  	CloudName() string
   109  	Cloud() (cloud.Cloud, error)
   110  	CloudCredentialTag() (names.CloudCredentialTag, bool)
   111  	CloudCredential() (state.Credential, bool, error)
   112  	CloudRegion() string
   113  	Users() ([]permission.UserAccess, error)
   114  	Destroy(state.DestroyModelParams) error
   115  	SLALevel() string
   116  	SLAOwner() string
   117  	MigrationMode() state.MigrationMode
   118  	Name() string
   119  	UUID() string
   120  	ControllerUUID() string
   121  	LastModelConnection(user names.UserTag) (time.Time, error)
   122  	AddUser(state.UserAccessSpec) (permission.UserAccess, error)
   123  	AutoConfigureContainerNetworking(environ environs.BootstrapEnviron) error
   124  	SetCloudCredential(tag names.CloudCredentialTag) (bool, error)
   125  }
   126  
   127  var _ ModelManagerBackend = (*modelManagerStateShim)(nil)
   128  
   129  type modelManagerStateShim struct {
   130  	*state.State
   131  	model *state.Model
   132  	pool  *state.StatePool
   133  	user  names.UserTag
   134  }
   135  
   136  // NewModelManagerBackend returns a modelManagerStateShim wrapping the passed
   137  // state, which implements ModelManagerBackend.
   138  func NewModelManagerBackend(m *state.Model, pool *state.StatePool) ModelManagerBackend {
   139  	return modelManagerStateShim{m.State(), m, pool, names.UserTag{}}
   140  }
   141  
   142  // NewUserAwareModelManagerBackend returns a user-aware modelManagerStateShim
   143  // wrapping the passed state, which implements ModelManagerBackend. The
   144  // returned backend may emit redirect errors when attempting a model lookup for
   145  // a migrated model that this user had been granted access to.
   146  func NewUserAwareModelManagerBackend(m *state.Model, pool *state.StatePool, u names.UserTag) ModelManagerBackend {
   147  	return modelManagerStateShim{m.State(), m, pool, u}
   148  }
   149  
   150  // NewModel implements ModelManagerBackend.
   151  func (st modelManagerStateShim) NewModel(args state.ModelArgs) (Model, ModelManagerBackend, error) {
   152  	aController := state.NewController(st.pool)
   153  	otherModel, otherState, err := aController.NewModel(args)
   154  	if err != nil {
   155  		return nil, nil, err
   156  	}
   157  	return modelShim{otherModel}, modelManagerStateShim{otherState, otherModel, st.pool, st.user}, nil
   158  }
   159  
   160  func (st modelManagerStateShim) ModelConfigDefaultValues(cloudName string) (config.ModelDefaultAttributes, error) {
   161  	return st.State.ModelConfigDefaultValues(cloudName)
   162  }
   163  
   164  // UpdateModelConfigDefaultValues implements the ModelManagerBackend method.
   165  func (st modelManagerStateShim) UpdateModelConfigDefaultValues(update map[string]interface{}, remove []string, regionSpec *environscloudspec.CloudRegionSpec) error {
   166  	return st.State.UpdateModelConfigDefaultValues(update, remove, regionSpec)
   167  }
   168  
   169  // ControllerTag exposes Model ControllerTag for ModelManagerBackend inteface
   170  func (st modelManagerStateShim) ControllerTag() names.ControllerTag {
   171  	return st.model.ControllerTag()
   172  }
   173  
   174  // GetBackend implements ModelManagerBackend.
   175  func (st modelManagerStateShim) GetBackend(modelUUID string) (ModelManagerBackend, func() bool, error) {
   176  	otherState, err := st.pool.Get(modelUUID)
   177  	if err != nil {
   178  		return nil, nil, errors.Trace(err)
   179  	}
   180  	otherModel, err := otherState.Model()
   181  	if err != nil {
   182  		defer otherState.Release()
   183  		if !errors.IsNotFound(err) || st.user.Id() == "" {
   184  			return nil, nil, err
   185  		}
   186  
   187  		// Check if this model has been migrated and this user had
   188  		// access to it before its migration.
   189  		mig, mErr := otherState.CompletedMigration()
   190  		if mErr != nil && !errors.IsNotFound(mErr) {
   191  			return nil, nil, errors.Trace(mErr)
   192  		}
   193  
   194  		if mig == nil || mig.ModelUserAccess(st.user) == permission.NoAccess {
   195  			return nil, nil, errors.Trace(err) // return original NotFound error
   196  		}
   197  
   198  		target, mErr := mig.TargetInfo()
   199  		if mErr != nil {
   200  			return nil, nil, errors.Trace(mErr)
   201  		}
   202  
   203  		hps, mErr := network.ParseProviderHostPorts(target.Addrs...)
   204  		if mErr != nil {
   205  			return nil, nil, errors.Trace(mErr)
   206  		}
   207  
   208  		return nil, nil, &apiservererrors.RedirectError{
   209  			Servers:         []network.ProviderHostPorts{hps},
   210  			CACert:          target.CACert,
   211  			ControllerAlias: target.ControllerAlias,
   212  		}
   213  	}
   214  	return modelManagerStateShim{otherState.State, otherModel, st.pool, st.user}, otherState.Release, nil
   215  }
   216  
   217  // GetModel implements ModelManagerBackend.
   218  func (st modelManagerStateShim) GetModel(modelUUID string) (Model, func() bool, error) {
   219  	model, hp, err := st.pool.GetModel(modelUUID)
   220  	if err != nil {
   221  		return nil, nil, errors.Trace(err)
   222  	}
   223  	return modelShim{model}, hp.Release, nil
   224  }
   225  
   226  // Model implements ModelManagerBackend.
   227  func (st modelManagerStateShim) Model() (Model, error) {
   228  	return modelShim{st.model}, nil
   229  }
   230  
   231  // Name implements ModelManagerBackend.
   232  func (st modelManagerStateShim) Name() string {
   233  	return st.model.Name()
   234  }
   235  
   236  func (st modelManagerStateShim) ControllerNodes() ([]ControllerNode, error) {
   237  	nodes, err := st.State.ControllerNodes()
   238  	if err != nil {
   239  		return nil, errors.Trace(err)
   240  	}
   241  	result := make([]ControllerNode, len(nodes))
   242  	for i, n := range nodes {
   243  		result[i] = n
   244  	}
   245  	return result, nil
   246  }
   247  
   248  func (st modelManagerStateShim) IsController() bool {
   249  	return st.State.IsController()
   250  }
   251  
   252  func (st modelManagerStateShim) ListModelSecrets(all bool) (map[string]set.Strings, error) {
   253  	secretsState := state.NewSecrets(st.State)
   254  	return secretsState.ListModelSecrets(all)
   255  }
   256  
   257  func (st modelManagerStateShim) ListSecretBackends() ([]*secrets.SecretBackend, error) {
   258  	backendState := state.NewSecretBackends(st.State)
   259  	return backendState.ListSecretBackends()
   260  }
   261  
   262  func (st modelManagerStateShim) GetSecretBackendByID(id string) (*secrets.SecretBackend, error) {
   263  	backendState := state.NewSecretBackends(st.State)
   264  	return backendState.GetSecretBackendByID(id)
   265  }
   266  
   267  var _ Model = (*modelShim)(nil)
   268  
   269  type modelShim struct {
   270  	*state.Model
   271  }
   272  
   273  // Users implements ModelManagerBackend.
   274  func (m modelShim) Users() ([]permission.UserAccess, error) {
   275  	stateUsers, err := m.Model.Users()
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  	users := make([]permission.UserAccess, len(stateUsers))
   280  	for i, user := range stateUsers {
   281  		users[i] = user
   282  	}
   283  	return users, nil
   284  }
   285  
   286  type machineShim struct {
   287  	*state.Machine
   288  }
   289  
   290  func (st modelManagerStateShim) AllMachines() ([]Machine, error) {
   291  	allStateMachines, err := st.State.AllMachines()
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  	all := make([]Machine, len(allStateMachines))
   296  	for i, m := range allStateMachines {
   297  		all[i] = machineShim{m}
   298  	}
   299  	return all, nil
   300  }
   301  
   302  // Application defines methods provided by a state.Application instance.
   303  type Application interface {
   304  	Name() string
   305  	UnitCount() int
   306  }
   307  
   308  type applicationShim struct {
   309  	*state.Application
   310  }
   311  
   312  func (st modelManagerStateShim) AllApplications() ([]Application, error) {
   313  	allStateApplications, err := st.State.AllApplications()
   314  	if err != nil {
   315  		return nil, err
   316  	}
   317  	all := make([]Application, len(allStateApplications))
   318  	for i, a := range allStateApplications {
   319  		all[i] = applicationShim{a}
   320  	}
   321  	return all, nil
   322  }
   323  
   324  func (st modelManagerStateShim) AllFilesystems() ([]state.Filesystem, error) {
   325  	sb, err := state.NewStorageBackend(st.State)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  	return sb.AllFilesystems()
   330  }
   331  
   332  func (st modelManagerStateShim) AllVolumes() ([]state.Volume, error) {
   333  	sb, err := state.NewStorageBackend(st.State)
   334  	if err != nil {
   335  		return nil, err
   336  	}
   337  	return sb.AllVolumes()
   338  }
   339  
   340  // ModelConfig returns the underlying model's config. Exposed here to satisfy the
   341  // ModelBackend interface.
   342  func (st modelManagerStateShim) ModelConfig() (*config.Config, error) {
   343  	model, err := st.State.Model()
   344  	if err != nil {
   345  		return nil, errors.Trace(err)
   346  	}
   347  	return model.ModelConfig()
   348  }
   349  
   350  // [TODO: Eric Claude Jones] This method ignores an error for the purpose of
   351  // expediting refactoring for CAAS features (we are avoiding changing method
   352  // signatures so that refactoring doesn't spiral out of control). This method
   353  // should be deleted immediately upon the removal of the ModelTag method from
   354  // state.State.
   355  func (st modelManagerStateShim) ModelTag() names.ModelTag {
   356  	return names.NewModelTag(st.ModelUUID())
   357  }