2
0

services_test.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. //go:build linux
  4. package main
  5. import (
  6. "net/netip"
  7. "reflect"
  8. "testing"
  9. "tailscale.com/kube/egressservices"
  10. )
  11. func Test_updatesForSvc(t *testing.T) {
  12. tailnetIPv4, tailnetIPv6 := netip.MustParseAddr("100.99.99.99"), netip.MustParseAddr("fd7a:115c:a1e0::701:b62a")
  13. tailnetIPv4_1, tailnetIPv6_1 := netip.MustParseAddr("100.88.88.88"), netip.MustParseAddr("fd7a:115c:a1e0::4101:512f")
  14. ports := map[egressservices.PortMap]struct{}{{Protocol: "tcp", MatchPort: 4003, TargetPort: 80}: {}}
  15. ports1 := map[egressservices.PortMap]struct{}{{Protocol: "udp", MatchPort: 4004, TargetPort: 53}: {}}
  16. ports2 := map[egressservices.PortMap]struct{}{{Protocol: "tcp", MatchPort: 4003, TargetPort: 80}: {},
  17. {Protocol: "tcp", MatchPort: 4005, TargetPort: 443}: {}}
  18. fqdnSpec := egressservices.Config{
  19. TailnetTarget: egressservices.TailnetTarget{FQDN: "test"},
  20. Ports: ports,
  21. }
  22. fqdnSpec1 := egressservices.Config{
  23. TailnetTarget: egressservices.TailnetTarget{FQDN: "test"},
  24. Ports: ports1,
  25. }
  26. fqdnSpec2 := egressservices.Config{
  27. TailnetTarget: egressservices.TailnetTarget{IP: tailnetIPv4.String()},
  28. Ports: ports,
  29. }
  30. fqdnSpec3 := egressservices.Config{
  31. TailnetTarget: egressservices.TailnetTarget{IP: tailnetIPv4.String()},
  32. Ports: ports2,
  33. }
  34. r := rule{containerPort: 4003, tailnetPort: 80, protocol: "tcp", tailnetIP: tailnetIPv4}
  35. r1 := rule{containerPort: 4003, tailnetPort: 80, protocol: "tcp", tailnetIP: tailnetIPv6}
  36. r2 := rule{tailnetPort: 53, containerPort: 4004, protocol: "udp", tailnetIP: tailnetIPv4}
  37. r3 := rule{tailnetPort: 53, containerPort: 4004, protocol: "udp", tailnetIP: tailnetIPv6}
  38. r4 := rule{containerPort: 4003, tailnetPort: 80, protocol: "tcp", tailnetIP: tailnetIPv4_1}
  39. r5 := rule{containerPort: 4003, tailnetPort: 80, protocol: "tcp", tailnetIP: tailnetIPv6_1}
  40. r6 := rule{containerPort: 4005, tailnetPort: 443, protocol: "tcp", tailnetIP: tailnetIPv4}
  41. tests := []struct {
  42. name string
  43. svcName string
  44. tailnetTargetIPs []netip.Addr
  45. podIP string
  46. spec egressservices.Config
  47. status *egressservices.Status
  48. wantRulesToAdd []rule
  49. wantRulesToDelete []rule
  50. }{
  51. {
  52. name: "add_fqdn_svc_that_does_not_yet_exist",
  53. svcName: "test",
  54. tailnetTargetIPs: []netip.Addr{tailnetIPv4, tailnetIPv6},
  55. spec: fqdnSpec,
  56. status: &egressservices.Status{},
  57. wantRulesToAdd: []rule{r, r1},
  58. wantRulesToDelete: []rule{},
  59. },
  60. {
  61. name: "fqdn_svc_already_exists",
  62. svcName: "test",
  63. tailnetTargetIPs: []netip.Addr{tailnetIPv4, tailnetIPv6},
  64. spec: fqdnSpec,
  65. status: &egressservices.Status{
  66. Services: map[string]*egressservices.ServiceStatus{"test": {
  67. TailnetTargetIPs: []netip.Addr{tailnetIPv4, tailnetIPv6},
  68. TailnetTarget: egressservices.TailnetTarget{FQDN: "test"},
  69. Ports: ports,
  70. }}},
  71. wantRulesToAdd: []rule{},
  72. wantRulesToDelete: []rule{},
  73. },
  74. {
  75. name: "fqdn_svc_already_exists_add_port_remove_port",
  76. svcName: "test",
  77. tailnetTargetIPs: []netip.Addr{tailnetIPv4, tailnetIPv6},
  78. spec: fqdnSpec1,
  79. status: &egressservices.Status{
  80. Services: map[string]*egressservices.ServiceStatus{"test": {
  81. TailnetTargetIPs: []netip.Addr{tailnetIPv4, tailnetIPv6},
  82. TailnetTarget: egressservices.TailnetTarget{FQDN: "test"},
  83. Ports: ports,
  84. }}},
  85. wantRulesToAdd: []rule{r2, r3},
  86. wantRulesToDelete: []rule{r, r1},
  87. },
  88. {
  89. name: "fqdn_svc_already_exists_change_fqdn_backend_ips",
  90. svcName: "test",
  91. tailnetTargetIPs: []netip.Addr{tailnetIPv4_1, tailnetIPv6_1},
  92. spec: fqdnSpec,
  93. status: &egressservices.Status{
  94. Services: map[string]*egressservices.ServiceStatus{"test": {
  95. TailnetTargetIPs: []netip.Addr{tailnetIPv4, tailnetIPv6},
  96. TailnetTarget: egressservices.TailnetTarget{FQDN: "test"},
  97. Ports: ports,
  98. }}},
  99. wantRulesToAdd: []rule{r4, r5},
  100. wantRulesToDelete: []rule{r, r1},
  101. },
  102. {
  103. name: "add_ip_service",
  104. svcName: "test",
  105. tailnetTargetIPs: []netip.Addr{tailnetIPv4},
  106. spec: fqdnSpec2,
  107. status: &egressservices.Status{},
  108. wantRulesToAdd: []rule{r},
  109. wantRulesToDelete: []rule{},
  110. },
  111. {
  112. name: "add_ip_service_already_exists",
  113. svcName: "test",
  114. tailnetTargetIPs: []netip.Addr{tailnetIPv4},
  115. spec: fqdnSpec2,
  116. status: &egressservices.Status{
  117. Services: map[string]*egressservices.ServiceStatus{"test": {
  118. TailnetTargetIPs: []netip.Addr{tailnetIPv4},
  119. TailnetTarget: egressservices.TailnetTarget{IP: tailnetIPv4.String()},
  120. Ports: ports,
  121. }}},
  122. wantRulesToAdd: []rule{},
  123. wantRulesToDelete: []rule{},
  124. },
  125. {
  126. name: "ip_service_add_port",
  127. svcName: "test",
  128. tailnetTargetIPs: []netip.Addr{tailnetIPv4},
  129. spec: fqdnSpec3,
  130. status: &egressservices.Status{
  131. Services: map[string]*egressservices.ServiceStatus{"test": {
  132. TailnetTargetIPs: []netip.Addr{tailnetIPv4},
  133. TailnetTarget: egressservices.TailnetTarget{IP: tailnetIPv4.String()},
  134. Ports: ports,
  135. }}},
  136. wantRulesToAdd: []rule{r6},
  137. wantRulesToDelete: []rule{},
  138. },
  139. {
  140. name: "ip_service_delete_port",
  141. svcName: "test",
  142. tailnetTargetIPs: []netip.Addr{tailnetIPv4},
  143. spec: fqdnSpec,
  144. status: &egressservices.Status{
  145. Services: map[string]*egressservices.ServiceStatus{"test": {
  146. TailnetTargetIPs: []netip.Addr{tailnetIPv4},
  147. TailnetTarget: egressservices.TailnetTarget{IP: tailnetIPv4.String()},
  148. Ports: ports2,
  149. }}},
  150. wantRulesToAdd: []rule{},
  151. wantRulesToDelete: []rule{r6},
  152. },
  153. }
  154. for _, tt := range tests {
  155. t.Run(tt.name, func(t *testing.T) {
  156. gotRulesToAdd, gotRulesToDelete, err := updatesForCfg(tt.svcName, tt.spec, tt.status, tt.tailnetTargetIPs)
  157. if err != nil {
  158. t.Errorf("updatesForSvc() unexpected error %v", err)
  159. return
  160. }
  161. if !reflect.DeepEqual(gotRulesToAdd, tt.wantRulesToAdd) {
  162. t.Errorf("updatesForSvc() got rulesToAdd = \n%v\n want rulesToAdd \n%v", gotRulesToAdd, tt.wantRulesToAdd)
  163. }
  164. if !reflect.DeepEqual(gotRulesToDelete, tt.wantRulesToDelete) {
  165. t.Errorf("updatesForSvc() got rulesToDelete = \n%v\n want rulesToDelete \n%v", gotRulesToDelete, tt.wantRulesToDelete)
  166. }
  167. })
  168. }
  169. }