server_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. Copyright 2015 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package app
  14. import (
  15. "errors"
  16. "fmt"
  17. "io/ioutil"
  18. "os"
  19. "path/filepath"
  20. "reflect"
  21. "runtime"
  22. "strings"
  23. "testing"
  24. "time"
  25. "github.com/google/go-cmp/cmp"
  26. "github.com/stretchr/testify/assert"
  27. utilpointer "k8s.io/utils/pointer"
  28. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  29. componentbaseconfig "k8s.io/component-base/config"
  30. kubeproxyconfig "k8s.io/kubernetes/pkg/proxy/apis/config"
  31. "k8s.io/kubernetes/pkg/util/configz"
  32. )
  33. // This test verifies that NewProxyServer does not crash when CleanupAndExit is true.
  34. func TestProxyServerWithCleanupAndExit(t *testing.T) {
  35. // Each bind address below is a separate test case
  36. bindAddresses := []string{
  37. "0.0.0.0",
  38. "::",
  39. }
  40. for _, addr := range bindAddresses {
  41. options := NewOptions()
  42. options.config = &kubeproxyconfig.KubeProxyConfiguration{
  43. BindAddress: addr,
  44. }
  45. options.CleanupAndExit = true
  46. proxyserver, err := NewProxyServer(options)
  47. assert.Nil(t, err, "unexpected error in NewProxyServer, addr: %s", addr)
  48. assert.NotNil(t, proxyserver, "nil proxy server obj, addr: %s", addr)
  49. assert.NotNil(t, proxyserver.IptInterface, "nil iptables intf, addr: %s", addr)
  50. // Clean up config for next test case
  51. configz.Delete(kubeproxyconfig.GroupName)
  52. }
  53. }
  54. func TestGetConntrackMax(t *testing.T) {
  55. ncores := runtime.NumCPU()
  56. testCases := []struct {
  57. min int32
  58. maxPerCore int32
  59. expected int
  60. err string
  61. }{
  62. {
  63. expected: 0,
  64. },
  65. {
  66. maxPerCore: 67890, // use this if Max is 0
  67. min: 1, // avoid 0 default
  68. expected: 67890 * ncores,
  69. },
  70. {
  71. maxPerCore: 1, // ensure that Min is considered
  72. min: 123456,
  73. expected: 123456,
  74. },
  75. {
  76. maxPerCore: 0, // leave system setting
  77. min: 123456,
  78. expected: 0,
  79. },
  80. }
  81. for i, tc := range testCases {
  82. cfg := kubeproxyconfig.KubeProxyConntrackConfiguration{
  83. Min: utilpointer.Int32Ptr(tc.min),
  84. MaxPerCore: utilpointer.Int32Ptr(tc.maxPerCore),
  85. }
  86. x, e := getConntrackMax(cfg)
  87. if e != nil {
  88. if tc.err == "" {
  89. t.Errorf("[%d] unexpected error: %v", i, e)
  90. } else if !strings.Contains(e.Error(), tc.err) {
  91. t.Errorf("[%d] expected an error containing %q: %v", i, tc.err, e)
  92. }
  93. } else if x != tc.expected {
  94. t.Errorf("[%d] expected %d, got %d", i, tc.expected, x)
  95. }
  96. }
  97. }
  98. // TestLoadConfig tests proper operation of loadConfig()
  99. func TestLoadConfig(t *testing.T) {
  100. yamlTemplate := `apiVersion: kubeproxy.config.k8s.io/v1alpha1
  101. bindAddress: %s
  102. clientConnection:
  103. acceptContentTypes: "abc"
  104. burst: 100
  105. contentType: content-type
  106. kubeconfig: "/path/to/kubeconfig"
  107. qps: 7
  108. clusterCIDR: "%s"
  109. configSyncPeriod: 15s
  110. conntrack:
  111. maxPerCore: 2
  112. min: 1
  113. tcpCloseWaitTimeout: 10s
  114. tcpEstablishedTimeout: 20s
  115. healthzBindAddress: "%s"
  116. hostnameOverride: "foo"
  117. iptables:
  118. masqueradeAll: true
  119. masqueradeBit: 17
  120. minSyncPeriod: 10s
  121. syncPeriod: 60s
  122. ipvs:
  123. minSyncPeriod: 10s
  124. syncPeriod: 60s
  125. excludeCIDRs:
  126. - "10.20.30.40/16"
  127. - "fd00:1::0/64"
  128. kind: KubeProxyConfiguration
  129. metricsBindAddress: "%s"
  130. mode: "%s"
  131. oomScoreAdj: 17
  132. portRange: "2-7"
  133. udpIdleTimeout: 123ms
  134. detectLocalMode: "ClusterCIDR"
  135. nodePortAddresses:
  136. - "10.20.30.40/16"
  137. - "fd00:1::0/64"
  138. `
  139. testCases := []struct {
  140. name string
  141. mode string
  142. bindAddress string
  143. clusterCIDR string
  144. healthzBindAddress string
  145. metricsBindAddress string
  146. extraConfig string
  147. }{
  148. {
  149. name: "iptables mode, IPv4 all-zeros bind address",
  150. mode: "iptables",
  151. bindAddress: "0.0.0.0",
  152. clusterCIDR: "1.2.3.0/24",
  153. healthzBindAddress: "1.2.3.4:12345",
  154. metricsBindAddress: "2.3.4.5:23456",
  155. },
  156. {
  157. name: "iptables mode, non-zeros IPv4 config",
  158. mode: "iptables",
  159. bindAddress: "9.8.7.6",
  160. clusterCIDR: "1.2.3.0/24",
  161. healthzBindAddress: "1.2.3.4:12345",
  162. metricsBindAddress: "2.3.4.5:23456",
  163. },
  164. {
  165. // Test for 'bindAddress: "::"' (IPv6 all-zeros) in kube-proxy
  166. // config file. The user will need to put quotes around '::' since
  167. // 'bindAddress: ::' is invalid yaml syntax.
  168. name: "iptables mode, IPv6 \"::\" bind address",
  169. mode: "iptables",
  170. bindAddress: "\"::\"",
  171. clusterCIDR: "fd00:1::0/64",
  172. healthzBindAddress: "[fd00:1::5]:12345",
  173. metricsBindAddress: "[fd00:2::5]:23456",
  174. },
  175. {
  176. // Test for 'bindAddress: "[::]"' (IPv6 all-zeros in brackets)
  177. // in kube-proxy config file. The user will need to use
  178. // surrounding quotes here since 'bindAddress: [::]' is invalid
  179. // yaml syntax.
  180. name: "iptables mode, IPv6 \"[::]\" bind address",
  181. mode: "iptables",
  182. bindAddress: "\"[::]\"",
  183. clusterCIDR: "fd00:1::0/64",
  184. healthzBindAddress: "[fd00:1::5]:12345",
  185. metricsBindAddress: "[fd00:2::5]:23456",
  186. },
  187. {
  188. // Test for 'bindAddress: ::0' (another form of IPv6 all-zeros).
  189. // No surrounding quotes are required around '::0'.
  190. name: "iptables mode, IPv6 ::0 bind address",
  191. mode: "iptables",
  192. bindAddress: "::0",
  193. clusterCIDR: "fd00:1::0/64",
  194. healthzBindAddress: "[fd00:1::5]:12345",
  195. metricsBindAddress: "[fd00:2::5]:23456",
  196. },
  197. {
  198. name: "ipvs mode, IPv6 config",
  199. mode: "ipvs",
  200. bindAddress: "2001:db8::1",
  201. clusterCIDR: "fd00:1::0/64",
  202. healthzBindAddress: "[fd00:1::5]:12345",
  203. metricsBindAddress: "[fd00:2::5]:23456",
  204. },
  205. {
  206. // Test for unknown field within config.
  207. // For v1alpha1 a lenient path is implemented and will throw a
  208. // strict decoding warning instead of failing to load
  209. name: "unknown field",
  210. mode: "iptables",
  211. bindAddress: "9.8.7.6",
  212. clusterCIDR: "1.2.3.0/24",
  213. healthzBindAddress: "1.2.3.4:12345",
  214. metricsBindAddress: "2.3.4.5:23456",
  215. extraConfig: "foo: bar",
  216. },
  217. {
  218. // Test for duplicate field within config.
  219. // For v1alpha1 a lenient path is implemented and will throw a
  220. // strict decoding warning instead of failing to load
  221. name: "duplicate field",
  222. mode: "iptables",
  223. bindAddress: "9.8.7.6",
  224. clusterCIDR: "1.2.3.0/24",
  225. healthzBindAddress: "1.2.3.4:12345",
  226. metricsBindAddress: "2.3.4.5:23456",
  227. extraConfig: "bindAddress: 9.8.7.6",
  228. },
  229. }
  230. for _, tc := range testCases {
  231. expBindAddr := tc.bindAddress
  232. if tc.bindAddress[0] == '"' {
  233. // Surrounding double quotes will get stripped by the yaml parser.
  234. expBindAddr = expBindAddr[1 : len(tc.bindAddress)-1]
  235. }
  236. expected := &kubeproxyconfig.KubeProxyConfiguration{
  237. BindAddress: expBindAddr,
  238. ClientConnection: componentbaseconfig.ClientConnectionConfiguration{
  239. AcceptContentTypes: "abc",
  240. Burst: 100,
  241. ContentType: "content-type",
  242. Kubeconfig: "/path/to/kubeconfig",
  243. QPS: 7,
  244. },
  245. ClusterCIDR: tc.clusterCIDR,
  246. ConfigSyncPeriod: metav1.Duration{Duration: 15 * time.Second},
  247. Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{
  248. MaxPerCore: utilpointer.Int32Ptr(2),
  249. Min: utilpointer.Int32Ptr(1),
  250. TCPCloseWaitTimeout: &metav1.Duration{Duration: 10 * time.Second},
  251. TCPEstablishedTimeout: &metav1.Duration{Duration: 20 * time.Second},
  252. },
  253. FeatureGates: map[string]bool{},
  254. HealthzBindAddress: tc.healthzBindAddress,
  255. HostnameOverride: "foo",
  256. IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{
  257. MasqueradeAll: true,
  258. MasqueradeBit: utilpointer.Int32Ptr(17),
  259. MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
  260. SyncPeriod: metav1.Duration{Duration: 60 * time.Second},
  261. },
  262. IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{
  263. MinSyncPeriod: metav1.Duration{Duration: 10 * time.Second},
  264. SyncPeriod: metav1.Duration{Duration: 60 * time.Second},
  265. ExcludeCIDRs: []string{"10.20.30.40/16", "fd00:1::0/64"},
  266. },
  267. MetricsBindAddress: tc.metricsBindAddress,
  268. Mode: kubeproxyconfig.ProxyMode(tc.mode),
  269. OOMScoreAdj: utilpointer.Int32Ptr(17),
  270. PortRange: "2-7",
  271. UDPIdleTimeout: metav1.Duration{Duration: 123 * time.Millisecond},
  272. NodePortAddresses: []string{"10.20.30.40/16", "fd00:1::0/64"},
  273. DetectLocalMode: kubeproxyconfig.LocalModeClusterCIDR,
  274. }
  275. options := NewOptions()
  276. baseYAML := fmt.Sprintf(
  277. yamlTemplate, tc.bindAddress, tc.clusterCIDR,
  278. tc.healthzBindAddress, tc.metricsBindAddress, tc.mode)
  279. // Append additional configuration to the base yaml template
  280. yaml := fmt.Sprintf("%s\n%s", baseYAML, tc.extraConfig)
  281. config, err := options.loadConfig([]byte(yaml))
  282. assert.NoError(t, err, "unexpected error for %s: %v", tc.name, err)
  283. if !reflect.DeepEqual(expected, config) {
  284. t.Fatalf("unexpected config for %s, diff = %s", tc.name, cmp.Diff(config, expected))
  285. }
  286. }
  287. }
  288. // TestLoadConfigFailures tests failure modes for loadConfig()
  289. func TestLoadConfigFailures(t *testing.T) {
  290. // TODO(phenixblue): Uncomment below template when v1alpha2+ of kube-proxy config is
  291. // released with strict decoding. These associated tests will fail with
  292. // the lenient codec and only one config API version.
  293. /*
  294. yamlTemplate := `bindAddress: 0.0.0.0
  295. clusterCIDR: "1.2.3.0/24"
  296. configSyncPeriod: 15s
  297. kind: KubeProxyConfiguration`
  298. */
  299. testCases := []struct {
  300. name string
  301. config string
  302. expErr string
  303. checkFn func(err error) bool
  304. }{
  305. {
  306. name: "Decode error test",
  307. config: "Twas bryllyg, and ye slythy toves",
  308. expErr: "could not find expected ':'",
  309. },
  310. {
  311. name: "Bad config type test",
  312. config: "kind: KubeSchedulerConfiguration",
  313. expErr: "no kind",
  314. },
  315. {
  316. name: "Missing quotes around :: bindAddress",
  317. config: "bindAddress: ::",
  318. expErr: "mapping values are not allowed in this context",
  319. },
  320. // TODO(phenixblue): Uncomment below tests when v1alpha2+ of kube-proxy config is
  321. // released with strict decoding. These tests will fail with the
  322. // lenient codec and only one config API version.
  323. /*
  324. {
  325. name: "Duplicate fields",
  326. config: fmt.Sprintf("%s\nbindAddress: 1.2.3.4", yamlTemplate),
  327. checkFn: kuberuntime.IsStrictDecodingError,
  328. },
  329. {
  330. name: "Unknown field",
  331. config: fmt.Sprintf("%s\nfoo: bar", yamlTemplate),
  332. checkFn: kuberuntime.IsStrictDecodingError,
  333. },
  334. */
  335. }
  336. version := "apiVersion: kubeproxy.config.k8s.io/v1alpha1"
  337. for _, tc := range testCases {
  338. t.Run(tc.name, func(t *testing.T) {
  339. options := NewOptions()
  340. config := fmt.Sprintf("%s\n%s", version, tc.config)
  341. _, err := options.loadConfig([]byte(config))
  342. if assert.Error(t, err, tc.name) {
  343. if tc.expErr != "" {
  344. assert.Contains(t, err.Error(), tc.expErr)
  345. }
  346. if tc.checkFn != nil {
  347. assert.True(t, tc.checkFn(err), tc.name)
  348. }
  349. }
  350. })
  351. }
  352. }
  353. // TestProcessHostnameOverrideFlag tests processing hostname-override arg
  354. func TestProcessHostnameOverrideFlag(t *testing.T) {
  355. testCases := []struct {
  356. name string
  357. hostnameOverrideFlag string
  358. expectedHostname string
  359. expectError bool
  360. }{
  361. {
  362. name: "Hostname from config file",
  363. hostnameOverrideFlag: "",
  364. expectedHostname: "foo",
  365. expectError: false,
  366. },
  367. {
  368. name: "Hostname from flag",
  369. hostnameOverrideFlag: " bar ",
  370. expectedHostname: "bar",
  371. expectError: false,
  372. },
  373. {
  374. name: "Hostname is space",
  375. hostnameOverrideFlag: " ",
  376. expectError: true,
  377. },
  378. }
  379. for _, tc := range testCases {
  380. t.Run(tc.name, func(t *testing.T) {
  381. options := NewOptions()
  382. options.config = &kubeproxyconfig.KubeProxyConfiguration{
  383. HostnameOverride: "foo",
  384. }
  385. options.hostnameOverride = tc.hostnameOverrideFlag
  386. err := options.processHostnameOverrideFlag()
  387. if tc.expectError {
  388. if err == nil {
  389. t.Fatalf("should error for this case %s", tc.name)
  390. }
  391. } else {
  392. assert.NoError(t, err, "unexpected error %v", err)
  393. if tc.expectedHostname != options.config.HostnameOverride {
  394. t.Fatalf("expected hostname: %s, but got: %s", tc.expectedHostname, options.config.HostnameOverride)
  395. }
  396. }
  397. })
  398. }
  399. }
  400. func TestConfigChange(t *testing.T) {
  401. setUp := func() (*os.File, string, error) {
  402. tempDir, err := ioutil.TempDir("", "kubeproxy-config-change")
  403. if err != nil {
  404. return nil, "", fmt.Errorf("unable to create temporary directory: %v", err)
  405. }
  406. fullPath := filepath.Join(tempDir, "kube-proxy-config")
  407. file, err := os.Create(fullPath)
  408. if err != nil {
  409. return nil, "", fmt.Errorf("unexpected error when creating temp file: %v", err)
  410. }
  411. _, err = file.WriteString(`apiVersion: kubeproxy.config.k8s.io/v1alpha1
  412. bindAddress: 0.0.0.0
  413. clientConnection:
  414. acceptContentTypes: ""
  415. burst: 10
  416. contentType: application/vnd.kubernetes.protobuf
  417. kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
  418. qps: 5
  419. clusterCIDR: 10.244.0.0/16
  420. configSyncPeriod: 15m0s
  421. conntrack:
  422. maxPerCore: 32768
  423. min: 131072
  424. tcpCloseWaitTimeout: 1h0m0s
  425. tcpEstablishedTimeout: 24h0m0s
  426. enableProfiling: false
  427. healthzBindAddress: 0.0.0.0:10256
  428. hostnameOverride: ""
  429. iptables:
  430. masqueradeAll: false
  431. masqueradeBit: 14
  432. minSyncPeriod: 0s
  433. syncPeriod: 30s
  434. ipvs:
  435. excludeCIDRs: null
  436. minSyncPeriod: 0s
  437. scheduler: ""
  438. syncPeriod: 30s
  439. kind: KubeProxyConfiguration
  440. metricsBindAddress: 127.0.0.1:10249
  441. mode: ""
  442. nodePortAddresses: null
  443. oomScoreAdj: -999
  444. portRange: ""
  445. detectLocalMode: "ClusterCIDR"
  446. udpIdleTimeout: 250ms`)
  447. if err != nil {
  448. return nil, "", fmt.Errorf("unexpected error when writing content to temp kube-proxy config file: %v", err)
  449. }
  450. return file, tempDir, nil
  451. }
  452. tearDown := func(file *os.File, tempDir string) {
  453. file.Close()
  454. os.RemoveAll(tempDir)
  455. }
  456. testCases := []struct {
  457. name string
  458. proxyServer proxyRun
  459. append bool
  460. expectedErr string
  461. }{
  462. {
  463. name: "update config file",
  464. proxyServer: new(fakeProxyServerLongRun),
  465. append: true,
  466. expectedErr: "content of the proxy server's configuration file was updated",
  467. },
  468. {
  469. name: "fake error",
  470. proxyServer: new(fakeProxyServerError),
  471. expectedErr: "mocking error from ProxyServer.Run()",
  472. },
  473. }
  474. for _, tc := range testCases {
  475. file, tempDir, err := setUp()
  476. if err != nil {
  477. t.Fatalf("unexpected error when setting up environment: %v", err)
  478. }
  479. opt := NewOptions()
  480. opt.ConfigFile = file.Name()
  481. err = opt.Complete()
  482. if err != nil {
  483. t.Fatal(err)
  484. }
  485. opt.proxyServer = tc.proxyServer
  486. errCh := make(chan error)
  487. go func() {
  488. errCh <- opt.runLoop()
  489. }()
  490. if tc.append {
  491. file.WriteString("append fake content")
  492. }
  493. select {
  494. case err := <-errCh:
  495. if err != nil {
  496. if !strings.Contains(err.Error(), tc.expectedErr) {
  497. t.Errorf("[%s] Expected error containing %v, got %v", tc.name, tc.expectedErr, err)
  498. }
  499. }
  500. case <-time.After(10 * time.Second):
  501. t.Errorf("[%s] Timeout: unable to get any events or internal timeout.", tc.name)
  502. }
  503. tearDown(file, tempDir)
  504. }
  505. }
  506. type fakeProxyServerLongRun struct{}
  507. // Run runs the specified ProxyServer.
  508. func (s *fakeProxyServerLongRun) Run() error {
  509. for {
  510. time.Sleep(2 * time.Second)
  511. }
  512. }
  513. // CleanupAndExit runs in the specified ProxyServer.
  514. func (s *fakeProxyServerLongRun) CleanupAndExit() error {
  515. return nil
  516. }
  517. type fakeProxyServerError struct{}
  518. // Run runs the specified ProxyServer.
  519. func (s *fakeProxyServerError) Run() error {
  520. for {
  521. time.Sleep(2 * time.Second)
  522. return fmt.Errorf("mocking error from ProxyServer.Run()")
  523. }
  524. }
  525. // CleanupAndExit runs in the specified ProxyServer.
  526. func (s *fakeProxyServerError) CleanupAndExit() error {
  527. return errors.New("mocking error from ProxyServer.CleanupAndExit()")
  528. }
  529. func TestAddressFromDeprecatedFlags(t *testing.T) {
  530. testCases := []struct {
  531. name string
  532. healthzPort int32
  533. healthzBindAddress string
  534. metricsPort int32
  535. metricsBindAddress string
  536. expHealthz string
  537. expMetrics string
  538. }{
  539. {
  540. name: "IPv4 bind address",
  541. healthzBindAddress: "1.2.3.4",
  542. healthzPort: 12345,
  543. metricsBindAddress: "2.3.4.5",
  544. metricsPort: 23456,
  545. expHealthz: "1.2.3.4:12345",
  546. expMetrics: "2.3.4.5:23456",
  547. },
  548. {
  549. name: "IPv4 bind address has port",
  550. healthzBindAddress: "1.2.3.4:12345",
  551. healthzPort: 23456,
  552. metricsBindAddress: "2.3.4.5:12345",
  553. metricsPort: 23456,
  554. expHealthz: "1.2.3.4:12345",
  555. expMetrics: "2.3.4.5:12345",
  556. },
  557. {
  558. name: "IPv6 bind address",
  559. healthzBindAddress: "fd00:1::5",
  560. healthzPort: 12345,
  561. metricsBindAddress: "fd00:1::6",
  562. metricsPort: 23456,
  563. expHealthz: "[fd00:1::5]:12345",
  564. expMetrics: "[fd00:1::6]:23456",
  565. },
  566. {
  567. name: "IPv6 bind address has port",
  568. healthzBindAddress: "[fd00:1::5]:12345",
  569. healthzPort: 56789,
  570. metricsBindAddress: "[fd00:1::6]:56789",
  571. metricsPort: 12345,
  572. expHealthz: "[fd00:1::5]:12345",
  573. expMetrics: "[fd00:1::6]:56789",
  574. },
  575. {
  576. name: "Invalid IPv6 Config",
  577. healthzBindAddress: "[fd00:1::5]",
  578. healthzPort: 12345,
  579. metricsBindAddress: "[fd00:1::6]",
  580. metricsPort: 56789,
  581. expHealthz: "[fd00:1::5]",
  582. expMetrics: "[fd00:1::6]",
  583. },
  584. }
  585. for i := range testCases {
  586. gotHealthz := addressFromDeprecatedFlags(testCases[i].healthzBindAddress, testCases[i].healthzPort)
  587. gotMetrics := addressFromDeprecatedFlags(testCases[i].metricsBindAddress, testCases[i].metricsPort)
  588. errFn := func(name, except, got string) {
  589. t.Errorf("case %s: expected %v, got %v", name, except, got)
  590. }
  591. if gotHealthz != testCases[i].expHealthz {
  592. errFn(testCases[i].name, testCases[i].expHealthz, gotHealthz)
  593. }
  594. if gotMetrics != testCases[i].expMetrics {
  595. errFn(testCases[i].name, testCases[i].expMetrics, gotMetrics)
  596. }
  597. }
  598. }