github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/firewaller/firewaller_unit_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package firewaller_test 5 6 import ( 7 "github.com/juju/names/v5" 8 jc "github.com/juju/testing/checkers" 9 "go.uber.org/mock/gomock" 10 gc "gopkg.in/check.v1" 11 12 apitesting "github.com/juju/juju/api/testing" 13 "github.com/juju/juju/apiserver/common" 14 "github.com/juju/juju/apiserver/facades/controller/firewaller" 15 "github.com/juju/juju/apiserver/facades/controller/firewaller/mocks" 16 apiservertesting "github.com/juju/juju/apiserver/testing" 17 "github.com/juju/juju/controller" 18 "github.com/juju/juju/core/network" 19 "github.com/juju/juju/core/status" 20 "github.com/juju/juju/environs/config" 21 "github.com/juju/juju/rpc/params" 22 "github.com/juju/juju/state" 23 coretesting "github.com/juju/juju/testing" 24 ) 25 26 var _ = gc.Suite(&RemoteFirewallerSuite{}) 27 28 type RemoteFirewallerSuite struct { 29 coretesting.BaseSuite 30 31 resources *common.Resources 32 authorizer *apiservertesting.FakeAuthorizer 33 st *mocks.MockState 34 cc *mocks.MockControllerConfigAPI 35 api *firewaller.FirewallerAPI 36 } 37 38 func (s *RemoteFirewallerSuite) SetUpTest(c *gc.C) { 39 s.BaseSuite.SetUpTest(c) 40 41 s.resources = common.NewResources() 42 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 43 44 s.authorizer = &apiservertesting.FakeAuthorizer{ 45 Tag: names.NewMachineTag("0"), 46 Controller: true, 47 } 48 } 49 50 func (s *RemoteFirewallerSuite) setup(c *gc.C) *gomock.Controller { 51 ctrl := gomock.NewController(c) 52 53 s.st = mocks.NewMockState(ctrl) 54 s.cc = mocks.NewMockControllerConfigAPI(ctrl) 55 api, err := firewaller.NewStateFirewallerAPI(s.st, s.resources, s.authorizer, &mockCloudSpecAPI{}, s.cc) 56 c.Assert(err, jc.ErrorIsNil) 57 s.api = api 58 return ctrl 59 } 60 61 func (s *RemoteFirewallerSuite) TestWatchIngressAddressesForRelations(c *gc.C) { 62 defer s.setup(c).Finish() 63 64 db2Relation := newMockRelation(123) 65 s.st.EXPECT().ModelUUID().Return(coretesting.ModelTag.Id()).AnyTimes() 66 s.st.EXPECT().KeyRelation("remote-db2:db django:db").Return(db2Relation, nil) 67 68 result, err := s.api.WatchIngressAddressesForRelations( 69 params.Entities{Entities: []params.Entity{{ 70 Tag: names.NewRelationTag("remote-db2:db django:db").String(), 71 }}}, 72 ) 73 74 c.Assert(err, jc.ErrorIsNil) 75 c.Assert(result.Results, gc.HasLen, 1) 76 c.Assert(result.Results[0].Changes, jc.SameContents, []string{"1.2.3.4/32"}) 77 c.Assert(result.Results[0].Error, gc.IsNil) 78 c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1") 79 80 resource := s.resources.Get("1") 81 c.Assert(resource, gc.NotNil) 82 c.Assert(resource, gc.Implements, new(state.StringsWatcher)) 83 } 84 85 func (s *RemoteFirewallerSuite) TestMacaroonForRelations(c *gc.C) { 86 defer s.setup(c).Finish() 87 88 mac, err := apitesting.NewMacaroon("apimac") 89 c.Assert(err, jc.ErrorIsNil) 90 entity := names.NewRelationTag("mysql:db wordpress:db") 91 s.st.EXPECT().GetMacaroon(entity).Return(mac, nil) 92 93 result, err := s.api.MacaroonForRelations( 94 params.Entities{Entities: []params.Entity{{ 95 Tag: entity.String(), 96 }}}, 97 ) 98 99 c.Assert(err, jc.ErrorIsNil) 100 c.Assert(result.Results, gc.HasLen, 1) 101 c.Assert(result.Results[0].Error, gc.IsNil) 102 c.Assert(result.Results[0].Result, jc.DeepEquals, mac) 103 } 104 105 func (s *RemoteFirewallerSuite) TestSetRelationStatus(c *gc.C) { 106 defer s.setup(c).Finish() 107 108 db2Relation := newMockRelation(123) 109 entity := names.NewRelationTag("remote-db2:db django:db") 110 s.st.EXPECT().ModelUUID().Return(coretesting.ModelTag.Id()).AnyTimes() 111 s.st.EXPECT().KeyRelation("remote-db2:db django:db").Return(db2Relation, nil) 112 113 result, err := s.api.SetRelationsStatus( 114 params.SetStatus{Entities: []params.EntityStatusArgs{{ 115 Tag: entity.String(), 116 Status: "suspended", 117 Info: "a message", 118 }}}) 119 c.Assert(err, jc.ErrorIsNil) 120 c.Assert(result.Results, gc.HasLen, 1) 121 c.Assert(result.Results[0].Error, gc.IsNil) 122 c.Assert(db2Relation.status, jc.DeepEquals, status.StatusInfo{Status: status.Suspended, Message: "a message"}) 123 } 124 125 var _ = gc.Suite(&FirewallerSuite{}) 126 127 type FirewallerSuite struct { 128 coretesting.BaseSuite 129 130 resources *common.Resources 131 authorizer *apiservertesting.FakeAuthorizer 132 133 st *mocks.MockState 134 cc *mocks.MockControllerConfigAPI 135 api *firewaller.FirewallerAPI 136 } 137 138 func (s *FirewallerSuite) SetUpTest(c *gc.C) { 139 s.BaseSuite.SetUpTest(c) 140 141 s.resources = common.NewResources() 142 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 143 144 s.authorizer = &apiservertesting.FakeAuthorizer{ 145 Tag: names.NewMachineTag("0"), 146 Controller: true, 147 } 148 } 149 150 func (s *FirewallerSuite) setup(c *gc.C) *gomock.Controller { 151 ctrl := gomock.NewController(c) 152 153 s.st = mocks.NewMockState(ctrl) 154 s.cc = mocks.NewMockControllerConfigAPI(ctrl) 155 api, err := firewaller.NewStateFirewallerAPI(s.st, s.resources, s.authorizer, &mockCloudSpecAPI{}, s.cc) 156 c.Assert(err, jc.ErrorIsNil) 157 s.api = api 158 return ctrl 159 } 160 161 func (s *FirewallerSuite) TestModelFirewallRules(c *gc.C) { 162 defer s.setup(c).Finish() 163 164 modelAttrs := coretesting.FakeConfig().Merge(map[string]interface{}{ 165 config.SSHAllowKey: "192.168.0.0/24,192.168.1.0/24", 166 }) 167 s.st.EXPECT().ModelConfig().Return(config.New(config.UseDefaults, modelAttrs)) 168 s.st.EXPECT().ControllerConfig().Return(controller.NewConfig(coretesting.ControllerTag.Id(), coretesting.CACert, map[string]interface{}{})) 169 s.st.EXPECT().IsController().Return(false) 170 171 rules, err := s.api.ModelFirewallRules() 172 173 c.Assert(err, jc.ErrorIsNil) 174 c.Assert(rules, gc.DeepEquals, params.IngressRulesResult{Rules: []params.IngressRule{{ 175 PortRange: params.FromNetworkPortRange(network.MustParsePortRange("22")), 176 SourceCIDRs: []string{"192.168.0.0/24", "192.168.1.0/24"}, 177 }}}) 178 } 179 180 func (s *FirewallerSuite) TestModelFirewallRulesController(c *gc.C) { 181 defer s.setup(c).Finish() 182 183 modelAttrs := coretesting.FakeConfig().Merge(map[string]interface{}{ 184 config.SSHAllowKey: "192.168.0.0/24,192.168.1.0/24", 185 }) 186 s.st.EXPECT().ModelConfig().Return(config.New(config.UseDefaults, modelAttrs)) 187 188 ctrlAttrs := map[string]interface{}{ 189 controller.APIPort: 17777, 190 controller.AutocertDNSNameKey: "example.com", 191 } 192 s.st.EXPECT().ControllerConfig().Return(controller.NewConfig(coretesting.ControllerTag.Id(), coretesting.CACert, ctrlAttrs)) 193 s.st.EXPECT().IsController().Return(true) 194 195 rules, err := s.api.ModelFirewallRules() 196 197 c.Assert(err, jc.ErrorIsNil) 198 c.Assert(rules, gc.DeepEquals, params.IngressRulesResult{Rules: []params.IngressRule{{ 199 PortRange: params.FromNetworkPortRange(network.MustParsePortRange("22")), 200 SourceCIDRs: []string{"192.168.0.0/24", "192.168.1.0/24"}, 201 }, { 202 PortRange: params.FromNetworkPortRange(network.MustParsePortRange("17777")), 203 SourceCIDRs: []string{"0.0.0.0/0", "::/0"}, 204 }, { 205 PortRange: params.FromNetworkPortRange(network.MustParsePortRange("80")), 206 SourceCIDRs: []string{"0.0.0.0/0", "::/0"}, 207 }}}) 208 } 209 210 func (s *FirewallerSuite) TestWatchModelFirewallRules(c *gc.C) { 211 ctrl := s.setup(c) 212 defer ctrl.Finish() 213 214 ch := make(chan struct{}, 1) 215 // initial event 216 ch <- struct{}{} 217 w := mocks.NewMockNotifyWatcher(ctrl) 218 w.EXPECT().Changes().Return(ch).MinTimes(1) 219 w.EXPECT().Wait().AnyTimes() 220 w.EXPECT().Kill().AnyTimes() 221 222 s.st.EXPECT().WatchForModelConfigChanges().Return(w) 223 s.st.EXPECT().ModelConfig().Return(config.New(config.UseDefaults, coretesting.FakeConfig())) 224 225 result, err := s.api.WatchModelFirewallRules() 226 c.Assert(err, jc.ErrorIsNil) 227 c.Assert(result.Error, gc.IsNil) 228 c.Assert(result.NotifyWatcherId, gc.Equals, "1") 229 230 resource := s.resources.Get("1") 231 c.Assert(resource, gc.NotNil) 232 c.Assert(resource, gc.Implements, new(state.NotifyWatcher)) 233 } 234 235 func (s *FirewallerSuite) TestOpenedMachinePortRanges(c *gc.C) { 236 defer s.setup(c).Finish() 237 238 // Set up our mocks 239 mockMachine := newMockMachine("0") 240 mockMachine.openedPortRanges = newMockMachinePortRanges( 241 newMockUnitPortRanges( 242 "wordpress/0", 243 network.GroupedPortRanges{ 244 "": []network.PortRange{ 245 network.MustParsePortRange("80/tcp"), 246 }, 247 }, 248 ), 249 newMockUnitPortRanges( 250 "mysql/0", 251 network.GroupedPortRanges{ 252 "foo": []network.PortRange{ 253 network.MustParsePortRange("3306/tcp"), 254 }, 255 }, 256 ), 257 ) 258 spaceInfos := network.SpaceInfos{ 259 {ID: network.AlphaSpaceId, Name: "alpha", Subnets: []network.SubnetInfo{ 260 {ID: "11", CIDR: "10.0.0.0/24"}, 261 {ID: "12", CIDR: "10.0.1.0/24"}, 262 }}, 263 {ID: "42", Name: "questions-about-the-universe", Subnets: []network.SubnetInfo{ 264 {ID: "13", CIDR: "192.168.0.0/24"}, 265 {ID: "14", CIDR: "192.168.1.0/24"}, 266 }}, 267 } 268 applicationEndpointBindings := map[string]map[string]string{ 269 "mysql": { 270 "": network.AlphaSpaceId, 271 "foo": "42", 272 }, 273 "wordpress": { 274 "": network.AlphaSpaceId, 275 "monitoring": network.AlphaSpaceId, 276 "web": "42", 277 }, 278 } 279 s.st.EXPECT().Machine("0").Return(mockMachine, nil) 280 s.st.EXPECT().SpaceInfos().Return(spaceInfos, nil) 281 s.st.EXPECT().AllEndpointBindings().Return(applicationEndpointBindings, nil) 282 283 // Test call output 284 req := params.Entities{ 285 Entities: []params.Entity{ 286 {Tag: names.NewMachineTag("0").String()}, 287 }, 288 } 289 res, err := s.api.OpenedMachinePortRanges(req) 290 c.Assert(err, jc.ErrorIsNil) 291 c.Assert(res.Results, gc.HasLen, 1) 292 293 c.Assert(res.Results[0].Error, gc.IsNil) 294 c.Assert(res.Results[0].UnitPortRanges, gc.DeepEquals, map[string][]params.OpenUnitPortRanges{ 295 "unit-wordpress-0": { 296 { 297 Endpoint: "", 298 SubnetCIDRs: []string{"10.0.0.0/24", "10.0.1.0/24", "192.168.0.0/24", "192.168.1.0/24"}, 299 PortRanges: []params.PortRange{ 300 params.FromNetworkPortRange(network.MustParsePortRange("80/tcp")), 301 }, 302 }, 303 }, 304 "unit-mysql-0": { 305 { 306 Endpoint: "foo", 307 SubnetCIDRs: []string{"192.168.0.0/24", "192.168.1.0/24"}, 308 PortRanges: []params.PortRange{ 309 params.FromNetworkPortRange(network.MustParsePortRange("3306/tcp")), 310 }, 311 }, 312 }, 313 }) 314 } 315 316 func (s *FirewallerSuite) TestAllSpaceInfos(c *gc.C) { 317 defer s.setup(c).Finish() 318 319 // Set up our mocks 320 spaceInfos := network.SpaceInfos{ 321 { 322 ID: "42", 323 Name: "questions-about-the-universe", 324 ProviderId: "provider-id-2", 325 Subnets: []network.SubnetInfo{ 326 { 327 ID: "13", 328 CIDR: "1.168.1.0/24", 329 ProviderId: "provider-subnet-id-1", 330 ProviderSpaceId: "provider-space-id-1", 331 ProviderNetworkId: "provider-network-id-1", 332 VLANTag: 42, 333 AvailabilityZones: []string{"az1", "az2"}, 334 SpaceID: "42", 335 SpaceName: "questions-about-the-universe", 336 FanInfo: &network.FanCIDRs{ 337 FanLocalUnderlay: "192.168.0.0/16", 338 FanOverlay: "1.0.0.0/8", 339 }, 340 IsPublic: true, 341 }, 342 }}, 343 {ID: "99", Name: "special", Subnets: []network.SubnetInfo{ 344 {ID: "999", CIDR: "192.168.2.0/24"}, 345 }}, 346 } 347 s.st.EXPECT().SpaceInfos().Return(spaceInfos, nil) 348 349 // Test call output 350 req := params.SpaceInfosParams{ 351 FilterBySpaceIDs: []string{network.AlphaSpaceId, "42"}, 352 } 353 res, err := s.api.SpaceInfos(req) 354 c.Assert(err, jc.ErrorIsNil) 355 356 // Hydrate a network.SpaceInfos from the response 357 gotSpaceInfos := params.ToNetworkSpaceInfos(res) 358 c.Assert(gotSpaceInfos, gc.DeepEquals, spaceInfos[0:1], gc.Commentf("expected to get back a filtered list of the space infos")) 359 }