github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/unit_assignment_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state_test 5 6 import ( 7 "github.com/juju/errors" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 11 "github.com/juju/juju/core/constraints" 12 "github.com/juju/juju/core/instance" 13 "github.com/juju/juju/state" 14 ) 15 16 type UnitAssignmentSuite struct { 17 ConnSuite 18 } 19 20 var _ = gc.Suite(&UnitAssignmentSuite{}) 21 22 func (s *UnitAssignmentSuite) testAddApplicationUnitAssignment(c *gc.C) (*state.Application, []state.UnitAssignment) { 23 charm := s.AddTestingCharm(c, "dummy") 24 app, err := s.State.AddApplication(state.AddApplicationArgs{ 25 Name: "dummy", Charm: charm, NumUnits: 2, 26 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 27 OS: "ubuntu", 28 Channel: "22.04/stable", 29 }}, 30 Placement: []*instance.Placement{{s.State.ModelUUID(), "abc"}}, 31 }) 32 c.Assert(err, jc.ErrorIsNil) 33 units, err := app.AllUnits() 34 c.Assert(err, jc.ErrorIsNil) 35 c.Assert(units, gc.HasLen, 2) 36 for _, u := range units { 37 _, err := u.AssignedMachineId() 38 c.Assert(err, jc.Satisfies, errors.IsNotAssigned) 39 } 40 41 assignments, err := s.State.AllUnitAssignments() 42 c.Assert(err, jc.ErrorIsNil) 43 c.Assert(assignments, jc.SameContents, []state.UnitAssignment{ 44 {Unit: "dummy/0", Scope: s.State.ModelUUID(), Directive: "abc"}, 45 {Unit: "dummy/1"}, 46 }) 47 return app, assignments 48 } 49 50 func (s *UnitAssignmentSuite) TestAddApplicationUnitAssignment(c *gc.C) { 51 s.testAddApplicationUnitAssignment(c) 52 } 53 54 func (s *UnitAssignmentSuite) TestAssignStagedUnits(c *gc.C) { 55 app, _ := s.testAddApplicationUnitAssignment(c) 56 57 results, err := s.State.AssignStagedUnits([]string{ 58 "dummy/0", "dummy/1", 59 }) 60 c.Assert(err, jc.ErrorIsNil) 61 c.Assert(results, jc.SameContents, []state.UnitAssignmentResult{ 62 {Unit: "dummy/0"}, 63 {Unit: "dummy/1"}, 64 }) 65 66 units, err := app.AllUnits() 67 c.Assert(err, jc.ErrorIsNil) 68 c.Assert(units, gc.HasLen, 2) 69 for _, u := range units { 70 _, err := u.AssignedMachineId() 71 c.Assert(err, jc.ErrorIsNil) 72 } 73 74 // There should be no staged assignments now. 75 assignments, err := s.State.AllUnitAssignments() 76 c.Assert(err, jc.ErrorIsNil) 77 c.Assert(assignments, gc.HasLen, 0) 78 } 79 80 func (s *UnitAssignmentSuite) TestAssignUnitWithPlacementMakesContainerInNewMachine(c *gc.C) { 81 // Enables juju deploy <charm> --to <container-type> 82 // It creates a new machine with a new container of that type. 83 // https://bugs.launchpad.net/juju-core/+bug/1590960 84 charm := s.AddTestingCharm(c, "dummy") 85 placement := instance.Placement{Scope: "lxd"} 86 app, err := s.State.AddApplication(state.AddApplicationArgs{ 87 Name: "dummy", 88 Charm: charm, 89 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 90 OS: "ubuntu", 91 Channel: "22.04/stable", 92 }}, 93 NumUnits: 1, 94 Placement: []*instance.Placement{&placement}, 95 }) 96 c.Assert(err, jc.ErrorIsNil) 97 units, err := app.AllUnits() 98 c.Assert(err, jc.ErrorIsNil) 99 c.Assert(units, gc.HasLen, 1) 100 unit := units[0] 101 102 err = s.State.AssignUnitWithPlacement(unit, &placement) 103 c.Assert(err, jc.ErrorIsNil) 104 105 machineId, err := unit.AssignedMachineId() 106 c.Assert(err, jc.ErrorIsNil) 107 machine, err := s.State.Machine(machineId) 108 c.Assert(err, jc.ErrorIsNil) 109 parentId, isContainer := machine.ParentId() 110 c.Assert(isContainer, jc.IsTrue) 111 _, err = s.State.Machine(parentId) 112 c.Assert(err, jc.ErrorIsNil) 113 } 114 115 func (s *UnitAssignmentSuite) TestAssignUnitWithPlacementNewMachinesHaveBindingsAsConstraints(c *gc.C) { 116 specialSpace, err := s.State.AddSpace("special-space", "", nil, false) 117 c.Assert(err, jc.ErrorIsNil) 118 119 charm := s.AddTestingCharm(c, "dummy") 120 placement := instance.Placement{Scope: "lxd"} 121 app, err := s.State.AddApplication(state.AddApplicationArgs{ 122 Name: "dummy", 123 Charm: charm, 124 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 125 OS: "ubuntu", 126 Channel: "22.04/stable", 127 }}, 128 NumUnits: 1, 129 Placement: []*instance.Placement{&placement}, 130 EndpointBindings: map[string]string{ 131 "": specialSpace.Id(), 132 }, 133 }) 134 c.Assert(err, jc.ErrorIsNil) 135 136 units, err := app.AllUnits() 137 c.Assert(err, jc.ErrorIsNil) 138 c.Assert(units, gc.HasLen, 1) 139 unit := units[0] 140 141 err = s.State.AssignUnitWithPlacement(unit, &placement) 142 c.Assert(err, jc.ErrorIsNil) 143 144 guestID, err := unit.AssignedMachineId() 145 c.Assert(err, jc.ErrorIsNil) 146 147 guest, err := s.State.Machine(guestID) 148 c.Assert(err, jc.ErrorIsNil) 149 150 hostID, _ := guest.ParentId() 151 host, err := s.State.Machine(hostID) 152 c.Assert(err, jc.ErrorIsNil) 153 154 for _, m := range []*state.Machine{guest, host} { 155 cons, err := m.Constraints() 156 c.Assert(err, jc.ErrorIsNil) 157 c.Assert(cons.IncludeSpaces(), gc.DeepEquals, []string{"special-space"}) 158 } 159 } 160 161 func (s *UnitAssignmentSuite) TestAssignUnitWithPlacementNewMachinesHaveBindingsAsConstraintsMerged(c *gc.C) { 162 boundSpace, err := s.State.AddSpace("bound-space", "", nil, false) 163 c.Assert(err, jc.ErrorIsNil) 164 165 constrainedSpace, err := s.State.AddSpace("constrained-space", "", nil, false) 166 c.Assert(err, jc.ErrorIsNil) 167 168 charm := s.AddTestingCharm(c, "dummy") 169 placement := instance.Placement{Scope: "lxd"} 170 app, err := s.State.AddApplication(state.AddApplicationArgs{ 171 Name: "dummy", 172 Charm: charm, 173 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 174 OS: "ubuntu", 175 Channel: "22.04/stable", 176 }}, 177 NumUnits: 1, 178 Placement: []*instance.Placement{&placement}, 179 // Same space used in both bindings and constraints to test merging. 180 Constraints: constraints.MustParse("spaces=bound-space,constrained-space"), 181 EndpointBindings: map[string]string{ 182 "": boundSpace.Id(), 183 }, 184 }) 185 c.Assert(err, jc.ErrorIsNil) 186 187 units, err := app.AllUnits() 188 c.Assert(err, jc.ErrorIsNil) 189 c.Assert(units, gc.HasLen, 1) 190 unit := units[0] 191 192 err = s.State.AssignUnitWithPlacement(unit, &placement) 193 c.Assert(err, jc.ErrorIsNil) 194 195 guestID, err := unit.AssignedMachineId() 196 c.Assert(err, jc.ErrorIsNil) 197 198 guest, err := s.State.Machine(guestID) 199 c.Assert(err, jc.ErrorIsNil) 200 201 hostID, _ := guest.ParentId() 202 host, err := s.State.Machine(hostID) 203 c.Assert(err, jc.ErrorIsNil) 204 205 for _, m := range []*state.Machine{guest, host} { 206 cons, err := m.Constraints() 207 c.Assert(err, jc.ErrorIsNil) 208 c.Assert(cons.IncludeSpaces(), jc.SameContents, []string{boundSpace.Name(), constrainedSpace.Name()}) 209 } 210 } 211 212 func (s *UnitAssignmentSuite) TestAssignUnitWithPlacementDirective(c *gc.C) { 213 // Enables juju deploy <charm> --to <container-type> 214 // It creates a new machine with a new container of that type. 215 // https://bugs.launchpad.net/juju-core/+bug/1590960 216 charm := s.AddTestingCharm(c, "dummy") 217 placement := instance.Placement{Scope: s.State.ModelUUID(), Directive: "zone=test"} 218 app, err := s.State.AddApplication(state.AddApplicationArgs{ 219 Name: "dummy", 220 Charm: charm, 221 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 222 OS: "ubuntu", 223 Channel: "22.04/stable", 224 }}, 225 NumUnits: 1, 226 Placement: []*instance.Placement{&placement}, 227 }) 228 c.Assert(err, jc.ErrorIsNil) 229 units, err := app.AllUnits() 230 c.Assert(err, jc.ErrorIsNil) 231 c.Assert(units, gc.HasLen, 1) 232 unit := units[0] 233 234 err = s.State.AssignUnitWithPlacement(unit, &placement) 235 c.Assert(err, jc.ErrorIsNil) 236 237 machineId, err := unit.AssignedMachineId() 238 c.Assert(err, jc.ErrorIsNil) 239 machine, err := s.State.Machine(machineId) 240 c.Assert(err, jc.ErrorIsNil) 241 c.Assert(machine.Placement(), gc.Equals, "zone=test") 242 } 243 244 func (s *UnitAssignmentSuite) TestAssignUnitCleanMachineUpgradeSeriesLockError(c *gc.C) { 245 s.addLockedMachine(c, true) 246 247 charm := s.AddTestingCharm(c, "dummy") 248 app, err := s.State.AddApplication(state.AddApplicationArgs{ 249 Name: "dummy", 250 Charm: charm, 251 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 252 OS: "ubuntu", 253 Channel: "22.04/stable", 254 }}, 255 NumUnits: 1, 256 }) 257 c.Assert(err, jc.ErrorIsNil) 258 units, err := app.AllUnits() 259 c.Assert(err, jc.ErrorIsNil) 260 c.Assert(units, gc.HasLen, 1) 261 262 unit := units[0] 263 _, err = unit.AssignToCleanEmptyMachine() 264 c.Assert(err, gc.ErrorMatches, eligibleMachinesInUse) 265 } 266 267 func (s *UnitAssignmentSuite) TestAssignUnitMachinePlacementUpgradeSeriesLockError(c *gc.C) { 268 machine, _ := s.addLockedMachine(c, false) 269 // As in --to 0 270 s.testPlacementUpgradeSeriesLockError(c, &instance.Placement{Scope: "#", Directive: machine.Id()}) 271 } 272 273 func (s *UnitAssignmentSuite) TestAssignUnitContainerOnMachinePlacementUpgradeSeriesLockError(c *gc.C) { 274 machine, _ := s.addLockedMachine(c, false) 275 // As in --to lxd:0 276 s.testPlacementUpgradeSeriesLockError(c, &instance.Placement{Scope: "lxd", Directive: machine.Id()}) 277 } 278 279 func (s *UnitAssignmentSuite) TestAssignUnitExtantContainerOnMachinePlacementUpgradeSeriesLockError(c *gc.C) { 280 _, child := s.addLockedMachine(c, true) 281 282 // As in --to 0/lxd/0 283 s.testPlacementUpgradeSeriesLockError(c, &instance.Placement{Scope: "#", Directive: child.Id()}) 284 } 285 286 func (s *UnitAssignmentSuite) testPlacementUpgradeSeriesLockError(c *gc.C, placement *instance.Placement) { 287 charm := s.AddTestingCharm(c, "dummy") 288 app, err := s.State.AddApplication(state.AddApplicationArgs{ 289 Name: "dummy", 290 Charm: charm, 291 CharmOrigin: &state.CharmOrigin{Platform: &state.Platform{ 292 OS: "ubuntu", 293 Channel: "12.10/stable", 294 }}, 295 NumUnits: 1, 296 Placement: []*instance.Placement{placement}, 297 }) 298 c.Assert(err, jc.ErrorIsNil) 299 units, err := app.AllUnits() 300 c.Assert(err, jc.ErrorIsNil) 301 c.Assert(units, gc.HasLen, 1) 302 303 unit := units[0] 304 err = s.State.AssignUnitWithPlacement(unit, placement) 305 c.Assert(err, gc.ErrorMatches, ".* is locked for series upgrade") 306 } 307 308 func (s *UnitAssignmentSuite) addLockedMachine(c *gc.C, addContainer bool) (*state.Machine, *state.Machine) { 309 machine, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobHostUnits) 310 c.Assert(err, jc.ErrorIsNil) 311 312 var child *state.Machine 313 if addContainer { 314 template := state.MachineTemplate{ 315 Base: state.UbuntuBase("12.10"), 316 Jobs: []state.MachineJob{state.JobHostUnits}, 317 } 318 child, err = s.State.AddMachineInsideMachine(template, machine.Id(), "lxd") 319 c.Assert(err, jc.ErrorIsNil) 320 } 321 322 c.Assert(machine.CreateUpgradeSeriesLock(nil, state.UbuntuBase("22.04")), jc.ErrorIsNil) 323 return machine, child 324 }