github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/controller_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/collections/set"
    11  	"github.com/juju/errors"
    12  	mgotesting "github.com/juju/mgo/v3/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/controller"
    17  	"github.com/juju/juju/core/model"
    18  	"github.com/juju/juju/core/network"
    19  	"github.com/juju/juju/state"
    20  	"github.com/juju/juju/testing/factory"
    21  )
    22  
    23  type ControllerSuite struct {
    24  	ConnSuite
    25  }
    26  
    27  var _ = gc.Suite(&ControllerSuite{})
    28  
    29  func (s *ControllerSuite) TestControllerAndModelConfigInitialisation(c *gc.C) {
    30  	// Test setup has created model using a fully populated environs.Config.
    31  	// This test ensure that the controller specific attributes have been separated out.
    32  	controllerSettings, err := s.State.ReadSettings(state.ControllersC, "controllerSettings")
    33  	c.Assert(err, jc.ErrorIsNil)
    34  
    35  	optional := set.NewStrings(
    36  		controller.AgentRateLimitMax,
    37  		controller.AgentRateLimitRate,
    38  		controller.AllowModelAccessKey,
    39  		controller.APIPortOpenDelay,
    40  		controller.AuditLogExcludeMethods,
    41  		controller.AutocertURLKey,
    42  		controller.AutocertDNSNameKey,
    43  		controller.CAASImageRepo,
    44  		controller.CAASOperatorImagePath,
    45  		controller.ControllerAPIPort,
    46  		controller.ControllerName,
    47  		controller.Features,
    48  		controller.IdentityURL,
    49  		controller.IdentityPublicKey,
    50  		controller.LoginTokenRefreshURL,
    51  		controller.JujuDBSnapChannel,
    52  		controller.JujuHASpace,
    53  		controller.JujuManagementSpace,
    54  		controller.MaxDebugLogDuration,
    55  		controller.MaxPruneTxnBatchSize,
    56  		controller.MaxPruneTxnPasses,
    57  		controller.MeteringURL,
    58  		controller.ModelLogfileMaxBackups,
    59  		controller.ModelLogfileMaxSize,
    60  		controller.MongoMemoryProfile,
    61  		controller.PruneTxnQueryCount,
    62  		controller.PruneTxnSleepTime,
    63  		controller.PublicDNSAddress,
    64  		controller.MaxCharmStateSize,
    65  		controller.MaxAgentStateSize,
    66  		controller.MigrationMinionWaitMax,
    67  		controller.AgentLogfileMaxBackups,
    68  		controller.AgentLogfileMaxSize,
    69  		controller.ControllerResourceDownloadLimit,
    70  		controller.ApplicationResourceDownloadLimit,
    71  		controller.QueryTracingEnabled,
    72  		controller.QueryTracingThreshold,
    73  		controller.JujudControllerSnapSource,
    74  	)
    75  	for _, controllerAttr := range controller.ControllerOnlyConfigAttributes {
    76  		v, ok := controllerSettings.Get(controllerAttr)
    77  		c.Logf(controllerAttr)
    78  		if !optional.Contains(controllerAttr) {
    79  			c.Check(ok, jc.IsTrue)
    80  			c.Check(v, gc.Not(gc.Equals), "")
    81  		}
    82  	}
    83  }
    84  
    85  func (s *ControllerSuite) TestNewState(c *gc.C) {
    86  	st, err := s.Controller.GetState(s.Model.ModelTag())
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	defer st.Close()
    89  	c.Check(st.ModelUUID(), gc.Equals, s.State.ModelUUID())
    90  	c.Check(st, gc.Not(gc.Equals), s.State)
    91  }
    92  
    93  func (s *ControllerSuite) TestControllerConfig(c *gc.C) {
    94  	cfg, err := s.State.ControllerConfig()
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	c.Assert(cfg["controller-uuid"], gc.Equals, s.State.ControllerUUID())
    97  }
    98  
    99  func (s *ControllerSuite) TestPing(c *gc.C) {
   100  	c.Assert(s.Controller.Ping(), gc.IsNil)
   101  	mgotesting.MgoServer.Restart()
   102  	c.Assert(s.Controller.Ping(), gc.NotNil)
   103  }
   104  
   105  func (s *ControllerSuite) TestUpdateControllerConfig(c *gc.C) {
   106  	cfg, err := s.State.ControllerConfig()
   107  	c.Assert(err, jc.ErrorIsNil)
   108  	// Sanity check.
   109  	c.Check(cfg.AuditingEnabled(), gc.Equals, false)
   110  	c.Check(cfg.AuditLogCaptureArgs(), gc.Equals, true)
   111  	c.Assert(cfg.PublicDNSAddress(), gc.Equals, "")
   112  
   113  	err = s.State.UpdateControllerConfig(map[string]interface{}{
   114  		controller.AuditingEnabled:     true,
   115  		controller.AuditLogCaptureArgs: false,
   116  		controller.AuditLogMaxBackups:  "10",
   117  		controller.PublicDNSAddress:    "controller.test.com:1234",
   118  		controller.APIPortOpenDelay:    "100ms",
   119  	}, nil)
   120  	c.Assert(err, jc.ErrorIsNil)
   121  
   122  	newCfg, err := s.State.ControllerConfig()
   123  	c.Assert(err, jc.ErrorIsNil)
   124  
   125  	c.Assert(newCfg.AuditingEnabled(), gc.Equals, true)
   126  	c.Assert(newCfg.AuditLogCaptureArgs(), gc.Equals, false)
   127  	c.Assert(newCfg.AuditLogMaxBackups(), gc.Equals, 10)
   128  	c.Assert(newCfg.PublicDNSAddress(), gc.Equals, "controller.test.com:1234")
   129  	c.Assert(newCfg.APIPortOpenDelay(), gc.Equals, 100*time.Millisecond)
   130  }
   131  
   132  func (s *ControllerSuite) TestUpdateControllerConfigRemoveYieldsDefaults(c *gc.C) {
   133  	err := s.State.UpdateControllerConfig(map[string]interface{}{
   134  		controller.AuditingEnabled:     true,
   135  		controller.AuditLogCaptureArgs: true,
   136  	}, nil)
   137  	c.Assert(err, jc.ErrorIsNil)
   138  
   139  	err = s.State.UpdateControllerConfig(nil, []string{
   140  		controller.AuditLogCaptureArgs,
   141  	})
   142  	c.Assert(err, jc.ErrorIsNil)
   143  
   144  	newCfg, err := s.State.ControllerConfig()
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	c.Assert(newCfg.AuditLogCaptureArgs(), gc.Equals, false)
   148  }
   149  
   150  func (s *ControllerSuite) TestUpdateControllerConfigRejectsDisallowedUpdates(c *gc.C) {
   151  	// Sanity check.
   152  	c.Assert(controller.AllowedUpdateConfigAttributes.Contains(controller.APIPort), jc.IsFalse)
   153  
   154  	err := s.State.UpdateControllerConfig(map[string]interface{}{
   155  		controller.APIPort: 1234,
   156  	}, nil)
   157  	c.Assert(err, gc.ErrorMatches, `can't change "api-port" after bootstrap`)
   158  
   159  	err = s.State.UpdateControllerConfig(nil, []string{controller.APIPort})
   160  	c.Assert(err, gc.ErrorMatches, `can't change "api-port" after bootstrap`)
   161  }
   162  
   163  func (s *ControllerSuite) TestUpdateControllerConfigChecksSchema(c *gc.C) {
   164  	err := s.State.UpdateControllerConfig(map[string]interface{}{
   165  		controller.AuditLogExcludeMethods: []int{1, 2, 3},
   166  	}, nil)
   167  	c.Assert(err, gc.ErrorMatches, `audit-log-exclude-methods\[0\]: expected string, got int\(1\)`)
   168  }
   169  
   170  func (s *ControllerSuite) TestUpdateControllerConfigValidates(c *gc.C) {
   171  	err := s.State.UpdateControllerConfig(map[string]interface{}{
   172  		controller.AuditLogExcludeMethods: []string{"thing"},
   173  	}, nil)
   174  	c.Assert(err, gc.ErrorMatches, `invalid audit log exclude methods: should be a list of "Facade.Method" names \(or "ReadOnlyMethods"\), got "thing" at position 1`)
   175  }
   176  
   177  func (s *ControllerSuite) TestUpdatingUnknownName(c *gc.C) {
   178  	err := s.State.UpdateControllerConfig(map[string]interface{}{
   179  		"ana-ng": "majestic",
   180  	}, nil)
   181  	c.Assert(err, gc.ErrorMatches, `unknown controller config setting "ana-ng"`)
   182  }
   183  
   184  func (s *ControllerSuite) TestRemovingUnknownName(c *gc.C) {
   185  	err := s.State.UpdateControllerConfig(nil, []string{"dr-worm"})
   186  	c.Assert(err, gc.ErrorMatches, `unknown controller config setting "dr-worm"`)
   187  }
   188  
   189  func (s *ControllerSuite) TestUpdateControllerConfigRejectsSpaceWithoutAddresses(c *gc.C) {
   190  	_, err := s.State.AddSpace("mgmt-space", "", nil, false)
   191  	c.Assert(err, jc.ErrorIsNil)
   192  
   193  	m, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobManageModel, state.JobHostUnits)
   194  	c.Assert(err, jc.ErrorIsNil)
   195  	c.Assert(m.SetMachineAddresses(network.NewSpaceAddress("192.168.9.9")), jc.ErrorIsNil)
   196  
   197  	err = s.State.UpdateControllerConfig(map[string]interface{}{
   198  		controller.JujuManagementSpace: "mgmt-space",
   199  	}, nil)
   200  	c.Assert(err, gc.ErrorMatches,
   201  		`invalid config "juju-mgmt-space"="mgmt-space": machines with no addresses in this space: 0`)
   202  }
   203  
   204  func (s *ControllerSuite) TestUpdateControllerConfigAcceptsSpaceWithAddresses(c *gc.C) {
   205  	sp, err := s.State.AddSpace("mgmt-space", "", nil, false)
   206  	c.Assert(err, jc.ErrorIsNil)
   207  
   208  	m, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobManageModel, state.JobHostUnits)
   209  	c.Assert(err, jc.ErrorIsNil)
   210  
   211  	addr := network.NewSpaceAddress("192.168.9.9")
   212  	addr.SpaceID = sp.Id()
   213  
   214  	c.Assert(m.SetProviderAddresses(addr), jc.ErrorIsNil)
   215  
   216  	err = s.State.UpdateControllerConfig(map[string]interface{}{
   217  		controller.JujuManagementSpace: "mgmt-space",
   218  	}, nil)
   219  	c.Assert(err, jc.ErrorIsNil)
   220  }
   221  
   222  func (s *ControllerSuite) TestControllerInfo(c *gc.C) {
   223  	info, err := s.State.ControllerInfo()
   224  	c.Assert(err, jc.ErrorIsNil)
   225  	c.Assert(info.CloudName, gc.Equals, "dummy")
   226  	c.Assert(info.ModelTag, gc.Equals, s.modelTag)
   227  	c.Assert(info.ControllerIds, gc.HasLen, 0)
   228  
   229  	node, err := s.State.AddControllerNode()
   230  	c.Assert(err, jc.ErrorIsNil)
   231  	info, err = s.State.ControllerInfo()
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	c.Assert(info.ControllerIds, jc.DeepEquals, []string{node.Id()})
   234  }
   235  
   236  func (s *ControllerSuite) TestSetMachineAddressesControllerCharm(c *gc.C) {
   237  	controller, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobManageModel, state.JobHostUnits)
   238  	c.Assert(err, jc.ErrorIsNil)
   239  	worker, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobHostUnits)
   240  	c.Assert(err, jc.ErrorIsNil)
   241  
   242  	controllerApp := s.AddTestingApplication(c, "controller", s.AddTestingCharm(c, "juju-controller"))
   243  	s.Factory.MakeUnit(c, &factory.UnitParams{
   244  		Application: controllerApp,
   245  		Machine:     controller,
   246  	})
   247  
   248  	addresses := network.NewSpaceAddresses("10.0.0.1")
   249  	err = controller.SetMachineAddresses(addresses...)
   250  	c.Assert(err, jc.ErrorIsNil)
   251  
   252  	// Updating a worker machine does not affect charm config.
   253  	addresses = network.NewSpaceAddresses("10.0.0.2")
   254  	err = worker.SetMachineAddresses(addresses...)
   255  	c.Assert(err, jc.ErrorIsNil)
   256  
   257  	cfg, err := controllerApp.CharmConfig(model.GenerationMaster)
   258  	c.Assert(err, jc.ErrorIsNil)
   259  	c.Assert(cfg["controller-url"], gc.Equals, "wss://10.0.0.1:17777/api")
   260  }
   261  
   262  func (s *ControllerSuite) testOpenParams() state.OpenParams {
   263  	return state.OpenParams{
   264  		Clock:              clock.WallClock,
   265  		ControllerTag:      s.State.ControllerTag(),
   266  		ControllerModelTag: s.modelTag,
   267  		MongoSession:       s.Session,
   268  	}
   269  }
   270  
   271  func (s *ControllerSuite) TestReopenWithNoMachines(c *gc.C) {
   272  	expected := &state.ControllerInfo{
   273  		CloudName: "dummy",
   274  		ModelTag:  s.modelTag,
   275  	}
   276  	info, err := s.State.ControllerInfo()
   277  	c.Assert(err, jc.ErrorIsNil)
   278  	c.Assert(info, jc.DeepEquals, expected)
   279  
   280  	controller, err := state.OpenController(s.testOpenParams())
   281  	c.Assert(err, jc.ErrorIsNil)
   282  	defer controller.Close()
   283  	st, err := controller.SystemState()
   284  	c.Assert(err, jc.ErrorIsNil)
   285  
   286  	info, err = st.ControllerInfo()
   287  	c.Assert(err, jc.ErrorIsNil)
   288  	c.Assert(info, jc.DeepEquals, expected)
   289  }
   290  
   291  func (s *ControllerSuite) TestStateServingInfo(c *gc.C) {
   292  	_, err := s.State.StateServingInfo()
   293  	c.Assert(err, gc.ErrorMatches, "state serving info not found")
   294  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   295  
   296  	data := controller.StateServingInfo{
   297  		APIPort:      69,
   298  		StatePort:    80,
   299  		Cert:         "Some cert",
   300  		PrivateKey:   "Some key",
   301  		SharedSecret: "Some Keyfile",
   302  	}
   303  	err = s.State.SetStateServingInfo(data)
   304  	c.Assert(err, jc.ErrorIsNil)
   305  
   306  	info, err := s.State.StateServingInfo()
   307  	c.Assert(err, jc.ErrorIsNil)
   308  	c.Assert(info, jc.DeepEquals, data)
   309  }
   310  
   311  var setStateServingInfoWithInvalidInfoTests = []func(info *controller.StateServingInfo){
   312  	func(info *controller.StateServingInfo) { info.APIPort = 0 },
   313  	func(info *controller.StateServingInfo) { info.StatePort = 0 },
   314  	func(info *controller.StateServingInfo) { info.Cert = "" },
   315  	func(info *controller.StateServingInfo) { info.PrivateKey = "" },
   316  }
   317  
   318  func (s *ControllerSuite) TestSetStateServingInfoWithInvalidInfo(c *gc.C) {
   319  	origData := controller.StateServingInfo{
   320  		APIPort:      69,
   321  		StatePort:    80,
   322  		Cert:         "Some cert",
   323  		PrivateKey:   "Some key",
   324  		SharedSecret: "Some Keyfile",
   325  	}
   326  	for i, test := range setStateServingInfoWithInvalidInfoTests {
   327  		c.Logf("test %d", i)
   328  		data := origData
   329  		test(&data)
   330  		err := s.State.SetStateServingInfo(data)
   331  		c.Assert(err, gc.ErrorMatches, "incomplete state serving info set in state")
   332  	}
   333  }