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 }