From 54ad84e2d5e54a203f32e32916d6da596afae2dd Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:22:07 -0800 Subject: [PATCH 01/12] chore: add CI tests --- .ci/check.sh | 7 + .ci/setup_kong.sh | 65 + .ci/setup_kong_ee.sh | 129 + .github/workflows/integration.yaml | 50 + .github/workflows/test.yaml | 36 + Makefile | 52 + tests/integration/diff_test.go | 744 +++ tests/integration/dump_test.go | 253 + tests/integration/lint_test.go | 140 + tests/integration/ping_test.go | 31 + tests/integration/reset_test.go | 108 + tests/integration/sync_test.go | 4716 +++++++++++++++++ tests/integration/test_utils.go | 344 ++ .../diff/001-not-existing-workspace/kong.yaml | 9 + .../001-not-existing-workspace/kong3x.yaml | 10 + .../testdata/diff/002-mask/initial.yaml | 5 + .../testdata/diff/002-mask/initial3x.yaml | 5 + .../testdata/diff/002-mask/kong.yaml | 16 + .../testdata/diff/002-mask/kong3x.yaml | 16 + .../testdata/diff/003-unmask/initial.yaml | 5 + .../testdata/diff/003-unmask/initial3x.yaml | 5 + .../testdata/diff/003-unmask/kong.yaml | 12 + .../testdata/diff/003-unmask/kong3x.yaml | 12 + .../dump/001-entities-with-tags/expected.yaml | 236 + .../001-entities-with-tags/expected30.yaml | 235 + .../dump/001-entities-with-tags/kong.yaml | 288 + .../expected-no-skip-34.yaml | 60 + .../expected-no-skip-35.yaml | 60 + .../002-skip-consumers/expected-no-skip.yaml | 26 + .../expected-no-skip_konnect.yaml | 62 + .../dump/002-skip-consumers/expected.yaml | 11 + .../002-skip-consumers/expected_konnect.yaml | 13 + .../dump/002-skip-consumers/kong.yaml | 18 + .../dump/002-skip-consumers/kong34.yaml | 19 + .../expected-fail-severity-error.json | 14 + .../expected-fail-severity-error.yaml | 9 + .../lint/001-simple-lint/expected.json | 22 + .../lint/001-simple-lint/expected.yaml | 15 + .../testdata/lint/001-simple-lint/kong.yaml | 9 + .../lint/001-simple-lint/ruleset.yaml | 17 + .../testdata/reset/001-skip-ca-cert/kong.yaml | 35 + .../reset/001-skip-ca-cert/kong3x.yaml | 36 + .../sync/001-create-a-service/kong.yaml | 10 + .../sync/001-create-a-service/kong3x.yaml | 10 + .../002-create-services-and-routes/kong.yaml | 16 + .../kong3x.yaml | 16 + .../sync/003-create-a-plugin/kong.yaml | 13 + .../sync/003-create-a-plugin/kong3x.yaml | 13 + .../004-create-upstream-and-target/kong.yaml | 5 + .../kong3x.yaml | 6 + .../kong.yaml | 6 + .../kong3x.yaml | 7 + .../006-fill-defaults-rate-limiting/kong.yaml | 4 + .../kong.yaml | 7 + .../sync/008-create-simple-entities/kong.yaml | 19 + .../testdata/sync/009-skip-ca-cert/kong.yaml | 30 + .../sync/009-skip-ca-cert/kong3x.yaml | 31 + .../kong.yaml | 18 + .../kong3x.yaml | 18 + .../sync/011-plugin-ordering/kong.yaml | 16 + .../testdata/sync/012-vaults/kong3x.yaml | 24 + .../kong-initial.yaml | 4 + .../kong.yaml | 4 + .../kong3x-initial.yaml | 4 + .../kong3x.yaml | 4 + .../kong-initial.yaml | 4 + .../kong.yaml | 4 + .../kong3x-initial.yaml | 4 + .../kong3x.yaml | 4 + .../sync/015-consumer-groups/kong.yaml | 14 + .../015-consumer-groups/kong3x-initial.yaml | 18 + .../sync/015-consumer-groups/kong3x.yaml | 20 + .../016-consumer-groups-and-plugins/kong.yaml | 33 + .../kong3x-initial.yaml | 35 + .../kong3x.yaml | 36 + .../kong.yaml | 79 + .../kong3x-empty-application.yaml | 48 + .../kong3x.yaml | 109 + .../kong-with-instance_name.yaml | 13 + .../kong-without-instance_name.yaml | 12 + .../sync/019-skip-consumers/kong34.yaml | 49 + .../sync/019-skip-consumers/kong3x.yaml | 45 + .../020-same-names-altered-ids/1-before.yaml | 26 + .../020-same-names-altered-ids/2-before.yaml | 26 + .../020-same-names-altered-ids/3-before.yaml | 26 + .../020-same-names-altered-ids/desired.yaml | 26 + .../021-update-with-explicit-ids/after.yaml | 18 + .../021-update-with-explicit-ids/before.yaml | 15 + .../after.yaml | 12 + .../before.yaml | 10 + .../initial.yaml | 55 + .../update.yaml | 55 + .../kong3x-reverse-order.yaml | 5 + .../kong3x.yaml | 12 + .../kong3x.yaml | 79 + .../konnect.yaml | 79 + .../sync/026-konnect-rename/default.yaml | 10 + .../konnect_default_cp.yaml | 12 + .../konnect_default_rg.yaml | 12 + .../026-konnect-rename/konnect_test_cp.yaml | 14 + .../026-konnect-rename/konnect_test_rg.yaml | 14 + .../sync/026-konnect-rename/test.yaml | 10 + .../testdata/sync/027-created-at/new.yaml | 22 + .../testdata/sync/027-created-at/old.yaml | 22 + .../sync/xxx-plugins-on-entities/kong.yaml | 50 + .../xxx-rbac-endpoint-permissions/kong.yaml | 91 + .../xxx-rbac-endpoint-permissions/kong3x.yaml | 91 + 107 files changed, 9559 insertions(+) create mode 100755 .ci/check.sh create mode 100755 .ci/setup_kong.sh create mode 100755 .ci/setup_kong_ee.sh create mode 100644 .github/workflows/integration.yaml create mode 100644 .github/workflows/test.yaml create mode 100644 Makefile create mode 100644 tests/integration/diff_test.go create mode 100644 tests/integration/dump_test.go create mode 100644 tests/integration/lint_test.go create mode 100644 tests/integration/ping_test.go create mode 100644 tests/integration/reset_test.go create mode 100644 tests/integration/sync_test.go create mode 100644 tests/integration/test_utils.go create mode 100644 tests/integration/testdata/diff/001-not-existing-workspace/kong.yaml create mode 100644 tests/integration/testdata/diff/001-not-existing-workspace/kong3x.yaml create mode 100644 tests/integration/testdata/diff/002-mask/initial.yaml create mode 100644 tests/integration/testdata/diff/002-mask/initial3x.yaml create mode 100644 tests/integration/testdata/diff/002-mask/kong.yaml create mode 100644 tests/integration/testdata/diff/002-mask/kong3x.yaml create mode 100644 tests/integration/testdata/diff/003-unmask/initial.yaml create mode 100644 tests/integration/testdata/diff/003-unmask/initial3x.yaml create mode 100644 tests/integration/testdata/diff/003-unmask/kong.yaml create mode 100644 tests/integration/testdata/diff/003-unmask/kong3x.yaml create mode 100644 tests/integration/testdata/dump/001-entities-with-tags/expected.yaml create mode 100644 tests/integration/testdata/dump/001-entities-with-tags/expected30.yaml create mode 100644 tests/integration/testdata/dump/001-entities-with-tags/kong.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-34.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-35.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/expected-no-skip.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/expected.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/expected_konnect.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/kong.yaml create mode 100644 tests/integration/testdata/dump/002-skip-consumers/kong34.yaml create mode 100644 tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.json create mode 100644 tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.yaml create mode 100644 tests/integration/testdata/lint/001-simple-lint/expected.json create mode 100644 tests/integration/testdata/lint/001-simple-lint/expected.yaml create mode 100644 tests/integration/testdata/lint/001-simple-lint/kong.yaml create mode 100644 tests/integration/testdata/lint/001-simple-lint/ruleset.yaml create mode 100644 tests/integration/testdata/reset/001-skip-ca-cert/kong.yaml create mode 100644 tests/integration/testdata/reset/001-skip-ca-cert/kong3x.yaml create mode 100644 tests/integration/testdata/sync/001-create-a-service/kong.yaml create mode 100644 tests/integration/testdata/sync/001-create-a-service/kong3x.yaml create mode 100644 tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml create mode 100644 tests/integration/testdata/sync/002-create-services-and-routes/kong3x.yaml create mode 100644 tests/integration/testdata/sync/003-create-a-plugin/kong.yaml create mode 100644 tests/integration/testdata/sync/003-create-a-plugin/kong3x.yaml create mode 100644 tests/integration/testdata/sync/004-create-upstream-and-target/kong.yaml create mode 100644 tests/integration/testdata/sync/004-create-upstream-and-target/kong3x.yaml create mode 100644 tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong.yaml create mode 100644 tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml create mode 100644 tests/integration/testdata/sync/006-fill-defaults-rate-limiting/kong.yaml create mode 100644 tests/integration/testdata/sync/007-fill-defaults-rate-limiting-dedup/kong.yaml create mode 100644 tests/integration/testdata/sync/008-create-simple-entities/kong.yaml create mode 100644 tests/integration/testdata/sync/009-skip-ca-cert/kong.yaml create mode 100644 tests/integration/testdata/sync/009-skip-ca-cert/kong3x.yaml create mode 100644 tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml create mode 100644 tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong3x.yaml create mode 100644 tests/integration/testdata/sync/011-plugin-ordering/kong.yaml create mode 100644 tests/integration/testdata/sync/012-vaults/kong3x.yaml create mode 100644 tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong-initial.yaml create mode 100644 tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong.yaml create mode 100644 tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x-initial.yaml create mode 100644 tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x.yaml create mode 100644 tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong-initial.yaml create mode 100644 tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong.yaml create mode 100644 tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x-initial.yaml create mode 100644 tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x.yaml create mode 100644 tests/integration/testdata/sync/015-consumer-groups/kong.yaml create mode 100644 tests/integration/testdata/sync/015-consumer-groups/kong3x-initial.yaml create mode 100644 tests/integration/testdata/sync/015-consumer-groups/kong3x.yaml create mode 100644 tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong.yaml create mode 100644 tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x-initial.yaml create mode 100644 tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x.yaml create mode 100644 tests/integration/testdata/sync/017-consumer-groups-rla-application/kong.yaml create mode 100644 tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x-empty-application.yaml create mode 100644 tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x.yaml create mode 100644 tests/integration/testdata/sync/018-plugin-instance_name/kong-with-instance_name.yaml create mode 100644 tests/integration/testdata/sync/018-plugin-instance_name/kong-without-instance_name.yaml create mode 100644 tests/integration/testdata/sync/019-skip-consumers/kong34.yaml create mode 100644 tests/integration/testdata/sync/019-skip-consumers/kong3x.yaml create mode 100644 tests/integration/testdata/sync/020-same-names-altered-ids/1-before.yaml create mode 100644 tests/integration/testdata/sync/020-same-names-altered-ids/2-before.yaml create mode 100644 tests/integration/testdata/sync/020-same-names-altered-ids/3-before.yaml create mode 100644 tests/integration/testdata/sync/020-same-names-altered-ids/desired.yaml create mode 100644 tests/integration/testdata/sync/021-update-with-explicit-ids/after.yaml create mode 100644 tests/integration/testdata/sync/021-update-with-explicit-ids/before.yaml create mode 100644 tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/after.yaml create mode 100644 tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/before.yaml create mode 100644 tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/initial.yaml create mode 100644 tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/update.yaml create mode 100644 tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x-reverse-order.yaml create mode 100644 tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x.yaml create mode 100644 tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml create mode 100644 tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/konnect.yaml create mode 100644 tests/integration/testdata/sync/026-konnect-rename/default.yaml create mode 100644 tests/integration/testdata/sync/026-konnect-rename/konnect_default_cp.yaml create mode 100644 tests/integration/testdata/sync/026-konnect-rename/konnect_default_rg.yaml create mode 100644 tests/integration/testdata/sync/026-konnect-rename/konnect_test_cp.yaml create mode 100644 tests/integration/testdata/sync/026-konnect-rename/konnect_test_rg.yaml create mode 100644 tests/integration/testdata/sync/026-konnect-rename/test.yaml create mode 100644 tests/integration/testdata/sync/027-created-at/new.yaml create mode 100644 tests/integration/testdata/sync/027-created-at/old.yaml create mode 100644 tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml create mode 100644 tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong.yaml create mode 100644 tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong3x.yaml diff --git a/.ci/check.sh b/.ci/check.sh new file mode 100755 index 0000000..27d3421 --- /dev/null +++ b/.ci/check.sh @@ -0,0 +1,7 @@ +#!/bin/bash -ex + +diff -u <(echo -n) <(gofmt -d -s .) +./scripts/verify-codegen.sh +golint -set_exit_status $(go list ./...) +go vet . +go test ./... diff --git a/.ci/setup_kong.sh b/.ci/setup_kong.sh new file mode 100755 index 0000000..03bdb31 --- /dev/null +++ b/.ci/setup_kong.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +set -e + +KONG_IMAGE=${KONG_IMAGE} +NETWORK_NAME=deck-test + +PG_CONTAINER_NAME=pg +DATABASE_USER=kong +DATABASE_NAME=kong +KONG_DB_PASSWORD=kong +KONG_PG_HOST=pg + +GATEWAY_CONTAINER_NAME=kong + +waitContainer() { + for try in {1..100}; do + echo "waiting for $1.." + nc localhost $2 && break; + sleep $3 + done +} + +# create docker network +docker network create $NETWORK_NAME + +# Start a PostgreSQL container +docker run --rm -d --name $PG_CONTAINER_NAME \ + --network=$NETWORK_NAME \ + -p 5432:5432 \ + -e "POSTGRES_USER=$DATABASE_USER" \ + -e "POSTGRES_DB=$DATABASE_NAME" \ + -e "POSTGRES_PASSWORD=$KONG_DB_PASSWORD" \ + postgres:9.6 + +waitContainer "PostgreSQL" 8001 0.2 + +# Prepare the Kong database +docker run --rm --network=$NETWORK_NAME \ + -e "KONG_DATABASE=postgres" \ + -e "KONG_PG_HOST=$KONG_PG_HOST" \ + -e "KONG_PG_PASSWORD=$KONG_DB_PASSWORD" \ + -e "KONG_PASSWORD=$KONG_DB_PASSWORD" \ + $KONG_IMAGE kong migrations bootstrap + +# Start Kong Gateway +docker run -d --name $GATEWAY_CONTAINER_NAME \ + --network=$NETWORK_NAME \ + -e "KONG_DATABASE=postgres" \ + -e "KONG_PG_HOST=$KONG_PG_HOST" \ + -e "KONG_PG_USER=$DATABASE_USER" \ + -e "KONG_PG_PASSWORD=$KONG_DB_PASSWORD" \ + -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \ + -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ + -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ + -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ + -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ + -e "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl" \ + -p 8000:8000 \ + -p 8443:8443 \ + -p 127.0.0.1:8001:8001 \ + -p 127.0.0.1:8444:8444 \ + $KONG_IMAGE + +waitContainer "Kong" 8001 0.2 \ No newline at end of file diff --git a/.ci/setup_kong_ee.sh b/.ci/setup_kong_ee.sh new file mode 100755 index 0000000..ed76b30 --- /dev/null +++ b/.ci/setup_kong_ee.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +set -e + +MY_SECRET_CERT='''-----BEGIN CERTIFICATE----- +MIIEczCCAlugAwIBAgIJAMw8/GAiHIFBMA0GCSqGSIb3DQEBCwUAMDYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQDDAlsb2NhbGhvc3Qw +HhcNMjIxMDA0MTg1MjI5WhcNMjcxMDAzMTg1MjI5WjA2MQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3LUv6RauFfFn4a2BNSTE5oQNhASBh2Lk +0Gd0tfPcmTzJbohFwyAGskYj0NBRxnRVZdLPeoZIQyYSaiPWyeDITnXyKk3Nh9Zk +xQ03YsbZCk9jIsp78/ECdnYCCS4dpYGswu8b37dxUta+6AhEEte73ezrAhc+ZIy5 +2yjcix4P5+vfhBf0EzBT8D7z+wZjji3F/A969EqphFwPz3KudkTOR6d0bQEVbN3x +cg4lcj49RzwS4sPbq6ub52QrKcx8s+d9bqC/nhHLn1HM/eef+cxROedcIWZs5RvG +mk/H+K2lcKL33gIcXgzSeunobV+8xwwoYk4GZroXjavUkgelKKjQBQIDAQABo4GD +MIGAMFAGA1UdIwRJMEehOqQ4MDYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp +Zm9ybmlhMRIwEAYDVQQDDAlsb2NhbGhvc3SCCQCjgi452nKnUDAJBgNVHRMEAjAA +MAsGA1UdDwQEAwIE8DAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZIhvcNAQEL +BQADggIBAJiKfxuh2g0fYcR7s6iiiOMhT1ZZoXhyDhoHUUMlyN9Lm549PBQHOX6V +f/g+jqVawIrGLaQbTbPoq0XPTZohk4aYwSgU2Th3Ku8Q73FfO0MM1jjop3WCatNF +VZj/GBc9uVunOV5aMcMIs2dFU2fwH4ZjOwnv7rJRldoW1Qlk3uWeIktbmv4yZKvu +FWPuo3ks+7B+BniqKXuYkNcuhlE+iVr3kJ55qRgX1RxKo4CB3Tynkp7sikp4al7x +jlHSM9YAqvPFFMOhlU2U3SxE4CLasL99zP0ChINKp9XqzW/qo+F0/Jd4rZmddU2f +M9Cx62cc0L5IlsHLVJj3zwHZzc/ifpBUeebB98IjoQAfiRkbX0Oe/c2TxtR4o/RH +GWNeKCThdliZkXaLiOPswOV1BYfA00etorcY0CIy0aTaZgfvrYsJe4aT/hkF/JvF +tHJ/iD67m8RhLysRL/w50+quVMluUDqJps0HhKrB9wzNJWrddWhvplVeuOXEJfTM +i80W1JE4OApdISMEn56vRi+BMQMgIeYWznfyQnI4G3rUJQFMI5KzLxkvfYNTF3Ci +3Am0KaJ7X2oLOq4Qc6CM3qDkvvId61COlfJb2Fo3ETnoT66mxcb6bjtz1WTWOopm +UcmBKErRUKksINUxwuvP/VW007tXOjZH7wmiM2IW5LUZVkbhB1iE +-----END CERTIFICATE-----''' + +MY_SECRET_KEY='''-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEA3LUv6RauFfFn4a2BNSTE5oQNhASBh2Lk0Gd0tfPcmTzJbohF +wyAGskYj0NBRxnRVZdLPeoZIQyYSaiPWyeDITnXyKk3Nh9ZkxQ03YsbZCk9jIsp7 +8/ECdnYCCS4dpYGswu8b37dxUta+6AhEEte73ezrAhc+ZIy52yjcix4P5+vfhBf0 +EzBT8D7z+wZjji3F/A969EqphFwPz3KudkTOR6d0bQEVbN3xcg4lcj49RzwS4sPb +q6ub52QrKcx8s+d9bqC/nhHLn1HM/eef+cxROedcIWZs5RvGmk/H+K2lcKL33gIc +XgzSeunobV+8xwwoYk4GZroXjavUkgelKKjQBQIDAQABAoIBAQDcd/nmAwvfS4iT +vTgGmDZAdsTxjXa+gSFEtTO21mUUhc5JpcLaSdGmn74DRzWI4oiz8EPlhuIEgbF/ +aVGT1AEDr3o6nAGloZqD5NHgz/XbALZs+IudgLEPGI6sEO74d3LWPvg/IAYJ1A5b +xnYJxIscAyA2tHVVB+ZYcJbuORd2eSKeZSjfEfX8/DN8sKD+4DK9g/GiVlOJBG/d +bSoZmcRv3HXpnSKTvCydkxbBliD/8H7jRvkCOi2VcYT9+08rucwXc6v+q9wiQ/b7 +hPdBn6KqDKRO9HPZYVkztlsdHXnthq16QyNPOk2umggfyXMIPhYBcW/dZ5xNqxBD +KiInqjbBAoGBAP3s/FS8GvFJ80pwtA0AUtB7Lo3ZASSs9dq+Dr8binPpp/1qz3hJ +Q/gRC9EP63MOWA2PK22D4qsjTfrBpqxLaalZCbCJGDGT+2knTN+qsOJ3//qI5zjj +cFEcnWcJ3bI5eLAU/2GKViyXzdGlZxBbc4zKBUSyxMAUewr3PsqEO0SJAoGBAN6C +vEYAbNuCZagtDrhhGYb+8rbSKZA7K4QjJcLTyZZ+z4ohWRW9tVyEXkszIwCRrs3y +rhHJU+z1bJOXxIin1i5tCzVlG6iNLct9dm2Z5v4hbDGNw4HhIV0l+tXrVGhkM/1v +vbRhldQA0H9iwWx+bKNS3lVLeUvYu4udmzrY74idAoGBAJ/8zQ9mZWNZwJxKXmdC +qOsKcc6Vx46gG1dzID9wzs8xjNKylX2oS9bkhpl2elbH1trUNfyOeCZz3BH+KVGt +QimdG+nKtx+lqWYbiOfz1/cYvIPR9j11r7KrYNEm+jPs2gm3cSC31IvMKbXJjSJV +PHycXK1oJWcQgGXsWfenUOBhAoGBAKezvRa9Z04h/2A7ZWbNuCGosWHdD/pmvit/ +Ggy29q54sQ8Yhz39l109Xpwq1GyvYCJUj6FULe7gIo8yyat9Y83l3ZbGt4vXq/Y8 +fy+n2RMcOaE3iWywMyczYtQr45gyPYT73OzAx93bJ0l7MvEEb/jAklWS5r6lgOR/ +SumVayN5AoGBALLaG16NDrV2L3u/xzxw7uy5b3prpEi4wgZd4i72XaK+dMqtNVYy +KlBs7O9y+fc4AIIn6JD+9tymB1TWEn1B+3Vv6jmtzbztuCQTbJ6rTT3CFcE6TdyJ +8rYuG3/p2VkcG29TWbQARtj5ewv9p5QNfaecUzN+tps89YzawWQBanwI +-----END RSA PRIVATE KEY-----''' + +KONG_IMAGE=${KONG_IMAGE} +NETWORK_NAME=deck-test + +PG_CONTAINER_NAME=pg +DATABASE_USER=kong +DATABASE_NAME=kong +KONG_DB_PASSWORD=kong +KONG_PG_HOST=pg + +GATEWAY_CONTAINER_NAME=kong + +# create docker network +docker network create $NETWORK_NAME + +waitContainer() { + for try in {1..100}; do + echo "waiting for $1.." + nc localhost $2 && break; + sleep $3 + done +} + +# Start a PostgreSQL container +docker run --rm -d --name $PG_CONTAINER_NAME \ + --network=$NETWORK_NAME \ + -p 5432:5432 \ + -e "POSTGRES_USER=$DATABASE_USER" \ + -e "POSTGRES_DB=$DATABASE_NAME" \ + -e "POSTGRES_PASSWORD=$KONG_DB_PASSWORD" \ + postgres:9.6 + +waitContainer "PostgreSQL" 5432 0.2 + +# Prepare the Kong database +docker run --rm --network=$NETWORK_NAME \ + -e "KONG_DATABASE=postgres" \ + -e "KONG_PG_HOST=$KONG_PG_HOST" \ + -e "KONG_PG_PASSWORD=$KONG_DB_PASSWORD" \ + -e "KONG_PASSWORD=$KONG_DB_PASSWORD" \ + -e "KONG_LICENSE_DATA=$KONG_LICENSE_DATA" \ + $KONG_IMAGE kong migrations bootstrap + +# Start Kong Gateway EE +docker run -d --name $GATEWAY_CONTAINER_NAME \ + --network=$NETWORK_NAME \ + -e "KONG_DATABASE=postgres" \ + -e "KONG_PG_HOST=$KONG_PG_HOST" \ + -e "KONG_PG_USER=$DATABASE_USER" \ + -e "KONG_PG_PASSWORD=$KONG_DB_PASSWORD" \ + -e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \ + -e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \ + -e "KONG_PROXY_ERROR_LOG=/dev/stderr" \ + -e "KONG_ADMIN_ERROR_LOG=/dev/stderr" \ + -e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \ + -e "KONG_PORTAL_GUI_URI=127.0.0.1:8003" \ + -e "KONG_ADMIN_GUI_URL=http://127.0.0.1:8002" \ + -e "KONG_LICENSE_DATA=$KONG_LICENSE_DATA" \ + -e "MY_SECRET_CERT=$MY_SECRET_CERT" \ + -e "MY_SECRET_KEY=$MY_SECRET_KEY" \ + -p 8000:8000 \ + -p 8443:8443 \ + -p 8001:8001 \ + -p 8444:8444 \ + -p 8002:8002 \ + -p 8445:8445 \ + -p 8003:8003 \ + -p 8004:8004 \ + $KONG_IMAGE + +waitContainer "Kong" 8001 0.2 diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml new file mode 100644 index 0000000..e9a789b --- /dev/null +++ b/.github/workflows/integration.yaml @@ -0,0 +1,50 @@ +name: Integration Test + +concurrency: + # Run only for most recent commit in PRs but for all tags and commits on main + # Ref: https://docs.github.com/en/actions/using-jobs/using-concurrency + group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: {} + +jobs: + integration: + strategy: + matrix: + kong_image: + - 'kong:1.4.3' + - 'kong:1.5.1' + - 'kong:2.0.5' + - 'kong:2.1.4' + - 'kong:2.2.2' + - 'kong:2.3.3' + - 'kong:2.4.1' + - 'kong:2.5.1' + - 'kong:2.6.0' + - 'kong:2.7' + - 'kong:2.8' + - 'kong:3.0' + - 'kong:3.1' + - 'kong:3.2' + - 'kong:3.3' + - 'kong/kong:master-alpine' + env: + KONG_ANONYMOUS_REPORTS: "off" + KONG_IMAGE: ${{ matrix.kong_image }} + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup go + uses: actions/setup-go@v4 + with: + go-version: '^1.20' + - name: Setup Kong + run: make setup-kong + - name: Run integration tests + run: make test-integration diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..1da27c0 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,36 @@ +name: CI Test + +concurrency: + # Run only for most recent commit in PRs but for all tags and commits on main + # Ref: https://docs.github.com/en/actions/using-jobs/using-concurrency + group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: {} + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup go + uses: actions/setup-go@v4 + with: + go-version: '^1.20' + - name: Setup golangci-lint + uses: golangci/golangci-lint-action@v3.7.0 + - name: Run tests with Coverage + run: make coverage + - name: Upload Code Coverage + uses: codecov/codecov-action@v3 + with: + name: codecov-deck + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: true + - name: Build + run: make build diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d3b4e53 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +.DEFAULT_GOAL := test-all + +CLI_DOCS_PATH=docs/cli-docs/ +.PHONY: test-all +test-all: lint test + +.PHONY: test +test: + go test -race -count=1 ./... + +.PHONY: lint +lint: + golangci-lint run -v ./... + +.PHONY: build +build: + CGO_ENABLED=0 go build -o deck main.go + +.PHONY: verify-codegen +verify-codegen: + ./scripts/verify-codegen.sh + ./scripts/verify-deepcopy-gen.sh + +.PHONY: update-codegen +update-codegen: + ./scripts/update-deepcopy-gen.sh + go generate ./... + +.PHONY: coverage +coverage: + go test -race -v -count=1 -coverprofile=coverage.out.tmp ./... + # ignoring generated code for coverage + grep -E -v 'generated.deepcopy.go' coverage.out.tmp > coverage.out + rm -f coverage.out.tmp + +generate-cli-docs: + mkdir -p $(CLI_DOCS_PATH) + go run docs/*.go -output-path $(CLI_DOCS_PATH) + +.PHONY: setup-kong +setup-kong: + bash .ci/setup_kong.sh + +.PHONY: setup-kong-ee +setup-kong-ee: + bash .ci/setup_kong_ee.sh + +.PHONY: test-integration +test-integration: + go test -v -count=1 -tags=integration \ + -race \ + ./tests/integration/... \ No newline at end of file diff --git a/tests/integration/diff_test.go b/tests/integration/diff_test.go new file mode 100644 index 0000000..e033c00 --- /dev/null +++ b/tests/integration/diff_test.go @@ -0,0 +1,744 @@ +//go:build integration + +package integration + +import ( + "testing" + + "github.com/kong/go-database-reconciler/pkg/utils" + "github.com/stretchr/testify/assert" +) + +var ( + expectedOutputMasked = `updating service svc1 { + "connect_timeout": 60000, + "enabled": true, + "host": "[masked]", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000 ++ "tags": [ ++ "[masked] is an external host. I like [masked]!", ++ "foo:foo", ++ "baz:[masked]", ++ "another:[masked]", ++ "bar:[masked]" ++ ] + } + +creating plugin rate-limiting (global) +Summary: + Created: 1 + Updated: 1 + Deleted: 0 +` + + expectedOutputUnMasked = `updating service svc1 { + "connect_timeout": 60000, + "enabled": true, + "host": "mockbin.org", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000 ++ "tags": [ ++ "test" ++ ] + } + +creating plugin rate-limiting (global) +Summary: + Created: 1 + Updated: 1 + Deleted: 0 +` + + diffEnvVars = map[string]string{ + "DECK_SVC1_HOSTNAME": "mockbin.org", + "DECK_BARR": "barbar", + "DECK_BAZZ": "bazbaz", // used more than once + "DECK_FUB": "fubfub", // unused + "DECK_FOO": "foo_test", // unused, partial match + } + + expectedOutputUnMaskedJSON = `{ + "changes": { + "creating": [ + { + "name": "rate-limiting (global)", + "kind": "plugin", + "body": { + "new": { + "id": "a1368a28-cb5c-4eee-86d8-03a6bdf94b5e", + "name": "rate-limiting", + "config": { + "day": null, + "error_code": 429, + "error_message": "API rate limit exceeded", + "fault_tolerant": true, + "header_name": null, + "hide_client_headers": false, + "hour": null, + "limit_by": "consumer", + "minute": 123, + "month": null, + "path": null, + "policy": "local", + "redis_database": 0, + "redis_host": null, + "redis_password": null, + "redis_port": 6379, + "redis_server_name": null, + "redis_ssl": false, + "redis_ssl_verify": false, + "redis_timeout": 2000, + "redis_username": null, + "second": null, + "year": null + }, + "enabled": true, + "protocols": [ + "grpc", + "grpcs", + "http", + "https" + ] + }, + "old": null + } + } + ], + "updating": [ + { + "name": "svc1", + "kind": "service", + "body": { + "new": { + "connect_timeout": 60000, + "enabled": true, + "host": "mockbin.org", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000, + "tags": [ + "test" + ] + }, + "old": { + "connect_timeout": 60000, + "enabled": true, + "host": "mockbin.org", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000 + } + } + } + ], + "deleting": [] + }, + "summary": { + "creating": 1, + "updating": 1, + "deleting": 0, + "total": 2 + }, + "warnings": [], + "errors": [] +} + +` + + expectedOutputMaskedJSON = `{ + "changes": { + "creating": [ + { + "name": "rate-limiting (global)", + "kind": "plugin", + "body": { + "new": { + "id": "a1368a28-cb5c-4eee-86d8-03a6bdf94b5e", + "name": "rate-limiting", + "config": { + "day": null, + "error_code": 429, + "error_message": "API rate limit exceeded", + "fault_tolerant": true, + "header_name": null, + "hide_client_headers": false, + "hour": null, + "limit_by": "consumer", + "minute": 123, + "month": null, + "path": null, + "policy": "local", + "redis_database": 0, + "redis_host": null, + "redis_password": null, + "redis_port": 6379, + "redis_server_name": null, + "redis_ssl": false, + "redis_ssl_verify": false, + "redis_timeout": 2000, + "redis_username": null, + "second": null, + "year": null + }, + "enabled": true, + "protocols": [ + "grpc", + "grpcs", + "http", + "https" + ] + }, + "old": null + } + } + ], + "updating": [ + { + "name": "svc1", + "kind": "service", + "body": { + "new": { + "connect_timeout": 60000, + "enabled": true, + "host": "[masked]", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000, + "tags": [ + "[masked] is an external host. I like [masked]!", + "foo:foo", + "baz:[masked]", + "another:[masked]", + "bar:[masked]" + ] + }, + "old": { + "connect_timeout": 60000, + "enabled": true, + "host": "[masked]", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000 + } + } + } + ], + "deleting": [] + }, + "summary": { + "creating": 1, + "updating": 1, + "deleting": 0, + "total": 2 + }, + "warnings": [], + "errors": [] +} + +` + + expectedOutputUnMaskedJSON30x = `{ + "changes": { + "creating": [ + { + "name": "rate-limiting (global)", + "kind": "plugin", + "body": { + "new": { + "id": "a1368a28-cb5c-4eee-86d8-03a6bdf94b5e", + "name": "rate-limiting", + "config": { + "day": null, + "fault_tolerant": true, + "header_name": null, + "hide_client_headers": false, + "hour": null, + "limit_by": "consumer", + "minute": 123, + "month": null, + "path": null, + "policy": "local", + "redis_database": 0, + "redis_host": null, + "redis_password": null, + "redis_port": 6379, + "redis_server_name": null, + "redis_ssl": false, + "redis_ssl_verify": false, + "redis_timeout": 2000, + "redis_username": null, + "second": null, + "year": null + }, + "enabled": true, + "protocols": [ + "grpc", + "grpcs", + "http", + "https" + ] + }, + "old": null + } + } + ], + "updating": [ + { + "name": "svc1", + "kind": "service", + "body": { + "new": { + "connect_timeout": 60000, + "enabled": true, + "host": "mockbin.org", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000, + "tags": [ + "test" + ] + }, + "old": { + "connect_timeout": 60000, + "enabled": true, + "host": "mockbin.org", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000 + } + } + } + ], + "deleting": [] + }, + "summary": { + "creating": 1, + "updating": 1, + "deleting": 0, + "total": 2 + }, + "warnings": [], + "errors": [] +} + +` + + expectedOutputMaskedJSON30x = `{ + "changes": { + "creating": [ + { + "name": "rate-limiting (global)", + "kind": "plugin", + "body": { + "new": { + "id": "a1368a28-cb5c-4eee-86d8-03a6bdf94b5e", + "name": "rate-limiting", + "config": { + "day": null, + "fault_tolerant": true, + "header_name": null, + "hide_client_headers": false, + "hour": null, + "limit_by": "consumer", + "minute": 123, + "month": null, + "path": null, + "policy": "local", + "redis_database": 0, + "redis_host": null, + "redis_password": null, + "redis_port": 6379, + "redis_server_name": null, + "redis_ssl": false, + "redis_ssl_verify": false, + "redis_timeout": 2000, + "redis_username": null, + "second": null, + "year": null + }, + "enabled": true, + "protocols": [ + "grpc", + "grpcs", + "http", + "https" + ] + }, + "old": null + } + } + ], + "updating": [ + { + "name": "svc1", + "kind": "service", + "body": { + "new": { + "connect_timeout": 60000, + "enabled": true, + "host": "[masked]", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000, + "tags": [ + "[masked] is an external host. I like [masked]!", + "foo:foo", + "baz:[masked]", + "another:[masked]", + "bar:[masked]" + ] + }, + "old": { + "connect_timeout": 60000, + "enabled": true, + "host": "[masked]", + "id": "9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d", + "name": "svc1", + "port": 80, + "protocol": "http", + "read_timeout": 60000, + "retries": 5, + "write_timeout": 60000 + } + } + } + ], + "deleting": [] + }, + "summary": { + "creating": 1, + "updating": 1, + "deleting": 0, + "total": 2 + }, + "warnings": [], + "errors": [] +} + +` +) + +// test scope: +// - 1.x +// - 2.x +func Test_Diff_Workspace_OlderThan3x(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedState utils.KongRawState + }{ + { + name: "diff with not existent workspace doesn't error out", + stateFile: "testdata/diff/001-not-existing-workspace/kong.yaml", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "<3.0.0") + setup(t) + + _, err := diff(tc.stateFile) + assert.NoError(t, err) + }) + } +} + +// test scope: +// - 3.x +func Test_Diff_Workspace_NewerThan3x(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedState utils.KongRawState + }{ + { + name: "diff with not existent workspace doesn't error out", + stateFile: "testdata/diff/001-not-existing-workspace/kong3x.yaml", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=3.0.0") + setup(t) + + _, err := diff(tc.stateFile) + assert.NoError(t, err) + }) + } +} + +// test scope: +// - 2.8.0 +func Test_Diff_Masked_OlderThan3x(t *testing.T) { + tests := []struct { + name string + initialStateFile string + stateFile string + expectedState utils.KongRawState + envVars map[string]string + }{ + { + name: "env variable are masked", + initialStateFile: "testdata/diff/002-mask/initial.yaml", + stateFile: "testdata/diff/002-mask/kong.yaml", + envVars: diffEnvVars, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", "==2.8.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile) + assert.NoError(t, err) + assert.Equal(t, expectedOutputMasked, out) + }) + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", "==2.8.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--json-output") + assert.NoError(t, err) + assert.Equal(t, expectedOutputMaskedJSON, out) + }) + } +} + +// test scope: +// - 3.x +func Test_Diff_Masked_NewerThan3x(t *testing.T) { + tests := []struct { + name string + initialStateFile string + stateFile string + expectedState utils.KongRawState + envVars map[string]string + }{ + { + name: "env variable are masked", + initialStateFile: "testdata/diff/002-mask/initial3x.yaml", + stateFile: "testdata/diff/002-mask/kong3x.yaml", + envVars: diffEnvVars, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", ">=3.0.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile) + assert.NoError(t, err) + assert.Equal(t, expectedOutputMasked, out) + }) + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", ">=3.0.0 <3.1.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--json-output") + assert.NoError(t, err) + assert.Equal(t, expectedOutputMaskedJSON30x, out) + }) + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", ">=3.1.0 <3.4.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--json-output") + assert.NoError(t, err) + assert.Equal(t, expectedOutputMaskedJSON, out) + }) + } +} + +// test scope: +// - 2.8.0 +func Test_Diff_Unmasked_OlderThan3x(t *testing.T) { + tests := []struct { + name string + initialStateFile string + stateFile string + expectedState utils.KongRawState + envVars map[string]string + }{ + { + name: "env variable are unmasked", + initialStateFile: "testdata/diff/003-unmask/initial.yaml", + stateFile: "testdata/diff/003-unmask/kong.yaml", + envVars: diffEnvVars, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", "==2.8.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--no-mask-deck-env-vars-value") + assert.NoError(t, err) + assert.Equal(t, expectedOutputUnMasked, out) + }) + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", "==2.8.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--no-mask-deck-env-vars-value", "--json-output") + assert.NoError(t, err) + assert.Equal(t, expectedOutputUnMaskedJSON, out) + }) + } +} + +// test scope: +// - 3.x +func Test_Diff_Unmasked_NewerThan3x(t *testing.T) { + tests := []struct { + name string + initialStateFile string + stateFile string + expectedState utils.KongRawState + envVars map[string]string + }{ + { + name: "env variable are unmasked", + initialStateFile: "testdata/diff/003-unmask/initial3x.yaml", + stateFile: "testdata/diff/003-unmask/kong3x.yaml", + envVars: diffEnvVars, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", ">=3.0.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--no-mask-deck-env-vars-value") + assert.NoError(t, err) + assert.Equal(t, expectedOutputUnMasked, out) + }) + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", ">=3.0.0 <3.1.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--no-mask-deck-env-vars-value", "--json-output") + assert.NoError(t, err) + assert.Equal(t, expectedOutputUnMaskedJSON30x, out) + }) + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + for k, v := range tc.envVars { + t.Setenv(k, v) + } + runWhen(t, "kong", ">=3.1.0 <3.4.0") + setup(t) + + // initialize state + assert.NoError(t, sync(tc.initialStateFile)) + + out, err := diff(tc.stateFile, "--no-mask-deck-env-vars-value", "--json-output") + assert.NoError(t, err) + assert.Equal(t, expectedOutputUnMaskedJSON, out) + }) + } +} diff --git a/tests/integration/dump_test.go b/tests/integration/dump_test.go new file mode 100644 index 0000000..5aa89ba --- /dev/null +++ b/tests/integration/dump_test.go @@ -0,0 +1,253 @@ +//go:build integration + +package integration + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Dump_SelectTags_30(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedFile string + }{ + { + name: "dump with select-tags", + stateFile: "testdata/dump/001-entities-with-tags/kong.yaml", + expectedFile: "testdata/dump/001-entities-with-tags/expected30.yaml", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=3.0.0 <3.1.0") + setup(t) + + assert.NoError(t, sync(tc.stateFile)) + + output, err := dump( + "--select-tag", "managed-by-deck", + "--select-tag", "org-unit-42", + "-o", "-", + ) + assert.NoError(t, err) + + expected, err := readFile(tc.expectedFile) + assert.NoError(t, err) + assert.Equal(t, output, expected) + }) + } +} + +func Test_Dump_SelectTags_3x(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedFile string + }{ + { + name: "dump with select-tags", + stateFile: "testdata/dump/001-entities-with-tags/kong.yaml", + expectedFile: "testdata/dump/001-entities-with-tags/expected.yaml", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=3.1.0") + setup(t) + + assert.NoError(t, sync(tc.stateFile)) + + output, err := dump( + "--select-tag", "managed-by-deck", + "--select-tag", "org-unit-42", + "-o", "-", + ) + assert.NoError(t, err) + + expected, err := readFile(tc.expectedFile) + assert.NoError(t, err) + assert.Equal(t, output, expected) + }) + } +} + +func Test_Dump_SkipConsumers(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedFile string + skipConsumers bool + runWhen func(t *testing.T) + }{ + { + name: "3.2 & 3.3 dump with skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected.yaml", + skipConsumers: true, + runWhen: func(t *testing.T) { runWhen(t, "enterprise", ">=3.2.0 <3.4.0") }, + }, + { + name: "3.2 & 3.3 dump with no skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected-no-skip.yaml", + skipConsumers: false, + runWhen: func(t *testing.T) { runWhen(t, "enterprise", ">=3.2.0 <3.4.0") }, + }, + { + name: "3.4 dump with skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong34.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected.yaml", + skipConsumers: true, + runWhen: func(t *testing.T) { runWhen(t, "enterprise", ">=3.4.0 <3.5.0") }, + }, + { + name: "3.4 dump with no skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong34.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected-no-skip-34.yaml", + skipConsumers: false, + runWhen: func(t *testing.T) { runWhen(t, "enterprise", ">=3.4.0 <3.5.0") }, + }, + { + name: "3.5 dump with skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong34.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected.yaml", + skipConsumers: true, + runWhen: func(t *testing.T) { runWhen(t, "enterprise", ">=3.5.0") }, + }, + { + name: "3.5 dump with no skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong34.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected-no-skip-35.yaml", + skipConsumers: false, + runWhen: func(t *testing.T) { runWhen(t, "enterprise", ">=3.5.0") }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tc.runWhen(t) + setup(t) + + assert.NoError(t, sync(tc.stateFile)) + + var ( + output string + err error + ) + if tc.skipConsumers { + output, err = dump( + "--skip-consumers", + "-o", "-", + ) + } else { + output, err = dump( + "-o", "-", + ) + } + assert.NoError(t, err) + + expected, err := readFile(tc.expectedFile) + assert.NoError(t, err) + assert.Equal(t, expected, output) + }) + } +} + +func Test_Dump_SkipConsumers_Konnect(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedFile string + skipConsumers bool + }{ + { + name: "dump with skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong34.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected_konnect.yaml", + skipConsumers: true, + }, + { + name: "dump with no skip-consumers", + stateFile: "testdata/dump/002-skip-consumers/kong34.yaml", + expectedFile: "testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml", + skipConsumers: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKonnect(t) + setup(t) + + assert.NoError(t, sync(tc.stateFile)) + + var ( + output string + err error + ) + if tc.skipConsumers { + output, err = dump( + "--skip-consumers", + "-o", "-", + ) + } else { + output, err = dump( + "-o", "-", + ) + } + assert.NoError(t, err) + + expected, err := readFile(tc.expectedFile) + assert.NoError(t, err) + assert.Equal(t, expected, output) + }) + } +} + +func Test_Dump_KonnectRename(t *testing.T) { + tests := []struct { + name string + stateFile string + expectedFile string + flags []string + }{ + { + name: "dump with konnect-control-plane-name", + stateFile: "testdata/sync/026-konnect-rename/konnect_test_cp.yaml", + expectedFile: "testdata/sync/026-konnect-rename/konnect_test_cp.yaml", + flags: []string{"--konnect-control-plane-name", "test"}, + }, + { + name: "dump with konnect-runtime-group-name", + stateFile: "testdata/sync/026-konnect-rename/konnect_test_rg.yaml", + expectedFile: "testdata/sync/026-konnect-rename/konnect_test_cp.yaml", + flags: []string{"--konnect-runtime-group-name", "test"}, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Cleanup(func() { + reset(t, tc.flags...) + }) + runWhenKonnect(t) + setup(t) + + assert.NoError(t, sync(tc.stateFile)) + + var ( + output string + err error + ) + flags := []string{"-o", "-", "--with-id"} + flags = append(flags, tc.flags...) + output, err = dump(flags...) + + assert.NoError(t, err) + + expected, err := readFile(tc.expectedFile) + assert.NoError(t, err) + assert.Equal(t, expected, output) + }) + } +} diff --git a/tests/integration/lint_test.go b/tests/integration/lint_test.go new file mode 100644 index 0000000..a512b79 --- /dev/null +++ b/tests/integration/lint_test.go @@ -0,0 +1,140 @@ +//go:build integration + +package integration + +import ( + "encoding/json" + "os" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/kong/deck/cmd" + "github.com/stretchr/testify/assert" + "sigs.k8s.io/yaml" +) + +func Test_LintPlain(t *testing.T) { + tests := []struct { + name string + stateFile string + rulesetFile string + }{ + { + name: "lint plain", + stateFile: "testdata/lint/001-simple-lint/kong.yaml", + rulesetFile: "testdata/lint/001-simple-lint/ruleset.yaml", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + output, err := lint( + "-s", tc.stateFile, + tc.rulesetFile, + ) + assert.Error(t, err) + + assert.Contains(t, output, "Linting Violations: 2") + assert.Contains(t, output, "Failures: 1") + assert.Contains(t, output, "[warn][5:13] Must use HTTPS protocol: `http` does not match the expression `^https`") + assert.Contains(t, output, "[error][1:18] Check the version is correct: `3.0` does not match the expression `^1.1$`") + }) + } +} + +type lintErrors struct { + TotalCount int + FailCount int + Results []cmd.LintResult +} + +func Test_LintStructured(t *testing.T) { + tests := []struct { + name string + stateFile string + rulesetFile string + expectedFile string + format string + displayOnlyFailures bool + failSeverity string + }{ + { + name: "lint yaml", + stateFile: "testdata/lint/001-simple-lint/kong.yaml", + rulesetFile: "testdata/lint/001-simple-lint/ruleset.yaml", + expectedFile: "testdata/lint/001-simple-lint/expected.yaml", + format: "yaml", + }, + { + name: "lint yaml with modified severity", + stateFile: "testdata/lint/001-simple-lint/kong.yaml", + rulesetFile: "testdata/lint/001-simple-lint/ruleset.yaml", + expectedFile: "testdata/lint/001-simple-lint/expected-fail-severity-error.yaml", + format: "yaml", + displayOnlyFailures: true, + failSeverity: "error", + }, + { + name: "lint json", + stateFile: "testdata/lint/001-simple-lint/kong.yaml", + rulesetFile: "testdata/lint/001-simple-lint/ruleset.yaml", + expectedFile: "testdata/lint/001-simple-lint/expected.json", + format: "json", + }, + { + name: "lint json with modified severity", + stateFile: "testdata/lint/001-simple-lint/kong.yaml", + rulesetFile: "testdata/lint/001-simple-lint/ruleset.yaml", + expectedFile: "testdata/lint/001-simple-lint/expected-fail-severity-error.json", + format: "json", + displayOnlyFailures: true, + failSeverity: "error", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + lintOpts := []string{ + "-s", tc.stateFile, + "--format", tc.format, + tc.rulesetFile, + } + if tc.displayOnlyFailures { + lintOpts = append(lintOpts, "--display-only-failures") + } + if tc.failSeverity != "" { + lintOpts = append(lintOpts, "--fail-severity", tc.failSeverity) + } + output, err := lint(lintOpts...) + assert.Error(t, err) + + var expectedErrors, outputErrors lintErrors + // get expected errors from file + content, err := os.ReadFile(tc.expectedFile) + assert.NoError(t, err) + + if tc.format == "yaml" { + err = yaml.Unmarshal(content, &expectedErrors) + assert.NoError(t, err) + + // parse result errors from lint command + err = yaml.Unmarshal([]byte(output), &outputErrors) + assert.NoError(t, err) + } else { + err = json.Unmarshal(content, &expectedErrors) + assert.NoError(t, err) + + // parse result errors from lint command + err = json.Unmarshal([]byte(output), &outputErrors) + assert.NoError(t, err) + } + + cmpOpts := []cmp.Option{ + cmpopts.SortSlices(func(a, b cmd.LintResult) bool { return a.Line < b.Line }), + cmpopts.EquateEmpty(), + } + if diff := cmp.Diff(outputErrors, expectedErrors, cmpOpts...); diff != "" { + t.Errorf(diff) + } + }) + } +} diff --git a/tests/integration/ping_test.go b/tests/integration/ping_test.go new file mode 100644 index 0000000..fa922a1 --- /dev/null +++ b/tests/integration/ping_test.go @@ -0,0 +1,31 @@ +//go:build integration + +package integration + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_KonnectPing(t *testing.T) { + t.Run("konnect ping - email/password", func(t *testing.T) { + // TODO: https://github.com/Kong/deck/issues/1100 + // Remove the test altogether or fix the basic auth support. + t.Skip("https://github.com/Kong/deck/issues/1100") + + runWhen(t, "konnect", "") + require.NoError(t, ping( + "--konnect-email", os.Getenv("DECK_KONNECT_EMAIL"), + "--konnect-password", os.Getenv("DECK_KONNECT_PASSWORD"), + )) + }) + + t.Run("konnect ping - token", func(t *testing.T) { + runWhen(t, "konnect", "") + require.NoError(t, ping( + "--konnect-token", os.Getenv("DECK_KONNECT_TOKEN"), + )) + }) +} diff --git a/tests/integration/reset_test.go b/tests/integration/reset_test.go new file mode 100644 index 0000000..aff9354 --- /dev/null +++ b/tests/integration/reset_test.go @@ -0,0 +1,108 @@ +//go:build integration + +package integration + +import ( + "testing" + + "github.com/kong/go-database-reconciler/pkg/utils" + "github.com/kong/go-kong/kong" +) + +var caCert = &kong.CACertificate{ + CertDigest: kong.String("34e0f1f3d83faefcc8514b6295bc822eab1110dc120140ddf342c017baee8c0f"), + Cert: kong.String(`-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUYGc07pbHSjOBPreXh7OcNT2+sD4wDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIs +IEluYy4xJjAkBgNVBAMMHVlvbG80MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMB4X +DTIyMDMyOTE5NDczM1oXDTMyMDMyNjE5NDczM1owWTELMAkGA1UEBhMCVVMxCzAJ +BgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIsIEluYy4xJjAkBgNVBAMMHVlvbG80 +MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAvnhTgdJALnuLKDA0ZUZRVMqcaaC+qvfJkiEFGYwX2ZJiFtzU65F/ +sB2L0ToFqY4tmMVlOmiSZFnRLDZecmQDbbNwc3wtNikmxIOzx4qR4kbRP8DDdyIf +gaNmGCuaXTM5+FYy2iNBn6CeibIjqdErQlAbFLwQs5t3mLsjii2U4cyvfRtO+0RV +HdJ6Np5LsVziN0c5gVIesIrrbxLcOjtXDzwd/w/j5NXqL/OwD5EBH2vqd3QKKX4t +s83BLl2EsbUse47VAImavrwDhmV6S/p/NuJHqjJ6dIbXLYxNS7g26ijcrXxvNhiu +YoZTykSgdI3BXMNAm1ahP/BtJPZpU7CVdQIDAQABo1MwUTAdBgNVHQ4EFgQUe1WZ +fMfZQ9QIJIttwTmcrnl40ccwHwYDVR0jBBgwFoAUe1WZfMfZQ9QIJIttwTmcrnl4 +0ccwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAs4Z8VYbvEs93 +haTHdbbaKk0V6xAL/Q8I8GitK9E8cgf8C5rwwn+wU/Gf39dtMUlnW8uxyzRPx53u +CAAcJAWkabT+xwrlrqjO68H3MgIAwgWA5yZC+qW7ECA8xYEK6DzEHIaOpagJdKcL +IaZr/qTJlEQClvwDs4x/BpHRB5XbmJs86GqEB7XWAm+T2L8DluHAXvek+welF4Xo +fQtLlNS/vqTDqPxkSbJhFv1L7/4gdwfAz51wH/iL7AG/ubFEtoGZPK9YCJ40yTWz +8XrUoqUC+2WIZdtmo6dFFJcLfQg4ARJZjaK6lmxJun3iRMZjKJdQKm/NEKz4y9kA +u8S6yNlu2Q== +-----END CERTIFICATE-----`), +} + +func Test_Reset_SkipCACert_2x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Errorf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "reset with --skip-ca-certificates should ignore CA certs", + kongFile: "testdata/reset/001-skip-ca-cert/kong.yaml", + expectedState: utils.KongRawState{ + CACertificates: []*kong.CACertificate{caCert}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // ca_certificates first appeared in 1.3, but we limit to 2.7+ + // here because the schema changed and the entities aren't the same + // across all versions, even though the skip functionality works the same. + runWhen(t, "kong", ">=2.7.0 <3.0.0") + setup(t) + + sync(tc.kongFile) + reset(t, "--skip-ca-certificates") + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Reset_SkipCACert_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Errorf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "reset with --skip-ca-certificates should ignore CA certs", + kongFile: "testdata/reset/001-skip-ca-cert/kong3x.yaml", + expectedState: utils.KongRawState{ + CACertificates: []*kong.CACertificate{caCert}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // ca_certificates first appeared in 1.3, but we limit to 2.7+ + // here because the schema changed and the entities aren't the same + // across all versions, even though the skip functionality works the same. + runWhen(t, "kong", ">=3.0.0") + setup(t) + + sync(tc.kongFile) + reset(t, "--skip-ca-certificates") + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go new file mode 100644 index 0000000..44ab032 --- /dev/null +++ b/tests/integration/sync_test.go @@ -0,0 +1,4716 @@ +//go:build integration + +package integration + +import ( + "context" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "net/http" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + deckDump "github.com/kong/go-database-reconciler/pkg/dump" + "github.com/kong/go-database-reconciler/pkg/utils" + "github.com/kong/go-kong/kong" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + // missing Enable + svc1 = []*kong.Service{ + { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + Name: kong.String("svc1"), + ConnectTimeout: kong.Int(60000), + Host: kong.String("mockbin.org"), + Port: kong.Int(80), + Protocol: kong.String("http"), + ReadTimeout: kong.Int(60000), + Retries: kong.Int(5), + WriteTimeout: kong.Int(60000), + Tags: nil, + }, + } + + // latest + svc1_207 = []*kong.Service{ + { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + Name: kong.String("svc1"), + ConnectTimeout: kong.Int(60000), + Host: kong.String("mockbin.org"), + Port: kong.Int(80), + Protocol: kong.String("http"), + ReadTimeout: kong.Int(60000), + Retries: kong.Int(5), + WriteTimeout: kong.Int(60000), + Enabled: kong.Bool(true), + Tags: nil, + }, + } + + defaultCPService = []*kong.Service{ + { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + Name: kong.String("default"), + ConnectTimeout: kong.Int(60000), + Host: kong.String("mockbin-default.org"), + Port: kong.Int(80), + Protocol: kong.String("http"), + ReadTimeout: kong.Int(60000), + Retries: kong.Int(5), + WriteTimeout: kong.Int(60000), + Enabled: kong.Bool(true), + Tags: nil, + }, + } + + testCPService = []*kong.Service{ + { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + Name: kong.String("test"), + ConnectTimeout: kong.Int(60000), + Host: kong.String("mockbin-test.org"), + Port: kong.Int(80), + Protocol: kong.String("http"), + ReadTimeout: kong.Int(60000), + Retries: kong.Int(5), + WriteTimeout: kong.Int(60000), + Enabled: kong.Bool(true), + Tags: nil, + }, + } + + // missing RequestBuffering, ResponseBuffering, Service, PathHandling + route1_143 = []*kong.Route{ + { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + Name: kong.String("r1"), + Paths: []*string{kong.String("/r1")}, + PreserveHost: kong.Bool(false), + Protocols: []*string{kong.String("http"), kong.String("https")}, + RegexPriority: kong.Int(0), + StripPath: kong.Bool(true), + HTTPSRedirectStatusCode: kong.Int(301), + }, + } + + // missing RequestBuffering, ResponseBuffering + // PathHandling set to v1 + route1_151 = []*kong.Route{ + { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + Name: kong.String("r1"), + Paths: []*string{kong.String("/r1")}, + PathHandling: kong.String("v1"), + PreserveHost: kong.Bool(false), + Protocols: []*string{kong.String("http"), kong.String("https")}, + RegexPriority: kong.Int(0), + StripPath: kong.Bool(true), + HTTPSRedirectStatusCode: kong.Int(301), + Service: &kong.Service{ + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + }, + }, + } + + // missing RequestBuffering, ResponseBuffering + route1_205_214 = []*kong.Route{ + { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + Name: kong.String("r1"), + Paths: []*string{kong.String("/r1")}, + PathHandling: kong.String("v0"), + PreserveHost: kong.Bool(false), + Protocols: []*string{kong.String("http"), kong.String("https")}, + RegexPriority: kong.Int(0), + StripPath: kong.Bool(true), + HTTPSRedirectStatusCode: kong.Int(301), + Service: &kong.Service{ + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + }, + }, + } + + // latest + route1_20x = []*kong.Route{ + { + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + Name: kong.String("r1"), + Paths: []*string{kong.String("/r1")}, + PathHandling: kong.String("v0"), + PreserveHost: kong.Bool(false), + Protocols: []*string{kong.String("http"), kong.String("https")}, + RegexPriority: kong.Int(0), + StripPath: kong.Bool(true), + HTTPSRedirectStatusCode: kong.Int(301), + RequestBuffering: kong.Bool(true), + ResponseBuffering: kong.Bool(true), + Service: &kong.Service{ + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + }, + }, + } + + // has run-on set to 'first' + plugin_143_151 = []*kong.Plugin{ //nolint:revive,stylecheck + { + Name: kong.String("basic-auth"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "anonymous": "58076db2-28b6-423b-ba39-a797193017f7", + "hide_credentials": false, + }, + RunOn: kong.String("first"), + }, + } + + // latest + plugin = []*kong.Plugin{ + { + Name: kong.String("basic-auth"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "anonymous": "58076db2-28b6-423b-ba39-a797193017f7", + "hide_credentials": false, + }, + }, + } + + plugin_on_entities = []*kong.Plugin{ //nolint:revive,stylecheck + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "per_consumer": false, + }, + Service: &kong.Service{ + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + }, + }, + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "per_consumer": false, + }, + Route: &kong.Route{ + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + }, + }, + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "per_consumer": false, + }, + Consumer: &kong.Consumer{ + ID: kong.String("d2965b9b-0608-4458-a9f8-0b93d88d03b8"), + }, + }, + } + + plugin_on_entities3x = []*kong.Plugin{ //nolint:revive,stylecheck + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "bandwidth_metrics": false, + "latency_metrics": false, + "per_consumer": false, + "status_code_metrics": false, + "upstream_health_metrics": false, + }, + Service: &kong.Service{ + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + }, + }, + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "bandwidth_metrics": false, + "latency_metrics": false, + "per_consumer": false, + "status_code_metrics": false, + "upstream_health_metrics": false, + }, + Route: &kong.Route{ + ID: kong.String("87b6a97e-f3f7-4c47-857a-7464cb9e202b"), + }, + }, + { + Name: kong.String("prometheus"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "bandwidth_metrics": false, + "latency_metrics": false, + "per_consumer": false, + "status_code_metrics": false, + "upstream_health_metrics": false, + }, + Consumer: &kong.Consumer{ + ID: kong.String("d2965b9b-0608-4458-a9f8-0b93d88d03b8"), + }, + }, + } + + upstream_pre31 = []*kong.Upstream{ //nolint:revive,stylecheck + { + Name: kong.String("upstream1"), + Algorithm: kong.String("round-robin"), + Slots: kong.Int(10000), + Healthchecks: &kong.Healthcheck{ + Threshold: kong.Float64(0), + Active: &kong.ActiveHealthcheck{ + Concurrency: kong.Int(10), + Healthy: &kong.Healthy{ + HTTPStatuses: []int{200, 302}, + Interval: kong.Int(0), + Successes: kong.Int(0), + }, + HTTPPath: kong.String("/"), + Type: kong.String("http"), + Timeout: kong.Int(1), + HTTPSVerifyCertificate: kong.Bool(true), + Unhealthy: &kong.Unhealthy{ + HTTPFailures: kong.Int(0), + TCPFailures: kong.Int(0), + Timeouts: kong.Int(0), + Interval: kong.Int(0), + HTTPStatuses: []int{429, 404, 500, 501, 502, 503, 504, 505}, + }, + }, + Passive: &kong.PassiveHealthcheck{ + Healthy: &kong.Healthy{ + HTTPStatuses: []int{ + 200, 201, 202, 203, 204, 205, + 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, + 306, 307, 308, + }, + Successes: kong.Int(0), + }, + Type: kong.String("http"), + Unhealthy: &kong.Unhealthy{ + HTTPFailures: kong.Int(0), + TCPFailures: kong.Int(0), + Timeouts: kong.Int(0), + HTTPStatuses: []int{429, 500, 503}, + }, + }, + }, + HashOn: kong.String("none"), + HashFallback: kong.String("none"), + HashOnCookiePath: kong.String("/"), + }, + } + + // latest + upstream = []*kong.Upstream{ + { + Name: kong.String("upstream1"), + Algorithm: kong.String("round-robin"), + Slots: kong.Int(10000), + Healthchecks: &kong.Healthcheck{ + Threshold: kong.Float64(0), + Active: &kong.ActiveHealthcheck{ + Concurrency: kong.Int(10), + Healthy: &kong.Healthy{ + HTTPStatuses: []int{200, 302}, + Interval: kong.Int(0), + Successes: kong.Int(0), + }, + HTTPPath: kong.String("/"), + Type: kong.String("http"), + Timeout: kong.Int(1), + HTTPSVerifyCertificate: kong.Bool(true), + Unhealthy: &kong.Unhealthy{ + HTTPFailures: kong.Int(0), + TCPFailures: kong.Int(0), + Timeouts: kong.Int(0), + Interval: kong.Int(0), + HTTPStatuses: []int{429, 404, 500, 501, 502, 503, 504, 505}, + }, + }, + Passive: &kong.PassiveHealthcheck{ + Healthy: &kong.Healthy{ + HTTPStatuses: []int{ + 200, 201, 202, 203, 204, 205, + 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, + 306, 307, 308, + }, + Successes: kong.Int(0), + }, + Type: kong.String("http"), + Unhealthy: &kong.Unhealthy{ + HTTPFailures: kong.Int(0), + TCPFailures: kong.Int(0), + Timeouts: kong.Int(0), + HTTPStatuses: []int{429, 500, 503}, + }, + }, + }, + HashOn: kong.String("none"), + HashFallback: kong.String("none"), + HashOnCookiePath: kong.String("/"), + UseSrvName: kong.Bool(false), + }, + } + + target = []*kong.Target{ + { + Target: kong.String("198.51.100.11:80"), + Upstream: &kong.Upstream{ + ID: kong.String("a6f89ffc-1e53-4b01-9d3d-7a142bcd"), + }, + Weight: kong.Int(100), + }, + } + + targetZeroWeight = []*kong.Target{ + { + Target: kong.String("198.51.100.11:80"), + Upstream: &kong.Upstream{ + ID: kong.String("a6f89ffc-1e53-4b01-9d3d-7a142bcd"), + }, + Weight: kong.Int(0), + }, + } + + rateLimitingPlugin = []*kong.Plugin{ + { + Name: kong.String("rate-limiting"), + Config: kong.Configuration{ + "day": nil, + "fault_tolerant": true, + "header_name": nil, + "hide_client_headers": false, + "hour": nil, + "limit_by": "consumer", + "minute": float64(123), + "month": nil, + "path": nil, + "policy": "cluster", + "redis_database": float64(0), + "redis_host": nil, + "redis_password": nil, + "redis_port": float64(6379), + "redis_server_name": nil, + "redis_ssl": false, + "redis_ssl_verify": false, + "redis_timeout": float64(2000), + "second": nil, + "year": nil, + }, + Enabled: kong.Bool(true), + RunOn: nil, + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Tags: nil, + }, + } + + consumer = []*kong.Consumer{ + { + Username: kong.String("yolo"), + ID: kong.String("d2965b9b-0608-4458-a9f8-0b93d88d03b8"), + }, + } + + consumerGroupsConsumers = []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + { + Username: kong.String("bar"), + }, + { + Username: kong.String("baz"), + }, + } + + consumerGroups = []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + { + Username: kong.String("baz"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + } + + consumerGroupsWithTags = []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + Tags: kong.StringSlice("tag1", "tag3"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + { + Username: kong.String("baz"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + Tags: kong.StringSlice("tag1", "tag2"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + } + + consumerGroupsWithRLA = []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + Plugins: []*kong.ConsumerGroupPlugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "limit": []any{float64(7)}, + "retry_after_jitter_max": float64(1), + "window_size": []any{float64(60)}, + "window_type": "sliding", + }, + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("521a90ad-36cb-4e31-a5db-1d979aee40d1"), + }, + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + Plugins: []*kong.ConsumerGroupPlugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "limit": []any{float64(10)}, + "retry_after_jitter_max": float64(1), + "window_size": []any{float64(60)}, + "window_type": "sliding", + }, + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("92177268-b134-42f9-909a-36f9d2d3d5e7"), + }, + }, + }, + }, + } + + consumerGroupsWithTagsAndRLA = []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + Tags: kong.StringSlice("tag1", "tag3"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + Plugins: []*kong.ConsumerGroupPlugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "limit": []any{float64(7)}, + "retry_after_jitter_max": float64(1), + "window_size": []any{float64(60)}, + "window_type": "sliding", + }, + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("521a90ad-36cb-4e31-a5db-1d979aee40d1"), + }, + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + Tags: kong.StringSlice("tag1", "tag2"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + Plugins: []*kong.ConsumerGroupPlugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "limit": []any{float64(10)}, + "retry_after_jitter_max": float64(1), + "window_size": []any{float64(60)}, + "window_type": "sliding", + }, + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("92177268-b134-42f9-909a-36f9d2d3d5e7"), + }, + }, + }, + }, + } + + consumerGroupsWithRLAApp = []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + Plugins: []*kong.ConsumerGroupPlugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "limit": []any{float64(7)}, + "retry_after_jitter_max": float64(1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("f79972fe-e9a0-40b5-8dc6-f1bf3758b86b"), + }, + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + Plugins: []*kong.ConsumerGroupPlugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "limit": []any{float64(10)}, + "retry_after_jitter_max": float64(1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("8eea863e-460c-4019-895a-1e80cb08699d"), + }, + }, + }, + }, + } + + consumerGroupAppPlugins = []*kong.Plugin{ + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "consumer_groups": []any{string("silver"), string("gold")}, + "dictionary_name": string("kong_rate_limiting_counters"), + "enforce_consumer_groups": bool(true), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(5)}, + "namespace": string("dNRC6xKsRL8Koc1uVYA4Nki6DLW7XIdx"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(30), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(0), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("key-auth"), + Config: kong.Configuration{ + "anonymous": nil, + "hide_credentials": false, + "key_in_body": false, + "key_in_header": true, + "key_in_query": true, + "key_names": []interface{}{"apikey"}, + "run_on_preflight": true, + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("http"), kong.String("https")}, + }, + } + + consumerGroupScopedPlugins = []*kong.Plugin{ + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("77e6691d-67c0-446a-9401-27be2b141aae"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(10)}, + "namespace": string("gold"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("5bcbd3a7-030b-4310-bd1d-2721ff85d236"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(7)}, + "namespace": string("silver"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(5)}, + "namespace": string("silver"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("key-auth"), + Config: kong.Configuration{ + "anonymous": nil, + "hide_credentials": false, + "key_in_body": false, + "key_in_header": true, + "key_in_query": true, + "key_names": []interface{}{"apikey"}, + "run_on_preflight": true, + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("http"), kong.String("https")}, + }, + } + + consumerGroupScopedPlugins35x = []*kong.Plugin{ + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("77e6691d-67c0-446a-9401-27be2b141aae"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(10)}, + "namespace": string("gold"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("5bcbd3a7-030b-4310-bd1d-2721ff85d236"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(7)}, + "namespace": string("silver"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("rate-limiting-advanced"), + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(5)}, + "namespace": string("silver"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(256), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("key-auth"), + Config: kong.Configuration{ + "anonymous": nil, + "hide_credentials": false, + "key_in_body": false, + "key_in_header": true, + "key_in_query": true, + "key_names": []interface{}{"apikey"}, + "run_on_preflight": true, + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("http"), kong.String("https")}, + }, + } +) + +// test scope: +// - 1.4.3 +func Test_Sync_ServicesRoutes_Till_1_4_3(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + // ignore entities fields based on Kong version + ignoreFields := []cmp.Option{ + cmpopts.IgnoreFields(kong.Route{}, "Service"), + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_143, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "<=1.4.3") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, ignoreFields) + }) + } +} + +// test scope: +// - 1.5.1 +// - 1.5.0.11+enterprise +func Test_Sync_ServicesRoutes_Till_1_5_1(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_151, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">1.4.3 <=1.5.1") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.0.5 +// - 2.1.4 +func Test_Sync_ServicesRoutes_From_2_0_5_To_2_1_4(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_205_214, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.0.5 <=2.1.4") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.2.2 +// - 2.3.3 +// - 2.4.1 +// - 2.5.1 +// - 2.6.0 +// - 2.2.1.3+enterprise +// - 2.3.3.4+enterprise +// - 2.4.1.3+enterprise +// - 2.5.1.2+enterprise +func Test_Sync_ServicesRoutes_From_2_2_1_to_2_6_0(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_20x, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">2.2.1 <=2.6.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.7.0 +// - 2.6.0.2+enterprise +// - 2.7.0.0+enterprise +// - 2.8.0.0+enterprise +func Test_Sync_ServicesRoutes_From_2_6_9_Till_2_8_0(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">2.6.9 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_ServicesRoutes_From_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_ServicesRoutes_Konnect(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + }, + }, + { + name: "create services and routes", + kongFile: "testdata/sync/002-create-services-and-routes/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "konnect", "") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 1.4.3 +func Test_Sync_BasicAuth_Plugin_1_4_3(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin_143_151, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "==1.4.3") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 1.5.0.11+enterprise +func Test_Sync_BasicAuth_Plugin_Earlier_Than_1_5_1(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "<1.5.1 !1.4.3") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 1.5.1 +func Test_Sync_BasicAuth_Plugin_1_5_1(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin_143_151, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "==1.5.1") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.0.5 +// - 2.1.4 +// - 2.2.2 +// - 2.3.3 +// - 2.4.1 +// - 2.5.1 +// - 2.6.0 +// - 2.7.0 +// - 2.1.4.6+enterprise +// - 2.2.1.3+enterprise +// - 2.3.3.4+enterprise +// - 2.4.1.3+enterprise +// - 2.5.1.2+enterprise +// - 2.6.0.2+enterprise +// - 2.7.0.0+enterprise +// - 2.8.0.0+enterprise +func Test_Sync_BasicAuth_Plugin_From_2_0_5_Till_2_8_0(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.0.5 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_BasicAuth_Plugin_From_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong3x.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_BasicAuth_Plugin_Konnect(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin", + kongFile: "testdata/sync/003-create-a-plugin/kong3x.yaml", + expectedState: utils.KongRawState{ + Plugins: plugin, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "konnect", "") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 1.4.3 +// - 1.5.1 +// - 1.5.0.11+enterprise +func Test_Sync_Upstream_Target_Till_1_5_2(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + // ignore entities fields based on Kong version + ignoreFields := []cmp.Option{ + cmpopts.IgnoreFields(kong.Healthcheck{}, "Threshold"), + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target", + kongFile: "testdata/sync/004-create-upstream-and-target/kong.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream_pre31, + Targets: target, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "<=1.5.2") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, ignoreFields) + }) + } +} + +// test scope: +// - 2.0.5 +// - 2.1.4 +// - 2.2.2 +// - 2.3.3 +// - 2.4.1 +// - 2.5.1 +// - 2.6.0 +// - 2.7.0 +// - 2.1.4.6+enterprise +// - 2.2.1.3+enterprise +// - 2.3.3.4+enterprise +// - 2.4.1.3+enterprise +// - 2.5.1.2+enterprise +// - 2.6.0.2+enterprise +// - 2.7.0.0+enterprise +// - 2.8.0.0+enterprise +func Test_Sync_Upstream_Target_From_2x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target", + kongFile: "testdata/sync/004-create-upstream-and-target/kong.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream_pre31, + Targets: target, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.1.0 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.0 +func Test_Sync_Upstream_Target_From_30(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target", + kongFile: "testdata/sync/004-create-upstream-and-target/kong3x.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream_pre31, + Targets: target, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=3.0.0 <3.1.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_Upstream_Target_From_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target", + kongFile: "testdata/sync/004-create-upstream-and-target/kong3x.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream, + Targets: target, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.1.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_Upstream_Target_Konnect(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target", + kongFile: "testdata/sync/004-create-upstream-and-target/kong3x.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream, + Targets: target, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "konnect", "") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.4.1 +// - 2.5.1 +// - 2.6.0 +// - 2.7.0 +// - 2.4.1.3+enterprise +// - 2.5.1.2+enterprise +// - 2.6.0.2+enterprise +// - 2.7.0.0+enterprise +// - 2.8.0.0+enterprise +func Test_Sync_Upstreams_Target_ZeroWeight_2x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target with weight equals to zero", + kongFile: "testdata/sync/005-create-upstream-and-target-weight/kong.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream_pre31, + Targets: targetZeroWeight, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.4.1 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.0 +func Test_Sync_Upstreams_Target_ZeroWeight_30(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target with weight equals to zero", + kongFile: "testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream_pre31, + Targets: targetZeroWeight, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=3.0.0 <3.1.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_Upstreams_Target_ZeroWeight_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target with weight equals to zero", + kongFile: "testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream, + Targets: targetZeroWeight, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.1.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_Upstreams_Target_ZeroWeight_Konnect(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates an upstream and target with weight equals to zero", + kongFile: "testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml", + expectedState: utils.KongRawState{ + Upstreams: upstream, + Targets: targetZeroWeight, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "konnect", "") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_RateLimitingPlugin(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "fill defaults", + kongFile: "testdata/sync/006-fill-defaults-rate-limiting/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: rateLimitingPlugin, + }, + }, + { + name: "fill defaults with dedup", + kongFile: "testdata/sync/007-fill-defaults-rate-limiting-dedup/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: rateLimitingPlugin, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "==2.7.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 1.5.0.11+enterprise +func Test_Sync_FillDefaults_Earlier_Than_1_5_1(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + // ignore entities fields based on Kong version + ignoreFields := []cmp.Option{ + cmpopts.IgnoreFields(kong.Route{}, "Service"), + cmpopts.IgnoreFields(kong.Healthcheck{}, "Threshold"), + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates a service", + kongFile: "testdata/sync/008-create-simple-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_151, + Plugins: plugin, + Targets: target, + Upstreams: upstream_pre31, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", "<1.5.1 !1.4.3") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, ignoreFields) + }) + } +} + +// test scope: +// - 2.0.5 +// - 2.1.4 +func Test_Sync_FillDefaults_From_2_0_5_To_2_1_4(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create services and routes", + kongFile: "testdata/sync/008-create-simple-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_205_214, + Upstreams: upstream_pre31, + Targets: target, + Plugins: plugin, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.0.5 <=2.1.4") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.2.2 +// - 2.3.3 +// - 2.4.1 +// - 2.5.1 +// - 2.6.0 +// - 2.2.1.3+enterprise +// - 2.3.3.4+enterprise +// - 2.4.1.3+enterprise +// - 2.5.1.2+enterprise +func Test_Sync_FillDefaults_From_2_2_1_to_2_6_0(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create services and routes", + kongFile: "testdata/sync/008-create-simple-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1, + Routes: route1_20x, + Upstreams: upstream_pre31, + Targets: target, + Plugins: plugin, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">2.2.1 <=2.6.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.7.0 +// - 2.6.0.2+enterprise +// - 2.7.0.0+enterprise +// - 2.8.0.0+enterprise +func Test_Sync_FillDefaults_From_2_6_9(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates entities with minimum configuration", + kongFile: "testdata/sync/008-create-simple-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + Plugins: plugin, + Targets: target, + Upstreams: upstream_pre31, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">2.6.9 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_SkipCACert_2x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "syncing with --skip-ca-certificates should ignore CA certs", + kongFile: "testdata/sync/009-skip-ca-cert/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + CACertificates: []*kong.CACertificate{}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // ca_certificates first appeared in 1.3, but we limit to 2.7+ + // here because the schema changed and the entities aren't the same + // across all versions, even though the skip functionality works the same. + runWhen(t, "kong", ">=2.7.0 <3.0.0") + setup(t) + + sync(tc.kongFile, "--skip-ca-certificates") + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_SkipCACert_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "syncing with --skip-ca-certificates should ignore CA certs", + kongFile: "testdata/sync/009-skip-ca-cert/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + CACertificates: []*kong.CACertificate{}, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // ca_certificates first appeared in 1.3, but we limit to 2.7+ + // here because the schema changed and the entities aren't the same + // across all versions, even though the skip functionality works the same. + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + sync(tc.kongFile, "--skip-ca-certificates") + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_RBAC_2x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "rbac", + kongFile: "testdata/sync/xxx-rbac-endpoint-permissions/kong.yaml", + expectedState: utils.KongRawState{ + RBACRoles: []*kong.RBACRole{ + { + Name: kong.String("workspace-portal-admin"), + Comment: kong.String("Full access to Dev Portal related endpoints in the workspace"), + }, + }, + RBACEndpointPermissions: []*kong.RBACEndpointPermission{ + { + Workspace: kong.String("default"), + Endpoint: kong.String("/developers"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/developers/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/files"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/files/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/kong"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*/*/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/workspaces/default"), + Actions: []*string{kong.String("read"), kong.String("update")}, + Negative: kong.Bool(false), + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=2.7.0 <3.0.0") + setup(t) + + sync(tc.kongFile, "--rbac-resources-only") + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_RBAC_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "rbac", + kongFile: "testdata/sync/xxx-rbac-endpoint-permissions/kong3x.yaml", + expectedState: utils.KongRawState{ + RBACRoles: []*kong.RBACRole{ + { + Name: kong.String("workspace-portal-admin"), + Comment: kong.String("Full access to Dev Portal related endpoints in the workspace"), + }, + }, + RBACEndpointPermissions: []*kong.RBACEndpointPermission{ + { + Workspace: kong.String("default"), + Endpoint: kong.String("/developers"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/developers/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/files"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/files/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/kong"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(false), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/rbac/*/*/*/*/*"), + Actions: []*string{kong.String("read"), kong.String("delete"), kong.String("create"), kong.String("update")}, + Negative: kong.Bool(true), + }, + { + Workspace: kong.String("default"), + Endpoint: kong.String("/workspaces/default"), + Actions: []*string{kong.String("read"), kong.String("update")}, + Negative: kong.Bool(false), + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.0.0") + setup(t) + + sync(tc.kongFile, "--rbac-resources-only") + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_Create_Route_With_Service_Name_Reference_2x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create a route with a service name reference", + kongFile: "testdata/sync/010-create-route-with-service-name-reference/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.7.0 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +func Test_Sync_Create_Route_With_Service_Name_Reference_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create a route with a service name reference", + kongFile: "testdata/sync/010-create-route-with-service-name-reference/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.7.0 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 1.x.x +// - 2.x.x +func Test_Sync_PluginsOnEntitiesTill_3_0_0(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create plugins on services, routes and consumers", + kongFile: "testdata/sync/xxx-plugins-on-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + Plugins: plugin_on_entities, + Consumers: consumer, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.8.0 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.0.0+ +func Test_Sync_PluginsOnEntitiesFrom_3_0_0(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "create plugins on services, routes and consumers", + kongFile: "testdata/sync/xxx-plugins-on-entities/kong.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Routes: route1_20x, + Plugins: plugin_on_entities3x, + Consumers: consumer, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.0.0+ +func Test_Sync_PluginOrdering(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin with ordering", + kongFile: "testdata/sync/011-plugin-ordering/kong.yaml", + expectedState: utils.KongRawState{ + Plugins: []*kong.Plugin{ + { + Name: kong.String("request-termination"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "status_code": float64(200), + "echo": false, + "content_type": nil, + "body": nil, + "message": nil, + "trigger": nil, + }, + Ordering: &kong.PluginOrdering{ + Before: kong.PluginOrderingPhase{ + "access": []string{"basic-auth"}, + }, + }, + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_Unsupported_Formats(t *testing.T) { + tests := []struct { + name string + kongFile string + expectedError error + }{ + { + name: "creates a service", + kongFile: "testdata/sync/001-create-a-service/kong.yaml", + expectedError: errors.New( + "cannot apply '1.1' config format version to Kong version 3.0 or above.\n" + + utils.UpgradeMessage), + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=3.0.0") + setup(t) + + err := sync(tc.kongFile) + assert.Equal(t, err, tc.expectedError) + }) + } +} + +var ( + goodCACertPEM = []byte(`-----BEGIN CERTIFICATE----- +MIIE6DCCAtACCQCjgi452nKnUDANBgkqhkiG9w0BAQsFADA2MQswCQYDVQQGEwJV +UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIy +MTAwNDE4NTEyOFoXDTMyMTAwMTE4NTEyOFowNjELMAkGA1UEBhMCVVMxEzARBgNV +BAgMCkNhbGlmb3JuaWExEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBALUwleXMo+CxQFvgtmJbWHO4k3YBJwzWqcr2xWn+ +vgeoLiKFDQC11F/nnWNKkPZyilLeJda5c9YEVaA9IW6/PZhxQ430RM53EJHoiIPB +B9j7BHGzsvWYHEkjXvGQWeD3mR4TAkoCVTfPAjBji/SL+WvLpgPW5hKRVuedD8ja +cTvkNfk6u2TwPYGgekh9+wS9zcEQs4OwsEiQxmi3Z8if1m1uD09tjqAHb0klPEzM +64tPvlzJrIcH3Z5iF+B9qr91PCQJVYOCjGWlUgPULaqIoTVtY+AnaNnNcol0LM/i +oq7uD0JbeyIFDFMDJVqZwDf/zowzLLlP8Hkok4M8JTefXvB0puQoxmGwOAhwlA0G +KF5etrmhg+dOb+f3nWdgbyjPEytyOeMOOA/4Lb8dHRlf9JnEc4DJqwRVPM9BMeUu +9ZlrSWvURRk8nUZfkjTstLqO2aeubfOvb+tDKUq5Ue2B+AFs0ETLy3bds8TU9syV +5Kl+tIwek2TXzc7afvmeCDoRunAx5nVhmW8dpGhknOmJM0GxOi5s2tiu8/3T9XdH +WcH/GMrocZrkhvzkZccSLYoo1jcDn9LwxHVr/BZ43NymjVa6T3QRTta4Kg5wWpfS +yXi4gIW7VJM12CmNfSDEXqhF03+fjFzoWH+YfBK/9GgUMNjnXWIL9PgFFOBomwEL +tv5zAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAKH8eUGgH/OSS3mHB3Gqv1m2Ea04 +Cs03KNEt1weelcHIBWVnPp+jGcSIIfMBnDFAwgxtBKhwptJ9ZKXIzjh7YFxbOT01 +NU+KQ6tD+NFDf+SAUC4AWV9Cam63JIaCVNDoo5UjVMlssnng7NefM1q2+ucoP+gs ++bvUCTJcp3FZsq8aUI9Rka575HqRhl/8kyhcwICCgT5UHQJvCQYrInJ0Faem6dr0 +tHw+PZ1bo6qB7uxBjK9kyu7dK/vEKliUGM4/MXMDKIc5qXUs47wPLbjxvKsuDglK +KftgUWNYRxx9Bf9ylbjd+ayo3+1Lb9cbvdZnh0UHN6677NvXlWNheCmeysLGQHtm +5H6iIhZ75r6QuC7m6hBSJYtLU3fsQECrmaS/+xBGoSSZjacciO7b7qjQdWOfQREn +7vc5eu0N+CJkp8t3SsyQP6v2Su3ILeTt2EWrmmE4K7SYlJe1HrUVj0AWUwzLa6+Z ++Dx16p3M0RBdFMGNNhLqvG3WRfE5c5md34Aq/C5ePjN7pQGmJhI6weowuX9wCrnh +nJJJRfqyJvqgnVBZ6IawNcOyIofITZHlYVKuaDB1odzWCDNEvFftgJvH0MnO7OY9 +Pb9hILPoCy+91jQAVh6Z/ghIcZKHV+N6zV3uS3t5vCejhCNK8mUPSOwAeDf3Bq5r +wQPXd0DdsYGmXVIh +-----END CERTIFICATE-----`) + + badCACertPEM = []byte(`-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUYGc07pbHSjOBPreXh7OcNT2+sD4wDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIs +IEluYy4xJjAkBgNVBAMMHVlvbG80MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMB4X +DTIyMDMyOTE5NDczM1oXDTMyMDMyNjE5NDczM1owWTELMAkGA1UEBhMCVVMxCzAJ +BgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIsIEluYy4xJjAkBgNVBAMMHVlvbG80 +MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAvnhTgdJALnuLKDA0ZUZRVMqcaaC+qvfJkiEFGYwX2ZJiFtzU65F/ +sB2L0ToFqY4tmMVlOmiSZFnRLDZecmQDbbNwc3wtNikmxIOzx4qR4kbRP8DDdyIf +gaNmGCuaXTM5+FYy2iNBn6CeibIjqdErQlAbFLwQs5t3mLsjii2U4cyvfRtO+0RV +HdJ6Np5LsVziN0c5gVIesIrrbxLcOjtXDzwd/w/j5NXqL/OwD5EBH2vqd3QKKX4t +s83BLl2EsbUse47VAImavrwDhmV6S/p/NuJHqjJ6dIbXLYxNS7g26ijcrXxvNhiu +YoZTykSgdI3BXMNAm1ahP/BtJPZpU7CVdQIDAQABo1MwUTAdBgNVHQ4EFgQUe1WZ +fMfZQ9QIJIttwTmcrnl40ccwHwYDVR0jBBgwFoAUe1WZfMfZQ9QIJIttwTmcrnl4 +0ccwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAs4Z8VYbvEs93 +haTHdbbaKk0V6xAL/Q8I8GitK9E8cgf8C5rwwn+wU/Gf39dtMUlnW8uxyzRPx53u +CAAcJAWkabT+xwrlrqjO68H3MgIAwgWA5yZC+qW7ECA8xYEK6DzEHIaOpagJdKcL +IaZr/qTJlEQClvwDs4x/BpHRB5XbmJs86GqEB7XWAm+T2L8DluHAXvek+welF4Xo +fQtLlNS/vqTDqPxkSbJhFv1L7/4gdwfAz51wH/iL7AG/ubFEtoGZPK9YCJ40yTWz +8XrUoqUC+2WIZdtmo6dFFJcLfQg4ARJZjaK6lmxJun3iRMZjKJdQKm/NEKz4y9kA +u8S6yNlu2Q== +-----END CERTIFICATE-----`) +) + +// test scope: +// - 3.0.0+ +// +// This test does two things: +// 1. makes sure decK can correctly configure a Vault entity +// 2. makes sure secrets management works as expected end-to-end +// +// Specifically, for (2) we make use of: +// - a Service and a Route to verify the overall flow works end-to-end +// - a Certificate with secret references +// - an {env} Vault using 'MY_SECRET_' as env variables prefix +// +// The Kong EE instance running in the CI includes the MY_SECRET_CERT +// and MY_SECRET_KEY env variables storing cert/key signed with `caCert`. +// These variables are pulled into the {env} Vault after decK deploy +// the configuration. +// +// After the `deck sync` and the configuration verification step, +// an HTTPS client is created using the `caCert` used to sign the +// deployed certificate, and then a GET is performed to test the +// proxy functionality, which should return a 200. +func Test_Sync_Vault(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create an SSL service/route using an ENV vault", + kongFile: "testdata/sync/012-vaults/kong3x.yaml", + expectedState: utils.KongRawState{ + Vaults: []*kong.Vault{ + { + Name: kong.String("env"), + Prefix: kong.String("my-env-vault"), + Description: kong.String("ENV vault for secrets"), + Config: kong.Configuration{ + "prefix": "MY_SECRET_", + }, + }, + }, + Services: []*kong.Service{ + { + ID: kong.String("58076db2-28b6-423b-ba39-a797193017f7"), + Name: kong.String("svc1"), + ConnectTimeout: kong.Int(60000), + Host: kong.String("httpbin.org"), + Port: kong.Int(80), + Path: kong.String("/status/200"), + Protocol: kong.String("http"), + ReadTimeout: kong.Int(60000), + Retries: kong.Int(5), + WriteTimeout: kong.Int(60000), + Tags: nil, + Enabled: kong.Bool(true), + }, + }, + Routes: route1_20x, + Certificates: []*kong.Certificate{ + { + ID: kong.String("13c562a1-191c-4464-9b18-e5222b46035b"), + Cert: kong.String("{vault://my-env-vault/cert}"), + Key: kong.String("{vault://my-env-vault/key}"), + }, + }, + SNIs: []*kong.SNI{ + { + Name: kong.String("localhost"), + Certificate: &kong.Certificate{ + ID: kong.String("13c562a1-191c-4464-9b18-e5222b46035b"), + }, + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + + // Kong proxy may need a bit to be ready. + time.Sleep(time.Second * 5) + + // build simple http client + client := &http.Client{} + + // use simple http client with https should result + // in a failure due missing certificate. + _, err := client.Get("https://localhost:8443/r1") + assert.NotNil(t, err) + + // use transport with wrong CA cert this should result + // in a failure due to unknown authority. + badCACertPool := x509.NewCertPool() + badCACertPool.AppendCertsFromPEM(badCACertPEM) + + client = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: badCACertPool, + ClientAuth: tls.RequireAndVerifyClientCert, + }, + }, + } + + _, err = client.Get("https://localhost:8443/r1") + assert.NotNil(t, err) + + // use transport with good CA cert should pass + // if referenced secrets are resolved correctly + // using the ENV vault. + goodCACertPool := x509.NewCertPool() + goodCACertPool.AppendCertsFromPEM(goodCACertPEM) + + client = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: goodCACertPool, + ClientAuth: tls.RequireAndVerifyClientCert, + }, + }, + } + + res, err := client.Get("https://localhost:8443/r1") + assert.NoError(t, err) + assert.Equal(t, res.StatusCode, http.StatusOK) + }) + } +} + +// test scope: +// - 2.8.x +func Test_Sync_UpdateUsernameInConsumerWithCustomID(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + kongFileInitial string + expectedState utils.KongRawState + }{ + { + name: "update username on a consumer with custom_id", + kongFile: "testdata/sync/013-update-username-consumer-with-custom-id/kong.yaml", + kongFileInitial: "testdata/sync/013-update-username-consumer-with-custom-id/kong-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: []*kong.Consumer{ + { + Username: kong.String("test_new"), + CustomID: kong.String("custom_test"), + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.8.0 <3.0.0") + setup(t) + + // set up initial state + sync(tc.kongFileInitial) + // update with desired final state + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.8.x +func Test_Sync_UpdateConsumerWithCustomID(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + kongFileInitial string + expectedState utils.KongRawState + }{ + { + name: "update username on a consumer with custom_id", + kongFile: "testdata/sync/014-update-consumer-with-custom-id/kong.yaml", + kongFileInitial: "testdata/sync/014-update-consumer-with-custom-id/kong-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: []*kong.Consumer{ + { + Username: kong.String("test"), + CustomID: kong.String("new_custom_test"), + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "kong", ">=2.8.0 <3.0.0") + setup(t) + + // set up initial state + sync(tc.kongFileInitial) + // update with desired final state + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_UpdateUsernameInConsumerWithCustomID_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + kongFileInitial string + expectedState utils.KongRawState + }{ + { + name: "update username on a consumer with custom_id", + kongFile: "testdata/sync/013-update-username-consumer-with-custom-id/kong3x.yaml", + kongFileInitial: "testdata/sync/013-update-username-consumer-with-custom-id/kong3x-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: []*kong.Consumer{ + { + Username: kong.String("test_new"), + CustomID: kong.String("custom_test"), + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + // set up initial state + sync(tc.kongFileInitial) + // update with desired final state + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.x +func Test_Sync_UpdateConsumerWithCustomID_3x(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + kongFileInitial string + expectedState utils.KongRawState + }{ + { + name: "update username on a consumer with custom_id", + kongFile: "testdata/sync/014-update-consumer-with-custom-id/kong3x.yaml", + kongFileInitial: "testdata/sync/014-update-consumer-with-custom-id/kong3x-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: []*kong.Consumer{ + { + Username: kong.String("test_consumer_3x"), + CustomID: kong.String("test_consumer_3x_custom_test"), + }, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + // set up initial state + sync(tc.kongFileInitial) + // update with desired final state + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 2.7+ +func Test_Sync_ConsumerGroupsTill30(t *testing.T) { + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups", + kongFile: "testdata/sync/015-consumer-groups/kong.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroups, + }, + }, + { + name: "creates consumer groups and plugin", + kongFile: "testdata/sync/016-consumer-groups-and-plugins/kong.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroupsWithRLA, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=2.7.0 <3.0.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.1 +func Test_Sync_ConsumerGroups_31(t *testing.T) { + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + kongFileInitial string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups", + kongFile: "testdata/sync/015-consumer-groups/kong3x.yaml", + kongFileInitial: "testdata/sync/015-consumer-groups/kong3x-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroupsWithTags, + }, + }, + { + name: "creates consumer groups and plugin", + kongFile: "testdata/sync/016-consumer-groups-and-plugins/kong3x.yaml", + kongFileInitial: "testdata/sync/016-consumer-groups-and-plugins/kong3x-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroupsWithTagsAndRLA, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", "==3.1.0") + setup(t) + + // set up initial state + sync(tc.kongFileInitial) + // update with desired final state + sync(tc.kongFile) + + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// This test has 2 goals: +// - make sure consumer groups and their related properties +// can be configured correctly in Kong +// - the actual consumer groups functionality works once set +// +// This is achieved via configuring: +// - 3 consumers: +// - 1 belonging to Gold Consumer Group +// - 1 belonging to Silver Consumer Group +// - 1 not belonging to any Consumer Group +// +// - 3 key-auths, one for each consumer +// - 1 global key-auth plugin +// - 1 global RLA plugin +// - 2 consumer group +// - 2 RLA override, 1 for each consumer group +// - 1 service pointing to mockbin.org +// - 1 route proxying the above service +// +// Once the configuration is verified to be matching in Kong, +// we then check whether the override is correctly applied: consumers +// not belonging to the consumer group should be limited to 5 requests +// every 30s, while consumers belonging to the 'gold' and 'silver' consumer groups +// should be allowed to run respectively 10 and 7 requests in the same timeframe. +// In order to make sure this is the case, we run requests in a loop +// for all consumers and then check at what point they start to receive 429. +func Test_Sync_ConsumerGroupsRLAFrom31(t *testing.T) { + const ( + maxGoldRequestsNumber = 10 + maxSilverRequestsNumber = 7 + maxRegularRequestsNumber = 5 + ) + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups application", + kongFile: "testdata/sync/017-consumer-groups-rla-application/kong3x.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroupsWithRLAApp, + Plugins: consumerGroupAppPlugins, + Services: svc1_207, + Routes: route1_20x, + KeyAuths: []*kong.KeyAuth{ + { + Consumer: &kong.Consumer{ + ID: kong.String("87095815-5395-454e-8c18-a11c9bc0ef04"), + }, + Key: kong.String("i-am-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("5a5b9369-baeb-4faa-a902-c40ccdc2928e"), + }, + Key: kong.String("i-am-not-so-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("e894ea9e-ad08-4acf-a960-5a23aa7701c7"), + }, + Key: kong.String("i-am-just-average"), + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.0.0 <3.1.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + + // Kong proxy may need a bit to be ready. + time.Sleep(time.Second * 10) + + // build simple http client + client := &http.Client{} + + // test 'foo' consumer (part of 'gold' group) + req, err := http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-special") + n := 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxGoldRequestsNumber, n) + + // test 'bar' consumer (part of 'silver' group) + req, err = http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-not-so-special") + n = 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxSilverRequestsNumber, n) + + // test 'baz' consumer (not part of any group) + req, err = http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-just-average") + n = 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxRegularRequestsNumber, n) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_ConsumerGroupsKonnect(t *testing.T) { + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + kongFileInitial string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups", + kongFile: "testdata/sync/015-consumer-groups/kong3x.yaml", + kongFileInitial: "testdata/sync/015-consumer-groups/kong3x-initial.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroupsWithTags, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "konnect", "") + setup(t) + + // set up initial state + sync(tc.kongFileInitial) + // update with desired final state + sync(tc.kongFile) + + testKongState(t, client, true, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.2.0+ +func Test_Sync_PluginInstanceName(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + initialKongFile string + expectedState utils.KongRawState + }{ + { + name: "create a plugin with instance_name", + kongFile: "testdata/sync/018-plugin-instance_name/kong-with-instance_name.yaml", + expectedState: utils.KongRawState{ + Plugins: []*kong.Plugin{ + { + Name: kong.String("request-termination"), + InstanceName: kong.String("my-plugin"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "status_code": float64(200), + "echo": false, + "content_type": nil, + "body": nil, + "message": nil, + "trigger": nil, + }, + }, + }, + }, + }, + { + name: "create a plugin without instance_name", + kongFile: "testdata/sync/018-plugin-instance_name/kong-without-instance_name.yaml", + expectedState: utils.KongRawState{ + Plugins: []*kong.Plugin{ + { + Name: kong.String("request-termination"), + Protocols: []*string{ + kong.String("grpc"), + kong.String("grpcs"), + kong.String("http"), + kong.String("https"), + }, + Enabled: kong.Bool(true), + Config: kong.Configuration{ + "status_code": float64(200), + "echo": false, + "content_type": nil, + "body": nil, + "message": nil, + "trigger": nil, + }, + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.2.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.2.x +// - 3.3.x +func Test_Sync_SkipConsumers(t *testing.T) { + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + skipConsumers bool + expectedState utils.KongRawState + }{ + { + name: "skip-consumers successfully", + kongFile: "testdata/sync/019-skip-consumers/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + }, + skipConsumers: true, + }, + { + name: "do not skip consumers successfully", + kongFile: "testdata/sync/019-skip-consumers/kong3x.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Consumers: consumerGroupsConsumers, + ConsumerGroups: consumerGroupsWithTagsAndRLA, + }, + skipConsumers: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.2.0 <3.4.0") + setup(t) + + if tc.skipConsumers { + sync(tc.kongFile, "--skip-consumers") + } else { + sync(tc.kongFile) + } + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - 3.4.x +func Test_Sync_SkipConsumers_34x(t *testing.T) { + runWhen(t, "enterprise", ">=3.4.0 <3.5.0") + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + skipConsumers bool + expectedState utils.KongRawState + }{ + { + name: "skip-consumers successfully", + kongFile: "testdata/sync/019-skip-consumers/kong34.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + }, + skipConsumers: true, + }, + { + name: "do not skip consumers successfully", + kongFile: "testdata/sync/019-skip-consumers/kong34.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Consumers: consumerGroupsConsumers, + ConsumerGroups: []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + Tags: kong.StringSlice("tag1", "tag3"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + Tags: kong.StringSlice("tag1", "tag2"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + }, + Plugins: []*kong.Plugin{ + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("77e6691d-67c0-446a-9401-27be2b141aae"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(10)}, + "namespace": string("gold"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(30), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("5bcbd3a7-030b-4310-bd1d-2721ff85d236"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(7)}, + "namespace": string("silver"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(30), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": float64(-1), + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + }, + }, + skipConsumers: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + setup(t) + + if tc.skipConsumers { + sync(tc.kongFile, "--skip-consumers") + } else { + sync(tc.kongFile) + } + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_SkipConsumers_Konnect(t *testing.T) { + runWhenKonnect(t) + // setup stage + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + tests := []struct { + name string + kongFile string + skipConsumers bool + expectedState utils.KongRawState + }{ + { + name: "skip-consumers successfully", + kongFile: "testdata/sync/019-skip-consumers/kong34.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + }, + skipConsumers: true, + }, + { + name: "do not skip consumers successfully", + kongFile: "testdata/sync/019-skip-consumers/kong34.yaml", + expectedState: utils.KongRawState{ + Services: svc1_207, + Consumers: consumerGroupsConsumers, + ConsumerGroups: []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + Tags: kong.StringSlice("tag1", "tag3"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + Tags: kong.StringSlice("tag1", "tag2"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + }, + Plugins: []*kong.Plugin{ + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("77e6691d-67c0-446a-9401-27be2b141aae"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(10)}, + "namespace": string("gold"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(30), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": nil, + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + { + Name: kong.String("rate-limiting-advanced"), + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("5bcbd3a7-030b-4310-bd1d-2721ff85d236"), + }, + Config: kong.Configuration{ + "consumer_groups": nil, + "dictionary_name": string("kong_rate_limiting_counters"), + "disable_penalty": bool(false), + "enforce_consumer_groups": bool(false), + "error_code": float64(429), + "error_message": string("API rate limit exceeded"), + "header_name": nil, + "hide_client_headers": bool(false), + "identifier": string("consumer"), + "limit": []any{float64(7)}, + "namespace": string("silver"), + "path": nil, + "redis": map[string]any{ + "cluster_addresses": nil, + "connect_timeout": nil, + "database": float64(0), + "host": nil, + "keepalive_backlog": nil, + "keepalive_pool_size": float64(30), + "password": nil, + "port": nil, + "read_timeout": nil, + "send_timeout": nil, + "sentinel_addresses": nil, + "sentinel_master": nil, + "sentinel_password": nil, + "sentinel_role": nil, + "sentinel_username": nil, + "server_name": nil, + "ssl": false, + "ssl_verify": false, + "timeout": float64(2000), + "username": nil, + }, + "retry_after_jitter_max": float64(1), + "strategy": string("local"), + "sync_rate": nil, + "window_size": []any{float64(60)}, + "window_type": string("sliding"), + }, + Enabled: kong.Bool(true), + Protocols: []*string{kong.String("grpc"), kong.String("grpcs"), kong.String("http"), kong.String("https")}, + }, + }, + }, + skipConsumers: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.2.0") + setup(t) + + if tc.skipConsumers { + sync(tc.kongFile, "--skip-consumers") + } else { + sync(tc.kongFile) + } + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// In the tests we're concerned only with the IDs and names of the entities +// we'll ignore other fields when comparing states. +var ignoreFieldsIrrelevantForIDsTests = []cmp.Option{ + cmpopts.IgnoreFields( + kong.Plugin{}, + "Config", + "Protocols", + "Enabled", + ), + cmpopts.IgnoreFields( + kong.Service{}, + "ConnectTimeout", + "Enabled", + "Host", + "Port", + "Protocol", + "ReadTimeout", + "WriteTimeout", + "Retries", + ), + cmpopts.IgnoreFields( + kong.Route{}, + "Paths", + "PathHandling", + "PreserveHost", + "Protocols", + "RegexPriority", + "StripPath", + "HTTPSRedirectStatusCode", + "Sources", + "Destinations", + "RequestBuffering", + "ResponseBuffering", + ), +} + +// test scope: +// - 3.0.0+ +// - konnect +func Test_Sync_ChangingIDsWhileKeepingNames(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + // These are the IDs that should be present in Kong after the second sync in all cases. + var ( + expectedServiceID = kong.String("98076db2-28b6-423b-ba39-a797193017f7") + expectedRouteID = kong.String("97b6a97e-f3f7-4c47-857a-7464cb9e202b") + expectedConsumerID = kong.String("9a1e49a8-2536-41fa-a4e9-605bf218a4fa") + ) + + // These are the entities that should be present in Kong after the second sync in all cases. + var ( + expectedService = &kong.Service{ + Name: kong.String("s1"), + ID: expectedServiceID, + } + + expectedRoute = &kong.Route{ + Name: kong.String("r1"), + ID: expectedRouteID, + Service: &kong.Service{ + ID: expectedServiceID, + }, + } + + expectedConsumer = &kong.Consumer{ + Username: kong.String("c1"), + ID: expectedConsumerID, + } + + expectedPlugins = []*kong.Plugin{ + { + Name: kong.String("rate-limiting"), + Route: &kong.Route{ + ID: expectedRouteID, + }, + }, + { + Name: kong.String("rate-limiting"), + Service: &kong.Service{ + ID: expectedServiceID, + }, + }, + { + Name: kong.String("rate-limiting"), + Consumer: &kong.Consumer{ + ID: expectedConsumerID, + }, + }, + } + ) + + testCases := []struct { + name string + beforeConfig string + }{ + { + name: "all entities have the same names, but different IDs", + beforeConfig: "testdata/sync/020-same-names-altered-ids/1-before.yaml", + }, + { + name: "service and consumer changed IDs, route did not", + beforeConfig: "testdata/sync/020-same-names-altered-ids/2-before.yaml", + }, + { + name: "route and consumer changed IDs, service did not", + beforeConfig: "testdata/sync/020-same-names-altered-ids/3-before.yaml", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + setup(t) + + // First, create the entities with the original IDs. + err = sync(tc.beforeConfig) + require.NoError(t, err) + + // Then, sync again with the same names, but different IDs. + err = sync("testdata/sync/020-same-names-altered-ids/desired.yaml") + require.NoError(t, err) + + // Finally, check that the all entities exist and have the expected IDs. + testKongState(t, client, false, utils.KongRawState{ + Services: []*kong.Service{expectedService}, + Routes: []*kong.Route{expectedRoute}, + Consumers: []*kong.Consumer{expectedConsumer}, + Plugins: expectedPlugins, + }, ignoreFieldsIrrelevantForIDsTests) + }) + } +} + +// test scope: +// - 3.0.0+ +// - konnect +func Test_Sync_UpdateWithExplicitIDs(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + const ( + beforeConfig = "testdata/sync/021-update-with-explicit-ids/before.yaml" + afterConfig = "testdata/sync/021-update-with-explicit-ids/after.yaml" + ) + + // First, create entities with IDs assigned explicitly. + err = sync(beforeConfig) + require.NoError(t, err) + + // Then, sync again, adding tags to every entity just to trigger an update. + err = sync(afterConfig) + require.NoError(t, err) + + // Finally, verify that the update was successful. + testKongState(t, client, false, utils.KongRawState{ + Services: []*kong.Service{ + { + Name: kong.String("s1"), + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + Tags: kong.StringSlice("after"), + }, + }, + Routes: []*kong.Route{ + { + Name: kong.String("r1"), + ID: kong.String("97b6a97e-f3f7-4c47-857a-7464cb9e202b"), + Tags: kong.StringSlice("after"), + Service: &kong.Service{ + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + }, + }, + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("c1"), + Tags: kong.StringSlice("after"), + }, + }, + }, ignoreFieldsIrrelevantForIDsTests) +} + +// test scope: +// - 3.0.0+ +// - konnect +func Test_Sync_UpdateWithExplicitIDsWithNoNames(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + const ( + beforeConfig = "testdata/sync/022-update-with-explicit-ids-with-no-names/before.yaml" + afterConfig = "testdata/sync/022-update-with-explicit-ids-with-no-names/after.yaml" + ) + + // First, create entities with IDs assigned explicitly. + err = sync(beforeConfig) + require.NoError(t, err) + + // Then, sync again, adding tags to every entity just to trigger an update. + err = sync(afterConfig) + require.NoError(t, err) + + // Finally, verify that the update was successful. + testKongState(t, client, false, utils.KongRawState{ + Services: []*kong.Service{ + { + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + Tags: kong.StringSlice("after"), + }, + }, + Routes: []*kong.Route{ + { + ID: kong.String("97b6a97e-f3f7-4c47-857a-7464cb9e202b"), + Tags: kong.StringSlice("after"), + Service: &kong.Service{ + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + }, + }, + }, + }, ignoreFieldsIrrelevantForIDsTests) +} + +// test scope: +// - 3.0.0+ +// - konnect +func Test_Sync_CreateCertificateWithSNIs(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + err = sync("testdata/sync/023-create-and-update-certificate-with-snis/initial.yaml") + require.NoError(t, err) + + // To ignore noise, we ignore the Key and Cert fields because they are not relevant for this test. + ignoredFields := []cmp.Option{ + cmpopts.IgnoreFields( + kong.Certificate{}, + "Key", + "Cert", + ), + } + + testKongState(t, client, false, utils.KongRawState{ + Certificates: []*kong.Certificate{ + { + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + Tags: kong.StringSlice("before"), + }, + }, + SNIs: []*kong.SNI{ + { + Name: kong.String("example.com"), + Certificate: &kong.Certificate{ + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + }, + }, + }, + }, ignoredFields) + + err = sync("testdata/sync/023-create-and-update-certificate-with-snis/update.yaml") + require.NoError(t, err) + + testKongState(t, client, false, utils.KongRawState{ + Certificates: []*kong.Certificate{ + { + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + Tags: kong.StringSlice("after"), // Tag should be updated. + }, + }, + SNIs: []*kong.SNI{ + { + Name: kong.String("example.com"), + Certificate: &kong.Certificate{ + ID: kong.String("c75a775b-3a32-4b73-8e05-f68169c23941"), + }, + }, + }, + }, ignoredFields) +} + +// test scope: +// - 3.0.0+ +// - konnect +func Test_Sync_ConsumersWithCustomIDAndOrUsername(t *testing.T) { + runWhenKongOrKonnect(t, ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + err = sync("testdata/sync/024-consumers-with-custom_id-and-username/kong3x.yaml") + require.NoError(t, err) + + testKongState(t, client, false, utils.KongRawState{ + Consumers: []*kong.Consumer{ + { + ID: kong.String("ce49186d-7670-445d-a218-897631b29ada"), + Username: kong.String("Foo"), + CustomID: kong.String("foo"), + }, + { + ID: kong.String("7820f383-7b77-4fcc-af7f-14ff3e256693"), + Username: kong.String("foo"), + CustomID: kong.String("bar"), + }, + { + ID: kong.String("18c62c3c-12cc-429a-8e5a-57f2c3691a6b"), + CustomID: kong.String("custom_id_only"), + }, + { + ID: kong.String("8ef278c9-48c1-43e1-b665-e9bc18fab4c8"), + Username: kong.String("username_only"), + }, + }, + }, nil) + + err = sync("testdata/sync/024-consumers-with-custom_id-and-username/kong3x-reverse-order.yaml") + require.NoError(t, err) + + testKongState(t, client, false, utils.KongRawState{ + Consumers: []*kong.Consumer{ + { + Username: kong.String("TestUser"), + }, + { + Username: kong.String("OtherUser"), + CustomID: kong.String("TestUser"), + }, + }, + }, nil) +} + +// This test has 2 goals: +// - make sure consumer groups scoped plugins can be configured correctly in Kong +// - the actual consumer groups functionality works once set +// +// This is achieved via configuring: +// - 3 consumers: +// - 1 belonging to Gold Consumer Group +// - 1 belonging to Silver Consumer Group +// - 1 not belonging to any Consumer Group +// +// - 3 key-auths, one for each consumer +// - 1 global key-auth plugin +// - 2 consumer group +// - 1 global RLA plugin +// - 2 RLA plugins, scoped to the related consumer groups +// - 1 service pointing to mockbin.org +// - 1 route proxying the above service +// +// Once the configuration is verified to be matching in Kong, +// we then check whether the specific RLA configuration is correctly applied: consumers +// not belonging to the consumer group should be limited to 5 requests +// every 30s, while consumers belonging to the 'gold' and 'silver' consumer groups +// should be allowed to run respectively 10 and 7 requests in the same timeframe. +// In order to make sure this is the case, we run requests in a loop +// for all consumers and then check at what point they start to receive 429. +func Test_Sync_ConsumerGroupsScopedPlugins(t *testing.T) { + const ( + maxGoldRequestsNumber = 10 + maxSilverRequestsNumber = 7 + maxRegularRequestsNumber = 5 + ) + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups scoped plugins", + kongFile: "testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + }, + Plugins: consumerGroupScopedPlugins, + Services: svc1_207, + Routes: route1_20x, + KeyAuths: []*kong.KeyAuth{ + { + Consumer: &kong.Consumer{ + ID: kong.String("87095815-5395-454e-8c18-a11c9bc0ef04"), + }, + Key: kong.String("i-am-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("5a5b9369-baeb-4faa-a902-c40ccdc2928e"), + }, + Key: kong.String("i-am-not-so-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("e894ea9e-ad08-4acf-a960-5a23aa7701c7"), + }, + Key: kong.String("i-am-just-average"), + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.4.0 <3.5.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + + // Kong proxy may need a bit to be ready. + time.Sleep(time.Second * 10) + + // build simple http client + client := &http.Client{} + + // test 'foo' consumer (part of 'gold' group) + req, err := http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-special") + n := 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxGoldRequestsNumber, n) + + // test 'bar' consumer (part of 'silver' group) + req, err = http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-not-so-special") + n = 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxSilverRequestsNumber, n) + + // test 'baz' consumer (not part of any group) + req, err = http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-just-average") + n = 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxRegularRequestsNumber, n) + }) + } +} + +func Test_Sync_ConsumerGroupsScopedPlugins_After350(t *testing.T) { + const ( + maxGoldRequestsNumber = 10 + maxSilverRequestsNumber = 7 + maxRegularRequestsNumber = 5 + ) + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups scoped plugins", + kongFile: "testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + }, + Plugins: consumerGroupScopedPlugins35x, + Services: svc1_207, + Routes: route1_20x, + KeyAuths: []*kong.KeyAuth{ + { + Consumer: &kong.Consumer{ + ID: kong.String("87095815-5395-454e-8c18-a11c9bc0ef04"), + }, + Key: kong.String("i-am-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("5a5b9369-baeb-4faa-a902-c40ccdc2928e"), + }, + Key: kong.String("i-am-not-so-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("e894ea9e-ad08-4acf-a960-5a23aa7701c7"), + }, + Key: kong.String("i-am-just-average"), + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.5.0") + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + + // Kong proxy may need a bit to be ready. + time.Sleep(time.Second * 10) + + // build simple http client + client := &http.Client{} + + // test 'foo' consumer (part of 'gold' group) + req, err := http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-special") + n := 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxGoldRequestsNumber, n) + + // test 'bar' consumer (part of 'silver' group) + req, err = http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-not-so-special") + n = 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxSilverRequestsNumber, n) + + // test 'baz' consumer (not part of any group) + req, err = http.NewRequest("GET", "http://localhost:8000/r1", nil) + assert.NoError(t, err) + req.Header.Add("apikey", "i-am-just-average") + n = 0 + for n < 11 { + resp, err := client.Do(req) + assert.NoError(t, err) + defer resp.Body.Close() + if resp.StatusCode == http.StatusTooManyRequests { + break + } + n++ + } + assert.Equal(t, maxRegularRequestsNumber, n) + }) + } +} + +// test scope: +// - > 3.4.0 +func Test_Sync_ConsumerGroupsScopedPlugins_Post340(t *testing.T) { + tests := []struct { + name string + kongFile string + expectedError error + }{ + { + name: "attempt to create deprecated consumer groups configuration with Kong version >= 3.4.0 fails", + kongFile: "testdata/sync/017-consumer-groups-rla-application/kong3x.yaml", + expectedError: fmt.Errorf("building state: %w", utils.ErrorConsumerGroupUpgrade), + }, + { + name: "empty deprecated consumer groups configuration fields do not fail with Kong version >= 3.4.0", + kongFile: "testdata/sync/017-consumer-groups-rla-application/kong3x-empty-application.yaml", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhen(t, "enterprise", ">=3.4.0") + setup(t) + + err := sync(tc.kongFile) + if tc.expectedError == nil { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, tc.expectedError.Error()) + } + }) + } +} + +func Test_Sync_ConsumerGroupsScopedPluginsKonnect(t *testing.T) { + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + tests := []struct { + name string + kongFile string + expectedState utils.KongRawState + }{ + { + name: "creates consumer groups scoped plugins", + kongFile: "testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml", + expectedState: utils.KongRawState{ + Consumers: consumerGroupsConsumers, + ConsumerGroups: []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("silver"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("bar"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + Name: kong.String("gold"), + }, + Consumers: []*kong.Consumer{ + { + Username: kong.String("foo"), + }, + }, + }, + }, + Plugins: consumerGroupScopedPlugins, + Services: svc1_207, + Routes: route1_20x, + KeyAuths: []*kong.KeyAuth{ + { + Consumer: &kong.Consumer{ + ID: kong.String("87095815-5395-454e-8c18-a11c9bc0ef04"), + }, + Key: kong.String("i-am-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("5a5b9369-baeb-4faa-a902-c40ccdc2928e"), + }, + Key: kong.String("i-am-not-so-special"), + }, + { + Consumer: &kong.Consumer{ + ID: kong.String("e894ea9e-ad08-4acf-a960-5a23aa7701c7"), + }, + Key: kong.String("i-am-just-average"), + }, + }, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKonnect(t) + setup(t) + + sync(tc.kongFile) + testKongState(t, client, false, tc.expectedState, nil) + }) + } +} + +// test scope: +// - konnect +func Test_Sync_KonnectRename(t *testing.T) { + // setup stage + tests := []struct { + name string + controlPlaneName string + runtimeGroupName string + kongFile string + flags []string + expectedState utils.KongRawState + }{ + { + name: "konnect-runtime-group-name flag - default", + kongFile: "testdata/sync/026-konnect-rename/default.yaml", + flags: []string{"--konnect-runtime-group-name", "default"}, + expectedState: utils.KongRawState{ + Services: defaultCPService, + }, + }, + { + name: "konnect-control-plane-name flag - default", + kongFile: "testdata/sync/026-konnect-rename/default.yaml", + flags: []string{"--konnect-control-plane-name", "default"}, + expectedState: utils.KongRawState{ + Services: defaultCPService, + }, + }, + { + name: "konnect-runtime-group-name flag - test", + runtimeGroupName: "test", + kongFile: "testdata/sync/026-konnect-rename/test.yaml", + flags: []string{"--konnect-runtime-group-name", "test"}, + expectedState: utils.KongRawState{ + Services: testCPService, + }, + }, + { + name: "konnect-control-plane-name flag - test", + controlPlaneName: "test", + kongFile: "testdata/sync/026-konnect-rename/test.yaml", + flags: []string{"--konnect-control-plane-name", "test"}, + expectedState: utils.KongRawState{ + Services: testCPService, + }, + }, + { + name: "konnect.runtime_group_name - default", + kongFile: "testdata/sync/026-konnect-rename/konnect_default_rg.yaml", + expectedState: utils.KongRawState{ + Services: defaultCPService, + }, + }, + { + name: "konnect.control_plane_name - default", + kongFile: "testdata/sync/026-konnect-rename/konnect_default_cp.yaml", + expectedState: utils.KongRawState{ + Services: defaultCPService, + }, + }, + { + name: "konnect.runtime_group_name - test", + runtimeGroupName: "test", + kongFile: "testdata/sync/026-konnect-rename/konnect_test_rg.yaml", + expectedState: utils.KongRawState{ + Services: testCPService, + }, + }, + { + name: "konnect.control_plane_name - test", + controlPlaneName: "test", + kongFile: "testdata/sync/026-konnect-rename/konnect_test_cp.yaml", + expectedState: utils.KongRawState{ + Services: testCPService, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + runWhenKonnect(t) + setup(t) + if tc.controlPlaneName != "" { + t.Setenv("DECK_KONNECT_CONTROL_PLANE_NAME", tc.controlPlaneName) + t.Cleanup(func() { + reset(t, "--konnect-control-plane-name", tc.controlPlaneName) + }) + } else if tc.runtimeGroupName != "" { + t.Setenv("DECK_KONNECT_RUNTIME_GROUP_NAME", tc.runtimeGroupName) + t.Cleanup(func() { + reset(t, "--konnect-runtime-group-name", tc.runtimeGroupName) + }) + } + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + sync(tc.kongFile, tc.flags...) + testKongState(t, client, true, tc.expectedState, nil) + }) + } +} + +func Test_Sync_KonnectRenameErrors(t *testing.T) { + tests := []struct { + name string + kongFile string + flags []string + expectedError error + }{ + { + name: "different runtime group names fail", + kongFile: "testdata/sync/026-konnect-rename/konnect_default_cp.yaml", + flags: []string{"--konnect-runtime-group-name", "rg1"}, + expectedError: errors.New(`warning: control plane 'rg1' specified via ` + + `--konnect-[control-plane|runtime-group]-name flag is different from 'default' found in state file(s)`), + }, + { + name: "different runtime group names fail", + kongFile: "testdata/sync/026-konnect-rename/konnect_default_rg.yaml", + flags: []string{"--konnect-runtime-group-name", "rg1"}, + expectedError: errors.New(`warning: control plane 'rg1' specified via ` + + `--konnect-[control-plane|runtime-group]-name flag is different from 'default' found in state file(s)`), + }, + { + name: "different control plane names fail", + kongFile: "testdata/sync/026-konnect-rename/konnect_default_cp.yaml", + flags: []string{"--konnect-control-plane-name", "cp1"}, + expectedError: errors.New(`warning: control plane 'cp1' specified via ` + + `--konnect-[control-plane|runtime-group]-name flag is different from 'default' found in state file(s)`), + }, + { + name: "different control plane names fail", + kongFile: "testdata/sync/026-konnect-rename/konnect_default_rg.yaml", + flags: []string{"--konnect-control-plane-name", "cp1"}, + expectedError: errors.New(`warning: control plane 'cp1' specified via ` + + `--konnect-[control-plane|runtime-group]-name flag is different from 'default' found in state file(s)`), + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + err := sync(tc.kongFile, tc.flags...) + assert.Equal(t, err, tc.expectedError) + }) + } +} + +// test scope: +// - 3.0.0+ +func Test_Sync_DoNotUpdateCreatedAt(t *testing.T) { + runWhen(t, "kong", ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + const ( + oldConfig = "testdata/sync/027-created-at/old.yaml" + newConfig = "testdata/sync/027-created-at/new.yaml" + ) + + // provision entities + require.NoError(t, sync(oldConfig)) + + // get the current state + ctx := context.Background() + oldKongState, err := deckDump.Get(ctx, client, deckDump.Config{}) + if err != nil { + t.Errorf(err.Error()) + } + + // update entities + time.Sleep(time.Second) + require.NoError(t, sync(newConfig)) + + // get the new state + newKongState, err := deckDump.Get(ctx, client, deckDump.Config{}) + if err != nil { + t.Errorf(err.Error()) + } + + // verify that the created_at have not changed across deployments + require.Equal(t, oldKongState.Services[0].CreatedAt, newKongState.Services[0].CreatedAt) + require.Equal(t, oldKongState.Routes[0].CreatedAt, newKongState.Routes[0].CreatedAt) + require.Equal(t, oldKongState.Plugins[0].CreatedAt, newKongState.Plugins[0].CreatedAt) + require.Equal(t, oldKongState.Consumers[0].CreatedAt, newKongState.Consumers[0].CreatedAt) + + // verify that the updated_at have changed across deployments + require.NotEqual(t, oldKongState.Services[0].UpdatedAt, newKongState.Services[0].UpdatedAt) + require.NotEqual(t, oldKongState.Routes[0].UpdatedAt, newKongState.Routes[0].UpdatedAt) + // plugins do not have an updated_at field + // consumers do not have an updated_at field +} diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go new file mode 100644 index 0000000..7f194a0 --- /dev/null +++ b/tests/integration/test_utils.go @@ -0,0 +1,344 @@ +//nolint:deadcode +package integration + +import ( + "context" + "io" + "os" + "testing" + + "github.com/acarl005/stripansi" + "github.com/fatih/color" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/kong/deck/cmd" + deckDump "github.com/kong/go-database-reconciler/pkg/dump" + "github.com/kong/go-database-reconciler/pkg/utils" + "github.com/kong/go-kong/kong" +) + +func int32p(i int) *int32 { + p := int32(i) + return &p +} + +func getKongAddress() string { + address := os.Getenv("DECK_KONG_ADDR") + if address != "" { + return address + } + return "http://localhost:8001" +} + +func getTestClient() (*kong.Client, error) { + ctx := context.Background() + controlPlaneName := os.Getenv("DECK_KONNECT_RUNTIME_GROUP_NAME") + if controlPlaneName == "" { + controlPlaneName = os.Getenv("DECK_KONNECT_CONTROL_PLANE_NAME") + } + konnectConfig := utils.KonnectConfig{ + Address: os.Getenv("DECK_KONNECT_ADDR"), + Email: os.Getenv("DECK_KONNECT_EMAIL"), + Password: os.Getenv("DECK_KONNECT_PASSWORD"), + Token: os.Getenv("DECK_KONNECT_TOKEN"), + ControlPlaneName: controlPlaneName, + } + if (konnectConfig.Email != "" && konnectConfig.Password != "") || konnectConfig.Token != "" { + return cmd.GetKongClientForKonnectMode(ctx, &konnectConfig) + } + return utils.GetKongClient(utils.KongClientConfig{ + Address: getKongAddress(), + }) +} + +func runWhenKonnect(t *testing.T) { + t.Helper() + + if os.Getenv("DECK_KONNECT_EMAIL") == "" && + os.Getenv("DECK_KONNECT_PASSWORD") == "" && + os.Getenv("DECK_KONNECT_TOKEN") == "" { + t.Skip("non-Konnect test instance, skipping") + } +} + +func skipWhenKonnect(t *testing.T) { + t.Helper() + + if os.Getenv("DECK_KONNECT_EMAIL") != "" || + os.Getenv("DECK_KONNECT_PASSWORD") != "" || + os.Getenv("DECK_KONNECT_TOKEN") != "" { + t.Skip("non-Kong test instance, skipping") + } +} + +func runWhenKongOrKonnect(t *testing.T, kongSemverRange string) { + t.Helper() + + if os.Getenv("DECK_KONNECT_EMAIL") != "" && + os.Getenv("DECK_KONNECT_PASSWORD") != "" && + os.Getenv("DECK_KONNECT_TOKEN") != "" { + return + } + kong.RunWhenKong(t, kongSemverRange) +} + +func runWhen(t *testing.T, mode string, semverRange string) { + t.Helper() + + switch mode { + case "kong": + skipWhenKonnect(t) + kong.RunWhenKong(t, semverRange) + case "enterprise": + skipWhenKonnect(t) + kong.RunWhenEnterprise(t, semverRange, kong.RequiredFeatures{}) + case "konnect": + runWhenKonnect(t) + } +} + +func sortSlices(x, y interface{}) bool { + var xName, yName string + switch xEntity := x.(type) { + case *kong.Service: + yEntity := y.(*kong.Service) + xName = *xEntity.Name + yName = *yEntity.Name + case *kong.Route: + yEntity := y.(*kong.Route) + xName = *xEntity.Name + yName = *yEntity.Name + case *kong.Vault: + yEntity := y.(*kong.Vault) + xName = *xEntity.Prefix + yName = *yEntity.Prefix + case *kong.Consumer: + yEntity := y.(*kong.Consumer) + if xEntity.Username != nil { + xName = *xEntity.Username + } else { + xName = *xEntity.ID + } + if yEntity.Username != nil { + yName = *yEntity.Username + } else { + yName = *yEntity.ID + } + case *kong.ConsumerGroup: + yEntity := y.(*kong.ConsumerGroup) + xName = *xEntity.Name + yName = *yEntity.Name + case *kong.ConsumerGroupObject: + yEntity := y.(*kong.ConsumerGroupObject) + xName = *xEntity.ConsumerGroup.Name + yName = *yEntity.ConsumerGroup.Name + case *kong.ConsumerGroupPlugin: + yEntity := y.(*kong.ConsumerGroupPlugin) + xName = *xEntity.ConsumerGroup.ID + yName = *yEntity.ConsumerGroup.ID + case *kong.KeyAuth: + yEntity := y.(*kong.KeyAuth) + xName = *xEntity.Key + yName = *yEntity.Key + case *kong.Plugin: + yEntity := y.(*kong.Plugin) + xName = *xEntity.Name + yName = *yEntity.Name + if xEntity.Route != nil { + xName += *xEntity.Route.ID + } + if xEntity.Service != nil { + xName += *xEntity.Service.ID + } + if xEntity.Consumer != nil { + xName += *xEntity.Consumer.ID + } + if xEntity.ConsumerGroup != nil { + xName += *xEntity.ConsumerGroup.ID + } + if yEntity.Route != nil { + yName += *yEntity.Route.ID + } + if yEntity.Service != nil { + yName += *yEntity.Service.ID + } + if yEntity.Consumer != nil { + yName += *yEntity.Consumer.ID + } + if yEntity.ConsumerGroup != nil { + yName += *yEntity.ConsumerGroup.ID + } + } + return xName < yName +} + +func testKongState(t *testing.T, client *kong.Client, isKonnect bool, + expectedState utils.KongRawState, ignoreFields []cmp.Option, +) { + // Get entities from Kong + ctx := context.Background() + dumpConfig := deckDump.Config{} + if expectedState.RBACEndpointPermissions != nil { + dumpConfig.RBACResourcesOnly = true + } + if isKonnect { + controlPlaneName := os.Getenv("DECK_KONNECT_CONTROL_PLANE_NAME") + if controlPlaneName == "" { + controlPlaneName = os.Getenv("DECK_KONNECT_CONTROL_PLANE_NAME") + } + if controlPlaneName != "" { + dumpConfig.KonnectControlPlane = controlPlaneName + } else { + dumpConfig.KonnectControlPlane = "default" + } + } + kongState, err := deckDump.Get(ctx, client, dumpConfig) + if err != nil { + t.Errorf(err.Error()) + } + + opt := []cmp.Option{ + cmpopts.IgnoreFields(kong.Service{}, "CreatedAt", "UpdatedAt"), + cmpopts.IgnoreFields(kong.Route{}, "CreatedAt", "UpdatedAt"), + cmpopts.IgnoreFields(kong.Plugin{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.Upstream{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.Target{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.CACertificate{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.RBACEndpointPermission{}, "Role", "CreatedAt"), + cmpopts.IgnoreFields(kong.RBACRole{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.Consumer{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.Vault{}, "ID", "CreatedAt", "UpdatedAt"), + cmpopts.IgnoreFields(kong.Certificate{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.SNI{}, "ID", "CreatedAt"), + cmpopts.IgnoreFields(kong.ConsumerGroup{}, "CreatedAt", "ID"), + cmpopts.IgnoreFields(kong.ConsumerGroupPlugin{}, "CreatedAt", "ID"), + cmpopts.IgnoreFields(kong.KeyAuth{}, "ID", "CreatedAt"), + cmpopts.SortSlices(sortSlices), + cmpopts.SortSlices(func(a, b *string) bool { return *a < *b }), + cmpopts.EquateEmpty(), + } + opt = append(opt, ignoreFields...) + + if diff := cmp.Diff(kongState, &expectedState, opt...); diff != "" { + t.Errorf(diff) + } +} + +func reset(t *testing.T, opts ...string) { + deckCmd := cmd.NewRootCmd() + args := []string{"reset", "--force"} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + if err := deckCmd.Execute(); err != nil { + t.Fatalf(err.Error(), "failed to reset Kong's state") + } +} + +func readFile(filepath string) (string, error) { + content, err := os.ReadFile(filepath) + if err != nil { + return "", err + } + return string(content), nil +} + +// setup sets deck env variable to prevent analytics in tests and registers reset +// command with t.Cleanup(). +// +// NOTE: Can't be called with tests running t.Parallel() because of the usage +// of t.Setenv(). +func setup(t *testing.T) { + // disable analytics for integration tests + t.Setenv("DECK_ANALYTICS", "off") + t.Cleanup(func() { + reset(t) + }) +} + +func sync(kongFile string, opts ...string) error { + deckCmd := cmd.NewRootCmd() + args := []string{"sync", "-s", kongFile} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + return deckCmd.ExecuteContext(context.Background()) +} + +func diff(kongFile string, opts ...string) (string, error) { + deckCmd := cmd.NewRootCmd() + args := []string{"diff", "-s", kongFile} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + + // overwrite default standard output + r, w, _ := os.Pipe() + color.Output = w + + // execute decK command + cmdErr := deckCmd.ExecuteContext(context.Background()) + + // read command output + w.Close() + out, _ := io.ReadAll(r) + + return stripansi.Strip(string(out)), cmdErr +} + +func dump(opts ...string) (string, error) { + deckCmd := cmd.NewRootCmd() + args := []string{"dump"} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + + // capture command output to be used during tests + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + cmdErr := deckCmd.ExecuteContext(context.Background()) + + w.Close() + out, _ := io.ReadAll(r) + os.Stdout = rescueStdout + + return stripansi.Strip(string(out)), cmdErr +} + +func lint(opts ...string) (string, error) { + deckCmd := cmd.NewRootCmd() + args := []string{"file", "lint"} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + + // capture command output to be used during tests + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + cmdErr := deckCmd.ExecuteContext(context.Background()) + + w.Close() + out, _ := io.ReadAll(r) + os.Stdout = rescueStdout + + return stripansi.Strip(string(out)), cmdErr +} + +func ping(opts ...string) error { + deckCmd := cmd.NewRootCmd() + args := []string{"gateway", "ping"} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + return deckCmd.ExecuteContext(context.Background()) +} diff --git a/tests/integration/testdata/diff/001-not-existing-workspace/kong.yaml b/tests/integration/testdata/diff/001-not-existing-workspace/kong.yaml new file mode 100644 index 0000000..7af70f2 --- /dev/null +++ b/tests/integration/testdata/diff/001-not-existing-workspace/kong.yaml @@ -0,0 +1,9 @@ +_workspace: test +services: + - name: svc1 + host: mockbin.org +plugins: + - name: rate-limiting + id: a1368a28-cb5c-4eee-86d8-03a6bdf94b5e + config: + minute: 123 diff --git a/tests/integration/testdata/diff/001-not-existing-workspace/kong3x.yaml b/tests/integration/testdata/diff/001-not-existing-workspace/kong3x.yaml new file mode 100644 index 0000000..c540331 --- /dev/null +++ b/tests/integration/testdata/diff/001-not-existing-workspace/kong3x.yaml @@ -0,0 +1,10 @@ +_format_version: "3.0" +_workspace: test +services: + - name: svc1 + host: mockbin.org +plugins: + - name: rate-limiting + id: a1368a28-cb5c-4eee-86d8-03a6bdf94b5e + config: + minute: 123 diff --git a/tests/integration/testdata/diff/002-mask/initial.yaml b/tests/integration/testdata/diff/002-mask/initial.yaml new file mode 100644 index 0000000..b8d32ad --- /dev/null +++ b/tests/integration/testdata/diff/002-mask/initial.yaml @@ -0,0 +1,5 @@ +_format_version: "1.1" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: ${{ env "DECK_SVC1_HOSTNAME" }} diff --git a/tests/integration/testdata/diff/002-mask/initial3x.yaml b/tests/integration/testdata/diff/002-mask/initial3x.yaml new file mode 100644 index 0000000..44bb50d --- /dev/null +++ b/tests/integration/testdata/diff/002-mask/initial3x.yaml @@ -0,0 +1,5 @@ +_format_version: "3.0" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: ${{ env "DECK_SVC1_HOSTNAME" }} diff --git a/tests/integration/testdata/diff/002-mask/kong.yaml b/tests/integration/testdata/diff/002-mask/kong.yaml new file mode 100644 index 0000000..aa1de15 --- /dev/null +++ b/tests/integration/testdata/diff/002-mask/kong.yaml @@ -0,0 +1,16 @@ +_format_version: "1.1" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: ${{ env "DECK_SVC1_HOSTNAME" }} + tags: + - ${{ env "DECK_SVC1_HOSTNAME" }} is an external host. I like mockbin.org! + - foo:foo + - baz:${{ env "DECK_BAZZ" }} + - another:${{ env "DECK_BAZZ" }} + - bar:${{ env "DECK_BARR" }} +plugins: + - name: rate-limiting + id: a1368a28-cb5c-4eee-86d8-03a6bdf94b5e + config: + minute: 123 diff --git a/tests/integration/testdata/diff/002-mask/kong3x.yaml b/tests/integration/testdata/diff/002-mask/kong3x.yaml new file mode 100644 index 0000000..8c5139a --- /dev/null +++ b/tests/integration/testdata/diff/002-mask/kong3x.yaml @@ -0,0 +1,16 @@ +_format_version: "3.0" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: ${{ env "DECK_SVC1_HOSTNAME" }} + tags: + - ${{ env "DECK_SVC1_HOSTNAME" }} is an external host. I like mockbin.org! + - foo:foo + - baz:${{ env "DECK_BAZZ" }} + - another:${{ env "DECK_BAZZ" }} + - bar:${{ env "DECK_BARR" }} +plugins: + - name: rate-limiting + id: a1368a28-cb5c-4eee-86d8-03a6bdf94b5e + config: + minute: 123 diff --git a/tests/integration/testdata/diff/003-unmask/initial.yaml b/tests/integration/testdata/diff/003-unmask/initial.yaml new file mode 100644 index 0000000..a089e7c --- /dev/null +++ b/tests/integration/testdata/diff/003-unmask/initial.yaml @@ -0,0 +1,5 @@ +_format_version: "1.1" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: mockbin.org diff --git a/tests/integration/testdata/diff/003-unmask/initial3x.yaml b/tests/integration/testdata/diff/003-unmask/initial3x.yaml new file mode 100644 index 0000000..ba67ee9 --- /dev/null +++ b/tests/integration/testdata/diff/003-unmask/initial3x.yaml @@ -0,0 +1,5 @@ +_format_version: "3.0" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: mockbin.org diff --git a/tests/integration/testdata/diff/003-unmask/kong.yaml b/tests/integration/testdata/diff/003-unmask/kong.yaml new file mode 100644 index 0000000..a116542 --- /dev/null +++ b/tests/integration/testdata/diff/003-unmask/kong.yaml @@ -0,0 +1,12 @@ +_format_version: "1.1" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: mockbin.org + tags: + - test +plugins: + - name: rate-limiting + id: a1368a28-cb5c-4eee-86d8-03a6bdf94b5e + config: + minute: 123 diff --git a/tests/integration/testdata/diff/003-unmask/kong3x.yaml b/tests/integration/testdata/diff/003-unmask/kong3x.yaml new file mode 100644 index 0000000..219570e --- /dev/null +++ b/tests/integration/testdata/diff/003-unmask/kong3x.yaml @@ -0,0 +1,12 @@ +_format_version: "3.0" +services: + - name: svc1 + id: 9ecf5708-f2f4-444e-a4c7-fcd3a57f9a6d + host: mockbin.org + tags: + - test +plugins: + - name: rate-limiting + id: a1368a28-cb5c-4eee-86d8-03a6bdf94b5e + config: + minute: 123 diff --git a/tests/integration/testdata/dump/001-entities-with-tags/expected.yaml b/tests/integration/testdata/dump/001-entities-with-tags/expected.yaml new file mode 100644 index 0000000..9a6c585 --- /dev/null +++ b/tests/integration/testdata/dump/001-entities-with-tags/expected.yaml @@ -0,0 +1,236 @@ +_format_version: "3.0" +_info: + defaults: {} + select_tags: + - managed-by-deck + - org-unit-42 +certificates: +- cert: | + -----BEGIN CERTIFICATE----- + MIIC1jCCAb4CCQCt23nwvxSCvjANBgkqhkiG9w0BAQsFADAtMRYwFAYDVQQDDA0q + LmV4YW1wbGUuY29tMRMwEQYDVQQKDAprb25naHEub3JnMB4XDTE4MTIzMTIwMTkw + MVoXDTE5MTIzMTIwMTkwMVowLTEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTETMBEG + A1UECgwKa29uZ2hxLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + AKj/2r1AXo9x+2Csrd0SHbpnzuW+xYqgsd+YA9ZrZNV7SZGSbaZymsRMz8wg5OIU + iUik2GM1749/lYvojLFStBPy9UY/gd++5f3wLp4xHiI+IU2XQ97otXKGfyh36RmN + dKDqPLN8BG3R346s/y1GOulFvLthYmZVYF9ufHiqimfEDSbTt79P5C3X0Rw/afK1 + GjHEJPCB/XkZ6lkcEyL6LqZI5oBigDqa9hI/nWLxEzfm8pgosiS38p9TAijlOkpm + tX2p2b1pktlNIy3rxsqj6IynN9Wc7FpV1N4HoPKV7vQQ08hjwW6WfanVthaaJosj + Vr2TBCJ1ltAmsb+5B2VPYVkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnByTyQfV + 3LkwuoWS57CWcqbNw/cHnv/ChzmIv+6mIXvDBSvCgrPZIWCpaCfYRG6R51E44fr/ + 8V1AKT0Zt15DjrXEEcIGQgsIDO91/wlL091fTAUzSbL0yt7HTlm8sX6xndPNAZrq + cfcIPVMxknfqPy2VqS4IrNC03pHkDKtokphBjVUlkiWsdcq+fHYbS2xL2d1Da/uN + hX/iwgo+v5gOF5xtaXx7D7L3Cf+MHb/MOXWPfYXNiTpSBVX8/Kx5RP+QLI16nWvw + lrijTlXZFR8NIZBrCo/QZ2cNbUAbN3R0n+/kMFubxBL8WEm6Qhi9jBjbJeDMspd8 + C+/TZJQMpx5vyA== + -----END CERTIFICATE----- + id: 13c562a1-191c-4464-9b18-e5222b46035b + key: | + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo/9q9QF6Pcftg + rK3dEh26Z87lvsWKoLHfmAPWa2TVe0mRkm2mcprETM/MIOTiFIlIpNhjNe+Pf5WL + 6IyxUrQT8vVGP4HfvuX98C6eMR4iPiFNl0Pe6LVyhn8od+kZjXSg6jyzfARt0d+O + rP8tRjrpRby7YWJmVWBfbnx4qopnxA0m07e/T+Qt19EcP2nytRoxxCTwgf15GepZ + HBMi+i6mSOaAYoA6mvYSP51i8RM35vKYKLIkt/KfUwIo5TpKZrV9qdm9aZLZTSMt + 68bKo+iMpzfVnOxaVdTeB6Dyle70ENPIY8Fuln2p1bYWmiaLI1a9kwQidZbQJrG/ + uQdlT2FZAgMBAAECggEAVnyRcda2Tcy0K7ZTR9aUlie370VhDN/OB7JhDGNreAEf + FjuMl+kAoUL5+OpAmB6QXzfVcXhRv+s4GiCJl9nORINK2Id5rIqiYwF+qgBS/o0z + N+UYm8QVz6Va/9fV1/jXXd5h8Cygi58jPH32HTJaxbSlsHNXCy3YIx6E3q/QIueR + 6ZdSXPqMEqxEU19M9jW8UeiRFrpmcyYxVpfxYIY/+O9lYjSpaeLs7hZeCP9PqWXA + Sxz2CnHZ8BcsDxAyuoHoVw+kjMpUMvA3sD4lwkV8BAYzfLmQf6PR83SFNsrE8XYu + /8WnQuCuytcl8Zg55R6tGCvf6Wyyf+MDRPwv/43QMQKBgQDbqK9Dq54k+EHgSNnP + K6AhNjFd6aqcNC1kom/sSlWBnuA/BEqJMECr8S2dYvzONUPPfX5NNUjB4Vw3Qw7a + pUgKuCQoVpzpZs5m1bk78itWDtA84LjkXfdejnUXVw/aVxLCM5QV9aEkm/dEWWMI + P1WTYVoWoZCLlEE08q0AvZQcdQKBgQDE9ZCmc6ncmhnQftuRj5PnXG2a79MLCT61 + sCEBDVvkcUJVqbzwGRLwRkdIzLgvmiuP+SukHgyfr8/RXG99xEW/q7NDrtEcqfXP + 19QXwOIp5NwDnOXyAlXiyZ50fCE2tSo2wP485+NIhmKj5Zt6y/DL6Qbc5k73XmK4 + KX5Ej15k1QKBgQCc6KeiIFLMt+Ze78tfORue/dZP7p3oDUGr1Hk9AnCIMlSfz1Hr + I+Per17VQaOzLcttyYhSYNDDZld4RlezCkQnHBkAE7bs53pjbSJv1vLr+5L3GdQZ + laIiEoNEE/YIExEcVrne4eKlgyAj2/JpLszThcRTzD+z5UibKQs6LzJBDQKBgDVa + dAGzCUt57w48nwvyQdWFgydaWef+bB9Zg8c+MCtUxuxfm4/Kqwetcff1hNtYPv60 + N68weKj1Pi1vhcAi3+YJA/mMrJbAL5dK1uhMVreUiEjuQpfpLAzQIv1Y9sJUFwhY + BUbIZhgqVyQguZptDmCeUj6aoL9/sOxESTEXSTG1AoGBAMQ5iJZMsdLCERv0+6Y1 + F/t/YSW8cugB3vdV9jHZuosoprz48p92pYP8OdQc70H5hZt53hoYNgYFSd+MU6H1 + hJCaXTsiP4IUmBjiwzSp3o1ctP8lWvnyJpAadYdDhaDaAAoaMjCo9cm5OMwc8t8x + hwAPXV2cgWH8fPcT9NLAcwWk + -----END PRIVATE KEY----- + snis: + - name: demo1.example.com + - name: demo2.example.com + - name: demo3.example.com + tags: + - cloudops-managed +consumers: +- acls: + - group: foo-group + hmacauth_credentials: + - secret: yeNZBeqCuk0D3H85VX77Umacf91MwqRo + username: hmac-user + jwt_secrets: + - algorithm: HS256 + key: MKWeR0nu9OAUR9HrjpUG82Hbfz7ZXsIw + secret: 6gkrxTKAraykMSpmnLNEGiEE3Yz8XL6U + keyauth_credentials: + - key: iwb6Djkk4HhUlOCmLilDIKh6nZrn90ts + username: harry +plugins: +- config: + bandwidth_metrics: false + latency_metrics: false + per_consumer: false + status_code_metrics: false + upstream_health_metrics: false + enabled: true + name: prometheus + protocols: + - http + - https +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + name: r1 + path_handling: v0 + paths: + - /r1 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + tags: + - team-svc1 + write_timeout: 60000 +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc2 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + name: r2 + path_handling: v0 + paths: + - /r2 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + write_timeout: 60000 +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc3 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + methods: + - GET + name: r3 + path_handling: v0 + paths: + - /r3 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + write_timeout: 60000 +upstreams: +- algorithm: round-robin + hash_fallback: none + hash_on: none + hash_on_cookie_path: / + healthchecks: + active: + concurrency: 10 + healthy: + http_statuses: + - 200 + - 302 + interval: 0 + successes: 0 + http_path: / + https_verify_certificate: true + timeout: 1 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 404 + - 500 + - 501 + - 502 + - 503 + - 504 + - 505 + interval: 0 + tcp_failures: 0 + timeouts: 0 + passive: + healthy: + http_statuses: + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 226 + - 300 + - 301 + - 302 + - 303 + - 304 + - 305 + - 306 + - 307 + - 308 + successes: 0 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 500 + - 503 + tcp_failures: 0 + timeouts: 0 + threshold: 0 + name: upstream1 + slots: 10000 + targets: + - target: 198.51.100.11:80 + weight: 100 + - target: 198.51.100.12:80 + weight: 100 + - target: 198.51.100.13:80 + weight: 100 + use_srv_name: false diff --git a/tests/integration/testdata/dump/001-entities-with-tags/expected30.yaml b/tests/integration/testdata/dump/001-entities-with-tags/expected30.yaml new file mode 100644 index 0000000..c575b80 --- /dev/null +++ b/tests/integration/testdata/dump/001-entities-with-tags/expected30.yaml @@ -0,0 +1,235 @@ +_format_version: "3.0" +_info: + defaults: {} + select_tags: + - managed-by-deck + - org-unit-42 +certificates: +- cert: | + -----BEGIN CERTIFICATE----- + MIIC1jCCAb4CCQCt23nwvxSCvjANBgkqhkiG9w0BAQsFADAtMRYwFAYDVQQDDA0q + LmV4YW1wbGUuY29tMRMwEQYDVQQKDAprb25naHEub3JnMB4XDTE4MTIzMTIwMTkw + MVoXDTE5MTIzMTIwMTkwMVowLTEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTETMBEG + A1UECgwKa29uZ2hxLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + AKj/2r1AXo9x+2Csrd0SHbpnzuW+xYqgsd+YA9ZrZNV7SZGSbaZymsRMz8wg5OIU + iUik2GM1749/lYvojLFStBPy9UY/gd++5f3wLp4xHiI+IU2XQ97otXKGfyh36RmN + dKDqPLN8BG3R346s/y1GOulFvLthYmZVYF9ufHiqimfEDSbTt79P5C3X0Rw/afK1 + GjHEJPCB/XkZ6lkcEyL6LqZI5oBigDqa9hI/nWLxEzfm8pgosiS38p9TAijlOkpm + tX2p2b1pktlNIy3rxsqj6IynN9Wc7FpV1N4HoPKV7vQQ08hjwW6WfanVthaaJosj + Vr2TBCJ1ltAmsb+5B2VPYVkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnByTyQfV + 3LkwuoWS57CWcqbNw/cHnv/ChzmIv+6mIXvDBSvCgrPZIWCpaCfYRG6R51E44fr/ + 8V1AKT0Zt15DjrXEEcIGQgsIDO91/wlL091fTAUzSbL0yt7HTlm8sX6xndPNAZrq + cfcIPVMxknfqPy2VqS4IrNC03pHkDKtokphBjVUlkiWsdcq+fHYbS2xL2d1Da/uN + hX/iwgo+v5gOF5xtaXx7D7L3Cf+MHb/MOXWPfYXNiTpSBVX8/Kx5RP+QLI16nWvw + lrijTlXZFR8NIZBrCo/QZ2cNbUAbN3R0n+/kMFubxBL8WEm6Qhi9jBjbJeDMspd8 + C+/TZJQMpx5vyA== + -----END CERTIFICATE----- + id: 13c562a1-191c-4464-9b18-e5222b46035b + key: | + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo/9q9QF6Pcftg + rK3dEh26Z87lvsWKoLHfmAPWa2TVe0mRkm2mcprETM/MIOTiFIlIpNhjNe+Pf5WL + 6IyxUrQT8vVGP4HfvuX98C6eMR4iPiFNl0Pe6LVyhn8od+kZjXSg6jyzfARt0d+O + rP8tRjrpRby7YWJmVWBfbnx4qopnxA0m07e/T+Qt19EcP2nytRoxxCTwgf15GepZ + HBMi+i6mSOaAYoA6mvYSP51i8RM35vKYKLIkt/KfUwIo5TpKZrV9qdm9aZLZTSMt + 68bKo+iMpzfVnOxaVdTeB6Dyle70ENPIY8Fuln2p1bYWmiaLI1a9kwQidZbQJrG/ + uQdlT2FZAgMBAAECggEAVnyRcda2Tcy0K7ZTR9aUlie370VhDN/OB7JhDGNreAEf + FjuMl+kAoUL5+OpAmB6QXzfVcXhRv+s4GiCJl9nORINK2Id5rIqiYwF+qgBS/o0z + N+UYm8QVz6Va/9fV1/jXXd5h8Cygi58jPH32HTJaxbSlsHNXCy3YIx6E3q/QIueR + 6ZdSXPqMEqxEU19M9jW8UeiRFrpmcyYxVpfxYIY/+O9lYjSpaeLs7hZeCP9PqWXA + Sxz2CnHZ8BcsDxAyuoHoVw+kjMpUMvA3sD4lwkV8BAYzfLmQf6PR83SFNsrE8XYu + /8WnQuCuytcl8Zg55R6tGCvf6Wyyf+MDRPwv/43QMQKBgQDbqK9Dq54k+EHgSNnP + K6AhNjFd6aqcNC1kom/sSlWBnuA/BEqJMECr8S2dYvzONUPPfX5NNUjB4Vw3Qw7a + pUgKuCQoVpzpZs5m1bk78itWDtA84LjkXfdejnUXVw/aVxLCM5QV9aEkm/dEWWMI + P1WTYVoWoZCLlEE08q0AvZQcdQKBgQDE9ZCmc6ncmhnQftuRj5PnXG2a79MLCT61 + sCEBDVvkcUJVqbzwGRLwRkdIzLgvmiuP+SukHgyfr8/RXG99xEW/q7NDrtEcqfXP + 19QXwOIp5NwDnOXyAlXiyZ50fCE2tSo2wP485+NIhmKj5Zt6y/DL6Qbc5k73XmK4 + KX5Ej15k1QKBgQCc6KeiIFLMt+Ze78tfORue/dZP7p3oDUGr1Hk9AnCIMlSfz1Hr + I+Per17VQaOzLcttyYhSYNDDZld4RlezCkQnHBkAE7bs53pjbSJv1vLr+5L3GdQZ + laIiEoNEE/YIExEcVrne4eKlgyAj2/JpLszThcRTzD+z5UibKQs6LzJBDQKBgDVa + dAGzCUt57w48nwvyQdWFgydaWef+bB9Zg8c+MCtUxuxfm4/Kqwetcff1hNtYPv60 + N68weKj1Pi1vhcAi3+YJA/mMrJbAL5dK1uhMVreUiEjuQpfpLAzQIv1Y9sJUFwhY + BUbIZhgqVyQguZptDmCeUj6aoL9/sOxESTEXSTG1AoGBAMQ5iJZMsdLCERv0+6Y1 + F/t/YSW8cugB3vdV9jHZuosoprz48p92pYP8OdQc70H5hZt53hoYNgYFSd+MU6H1 + hJCaXTsiP4IUmBjiwzSp3o1ctP8lWvnyJpAadYdDhaDaAAoaMjCo9cm5OMwc8t8x + hwAPXV2cgWH8fPcT9NLAcwWk + -----END PRIVATE KEY----- + snis: + - name: demo1.example.com + - name: demo2.example.com + - name: demo3.example.com + tags: + - cloudops-managed +consumers: +- acls: + - group: foo-group + hmacauth_credentials: + - secret: yeNZBeqCuk0D3H85VX77Umacf91MwqRo + username: hmac-user + jwt_secrets: + - algorithm: HS256 + key: MKWeR0nu9OAUR9HrjpUG82Hbfz7ZXsIw + secret: 6gkrxTKAraykMSpmnLNEGiEE3Yz8XL6U + keyauth_credentials: + - key: iwb6Djkk4HhUlOCmLilDIKh6nZrn90ts + username: harry +plugins: +- config: + bandwidth_metrics: false + latency_metrics: false + per_consumer: false + status_code_metrics: false + upstream_health_metrics: false + enabled: true + name: prometheus + protocols: + - http + - https +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + name: r1 + path_handling: v0 + paths: + - /r1 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + tags: + - team-svc1 + write_timeout: 60000 +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc2 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + name: r2 + path_handling: v0 + paths: + - /r2 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + write_timeout: 60000 +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc3 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + methods: + - GET + name: r3 + path_handling: v0 + paths: + - /r3 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + write_timeout: 60000 +upstreams: +- algorithm: round-robin + hash_fallback: none + hash_on: none + hash_on_cookie_path: / + healthchecks: + active: + concurrency: 10 + healthy: + http_statuses: + - 200 + - 302 + interval: 0 + successes: 0 + http_path: / + https_verify_certificate: true + timeout: 1 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 404 + - 500 + - 501 + - 502 + - 503 + - 504 + - 505 + interval: 0 + tcp_failures: 0 + timeouts: 0 + passive: + healthy: + http_statuses: + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 226 + - 300 + - 301 + - 302 + - 303 + - 304 + - 305 + - 306 + - 307 + - 308 + successes: 0 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 500 + - 503 + tcp_failures: 0 + timeouts: 0 + threshold: 0 + name: upstream1 + slots: 10000 + targets: + - target: 198.51.100.11:80 + weight: 100 + - target: 198.51.100.12:80 + weight: 100 + - target: 198.51.100.13:80 + weight: 100 diff --git a/tests/integration/testdata/dump/001-entities-with-tags/kong.yaml b/tests/integration/testdata/dump/001-entities-with-tags/kong.yaml new file mode 100644 index 0000000..8eb58d1 --- /dev/null +++ b/tests/integration/testdata/dump/001-entities-with-tags/kong.yaml @@ -0,0 +1,288 @@ +_format_version: "3.0" +certificates: +- cert: | + -----BEGIN CERTIFICATE----- + MIIC1jCCAb4CCQCt23nwvxSCvjANBgkqhkiG9w0BAQsFADAtMRYwFAYDVQQDDA0q + LmV4YW1wbGUuY29tMRMwEQYDVQQKDAprb25naHEub3JnMB4XDTE4MTIzMTIwMTkw + MVoXDTE5MTIzMTIwMTkwMVowLTEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTETMBEG + A1UECgwKa29uZ2hxLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + AKj/2r1AXo9x+2Csrd0SHbpnzuW+xYqgsd+YA9ZrZNV7SZGSbaZymsRMz8wg5OIU + iUik2GM1749/lYvojLFStBPy9UY/gd++5f3wLp4xHiI+IU2XQ97otXKGfyh36RmN + dKDqPLN8BG3R346s/y1GOulFvLthYmZVYF9ufHiqimfEDSbTt79P5C3X0Rw/afK1 + GjHEJPCB/XkZ6lkcEyL6LqZI5oBigDqa9hI/nWLxEzfm8pgosiS38p9TAijlOkpm + tX2p2b1pktlNIy3rxsqj6IynN9Wc7FpV1N4HoPKV7vQQ08hjwW6WfanVthaaJosj + Vr2TBCJ1ltAmsb+5B2VPYVkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnByTyQfV + 3LkwuoWS57CWcqbNw/cHnv/ChzmIv+6mIXvDBSvCgrPZIWCpaCfYRG6R51E44fr/ + 8V1AKT0Zt15DjrXEEcIGQgsIDO91/wlL091fTAUzSbL0yt7HTlm8sX6xndPNAZrq + cfcIPVMxknfqPy2VqS4IrNC03pHkDKtokphBjVUlkiWsdcq+fHYbS2xL2d1Da/uN + hX/iwgo+v5gOF5xtaXx7D7L3Cf+MHb/MOXWPfYXNiTpSBVX8/Kx5RP+QLI16nWvw + lrijTlXZFR8NIZBrCo/QZ2cNbUAbN3R0n+/kMFubxBL8WEm6Qhi9jBjbJeDMspd8 + C+/TZJQMpx5vyA== + -----END CERTIFICATE----- + id: 13c562a1-191c-4464-9b18-e5222b46035b + key: | + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo/9q9QF6Pcftg + rK3dEh26Z87lvsWKoLHfmAPWa2TVe0mRkm2mcprETM/MIOTiFIlIpNhjNe+Pf5WL + 6IyxUrQT8vVGP4HfvuX98C6eMR4iPiFNl0Pe6LVyhn8od+kZjXSg6jyzfARt0d+O + rP8tRjrpRby7YWJmVWBfbnx4qopnxA0m07e/T+Qt19EcP2nytRoxxCTwgf15GepZ + HBMi+i6mSOaAYoA6mvYSP51i8RM35vKYKLIkt/KfUwIo5TpKZrV9qdm9aZLZTSMt + 68bKo+iMpzfVnOxaVdTeB6Dyle70ENPIY8Fuln2p1bYWmiaLI1a9kwQidZbQJrG/ + uQdlT2FZAgMBAAECggEAVnyRcda2Tcy0K7ZTR9aUlie370VhDN/OB7JhDGNreAEf + FjuMl+kAoUL5+OpAmB6QXzfVcXhRv+s4GiCJl9nORINK2Id5rIqiYwF+qgBS/o0z + N+UYm8QVz6Va/9fV1/jXXd5h8Cygi58jPH32HTJaxbSlsHNXCy3YIx6E3q/QIueR + 6ZdSXPqMEqxEU19M9jW8UeiRFrpmcyYxVpfxYIY/+O9lYjSpaeLs7hZeCP9PqWXA + Sxz2CnHZ8BcsDxAyuoHoVw+kjMpUMvA3sD4lwkV8BAYzfLmQf6PR83SFNsrE8XYu + /8WnQuCuytcl8Zg55R6tGCvf6Wyyf+MDRPwv/43QMQKBgQDbqK9Dq54k+EHgSNnP + K6AhNjFd6aqcNC1kom/sSlWBnuA/BEqJMECr8S2dYvzONUPPfX5NNUjB4Vw3Qw7a + pUgKuCQoVpzpZs5m1bk78itWDtA84LjkXfdejnUXVw/aVxLCM5QV9aEkm/dEWWMI + P1WTYVoWoZCLlEE08q0AvZQcdQKBgQDE9ZCmc6ncmhnQftuRj5PnXG2a79MLCT61 + sCEBDVvkcUJVqbzwGRLwRkdIzLgvmiuP+SukHgyfr8/RXG99xEW/q7NDrtEcqfXP + 19QXwOIp5NwDnOXyAlXiyZ50fCE2tSo2wP485+NIhmKj5Zt6y/DL6Qbc5k73XmK4 + KX5Ej15k1QKBgQCc6KeiIFLMt+Ze78tfORue/dZP7p3oDUGr1Hk9AnCIMlSfz1Hr + I+Per17VQaOzLcttyYhSYNDDZld4RlezCkQnHBkAE7bs53pjbSJv1vLr+5L3GdQZ + laIiEoNEE/YIExEcVrne4eKlgyAj2/JpLszThcRTzD+z5UibKQs6LzJBDQKBgDVa + dAGzCUt57w48nwvyQdWFgydaWef+bB9Zg8c+MCtUxuxfm4/Kqwetcff1hNtYPv60 + N68weKj1Pi1vhcAi3+YJA/mMrJbAL5dK1uhMVreUiEjuQpfpLAzQIv1Y9sJUFwhY + BUbIZhgqVyQguZptDmCeUj6aoL9/sOxESTEXSTG1AoGBAMQ5iJZMsdLCERv0+6Y1 + F/t/YSW8cugB3vdV9jHZuosoprz48p92pYP8OdQc70H5hZt53hoYNgYFSd+MU6H1 + hJCaXTsiP4IUmBjiwzSp3o1ctP8lWvnyJpAadYdDhaDaAAoaMjCo9cm5OMwc8t8x + hwAPXV2cgWH8fPcT9NLAcwWk + -----END PRIVATE KEY----- + snis: + - name: demo1.example.com + tags: + - managed-by-deck + - org-unit-42 + - name: demo2.example.com + tags: + - managed-by-deck + - org-unit-42 + - name: demo3.example.com + tags: + - managed-by-deck + - org-unit-42 + tags: + - cloudops-managed + - managed-by-deck + - org-unit-42 +consumers: +- acls: + - group: foo-group + tags: + - managed-by-deck + - org-unit-42 + hmacauth_credentials: + - secret: yeNZBeqCuk0D3H85VX77Umacf91MwqRo + tags: + - managed-by-deck + - org-unit-42 + username: hmac-user + jwt_secrets: + - algorithm: HS256 + key: MKWeR0nu9OAUR9HrjpUG82Hbfz7ZXsIw + secret: 6gkrxTKAraykMSpmnLNEGiEE3Yz8XL6U + tags: + - managed-by-deck + - org-unit-42 + keyauth_credentials: + - key: iwb6Djkk4HhUlOCmLilDIKh6nZrn90ts + tags: + - managed-by-deck + - org-unit-42 + tags: + - managed-by-deck + - org-unit-42 + username: harry +plugins: +- config: + bandwidth_metrics: false + latency_metrics: false + per_consumer: false + status_code_metrics: false + upstream_health_metrics: false + enabled: true + name: prometheus + protocols: + - http + - https + tags: + - managed-by-deck + - org-unit-42 +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + name: r1 + path_handling: v0 + paths: + - /r1 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + tags: + - managed-by-deck + - org-unit-42 + tags: + - team-svc1 + - managed-by-deck + - org-unit-42 + write_timeout: 60000 +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc2 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + name: r2 + path_handling: v0 + paths: + - /r2 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + tags: + - managed-by-deck + - org-unit-42 + tags: + - managed-by-deck + - org-unit-42 + write_timeout: 60000 +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc3 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - https_redirect_status_code: 301 + methods: + - GET + name: r3 + path_handling: v0 + paths: + - /r3 + preserve_host: false + protocols: + - http + - https + regex_priority: 0 + request_buffering: true + response_buffering: true + strip_path: true + tags: + - managed-by-deck + - org-unit-42 + tags: + - managed-by-deck + - org-unit-42 + write_timeout: 60000 +upstreams: +- algorithm: round-robin + hash_fallback: none + hash_on: none + hash_on_cookie_path: / + healthchecks: + active: + concurrency: 10 + healthy: + http_statuses: + - 200 + - 302 + interval: 0 + successes: 0 + http_path: / + https_verify_certificate: true + timeout: 1 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 404 + - 500 + - 501 + - 502 + - 503 + - 504 + - 505 + interval: 0 + tcp_failures: 0 + timeouts: 0 + passive: + healthy: + http_statuses: + - 200 + - 201 + - 202 + - 203 + - 204 + - 205 + - 206 + - 207 + - 208 + - 226 + - 300 + - 301 + - 302 + - 303 + - 304 + - 305 + - 306 + - 307 + - 308 + successes: 0 + type: http + unhealthy: + http_failures: 0 + http_statuses: + - 429 + - 500 + - 503 + tcp_failures: 0 + timeouts: 0 + threshold: 0 + name: upstream1 + slots: 10000 + tags: + - managed-by-deck + - org-unit-42 + targets: + - tags: + - managed-by-deck + - org-unit-42 + target: 198.51.100.11:80 + weight: 100 + - tags: + - managed-by-deck + - org-unit-42 + target: 198.51.100.12:80 + weight: 100 + - tags: + - managed-by-deck + - org-unit-42 + target: 198.51.100.13:80 + weight: 100 diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-34.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-34.yaml new file mode 100644 index 0000000..ee591de --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-34.yaml @@ -0,0 +1,60 @@ +_format_version: "3.0" +consumer_groups: +- name: basic + plugins: + - config: + consumer_groups: null + dictionary_name: kong_rate_limiting_counters + disable_penalty: false + enforce_consumer_groups: false + error_code: 429 + error_message: API rate limit exceeded + header_name: null + hide_client_headers: false + identifier: consumer + limit: + - 30000 + namespace: basic + path: null + redis: + cluster_addresses: null + connect_timeout: null + database: 0 + host: null + keepalive_backlog: null + keepalive_pool_size: 30 + password: null + port: null + read_timeout: null + send_timeout: null + sentinel_addresses: null + sentinel_master: null + sentinel_password: null + sentinel_role: null + sentinel_username: null + server_name: null + ssl: false + ssl_verify: false + timeout: 2000 + username: null + retry_after_jitter_max: 0 + strategy: local + sync_rate: -1 + window_size: + - 2628000 + window_type: sliding + name: rate-limiting-advanced +consumers: +- groups: + - name: basic + username: foo +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-35.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-35.yaml new file mode 100644 index 0000000..86cd73d --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip-35.yaml @@ -0,0 +1,60 @@ +_format_version: "3.0" +consumer_groups: +- name: basic + plugins: + - config: + consumer_groups: null + dictionary_name: kong_rate_limiting_counters + disable_penalty: false + enforce_consumer_groups: false + error_code: 429 + error_message: API rate limit exceeded + header_name: null + hide_client_headers: false + identifier: consumer + limit: + - 30000 + namespace: basic + path: null + redis: + cluster_addresses: null + connect_timeout: null + database: 0 + host: null + keepalive_backlog: null + keepalive_pool_size: 256 + password: null + port: null + read_timeout: null + send_timeout: null + sentinel_addresses: null + sentinel_master: null + sentinel_password: null + sentinel_role: null + sentinel_username: null + server_name: null + ssl: false + ssl_verify: false + timeout: 2000 + username: null + retry_after_jitter_max: 0 + strategy: local + sync_rate: -1 + window_size: + - 2628000 + window_type: sliding + name: rate-limiting-advanced +consumers: +- groups: + - name: basic + username: foo +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip.yaml new file mode 100644 index 0000000..6fd4326 --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip.yaml @@ -0,0 +1,26 @@ +_format_version: "3.0" +consumer_groups: +- name: basic + plugins: + - config: + limit: + - 30000 + retry_after_jitter_max: 0 + window_size: + - 2628000 + window_type: sliding + name: rate-limiting-advanced +consumers: +- groups: + - name: basic + username: foo +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml new file mode 100644 index 0000000..82903df --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/expected-no-skip_konnect.yaml @@ -0,0 +1,62 @@ +_format_version: "3.0" +_konnect: + control_plane_name: default +consumer_groups: +- name: basic + plugins: + - config: + consumer_groups: null + dictionary_name: kong_rate_limiting_counters + disable_penalty: false + enforce_consumer_groups: false + error_code: 429 + error_message: API rate limit exceeded + header_name: null + hide_client_headers: false + identifier: consumer + limit: + - 30000 + namespace: basic + path: null + redis: + cluster_addresses: null + connect_timeout: null + database: 0 + host: null + keepalive_backlog: null + keepalive_pool_size: 256 + password: null + port: null + read_timeout: null + send_timeout: null + sentinel_addresses: null + sentinel_master: null + sentinel_password: null + sentinel_role: null + sentinel_username: null + server_name: null + ssl: false + ssl_verify: false + timeout: 2000 + username: null + retry_after_jitter_max: 0 + strategy: local + sync_rate: null + window_size: + - 2628000 + window_type: sliding + name: rate-limiting-advanced +consumers: +- groups: + - name: basic + username: foo +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected.yaml new file mode 100644 index 0000000..20b786b --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/expected.yaml @@ -0,0 +1,11 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/dump/002-skip-consumers/expected_konnect.yaml b/tests/integration/testdata/dump/002-skip-consumers/expected_konnect.yaml new file mode 100644 index 0000000..c81f858 --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/expected_konnect.yaml @@ -0,0 +1,13 @@ +_format_version: "3.0" +_konnect: + control_plane_name: default +services: +- connect_timeout: 60000 + enabled: true + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/dump/002-skip-consumers/kong.yaml b/tests/integration/testdata/dump/002-skip-consumers/kong.yaml new file mode 100644 index 0000000..6f6b1fa --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/kong.yaml @@ -0,0 +1,18 @@ +_format_version: "3.0" +consumer_groups: +- name: basic + plugins: + - config: + limit: + - 30000 + window_size: + - 2628000 + window_type: sliding + name: rate-limiting-advanced +consumers: + - username: foo + groups: + - name: basic +services: +- name: svc1 + host: mockbin.org diff --git a/tests/integration/testdata/dump/002-skip-consumers/kong34.yaml b/tests/integration/testdata/dump/002-skip-consumers/kong34.yaml new file mode 100644 index 0000000..5a04f75 --- /dev/null +++ b/tests/integration/testdata/dump/002-skip-consumers/kong34.yaml @@ -0,0 +1,19 @@ +_format_version: "3.0" +consumer_groups: +- name: basic + plugins: + - config: + limit: + - 30000 + window_size: + - 2628000 + window_type: sliding + namespace: basic + name: rate-limiting-advanced +consumers: + - username: foo + groups: + - name: basic +services: +- name: svc1 + host: mockbin.org \ No newline at end of file diff --git a/tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.json b/tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.json new file mode 100644 index 0000000..35945b2 --- /dev/null +++ b/tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.json @@ -0,0 +1,14 @@ +{ + "fail_count": 1, + "results": [ + { + "Message": "Check the version is correct: `3.0` does not match the expression `^1.1$`", + "Severity": "error", + "Line": 1, + "Column": 18, + "Character": 0, + "Path": "$._format_version" + } + ], + "total_count": 1 + } \ No newline at end of file diff --git a/tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.yaml b/tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.yaml new file mode 100644 index 0000000..87860c4 --- /dev/null +++ b/tests/integration/testdata/lint/001-simple-lint/expected-fail-severity-error.yaml @@ -0,0 +1,9 @@ +fail_count: 1 +results: +- Character: 0 + Column: 18 + Line: 1 + Message: 'Check the version is correct: `3.0` does not match the expression `^1.1$`' + Path: $._format_version + Severity: error +total_count: 1 \ No newline at end of file diff --git a/tests/integration/testdata/lint/001-simple-lint/expected.json b/tests/integration/testdata/lint/001-simple-lint/expected.json new file mode 100644 index 0000000..2ef8730 --- /dev/null +++ b/tests/integration/testdata/lint/001-simple-lint/expected.json @@ -0,0 +1,22 @@ +{ + "fail_count": 1, + "results": [ + { + "Message": "Check the version is correct: `3.0` does not match the expression `^1.1$`", + "Severity": "error", + "Line": 1, + "Column": 18, + "Character": 0, + "Path": "$._format_version" + }, + { + "Message": "Must use HTTPS protocol: `http` does not match the expression `^https`", + "Severity": "warn", + "Line": 5, + "Column": 13, + "Character": 0, + "Path": "$.services[*].protocol" + } + ], + "total_count": 2 + } \ No newline at end of file diff --git a/tests/integration/testdata/lint/001-simple-lint/expected.yaml b/tests/integration/testdata/lint/001-simple-lint/expected.yaml new file mode 100644 index 0000000..1f127eb --- /dev/null +++ b/tests/integration/testdata/lint/001-simple-lint/expected.yaml @@ -0,0 +1,15 @@ +fail_count: 1 +results: +- Character: 0 + Column: 18 + Line: 1 + Message: 'Check the version is correct: `3.0` does not match the expression `^1.1$`' + Path: $._format_version + Severity: error +- Character: 0 + Column: 13 + Line: 5 + Message: 'Must use HTTPS protocol: `http` does not match the expression `^https`' + Path: $.services[*].protocol + Severity: warn +total_count: 2 diff --git a/tests/integration/testdata/lint/001-simple-lint/kong.yaml b/tests/integration/testdata/lint/001-simple-lint/kong.yaml new file mode 100644 index 0000000..13b1ca9 --- /dev/null +++ b/tests/integration/testdata/lint/001-simple-lint/kong.yaml @@ -0,0 +1,9 @@ +_format_version: "3.0" +services: +- name: svc1 + host: mockbin.org + protocol: http + routes: + - name: r1 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/lint/001-simple-lint/ruleset.yaml b/tests/integration/testdata/lint/001-simple-lint/ruleset.yaml new file mode 100644 index 0000000..e437aca --- /dev/null +++ b/tests/integration/testdata/lint/001-simple-lint/ruleset.yaml @@ -0,0 +1,17 @@ +rules: + version-30: + description: "Check the version is correct" + given: $._format_version + severity: error + then: + function: pattern + functionOptions: + match: "^1.1$" + https-only: + description: "Must use HTTPS protocol" + given: $.services[*].protocol + severity: warn + then: + function: pattern + functionOptions: + match: "^https" \ No newline at end of file diff --git a/tests/integration/testdata/reset/001-skip-ca-cert/kong.yaml b/tests/integration/testdata/reset/001-skip-ca-cert/kong.yaml new file mode 100644 index 0000000..0f407f8 --- /dev/null +++ b/tests/integration/testdata/reset/001-skip-ca-cert/kong.yaml @@ -0,0 +1,35 @@ +ca_certificates: +- cert: |- + -----BEGIN CERTIFICATE----- + MIIDkzCCAnugAwIBAgIUYGc07pbHSjOBPreXh7OcNT2+sD4wDQYJKoZIhvcNAQEL + BQAwWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIs + IEluYy4xJjAkBgNVBAMMHVlvbG80MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMB4X + DTIyMDMyOTE5NDczM1oXDTMyMDMyNjE5NDczM1owWTELMAkGA1UEBhMCVVMxCzAJ + BgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIsIEluYy4xJjAkBgNVBAMMHVlvbG80 + MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A + MIIBCgKCAQEAvnhTgdJALnuLKDA0ZUZRVMqcaaC+qvfJkiEFGYwX2ZJiFtzU65F/ + sB2L0ToFqY4tmMVlOmiSZFnRLDZecmQDbbNwc3wtNikmxIOzx4qR4kbRP8DDdyIf + gaNmGCuaXTM5+FYy2iNBn6CeibIjqdErQlAbFLwQs5t3mLsjii2U4cyvfRtO+0RV + HdJ6Np5LsVziN0c5gVIesIrrbxLcOjtXDzwd/w/j5NXqL/OwD5EBH2vqd3QKKX4t + s83BLl2EsbUse47VAImavrwDhmV6S/p/NuJHqjJ6dIbXLYxNS7g26ijcrXxvNhiu + YoZTykSgdI3BXMNAm1ahP/BtJPZpU7CVdQIDAQABo1MwUTAdBgNVHQ4EFgQUe1WZ + fMfZQ9QIJIttwTmcrnl40ccwHwYDVR0jBBgwFoAUe1WZfMfZQ9QIJIttwTmcrnl4 + 0ccwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAs4Z8VYbvEs93 + haTHdbbaKk0V6xAL/Q8I8GitK9E8cgf8C5rwwn+wU/Gf39dtMUlnW8uxyzRPx53u + CAAcJAWkabT+xwrlrqjO68H3MgIAwgWA5yZC+qW7ECA8xYEK6DzEHIaOpagJdKcL + IaZr/qTJlEQClvwDs4x/BpHRB5XbmJs86GqEB7XWAm+T2L8DluHAXvek+welF4Xo + fQtLlNS/vqTDqPxkSbJhFv1L7/4gdwfAz51wH/iL7AG/ubFEtoGZPK9YCJ40yTWz + 8XrUoqUC+2WIZdtmo6dFFJcLfQg4ARJZjaK6lmxJun3iRMZjKJdQKm/NEKz4y9kA + u8S6yNlu2Q== + -----END CERTIFICATE----- + cert_digest: 34e0f1f3d83faefcc8514b6295bc822eab1110dc120140ddf342c017baee8c0f + id: b824e7c0-d116-4c03-9e27-de05c5d30083 +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 \ No newline at end of file diff --git a/tests/integration/testdata/reset/001-skip-ca-cert/kong3x.yaml b/tests/integration/testdata/reset/001-skip-ca-cert/kong3x.yaml new file mode 100644 index 0000000..30f8ca7 --- /dev/null +++ b/tests/integration/testdata/reset/001-skip-ca-cert/kong3x.yaml @@ -0,0 +1,36 @@ +_format_version: "3.0" +ca_certificates: +- cert: |- + -----BEGIN CERTIFICATE----- + MIIDkzCCAnugAwIBAgIUYGc07pbHSjOBPreXh7OcNT2+sD4wDQYJKoZIhvcNAQEL + BQAwWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIs + IEluYy4xJjAkBgNVBAMMHVlvbG80MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMB4X + DTIyMDMyOTE5NDczM1oXDTMyMDMyNjE5NDczM1owWTELMAkGA1UEBhMCVVMxCzAJ + BgNVBAgMAkNBMRUwEwYDVQQKDAxZb2xvNDIsIEluYy4xJjAkBgNVBAMMHVlvbG80 + MiBzZWxmLXNpZ25lZCB0ZXN0aW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A + MIIBCgKCAQEAvnhTgdJALnuLKDA0ZUZRVMqcaaC+qvfJkiEFGYwX2ZJiFtzU65F/ + sB2L0ToFqY4tmMVlOmiSZFnRLDZecmQDbbNwc3wtNikmxIOzx4qR4kbRP8DDdyIf + gaNmGCuaXTM5+FYy2iNBn6CeibIjqdErQlAbFLwQs5t3mLsjii2U4cyvfRtO+0RV + HdJ6Np5LsVziN0c5gVIesIrrbxLcOjtXDzwd/w/j5NXqL/OwD5EBH2vqd3QKKX4t + s83BLl2EsbUse47VAImavrwDhmV6S/p/NuJHqjJ6dIbXLYxNS7g26ijcrXxvNhiu + YoZTykSgdI3BXMNAm1ahP/BtJPZpU7CVdQIDAQABo1MwUTAdBgNVHQ4EFgQUe1WZ + fMfZQ9QIJIttwTmcrnl40ccwHwYDVR0jBBgwFoAUe1WZfMfZQ9QIJIttwTmcrnl4 + 0ccwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAs4Z8VYbvEs93 + haTHdbbaKk0V6xAL/Q8I8GitK9E8cgf8C5rwwn+wU/Gf39dtMUlnW8uxyzRPx53u + CAAcJAWkabT+xwrlrqjO68H3MgIAwgWA5yZC+qW7ECA8xYEK6DzEHIaOpagJdKcL + IaZr/qTJlEQClvwDs4x/BpHRB5XbmJs86GqEB7XWAm+T2L8DluHAXvek+welF4Xo + fQtLlNS/vqTDqPxkSbJhFv1L7/4gdwfAz51wH/iL7AG/ubFEtoGZPK9YCJ40yTWz + 8XrUoqUC+2WIZdtmo6dFFJcLfQg4ARJZjaK6lmxJun3iRMZjKJdQKm/NEKz4y9kA + u8S6yNlu2Q== + -----END CERTIFICATE----- + cert_digest: 34e0f1f3d83faefcc8514b6295bc822eab1110dc120140ddf342c017baee8c0f + id: b824e7c0-d116-4c03-9e27-de05c5d30083 +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/001-create-a-service/kong.yaml b/tests/integration/testdata/sync/001-create-a-service/kong.yaml new file mode 100644 index 0000000..398199a --- /dev/null +++ b/tests/integration/testdata/sync/001-create-a-service/kong.yaml @@ -0,0 +1,10 @@ +_format_version: "1.1" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 \ No newline at end of file diff --git a/tests/integration/testdata/sync/001-create-a-service/kong3x.yaml b/tests/integration/testdata/sync/001-create-a-service/kong3x.yaml new file mode 100644 index 0000000..747af52 --- /dev/null +++ b/tests/integration/testdata/sync/001-create-a-service/kong3x.yaml @@ -0,0 +1,10 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml b/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml new file mode 100644 index 0000000..da79fdf --- /dev/null +++ b/tests/integration/testdata/sync/002-create-services-and-routes/kong.yaml @@ -0,0 +1,16 @@ +_format_version: "1.1" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 \ No newline at end of file diff --git a/tests/integration/testdata/sync/002-create-services-and-routes/kong3x.yaml b/tests/integration/testdata/sync/002-create-services-and-routes/kong3x.yaml new file mode 100644 index 0000000..a6ff52d --- /dev/null +++ b/tests/integration/testdata/sync/002-create-services-and-routes/kong3x.yaml @@ -0,0 +1,16 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 diff --git a/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml b/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml new file mode 100644 index 0000000..cd66122 --- /dev/null +++ b/tests/integration/testdata/sync/003-create-a-plugin/kong.yaml @@ -0,0 +1,13 @@ +_format_version: "1.1" +plugins: +- id: efead952-0a1d-43ec-9794-0ac6abdc7f55 + name: basic-auth + config: + anonymous: 58076db2-28b6-423b-ba39-a797193017f7 + hide_credentials: false + enabled: true + protocols: + - grpc + - grpcs + - http + - https \ No newline at end of file diff --git a/tests/integration/testdata/sync/003-create-a-plugin/kong3x.yaml b/tests/integration/testdata/sync/003-create-a-plugin/kong3x.yaml new file mode 100644 index 0000000..5b4f520 --- /dev/null +++ b/tests/integration/testdata/sync/003-create-a-plugin/kong3x.yaml @@ -0,0 +1,13 @@ +_format_version: "3.0" +plugins: +- id: efead952-0a1d-43ec-9794-0ac6abdc7f55 + name: basic-auth + config: + anonymous: 58076db2-28b6-423b-ba39-a797193017f7 + hide_credentials: false + enabled: true + protocols: + - grpc + - grpcs + - http + - https diff --git a/tests/integration/testdata/sync/004-create-upstream-and-target/kong.yaml b/tests/integration/testdata/sync/004-create-upstream-and-target/kong.yaml new file mode 100644 index 0000000..32f0086 --- /dev/null +++ b/tests/integration/testdata/sync/004-create-upstream-and-target/kong.yaml @@ -0,0 +1,5 @@ +upstreams: +- name: upstream1 + algorithm: round-robin + targets: + - target: 198.51.100.11:80 \ No newline at end of file diff --git a/tests/integration/testdata/sync/004-create-upstream-and-target/kong3x.yaml b/tests/integration/testdata/sync/004-create-upstream-and-target/kong3x.yaml new file mode 100644 index 0000000..d344bf4 --- /dev/null +++ b/tests/integration/testdata/sync/004-create-upstream-and-target/kong3x.yaml @@ -0,0 +1,6 @@ +_format_version: "3.0" +upstreams: +- name: upstream1 + algorithm: round-robin + targets: + - target: 198.51.100.11:80 diff --git a/tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong.yaml b/tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong.yaml new file mode 100644 index 0000000..3a2fd77 --- /dev/null +++ b/tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong.yaml @@ -0,0 +1,6 @@ +upstreams: +- name: upstream1 + algorithm: round-robin + targets: + - target: 198.51.100.11:80 + weight: 0 \ No newline at end of file diff --git a/tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml b/tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml new file mode 100644 index 0000000..ace50b3 --- /dev/null +++ b/tests/integration/testdata/sync/005-create-upstream-and-target-weight/kong3x.yaml @@ -0,0 +1,7 @@ +_format_version: "3.0" +upstreams: +- name: upstream1 + algorithm: round-robin + targets: + - target: 198.51.100.11:80 + weight: 0 diff --git a/tests/integration/testdata/sync/006-fill-defaults-rate-limiting/kong.yaml b/tests/integration/testdata/sync/006-fill-defaults-rate-limiting/kong.yaml new file mode 100644 index 0000000..2b1b021 --- /dev/null +++ b/tests/integration/testdata/sync/006-fill-defaults-rate-limiting/kong.yaml @@ -0,0 +1,4 @@ +plugins: + - name: rate-limiting + config: + minute: 123 diff --git a/tests/integration/testdata/sync/007-fill-defaults-rate-limiting-dedup/kong.yaml b/tests/integration/testdata/sync/007-fill-defaults-rate-limiting-dedup/kong.yaml new file mode 100644 index 0000000..7c5b687 --- /dev/null +++ b/tests/integration/testdata/sync/007-fill-defaults-rate-limiting-dedup/kong.yaml @@ -0,0 +1,7 @@ +_plugin_configs: + rate-limiting-one: + minute: 123 + +plugins: + - name: rate-limiting + _config: rate-limiting-one diff --git a/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml b/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml new file mode 100644 index 0000000..bae23a3 --- /dev/null +++ b/tests/integration/testdata/sync/008-create-simple-entities/kong.yaml @@ -0,0 +1,19 @@ +_format_version: "1.1" +services: +- id: 58076db2-28b6-423b-ba39-a797193017f7 + name: svc1 + host: mockbin.org + routes: + - id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + https_redirect_status_code: 301 + paths: + - /r1 +upstreams: +- name: upstream1 + targets: + - target: 198.51.100.11:80 +plugins: +- name: basic-auth + config: + anonymous: 58076db2-28b6-423b-ba39-a797193017f7 \ No newline at end of file diff --git a/tests/integration/testdata/sync/009-skip-ca-cert/kong.yaml b/tests/integration/testdata/sync/009-skip-ca-cert/kong.yaml new file mode 100644 index 0000000..17b662c --- /dev/null +++ b/tests/integration/testdata/sync/009-skip-ca-cert/kong.yaml @@ -0,0 +1,30 @@ +ca_certificates: +- cert: |- + -----BEGIN CERTIFICATE----- + MIICvDCCAaSgAwIBAgIJAID17vZt1yWyMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV + BAMMCEhlbGxvTmV3MB4XDTIyMDMxNTE5MTgzOVoXDTIyMDQxNDE5MTgzOVowEzER + MA8GA1UEAwwISGVsbG9OZXcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB + AQDL1l6EB2rDPjKDoJX52VsnO8bdKnoGq2s5Er7piVQjYBA6U7NzEJwvsaL9uG1p + /OFud8uwJFCm0NF1DxkNA+qpUvaBXBnn4htbXE20C7HwAWCUU0TUWgTpGYC0EkGZ + VlbXoQ1SewK+AERjdBKqa0U9Wk0gkD0kVc2UfO7rxU7w6nkoFPgBI1IlJZXM5TVg + 1AeJDrdgUSa/fsja5qOYVcwGiUgqMr3nMs1jBJRgwhC0ELF1lFaANouqPC4KweLE + FNgam69AZallFNZOKVh6vJLKBfE9I8TM5yBpRllhKAaUv1qWlPFYxoIPvnFzQPku + ExGbYR6asSXwq6UHxREIOno1AgMBAAGjEzARMA8GA1UdEwQIMAYBAf8CAQAwDQYJ + KoZIhvcNAQELBQADggEBAHXc6lc6BGzdjwWX8XViBxY1NnK5HxNfD+rP7/JJ4m33 + zoTteY+KRcKo6t49TDqfpnVfCGunnoGOFP5ATY29vUavigICw7SGGLKWIM38c0bH + bx14/d/LQd2LaNd/cemTDkF3XJi3OdrGJPNOVLfX0InqbmwBzariWCwzufwHGxwR + WpOh8Qv2kFPuFVwlQNPNMhV7qsa/NM77Wo4Q6kA5V3aYSnF+KbWF3by/SqUC5JMz + cbvPj0Yzt97v7FpOILcDcMWjxuUnvuUYvGuB5tzBEe91s3ZTUK0A5moYOYkTHUlX + 9CkGSwFE+jBTxUBPKzm3MVoK2cGoX8gEpzcYSwjM8Ws= + -----END CERTIFICATE----- + cert_digest: b865971cecadd7bac9487901c9269c1fa903b3a3b521a927c5e2513f692ac61e + id: b824e7c0-d116-4c03-9e27-de05c5d30083 +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 \ No newline at end of file diff --git a/tests/integration/testdata/sync/009-skip-ca-cert/kong3x.yaml b/tests/integration/testdata/sync/009-skip-ca-cert/kong3x.yaml new file mode 100644 index 0000000..ec130f1 --- /dev/null +++ b/tests/integration/testdata/sync/009-skip-ca-cert/kong3x.yaml @@ -0,0 +1,31 @@ +_format_version: "3.0" +ca_certificates: +- cert: |- + -----BEGIN CERTIFICATE----- + MIICvDCCAaSgAwIBAgIJAID17vZt1yWyMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV + BAMMCEhlbGxvTmV3MB4XDTIyMDMxNTE5MTgzOVoXDTIyMDQxNDE5MTgzOVowEzER + MA8GA1UEAwwISGVsbG9OZXcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB + AQDL1l6EB2rDPjKDoJX52VsnO8bdKnoGq2s5Er7piVQjYBA6U7NzEJwvsaL9uG1p + /OFud8uwJFCm0NF1DxkNA+qpUvaBXBnn4htbXE20C7HwAWCUU0TUWgTpGYC0EkGZ + VlbXoQ1SewK+AERjdBKqa0U9Wk0gkD0kVc2UfO7rxU7w6nkoFPgBI1IlJZXM5TVg + 1AeJDrdgUSa/fsja5qOYVcwGiUgqMr3nMs1jBJRgwhC0ELF1lFaANouqPC4KweLE + FNgam69AZallFNZOKVh6vJLKBfE9I8TM5yBpRllhKAaUv1qWlPFYxoIPvnFzQPku + ExGbYR6asSXwq6UHxREIOno1AgMBAAGjEzARMA8GA1UdEwQIMAYBAf8CAQAwDQYJ + KoZIhvcNAQELBQADggEBAHXc6lc6BGzdjwWX8XViBxY1NnK5HxNfD+rP7/JJ4m33 + zoTteY+KRcKo6t49TDqfpnVfCGunnoGOFP5ATY29vUavigICw7SGGLKWIM38c0bH + bx14/d/LQd2LaNd/cemTDkF3XJi3OdrGJPNOVLfX0InqbmwBzariWCwzufwHGxwR + WpOh8Qv2kFPuFVwlQNPNMhV7qsa/NM77Wo4Q6kA5V3aYSnF+KbWF3by/SqUC5JMz + cbvPj0Yzt97v7FpOILcDcMWjxuUnvuUYvGuB5tzBEe91s3ZTUK0A5moYOYkTHUlX + 9CkGSwFE+jBTxUBPKzm3MVoK2cGoX8gEpzcYSwjM8Ws= + -----END CERTIFICATE----- + cert_digest: b865971cecadd7bac9487901c9269c1fa903b3a3b521a927c5e2513f692ac61e + id: b824e7c0-d116-4c03-9e27-de05c5d30083 +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml b/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml new file mode 100644 index 0000000..70d332a --- /dev/null +++ b/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong.yaml @@ -0,0 +1,18 @@ +_format_version: "1.1" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 +routes: +- id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + https_redirect_status_code: 301 + paths: + - /r1 + service: + name: svc1 \ No newline at end of file diff --git a/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong3x.yaml b/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong3x.yaml new file mode 100644 index 0000000..0cf0a2e --- /dev/null +++ b/tests/integration/testdata/sync/010-create-route-with-service-name-reference/kong3x.yaml @@ -0,0 +1,18 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 +routes: +- id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + https_redirect_status_code: 301 + paths: + - /r1 + service: + name: svc1 diff --git a/tests/integration/testdata/sync/011-plugin-ordering/kong.yaml b/tests/integration/testdata/sync/011-plugin-ordering/kong.yaml new file mode 100644 index 0000000..f871954 --- /dev/null +++ b/tests/integration/testdata/sync/011-plugin-ordering/kong.yaml @@ -0,0 +1,16 @@ +_format_version: "3.0" +plugins: +- id: efead952-0a1d-43ec-9794-0ac6abdc7f55 + name: request-termination + config: + status_code: 200 + enabled: true + ordering: + before: + access: + - basic-auth + protocols: + - grpc + - grpcs + - http + - https diff --git a/tests/integration/testdata/sync/012-vaults/kong3x.yaml b/tests/integration/testdata/sync/012-vaults/kong3x.yaml new file mode 100644 index 0000000..5e151eb --- /dev/null +++ b/tests/integration/testdata/sync/012-vaults/kong3x.yaml @@ -0,0 +1,24 @@ +_format_version: "3.0" +vaults: +- config: + prefix: MY_SECRET_ + description: ENV vault for secrets + name: env + prefix: my-env-vault +services: +- id: 58076db2-28b6-423b-ba39-a797193017f7 + host: httpbin.org + name: svc1 + path: /status/200 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 +certificates: +- id: 13c562a1-191c-4464-9b18-e5222b46035b + cert: "{vault://my-env-vault/cert}" + key: "{vault://my-env-vault/key}" + snis: + - name: localhost diff --git a/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong-initial.yaml b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong-initial.yaml new file mode 100644 index 0000000..6001ddf --- /dev/null +++ b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong-initial.yaml @@ -0,0 +1,4 @@ +_format_version: "1.1" +consumers: +- custom_id: custom_test + username: test diff --git a/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong.yaml b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong.yaml new file mode 100644 index 0000000..7728e09 --- /dev/null +++ b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong.yaml @@ -0,0 +1,4 @@ +_format_version: "1.1" +consumers: +- custom_id: custom_test + username: test_new diff --git a/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x-initial.yaml b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x-initial.yaml new file mode 100644 index 0000000..e1bd181 --- /dev/null +++ b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x-initial.yaml @@ -0,0 +1,4 @@ +_format_version: "3.0" +consumers: +- custom_id: custom_test + username: test diff --git a/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x.yaml b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x.yaml new file mode 100644 index 0000000..b607c59 --- /dev/null +++ b/tests/integration/testdata/sync/013-update-username-consumer-with-custom-id/kong3x.yaml @@ -0,0 +1,4 @@ +_format_version: "3.0" +consumers: +- custom_id: custom_test + username: test_new diff --git a/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong-initial.yaml b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong-initial.yaml new file mode 100644 index 0000000..6001ddf --- /dev/null +++ b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong-initial.yaml @@ -0,0 +1,4 @@ +_format_version: "1.1" +consumers: +- custom_id: custom_test + username: test diff --git a/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong.yaml b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong.yaml new file mode 100644 index 0000000..bac8b9f --- /dev/null +++ b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong.yaml @@ -0,0 +1,4 @@ +_format_version: "1.1" +consumers: +- custom_id: new_custom_test + username: test diff --git a/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x-initial.yaml b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x-initial.yaml new file mode 100644 index 0000000..22935cf --- /dev/null +++ b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x-initial.yaml @@ -0,0 +1,4 @@ +_format_version: "3.0" +consumers: +- custom_id: test_consumer_3x_custom_intial_test + username: test_consumer_3x diff --git a/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x.yaml b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x.yaml new file mode 100644 index 0000000..8f9e31f --- /dev/null +++ b/tests/integration/testdata/sync/014-update-consumer-with-custom-id/kong3x.yaml @@ -0,0 +1,4 @@ +_format_version: "3.0" +consumers: +- custom_id: test_consumer_3x_custom_test + username: test_consumer_3x diff --git a/tests/integration/testdata/sync/015-consumer-groups/kong.yaml b/tests/integration/testdata/sync/015-consumer-groups/kong.yaml new file mode 100644 index 0000000..3e1bcf3 --- /dev/null +++ b/tests/integration/testdata/sync/015-consumer-groups/kong.yaml @@ -0,0 +1,14 @@ +_format_version: "1.1" +consumer_groups: +- name: silver +- name: gold +consumers: +- username: foo + groups: + - name: gold +- username: bar + groups: + - name: silver +- username: baz + groups: + - name: silver diff --git a/tests/integration/testdata/sync/015-consumer-groups/kong3x-initial.yaml b/tests/integration/testdata/sync/015-consumer-groups/kong3x-initial.yaml new file mode 100644 index 0000000..388eb8f --- /dev/null +++ b/tests/integration/testdata/sync/015-consumer-groups/kong3x-initial.yaml @@ -0,0 +1,18 @@ +_format_version: "3.0" +consumer_groups: +- name: silver + tags: + - tag1 +- name: gold + tags: + - tag1 +consumers: +- username: foo + groups: + - name: gold +- username: bar + groups: + - name: silver +- username: baz + groups: + - name: silver diff --git a/tests/integration/testdata/sync/015-consumer-groups/kong3x.yaml b/tests/integration/testdata/sync/015-consumer-groups/kong3x.yaml new file mode 100644 index 0000000..b50eeac --- /dev/null +++ b/tests/integration/testdata/sync/015-consumer-groups/kong3x.yaml @@ -0,0 +1,20 @@ +_format_version: "3.0" +consumer_groups: +- name: silver + tags: + - tag1 + - tag3 +- name: gold + tags: + - tag1 + - tag2 +consumers: +- username: foo + groups: + - name: gold +- username: bar + groups: + - name: silver +- username: baz + groups: + - name: silver diff --git a/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong.yaml b/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong.yaml new file mode 100644 index 0000000..3251157 --- /dev/null +++ b/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong.yaml @@ -0,0 +1,33 @@ +_format_version: "1.1" +consumer_groups: +- name: gold + plugins: + - config: + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + name: rate-limiting-advanced +- name: silver + plugins: + - config: + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + name: rate-limiting-advanced +consumers: +- groups: + - name: silver + username: bar + id: 5a5b9369-baeb-4faa-a902-c40ccdc2928e +- username: baz + id: e894ea9e-ad08-4acf-a960-5a23aa7701c7 +- groups: + - name: gold + username: foo + id: 87095815-5395-454e-8c18-a11c9bc0ef04 diff --git a/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x-initial.yaml b/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x-initial.yaml new file mode 100644 index 0000000..e08e3b2 --- /dev/null +++ b/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x-initial.yaml @@ -0,0 +1,35 @@ +_format_version: "3.0" +consumer_groups: +- name: gold + tags: + - tag1 + - tag2 + plugins: + - name: rate-limiting-advanced + config: + limit: + - 20 + retry_after_jitter_max: 1 + window_size: + - 50 + window_type: sliding +- name: silver + tags: + - tag1 + plugins: + - name: rate-limiting-advanced + config: + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 50 + window_type: sliding +consumers: +- groups: + - name: gold + username: bar +- username: baz +- groups: + - name: gold + username: foo diff --git a/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x.yaml b/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x.yaml new file mode 100644 index 0000000..592b159 --- /dev/null +++ b/tests/integration/testdata/sync/016-consumer-groups-and-plugins/kong3x.yaml @@ -0,0 +1,36 @@ +_format_version: "3.0" +consumer_groups: +- name: gold + tags: + - tag1 + - tag2 + plugins: + - name: rate-limiting-advanced + config: + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding +- name: silver + tags: + - tag1 + - tag3 + plugins: + - name: rate-limiting-advanced + config: + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding +consumers: +- groups: + - name: silver + username: bar +- username: baz +- groups: + - name: gold + username: foo diff --git a/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong.yaml b/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong.yaml new file mode 100644 index 0000000..1ddc2c9 --- /dev/null +++ b/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong.yaml @@ -0,0 +1,79 @@ +_format_version: "1.1" +consumer_groups: +- name: silver + consumers: + - username: bar + - username: baz + plugins: + - config: + limit: + - 100 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + name: rate-limiting-advanced +- name: gold + consumers: + - username: foo + plugins: + - config: + limit: + - 1000 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + name: rate-limiting-advanced +consumers: +- username: foo +- username: bar +- username: baz +plugins: +- config: + consumer_groups: + - silver + - gold + dictionary_name: kong_rate_limiting_counters + enforce_consumer_groups: true + header_name: null + hide_client_headers: false + identifier: consumer + limit: + - 10 + namespace: dNRC6xKsRL8Koc1uVYA4Nki6DLW7XIdx + path: null + redis: + cluster_addresses: null + connect_timeout: null + database: 0 + host: null + keepalive_backlog: null + keepalive_pool_size: 30 + password: null + port: null + read_timeout: null + send_timeout: null + sentinel_addresses: null + sentinel_master: null + sentinel_password: null + sentinel_role: null + sentinel_username: null + server_name: null + ssl: false + ssl_verify: false + timeout: 2000 + username: null + retry_after_jitter_max: 0 + strategy: local + sync_rate: -1 + window_size: + - 60 + window_type: sliding + enabled: true + name: rate-limiting-advanced + protocols: + - grpc + - grpcs + - http + - https diff --git a/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x-empty-application.yaml b/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x-empty-application.yaml new file mode 100644 index 0000000..cd5cde8 --- /dev/null +++ b/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x-empty-application.yaml @@ -0,0 +1,48 @@ +_format_version: "3.0" +plugins: +- config: + consumer_groups: null + dictionary_name: kong_rate_limiting_counters + enforce_consumer_groups: false + header_name: null + hide_client_headers: false + identifier: consumer + limit: + - 5 + namespace: dNRC6xKsRL8Koc1uVYA4Nki6DLW7XIdx + path: null + redis: + cluster_addresses: null + connect_timeout: null + database: 0 + host: null + keepalive_backlog: null + keepalive_pool_size: 30 + password: null + port: null + read_timeout: null + send_timeout: null + sentinel_addresses: null + sentinel_master: null + sentinel_password: null + sentinel_role: null + sentinel_username: null + server_name: null + ssl: false + ssl_verify: false + timeout: 2000 + username: null + retry_after_jitter_max: 0 + strategy: local + sync_rate: -1 + window_size: + - 60 + window_type: sliding + enabled: true + name: rate-limiting-advanced + protocols: + - grpc + - grpcs + - http + - https + diff --git a/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x.yaml b/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x.yaml new file mode 100644 index 0000000..b5594d4 --- /dev/null +++ b/tests/integration/testdata/sync/017-consumer-groups-rla-application/kong3x.yaml @@ -0,0 +1,109 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 + +consumer_groups: +- id: f79972fe-e9a0-40b5-8dc6-f1bf3758b86b + name: silver + plugins: + - config: + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + name: rate-limiting-advanced +- id: 8eea863e-460c-4019-895a-1e80cb08699d + name: gold + plugins: + - config: + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + name: rate-limiting-advanced +consumers: +- username: foo + keyauth_credentials: + - key: i-am-special + groups: + - name: gold +- username: bar + keyauth_credentials: + - key: i-am-not-so-special + groups: + - name: silver +- username: baz + keyauth_credentials: + - key: i-am-just-average + +plugins: +- name: key-auth + enabled: true + protocols: + - http + - https +- config: + consumer_groups: + - silver + - gold + dictionary_name: kong_rate_limiting_counters + enforce_consumer_groups: true + header_name: null + hide_client_headers: false + identifier: consumer + limit: + - 5 + namespace: dNRC6xKsRL8Koc1uVYA4Nki6DLW7XIdx + path: null + redis: + cluster_addresses: null + connect_timeout: null + database: 0 + host: null + keepalive_backlog: null + keepalive_pool_size: 30 + password: null + port: null + read_timeout: null + send_timeout: null + sentinel_addresses: null + sentinel_master: null + sentinel_password: null + sentinel_role: null + sentinel_username: null + server_name: null + ssl: false + ssl_verify: false + timeout: 2000 + username: null + retry_after_jitter_max: 0 + strategy: local + sync_rate: -1 + window_size: + - 60 + window_type: sliding + enabled: true + name: rate-limiting-advanced + protocols: + - grpc + - grpcs + - http + - https + diff --git a/tests/integration/testdata/sync/018-plugin-instance_name/kong-with-instance_name.yaml b/tests/integration/testdata/sync/018-plugin-instance_name/kong-with-instance_name.yaml new file mode 100644 index 0000000..7f8d94c --- /dev/null +++ b/tests/integration/testdata/sync/018-plugin-instance_name/kong-with-instance_name.yaml @@ -0,0 +1,13 @@ +_format_version: "3.0" +plugins: +- id: efead952-0a1d-43ec-9794-0ac6abdc7f55 + name: request-termination + instance_name: my-plugin + config: + status_code: 200 + enabled: true + protocols: + - grpc + - grpcs + - http + - https diff --git a/tests/integration/testdata/sync/018-plugin-instance_name/kong-without-instance_name.yaml b/tests/integration/testdata/sync/018-plugin-instance_name/kong-without-instance_name.yaml new file mode 100644 index 0000000..ca22fb4 --- /dev/null +++ b/tests/integration/testdata/sync/018-plugin-instance_name/kong-without-instance_name.yaml @@ -0,0 +1,12 @@ +_format_version: "3.0" +plugins: +- id: efead952-0a1d-43ec-9794-0ac6abdc7f55 + name: request-termination + config: + status_code: 200 + enabled: true + protocols: + - grpc + - grpcs + - http + - https diff --git a/tests/integration/testdata/sync/019-skip-consumers/kong34.yaml b/tests/integration/testdata/sync/019-skip-consumers/kong34.yaml new file mode 100644 index 0000000..433ef42 --- /dev/null +++ b/tests/integration/testdata/sync/019-skip-consumers/kong34.yaml @@ -0,0 +1,49 @@ +_format_version: "3.0" +consumer_groups: +- id: 77e6691d-67c0-446a-9401-27be2b141aae + name: gold + tags: + - tag1 + - tag2 + plugins: + - name: rate-limiting-advanced + config: + namespace: gold + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding +- id: 5bcbd3a7-030b-4310-bd1d-2721ff85d236 + name: silver + tags: + - tag1 + - tag3 + plugins: + - name: rate-limiting-advanced + config: + namespace: silver + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding +consumers: +- groups: + - name: silver + username: bar +- username: baz +- groups: + - name: gold + username: foo +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/019-skip-consumers/kong3x.yaml b/tests/integration/testdata/sync/019-skip-consumers/kong3x.yaml new file mode 100644 index 0000000..f6ff84a --- /dev/null +++ b/tests/integration/testdata/sync/019-skip-consumers/kong3x.yaml @@ -0,0 +1,45 @@ +_format_version: "3.0" +consumer_groups: +- name: gold + tags: + - tag1 + - tag2 + plugins: + - name: rate-limiting-advanced + config: + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding +- name: silver + tags: + - tag1 + - tag3 + plugins: + - name: rate-limiting-advanced + config: + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding +consumers: +- groups: + - name: silver + username: bar +- username: baz +- groups: + - name: gold + username: foo +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/020-same-names-altered-ids/1-before.yaml b/tests/integration/testdata/sync/020-same-names-altered-ids/1-before.yaml new file mode 100644 index 0000000..22a367b --- /dev/null +++ b/tests/integration/testdata/sync/020-same-names-altered-ids/1-before.yaml @@ -0,0 +1,26 @@ +_format_version: "3.0" +services: + - id: 18076db2-28b6-423b-ba39-a797193017f7 # Changing ID, + name: s1 # leaving the same name. + host: "mockbin.org" + routes: + - id: 17b6a97e-f3f7-4c47-857a-7464cb9e202b # Changing ID, + name: r1 # leaving the same name. + paths: + - /r1 +consumers: + - id: 5a1e49a8-2536-41fa-a4e9-605bf218a4fa # Changing ID, + username: c1 # leaving the same name. +plugins: + - name: rate-limiting + config: + second: 1 + service: s1 + - name: rate-limiting + config: + second: 1 + route: r1 + - name: rate-limiting + config: + second: 1 + consumer: c1 diff --git a/tests/integration/testdata/sync/020-same-names-altered-ids/2-before.yaml b/tests/integration/testdata/sync/020-same-names-altered-ids/2-before.yaml new file mode 100644 index 0000000..7bbcd6b --- /dev/null +++ b/tests/integration/testdata/sync/020-same-names-altered-ids/2-before.yaml @@ -0,0 +1,26 @@ +_format_version: "3.0" +services: + - id: 18076db2-28b6-423b-ba39-a797193017f7 # Changing ID, + name: s1 # leaving the same name. + host: "mockbin.org" + routes: + - id: 97b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + paths: + - /r1 +consumers: + - id: 5a1e49a8-2536-41fa-a4e9-605bf218a4fa # Changing ID, + username: c1 # leaving the same name. +plugins: + - name: rate-limiting + config: + second: 1 + service: s1 + - name: rate-limiting + config: + second: 1 + route: r1 + - name: rate-limiting + config: + second: 1 + consumer: c1 diff --git a/tests/integration/testdata/sync/020-same-names-altered-ids/3-before.yaml b/tests/integration/testdata/sync/020-same-names-altered-ids/3-before.yaml new file mode 100644 index 0000000..577dbd5 --- /dev/null +++ b/tests/integration/testdata/sync/020-same-names-altered-ids/3-before.yaml @@ -0,0 +1,26 @@ +_format_version: "3.0" +services: + - id: 98076db2-28b6-423b-ba39-a797193017f7 + name: s1 + host: "mockbin.org" + routes: + - id: 17b6a97e-f3f7-4c47-857a-7464cb9e202b # Changing ID, + name: r1 # leaving the same name. + paths: + - /r1 +consumers: + - id: 5a1e49a8-2536-41fa-a4e9-605bf218a4fa # Changing ID, + username: c1 # leaving the same name. +plugins: + - name: rate-limiting + config: + second: 1 + service: s1 + - name: rate-limiting + config: + second: 1 + route: r1 + - name: rate-limiting + config: + second: 1 + consumer: c1 diff --git a/tests/integration/testdata/sync/020-same-names-altered-ids/desired.yaml b/tests/integration/testdata/sync/020-same-names-altered-ids/desired.yaml new file mode 100644 index 0000000..25bb0f0 --- /dev/null +++ b/tests/integration/testdata/sync/020-same-names-altered-ids/desired.yaml @@ -0,0 +1,26 @@ +_format_version: "3.0" +services: + - id: 98076db2-28b6-423b-ba39-a797193017f7 + name: s1 + host: "mockbin.org" + routes: + - id: 97b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + paths: + - /r1 +consumers: + - id: 9a1e49a8-2536-41fa-a4e9-605bf218a4fa + username: c1 +plugins: + - name: rate-limiting + config: + second: 1 + service: s1 + - name: rate-limiting + config: + second: 1 + route: r1 + - name: rate-limiting + config: + second: 1 + consumer: c1 diff --git a/tests/integration/testdata/sync/021-update-with-explicit-ids/after.yaml b/tests/integration/testdata/sync/021-update-with-explicit-ids/after.yaml new file mode 100644 index 0000000..b0b7058 --- /dev/null +++ b/tests/integration/testdata/sync/021-update-with-explicit-ids/after.yaml @@ -0,0 +1,18 @@ +_format_version: "3.0" +services: + - enabled: true + host: mockbin.org + id: c75a775b-3a32-4b73-8e05-f68169c23941 # Leaving ID + name: s1 # and name unchanged. + port: 80 + tags: [after] + routes: + - id: 97b6a97e-f3f7-4c47-857a-7464cb9e202b # Leaving ID + name: r1 # and name unchanged. + paths: + - /r1 + tags: [after] +consumers: + - id: 9a1e49a8-2536-41fa-a4e9-605bf218a4fa # Leaving ID + username: c1 # and username unchanged. + tags: [after] diff --git a/tests/integration/testdata/sync/021-update-with-explicit-ids/before.yaml b/tests/integration/testdata/sync/021-update-with-explicit-ids/before.yaml new file mode 100644 index 0000000..6ed10eb --- /dev/null +++ b/tests/integration/testdata/sync/021-update-with-explicit-ids/before.yaml @@ -0,0 +1,15 @@ +_format_version: "3.0" +services: + - enabled: true + host: mockbin.org + id: c75a775b-3a32-4b73-8e05-f68169c23941 # Leaving ID + name: s1 # and name unchanged. + port: 80 + routes: + - id: 97b6a97e-f3f7-4c47-857a-7464cb9e202b # Leaving ID + name: r1 # and name unchanged. + paths: + - /r1 +consumers: + - id: 9a1e49a8-2536-41fa-a4e9-605bf218a4fa # Leaving ID + username: c1 # and username unchanged. diff --git a/tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/after.yaml b/tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/after.yaml new file mode 100644 index 0000000..f823fde --- /dev/null +++ b/tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/after.yaml @@ -0,0 +1,12 @@ +_format_version: "3.0" +services: + - enabled: true + host: mockbin.org + id: c75a775b-3a32-4b73-8e05-f68169c23941 # Leaving ID + port: 80 + tags: [after] + routes: + - id: 97b6a97e-f3f7-4c47-857a-7464cb9e202b # Leaving ID + paths: + - /r1 + tags: [after] diff --git a/tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/before.yaml b/tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/before.yaml new file mode 100644 index 0000000..413ecb4 --- /dev/null +++ b/tests/integration/testdata/sync/022-update-with-explicit-ids-with-no-names/before.yaml @@ -0,0 +1,10 @@ +_format_version: "3.0" +services: + - enabled: true + host: mockbin.org + id: c75a775b-3a32-4b73-8e05-f68169c23941 # Leaving ID + port: 80 + routes: + - id: 97b6a97e-f3f7-4c47-857a-7464cb9e202b # Leaving ID + paths: + - /r1 diff --git a/tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/initial.yaml b/tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/initial.yaml new file mode 100644 index 0000000..65f2781 --- /dev/null +++ b/tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/initial.yaml @@ -0,0 +1,55 @@ +_format_version: "3.0" +certificates: + - id: 13c562a1-191c-4464-9b18-e5222b46035b + cert: | + -----BEGIN CERTIFICATE----- + MIIC1jCCAb4CCQCt23nwvxSCvjANBgkqhkiG9w0BAQsFADAtMRYwFAYDVQQDDA0q + LmV4YW1wbGUuY29tMRMwEQYDVQQKDAprb25naHEub3JnMB4XDTE4MTIzMTIwMTkw + MVoXDTE5MTIzMTIwMTkwMVowLTEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTETMBEG + A1UECgwKa29uZ2hxLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + AKj/2r1AXo9x+2Csrd0SHbpnzuW+xYqgsd+YA9ZrZNV7SZGSbaZymsRMz8wg5OIU + iUik2GM1749/lYvojLFStBPy9UY/gd++5f3wLp4xHiI+IU2XQ97otXKGfyh36RmN + dKDqPLN8BG3R346s/y1GOulFvLthYmZVYF9ufHiqimfEDSbTt79P5C3X0Rw/afK1 + GjHEJPCB/XkZ6lkcEyL6LqZI5oBigDqa9hI/nWLxEzfm8pgosiS38p9TAijlOkpm + tX2p2b1pktlNIy3rxsqj6IynN9Wc7FpV1N4HoPKV7vQQ08hjwW6WfanVthaaJosj + Vr2TBCJ1ltAmsb+5B2VPYVkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnByTyQfV + 3LkwuoWS57CWcqbNw/cHnv/ChzmIv+6mIXvDBSvCgrPZIWCpaCfYRG6R51E44fr/ + 8V1AKT0Zt15DjrXEEcIGQgsIDO91/wlL091fTAUzSbL0yt7HTlm8sX6xndPNAZrq + cfcIPVMxknfqPy2VqS4IrNC03pHkDKtokphBjVUlkiWsdcq+fHYbS2xL2d1Da/uN + hX/iwgo+v5gOF5xtaXx7D7L3Cf+MHb/MOXWPfYXNiTpSBVX8/Kx5RP+QLI16nWvw + lrijTlXZFR8NIZBrCo/QZ2cNbUAbN3R0n+/kMFubxBL8WEm6Qhi9jBjbJeDMspd8 + C+/TZJQMpx5vyA== + -----END CERTIFICATE----- + key: | + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo/9q9QF6Pcftg + rK3dEh26Z87lvsWKoLHfmAPWa2TVe0mRkm2mcprETM/MIOTiFIlIpNhjNe+Pf5WL + 6IyxUrQT8vVGP4HfvuX98C6eMR4iPiFNl0Pe6LVyhn8od+kZjXSg6jyzfARt0d+O + rP8tRjrpRby7YWJmVWBfbnx4qopnxA0m07e/T+Qt19EcP2nytRoxxCTwgf15GepZ + HBMi+i6mSOaAYoA6mvYSP51i8RM35vKYKLIkt/KfUwIo5TpKZrV9qdm9aZLZTSMt + 68bKo+iMpzfVnOxaVdTeB6Dyle70ENPIY8Fuln2p1bYWmiaLI1a9kwQidZbQJrG/ + uQdlT2FZAgMBAAECggEAVnyRcda2Tcy0K7ZTR9aUlie370VhDN/OB7JhDGNreAEf + FjuMl+kAoUL5+OpAmB6QXzfVcXhRv+s4GiCJl9nORINK2Id5rIqiYwF+qgBS/o0z + N+UYm8QVz6Va/9fV1/jXXd5h8Cygi58jPH32HTJaxbSlsHNXCy3YIx6E3q/QIueR + 6ZdSXPqMEqxEU19M9jW8UeiRFrpmcyYxVpfxYIY/+O9lYjSpaeLs7hZeCP9PqWXA + Sxz2CnHZ8BcsDxAyuoHoVw+kjMpUMvA3sD4lwkV8BAYzfLmQf6PR83SFNsrE8XYu + /8WnQuCuytcl8Zg55R6tGCvf6Wyyf+MDRPwv/43QMQKBgQDbqK9Dq54k+EHgSNnP + K6AhNjFd6aqcNC1kom/sSlWBnuA/BEqJMECr8S2dYvzONUPPfX5NNUjB4Vw3Qw7a + pUgKuCQoVpzpZs5m1bk78itWDtA84LjkXfdejnUXVw/aVxLCM5QV9aEkm/dEWWMI + P1WTYVoWoZCLlEE08q0AvZQcdQKBgQDE9ZCmc6ncmhnQftuRj5PnXG2a79MLCT61 + sCEBDVvkcUJVqbzwGRLwRkdIzLgvmiuP+SukHgyfr8/RXG99xEW/q7NDrtEcqfXP + 19QXwOIp5NwDnOXyAlXiyZ50fCE2tSo2wP485+NIhmKj5Zt6y/DL6Qbc5k73XmK4 + KX5Ej15k1QKBgQCc6KeiIFLMt+Ze78tfORue/dZP7p3oDUGr1Hk9AnCIMlSfz1Hr + I+Per17VQaOzLcttyYhSYNDDZld4RlezCkQnHBkAE7bs53pjbSJv1vLr+5L3GdQZ + laIiEoNEE/YIExEcVrne4eKlgyAj2/JpLszThcRTzD+z5UibKQs6LzJBDQKBgDVa + dAGzCUt57w48nwvyQdWFgydaWef+bB9Zg8c+MCtUxuxfm4/Kqwetcff1hNtYPv60 + N68weKj1Pi1vhcAi3+YJA/mMrJbAL5dK1uhMVreUiEjuQpfpLAzQIv1Y9sJUFwhY + BUbIZhgqVyQguZptDmCeUj6aoL9/sOxESTEXSTG1AoGBAMQ5iJZMsdLCERv0+6Y1 + F/t/YSW8cugB3vdV9jHZuosoprz48p92pYP8OdQc70H5hZt53hoYNgYFSd+MU6H1 + hJCaXTsiP4IUmBjiwzSp3o1ctP8lWvnyJpAadYdDhaDaAAoaMjCo9cm5OMwc8t8x + hwAPXV2cgWH8fPcT9NLAcwWk + -----END PRIVATE KEY----- + tags: + - before + snis: + - name: example.com diff --git a/tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/update.yaml b/tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/update.yaml new file mode 100644 index 0000000..7256a7d --- /dev/null +++ b/tests/integration/testdata/sync/023-create-and-update-certificate-with-snis/update.yaml @@ -0,0 +1,55 @@ +_format_version: "3.0" +certificates: + - id: 13c562a1-191c-4464-9b18-e5222b46035b + cert: | + -----BEGIN CERTIFICATE----- + MIIC1jCCAb4CCQCt23nwvxSCvjANBgkqhkiG9w0BAQsFADAtMRYwFAYDVQQDDA0q + LmV4YW1wbGUuY29tMRMwEQYDVQQKDAprb25naHEub3JnMB4XDTE4MTIzMTIwMTkw + MVoXDTE5MTIzMTIwMTkwMVowLTEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTETMBEG + A1UECgwKa29uZ2hxLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB + AKj/2r1AXo9x+2Csrd0SHbpnzuW+xYqgsd+YA9ZrZNV7SZGSbaZymsRMz8wg5OIU + iUik2GM1749/lYvojLFStBPy9UY/gd++5f3wLp4xHiI+IU2XQ97otXKGfyh36RmN + dKDqPLN8BG3R346s/y1GOulFvLthYmZVYF9ufHiqimfEDSbTt79P5C3X0Rw/afK1 + GjHEJPCB/XkZ6lkcEyL6LqZI5oBigDqa9hI/nWLxEzfm8pgosiS38p9TAijlOkpm + tX2p2b1pktlNIy3rxsqj6IynN9Wc7FpV1N4HoPKV7vQQ08hjwW6WfanVthaaJosj + Vr2TBCJ1ltAmsb+5B2VPYVkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnByTyQfV + 3LkwuoWS57CWcqbNw/cHnv/ChzmIv+6mIXvDBSvCgrPZIWCpaCfYRG6R51E44fr/ + 8V1AKT0Zt15DjrXEEcIGQgsIDO91/wlL091fTAUzSbL0yt7HTlm8sX6xndPNAZrq + cfcIPVMxknfqPy2VqS4IrNC03pHkDKtokphBjVUlkiWsdcq+fHYbS2xL2d1Da/uN + hX/iwgo+v5gOF5xtaXx7D7L3Cf+MHb/MOXWPfYXNiTpSBVX8/Kx5RP+QLI16nWvw + lrijTlXZFR8NIZBrCo/QZ2cNbUAbN3R0n+/kMFubxBL8WEm6Qhi9jBjbJeDMspd8 + C+/TZJQMpx5vyA== + -----END CERTIFICATE----- + key: | + -----BEGIN PRIVATE KEY----- + MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo/9q9QF6Pcftg + rK3dEh26Z87lvsWKoLHfmAPWa2TVe0mRkm2mcprETM/MIOTiFIlIpNhjNe+Pf5WL + 6IyxUrQT8vVGP4HfvuX98C6eMR4iPiFNl0Pe6LVyhn8od+kZjXSg6jyzfARt0d+O + rP8tRjrpRby7YWJmVWBfbnx4qopnxA0m07e/T+Qt19EcP2nytRoxxCTwgf15GepZ + HBMi+i6mSOaAYoA6mvYSP51i8RM35vKYKLIkt/KfUwIo5TpKZrV9qdm9aZLZTSMt + 68bKo+iMpzfVnOxaVdTeB6Dyle70ENPIY8Fuln2p1bYWmiaLI1a9kwQidZbQJrG/ + uQdlT2FZAgMBAAECggEAVnyRcda2Tcy0K7ZTR9aUlie370VhDN/OB7JhDGNreAEf + FjuMl+kAoUL5+OpAmB6QXzfVcXhRv+s4GiCJl9nORINK2Id5rIqiYwF+qgBS/o0z + N+UYm8QVz6Va/9fV1/jXXd5h8Cygi58jPH32HTJaxbSlsHNXCy3YIx6E3q/QIueR + 6ZdSXPqMEqxEU19M9jW8UeiRFrpmcyYxVpfxYIY/+O9lYjSpaeLs7hZeCP9PqWXA + Sxz2CnHZ8BcsDxAyuoHoVw+kjMpUMvA3sD4lwkV8BAYzfLmQf6PR83SFNsrE8XYu + /8WnQuCuytcl8Zg55R6tGCvf6Wyyf+MDRPwv/43QMQKBgQDbqK9Dq54k+EHgSNnP + K6AhNjFd6aqcNC1kom/sSlWBnuA/BEqJMECr8S2dYvzONUPPfX5NNUjB4Vw3Qw7a + pUgKuCQoVpzpZs5m1bk78itWDtA84LjkXfdejnUXVw/aVxLCM5QV9aEkm/dEWWMI + P1WTYVoWoZCLlEE08q0AvZQcdQKBgQDE9ZCmc6ncmhnQftuRj5PnXG2a79MLCT61 + sCEBDVvkcUJVqbzwGRLwRkdIzLgvmiuP+SukHgyfr8/RXG99xEW/q7NDrtEcqfXP + 19QXwOIp5NwDnOXyAlXiyZ50fCE2tSo2wP485+NIhmKj5Zt6y/DL6Qbc5k73XmK4 + KX5Ej15k1QKBgQCc6KeiIFLMt+Ze78tfORue/dZP7p3oDUGr1Hk9AnCIMlSfz1Hr + I+Per17VQaOzLcttyYhSYNDDZld4RlezCkQnHBkAE7bs53pjbSJv1vLr+5L3GdQZ + laIiEoNEE/YIExEcVrne4eKlgyAj2/JpLszThcRTzD+z5UibKQs6LzJBDQKBgDVa + dAGzCUt57w48nwvyQdWFgydaWef+bB9Zg8c+MCtUxuxfm4/Kqwetcff1hNtYPv60 + N68weKj1Pi1vhcAi3+YJA/mMrJbAL5dK1uhMVreUiEjuQpfpLAzQIv1Y9sJUFwhY + BUbIZhgqVyQguZptDmCeUj6aoL9/sOxESTEXSTG1AoGBAMQ5iJZMsdLCERv0+6Y1 + F/t/YSW8cugB3vdV9jHZuosoprz48p92pYP8OdQc70H5hZt53hoYNgYFSd+MU6H1 + hJCaXTsiP4IUmBjiwzSp3o1ctP8lWvnyJpAadYdDhaDaAAoaMjCo9cm5OMwc8t8x + hwAPXV2cgWH8fPcT9NLAcwWk + -----END PRIVATE KEY----- + tags: + - after # Only this changes between initial and updated config. + snis: + - name: example.com diff --git a/tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x-reverse-order.yaml b/tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x-reverse-order.yaml new file mode 100644 index 0000000..fc89cf3 --- /dev/null +++ b/tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x-reverse-order.yaml @@ -0,0 +1,5 @@ +_format_version: "3.0" +consumers: +- username: OtherUser + custom_id: TestUser +- username: TestUser \ No newline at end of file diff --git a/tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x.yaml b/tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x.yaml new file mode 100644 index 0000000..c858f03 --- /dev/null +++ b/tests/integration/testdata/sync/024-consumers-with-custom_id-and-username/kong3x.yaml @@ -0,0 +1,12 @@ +_format_version: "3.0" +consumers: +- custom_id: foo + id: ce49186d-7670-445d-a218-897631b29ada + username: Foo +- custom_id: bar + id: 7820f383-7b77-4fcc-af7f-14ff3e256693 + username: foo +- custom_id: custom_id_only + id: 18c62c3c-12cc-429a-8e5a-57f2c3691a6b +- id: 8ef278c9-48c1-43e1-b665-e9bc18fab4c8 + username: username_only \ No newline at end of file diff --git a/tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml b/tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml new file mode 100644 index 0000000..ca22940 --- /dev/null +++ b/tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/kong3x.yaml @@ -0,0 +1,79 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 + +consumer_groups: +- id: 5bcbd3a7-030b-4310-bd1d-2721ff85d236 + name: silver + consumers: + - username: bar + - username: baz + plugins: + - name: rate-limiting-advanced + config: + namespace: silver + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + sync_rate: -1 +- id: 77e6691d-67c0-446a-9401-27be2b141aae + name: gold + consumers: + - username: foo + plugins: + - name: rate-limiting-advanced + config: + namespace: gold + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + sync_rate: -1 +consumers: +- username: foo + keyauth_credentials: + - key: i-am-special + groups: + - name: gold +- username: bar + keyauth_credentials: + - key: i-am-not-so-special + groups: + - name: silver +- username: baz + keyauth_credentials: + - key: i-am-just-average +plugins: +- name: key-auth + enabled: true + protocols: + - http + - https +- name: rate-limiting-advanced + config: + namespace: silver + limit: + - 5 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + sync_rate: -1 diff --git a/tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/konnect.yaml b/tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/konnect.yaml new file mode 100644 index 0000000..ca22940 --- /dev/null +++ b/tests/integration/testdata/sync/025-consumer-groups-scoped-plugins/konnect.yaml @@ -0,0 +1,79 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - name: r1 + id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + https_redirect_status_code: 301 + paths: + - /r1 + +consumer_groups: +- id: 5bcbd3a7-030b-4310-bd1d-2721ff85d236 + name: silver + consumers: + - username: bar + - username: baz + plugins: + - name: rate-limiting-advanced + config: + namespace: silver + limit: + - 7 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + sync_rate: -1 +- id: 77e6691d-67c0-446a-9401-27be2b141aae + name: gold + consumers: + - username: foo + plugins: + - name: rate-limiting-advanced + config: + namespace: gold + limit: + - 10 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + sync_rate: -1 +consumers: +- username: foo + keyauth_credentials: + - key: i-am-special + groups: + - name: gold +- username: bar + keyauth_credentials: + - key: i-am-not-so-special + groups: + - name: silver +- username: baz + keyauth_credentials: + - key: i-am-just-average +plugins: +- name: key-auth + enabled: true + protocols: + - http + - https +- name: rate-limiting-advanced + config: + namespace: silver + limit: + - 5 + retry_after_jitter_max: 1 + window_size: + - 60 + window_type: sliding + sync_rate: -1 diff --git a/tests/integration/testdata/sync/026-konnect-rename/default.yaml b/tests/integration/testdata/sync/026-konnect-rename/default.yaml new file mode 100644 index 0000000..3ac6842 --- /dev/null +++ b/tests/integration/testdata/sync/026-konnect-rename/default.yaml @@ -0,0 +1,10 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin-default.org + name: default + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/026-konnect-rename/konnect_default_cp.yaml b/tests/integration/testdata/sync/026-konnect-rename/konnect_default_cp.yaml new file mode 100644 index 0000000..9e8b742 --- /dev/null +++ b/tests/integration/testdata/sync/026-konnect-rename/konnect_default_cp.yaml @@ -0,0 +1,12 @@ +_format_version: "3.0" +_konnect: + control_plane_name: default +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin-default.org + name: default + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/026-konnect-rename/konnect_default_rg.yaml b/tests/integration/testdata/sync/026-konnect-rename/konnect_default_rg.yaml new file mode 100644 index 0000000..d6a6e89 --- /dev/null +++ b/tests/integration/testdata/sync/026-konnect-rename/konnect_default_rg.yaml @@ -0,0 +1,12 @@ +_format_version: "3.0" +_konnect: + runtime_group_name: default +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin-default.org + name: default + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/026-konnect-rename/konnect_test_cp.yaml b/tests/integration/testdata/sync/026-konnect-rename/konnect_test_cp.yaml new file mode 100644 index 0000000..2ce1ad6 --- /dev/null +++ b/tests/integration/testdata/sync/026-konnect-rename/konnect_test_cp.yaml @@ -0,0 +1,14 @@ +_format_version: "3.0" +_konnect: + control_plane_name: test +services: +- connect_timeout: 60000 + enabled: true + host: mockbin-test.org + id: 58076db2-28b6-423b-ba39-a797193017f7 + name: test + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 diff --git a/tests/integration/testdata/sync/026-konnect-rename/konnect_test_rg.yaml b/tests/integration/testdata/sync/026-konnect-rename/konnect_test_rg.yaml new file mode 100644 index 0000000..928a7ce --- /dev/null +++ b/tests/integration/testdata/sync/026-konnect-rename/konnect_test_rg.yaml @@ -0,0 +1,14 @@ +_format_version: "3.0" +_konnect: + runtime_group_name: test +services: +- connect_timeout: 60000 + enabled: true + host: mockbin-test.org + id: 58076db2-28b6-423b-ba39-a797193017f7 + name: test + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + write_timeout: 60000 \ No newline at end of file diff --git a/tests/integration/testdata/sync/026-konnect-rename/test.yaml b/tests/integration/testdata/sync/026-konnect-rename/test.yaml new file mode 100644 index 0000000..87ac25e --- /dev/null +++ b/tests/integration/testdata/sync/026-konnect-rename/test.yaml @@ -0,0 +1,10 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin-test.org + name: test + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 diff --git a/tests/integration/testdata/sync/027-created-at/new.yaml b/tests/integration/testdata/sync/027-created-at/new.yaml new file mode 100644 index 0000000..c4da620 --- /dev/null +++ b/tests/integration/testdata/sync/027-created-at/new.yaml @@ -0,0 +1,22 @@ +_format_version: "3.0" +services: +- name: svc1 + host: mockbin.org + port: 8080 + protocol: http + routes: + - name: r1 + paths: + - /r1 +consumers: +- username: foo + custom_id: new +upstreams: +- name: upstream1 + algorithm: consistent-hashing +plugins: +- name: prometheus + enabled: false + protocols: + - http + - https diff --git a/tests/integration/testdata/sync/027-created-at/old.yaml b/tests/integration/testdata/sync/027-created-at/old.yaml new file mode 100644 index 0000000..c82ab6a --- /dev/null +++ b/tests/integration/testdata/sync/027-created-at/old.yaml @@ -0,0 +1,22 @@ +_format_version: "3.0" +services: +- name: svc1 + host: mockbin.org + port: 80 + protocol: http + routes: + - name: r1 + paths: + - / +consumers: +- username: foo + custom_id: old +upstreams: +- name: upstream1 + algorithm: round-robin +plugins: +- name: prometheus + enabled: true + protocols: + - http + - https diff --git a/tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml b/tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml new file mode 100644 index 0000000..c059c8e --- /dev/null +++ b/tests/integration/testdata/sync/xxx-plugins-on-entities/kong.yaml @@ -0,0 +1,50 @@ +--- +_format_version: "3.0" +consumers: +- plugins: + - config: + per_consumer: false + enabled: true + name: prometheus + protocols: + - grpc + - grpcs + - http + - https + username: yolo + id: d2965b9b-0608-4458-a9f8-0b93d88d03b8 +services: +- id: 58076db2-28b6-423b-ba39-a797193017f7 + connect_timeout: 60000 + host: mockbin.org + name: svc1 + plugins: + - config: + per_consumer: false + enabled: true + name: prometheus + protocols: + - grpc + - grpcs + - http + - https + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 + routes: + - id: 87b6a97e-f3f7-4c47-857a-7464cb9e202b + name: r1 + https_redirect_status_code: 301 + paths: + - /r1 + plugins: + - config: + per_consumer: false + enabled: true + name: prometheus + protocols: + - grpc + - grpcs + - http + - https diff --git a/tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong.yaml b/tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong.yaml new file mode 100644 index 0000000..4c3c112 --- /dev/null +++ b/tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong.yaml @@ -0,0 +1,91 @@ +_format_version: "1.1" +rbac_roles: +- comment: Full access to Dev Portal related endpoints in the workspace + endpoint_permissions: + - actions: + - read + - delete + - create + - update + endpoint: /developers + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /developers/* + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /files + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /files/* + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /kong + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/*/*/* + negative: true + workspace: default + - actions: + - read + - update + endpoint: /workspaces/default + negative: false + workspace: default + name: workspace-portal-admin \ No newline at end of file diff --git a/tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong3x.yaml b/tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong3x.yaml new file mode 100644 index 0000000..eb2cf21 --- /dev/null +++ b/tests/integration/testdata/sync/xxx-rbac-endpoint-permissions/kong3x.yaml @@ -0,0 +1,91 @@ +_format_version: "3.0" +rbac_roles: +- comment: Full access to Dev Portal related endpoints in the workspace + endpoint_permissions: + - actions: + - read + - delete + - create + - update + endpoint: /developers + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /developers/* + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /files + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /files/* + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /kong + negative: false + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/*/* + negative: true + workspace: default + - actions: + - read + - delete + - create + - update + endpoint: /rbac/*/*/*/*/* + negative: true + workspace: default + - actions: + - read + - update + endpoint: /workspaces/default + negative: false + workspace: default + name: workspace-portal-admin From be06d141aa1b25eaca93a0a4364497fb226a9f9c Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:25:07 -0800 Subject: [PATCH 02/12] chore: tidy mod --- go.mod | 60 ++++- go.sum | 687 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 729 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 3e30b17..361967d 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ replace github.com/yudai/gojsondiff v1.0.0 => github.com/Kong/gojsondiff v1.3.0 require ( dario.cat/mergo v1.0.0 github.com/Kong/gojsondiff v1.3.2 + github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2 github.com/blang/semver/v4 v4.0.0 github.com/cenkalti/backoff/v4 v4.2.1 @@ -17,6 +18,7 @@ require ( github.com/hashicorp/go-memdb v1.3.4 github.com/hashicorp/go-retryablehttp v0.7.5 github.com/hexops/gotextdiff v1.0.3 + github.com/kong/deck v1.29.2 github.com/kong/go-kong v0.48.0 github.com/shirou/gopsutil/v3 v3.23.10 github.com/ssgelm/cookiejarparser v1.0.1 @@ -27,32 +29,82 @@ require ( ) require ( + atomicgo.dev/cursor v0.1.1 // indirect + atomicgo.dev/keyboard v0.2.9 // indirect + atomicgo.dev/schedule v0.0.2 // indirect github.com/Kong/go-diff v1.2.2 // indirect github.com/adrg/strutil v0.2.3 // indirect + github.com/containerd/console v1.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/daveshanley/vacuum v0.2.7 // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/getkin/kin-openapi v0.108.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/swag v0.22.3 // indirect + github.com/gookit/color v1.5.3 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-immutable-radix v1.3.0 // indirect + github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/yaml v0.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kong/go-apiops v0.1.23 // indirect + github.com/kong/go-slugify v0.0.0-20231027194833-8e212cc29c16 // indirect github.com/kong/semver/v4 v4.0.1 // indirect + github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/mozillazg/go-unidecode v0.2.0 // indirect + github.com/pb33f/libopenapi v0.9.6 // indirect + github.com/pb33f/libopenapi-validator v0.0.10 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/pterm/pterm v0.12.62 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect + github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.16.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/tidwall/gjson v1.17.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/yudai/golcs v0.0.0-20150405163532-d1c525dea8ce // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sys v0.14.0 // indirect + golang.org/x/term v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a00fd4f..dc5bdd5 100644 --- a/go.sum +++ b/go.sum @@ -1,39 +1,220 @@ +atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= +atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= +atomicgo.dev/cursor v0.1.1 h1:0t9sxQomCTRh5ug+hAMCs59x/UmC9QL6Ci5uosINKD4= +atomicgo.dev/cursor v0.1.1/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= +atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= +atomicgo.dev/keyboard v0.2.9/go.mod h1:BC4w9g00XkxH/f1HXhW2sXmJFOCWbKn9xrOunSFtExQ= +atomicgo.dev/schedule v0.0.2 h1:2e/4KY6t3wokja01Cyty6qgkQM8MotJzjtqCH70oX2Q= +atomicgo.dev/schedule v0.0.2/go.mod h1:xeUa3oAkiuHYh8bKiQBRojqAMq3PXXbJujjb0hw8pEU= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Kong/go-diff v1.2.2 h1:KKKaqHc8IxuguFVIZMNt3bi6YuC/t9r7BGD8bOOpSgM= github.com/Kong/go-diff v1.2.2/go.mod h1:nlvdwVZQk3Rm+tbI0cDmKFrOjghtcZTrZBp+UruvvA8= github.com/Kong/gojsondiff v1.3.2 h1:qIOVq2mUXt+NXy8Be5gRUee9TP3Ve0MbQSafg9bXKZE= github.com/Kong/gojsondiff v1.3.2/go.mod h1:DiIxtU59q4alK7ecP+7k56C5UjgOviJ5gQVR2esEhYw= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= +github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/adrg/strutil v0.2.3 h1:WZVn3ItPBovFmP4wMHHVXUr8luRaHrbyIuLlHt32GZQ= github.com/adrg/strutil v0.2.3/go.mod h1:+SNxbiH6t+O+5SZqIj5n/9i5yUjR+S3XXVrjEcN2mxg= github.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2 h1:swGeCLPiUQ647AIRnFxnAHdzlg6IPpmU6QdkOPZINt8= github.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2/go.mod h1:Juc2PrI3wtNfUwptSvAIeNx+HrETwHQs6nf+TkOJlOA= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/daveshanley/vacuum v0.2.7 h1:NaSvAfFLVadA5DUB+YLfnPM5B2Fkd4dF2t1z33BHosg= +github.com/daveshanley/vacuum v0.2.7/go.mod h1:e9X5qgIiC38ytY3XcZ8F19DhJlKggvLg+6aHyCHTZXQ= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/getkin/kin-openapi v0.108.0 h1:EYf0GtsKa4hQNIlplGS+Au7NEfGQ1F7MoHD2kcVevPQ= +github.com/getkin/kin-openapi v0.108.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v2.20.0+incompatible h1:4Xh3bDzO29j4TWNOI+24ubc0vbVFMg2PMnXKxK54/CA= +github.com/go-task/slim-sprig v2.20.0+incompatible/go.mod h1:N/mhXZITr/EQAOErEHciKvO1bFei2Lld2Ym6h96pdy0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= +github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE= +github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= @@ -41,44 +222,150 @@ github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5 github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= +github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kong/deck v1.29.2 h1:DilWRAHh4vZiTTokk5LYzzlKpXPatQ6KjHcXH8zHu8c= +github.com/kong/deck v1.29.2/go.mod h1:87zwg1HgM/cGm/4ENlvAlq199ClP0xZ6VTdbZiefAO8= +github.com/kong/go-apiops v0.1.23 h1:SFDfAS99xt/EchJMWw5pDcYysrFSapZ0L09JeH2dH9M= +github.com/kong/go-apiops v0.1.23/go.mod h1:kFc+1mlnUpmyCqem9O7aes3UaBnezu4WhgDCfrh5zAA= github.com/kong/go-kong v0.48.0 h1:vK1OpoxO50qlKdwPfmx9ChvkTKRsoCCB3b3iHo1umLc= github.com/kong/go-kong v0.48.0/go.mod h1:qH4CEFqT83ywmu1TlMZX09clQH4B8/dX88CtT/jdv/E= +github.com/kong/go-slugify v0.0.0-20231027194833-8e212cc29c16 h1:twB8aTpaG0t29jL+VYtkZiP5nMOTznt7/q4mPuNa54E= +github.com/kong/go-slugify v0.0.0-20231027194833-8e212cc29c16/go.mod h1:dbR2h3J2QKXQ1k0aww6cN7o4cIcwlWflr6RKRdcoaiw= github.com/kong/semver/v4 v4.0.1 h1:DIcNR8W3gfx0KabFBADPalxxsp+q/5COwIFkkhrFQ2Y= github.com/kong/semver/v4 v4.0.1/go.mod h1:LImQ0oT15pJvSns/hs2laLca2zcYoHu5EsSNY0J6/QA= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= +github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/onsi/ginkgo v1.1.1-0.20150303023352-38caab951a9f h1:znMoXRti03ZIy/gaW5cl3EO2A5zqzHBKA6uMnrAQDE0= -github.com/onsi/ginkgo v1.1.1-0.20150303023352-38caab951a9f/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20150401040250-4dfabf7db2e4 h1:vXLCFNIK5zI1YgKSvgc5qXOvegcGfwvQ4G3hgFCA11A= -github.com/onsi/gomega v0.0.0-20150401040250-4dfabf7db2e4/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/mozillazg/go-unidecode v0.2.0 h1:vFGEzAH9KSwyWmXCOblazEWDh7fOkpmy/Z4ArmamSUc= +github.com/mozillazg/go-unidecode v0.2.0/go.mod h1:zB48+/Z5toiRolOZy9ksLryJ976VIwmDmpQ2quyt1aA= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= +github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/pb33f/libopenapi v0.9.6 h1:PqNqdBk0lqr/luxDLv8HPKFEJ4i0zf/hpyXqQ4r8jbM= +github.com/pb33f/libopenapi v0.9.6/go.mod h1:8lr9sjsI5uZxtiEvHgg1A9/p/70briQ5WUGoJiuTFPc= +github.com/pb33f/libopenapi-validator v0.0.10 h1:+8WE5TPJ35ptp0FoiurRy0gPq9/BoezSBUgk140xZNQ= +github.com/pb33f/libopenapi-validator v0.0.10/go.mod h1:NjY6ZsalzzcenfYJe9NFB4Hy9DKWjM/7DTnf4MF+n/M= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= +github.com/pterm/pterm v0.12.62 h1:Xjj5Wl6UR4Il9xOiDUOZRwReRTdO75if/JdWsn9I59s= +github.com/pterm/pterm v0.12.62/go.mod h1:+c3ujjE7N5qmNx6eKAa7YVSC6m/gCorJJKhzwYTbL90= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.0 h1:uIkTLo0AGRc8l7h5l9r+GcYi9qfVPt6lD4/bhmzfiKo= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/ssgelm/cookiejarparser v1.0.1 h1:cRdXauUbOTFzTPJFaeiWbHnQ+tRGlpKKzvIK9PUekE4= github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9VrZuz3wSlI+OEI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -88,11 +375,17 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -103,46 +396,412 @@ github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFA github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/yudai/golcs v0.0.0-20150405163532-d1c525dea8ce h1:888GrqRxabUce7lj4OaoShPxodm3kXOMpSa85wdYzfY= -github.com/yudai/golcs v0.0.0-20150405163532-d1c525dea8ce/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.2-0.20150410014804-be8315415630+incompatible h1:TmF93o7P81230DTx1l2zw5rZbsDpOOQXoKVCa8+nXXI= github.com/yudai/pp v2.0.2-0.20150410014804-be8315415630+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E= +golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= From 14f6c2f0f1ff5e5ef350e3588bbaf9c9f14ab92b Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:34:09 -0800 Subject: [PATCH 03/12] tmp: use draft deck --- go.mod | 4 ++-- go.sum | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 361967d..f8ffa3f 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/hashicorp/go-memdb v1.3.4 github.com/hashicorp/go-retryablehttp v0.7.5 github.com/hexops/gotextdiff v1.0.3 - github.com/kong/deck v1.29.2 + github.com/kong/deck v1.29.3-0.20231114000742-27bb40ad93d6 github.com/kong/go-kong v0.48.0 github.com/shirou/gopsutil/v3 v3.23.10 github.com/ssgelm/cookiejarparser v1.0.1 @@ -80,7 +80,7 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect - github.com/spf13/cobra v1.7.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.16.0 // indirect diff --git a/go.sum b/go.sum index dc5bdd5..dc791c3 100644 --- a/go.sum +++ b/go.sum @@ -89,6 +89,7 @@ github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnht github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -252,6 +253,8 @@ github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y7 github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/kong/deck v1.29.2 h1:DilWRAHh4vZiTTokk5LYzzlKpXPatQ6KjHcXH8zHu8c= github.com/kong/deck v1.29.2/go.mod h1:87zwg1HgM/cGm/4ENlvAlq199ClP0xZ6VTdbZiefAO8= +github.com/kong/deck v1.29.3-0.20231114000742-27bb40ad93d6 h1:gvpVZ6nNRITEF0jsu2yKamiqAKdspQ3/g3CrqmXFdAs= +github.com/kong/deck v1.29.3-0.20231114000742-27bb40ad93d6/go.mod h1:0Pq1fdfG76+ftGL6rg9qWMcRR7+qKUbM755uWfz7G94= github.com/kong/go-apiops v0.1.23 h1:SFDfAS99xt/EchJMWw5pDcYysrFSapZ0L09JeH2dH9M= github.com/kong/go-apiops v0.1.23/go.mod h1:kFc+1mlnUpmyCqem9O7aes3UaBnezu4WhgDCfrh5zAA= github.com/kong/go-kong v0.48.0 h1:vK1OpoxO50qlKdwPfmx9ChvkTKRsoCCB3b3iHo1umLc= @@ -360,6 +363,8 @@ github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= From 48036e512f0263341219fc418eca23dcc0d759c1 Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:57:13 -0800 Subject: [PATCH 04/12] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Patryk Małek --- .ci/check.sh | 2 +- .ci/setup_kong.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/check.sh b/.ci/check.sh index 27d3421..aafa3ab 100755 --- a/.ci/check.sh +++ b/.ci/check.sh @@ -1,6 +1,6 @@ #!/bin/bash -ex -diff -u <(echo -n) <(gofmt -d -s .) +gofmt -d -s . ./scripts/verify-codegen.sh golint -set_exit_status $(go list ./...) go vet . diff --git a/.ci/setup_kong.sh b/.ci/setup_kong.sh index 03bdb31..023710f 100755 --- a/.ci/setup_kong.sh +++ b/.ci/setup_kong.sh @@ -62,4 +62,4 @@ docker run -d --name $GATEWAY_CONTAINER_NAME \ -p 127.0.0.1:8444:8444 \ $KONG_IMAGE -waitContainer "Kong" 8001 0.2 \ No newline at end of file +waitContainer "Kong" 8001 0.2 From c215b26ac208206d74249fc1743066ee72072ac5 Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:44:23 -0800 Subject: [PATCH 05/12] chore: run tests on PRs --- .github/workflows/integration.yaml | 3 ++- .github/workflows/test.yaml | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index e9a789b..281c8d6 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -10,7 +10,8 @@ on: push: branches: - main - pull_request: {} + pull_request: + - * jobs: integration: diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1da27c0..f033f2b 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -10,7 +10,8 @@ on: push: branches: - main - pull_request: {} + pull_request: + - * jobs: test: @@ -29,7 +30,7 @@ jobs: - name: Upload Code Coverage uses: codecov/codecov-action@v3 with: - name: codecov-deck + name: codecov token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true - name: Build From ac247e45ee86d569a92c601d04d5ff205a6c0399 Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:45:49 -0800 Subject: [PATCH 06/12] chore: tidy mod --- go.sum | 5 ----- 1 file changed, 5 deletions(-) diff --git a/go.sum b/go.sum index dc791c3..bcad6d7 100644 --- a/go.sum +++ b/go.sum @@ -88,7 +88,6 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -251,8 +250,6 @@ github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuOb github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/kong/deck v1.29.2 h1:DilWRAHh4vZiTTokk5LYzzlKpXPatQ6KjHcXH8zHu8c= -github.com/kong/deck v1.29.2/go.mod h1:87zwg1HgM/cGm/4ENlvAlq199ClP0xZ6VTdbZiefAO8= github.com/kong/deck v1.29.3-0.20231114000742-27bb40ad93d6 h1:gvpVZ6nNRITEF0jsu2yKamiqAKdspQ3/g3CrqmXFdAs= github.com/kong/deck v1.29.3-0.20231114000742-27bb40ad93d6/go.mod h1:0Pq1fdfG76+ftGL6rg9qWMcRR7+qKUbM755uWfz7G94= github.com/kong/go-apiops v0.1.23 h1:SFDfAS99xt/EchJMWw5pDcYysrFSapZ0L09JeH2dH9M= @@ -361,8 +358,6 @@ github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= From a4898b2f1c0c3f993f0237de711d5e9bfcab5a78 Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:19:04 -0500 Subject: [PATCH 07/12] fix: correct bug when consumer-group-consumer doesn't have an username Co-authored-by: Gabriele Gerbino --- pkg/state/consumer_group_consumers.go | 11 ++- pkg/state/types.go | 5 +- pkg/types/consumer_group_consumer.go | 32 ++++++-- tests/integration/dump_test.go | 33 +++++++++ tests/integration/reset_test.go | 15 ++++ tests/integration/sync_test.go | 73 +++++++++++++++++++ tests/integration/test_utils.go | 11 +++ .../konnect.yaml | 27 +++++++ .../kong.yaml | 25 +++++++ 9 files changed, 222 insertions(+), 10 deletions(-) create mode 100644 tests/integration/testdata/dump/003-consumer-group-consumers-custom_id/konnect.yaml create mode 100644 tests/integration/testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml diff --git a/pkg/state/consumer_group_consumers.go b/pkg/state/consumer_group_consumers.go index c4e53c1..f74e1d9 100644 --- a/pkg/state/consumer_group_consumers.go +++ b/pkg/state/consumer_group_consumers.go @@ -92,6 +92,9 @@ func (k *ConsumerGroupConsumersCollection) Add(consumer ConsumerGroupConsumer) e if !utils.Empty(consumer.Consumer.Username) { searchBy = append(searchBy, *consumer.Consumer.Username) } + if !utils.Empty(consumer.Consumer.CustomID) { + searchBy = append(searchBy, *consumer.Consumer.CustomID) + } _, err := getConsumerGroupConsumer(txn, *consumer.ConsumerGroup.ID, searchBy...) if err == nil { return fmt.Errorf("inserting consumerGroupConsumer %v: %w", consumer.Console(), ErrAlreadyExists) @@ -132,7 +135,13 @@ func getConsumerGroupConsumer(txn *memdb.Txn, consumerGroupID string, IDs ...str for _, id := range IDs { for _, consumer := range consumers { - if id == *consumer.Consumer.ID || id == *consumer.Consumer.Username { + var username string + if consumer.Consumer.Username != nil { + username = *consumer.Consumer.Username + } else { + username = *consumer.Consumer.CustomID + } + if id == *consumer.Consumer.ID || id == username { return &ConsumerGroupConsumer{ConsumerGroupConsumer: *consumer.DeepCopy()}, nil } } diff --git a/pkg/state/types.go b/pkg/state/types.go index b9f14fb..8328eae 100644 --- a/pkg/state/types.go +++ b/pkg/state/types.go @@ -729,7 +729,10 @@ func (c1 *ConsumerGroupConsumer) Identifier() string { // Console returns an entity's identity in a human // readable string. func (c1 *ConsumerGroupConsumer) Console() string { - return *c1.ConsumerGroupConsumer.Consumer.Username + if c1.ConsumerGroupConsumer.Consumer.Username != nil { + return *c1.ConsumerGroupConsumer.Consumer.Username + } + return *c1.ConsumerGroupConsumer.Consumer.CustomID } // Equal returns true if c1 and c2 are equal. diff --git a/pkg/types/consumer_group_consumer.go b/pkg/types/consumer_group_consumer.go index e19e72f..cb313a3 100644 --- a/pkg/types/consumer_group_consumer.go +++ b/pkg/types/consumer_group_consumer.go @@ -39,7 +39,7 @@ func (s *consumerGroupConsumerCRUD) Create(ctx context.Context, arg ...crud.Arg) ctx, s.client, consumer.ConsumerGroup.ID, consumer.Consumer.ID, ) } else { - _, err = s.client.ConsumerGroupConsumers.Create(ctx, consumer.ConsumerGroup.ID, consumer.Consumer.Username) + _, err = s.client.ConsumerGroupConsumers.Create(ctx, consumer.ConsumerGroup.ID, consumer.Consumer.ID) } if err != nil { return nil, err @@ -65,7 +65,7 @@ func (s *consumerGroupConsumerCRUD) Delete(ctx context.Context, arg ...crud.Arg) if s.isKonnect { err = konnect.DeleteConsumerGroupMember(ctx, s.client, consumer.ConsumerGroup.ID, consumer.Consumer.ID) } else { - err = s.client.ConsumerGroupConsumers.Delete(ctx, consumer.ConsumerGroup.ID, consumer.Consumer.Username) + err = s.client.ConsumerGroupConsumers.Delete(ctx, consumer.ConsumerGroup.ID, consumer.Consumer.ID) } if err != nil { return nil, err @@ -90,7 +90,7 @@ func (s *consumerGroupConsumerCRUD) Update(ctx context.Context, arg ...crud.Arg) ) } else { err = s.client.ConsumerGroupConsumers.Delete( - ctx, consumer.ConsumerGroup.ID, consumer.Consumer.Username, + ctx, consumer.ConsumerGroup.ID, consumer.Consumer.ID, ) } if err != nil { @@ -104,7 +104,7 @@ func (s *consumerGroupConsumerCRUD) Update(ctx context.Context, arg ...crud.Arg) ) } else { _, err = s.client.ConsumerGroupConsumers.Create( - ctx, consumer.ConsumerGroup.ID, consumer.Consumer.Username, + ctx, consumer.ConsumerGroup.ID, consumer.Consumer.ID, ) } if err != nil { @@ -150,8 +150,16 @@ func (d *consumerGroupConsumerDiffer) Deletes(handler func(crud.Event) error) er func (d *consumerGroupConsumerDiffer) deleteConsumerGroupConsumer( consumer *state.ConsumerGroupConsumer, ) (*crud.Event, error) { + var nameOrID string + if consumer.Consumer.ID != nil { + nameOrID = *consumer.Consumer.ID + } else if consumer.Consumer.Username != nil { + nameOrID = *consumer.Consumer.Username + } else { + nameOrID = *consumer.Consumer.CustomID + } _, err := d.targetState.ConsumerGroupConsumers.Get( - *consumer.Consumer.Username, *consumer.ConsumerGroup.ID, + nameOrID, *consumer.ConsumerGroup.ID, ) if errors.Is(err, state.ErrNotFound) { return &crud.Event{ @@ -162,7 +170,7 @@ func (d *consumerGroupConsumerDiffer) deleteConsumerGroupConsumer( } if err != nil { return nil, fmt.Errorf("looking up consumerGroupConsumer %q: %w", - *consumer.Consumer.Username, err) + nameOrID, err) } return nil, nil } @@ -192,8 +200,16 @@ func (d *consumerGroupConsumerDiffer) createUpdateConsumerGroupConsumer( consumer *state.ConsumerGroupConsumer, ) (*crud.Event, error) { consumerCopy := &state.ConsumerGroupConsumer{ConsumerGroupConsumer: *consumer.DeepCopy()} + var nameOrID string + if consumer.Consumer.ID != nil { + nameOrID = *consumer.Consumer.ID + } else if consumer.Consumer.Username != nil { + nameOrID = *consumer.Consumer.Username + } else { + nameOrID = *consumer.Consumer.CustomID + } currentConsumer, err := d.currentState.ConsumerGroupConsumers.Get( - *consumer.Consumer.Username, *consumer.ConsumerGroup.ID, + nameOrID, *consumer.ConsumerGroup.ID, ) if errors.Is(err, state.ErrNotFound) { return &crud.Event{ @@ -204,7 +220,7 @@ func (d *consumerGroupConsumerDiffer) createUpdateConsumerGroupConsumer( } if err != nil { return nil, fmt.Errorf("error looking up consumerGroupConsumer %v: %w", - *currentConsumer.Consumer.Username, err) + nameOrID, err) } // found, check if update needed diff --git a/tests/integration/dump_test.go b/tests/integration/dump_test.go index 5aa89ba..8556da0 100644 --- a/tests/integration/dump_test.go +++ b/tests/integration/dump_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_Dump_SelectTags_30(t *testing.T) { @@ -251,3 +252,35 @@ func Test_Dump_KonnectRename(t *testing.T) { }) } } + +func Test_Dump_ConsumerGroupConsumersWithCustomID(t *testing.T) { + runWhen(t, "enterprise", ">=3.0.0") + setup(t) + + require.NoError(t, sync("testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml")) + + var output string + flags := []string{"-o", "-", "--with-id"} + output, err := dump(flags...) + assert.NoError(t, err) + + expected, err := readFile("testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml") + assert.NoError(t, err) + assert.Equal(t, expected, output) +} + +func Test_Dump_ConsumerGroupConsumersWithCustomID_Konnect(t *testing.T) { + runWhen(t, "konnect", "") + setup(t) + + require.NoError(t, sync("testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml")) + + var output string + flags := []string{"-o", "-", "--with-id"} + output, err := dump(flags...) + assert.NoError(t, err) + + expected, err := readFile("testdata/dump/003-consumer-group-consumers-custom_id/konnect.yaml") + assert.NoError(t, err) + assert.Equal(t, expected, output) +} diff --git a/tests/integration/reset_test.go b/tests/integration/reset_test.go index aff9354..47aa5b2 100644 --- a/tests/integration/reset_test.go +++ b/tests/integration/reset_test.go @@ -7,6 +7,7 @@ import ( "github.com/kong/go-database-reconciler/pkg/utils" "github.com/kong/go-kong/kong" + "github.com/stretchr/testify/require" ) var caCert = &kong.CACertificate{ @@ -106,3 +107,17 @@ func Test_Reset_SkipCACert_3x(t *testing.T) { }) } } + +func Test_Reset_ConsumerGroupConsumersWithCustomID(t *testing.T) { + runWhenEnterpriseOrKonnect(t, ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + require.NoError(t, sync("testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml")) + reset(t) + testKongState(t, client, false, utils.KongRawState{}, nil) +} diff --git a/tests/integration/sync_test.go b/tests/integration/sync_test.go index 44ab032..3d2a47b 100644 --- a/tests/integration/sync_test.go +++ b/tests/integration/sync_test.go @@ -4714,3 +4714,76 @@ func Test_Sync_DoNotUpdateCreatedAt(t *testing.T) { // plugins do not have an updated_at field // consumers do not have an updated_at field } + +// test scope: +// - 3.0.0+ +// - konnect +func Test_Sync_ConsumerGroupConsumersWithCustomID(t *testing.T) { + t.Setenv("DECK_KONNECT_CONTROL_PLANE_NAME", "default") + runWhenEnterpriseOrKonnect(t, ">=3.0.0") + setup(t) + + client, err := getTestClient() + if err != nil { + t.Fatalf(err.Error()) + } + + expectedState := utils.KongRawState{ + ConsumerGroups: []*kong.ConsumerGroupObject{ + { + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("48df7cd3-1cd0-4e53-af73-8f57f257be18"), + Name: kong.String("cg1"), + }, + Consumers: []*kong.Consumer{ + { + ID: kong.String("bcb296c3-22bb-46f6-99c8-4828af750b77"), + CustomID: kong.String("foo"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("1a81dc83-5329-4666-8ae7-8a966e62d076"), + Name: kong.String("cg2"), + }, + Consumers: []*kong.Consumer{ + { + ID: kong.String("562bf5c7-a7d9-4338-84dd-2c1064fb7f67"), + Username: kong.String("foo"), + }, + }, + }, + { + ConsumerGroup: &kong.ConsumerGroup{ + ID: kong.String("d140f9cc-227e-4872-8b0b-639f6922dfb0"), + Name: kong.String("cg3"), + }, + Consumers: []*kong.Consumer{ + { + ID: kong.String("7906968b-cd89-4a87-8dda-94678e7106b2"), + Username: kong.String("bar"), + CustomID: kong.String("custom_bar"), + }, + }, + }, + }, + Consumers: []*kong.Consumer{ + { + ID: kong.String("bcb296c3-22bb-46f6-99c8-4828af750b77"), + CustomID: kong.String("foo"), + }, + { + ID: kong.String("562bf5c7-a7d9-4338-84dd-2c1064fb7f67"), + Username: kong.String("foo"), + }, + { + ID: kong.String("7906968b-cd89-4a87-8dda-94678e7106b2"), + Username: kong.String("bar"), + CustomID: kong.String("custom_bar"), + }, + }, + } + require.NoError(t, sync("testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml")) + testKongState(t, client, false, expectedState, nil) +} diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go index 7f194a0..cf28cc5 100644 --- a/tests/integration/test_utils.go +++ b/tests/integration/test_utils.go @@ -82,6 +82,17 @@ func runWhenKongOrKonnect(t *testing.T, kongSemverRange string) { kong.RunWhenKong(t, kongSemverRange) } +func runWhenEnterpriseOrKonnect(t *testing.T, kongSemverRange string) { + t.Helper() + + if os.Getenv("DECK_KONNECT_EMAIL") != "" && + os.Getenv("DECK_KONNECT_PASSWORD") != "" && + os.Getenv("DECK_KONNECT_TOKEN") != "" { + return + } + kong.RunWhenEnterprise(t, kongSemverRange, kong.RequiredFeatures{}) +} + func runWhen(t *testing.T, mode string, semverRange string) { t.Helper() diff --git a/tests/integration/testdata/dump/003-consumer-group-consumers-custom_id/konnect.yaml b/tests/integration/testdata/dump/003-consumer-group-consumers-custom_id/konnect.yaml new file mode 100644 index 0000000..71fb742 --- /dev/null +++ b/tests/integration/testdata/dump/003-consumer-group-consumers-custom_id/konnect.yaml @@ -0,0 +1,27 @@ +_format_version: "3.0" +_konnect: + control_plane_name: default +consumer_groups: +- id: 48df7cd3-1cd0-4e53-af73-8f57f257be18 + name: cg1 +- id: 1a81dc83-5329-4666-8ae7-8a966e62d076 + name: cg2 +- id: d140f9cc-227e-4872-8b0b-639f6922dfb0 + name: cg3 +consumers: +- custom_id: custom_bar + groups: + - id: d140f9cc-227e-4872-8b0b-639f6922dfb0 + name: cg3 + id: 7906968b-cd89-4a87-8dda-94678e7106b2 + username: bar +- custom_id: foo + groups: + - id: 48df7cd3-1cd0-4e53-af73-8f57f257be18 + name: cg1 + id: bcb296c3-22bb-46f6-99c8-4828af750b77 +- groups: + - id: 1a81dc83-5329-4666-8ae7-8a966e62d076 + name: cg2 + id: 562bf5c7-a7d9-4338-84dd-2c1064fb7f67 + username: foo diff --git a/tests/integration/testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml b/tests/integration/testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml new file mode 100644 index 0000000..8084953 --- /dev/null +++ b/tests/integration/testdata/sync/028-consumer-group-consumers-custom_id/kong.yaml @@ -0,0 +1,25 @@ +_format_version: "3.0" +consumer_groups: +- id: 48df7cd3-1cd0-4e53-af73-8f57f257be18 + name: cg1 +- id: 1a81dc83-5329-4666-8ae7-8a966e62d076 + name: cg2 +- id: d140f9cc-227e-4872-8b0b-639f6922dfb0 + name: cg3 +consumers: +- custom_id: custom_bar + groups: + - id: d140f9cc-227e-4872-8b0b-639f6922dfb0 + name: cg3 + id: 7906968b-cd89-4a87-8dda-94678e7106b2 + username: bar +- custom_id: foo + groups: + - id: 48df7cd3-1cd0-4e53-af73-8f57f257be18 + name: cg1 + id: bcb296c3-22bb-46f6-99c8-4828af750b77 +- groups: + - id: 1a81dc83-5329-4666-8ae7-8a966e62d076 + name: cg2 + id: 562bf5c7-a7d9-4338-84dd-2c1064fb7f67 + username: foo From 5de7b2c7593246d00ab0b63d57518a877bc884ae Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:25:14 -0500 Subject: [PATCH 08/12] chore: add versions, add Enterprise, clean targets --- .github/workflows/integration-enterprise.yaml | 64 +++++++++++++++++++ .github/workflows/integration.yaml | 2 + Makefile | 5 +- 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/integration-enterprise.yaml diff --git a/.github/workflows/integration-enterprise.yaml b/.github/workflows/integration-enterprise.yaml new file mode 100644 index 0000000..d2380dc --- /dev/null +++ b/.github/workflows/integration-enterprise.yaml @@ -0,0 +1,64 @@ +name: Enterprise Integration Test + +concurrency: + # Run only for most recent commit in PRs but for all tags and commits on main + # Ref: https://docs.github.com/en/actions/using-jobs/using-concurrency + group: ${{ github.workflow }}-${{ github.head_ref || github.sha }} + cancel-in-progress: true + +on: + push: + branches: + - main + pull_request: {} + +jobs: + integration: + strategy: + matrix: + kong_image: + - 'kong/kong-gateway:1.5.0.11' + - 'kong/kong-gateway:2.1.4.6' + - 'kong/kong-gateway:2.2.1.3' + - 'kong/kong-gateway:2.3.3.4' + - 'kong/kong-gateway:2.4.1.3' + - 'kong/kong-gateway:2.5.1.2' + - 'kong/kong-gateway:2.6.0.2' + - 'kong/kong-gateway:2.7' + - 'kong/kong-gateway:2.8' + - 'kong/kong-gateway:3.0' + - 'kong/kong-gateway:3.1' + - 'kong/kong-gateway:3.2' + - 'kong/kong-gateway:3.3' + - 'kong/kong-gateway:3.4' + - 'kong/kong-gateway:3.5' + - 'kong/kong-gateway-dev:latest' + env: + KONG_ANONYMOUS_REPORTS: "off" + KONG_IMAGE: ${{ matrix.kong_image }} + + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup go + uses: actions/setup-go@v4 + with: + go-version: '^1.20' + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{secrets.DOCKERHUB_PULL_USERNAME}} + password: ${{secrets.DOCKERHUB_PULL_TOKEN}} + - uses: Kong/kong-license@master + id: license + with: + password: ${{ secrets.PULP_PASSWORD }} + - name: Setup Kong + env: + KONG_LICENSE_DATA: ${{ steps.license.outputs.license }} + run: make setup-kong-ee + - name: Run integration tests + env: + KONG_LICENSE_DATA: ${{ steps.license.outputs.license }} + run: make test-integration diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 281c8d6..dd0d7b2 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -33,6 +33,8 @@ jobs: - 'kong:3.1' - 'kong:3.2' - 'kong:3.3' + - 'kong:3.4' + - 'kong:3.5' - 'kong/kong:master-alpine' env: KONG_ANONYMOUS_REPORTS: "off" diff --git a/Makefile b/Makefile index d3b4e53..908e8c6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,3 @@ -.DEFAULT_GOAL := test-all - -CLI_DOCS_PATH=docs/cli-docs/ .PHONY: test-all test-all: lint test @@ -49,4 +46,4 @@ setup-kong-ee: test-integration: go test -v -count=1 -tags=integration \ -race \ - ./tests/integration/... \ No newline at end of file + ./tests/integration/... From 7cd0ca680a6496f54dd240223b6f7468cc4219a5 Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:35:05 -0500 Subject: [PATCH 09/12] chore: use org pull secret --- .github/workflows/integration-enterprise.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-enterprise.yaml b/.github/workflows/integration-enterprise.yaml index d2380dc..f3b07d4 100644 --- a/.github/workflows/integration-enterprise.yaml +++ b/.github/workflows/integration-enterprise.yaml @@ -48,8 +48,8 @@ jobs: - name: Login to Docker Hub uses: docker/login-action@v3 with: - username: ${{secrets.DOCKERHUB_PULL_USERNAME}} - password: ${{secrets.DOCKERHUB_PULL_TOKEN}} + username: ${{secrets.GHA_DOCKERHUB_PULL_USER}} + password: ${{secrets.GHA_KONG_BOT_READ_TOKEN}} - uses: Kong/kong-license@master id: license with: From a0d5e15d2486fbc5df94854920ca92622e71612a Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:39:11 -0500 Subject: [PATCH 10/12] Revert "chore: use org pull secret" This reverts commit 7cd0ca680a6496f54dd240223b6f7468cc4219a5. --- .github/workflows/integration-enterprise.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/integration-enterprise.yaml b/.github/workflows/integration-enterprise.yaml index f3b07d4..d2380dc 100644 --- a/.github/workflows/integration-enterprise.yaml +++ b/.github/workflows/integration-enterprise.yaml @@ -48,8 +48,8 @@ jobs: - name: Login to Docker Hub uses: docker/login-action@v3 with: - username: ${{secrets.GHA_DOCKERHUB_PULL_USER}} - password: ${{secrets.GHA_KONG_BOT_READ_TOKEN}} + username: ${{secrets.DOCKERHUB_PULL_USERNAME}} + password: ${{secrets.DOCKERHUB_PULL_TOKEN}} - uses: Kong/kong-license@master id: license with: From f2a4bc5f9ba2f743c4b49ab5ab62bad840d5e41f Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:52:08 -0500 Subject: [PATCH 11/12] chore: downgrade github.com/fatih/color --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f8ffa3f..1e12eff 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/alecthomas/jsonschema v0.0.0-20191017121752-4bb6e3fae4f2 github.com/blang/semver/v4 v4.0.0 github.com/cenkalti/backoff/v4 v4.2.1 - github.com/fatih/color v1.16.0 + github.com/fatih/color v1.15.0 github.com/google/go-cmp v0.6.0 github.com/google/go-querystring v1.1.0 github.com/google/uuid v1.4.0 diff --git a/go.sum b/go.sum index bcad6d7..1f53daf 100644 --- a/go.sum +++ b/go.sum @@ -104,8 +104,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= From 5f4c4744f2282a954c83404c0955755938b42971 Mon Sep 17 00:00:00 2001 From: Travis Raines <571832+rainest@users.noreply.github.com> Date: Tue, 21 Nov 2023 10:58:53 -0500 Subject: [PATCH 12/12] chore: remove 3.4 and 3.5 --- .github/workflows/integration-enterprise.yaml | 2 -- .github/workflows/integration.yaml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/integration-enterprise.yaml b/.github/workflows/integration-enterprise.yaml index d2380dc..8138ed3 100644 --- a/.github/workflows/integration-enterprise.yaml +++ b/.github/workflows/integration-enterprise.yaml @@ -30,8 +30,6 @@ jobs: - 'kong/kong-gateway:3.1' - 'kong/kong-gateway:3.2' - 'kong/kong-gateway:3.3' - - 'kong/kong-gateway:3.4' - - 'kong/kong-gateway:3.5' - 'kong/kong-gateway-dev:latest' env: KONG_ANONYMOUS_REPORTS: "off" diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index dd0d7b2..281c8d6 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -33,8 +33,6 @@ jobs: - 'kong:3.1' - 'kong:3.2' - 'kong:3.3' - - 'kong:3.4' - - 'kong:3.5' - 'kong/kong:master-alpine' env: KONG_ANONYMOUS_REPORTS: "off"