github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/rpc/params/network_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package params_test 5 6 import ( 7 "encoding/json" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 12 "github.com/juju/juju/core/network" 13 "github.com/juju/juju/rpc/params" 14 ) 15 16 type ( 17 P struct { 18 prot string 19 num int 20 } 21 IS []interface{} 22 M map[string]interface{} 23 ) 24 25 type NetworkSuite struct{} 26 27 var _ = gc.Suite(&NetworkSuite{}) 28 29 func (s *NetworkSuite) TestPortsResults(c *gc.C) { 30 // Convenience helpers. 31 mkPortsResults := func(prs ...params.PortsResult) params.PortsResults { 32 return params.PortsResults{ 33 Results: prs, 34 } 35 } 36 mkPortsResult := func(msg, code string, ports ...P) params.PortsResult { 37 pr := params.PortsResult{} 38 if msg != "" { 39 pr.Error = ¶ms.Error{Message: msg, Code: code} 40 } 41 for _, p := range ports { 42 pr.Ports = append(pr.Ports, params.Port{p.prot, p.num}) 43 } 44 return pr 45 } 46 mkResults := func(rs ...interface{}) M { 47 return M{"results": rs} 48 } 49 mkResult := func(err, ports interface{}) M { 50 result := M{"ports": ports} 51 if err != nil { 52 result["error"] = err 53 } 54 return result 55 } 56 mkError := func(msg, code string) M { 57 return M{"message": msg, "code": code} 58 } 59 mkPort := func(prot string, num int) M { 60 return M{"protocol": prot, "number": num} 61 } 62 // Tests. 63 tests := []struct { 64 about string 65 results params.PortsResults 66 expected M 67 }{{ 68 about: "empty result set", 69 results: mkPortsResults(), 70 expected: mkResults(), 71 }, { 72 about: "one error", 73 results: mkPortsResults( 74 mkPortsResult("I failed", "ERR42")), 75 expected: mkResults( 76 mkResult(mkError("I failed", "ERR42"), nil)), 77 }, { 78 about: "one succes with one port", 79 results: mkPortsResults( 80 mkPortsResult("", "", P{"tcp", 80})), 81 expected: mkResults( 82 mkResult(nil, IS{mkPort("tcp", 80)})), 83 }, { 84 about: "two results, one error and one success with two ports", 85 results: mkPortsResults( 86 mkPortsResult("I failed", "ERR42"), 87 mkPortsResult("", "", P{"tcp", 80}, P{"tcp", 443})), 88 expected: mkResults( 89 mkResult(mkError("I failed", "ERR42"), nil), 90 mkResult(nil, IS{mkPort("tcp", 80), mkPort("tcp", 443)})), 91 }} 92 for i, test := range tests { 93 c.Logf("\ntest %d: %s", i, test.about) 94 output, err := json.Marshal(test.results) 95 if !c.Check(err, jc.ErrorIsNil) { 96 continue 97 } 98 c.Logf("\nJSON output:\n%v", string(output)) 99 c.Check(string(output), jc.JSONEquals, test.expected) 100 } 101 } 102 103 func (s *NetworkSuite) TestHostPort(c *gc.C) { 104 mkHostPort := func(v, t, s string, p int) M { 105 return M{ 106 "value": v, 107 "type": t, 108 "scope": s, 109 "port": p, 110 } 111 } 112 tests := []struct { 113 about string 114 hostPort params.HostPort 115 expected M 116 }{{ 117 about: "address only value; port is 1234", 118 hostPort: params.HostPort{ 119 Address: params.Address{ 120 Value: "foo", 121 }, 122 Port: 1234, 123 }, 124 expected: mkHostPort("foo", "", "", 1234), 125 }, { 126 about: "address value and type; port is 1234", 127 hostPort: params.HostPort{ 128 Address: params.Address{ 129 Value: "foo", 130 Type: "ipv4", 131 }, 132 Port: 1234, 133 }, 134 expected: mkHostPort("foo", "ipv4", "", 1234), 135 }, { 136 about: "address value, type, and network name, port is 1234", 137 hostPort: params.HostPort{ 138 Address: params.Address{ 139 Value: "foo", 140 Type: "ipv4", 141 }, 142 Port: 1234, 143 }, 144 expected: mkHostPort("foo", "ipv4", "", 1234), 145 }, { 146 about: "address all fields, port is 1234", 147 hostPort: params.HostPort{ 148 Address: params.Address{ 149 Value: "foo", 150 Type: "ipv4", 151 Scope: "public", 152 }, 153 Port: 1234, 154 }, 155 expected: mkHostPort("foo", "ipv4", "public", 1234), 156 }, { 157 about: "address all fields, port is 0", 158 hostPort: params.HostPort{ 159 Address: params.Address{ 160 Value: "foo", 161 Type: "ipv4", 162 Scope: "public", 163 }, 164 Port: 0, 165 }, 166 expected: mkHostPort("foo", "ipv4", "public", 0), 167 }} 168 for i, test := range tests { 169 c.Logf("\ntest %d: %s", i, test.about) 170 output, err := json.Marshal(test.hostPort) 171 if !c.Check(err, jc.ErrorIsNil) { 172 continue 173 } 174 c.Logf("\nJSON output:\n%v", string(output)) 175 c.Check(string(output), jc.JSONEquals, test.expected) 176 } 177 } 178 179 func (s *NetworkSuite) TestMachinePortRange(c *gc.C) { 180 mkPortRange := func(u, r string, f, t int, p string) M { 181 return M{ 182 "unit-tag": u, 183 "relation-tag": r, 184 "port-range": M{ 185 "from-port": f, 186 "to-port": t, 187 "protocol": p, 188 }, 189 } 190 } 191 tests := []struct { 192 about string 193 machinePortRange params.MachinePortRange 194 expected M 195 }{{ 196 about: "all values", 197 machinePortRange: params.MachinePortRange{ 198 UnitTag: "foo/0", 199 RelationTag: "foo.db#bar.server", 200 PortRange: params.PortRange{ 201 FromPort: 100, 202 ToPort: 200, 203 Protocol: "tcp", 204 }, 205 }, 206 expected: mkPortRange("foo/0", "foo.db#bar.server", 100, 200, "tcp"), 207 }, { 208 about: "only port range, missing from", 209 machinePortRange: params.MachinePortRange{ 210 PortRange: params.PortRange{ 211 ToPort: 200, 212 Protocol: "tcp", 213 }, 214 }, 215 expected: mkPortRange("", "", 0, 200, "tcp"), 216 }, { 217 about: "only port range, missing to", 218 machinePortRange: params.MachinePortRange{ 219 PortRange: params.PortRange{ 220 FromPort: 100, 221 Protocol: "tcp", 222 }, 223 }, 224 expected: mkPortRange("", "", 100, 0, "tcp"), 225 }, { 226 about: "only port range, missing protocol", 227 machinePortRange: params.MachinePortRange{ 228 PortRange: params.PortRange{ 229 FromPort: 100, 230 ToPort: 200, 231 }, 232 }, 233 expected: mkPortRange("", "", 100, 200, ""), 234 }, { 235 about: "no field values", 236 machinePortRange: params.MachinePortRange{}, 237 expected: mkPortRange("", "", 0, 0, ""), 238 }} 239 for i, test := range tests { 240 c.Logf("\ntest %d: %s", i, test.about) 241 output, err := json.Marshal(test.machinePortRange) 242 if !c.Check(err, jc.ErrorIsNil) { 243 continue 244 } 245 c.Logf("\nJSON output:\n%v", string(output)) 246 c.Check(string(output), jc.JSONEquals, test.expected) 247 } 248 } 249 250 func (s *NetworkSuite) TestPortRangeConvenience(c *gc.C) { 251 networkPortRange := network.PortRange{ 252 FromPort: 61001, 253 ToPort: 61010, 254 Protocol: "tcp", 255 } 256 paramsPortRange := params.FromNetworkPortRange(networkPortRange) 257 networkPortRangeBack := paramsPortRange.NetworkPortRange() 258 c.Assert(networkPortRange, jc.DeepEquals, networkPortRangeBack) 259 } 260 261 func (s *NetworkSuite) TestProviderAddressConversion(c *gc.C) { 262 pAddrs := network.ProviderAddresses{ 263 network.NewMachineAddress("1.2.3.4", network.WithScope(network.ScopeCloudLocal), network.WithCIDR("1.2.3.0/24")).AsProviderAddress(), 264 network.NewMachineAddress("1.2.3.5", network.WithScope(network.ScopeCloudLocal), network.WithSecondary(true)).AsProviderAddress(), 265 network.NewMachineAddress("2.3.4.5", network.WithScope(network.ScopePublic), network.WithConfigType("dhcp")).AsProviderAddress(), 266 } 267 pAddrs[0].SpaceName = "test-space" 268 pAddrs[0].ProviderSpaceID = "666" 269 270 addrs := params.FromProviderAddresses(pAddrs...) 271 c.Assert(params.ToProviderAddresses(addrs...), jc.DeepEquals, pAddrs) 272 } 273 274 func (s *NetworkSuite) TestMachineAddressConversion(c *gc.C) { 275 mAddrs := []network.MachineAddress{ 276 network.NewMachineAddress("1.2.3.4", network.WithScope(network.ScopeCloudLocal), network.WithCIDR("1.2.3.0/24")), 277 network.NewMachineAddress("1.2.3.5", network.WithScope(network.ScopeCloudLocal), network.WithSecondary(true)), 278 network.NewMachineAddress("2.3.4.5", network.WithScope(network.ScopePublic), network.WithConfigType("dhcp")), 279 } 280 281 exp := []params.Address{ 282 {Value: "1.2.3.4", Scope: string(network.ScopeCloudLocal), Type: string(network.IPv4Address), CIDR: "1.2.3.0/24"}, 283 {Value: "1.2.3.5", Scope: string(network.ScopeCloudLocal), Type: string(network.IPv4Address), IsSecondary: true}, 284 {Value: "2.3.4.5", Scope: string(network.ScopePublic), Type: string(network.IPv4Address), ConfigType: "dhcp"}, 285 } 286 c.Assert(params.FromMachineAddresses(mAddrs...), jc.DeepEquals, exp) 287 } 288 289 func (s *NetworkSuite) TestProviderHostPortConversion(c *gc.C) { 290 pHPs := []network.ProviderHostPorts{ 291 { 292 { 293 ProviderAddress: network.NewMachineAddress("1.2.3.4", network.WithScope(network.ScopeCloudLocal)).AsProviderAddress(), 294 NetPort: 1234, 295 }, 296 { 297 ProviderAddress: network.NewMachineAddress("2.3.4.5", network.WithScope(network.ScopePublic)).AsProviderAddress(), 298 NetPort: 2345, 299 }, 300 }, 301 { 302 { 303 ProviderAddress: network.NewMachineAddress("3.4.5.6", network.WithScope(network.ScopeCloudLocal)).AsProviderAddress(), 304 NetPort: 3456, 305 }, 306 }, 307 } 308 pHPs[0][0].SpaceName = "test-space" 309 pHPs[0][0].ProviderSpaceID = "666" 310 311 hps := params.FromProviderHostsPorts(pHPs) 312 c.Assert(params.ToProviderHostsPorts(hps), jc.DeepEquals, pHPs) 313 } 314 315 func (s *NetworkSuite) TestMachineHostPortConversion(c *gc.C) { 316 hps := [][]params.HostPort{ 317 { 318 { 319 Address: params.Address{ 320 Value: "1.2.3.4", 321 Scope: string(network.ScopeCloudLocal), 322 Type: string(network.IPv4Address), 323 }, 324 Port: 1234, 325 }, 326 { 327 Address: params.Address{ 328 Value: "2.3.4.5", 329 Scope: string(network.ScopePublic), 330 Type: string(network.IPv4Address), 331 }, 332 Port: 2345, 333 }, 334 }, 335 { 336 { 337 Address: params.Address{ 338 Value: "3.4.5.6", 339 Scope: string(network.ScopeCloudLocal), 340 Type: string(network.IPv4Address), 341 }, 342 Port: 3456, 343 }, 344 }, 345 } 346 347 exp := []network.MachineHostPorts{ 348 { 349 { 350 MachineAddress: network.NewMachineAddress("1.2.3.4", network.WithScope(network.ScopeCloudLocal)), 351 NetPort: 1234, 352 }, 353 { 354 MachineAddress: network.NewMachineAddress("2.3.4.5", network.WithScope(network.ScopePublic)), 355 NetPort: 2345, 356 }, 357 }, 358 { 359 { 360 MachineAddress: network.NewMachineAddress("3.4.5.6", network.WithScope(network.ScopeCloudLocal)), 361 NetPort: 3456, 362 }, 363 }, 364 } 365 366 c.Assert(params.ToMachineHostsPorts(hps), jc.DeepEquals, exp) 367 } 368 369 func (s *NetworkSuite) TestHostPortConversion(c *gc.C) { 370 mHPs := []network.MachineHostPorts{ 371 { 372 { 373 MachineAddress: network.NewMachineAddress("1.2.3.4", network.WithScope(network.ScopeCloudLocal)), 374 NetPort: 1234, 375 }, 376 { 377 MachineAddress: network.NewMachineAddress("2.3.4.5", network.WithScope(network.ScopePublic)), 378 NetPort: 2345, 379 }, 380 }, 381 { 382 { 383 MachineAddress: network.NewMachineAddress("3.4.5.6", network.WithScope(network.ScopeCloudLocal)), 384 NetPort: 3456, 385 }, 386 }, 387 } 388 389 hps := make([]network.HostPorts, len(mHPs)) 390 for i, mHP := range mHPs { 391 hps[i] = mHP.HostPorts() 392 } 393 394 pHPs := params.FromHostsPorts(hps) 395 c.Assert(params.ToMachineHostsPorts(pHPs), jc.DeepEquals, mHPs) 396 } 397 398 func (s *NetworkSuite) TestSetNetworkConfigBackFillMachineOrigin(c *gc.C) { 399 cfg := params.SetMachineNetworkConfig{ 400 Tag: "machine-0", 401 Config: []params.NetworkConfig{ 402 { 403 ProviderId: "1", 404 // This would not happen in the wild, but serves to 405 // differentiate from the back-filled entries. 406 NetworkOrigin: params.NetworkOrigin(network.OriginProvider), 407 }, 408 {ProviderId: "2"}, 409 {ProviderId: "3"}, 410 }, 411 } 412 413 cfg.BackFillMachineOrigin() 414 c.Assert(cfg.Config, gc.DeepEquals, []params.NetworkConfig{ 415 { 416 ProviderId: "1", 417 NetworkOrigin: params.NetworkOrigin(network.OriginProvider), 418 }, 419 { 420 ProviderId: "2", 421 NetworkOrigin: params.NetworkOrigin(network.OriginMachine), 422 }, 423 { 424 ProviderId: "3", 425 NetworkOrigin: params.NetworkOrigin(network.OriginMachine), 426 }, 427 }) 428 } 429 430 func (s *NetworkSuite) TestNetworkConfigFromInterfaceMACNormalization(c *gc.C) { 431 in := network.InterfaceInfos{ 432 { 433 // All-caps and dashes 434 MACAddress: "00-AA-BB-CC-DD", 435 }, 436 { 437 // All-caps and colons 438 MACAddress: "00:AA:BB:CC:DD", 439 }, 440 { 441 // Already normalized 442 MACAddress: "00:aa:bb:cc:dd", 443 }, 444 } 445 446 got := params.NetworkConfigFromInterfaceInfo(in) 447 c.Assert(got, gc.DeepEquals, []params.NetworkConfig{ 448 { 449 MACAddress: "00:aa:bb:cc:dd", 450 }, 451 { 452 MACAddress: "00:aa:bb:cc:dd", 453 }, 454 { 455 MACAddress: "00:aa:bb:cc:dd", 456 }, 457 }) 458 } 459 func (s *NetworkSuite) TestInterfaceFromNetworkConfigMACNormalization(c *gc.C) { 460 cfg := []params.NetworkConfig{ 461 { 462 // All-caps and dashes 463 MACAddress: "AA-BB-CC-DD-EE-FF", 464 GatewayAddress: "192.168.0.254", 465 }, 466 { 467 // All-caps and colons 468 MACAddress: "AA:BB:CC:DD:EE:FF", 469 GatewayAddress: "192.168.0.254", 470 }, 471 { 472 // Already normalized 473 MACAddress: "aa:bb:cc:dd:ee:ff", 474 GatewayAddress: "192.168.0.254", 475 }, 476 } 477 478 got := params.InterfaceInfoFromNetworkConfig(cfg) 479 gwAddr := network.NewMachineAddress("192.168.0.254").AsProviderAddress() 480 c.Assert(got, gc.DeepEquals, network.InterfaceInfos{ 481 { 482 MACAddress: "aa:bb:cc:dd:ee:ff", 483 GatewayAddress: gwAddr, 484 }, 485 { 486 MACAddress: "aa:bb:cc:dd:ee:ff", 487 GatewayAddress: gwAddr, 488 }, 489 { 490 MACAddress: "aa:bb:cc:dd:ee:ff", 491 GatewayAddress: gwAddr, 492 }, 493 }) 494 }