github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/firewaller/firewaller_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewaller_test 5 6 import ( 7 "sort" 8 9 "github.com/juju/names/v5" 10 jc "github.com/juju/testing/checkers" 11 "go.uber.org/mock/gomock" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/common/cloudspec" 16 commontesting "github.com/juju/juju/apiserver/common/testing" 17 "github.com/juju/juju/apiserver/facade" 18 "github.com/juju/juju/apiserver/facades/controller/firewaller" 19 "github.com/juju/juju/apiserver/facades/controller/firewaller/mocks" 20 apiservertesting "github.com/juju/juju/apiserver/testing" 21 "github.com/juju/juju/core/network" 22 "github.com/juju/juju/rpc/params" 23 "github.com/juju/juju/state" 24 statetesting "github.com/juju/juju/state/testing" 25 ) 26 27 type firewallerSuite struct { 28 firewallerBaseSuite 29 *commontesting.ModelWatcherTest 30 31 firewaller *firewaller.FirewallerAPI 32 subnet *state.Subnet 33 34 ctrl *gomock.Controller 35 } 36 37 var _ = gc.Suite(&firewallerSuite{}) 38 39 func (s *firewallerSuite) SetUpTest(c *gc.C) { 40 s.firewallerBaseSuite.setUpTest(c) 41 42 subnet, err := s.State.AddSubnet(network.SubnetInfo{CIDR: "10.20.30.0/24"}) 43 c.Assert(err, jc.ErrorIsNil) 44 s.subnet = subnet 45 46 cloudSpecAPI := cloudspec.NewCloudSpec( 47 s.resources, 48 cloudspec.MakeCloudSpecGetterForModel(s.State), 49 cloudspec.MakeCloudSpecWatcherForModel(s.State), 50 cloudspec.MakeCloudSpecCredentialWatcherForModel(s.State), 51 cloudspec.MakeCloudSpecCredentialContentWatcherForModel(s.State), 52 common.AuthFuncForTag(s.Model.ModelTag()), 53 ) 54 55 s.ctrl = gomock.NewController(c) 56 controllerConfigAPI := mocks.NewMockControllerConfigAPI(s.ctrl) 57 // Create a firewaller API for the machine. 58 firewallerAPI, err := firewaller.NewStateFirewallerAPI( 59 firewaller.StateShim(s.State, s.Model), 60 s.resources, 61 s.authorizer, 62 cloudSpecAPI, 63 controllerConfigAPI, 64 ) 65 c.Assert(err, jc.ErrorIsNil) 66 s.firewaller = firewallerAPI 67 s.ModelWatcherTest = commontesting.NewModelWatcherTest(s.firewaller, s.State, s.resources) 68 } 69 70 func (s *firewallerSuite) TestFirewallerFailsWithNonControllerUser(c *gc.C) { 71 defer s.ctrl.Finish() 72 73 constructor := func(context facade.Context) error { 74 _, err := firewaller.NewFirewallerAPIV7(context) 75 return err 76 } 77 s.testFirewallerFailsWithNonControllerUser(c, constructor) 78 } 79 80 func (s *firewallerSuite) TestLife(c *gc.C) { 81 defer s.ctrl.Finish() 82 83 s.testLife(c, s.firewaller) 84 } 85 86 func (s *firewallerSuite) TestInstanceId(c *gc.C) { 87 defer s.ctrl.Finish() 88 89 s.testInstanceId(c, s.firewaller) 90 } 91 92 func (s *firewallerSuite) TestWatchModelMachines(c *gc.C) { 93 defer s.ctrl.Finish() 94 95 s.testWatchModelMachines(c, s.firewaller) 96 } 97 98 func (s *firewallerSuite) TestWatch(c *gc.C) { 99 defer s.ctrl.Finish() 100 101 s.testWatch(c, s.firewaller, cannotWatchUnits) 102 } 103 104 func (s *firewallerSuite) TestWatchUnits(c *gc.C) { 105 s.testWatchUnits(c, s.firewaller) 106 } 107 108 func (s *firewallerSuite) TestGetAssignedMachine(c *gc.C) { 109 defer s.ctrl.Finish() 110 111 s.testGetAssignedMachine(c, s.firewaller) 112 } 113 114 func (s *firewallerSuite) openPorts(c *gc.C) { 115 // Open some ports on the units. 116 allEndpoints := "" 117 s.mustOpenPorts(c, s.units[0], allEndpoints, []network.PortRange{ 118 network.MustParsePortRange("1234-1400/tcp"), 119 network.MustParsePortRange("4321/tcp"), 120 }) 121 s.mustOpenPorts(c, s.units[2], allEndpoints, []network.PortRange{ 122 network.MustParsePortRange("1111-2222/udp"), 123 }) 124 } 125 126 func (s *firewallerSuite) mustOpenPorts(c *gc.C, unit *state.Unit, endpointName string, portRanges []network.PortRange) { 127 unitPortRanges, err := unit.OpenedPortRanges() 128 c.Assert(err, jc.ErrorIsNil) 129 130 for _, pr := range portRanges { 131 unitPortRanges.Open(endpointName, pr) 132 } 133 134 c.Assert(s.State.ApplyOperation(unitPortRanges.Changes()), jc.ErrorIsNil) 135 } 136 137 func (s *firewallerSuite) TestWatchOpenedPorts(c *gc.C) { 138 defer s.ctrl.Finish() 139 140 c.Assert(s.resources.Count(), gc.Equals, 0) 141 142 s.openPorts(c) 143 expectChanges := []string{ // machine IDs 144 "0", 145 "2", 146 } 147 148 fakeModelTag := names.NewModelTag("deadbeef-deaf-face-feed-0123456789ab") 149 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 150 {Tag: fakeModelTag.String()}, 151 {Tag: s.machines[0].Tag().String()}, 152 {Tag: s.application.Tag().String()}, 153 {Tag: s.units[0].Tag().String()}, 154 }}) 155 result, err := s.firewaller.WatchOpenedPorts(args) 156 sort.Strings(result.Results[0].Changes) 157 c.Assert(err, jc.ErrorIsNil) 158 c.Assert(result, jc.DeepEquals, params.StringsWatchResults{ 159 Results: []params.StringsWatchResult{ 160 {Changes: expectChanges, StringsWatcherId: "1"}, 161 {Error: apiservertesting.ErrUnauthorized}, 162 {Error: apiservertesting.ErrUnauthorized}, 163 {Error: apiservertesting.ErrUnauthorized}, 164 {Error: apiservertesting.ErrUnauthorized}, 165 {Error: apiservertesting.ErrUnauthorized}, 166 {Error: apiservertesting.ErrUnauthorized}, 167 {Error: apiservertesting.ErrUnauthorized}, 168 {Error: apiservertesting.ErrUnauthorized}, 169 {Error: apiservertesting.ErrUnauthorized}, 170 }, 171 }) 172 173 // Verify the resource was registered and stop when done 174 c.Assert(s.resources.Count(), gc.Equals, 1) 175 c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1") 176 resource := s.resources.Get("1") 177 defer statetesting.AssertStop(c, resource) 178 179 // Check that the Watch has consumed the initial event ("returned" in 180 // the Watch call) 181 wc := statetesting.NewStringsWatcherC(c, resource.(state.StringsWatcher)) 182 wc.AssertNoChange() 183 } 184 185 func (s *firewallerSuite) TestAreManuallyProvisioned(c *gc.C) { 186 defer s.ctrl.Finish() 187 188 m, err := s.State.AddOneMachine(state.MachineTemplate{ 189 Base: state.UbuntuBase("12.10"), 190 Jobs: []state.MachineJob{state.JobHostUnits}, 191 InstanceId: "2", 192 Nonce: "manual:", 193 }) 194 c.Assert(err, jc.ErrorIsNil) 195 196 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 197 {Tag: s.machines[0].Tag().String()}, 198 {Tag: s.machines[1].Tag().String()}, 199 {Tag: m.Tag().String()}, 200 {Tag: s.application.Tag().String()}, 201 {Tag: s.units[0].Tag().String()}, 202 }}) 203 204 result, err := s.firewaller.AreManuallyProvisioned(args) 205 c.Assert(err, jc.ErrorIsNil) 206 c.Assert(result, jc.DeepEquals, params.BoolResults{ 207 Results: []params.BoolResult{ 208 {Result: false, Error: nil}, 209 {Result: false, Error: nil}, 210 {Result: true, Error: nil}, 211 {Result: false, Error: apiservertesting.ServerError(`"application-wordpress" is not a valid machine tag`)}, 212 {Result: false, Error: apiservertesting.ServerError(`"unit-wordpress-0" is not a valid machine tag`)}, 213 {Result: false, Error: apiservertesting.NotFoundError("machine 42")}, 214 {Result: false, Error: apiservertesting.ServerError(`"unit-foo-0" is not a valid machine tag`)}, 215 {Result: false, Error: apiservertesting.ServerError(`"application-bar" is not a valid machine tag`)}, 216 {Result: false, Error: apiservertesting.ServerError(`"user-foo" is not a valid machine tag`)}, 217 {Result: false, Error: apiservertesting.ServerError(`"foo-bar" is not a valid tag`)}, 218 {Result: false, Error: apiservertesting.ServerError(`"" is not a valid tag`)}, 219 }, 220 }) 221 } 222 223 func (s *firewallerSuite) TestGetExposeInfo(c *gc.C) { 224 defer s.ctrl.Finish() 225 226 // Set the application to exposed first. 227 err := s.application.MergeExposeSettings(map[string]state.ExposedEndpoint{ 228 "": { 229 ExposeToSpaceIDs: []string{network.AlphaSpaceId}, 230 ExposeToCIDRs: []string{"10.0.0.0/0"}, 231 }, 232 }) 233 c.Assert(err, jc.ErrorIsNil) 234 235 args := addFakeEntities(params.Entities{Entities: []params.Entity{ 236 {Tag: s.application.Tag().String()}, 237 }}) 238 result, err := s.firewaller.GetExposeInfo(args) 239 c.Assert(err, jc.ErrorIsNil) 240 c.Assert(result, jc.DeepEquals, params.ExposeInfoResults{ 241 Results: []params.ExposeInfoResult{ 242 { 243 Exposed: true, 244 ExposedEndpoints: map[string]params.ExposedEndpoint{ 245 "": { 246 ExposeToSpaces: []string{network.AlphaSpaceId}, 247 ExposeToCIDRs: []string{"10.0.0.0/0"}, 248 }, 249 }, 250 }, 251 {Error: apiservertesting.ErrUnauthorized}, 252 {Error: apiservertesting.ErrUnauthorized}, 253 {Error: apiservertesting.NotFoundError(`application "bar"`)}, 254 {Error: apiservertesting.ErrUnauthorized}, 255 {Error: apiservertesting.ErrUnauthorized}, 256 {Error: apiservertesting.ErrUnauthorized}, 257 }, 258 }) 259 260 // Now reset the exposed flag for the application and check again. 261 err = s.application.ClearExposed() 262 c.Assert(err, jc.ErrorIsNil) 263 264 args = params.Entities{Entities: []params.Entity{ 265 {Tag: s.application.Tag().String()}, 266 }} 267 result, err = s.firewaller.GetExposeInfo(args) 268 c.Assert(err, jc.ErrorIsNil) 269 c.Assert(result, jc.DeepEquals, params.ExposeInfoResults{ 270 Results: []params.ExposeInfoResult{ 271 {Exposed: false}, 272 }, 273 }) 274 } 275 276 func (s *firewallerSuite) TestWatchSubnets(c *gc.C) { 277 defer s.ctrl.Finish() 278 279 // Set up a spaces with two subnets 280 sp, err := s.State.AddSpace("outer-space", network.Id("outer-1"), nil, true) 281 c.Assert(err, jc.ErrorIsNil) 282 _, err = s.State.AddSubnet(network.SubnetInfo{ 283 CIDR: "192.168.0.0/24", 284 SpaceID: sp.Id(), 285 SpaceName: sp.Name(), 286 }) 287 c.Assert(err, jc.ErrorIsNil) 288 sub2, err := s.State.AddSubnet(network.SubnetInfo{ 289 CIDR: "192.168.42.0/24", 290 SpaceID: sp.Id(), 291 SpaceName: sp.Name(), 292 }) 293 c.Assert(err, jc.ErrorIsNil) 294 295 s.WaitForModelWatchersIdle(c, s.State.ModelUUID()) 296 c.Assert(s.resources.Count(), gc.Equals, 0) 297 298 watchSubnetTags := []names.SubnetTag{ 299 names.NewSubnetTag(sub2.ID()), 300 } 301 entities := params.Entities{ 302 Entities: make([]params.Entity, len(watchSubnetTags)), 303 } 304 for i, tag := range watchSubnetTags { 305 entities.Entities[i].Tag = tag.String() 306 } 307 308 got, err := s.firewaller.WatchSubnets(entities) 309 c.Assert(err, jc.ErrorIsNil) 310 want := params.StringsWatchResult{ 311 StringsWatcherId: "1", 312 Changes: []string{sub2.ID()}, 313 } 314 c.Assert(got.StringsWatcherId, gc.Equals, want.StringsWatcherId) 315 c.Assert(got.Changes, jc.SameContents, want.Changes) 316 317 // Verify the resources were registered and stop them when done. 318 c.Assert(s.resources.Count(), gc.Equals, 1) 319 resource := s.resources.Get("1") 320 defer statetesting.AssertStop(c, resource) 321 322 // Check that the Watch has consumed the initial event ("returned" 323 // in the Watch call) 324 wc := statetesting.NewStringsWatcherC(c, resource.(state.StringsWatcher)) 325 wc.AssertNoChange() 326 }