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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/apiserver/common"
    13  	apiservererrors "github.com/juju/juju/apiserver/errors"
    14  	"github.com/juju/juju/apiserver/facade/facadetest"
    15  	"github.com/juju/juju/apiserver/facades/client/controller"
    16  	apiservertesting "github.com/juju/juju/apiserver/testing"
    17  	"github.com/juju/juju/core/arch"
    18  	"github.com/juju/juju/core/constraints"
    19  	"github.com/juju/juju/core/instance"
    20  	"github.com/juju/juju/core/life"
    21  	"github.com/juju/juju/environs"
    22  	"github.com/juju/juju/environs/config"
    23  	"github.com/juju/juju/environs/context"
    24  	"github.com/juju/juju/provider/dummy"
    25  	"github.com/juju/juju/rpc/params"
    26  	"github.com/juju/juju/state"
    27  	statetesting "github.com/juju/juju/state/testing"
    28  	"github.com/juju/juju/storage"
    29  	"github.com/juju/juju/storage/provider"
    30  	"github.com/juju/juju/testing"
    31  	"github.com/juju/juju/testing/factory"
    32  )
    33  
    34  type modelStatusSuite struct {
    35  	statetesting.StateSuite
    36  
    37  	controller *controller.ControllerAPI
    38  	resources  *common.Resources
    39  	authorizer apiservertesting.FakeAuthorizer
    40  }
    41  
    42  var _ = gc.Suite(&modelStatusSuite{})
    43  
    44  func (s *modelStatusSuite) SetUpTest(c *gc.C) {
    45  	// Initial config needs to be set before the StateSuite SetUpTest.
    46  	s.InitialConfig = testing.CustomModelConfig(c, testing.Attrs{
    47  		"name": "controller",
    48  	})
    49  	s.NewPolicy = func(*state.State) state.Policy {
    50  		return statePolicy{}
    51  	}
    52  
    53  	s.StateSuite.SetUpTest(c)
    54  	s.resources = common.NewResources()
    55  	s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() })
    56  
    57  	s.authorizer = apiservertesting.FakeAuthorizer{
    58  		Tag:      s.Owner,
    59  		AdminTag: s.Owner,
    60  	}
    61  
    62  	controller, err := controller.LatestAPI(
    63  		facadetest.Context{
    64  			State_:     s.State,
    65  			Resources_: s.resources,
    66  			Auth_:      s.authorizer,
    67  			StatePool_: s.StatePool,
    68  		})
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	s.controller = controller
    71  
    72  	loggo.GetLogger("juju.apiserver.controller").SetLogLevel(loggo.TRACE)
    73  }
    74  
    75  func (s *modelStatusSuite) TestModelStatusNonAuth(c *gc.C) {
    76  	// Set up the user making the call.
    77  	user := s.Factory.MakeUser(c, &factory.UserParams{NoModelUser: true})
    78  	anAuthoriser := apiservertesting.FakeAuthorizer{
    79  		Tag: user.Tag(),
    80  	}
    81  	endpoint, err := controller.TestingAPI(
    82  		facadetest.Context{
    83  			State_:     s.State,
    84  			StatePool_: s.StatePool,
    85  			Resources_: s.resources,
    86  			Auth_:      anAuthoriser,
    87  		})
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	controllerModelTag := s.Model.ModelTag().String()
    90  
    91  	req := params.Entities{
    92  		Entities: []params.Entity{{Tag: controllerModelTag}},
    93  	}
    94  	result, err := endpoint.ModelStatus(req)
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	c.Assert(result.Results[0].Error, gc.ErrorMatches, "permission denied")
    97  }
    98  
    99  func (s *modelStatusSuite) TestModelStatusOwnerAllowed(c *gc.C) {
   100  	// Set up the user making the call.
   101  	owner := s.Factory.MakeUser(c, nil)
   102  	anAuthoriser := apiservertesting.FakeAuthorizer{
   103  		Tag: owner.Tag(),
   104  	}
   105  	st := s.Factory.MakeModel(c, &factory.ModelParams{Owner: owner.Tag()})
   106  	defer st.Close()
   107  	endpoint, err := controller.TestingAPI(
   108  		facadetest.Context{
   109  			State_:     s.State,
   110  			Resources_: s.resources,
   111  			Auth_:      anAuthoriser,
   112  			StatePool_: s.StatePool,
   113  		})
   114  	c.Assert(err, jc.ErrorIsNil)
   115  
   116  	model, err := st.Model()
   117  	c.Assert(err, jc.ErrorIsNil)
   118  	req := params.Entities{
   119  		Entities: []params.Entity{{Tag: model.ModelTag().String()}},
   120  	}
   121  	_, err = endpoint.ModelStatus(req)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  }
   124  
   125  func (s *modelStatusSuite) TestModelStatus(c *gc.C) {
   126  	otherModelOwner := s.Factory.MakeModelUser(c, nil)
   127  	otherSt := s.Factory.MakeModel(c, &factory.ModelParams{
   128  		Name:  "dummytoo",
   129  		Owner: otherModelOwner.UserTag,
   130  		ConfigAttrs: testing.Attrs{
   131  			"controller": false,
   132  		},
   133  	})
   134  	defer otherSt.Close()
   135  
   136  	eight := uint64(8)
   137  	s.Factory.MakeMachine(c, &factory.MachineParams{
   138  		Jobs:            []state.MachineJob{state.JobManageModel},
   139  		Characteristics: &instance.HardwareCharacteristics{CpuCores: &eight},
   140  		InstanceId:      "id-4",
   141  		DisplayName:     "snowflake",
   142  		Volumes: []state.HostVolumeParams{{
   143  			Volume: state.VolumeParams{
   144  				Pool: "modelscoped",
   145  				Size: 123,
   146  			},
   147  		}},
   148  	})
   149  	s.Factory.MakeMachine(c, &factory.MachineParams{
   150  		Jobs:       []state.MachineJob{state.JobHostUnits},
   151  		InstanceId: "id-5",
   152  		Filesystems: []state.HostFilesystemParams{{
   153  			Filesystem: state.FilesystemParams{
   154  				Pool: "modelscoped",
   155  				Size: 123,
   156  			},
   157  		}, {
   158  			Filesystem: state.FilesystemParams{
   159  				Pool: "machinescoped",
   160  				Size: 123,
   161  			},
   162  		}},
   163  	})
   164  	s.Factory.MakeApplication(c, &factory.ApplicationParams{
   165  		Charm: s.Factory.MakeCharm(c, nil),
   166  	})
   167  
   168  	otherFactory := factory.NewFactory(otherSt, s.StatePool)
   169  	otherFactory.MakeMachine(c, &factory.MachineParams{InstanceId: "id-8"})
   170  	otherFactory.MakeMachine(c, &factory.MachineParams{InstanceId: "id-9"})
   171  	otherFactory.MakeApplication(c, &factory.ApplicationParams{
   172  		Charm: otherFactory.MakeCharm(c, nil),
   173  	})
   174  
   175  	otherModel, err := otherSt.Model()
   176  	c.Assert(err, jc.ErrorIsNil)
   177  
   178  	controllerModelTag := s.Model.ModelTag().String()
   179  	hostedModelTag := otherModel.ModelTag().String()
   180  
   181  	req := params.Entities{
   182  		Entities: []params.Entity{{Tag: controllerModelTag}, {Tag: hostedModelTag}},
   183  	}
   184  	results, err := s.controller.ModelStatus(req)
   185  	c.Assert(err, jc.ErrorIsNil)
   186  
   187  	arch := arch.DefaultArchitecture
   188  	mem := uint64(64 * 1024 * 1024 * 1024)
   189  	stdHw := &params.MachineHardware{
   190  		Arch: &arch,
   191  		Mem:  &mem,
   192  	}
   193  	c.Assert(results.Results, jc.DeepEquals, []params.ModelStatus{
   194  		{
   195  			ModelTag:           controllerModelTag,
   196  			HostedMachineCount: 1,
   197  			ApplicationCount:   1,
   198  			OwnerTag:           s.Owner.String(),
   199  			Life:               life.Alive,
   200  			Type:               string(state.ModelTypeIAAS),
   201  			Machines: []params.ModelMachineInfo{
   202  				{Id: "0", Hardware: &params.MachineHardware{Cores: &eight}, InstanceId: "id-4", DisplayName: "snowflake", Status: "pending", WantsVote: true},
   203  				{Id: "1", Hardware: stdHw, InstanceId: "id-5", Status: "pending"},
   204  			},
   205  			Applications: []params.ModelApplicationInfo{
   206  				{Name: "mysql"},
   207  			},
   208  			Volumes: []params.ModelVolumeInfo{{
   209  				Id: "0", Status: "pending", Detachable: true,
   210  			}},
   211  			Filesystems: []params.ModelFilesystemInfo{{
   212  				Id: "0", Status: "pending", Detachable: true,
   213  			}, {
   214  				Id: "1/1", Status: "pending", Detachable: false,
   215  			}},
   216  		},
   217  		{
   218  			ModelTag:           hostedModelTag,
   219  			HostedMachineCount: 2,
   220  			ApplicationCount:   1,
   221  			OwnerTag:           otherModelOwner.UserTag.String(),
   222  			Life:               life.Alive,
   223  			Type:               string(state.ModelTypeIAAS),
   224  			Machines: []params.ModelMachineInfo{
   225  				{Id: "0", Hardware: stdHw, InstanceId: "id-8", Status: "pending"},
   226  				{Id: "1", Hardware: stdHw, InstanceId: "id-9", Status: "pending"},
   227  			},
   228  			Applications: []params.ModelApplicationInfo{
   229  				{Name: "mysql"},
   230  			},
   231  		},
   232  	})
   233  }
   234  
   235  func (s *modelStatusSuite) TestModelStatusCAAS(c *gc.C) {
   236  	otherModelOwner := s.Factory.MakeModelUser(c, nil)
   237  	otherSt := s.Factory.MakeCAASModel(c, &factory.ModelParams{
   238  		Owner: otherModelOwner.UserTag,
   239  		ConfigAttrs: testing.Attrs{
   240  			"controller": false,
   241  		},
   242  	})
   243  	defer otherSt.Close()
   244  
   245  	otherFactory := factory.NewFactory(otherSt, s.StatePool)
   246  	app := otherFactory.MakeApplication(c, &factory.ApplicationParams{
   247  		Charm: otherFactory.MakeCharm(c, &factory.CharmParams{Name: "gitlab", Series: "kubernetes"}),
   248  	})
   249  	otherFactory.MakeUnit(c, &factory.UnitParams{
   250  		Application: app,
   251  	})
   252  
   253  	otherModel, err := otherSt.Model()
   254  	c.Assert(err, jc.ErrorIsNil)
   255  
   256  	controllerModelTag := s.Model.ModelTag().String()
   257  	hostedModelTag := otherModel.ModelTag().String()
   258  
   259  	req := params.Entities{
   260  		Entities: []params.Entity{{Tag: controllerModelTag}, {Tag: hostedModelTag}},
   261  	}
   262  	results, err := s.controller.ModelStatus(req)
   263  	c.Assert(err, jc.ErrorIsNil)
   264  
   265  	c.Assert(results.Results, jc.DeepEquals, []params.ModelStatus{
   266  		{
   267  			ModelTag:           controllerModelTag,
   268  			HostedMachineCount: 0,
   269  			ApplicationCount:   0,
   270  			OwnerTag:           s.Owner.String(),
   271  			Life:               life.Alive,
   272  			Type:               string(state.ModelTypeIAAS),
   273  			Applications:       []params.ModelApplicationInfo{},
   274  		},
   275  		{
   276  			ModelTag:           hostedModelTag,
   277  			HostedMachineCount: 0,
   278  			ApplicationCount:   1,
   279  			UnitCount:          1,
   280  			OwnerTag:           otherModelOwner.UserTag.String(),
   281  			Life:               life.Alive,
   282  			Type:               string(state.ModelTypeCAAS),
   283  			Applications: []params.ModelApplicationInfo{
   284  				{Name: "gitlab"},
   285  			},
   286  		},
   287  	})
   288  }
   289  
   290  func (s *modelStatusSuite) TestModelStatusRunsForAllModels(c *gc.C) {
   291  	req := params.Entities{
   292  		Entities: []params.Entity{
   293  			{Tag: "fail.me"},
   294  			{Tag: s.Model.ModelTag().String()},
   295  		},
   296  	}
   297  	expected := params.ModelStatusResults{
   298  		Results: []params.ModelStatus{
   299  			{
   300  				Error: apiservererrors.ServerError(errors.New(`"fail.me" is not a valid tag`))},
   301  			{
   302  				ModelTag: s.Model.ModelTag().String(),
   303  				Life:     life.Value(s.Model.Life().String()),
   304  				OwnerTag: s.Model.Owner().String(),
   305  				Type:     string(state.ModelTypeIAAS),
   306  			},
   307  		},
   308  	}
   309  	result, err := s.controller.ModelStatus(req)
   310  	c.Assert(err, jc.ErrorIsNil)
   311  	c.Assert(result, jc.DeepEquals, expected)
   312  }
   313  
   314  type statePolicy struct{}
   315  
   316  func (statePolicy) Prechecker() (environs.InstancePrechecker, error) {
   317  	return nil, errors.NotImplementedf("Prechecker")
   318  }
   319  
   320  func (statePolicy) ConfigValidator() (config.Validator, error) {
   321  	return nil, errors.NotImplementedf("ConfigValidator")
   322  }
   323  
   324  func (statePolicy) ConstraintsValidator(context.ProviderCallContext) (constraints.Validator, error) {
   325  	return nil, errors.NotImplementedf("ConstraintsValidator")
   326  }
   327  
   328  func (statePolicy) InstanceDistributor() (context.Distributor, error) {
   329  	return nil, errors.NotImplementedf("InstanceDistributor")
   330  }
   331  
   332  func (statePolicy) StorageProviderRegistry() (storage.ProviderRegistry, error) {
   333  	return storage.ChainedProviderRegistry{
   334  		dummy.StorageProviders(),
   335  		provider.CommonStorageProviders(),
   336  	}, nil
   337  }
   338  
   339  func (statePolicy) ProviderConfigSchemaSource(cloudName string) (config.ConfigSchemaSource, error) {
   340  	return nil, errors.NotImplementedf("ConfigSchemaSource")
   341  }