diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index f72c24e49e440..b6e300fe4df08 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -102,6 +102,7 @@ jobs: - deep - external-issuer - external-prometheus-deep + - external-resources - helm-deep - helm-upgrade - multicluster diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 154a66c2cd78a..783bc034c1278 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -102,6 +102,7 @@ jobs: - deep - external-issuer - external-prometheus-deep + - external-resources - helm-deep - helm-upgrade - uninstall diff --git a/bin/_test-helpers.sh b/bin/_test-helpers.sh index ecbcb0dfcb6e6..47a76be9ec3db 100644 --- a/bin/_test-helpers.sh +++ b/bin/_test-helpers.sh @@ -7,7 +7,8 @@ set +e ##### Test setup helpers ##### export default_test_names=(deep external-issuer external-prometheus-deep helm-deep helm-upgrade uninstall upgrade-edge upgrade-stable) -export all_test_names=(cluster-domain cni-calico-deep multicluster "${default_test_names[*]}") +export external_resource_test_names=(external-resources) +export all_test_names=(cluster-domain cni-calico-deep multicluster "${default_test_names[*]}" "${external_resource_test_names[*]}") tests_usage() { progname="${0##*/}" @@ -224,7 +225,7 @@ cleanup_cluster() { setup_cluster() { local name=$1 - export helm_path="$bindir"/helm + export helm_path="$bindir"/helm test_setup if [ -z "$skip_cluster_create" ]; then @@ -535,6 +536,12 @@ run_cluster-domain_test() { run_test "$test_directory/install_test.go" --cluster-domain='custom.domain' } +# wrapper to implement external tests +run_external-resources_test(){ + run_test "$test_directory/install_test.go" + run_test "$test_directory/externalresources/rabbitmq_test.go" +} + # exit_on_err should be called right after a command to check the result status # and eventually generate a Github error annotation. Do not use after calls to # `go test` as that generates its own annotations. Note this should be called diff --git a/go.sum b/go.sum index a9d85e1d67a2c..ab5a09fd14f11 100644 --- a/go.sum +++ b/go.sum @@ -427,6 +427,7 @@ github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -463,8 +464,6 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/linkerd/linkerd2-proxy-api v0.1.16 h1:Qjqbw5Bw3QYUJpUSpYHr4nkJqBRnTlsFUwncCtCdOEs= github.com/linkerd/linkerd2-proxy-api v0.1.16/go.mod h1:yFz+DCCEomC3vpsChFzfCuOuSJtzx7jMNNHBIlbFil0= -github.com/linkerd/linkerd2-proxy-init v1.3.8 h1:fo/LbrIS3FHssAPLkVXi5h8K/3mWP7ncVwOU2oI6Dm8= -github.com/linkerd/linkerd2-proxy-init v1.3.8/go.mod h1:M6iaaLLi06ofuIV6x74SDknSFi7VS/MFqa5m+CwHgLY= github.com/linkerd/linkerd2-proxy-init v1.3.9 h1:T2H4P6N3V7mRRr3twp0JDzvq1XSvv9S/orxWbwj7kFM= github.com/linkerd/linkerd2-proxy-init v1.3.9/go.mod h1:M6iaaLLi06ofuIV6x74SDknSFi7VS/MFqa5m+CwHgLY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= @@ -687,6 +686,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271 h1:WhxRHzgeVGETMlmVfqhRn8RIeeNoPr2Czh33I4Zdccw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -1013,6 +1013,7 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= helm.sh/helm/v3 v3.4.1 h1:NIdlBGKFRTAkhz0ooYKw1VBbmTldxNAZRY1nH6Glk6I= diff --git a/test/integration/externalresources/rabbitmq_test.go b/test/integration/externalresources/rabbitmq_test.go new file mode 100644 index 0000000000000..63bfe2e542d6f --- /dev/null +++ b/test/integration/externalresources/rabbitmq_test.go @@ -0,0 +1,87 @@ +package externalresources + +import ( + "context" + "fmt" + "os" + "testing" + "time" + + "github.com/linkerd/linkerd2/testutil" +) + +var TestHelper *testutil.TestHelper + +func TestMain(m *testing.M) { + TestHelper = testutil.NewTestHelper() + os.Exit(m.Run()) +} + +////////////////////// +/// TEST EXECUTION /// +////////////////////// + +func TestRabbitMQDeploy(t *testing.T) { + ctx := context.Background() + TestHelper.WithDataPlaneNamespace(ctx, "rabbitmq-test", map[string]string{}, t, func(t *testing.T, testNamespace string) { + out, err := TestHelper.LinkerdRun("inject", "--manual", "testdata/rabbitmq-server.yaml") + // inject rabbitmq server + if err != nil { + testutil.AnnotatedFatalf(t, "'linkerd inject' command failed", "'linkerd inject' command failed: %s", err) + } + // deploy rabbitmq server + _, err = TestHelper.KubectlApply(out, testNamespace) + if err != nil { + testutil.AnnotatedFatalf(t, "kubectl apply command failed", "'kubectl apply' command failed: %s", err) + } + if err := TestHelper.CheckPods(ctx, testNamespace, "rabbitmq", 1); err != nil { + if rce, ok := err.(*testutil.RestartCountError); ok { + testutil.AnnotatedWarn(t, "CheckPods timed-out %s", rce) + } else { + testutil.AnnotatedError(t, "CheckPods timed-out %s", err) + } + } + if err := TestHelper.CheckDeployment(ctx, testNamespace, "rabbitmq", 1); err != nil { + testutil.AnnotatedErrorf(t, "CheckDeployment timed-out", "Error validating deployment [%s]: \n%s", "rabbitmq", err) + } + // inject rabbitmq-client + stdout, err := TestHelper.LinkerdRun("inject", "--manual", "testdata/rabbitmq-client.yaml") + if err != nil { + testutil.AnnotatedFatalf(t, "'linkerd inject' command failed", "'linkerd inject' command failed: %s", err) + } + // deploy rabbitmq client + _, err = TestHelper.KubectlApply(stdout, testNamespace) + if err != nil { + testutil.AnnotatedFatalf(t, "kubectl apply command failed", "'kubectl apply' command failed: %s", err) + } + if err := TestHelper.CheckPods(ctx, testNamespace, "rabbitmq-client", 1); err != nil { + if rce, ok := err.(*testutil.RestartCountError); ok { + testutil.AnnotatedWarn(t, "CheckPods timed-out %s", rce) + } else { + testutil.AnnotatedError(t, "CheckPods timed-out %s", err) + } + } + if err := TestHelper.CheckDeployment(ctx, testNamespace, "rabbitmq-client", 1); err != nil { + testutil.AnnotatedErrorf(t, "CheckDeployment timed-out", "Error validating deployment [%s]: \n%s", "rabbitmq", err) + } + // Verify client output + golden := "check.rabbitmq.golden" + timeout := 50 * time.Second + err = TestHelper.RetryFor(timeout, func() error { + out, err := TestHelper.Kubectl("", "-n", testNamespace, "logs", "-lapp=rabbitmq-client", "-crabbitmq-client") + if err != nil { + return fmt.Errorf("'kubectl logs -l app=rabbitmq-client -c rabbitmq-client' command failed\n%s", err) + } + err = TestHelper.ValidateOutput(out, golden) + if err != nil { + return fmt.Errorf("received unexpected output\n%s", err.Error()) + } + return nil + }) + if err != nil { + testutil.AnnotatedFatal(t, fmt.Sprintf("'kubectl logs' command timed-out (%s)", timeout), err) + } + + }) + +} diff --git a/test/integration/externalresources/testdata/check.rabbitmq.golden b/test/integration/externalresources/testdata/check.rabbitmq.golden new file mode 100644 index 0000000000000..d52ddfde989a5 --- /dev/null +++ b/test/integration/externalresources/testdata/check.rabbitmq.golden @@ -0,0 +1,3 @@ +[OK] Create message queue MQTestQueue +[OK] Published message. Message count: 1 +[OK] Consumed message. Message count: 0 diff --git a/test/integration/externalresources/testdata/rabbitmq-client.yaml b/test/integration/externalresources/testdata/rabbitmq-client.yaml new file mode 100644 index 0000000000000..72ff06aa91786 --- /dev/null +++ b/test/integration/externalresources/testdata/rabbitmq-client.yaml @@ -0,0 +1,31 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rabbitmq-client + name: rabbitmq-client +spec: + replicas: 1 + selector: + matchLabels: + app: rabbitmq-client + template: + metadata: + labels: + app: rabbitmq-client + spec: + containers: + - image: ghcr.io/barkardk/rabbitmq-client:1.0.0 + name: rabbitmq-client + env: + - name: RABBITMQ_AMQP_CONN_STR + value: "amqp://guest:guest@rabbitmq:5672/" + command: + - "/bin/sh" + args: + - "-c" + - | + sleep 20 # wait for pods to start + ./mq_test + restartPolicy: Always + diff --git a/test/integration/externalresources/testdata/rabbitmq-server.yaml b/test/integration/externalresources/testdata/rabbitmq-server.yaml new file mode 100644 index 0000000000000..8d19638c81a7b --- /dev/null +++ b/test/integration/externalresources/testdata/rabbitmq-server.yaml @@ -0,0 +1,59 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rabbitmq + name: rabbitmq +spec: + replicas: 1 + selector: + matchLabels: + app: rabbitmq + template: + metadata: + labels: + app: rabbitmq + spec: + containers: + - image: rabbitmq:3.8.12-rc.3-management + name: rabbitmq + livenessProbe: + exec: + command: + - rabbitmqctl + - status + failureThreshold: 6 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + readinessProbe: + exec: + command: + - rabbitmqctl + - status + failureThreshold: 6 + initialDelaySeconds: 10 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: rabbitmq + name: rabbitmq +spec: + ports: + - name: http + port: 15672 + protocol: TCP + targetPort: 15672 + - name: amqp + port: 5672 + protocol: TCP + targetPort: 5672 + selector: + app: rabbitmq + type: ClusterIP