mirror of https://github.com/linkerd/linkerd2.git
893 lines
29 KiB
Go
893 lines
29 KiB
Go
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/linkerd/linkerd2/controller/gen/config"
|
|
pb "github.com/linkerd/linkerd2/controller/gen/config"
|
|
"github.com/linkerd/linkerd2/pkg/k8s"
|
|
)
|
|
|
|
type testCase struct {
|
|
inputFileName string
|
|
goldenFileName string
|
|
reportFileName string
|
|
injectProxy bool
|
|
testInjectConfig *config.All
|
|
overrideAnnotations map[string]string
|
|
enableDebugSidecarFlag bool
|
|
}
|
|
|
|
func mkFilename(filename string, verbose bool) string {
|
|
if verbose {
|
|
return fmt.Sprintf("%s.verbose", filename)
|
|
}
|
|
return filename
|
|
}
|
|
|
|
func testUninjectAndInject(t *testing.T, tc testCase) {
|
|
file, err := os.Open("testdata/" + tc.inputFileName)
|
|
if err != nil {
|
|
t.Errorf("error opening test input file: %v\n", err)
|
|
}
|
|
|
|
read := bufio.NewReader(file)
|
|
|
|
output := new(bytes.Buffer)
|
|
report := new(bytes.Buffer)
|
|
transformer := &resourceTransformerInject{
|
|
injectProxy: tc.injectProxy,
|
|
configs: tc.testInjectConfig,
|
|
overrideAnnotations: tc.overrideAnnotations,
|
|
enableDebugSidecar: tc.enableDebugSidecarFlag,
|
|
allowNsInject: true,
|
|
}
|
|
|
|
if exitCode := uninjectAndInject([]io.Reader{read}, report, output, transformer); exitCode != 0 {
|
|
t.Errorf("Unexpected error injecting YAML: %v\n", report)
|
|
}
|
|
diffTestdata(t, tc.goldenFileName, output.String())
|
|
|
|
reportFileName := mkFilename(tc.reportFileName, verbose)
|
|
diffTestdata(t, reportFileName, report.String())
|
|
}
|
|
|
|
func testInstallConfig(ctx context.Context) *pb.All {
|
|
installOptions, err := testInstallOptions()
|
|
if err != nil {
|
|
log.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
_, c, err := installOptions.validateAndBuild(ctx, "", nil)
|
|
if err != nil {
|
|
log.Fatalf("test install options must be valid: %s", err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
func TestUninjectAndInject(t *testing.T) {
|
|
ctx := context.Background()
|
|
defaultConfig := testInstallConfig(ctx)
|
|
defaultConfig.Global.Version = "test-inject-control-plane-version"
|
|
defaultConfig.Proxy.ProxyVersion = "test-inject-proxy-version"
|
|
defaultConfig.Proxy.DebugImageVersion = "test-inject-debug-version"
|
|
|
|
emptyVersionConfig := testInstallConfig(ctx)
|
|
emptyVersionConfig.Global.Version = ""
|
|
emptyVersionConfig.Proxy.ProxyVersion = ""
|
|
|
|
emptyProxyVersionConfig := testInstallConfig(ctx)
|
|
emptyProxyVersionConfig.Global.Version = "test-inject-control-plane-version"
|
|
emptyProxyVersionConfig.Proxy.ProxyVersion = ""
|
|
|
|
overrideConfig := testInstallConfig(ctx)
|
|
overrideConfig.Proxy.ProxyVersion = "override"
|
|
|
|
proxyResourceConfig := testInstallConfig(ctx)
|
|
proxyResourceConfig.Proxy.ProxyVersion = defaultConfig.Proxy.ProxyVersion
|
|
proxyResourceConfig.Proxy.Resource = &config.ResourceRequirements{
|
|
RequestCpu: "110m",
|
|
RequestMemory: "100Mi",
|
|
LimitCpu: "160m",
|
|
LimitMemory: "150Mi",
|
|
}
|
|
|
|
cniEnabledConfig := testInstallConfig(ctx)
|
|
cniEnabledConfig.Proxy.ProxyVersion = defaultConfig.Proxy.ProxyVersion
|
|
cniEnabledConfig.Global.CniEnabled = true
|
|
|
|
proxyIgnorePortsOptions, err := testInstallOptions()
|
|
if err != nil {
|
|
log.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
proxyIgnorePortsOptions.ignoreInboundPorts = []string{"22", "8100-8102"}
|
|
proxyIgnorePortsOptions.ignoreOutboundPorts = []string{"5432"}
|
|
_, proxyIgnorePortsConfig, err := proxyIgnorePortsOptions.validateAndBuild(ctx, "", nil)
|
|
if err != nil {
|
|
log.Fatalf("test install proxy-ignore options must be valid: %s", err)
|
|
}
|
|
|
|
testCases := []testCase{
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_empty_version_config.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: emptyVersionConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_empty_proxy_version_config.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: emptyProxyVersionConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_overridden_noinject.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: false,
|
|
testInjectConfig: defaultConfig,
|
|
overrideAnnotations: map[string]string{
|
|
k8s.ProxyAdminPortAnnotation: "1234",
|
|
},
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_overridden.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
overrideAnnotations: map[string]string{
|
|
k8s.ProxyAdminPortAnnotation: "1234",
|
|
},
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_list.input.yml",
|
|
goldenFileName: "inject_emojivoto_list.golden.yml",
|
|
reportFileName: "inject_emojivoto_list.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_hostNetwork_false.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_hostNetwork_false.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment_hostNetwork_false.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_capabilities.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_capabilities.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_injectDisabled.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_injectDisabled.input.yml",
|
|
reportFileName: "inject_emojivoto_deployment_injectDisabled.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_controller_name.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_controller_name.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment_controller_name.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_statefulset.input.yml",
|
|
goldenFileName: "inject_emojivoto_statefulset.golden.yml",
|
|
reportFileName: "inject_emojivoto_statefulset.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_cronjob.input.yml",
|
|
goldenFileName: "inject_emojivoto_cronjob.golden.yml",
|
|
reportFileName: "inject_emojivoto_cronjob.report",
|
|
injectProxy: false,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_cronjob_nometa.input.yml",
|
|
goldenFileName: "inject_emojivoto_cronjob_nometa.golden.yml",
|
|
reportFileName: "inject_emojivoto_cronjob.report",
|
|
injectProxy: false,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_pod.input.yml",
|
|
goldenFileName: "inject_emojivoto_pod.golden.yml",
|
|
reportFileName: "inject_emojivoto_pod.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_pod_with_requests.input.yml",
|
|
goldenFileName: "inject_emojivoto_pod_with_requests.golden.yml",
|
|
reportFileName: "inject_emojivoto_pod_with_requests.report",
|
|
injectProxy: true,
|
|
testInjectConfig: proxyResourceConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_udp.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_udp.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment_udp.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_already_injected.input.yml",
|
|
goldenFileName: "inject_emojivoto_already_injected.golden.yml",
|
|
reportFileName: "inject_emojivoto_already_injected.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_contour.input.yml",
|
|
goldenFileName: "inject_contour.golden.yml",
|
|
reportFileName: "inject_contour.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_empty_resources.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_empty_resources.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment_empty_resources.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_list_empty_resources.input.yml",
|
|
goldenFileName: "inject_emojivoto_list_empty_resources.golden.yml",
|
|
reportFileName: "inject_emojivoto_list_empty_resources.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_no_init_container.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: cniEnabledConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_config_overrides.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_config_overrides.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: overrideConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_debug.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
enableDebugSidecarFlag: true,
|
|
},
|
|
{
|
|
inputFileName: "inject_tap_deployment.input.yml",
|
|
goldenFileName: "inject_tap_deployment_debug.golden.yml",
|
|
reportFileName: "inject_tap_deployment_debug.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
enableDebugSidecarFlag: true,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_namespace_good.input.yml",
|
|
goldenFileName: "inject_emojivoto_namespace_good.golden.yml",
|
|
reportFileName: "inject_emojivoto_namespace_good.golden.report",
|
|
injectProxy: false,
|
|
testInjectConfig: defaultConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_namespace_good.input.yml",
|
|
goldenFileName: "inject_emojivoto_namespace_overidden_good.golden.yml",
|
|
reportFileName: "inject_emojivoto_namespace_good.golden.report",
|
|
injectProxy: false,
|
|
testInjectConfig: defaultConfig,
|
|
overrideAnnotations: map[string]string{
|
|
k8s.IdentityModeAnnotation: "default",
|
|
k8s.CreatedByAnnotation: "linkerd/cli dev-undefined",
|
|
},
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_proxyignores.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment.report",
|
|
injectProxy: true,
|
|
testInjectConfig: proxyIgnorePortsConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_pod.input.yml",
|
|
goldenFileName: "inject_emojivoto_pod_proxyignores.golden.yml",
|
|
reportFileName: "inject_emojivoto_pod.report",
|
|
injectProxy: true,
|
|
testInjectConfig: proxyIgnorePortsConfig,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment.input.yml",
|
|
goldenFileName: "inject_emojivoto_deployment_trace.golden.yml",
|
|
reportFileName: "inject_emojivoto_deployment_trace.report",
|
|
injectProxy: true,
|
|
testInjectConfig: defaultConfig,
|
|
overrideAnnotations: map[string]string{
|
|
k8s.ProxyTraceCollectorSvcAddrAnnotation: "linkerd-collector",
|
|
k8s.ProxyTraceCollectorSvcAccountAnnotation: "linkerd-collector.linkerd",
|
|
},
|
|
},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc // pin
|
|
verbose = true
|
|
t.Run(fmt.Sprintf("%d: %s --verbose", i, tc.inputFileName), func(t *testing.T) {
|
|
testUninjectAndInject(t, tc)
|
|
})
|
|
verbose = false
|
|
t.Run(fmt.Sprintf("%d: %s", i, tc.inputFileName), func(t *testing.T) {
|
|
testUninjectAndInject(t, tc)
|
|
})
|
|
}
|
|
}
|
|
|
|
type injectCmd struct {
|
|
inputFileName string
|
|
stdErrGoldenFileName string
|
|
stdOutGoldenFileName string
|
|
exitCode int
|
|
injectProxy bool
|
|
}
|
|
|
|
func testInjectCmd(t *testing.T, tc injectCmd) {
|
|
testConfig := testInstallConfig(context.Background())
|
|
testConfig.Proxy.ProxyVersion = "testinjectversion"
|
|
|
|
errBuffer := &bytes.Buffer{}
|
|
outBuffer := &bytes.Buffer{}
|
|
|
|
in, err := os.Open(fmt.Sprintf("testdata/%s", tc.inputFileName))
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %v", err)
|
|
}
|
|
|
|
transformer := &resourceTransformerInject{
|
|
injectProxy: tc.injectProxy,
|
|
configs: testConfig,
|
|
}
|
|
exitCode := runInjectCmd([]io.Reader{in}, errBuffer, outBuffer, transformer)
|
|
if exitCode != tc.exitCode {
|
|
t.Fatalf("Expected exit code to be %d but got: %d", tc.exitCode, exitCode)
|
|
}
|
|
if tc.stdOutGoldenFileName != "" {
|
|
diffTestdata(t, tc.stdOutGoldenFileName, outBuffer.String())
|
|
} else if outBuffer.Len() != 0 {
|
|
t.Fatalf("Expected no standard output, but got: %s", outBuffer)
|
|
}
|
|
|
|
stdErrGoldenFileName := mkFilename(tc.stdErrGoldenFileName, verbose)
|
|
diffTestdata(t, stdErrGoldenFileName, errBuffer.String())
|
|
}
|
|
|
|
func TestRunInjectCmd(t *testing.T) {
|
|
testCases := []injectCmd{
|
|
{
|
|
inputFileName: "inject_gettest_deployment.bad.input.yml",
|
|
stdErrGoldenFileName: "inject_gettest_deployment.bad.golden",
|
|
exitCode: 1,
|
|
injectProxy: true,
|
|
},
|
|
{
|
|
inputFileName: "inject_tap_deployment.input.yml",
|
|
stdErrGoldenFileName: "inject_tap_deployment.bad.golden",
|
|
exitCode: 1,
|
|
injectProxy: false,
|
|
},
|
|
{
|
|
inputFileName: "inject_gettest_deployment.good.input.yml",
|
|
stdOutGoldenFileName: "inject_gettest_deployment.good.golden.yml",
|
|
stdErrGoldenFileName: "inject_gettest_deployment.good.golden.stderr",
|
|
exitCode: 0,
|
|
injectProxy: true,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_automountServiceAccountToken_false.input.yml",
|
|
stdOutGoldenFileName: "inject_emojivoto_deployment_automountServiceAccountToken_false.golden.yml",
|
|
stdErrGoldenFileName: "inject_emojivoto_deployment_automountServiceAccountToken_false.golden.stderr",
|
|
exitCode: 1,
|
|
injectProxy: false,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_istio.input.yml",
|
|
stdOutGoldenFileName: "inject_emojivoto_istio.golden.yml",
|
|
stdErrGoldenFileName: "inject_emojivoto_istio.golden.stderr",
|
|
exitCode: 1,
|
|
injectProxy: true,
|
|
},
|
|
{
|
|
inputFileName: "inject_emojivoto_deployment_hostNetwork_true.input.yml",
|
|
stdOutGoldenFileName: "inject_emojivoto_deployment_hostNetwork_true.golden.yml",
|
|
stdErrGoldenFileName: "inject_emojivoto_deployment_hostNetwork_true.golden.stderr",
|
|
exitCode: 1,
|
|
injectProxy: true,
|
|
},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc // pin
|
|
verbose = true
|
|
t.Run(fmt.Sprintf("%d: %s --verbose", i, tc.inputFileName), func(t *testing.T) {
|
|
testInjectCmd(t, tc)
|
|
})
|
|
verbose = false
|
|
t.Run(fmt.Sprintf("%d: %s", i, tc.inputFileName), func(t *testing.T) {
|
|
testInjectCmd(t, tc)
|
|
})
|
|
}
|
|
}
|
|
|
|
type injectFilePath struct {
|
|
resource string
|
|
resourceFile string
|
|
expectedFile string
|
|
stdErrFile string
|
|
}
|
|
|
|
func testInjectFilePath(ctx context.Context, t *testing.T, tc injectFilePath) {
|
|
in, err := read("testdata/" + tc.resourceFile)
|
|
if err != nil {
|
|
t.Fatal("Unexpected error: ", err)
|
|
}
|
|
|
|
errBuf := &bytes.Buffer{}
|
|
actual := &bytes.Buffer{}
|
|
transformer := &resourceTransformerInject{
|
|
injectProxy: true,
|
|
configs: testInstallConfig(ctx),
|
|
}
|
|
if exitCode := runInjectCmd(in, errBuf, actual, transformer); exitCode != 0 {
|
|
t.Fatal("Unexpected error. Exit code from runInjectCmd: ", exitCode)
|
|
}
|
|
diffTestdata(t, tc.expectedFile, actual.String())
|
|
|
|
stdErrFile := mkFilename(tc.stdErrFile, verbose)
|
|
diffTestdata(t, stdErrFile, errBuf.String())
|
|
}
|
|
|
|
func testReadFromFolder(ctx context.Context, t *testing.T, resourceFolder string, expectedFolder string) {
|
|
in, err := read("testdata/" + resourceFolder)
|
|
if err != nil {
|
|
t.Fatal("Unexpected error: ", err)
|
|
}
|
|
|
|
errBuf := &bytes.Buffer{}
|
|
actual := &bytes.Buffer{}
|
|
transformer := &resourceTransformerInject{
|
|
injectProxy: true,
|
|
configs: testInstallConfig(ctx),
|
|
}
|
|
if exitCode := runInjectCmd(in, errBuf, actual, transformer); exitCode != 0 {
|
|
t.Fatal("Unexpected error. Exit code from runInjectCmd: ", exitCode)
|
|
}
|
|
|
|
expectedFile := filepath.Join(expectedFolder, "injected_nginx_redis.yaml")
|
|
diffTestdata(t, expectedFile, actual.String())
|
|
|
|
stdErrFileName := mkFilename(filepath.Join(expectedFolder, "injected_nginx_redis.stderr"), verbose)
|
|
diffTestdata(t, stdErrFileName, errBuf.String())
|
|
}
|
|
|
|
func TestInjectFilePath(t *testing.T) {
|
|
var (
|
|
resourceFolder = filepath.Join("inject-filepath", "resources")
|
|
expectedFolder = filepath.Join("inject-filepath", "expected")
|
|
)
|
|
|
|
ctx := context.Background()
|
|
|
|
t.Run("read from files", func(t *testing.T) {
|
|
testCases := []injectFilePath{
|
|
{
|
|
resource: "nginx",
|
|
resourceFile: filepath.Join(resourceFolder, "nginx.yaml"),
|
|
expectedFile: filepath.Join(expectedFolder, "injected_nginx.yaml"),
|
|
stdErrFile: filepath.Join(expectedFolder, "injected_nginx.stderr"),
|
|
},
|
|
{
|
|
resource: "redis",
|
|
resourceFile: filepath.Join(resourceFolder, "db/redis.yaml"),
|
|
expectedFile: filepath.Join(expectedFolder, "injected_redis.yaml"),
|
|
stdErrFile: filepath.Join(expectedFolder, "injected_redis.stderr"),
|
|
},
|
|
}
|
|
|
|
for i, testCase := range testCases {
|
|
testCase := testCase // pin
|
|
verbose = true
|
|
t.Run(fmt.Sprintf("%d %s", i, testCase.resource), func(t *testing.T) {
|
|
testInjectFilePath(ctx, t, testCase)
|
|
})
|
|
verbose = false
|
|
t.Run(fmt.Sprintf("%d %s", i, testCase.resource), func(t *testing.T) {
|
|
testInjectFilePath(ctx, t, testCase)
|
|
})
|
|
}
|
|
})
|
|
|
|
verbose = true
|
|
t.Run("read from folder --verbose", func(t *testing.T) {
|
|
testReadFromFolder(ctx, t, resourceFolder, expectedFolder)
|
|
})
|
|
verbose = false
|
|
t.Run("read from folder --verbose", func(t *testing.T) {
|
|
testReadFromFolder(ctx, t, resourceFolder, expectedFolder)
|
|
})
|
|
}
|
|
|
|
func TestValidURL(t *testing.T) {
|
|
// if the string follows a URL pattern, true has to be returned
|
|
// if not false is returned
|
|
|
|
tests := map[string]bool{
|
|
"http://www.linkerd.io": true,
|
|
"https://www.linkerd.io": true,
|
|
"www.linkerd.io/": false,
|
|
"~/foo/bar.yaml": false,
|
|
"./foo/bar.yaml": false,
|
|
"/foo/bar/baz.yml": false,
|
|
"../foo/bar/baz.yaml": false,
|
|
"https//": false,
|
|
}
|
|
|
|
for url, expectedValue := range tests {
|
|
value := isValidURL(url)
|
|
if value != expectedValue {
|
|
t.Errorf("Result mismatch for %s. expected %v, but got %v", url, expectedValue, value)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestWalk(t *testing.T) {
|
|
// create two data files, one in the root folder and the other in a subfolder.
|
|
// walk should be able to read the content of the two data files recursively.
|
|
var (
|
|
tmpFolderRoot = "linkerd-testdata"
|
|
tmpFolderData = filepath.Join(tmpFolderRoot, "data")
|
|
)
|
|
|
|
if err := os.MkdirAll(tmpFolderData, os.ModeDir|os.ModePerm); err != nil {
|
|
t.Fatal("Unexpected error: ", err)
|
|
}
|
|
defer func() {
|
|
err := os.RemoveAll(tmpFolderRoot)
|
|
if err != nil {
|
|
t.Errorf("failed to remove temp dir %q: %v", tmpFolderRoot, err)
|
|
}
|
|
}()
|
|
|
|
var (
|
|
data = []byte(readTestdata(t, "inject_gettest_deployment.bad.input.yml"))
|
|
file1 = filepath.Join(tmpFolderRoot, "root.txt")
|
|
file2 = filepath.Join(tmpFolderData, "data.txt")
|
|
)
|
|
if err := ioutil.WriteFile(file1, data, 0644); err != nil {
|
|
t.Fatal("Unexpected error: ", err)
|
|
}
|
|
if err := ioutil.WriteFile(file2, data, 0644); err != nil {
|
|
t.Fatal("Unexpected error: ", err)
|
|
}
|
|
|
|
actual, err := walk(tmpFolderRoot)
|
|
if err != nil {
|
|
t.Fatal("Unexpected error: ", err)
|
|
}
|
|
|
|
for _, r := range actual {
|
|
b := make([]byte, len(data))
|
|
r.Read(b)
|
|
|
|
if string(b) != string(data) {
|
|
t.Errorf("Content mismatch. Expected %q, but got %q", data, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOverrideConfigsParameterized(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
description string
|
|
configOptions proxyConfigOptions
|
|
expectedOverrides map[string]string
|
|
}{
|
|
{
|
|
description: "proxy configuration overrides",
|
|
configOptions: proxyConfigOptions{
|
|
ignoreInboundPorts: []string{"8500-8505"},
|
|
ignoreOutboundPorts: []string{"3306"},
|
|
proxyAdminPort: 1234,
|
|
proxyControlPort: 4190,
|
|
proxyInboundPort: 4143,
|
|
proxyOutboundPort: 4140,
|
|
proxyUID: 999,
|
|
proxyLogLevel: "debug",
|
|
proxyLogFormat: "plain",
|
|
disableIdentity: true,
|
|
disableTap: true,
|
|
enableExternalProfiles: true,
|
|
proxyCPURequest: "10m",
|
|
proxyCPULimit: "100m",
|
|
proxyMemoryRequest: "10Mi",
|
|
proxyMemoryLimit: "50Mi",
|
|
traceCollector: "oc-collector.tracing:55678",
|
|
traceCollectorSvcAccount: "default",
|
|
waitBeforeExitSeconds: 10,
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyIgnoreInboundPortsAnnotation: "8500-8505",
|
|
k8s.ProxyIgnoreOutboundPortsAnnotation: "3306",
|
|
k8s.ProxyAdminPortAnnotation: "1234",
|
|
k8s.ProxyControlPortAnnotation: "4190",
|
|
k8s.ProxyInboundPortAnnotation: "4143",
|
|
k8s.ProxyOutboundPortAnnotation: "4140",
|
|
k8s.ProxyUIDAnnotation: "999",
|
|
k8s.ProxyLogLevelAnnotation: "debug",
|
|
k8s.ProxyLogFormatAnnotation: "plain",
|
|
k8s.ProxyDisableIdentityAnnotation: "true",
|
|
k8s.ProxyDisableTapAnnotation: "true",
|
|
k8s.ProxyEnableExternalProfilesAnnotation: "true",
|
|
k8s.ProxyCPURequestAnnotation: "10m",
|
|
k8s.ProxyCPULimitAnnotation: "100m",
|
|
k8s.ProxyMemoryRequestAnnotation: "10Mi",
|
|
k8s.ProxyMemoryLimitAnnotation: "50Mi",
|
|
k8s.ProxyTraceCollectorSvcAddrAnnotation: "oc-collector.tracing:55678",
|
|
k8s.ProxyTraceCollectorSvcAccountAnnotation: "default",
|
|
k8s.ProxyWaitBeforeExitSecondsAnnotation: "10",
|
|
},
|
|
},
|
|
{
|
|
description: "proxy image overrides",
|
|
configOptions: proxyConfigOptions{
|
|
proxyImage: "ghcr.io/linkerd/proxy",
|
|
proxyVersion: "test-proxy-version",
|
|
imagePullPolicy: "IfNotPresent",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyImageAnnotation: "ghcr.io/linkerd/proxy",
|
|
k8s.ProxyVersionOverrideAnnotation: "test-proxy-version",
|
|
k8s.ProxyImagePullPolicyAnnotation: "IfNotPresent",
|
|
},
|
|
},
|
|
{
|
|
description: "proxy-init image overrides",
|
|
configOptions: proxyConfigOptions{
|
|
initImage: "ghcr.io/linkerd/proxy-init",
|
|
initImageVersion: "test-proxy-init-version",
|
|
imagePullPolicy: "IfNotPresent",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyInitImageAnnotation: "ghcr.io/linkerd/proxy-init",
|
|
k8s.ProxyInitImageVersionAnnotation: "test-proxy-init-version",
|
|
k8s.ProxyImagePullPolicyAnnotation: "IfNotPresent",
|
|
},
|
|
},
|
|
{
|
|
description: "custom docker registry with proxy and proxy-init",
|
|
configOptions: proxyConfigOptions{
|
|
proxyImage: "ghcr.io/linkerd/proxy",
|
|
initImage: "ghcr.io/linkerd/proxy-init",
|
|
dockerRegistry: "my.custom.registry/linkerd-io",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyImageAnnotation: "ghcr.io/linkerd/proxy",
|
|
k8s.ProxyInitImageAnnotation: "ghcr.io/linkerd/proxy-init",
|
|
k8s.DebugImageAnnotation: "my.custom.registry/linkerd-io/debug",
|
|
},
|
|
},
|
|
{
|
|
description: "custom docker registry",
|
|
configOptions: proxyConfigOptions{
|
|
dockerRegistry: "my.custom.registry/linkerd-io",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyImageAnnotation: "my.custom.registry/linkerd-io/proxy",
|
|
k8s.ProxyInitImageAnnotation: "my.custom.registry/linkerd-io/proxy-init",
|
|
k8s.DebugImageAnnotation: "my.custom.registry/linkerd-io/debug",
|
|
},
|
|
},
|
|
{
|
|
description: "no overrides",
|
|
configOptions: proxyConfigOptions{},
|
|
expectedOverrides: map[string]string{},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
tt := tt // pin
|
|
t.Run(tt.description, func(t *testing.T) {
|
|
defaultConfig := testInstallConfig(context.Background())
|
|
actualOverrides := map[string]string{}
|
|
tt.configOptions.overrideConfigs(defaultConfig, actualOverrides)
|
|
if len(tt.expectedOverrides) != len(actualOverrides) {
|
|
t.Fatalf("expected %d annotation(s), but received %d", len(tt.expectedOverrides), len(actualOverrides))
|
|
}
|
|
for key, expected := range tt.expectedOverrides {
|
|
actual := actualOverrides[key]
|
|
if actual != expected {
|
|
t.Fatalf("expected annotation %q with %q, but got %q", key, expected, actual)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOverrideConfigsWithCustomRegistryInstall(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
description string
|
|
configOptions proxyConfigOptions
|
|
expectedOverrides map[string]string
|
|
}{
|
|
{
|
|
description: "proxy image overrides",
|
|
configOptions: proxyConfigOptions{
|
|
proxyImage: "ghcr.io/linkerd/proxy",
|
|
proxyVersion: "test-proxy-version",
|
|
imagePullPolicy: "IfNotPresent",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyImageAnnotation: "ghcr.io/linkerd/proxy",
|
|
k8s.ProxyVersionOverrideAnnotation: "test-proxy-version",
|
|
k8s.ProxyImagePullPolicyAnnotation: "IfNotPresent",
|
|
},
|
|
},
|
|
{
|
|
description: "proxy-init image overrides",
|
|
configOptions: proxyConfigOptions{
|
|
initImage: "ghcr.io/linkerd/proxy-init",
|
|
initImageVersion: "test-proxy-init-version",
|
|
imagePullPolicy: "IfNotPresent",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyInitImageAnnotation: "ghcr.io/linkerd/proxy-init",
|
|
k8s.ProxyInitImageVersionAnnotation: "test-proxy-init-version",
|
|
k8s.ProxyImagePullPolicyAnnotation: "IfNotPresent",
|
|
},
|
|
},
|
|
{
|
|
description: "custom docker registry with proxy and proxy-init",
|
|
configOptions: proxyConfigOptions{
|
|
proxyImage: "ghcr.io/linkerd/proxy",
|
|
initImage: "ghcr.io/linkerd/proxy-init",
|
|
dockerRegistry: "my.custom.registry/linkerd-io",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyImageAnnotation: "ghcr.io/linkerd/proxy",
|
|
k8s.ProxyInitImageAnnotation: "ghcr.io/linkerd/proxy-init",
|
|
k8s.DebugImageAnnotation: "my.custom.registry/linkerd-io/debug",
|
|
},
|
|
},
|
|
{
|
|
description: "custom docker registry",
|
|
configOptions: proxyConfigOptions{
|
|
dockerRegistry: "my.custom.registry/linkerd-io",
|
|
},
|
|
expectedOverrides: map[string]string{
|
|
k8s.ProxyImageAnnotation: "my.custom.registry/linkerd-io/proxy",
|
|
k8s.ProxyInitImageAnnotation: "my.custom.registry/linkerd-io/proxy-init",
|
|
k8s.DebugImageAnnotation: "my.custom.registry/linkerd-io/debug",
|
|
},
|
|
},
|
|
{
|
|
description: "no overrides",
|
|
configOptions: proxyConfigOptions{},
|
|
expectedOverrides: map[string]string{},
|
|
},
|
|
}
|
|
|
|
// Setup the registry used when "installing" linkerd
|
|
customRegistryAtInstall := "custom.install.registry/linkerd-io"
|
|
installFlags := make([]*pb.Install_Flag, 0)
|
|
installFlags = append(installFlags, &pb.Install_Flag{
|
|
Name: "registry",
|
|
Value: customRegistryAtInstall,
|
|
})
|
|
|
|
for _, tt := range tests {
|
|
tt := tt // pin
|
|
t.Run(tt.description, func(t *testing.T) {
|
|
|
|
defaultConfig := testInstallConfig(context.Background())
|
|
defaultConfig.Install.Flags = installFlags
|
|
defaultConfig.Proxy.ProxyImage.ImageName = customRegistryAtInstall + "/proxy"
|
|
defaultConfig.Proxy.ProxyInitImage.ImageName = customRegistryAtInstall + "/proxy-init"
|
|
defaultConfig.Proxy.DebugImage.ImageName = customRegistryAtInstall + "/debug"
|
|
|
|
actualOverrides := map[string]string{}
|
|
tt.configOptions.overrideConfigs(defaultConfig, actualOverrides)
|
|
if len(tt.expectedOverrides) != len(actualOverrides) {
|
|
t.Fatalf("expected %d annotation(s), but received %d", len(tt.expectedOverrides), len(actualOverrides))
|
|
}
|
|
for key, expected := range tt.expectedOverrides {
|
|
actual := actualOverrides[key]
|
|
if actual != expected {
|
|
t.Fatalf("expected annotation %q with %q, but got %q", key, expected, actual)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOverwriteRegistry(t *testing.T) {
|
|
testCases := []struct {
|
|
image string
|
|
registry string
|
|
expected string
|
|
}{
|
|
{
|
|
image: "ghcr.io/linkerd/image",
|
|
registry: "my.custom.registry",
|
|
expected: "my.custom.registry/image",
|
|
},
|
|
{
|
|
image: "ghcr.io/linkerd/image",
|
|
registry: "my.custom.registry/",
|
|
expected: "my.custom.registry/image",
|
|
},
|
|
{
|
|
image: "my.custom.registry/image",
|
|
registry: "my.custom.registry",
|
|
expected: "my.custom.registry/image",
|
|
},
|
|
{
|
|
image: "my.custom.registry/image",
|
|
registry: "ghcr.io/linkerd",
|
|
expected: "ghcr.io/linkerd/image",
|
|
},
|
|
{
|
|
image: "",
|
|
registry: "my.custom.registry",
|
|
expected: "",
|
|
},
|
|
{
|
|
image: "ghcr.io/linkerd/image",
|
|
registry: "",
|
|
expected: "image",
|
|
},
|
|
{
|
|
image: "image",
|
|
registry: "ghcr.io/linkerd",
|
|
expected: "ghcr.io/linkerd/image",
|
|
},
|
|
}
|
|
for i, tc := range testCases {
|
|
tc := tc // pin
|
|
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
|
actual := overwriteRegistry(tc.image, tc.registry)
|
|
if actual != tc.expected {
|
|
t.Fatalf("expected %q, but got %q", tc.expected, actual)
|
|
}
|
|
})
|
|
}
|
|
}
|