mirror of https://github.com/fluxcd/flux2.git
Merge pull request #4092 from fluxcd/azure-e2e-refactor
Add new Azure and GCP e2e test setuppull/4212/head
commit
ffe5657367
@ -0,0 +1,92 @@
|
|||||||
|
name: e2e-gcp
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * *'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'tests/**'
|
||||||
|
- '.github/workflows/e2e-gcp.yaml'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'tests/**'
|
||||||
|
- '.github/workflows/e2e-gcp.yaml'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
e2e-gcp:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./tests/integration
|
||||||
|
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && github.actor != 'dependabot[bot]'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||||
|
with:
|
||||||
|
go-version: 1.20.x
|
||||||
|
cache-dependency-path: tests/integration/go.sum
|
||||||
|
- name: Setup Flux CLI
|
||||||
|
run: make build
|
||||||
|
working-directory: ./
|
||||||
|
- name: Setup SOPS
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/.local/bin
|
||||||
|
wget -O $HOME/.local/bin/sops https://github.com/mozilla/sops/releases/download/v$SOPS_VER/sops-v$SOPS_VER.linux
|
||||||
|
chmod +x $HOME/.local/bin/sops
|
||||||
|
env:
|
||||||
|
SOPS_VER: 3.7.1
|
||||||
|
- name: Authenticate to Google Cloud
|
||||||
|
uses: google-github-actions/auth@35b0e87d162680511bf346c299f71c9c5c379033 # v1.1.1
|
||||||
|
id: 'auth'
|
||||||
|
with:
|
||||||
|
credentials_json: '${{ secrets.FLUX2_E2E_GOOGLE_CREDENTIALS }}'
|
||||||
|
token_format: 'access_token'
|
||||||
|
- name: Setup gcloud
|
||||||
|
uses: google-github-actions/setup-gcloud@e30db14379863a8c79331b04a9969f4c1e225e0b # v1.1.1
|
||||||
|
- name: Setup QEMU
|
||||||
|
uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@4c0219f9ac95b02789c1075625400b2acbff50b1 # v2.9.1
|
||||||
|
- name: Log into us-central1-docker.pkg.dev
|
||||||
|
uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0
|
||||||
|
with:
|
||||||
|
registry: us-central1-docker.pkg.dev
|
||||||
|
username: oauth2accesstoken
|
||||||
|
password: ${{ steps.auth.outputs.access_token }}
|
||||||
|
- name: Set dynamic variables in .env
|
||||||
|
run: |
|
||||||
|
cat > .env <<EOF
|
||||||
|
export TF_VAR_tags='{ "environment"="github", "ci"="true", "repo"="flux2", "createdat"="$(date -u +x%Y-%m-%d_%Hh%Mm%Ss)" }'
|
||||||
|
EOF
|
||||||
|
- name: Print .env for dynamic tag value reference
|
||||||
|
run: cat .env
|
||||||
|
- name: Run GCP e2e tests
|
||||||
|
env:
|
||||||
|
TF_VAR_gcp_project_id: ${{ vars.TF_VAR_gcp_project_id }}
|
||||||
|
TF_VAR_gcp_region: ${{ vars.TF_VAR_gcp_region }}
|
||||||
|
TF_VAR_gcp_zone: ${{ vars.TF_VAR_gcp_zone }}
|
||||||
|
TF_VAR_gcp_email: ${{ secrets.TF_VAR_gcp_email }}
|
||||||
|
TF_VAR_gcp_keyring: ${{ secrets.TF_VAR_gcp_keyring }}
|
||||||
|
TF_VAR_gcp_crypto_key: ${{ secrets.TF_VAR_gcp_crypto_key }}
|
||||||
|
GITREPO_SSH_CONTENTS: ${{ secrets.GCP_GITREPO_SSH_CONTENTS }}
|
||||||
|
GITREPO_SSH_PUB_CONTENTS: ${{ secrets.GCP_GITREPO_SSH_PUB_CONTENTS }}
|
||||||
|
run: |
|
||||||
|
source .env
|
||||||
|
mkdir -p ./build/ssh
|
||||||
|
touch ./build/ssh/key
|
||||||
|
echo $GITREPO_SSH_CONTENTS | base64 -d > build/ssh/key
|
||||||
|
export GITREPO_SSH_PATH=build/ssh/key
|
||||||
|
touch ./build/ssh/key.pub
|
||||||
|
echo $GITREPO_SSH_PUB_CONTENTS | base64 -d > ./build/ssh/key.pub
|
||||||
|
export GITREPO_SSH_PUB_PATH=build/ssh/key.pub
|
||||||
|
make test-gcp
|
@ -0,0 +1,29 @@
|
|||||||
|
## Azure
|
||||||
|
# export TF_VAR_azuredevops_org=
|
||||||
|
# export TF_VAR_azuredevops_pat=
|
||||||
|
# export TF_VAR_azure_location=
|
||||||
|
## Set the following only when authenticating using Service Principal (suited
|
||||||
|
## for CI environment).
|
||||||
|
# export ARM_CLIENT_ID=
|
||||||
|
# export ARM_CLIENT_SECRET=
|
||||||
|
# export ARM_SUBSCRIPTION_ID=
|
||||||
|
# export ARM_TENANT_ID=
|
||||||
|
|
||||||
|
## GCP
|
||||||
|
# export TF_VAR_gcp_project_id=
|
||||||
|
# export TF_VAR_gcp_zone=
|
||||||
|
# export TF_VAR_gcp_region=
|
||||||
|
# export TF_VAR_gcp_keyring=
|
||||||
|
# export TF_VAR_gcp_crypto_key=
|
||||||
|
## Email address of a GCP user used for git repository cloning over ssh.
|
||||||
|
# export TF_VAR_gcp_email=
|
||||||
|
## Set the following only when using service account.
|
||||||
|
## Provide absolute path to the service account JSON key file.
|
||||||
|
# export GOOGLE_APPLICATION_CREDENTIALS=
|
||||||
|
|
||||||
|
## Common variables
|
||||||
|
# export TF_VAR_tags='{"environment"="dev", "createdat"='"\"$(date -u +x%Y-%m-%d_%Hh%Mm%Ss)\""'}'
|
||||||
|
## These are not terraform variables
|
||||||
|
## but they are needed for the bootstrap tests
|
||||||
|
# export GITREPO_SSH_PATH=
|
||||||
|
# export GITREPO_SSH_PUB_PATH=
|
@ -0,0 +1,24 @@
|
|||||||
|
GO_TEST_ARGS ?=
|
||||||
|
PROVIDER_ARG ?=
|
||||||
|
TEST_TIMEOUT ?= 60m
|
||||||
|
FLUX_BINARY ?= ../../bin/flux
|
||||||
|
|
||||||
|
test: sops-check
|
||||||
|
mkdir -p build
|
||||||
|
cp $(FLUX_BINARY) build/flux
|
||||||
|
# These two versions of podinfo are pushed to the cloud registry and used in tests for ImageUpdateAutomation
|
||||||
|
docker pull ghcr.io/stefanprodan/podinfo:6.0.0
|
||||||
|
docker pull ghcr.io/stefanprodan/podinfo:6.0.1
|
||||||
|
go test -timeout $(TEST_TIMEOUT) -v ./ $(GO_TEST_ARGS) $(PROVIDER_ARG)
|
||||||
|
|
||||||
|
test-azure:
|
||||||
|
$(MAKE) test PROVIDER_ARG="-provider azure" GO_TEST_ARGS="--tags azure $(GO_TEST_ARGS)"
|
||||||
|
|
||||||
|
test-gcp:
|
||||||
|
$(MAKE) test PROVIDER_ARG="-provider gcp"
|
||||||
|
|
||||||
|
|
||||||
|
sops-check:
|
||||||
|
ifeq ($(shell which sops),)
|
||||||
|
$(error "no sops in PATH, consider installing")
|
||||||
|
endif
|
@ -0,0 +1,381 @@
|
|||||||
|
# E2E Tests
|
||||||
|
|
||||||
|
The goal is to verify that Flux integration with cloud providers are actually working now and in the future.
|
||||||
|
Currently, we only have tests for Azure and GCP.
|
||||||
|
|
||||||
|
## General requirements
|
||||||
|
|
||||||
|
These CLI tools need to be installed for each of the tests to run successfully.
|
||||||
|
|
||||||
|
- Docker CLI for registry login.
|
||||||
|
- [SOPS CLI](https://github.com/mozilla/sops) for encrypting files
|
||||||
|
- kubectl for applying certain install manifests.
|
||||||
|
|
||||||
|
## Azure
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
|
||||||
|
The [azure](./terraform/azure) Terraform creates the AKS cluster and related resources to run the tests. It creates:
|
||||||
|
- An Azure Container Registry
|
||||||
|
- An Azure Kubernetes Cluster
|
||||||
|
- Two Azure DevOps repositories
|
||||||
|
- Azure EventHub for sending notifications
|
||||||
|
- An Azure Key Vault
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- Azure account with an active subscription to be able to create AKS and ACR,
|
||||||
|
and permission to assign roles. Role assignment is required for allowing AKS workloads to access ACR.
|
||||||
|
- Azure CLI, need to be logged in using `az login` as a User or as a Service Principal
|
||||||
|
- An Azure DevOps organization, personal access token and ssh keys for accessing repositories
|
||||||
|
within the organization. The scope required for the personal access token is:
|
||||||
|
- `Project and Team` - read, write and manage access
|
||||||
|
- `Code` - Full
|
||||||
|
- Please take a look at the [terraform provider](https://registry.terraform.io/providers/microsoft/azuredevops/latest/docs/guides/authenticating_using_the_personal_access_token#create-a-personal-access-token)
|
||||||
|
for more explanation.
|
||||||
|
- Azure DevOps only supports RSA keys. Please see
|
||||||
|
[documentation](https://learn.microsoft.com/en-us/azure/devops/repos/git/use-ssh-keys-to-authenticate?view=azure-devops#set-up-ssh-key-authentication)
|
||||||
|
for how to set up SSH key authentication.
|
||||||
|
- When using in CI, create a test user and use the test user's PAT and SSH key
|
||||||
|
for all Azure DevOps interactions. To grant the test user access in Azure
|
||||||
|
DevOps:
|
||||||
|
- Go to `Organization Settings` on the sidebar of the organization page.
|
||||||
|
- Under `General` > `Users`, click on `Add User` and input the user's email,
|
||||||
|
select `Access Level` of `Basic`.
|
||||||
|
- Go to `Security` > `Permissions`, click on the `User` tab.
|
||||||
|
- For the invited user, set the following permissions to `Allow`:
|
||||||
|
- `General: Create new project`.
|
||||||
|
- The user will get an email invitation and would need to create a Microsoft
|
||||||
|
account if they don't have one yet.
|
||||||
|
|
||||||
|
**NOTE:** To use Service Principal (for example in CI environment), set the
|
||||||
|
`ARM-*` variables in `.env`, source it and authenticate Azure CLI with:
|
||||||
|
```console
|
||||||
|
$ az login --service-principal -u $ARM_CLIENT_ID -p $ARM_CLIENT_SECRET --tenant $ARM_TENANT_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permissions
|
||||||
|
|
||||||
|
Following permissions are needed for provisioning the infrastructure and running
|
||||||
|
the tests:
|
||||||
|
- `Microsoft.Kubernetes/*`
|
||||||
|
- `Microsoft.Resources/*`
|
||||||
|
- `Microsoft.Authorization/roleAssignments/{Read,Write,Delete}`
|
||||||
|
- `Microsoft.ContainerRegistry/*`
|
||||||
|
- `Microsoft.ContainerService/*`
|
||||||
|
- `Microsoft.KeyVault/*`
|
||||||
|
- `Microsoft.EventHub/*`
|
||||||
|
|
||||||
|
### IAM and CI setup
|
||||||
|
|
||||||
|
To create the necessary IAM role with all the permissions, set up CI secrets and
|
||||||
|
variables using
|
||||||
|
[azure-gh-actions](https://github.com/fluxcd/test-infra/tree/main/tf-modules/azure/github-actions)
|
||||||
|
use the terraform configuration below. Please make sure all the requirements of
|
||||||
|
azure-gh-actions are followed before running it.
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
provider "github" {
|
||||||
|
owner = "fluxcd"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "tls_private_key" "privatekey" {
|
||||||
|
algorithm = "RSA"
|
||||||
|
rsa_bits = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
module "azure_gh_actions" {
|
||||||
|
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/azure/github-actions"
|
||||||
|
|
||||||
|
azure_owners = ["owner-id-1", "owner-id-2"]
|
||||||
|
azure_app_name = "flux2-e2e"
|
||||||
|
azure_app_description = "flux2 e2e"
|
||||||
|
azure_app_secret_name = "flux2-e2e"
|
||||||
|
azure_permissions = [
|
||||||
|
"Microsoft.Kubernetes/*",
|
||||||
|
"Microsoft.Resources/*",
|
||||||
|
"Microsoft.Authorization/roleAssignments/Read",
|
||||||
|
"Microsoft.Authorization/roleAssignments/Write",
|
||||||
|
"Microsoft.Authorization/roleAssignments/Delete",
|
||||||
|
"Microsoft.ContainerRegistry/*",
|
||||||
|
"Microsoft.ContainerService/*",
|
||||||
|
"Microsoft.KeyVault/*",
|
||||||
|
"Microsoft.EventHub/*"
|
||||||
|
]
|
||||||
|
azure_location = "eastus"
|
||||||
|
|
||||||
|
github_project = "flux2"
|
||||||
|
|
||||||
|
github_secret_client_id_name = "AZ_ARM_CLIENT_ID"
|
||||||
|
github_secret_client_secret_name = "AZ_ARM_CLIENT_SECRET"
|
||||||
|
github_secret_subscription_id_name = "AZ_ARM_SUBSCRIPTION_ID"
|
||||||
|
github_secret_tenant_id_name = "AZ_ARM_TENANT_ID"
|
||||||
|
|
||||||
|
github_secret_custom = {
|
||||||
|
"TF_VAR_azuredevops_org" = "<azuredevops-org-name>",
|
||||||
|
"TF_VAR_azuredevops_pat" = "<azuredevops-pat>",
|
||||||
|
"AZURE_GITREPO_SSH_CONTENTS" = base64encode(tls_private_key.privatekey.private_key_openssh),
|
||||||
|
"AZURE_GITREPO_SSH_PUB_CONTENTS" = base64encode(tls_private_key.privatekey.public_key_openssh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "publickey" {
|
||||||
|
value = tls_private_key.privatekey.public_key_openssh
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the `publickey` output printed after applying, or run `terraform output` to
|
||||||
|
print it again, and add it in the Azure DevOps SSH public keys under the user
|
||||||
|
account that'll be used by flux in the tests.
|
||||||
|
|
||||||
|
**NOTE:** The environment variables used above are for the GitHub workflow that
|
||||||
|
runs the tests. Change the variable names if needed accordingly.
|
||||||
|
|
||||||
|
## GCP
|
||||||
|
|
||||||
|
### Architecture
|
||||||
|
|
||||||
|
The [gcp](./terraform/gcp) terraform files create the GKE cluster and related resources to run the tests. It creates:
|
||||||
|
- A Google Container Registry and Artifact Registry
|
||||||
|
- A Google Kubernetes Cluster
|
||||||
|
- Two Google Cloud Source Repositories
|
||||||
|
- A Google Pub/Sub Topic and a subscription to the service that would be used in the tests
|
||||||
|
|
||||||
|
Note: It doesn't create Google KMS keyrings and crypto keys because these cannot be destroyed. Instead, you have
|
||||||
|
to pass in the crypto key and keyring that would be used to test the sops encryption in Flux. Please see `.env.sample`
|
||||||
|
for the terraform variables
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- GCP account with an active project to be able to create GKE and GCR, and permission to assign roles.
|
||||||
|
- Existing GCP KMS keyring and crypto key.
|
||||||
|
- [Create a Keyring](https://cloud.google.com/kms/docs/create-key-ring) in
|
||||||
|
`global` location.
|
||||||
|
- [Create a Crypto Key](https://cloud.google.com/kms/docs/create-key) with
|
||||||
|
symmetric algorithm for encryption and decryption, and software based
|
||||||
|
protection level.
|
||||||
|
- gcloud CLI, need to be logged in using `gcloud auth login` as a User (not a
|
||||||
|
Service Account), configure application default credentials with `gcloud auth
|
||||||
|
application-default login` and docker credential helper with `gcloud auth configure-docker`.
|
||||||
|
|
||||||
|
**NOTE:** To use Service Account (for example in CI environment), set
|
||||||
|
`GOOGLE_APPLICATION_CREDENTIALS` variable in `.env` with the path to the JSON
|
||||||
|
key file, source it and authenticate gcloud CLI with:
|
||||||
|
```console
|
||||||
|
$ gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS
|
||||||
|
```
|
||||||
|
Depending on the Container/Artifact Registry host used in the test, authenticate
|
||||||
|
docker accordingly
|
||||||
|
```console
|
||||||
|
$ gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://us-central1-docker.pkg.dev
|
||||||
|
```
|
||||||
|
In this case, the GCP client in terraform uses the Service Account to
|
||||||
|
authenticate and the gcloud CLI is used only to authenticate with Google
|
||||||
|
Container Registry and Google Artifact Registry.
|
||||||
|
|
||||||
|
**NOTE FOR CI USAGE:** When saving the JSON key file as a CI secret, compress
|
||||||
|
the file content with
|
||||||
|
```console
|
||||||
|
$ cat key.json | jq -r tostring
|
||||||
|
```
|
||||||
|
to prevent aggressive masking in the logs. Refer
|
||||||
|
[aggressive replacement in logs](https://github.com/google-github-actions/auth/blob/v1.1.0/docs/TROUBLESHOOTING.md#aggressive--replacement-in-logs)
|
||||||
|
for more details.
|
||||||
|
- Register [SSH Keys with Google Cloud](https://cloud.google.com/source-repositories/docs/authentication#ssh)
|
||||||
|
- Google Cloud supports these three SSH key types: RSA (only for keys with
|
||||||
|
more than 2048 bits), ECDSA and ED25519.
|
||||||
|
- The SSH user doesn't have to be a member of the GCP project. The terraform
|
||||||
|
setup will grant the user permissions to the repository. Visit
|
||||||
|
https://source.cloud.google.com, login or create a GCP account with the SSH
|
||||||
|
user's email address and add SSH keys in the account. Set this email as the
|
||||||
|
value for the environment variable `TF_VAR_gcp_email` in `.env` file to be
|
||||||
|
used as a terraform variable.
|
||||||
|
|
||||||
|
**Note:** Google doesn't allow a SSH key to be associated with a service
|
||||||
|
account email address. Therefore, there has to be an actual user that the SSH
|
||||||
|
key is registered to.
|
||||||
|
|
||||||
|
### Permissions
|
||||||
|
|
||||||
|
Following roles are needed for provisioning the infrastructure and running the tests:
|
||||||
|
|
||||||
|
- Compute Instance Admin (v1) - `roles/compute.instanceAdmin.v1`
|
||||||
|
- Kubernetes Engine Admin - `roles/container.admin`
|
||||||
|
- Service Account User - `roles/iam.serviceAccountUser`
|
||||||
|
- Service Account Token Creator - `roles/iam.serviceAccountTokenCreator`
|
||||||
|
- Artifact Registry Administrator - `roles/artifactregistry.admin`
|
||||||
|
- Artifact Registry Repository Administrator - `roles/artifactregistry.repoAdmin`
|
||||||
|
- Cloud KMS Admin - `roles/cloudkms.admin`
|
||||||
|
- Cloud KMS CryptoKey Encrypter - `roles/cloudkms.cryptoKeyEncrypter`
|
||||||
|
- Source Repository Administrator - `roles/source.admin`
|
||||||
|
- Pub/Sub Admin - `roles/pubsub.admin`
|
||||||
|
|
||||||
|
### IAM and CI setup
|
||||||
|
|
||||||
|
To create the necessary IAM role with all the permissions, set up CI secrets and
|
||||||
|
variables using
|
||||||
|
[gcp-gh-actions](https://github.com/fluxcd/test-infra/tree/main/tf-modules/gcp/github-actions)
|
||||||
|
use the terraform configuration below. Please make sure all the requirements of
|
||||||
|
gcp-gh-actions are followed before running it.
|
||||||
|
|
||||||
|
**NOTE:** When running the following for a repo under and organization, set the
|
||||||
|
environment variable `GITHUB_ORGANIZATION` if setting the `owner` in the
|
||||||
|
`github` provider doesn't work.
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
provider "google" {}
|
||||||
|
|
||||||
|
provider "github" {
|
||||||
|
owner = "fluxcd"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "tls_private_key" "privatekey" {
|
||||||
|
algorithm = "RSA"
|
||||||
|
rsa_bits = 4096
|
||||||
|
}
|
||||||
|
|
||||||
|
module "gcp_gh_actions" {
|
||||||
|
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/gcp/github-actions"
|
||||||
|
|
||||||
|
gcp_service_account_id = "flux2-e2e-test"
|
||||||
|
gcp_service_account_name = "flux2-e2e-test"
|
||||||
|
gcp_service_account_description = "For running fluxcd/flux2 e2e tests."
|
||||||
|
gcp_roles = [
|
||||||
|
"roles/compute.instanceAdmin.v1",
|
||||||
|
"roles/container.admin",
|
||||||
|
"roles/iam.serviceAccountUser",
|
||||||
|
"roles/iam.serviceAccountTokenCreator",
|
||||||
|
"roles/artifactregistry.admin",
|
||||||
|
"roles/artifactregistry.repoAdmin",
|
||||||
|
"roles/cloudkms.admin",
|
||||||
|
"roles/cloudkms.cryptoKeyEncrypter",
|
||||||
|
"roles/source.admin",
|
||||||
|
"roles/pubsub.admin"
|
||||||
|
]
|
||||||
|
|
||||||
|
github_project = "flux2"
|
||||||
|
|
||||||
|
github_secret_credentials_name = "FLUX2_E2E_GOOGLE_CREDENTIALS"
|
||||||
|
|
||||||
|
github_secret_custom = {
|
||||||
|
"TF_VAR_gcp_keyring" = "<keyring-name>",
|
||||||
|
"TF_VAR_gcp_crypto_key" = "<key-name>",
|
||||||
|
"TF_VAR_gcp_email" = "<email>",
|
||||||
|
"GCP_GITREPO_SSH_CONTENTS" = base64encode(tls_private_key.privatekey.private_key_openssh),
|
||||||
|
"GCP_GITREPO_SSH_PUB_CONTENTS" = base64encode(tls_private_key.privatekey.public_key_openssh)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "publickey" {
|
||||||
|
value = tls_private_key.privatekey.public_key_openssh
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the `publickey` output printed after applying, or run `terraform output` to
|
||||||
|
print it again, and add it in the Google Source Repository SSH public keys under
|
||||||
|
the user account with email address referred in `TF_VAR_gcp_email` above.
|
||||||
|
|
||||||
|
**NOTE:** The environment variables used above are for the GitHub workflow that
|
||||||
|
runs the tests. Change the variable names if needed accordingly.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
Each test run is initiated by running `terraform apply` in the provider's terraform directory e.g terraform apply,
|
||||||
|
it does this by using the [tftestenv package](https://github.com/fluxcd/test-infra/blob/main/tftestenv/testenv.go)
|
||||||
|
within the `fluxcd/test-infra` repository. It then reads the output of the Terraform to get information needed
|
||||||
|
for the tests like the kubernetes client ID, the cloud repository urls, the key vault ID etc. This means that
|
||||||
|
a lot of the communication with the cloud provider API is offset to Terraform instead of requiring it to be implemented in the test.
|
||||||
|
|
||||||
|
The following tests are currently implemented:
|
||||||
|
|
||||||
|
- Flux can be successfully installed on the cluster using the Flux CLI
|
||||||
|
- source-controller can clone cloud provider repositories (Azure DevOps, Google Cloud Source Repositories) (https+ssh)
|
||||||
|
- image-reflector-controller can list tags from provider container Registry image repositories
|
||||||
|
- kustomize-controller can decrypt secrets using SOPS and provider key vault
|
||||||
|
- image-automation-controller can create branches and push to cloud repositories (https+ssh)
|
||||||
|
- source-controller can pull charts from cloud provider container registry Helm repositories
|
||||||
|
- notification-controller can forward events to cloud Events Service(EventHub for Azure and Google Pub/Sub)
|
||||||
|
|
||||||
|
The following tests are run only for Azure since it is supported in the notification-controller:
|
||||||
|
|
||||||
|
- notification-controller can send commit status to Azure DevOps
|
||||||
|
|
||||||
|
### Running tests locally
|
||||||
|
|
||||||
|
1. Ensure that you have the Flux CLI binary that is to be tested built and ready. You can build it by running
|
||||||
|
`make build` at the root of this repository. The binary is located at `./bin` directory at the root and by default
|
||||||
|
this is where the Makefile copies the binary for the tests from. If you have it in a different location, you can set it
|
||||||
|
with the `FLUX_BINARY` variable
|
||||||
|
2. Copy `.env.sample` to `.env` and add the values for the different variables for the provider that you are running the tests for.
|
||||||
|
3. Run `make test-<provider>`, setting the location of the flux binary with `FLUX_BINARY` variable
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ make test-azure
|
||||||
|
make test PROVIDER_ARG="-provider azure"
|
||||||
|
# These two versions of podinfo are pushed to the cloud registry and used in tests for ImageUpdateAutomation
|
||||||
|
mkdir -p build
|
||||||
|
cp ../../bin/flux build/flux
|
||||||
|
docker pull ghcr.io/stefanprodan/podinfo:6.0.0
|
||||||
|
6.0.0: Pulling from stefanprodan/podinfo
|
||||||
|
Digest: sha256:e7eeab287181791d36c82c904206a845e30557c3a4a66a8143fa1a15655dae97
|
||||||
|
Status: Image is up to date for ghcr.io/stefanprodan/podinfo:6.0.0
|
||||||
|
ghcr.io/stefanprodan/podinfo:6.0.0
|
||||||
|
docker pull ghcr.io/stefanprodan/podinfo:6.0.1
|
||||||
|
6.0.1: Pulling from stefanprodan/podinfo
|
||||||
|
Digest: sha256:1169f220a670cf640e45e1a7ac42dc381a441e9d4b7396432cadb75beb5b5d68
|
||||||
|
Status: Image is up to date for ghcr.io/stefanprodan/podinfo:6.0.1
|
||||||
|
ghcr.io/stefanprodan/podinfo:6.0.1
|
||||||
|
go test -timeout 60m -v ./ -existing -provider azure --tags=integration
|
||||||
|
2023/03/24 02:32:25 Setting up azure e2e test infrastructure
|
||||||
|
2023/03/24 02:32:25 Terraform binary: /usr/local/bin/terraform
|
||||||
|
2023/03/24 02:32:25 Init Terraform
|
||||||
|
....[some output has been cut out]
|
||||||
|
2023/03/24 02:39:33 helm repository condition not ready
|
||||||
|
--- PASS: TestACRHelmRelease (15.31s)
|
||||||
|
=== RUN TestKeyVaultSops
|
||||||
|
--- PASS: TestKeyVaultSops (15.98s)
|
||||||
|
PASS
|
||||||
|
2023/03/24 02:40:12 Destroying environment...
|
||||||
|
ok github.com/fluxcd/flux2/tests/integration 947.341s
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above, the test created a build directory build/ and the flux cli binary is copied build/flux. It would be used
|
||||||
|
to bootstrap Flux on the cluster. You can configure the location of the Flux CLI binary by setting the FLUX_BINARY variable.
|
||||||
|
We also pull two version of `ghcr.io/stefanprodan/podinfo` image. These images are pushed to the cloud provider's
|
||||||
|
Container Registry and used to test `ImageRepository` and `ImageUpdateAutomation`. The terraform resources get created
|
||||||
|
and the tests are run.
|
||||||
|
|
||||||
|
**IMPORTANT:** In case the terraform infrastructure results in a bad state, maybe due to a crash during the apply,
|
||||||
|
the whole infrastructure can be destroyed by running terraform destroy in terraform/<provider> directory.
|
||||||
|
|
||||||
|
### Debugging the tests
|
||||||
|
|
||||||
|
For debugging environment provisioning, enable verbose output with `-verbose` test flag.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make test-azure GO_TEST_ARGS="-verbose"
|
||||||
|
```
|
||||||
|
|
||||||
|
The test environment is destroyed at the end by default. Run the tests with -retain flag to retain the created test infrastructure.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make test-azure GO_TEST_ARGS="-retain"
|
||||||
|
```
|
||||||
|
The tests require the infrastructure state to be clean. For re-running the tests with a retained infrastructure, set -existing flag.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make test-azure GO_TEST_ARGS="-retain -existing"
|
||||||
|
```
|
||||||
|
|
||||||
|
To delete an existing infrastructure created with -retain flag:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make test-azure GO_TEST_ARGS="-existing"
|
||||||
|
```
|
||||||
|
|
||||||
|
To debug issues on the cluster created by the test (provided you passed in the `-retain` flag):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export KUBECONFIG=./build/kubeconfig
|
||||||
|
kubectl get pods
|
||||||
|
```
|
@ -0,0 +1,210 @@
|
|||||||
|
//go:build azure
|
||||||
|
// +build azure
|
||||||
|
|
||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/microsoft/azure-devops-go-api/azuredevops"
|
||||||
|
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
giturls "github.com/whilp/git-urls"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
|
notiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||||
|
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAzureDevOpsCommitStatus(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
branchName := "commit-status"
|
||||||
|
testID := branchName + randStringRunes(5)
|
||||||
|
manifest := `apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: foobar`
|
||||||
|
|
||||||
|
repoUrl := getTransportURL(cfg.applicationRepository)
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
c, err := getRepository(ctx, tmpDir, repoUrl, defaultBranch, cfg.defaultAuthOpts)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
files["configmap.yaml"] = strings.NewReader(manifest)
|
||||||
|
err = commitAndPushAll(ctx, c, files, branchName)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
modifyKsSpec := func(spec *kustomizev1.KustomizationSpec) {
|
||||||
|
spec.HealthChecks = []meta.NamespacedObjectKindReference{
|
||||||
|
{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
Name: "foobar",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = setUpFluxConfig(ctx, testID, nsConfig{
|
||||||
|
ref: &sourcev1.GitRepositoryRef{
|
||||||
|
Branch: branchName,
|
||||||
|
},
|
||||||
|
repoURL: repoUrl,
|
||||||
|
path: "./",
|
||||||
|
modifyKsSpec: modifyKsSpec,
|
||||||
|
})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := tearDownFluxConfig(ctx, testID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to delete resources in '%s' namespace: %s", testID, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
err := verifyGitAndKustomization(ctx, testEnv, testID, testID)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval)
|
||||||
|
|
||||||
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "azuredevops-token",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
StringData: map[string]string{
|
||||||
|
"token": cfg.gitPat,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &secret)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &secret)
|
||||||
|
|
||||||
|
provider := notiv1beta2.Provider{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "azuredevops",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: notiv1beta2.ProviderSpec{
|
||||||
|
Type: "azuredevops",
|
||||||
|
Address: repoUrl,
|
||||||
|
SecretRef: &meta.LocalObjectReference{
|
||||||
|
Name: "azuredevops-token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &provider)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &provider)
|
||||||
|
|
||||||
|
alert := notiv1beta2.Alert{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "azuredevops",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: notiv1beta2.AlertSpec{
|
||||||
|
ProviderRef: meta.LocalObjectReference{
|
||||||
|
Name: provider.Name,
|
||||||
|
},
|
||||||
|
EventSources: []notiv1.CrossNamespaceObjectReference{
|
||||||
|
{
|
||||||
|
Kind: "Kustomization",
|
||||||
|
Name: testID,
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &alert)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &alert)
|
||||||
|
|
||||||
|
url, err := ParseAzureDevopsURL(repoUrl)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
rev, err := c.Head()
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
connection := azuredevops.NewPatConnection(url.OrgURL, cfg.gitPat)
|
||||||
|
client, err := git.NewClient(ctx, connection)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
getArgs := git.GetStatusesArgs{
|
||||||
|
Project: &url.Project,
|
||||||
|
RepositoryId: &url.Repo,
|
||||||
|
CommitId: &rev,
|
||||||
|
}
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
statuses, err := client.GetStatuses(ctx, getArgs)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if len(*statuses) != 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, 500*time.Second, 5*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AzureDevOpsURL struct {
|
||||||
|
OrgURL string
|
||||||
|
Project string
|
||||||
|
Repo string
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(somtochiama): move this into fluxcd/pkg and reuse in NC
|
||||||
|
func ParseAzureDevopsURL(s string) (AzureDevOpsURL, error) {
|
||||||
|
var args AzureDevOpsURL
|
||||||
|
u, err := giturls.Parse(s)
|
||||||
|
if err != nil {
|
||||||
|
return args, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
scheme := u.Scheme
|
||||||
|
if u.Scheme == "ssh" {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
id := strings.TrimLeft(u.Path, "/")
|
||||||
|
id = strings.TrimSuffix(id, ".git")
|
||||||
|
|
||||||
|
comp := strings.Split(id, "/")
|
||||||
|
if len(comp) != 4 {
|
||||||
|
return args, fmt.Errorf("invalid repository id %q", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
args = AzureDevOpsURL{
|
||||||
|
OrgURL: fmt.Sprintf("%s://%s/%s", scheme, u.Host, comp[0]),
|
||||||
|
Project: comp[1],
|
||||||
|
Repo: comp[3],
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, nil
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
eventhub "github.com/Azure/azure-event-hubs-go/v3"
|
||||||
|
"github.com/fluxcd/pkg/git"
|
||||||
|
"github.com/fluxcd/test-infra/tftestenv"
|
||||||
|
tfjson "github.com/hashicorp/terraform-json"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
azureDevOpsKnownHosts = "ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H"
|
||||||
|
)
|
||||||
|
|
||||||
|
// createKubeConfigAKS constructs kubeconfig for an AKS cluster from the
|
||||||
|
// terraform state output at the given kubeconfig path.
|
||||||
|
func createKubeConfigAKS(ctx context.Context, state map[string]*tfjson.StateOutput, kcPath string) error {
|
||||||
|
kubeconfigYaml, ok := state["aks_kubeconfig"].Value.(string)
|
||||||
|
if !ok || kubeconfigYaml == "" {
|
||||||
|
return fmt.Errorf("failed to obtain kubeconfig from tf output")
|
||||||
|
}
|
||||||
|
return tftestenv.CreateKubeconfigAKS(ctx, kubeconfigYaml, kcPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestConfigAKS(ctx context.Context, outputs map[string]*tfjson.StateOutput) (*testConfig, error) {
|
||||||
|
fleetInfraRepository := outputs["fleet_infra_repository"].Value.(map[string]interface{})
|
||||||
|
applicationRepository := outputs["application_repository"].Value.(map[string]interface{})
|
||||||
|
|
||||||
|
eventHubSas := outputs["event_hub_sas"].Value.(string)
|
||||||
|
sharedSopsId := outputs["sops_id"].Value.(string)
|
||||||
|
|
||||||
|
kustomizeYaml := `
|
||||||
|
resources:
|
||||||
|
- gotk-components.yaml
|
||||||
|
- gotk-sync.yaml
|
||||||
|
patchesStrategicMerge:
|
||||||
|
- |-
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: kustomize-controller
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: manager
|
||||||
|
env:
|
||||||
|
- name: AZURE_AUTH_METHOD
|
||||||
|
value: msi
|
||||||
|
`
|
||||||
|
|
||||||
|
privateKeyFile, ok := os.LookupEnv(envVarGitRepoSSHPath)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s env variable isn't set", envVarGitRepoSSHPath)
|
||||||
|
}
|
||||||
|
privateKeyData, err := os.ReadFile(privateKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting azure devops private key, '%s': %w", privateKeyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKeyFile, ok := os.LookupEnv(envVarGitRepoSSHPubPath)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s env variable isn't set", envVarGitRepoSSHPubPath)
|
||||||
|
}
|
||||||
|
pubKeyData, err := os.ReadFile(pubKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting ssh pubkey '%s', %w", pubKeyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := make(chan []byte, 10)
|
||||||
|
closefn, err := setupEventHubHandler(ctx, c, eventHubSas)
|
||||||
|
|
||||||
|
var notificationCfg = notificationConfig{
|
||||||
|
notificationChan: c,
|
||||||
|
providerType: "azureeventhub",
|
||||||
|
closeChan: closefn,
|
||||||
|
secret: map[string]string{
|
||||||
|
"address": eventHubSas,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &testConfig{
|
||||||
|
defaultGitTransport: git.HTTP,
|
||||||
|
gitUsername: git.DefaultPublicKeyAuthUser,
|
||||||
|
gitPat: outputs["azure_devops_access_token"].Value.(string),
|
||||||
|
gitPrivateKey: string(privateKeyData),
|
||||||
|
gitPublicKey: string(pubKeyData),
|
||||||
|
knownHosts: azureDevOpsKnownHosts,
|
||||||
|
fleetInfraRepository: gitUrl{
|
||||||
|
http: fleetInfraRepository["http"].(string),
|
||||||
|
ssh: fleetInfraRepository["ssh"].(string),
|
||||||
|
},
|
||||||
|
applicationRepository: gitUrl{
|
||||||
|
http: applicationRepository["http"].(string),
|
||||||
|
ssh: applicationRepository["ssh"].(string),
|
||||||
|
},
|
||||||
|
notificationCfg: notificationCfg,
|
||||||
|
sopsArgs: fmt.Sprintf("--azure-kv %s", sharedSopsId),
|
||||||
|
sopsSecretData: map[string]string{
|
||||||
|
"sops.azure-kv": fmt.Sprintf(`clientId: %s`, outputs["aks_client_id"].Value.(string)),
|
||||||
|
},
|
||||||
|
kustomizationYaml: kustomizeYaml,
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := authOpts(config.fleetInfraRepository.http, map[string][]byte{
|
||||||
|
"password": []byte(config.gitPat),
|
||||||
|
"username": []byte("git"),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config.defaultAuthOpts = opts
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// registryLoginACR logs into the Azure Container Registries using the
|
||||||
|
// provider's CLI tools and returns the test repositories.
|
||||||
|
func registryLoginACR(ctx context.Context, output map[string]*tfjson.StateOutput) (string, error) {
|
||||||
|
// NOTE: ACR registry accept dynamic repository creation by just pushing a
|
||||||
|
// new image with a new repository name.
|
||||||
|
registryURL := output["acr_url"].Value.(string)
|
||||||
|
if err := tftestenv.RegistryLoginACR(ctx, registryURL); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return registryURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupEventHubHandler(ctx context.Context, c chan []byte, eventHubSas string) (func(), error) {
|
||||||
|
hub, err := eventhub.NewHubFromConnectionString(eventHubSas)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := func(ctx context.Context, event *eventhub.Event) error {
|
||||||
|
c <- event.Data
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
runtimeInfo, err := hub.GetRuntimeInformation(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
listenerHandler, err := hub.Receive(ctx, runtimeInfo.PartitionIDs[0], handler, eventhub.ReceiveWithLatestOffset())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
closefn := func() {
|
||||||
|
listenerHandler.Close(ctx)
|
||||||
|
hub.Close(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return closefn, nil
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fluxcd/pkg/git"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFluxInstallation(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
ctx := context.TODO()
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
err := verifyGitAndKustomization(ctx, testEnv.Client, "flux-system", "flux-system")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, 60*time.Second, 5*time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRepositoryCloning(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
branchName := "feature/branch"
|
||||||
|
tagName := "v1"
|
||||||
|
|
||||||
|
g := NewWithT(t)
|
||||||
|
|
||||||
|
type testStruct struct {
|
||||||
|
name string
|
||||||
|
refType string
|
||||||
|
cloneType git.TransportType
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []testStruct{
|
||||||
|
{
|
||||||
|
name: "ssh-feature-branch",
|
||||||
|
refType: "branch",
|
||||||
|
cloneType: git.SSH,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ssh-v1",
|
||||||
|
refType: "tag",
|
||||||
|
cloneType: git.SSH,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not all cloud providers have repositories that support authentication with an accessToken
|
||||||
|
// we don't run http tests for these.
|
||||||
|
if cfg.gitPat != "" {
|
||||||
|
httpTests := []testStruct{
|
||||||
|
{
|
||||||
|
name: "https-feature-branch",
|
||||||
|
refType: "branch",
|
||||||
|
cloneType: git.HTTP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "https-v1",
|
||||||
|
refType: "tag",
|
||||||
|
cloneType: git.HTTP,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests = append(tests, httpTests...)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log("Creating application sources")
|
||||||
|
url := getTransportURL(cfg.applicationRepository)
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
client, err := getRepository(ctx, tmpDir, url, defaultBranch, cfg.defaultAuthOpts)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
for _, tt := range tests {
|
||||||
|
manifest := `apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: foobar
|
||||||
|
`
|
||||||
|
name := fmt.Sprintf("cloning-test/%s/configmap.yaml", tt.name)
|
||||||
|
files[name] = strings.NewReader(manifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = commitAndPushAll(ctx, client, files, branchName)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = createTagAndPush(ctx, client, branchName, tagName)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
t.Log("Verifying application-gitops namespaces")
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
ref := &sourcev1.GitRepositoryRef{
|
||||||
|
Branch: branchName,
|
||||||
|
}
|
||||||
|
if tt.refType == "tag" {
|
||||||
|
ref = &sourcev1.GitRepositoryRef{
|
||||||
|
Tag: tagName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url := cfg.applicationRepository.http
|
||||||
|
if tt.cloneType == git.SSH {
|
||||||
|
url = cfg.applicationRepository.ssh
|
||||||
|
}
|
||||||
|
|
||||||
|
testID := fmt.Sprintf("%s-%s", tt.name, randStringRunes(5))
|
||||||
|
err := setUpFluxConfig(ctx, testID, nsConfig{
|
||||||
|
repoURL: url,
|
||||||
|
ref: ref,
|
||||||
|
protocol: tt.cloneType,
|
||||||
|
objectName: testID,
|
||||||
|
path: fmt.Sprintf("./cloning-test/%s", tt.name),
|
||||||
|
})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := tearDownFluxConfig(ctx, testID)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("failed to delete resources in '%s' namespace: %s", tt.name, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
err := verifyGitAndKustomization(ctx, testEnv.Client, testID, testID)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, 120*time.Second, 5*time.Second).Should(BeTrue())
|
||||||
|
|
||||||
|
// Wait for configmap to be deployed
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
nn := types.NamespacedName{Name: "foobar", Namespace: testID}
|
||||||
|
cm := &corev1.ConfigMap{}
|
||||||
|
err = testEnv.Get(ctx, nn, cm)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}, 120*time.Second, 5*time.Second).Should(BeTrue())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"cloud.google.com/go/pubsub"
|
||||||
|
tfjson "github.com/hashicorp/terraform-json"
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
|
"github.com/fluxcd/pkg/git"
|
||||||
|
"github.com/fluxcd/test-infra/tftestenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
gcpSourceRepoKnownHosts = "[source.developers.google.com]:2022 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBB5Iy4/cq/gt/fPqe3uyMy4jwv1Alc94yVPxmnwNhBzJqEV5gRPiRk5u4/JJMbbu9QUVAguBABxL7sBZa5PH/xY="
|
||||||
|
)
|
||||||
|
|
||||||
|
// createKubeConfigGKE constructs kubeconfig for a GKE cluster from the
|
||||||
|
// terraform state output at the given kubeconfig path.
|
||||||
|
func createKubeConfigGKE(ctx context.Context, state map[string]*tfjson.StateOutput, kcPath string) error {
|
||||||
|
kubeconfigYaml, ok := state["gke_kubeconfig"].Value.(string)
|
||||||
|
if !ok || kubeconfigYaml == "" {
|
||||||
|
return fmt.Errorf("failed to obtain kubeconfig from tf output")
|
||||||
|
}
|
||||||
|
return tftestenv.CreateKubeconfigGKE(ctx, kubeconfigYaml, kcPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registryLoginGCR logs into the Artifact registries using the gcloud
|
||||||
|
// and returns a list of test repositories.
|
||||||
|
func registryLoginGCR(ctx context.Context, output map[string]*tfjson.StateOutput) (string, error) {
|
||||||
|
project := output["gcp_project_id"].Value.(string)
|
||||||
|
region := output["gcp_region"].Value.(string)
|
||||||
|
repositoryID := output["artifact_registry_id"].Value.(string)
|
||||||
|
artifactRegistryURL, artifactRepoURL := tftestenv.GetGoogleArtifactRegistryAndRepository(project, region, repositoryID)
|
||||||
|
if err := tftestenv.RegistryLoginGCR(ctx, artifactRegistryURL); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return artifactRepoURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestConfigGKE(ctx context.Context, outputs map[string]*tfjson.StateOutput) (*testConfig, error) {
|
||||||
|
sharedSopsId := outputs["sops_id"].Value.(string)
|
||||||
|
|
||||||
|
privateKeyFile, ok := os.LookupEnv(envVarGitRepoSSHPath)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s env variable isn't set", envVarGitRepoSSHPath)
|
||||||
|
}
|
||||||
|
privateKeyData, err := os.ReadFile(privateKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting gcp source repositories private key, '%s': %w", privateKeyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pubKeyFile, ok := os.LookupEnv(envVarGitRepoSSHPubPath)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("%s env variable isn't set", envVarGitRepoSSHPubPath)
|
||||||
|
}
|
||||||
|
pubKeyData, err := os.ReadFile(pubKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting ssh pubkey '%s', %w", pubKeyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c := make(chan []byte, 10)
|
||||||
|
projectID := outputs["gcp_project_id"].Value.(string)
|
||||||
|
topicID := outputs["pubsub_topic"].Value.(string)
|
||||||
|
|
||||||
|
fn, err := setupPubSubReceiver(ctx, c, projectID, topicID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var notificationCfg = notificationConfig{
|
||||||
|
providerType: "googlepubsub",
|
||||||
|
providerChannel: topicID,
|
||||||
|
notificationChan: c,
|
||||||
|
closeChan: fn,
|
||||||
|
secret: map[string]string{
|
||||||
|
"address": projectID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
config := &testConfig{
|
||||||
|
defaultGitTransport: git.SSH,
|
||||||
|
gitUsername: "git",
|
||||||
|
gitPrivateKey: string(privateKeyData),
|
||||||
|
gitPublicKey: string(pubKeyData),
|
||||||
|
knownHosts: gcpSourceRepoKnownHosts,
|
||||||
|
fleetInfraRepository: gitUrl{
|
||||||
|
ssh: outputs["fleet_infra_repository"].Value.(string),
|
||||||
|
},
|
||||||
|
applicationRepository: gitUrl{
|
||||||
|
ssh: outputs["application_repository"].Value.(string),
|
||||||
|
},
|
||||||
|
notificationCfg: notificationCfg,
|
||||||
|
sopsArgs: fmt.Sprintf("--gcp-kms %s", sharedSopsId),
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := authOpts(config.fleetInfraRepository.ssh, map[string][]byte{
|
||||||
|
"identity": []byte(config.gitPrivateKey),
|
||||||
|
"known_hosts": []byte(config.knownHosts),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.defaultAuthOpts = opts
|
||||||
|
|
||||||
|
// In Azure, the repository is initialized with a default branch through
|
||||||
|
// terraform. We have to do it manually here for GCP to prevent errors
|
||||||
|
// when trying to clone later. We only need to do it for the application repository
|
||||||
|
// since flux bootstrap pushes to the main branch.
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
files["README.md"] = strings.NewReader("# Flux test repo")
|
||||||
|
tmpDir, err := os.MkdirTemp("", "*-flux-test")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
client, err := getRepository(context.Background(), tmpDir, config.applicationRepository.ssh, defaultBranch, config.defaultAuthOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = commitAndPushAll(context.Background(), client, files, defaultBranch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupPubSubReceiver(ctx context.Context, c chan []byte, projectID string, topicID string) (func(), error) {
|
||||||
|
newCtx, cancel := context.WithCancel(ctx)
|
||||||
|
pubsubClient, err := pubsub.NewClient(newCtx, projectID)
|
||||||
|
if err != nil {
|
||||||
|
cancel()
|
||||||
|
return nil, fmt.Errorf("error creating pubsub client: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub := pubsubClient.Subscription(topicID)
|
||||||
|
go func() {
|
||||||
|
err = sub.Receive(ctx, func(ctx context.Context, message *pubsub.Message) {
|
||||||
|
c <- message.Data
|
||||||
|
message.Ack()
|
||||||
|
})
|
||||||
|
if err != nil && status.Code(err) != codes.Canceled {
|
||||||
|
log.Printf("error receiving message in subscription: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
cancel()
|
||||||
|
pubsubClient.Close()
|
||||||
|
}, nil
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
module github.com/fluxcd/flux2/tests/integration
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go/pubsub v1.31.0
|
||||||
|
github.com/Azure/azure-event-hubs-go/v3 v3.6.0
|
||||||
|
github.com/fluxcd/helm-controller/api v0.34.1
|
||||||
|
github.com/fluxcd/image-automation-controller/api v0.34.1
|
||||||
|
github.com/fluxcd/image-reflector-controller/api v0.28.0
|
||||||
|
github.com/fluxcd/kustomize-controller/api v1.0.0-rc.4
|
||||||
|
github.com/fluxcd/notification-controller/api v1.0.0-rc.4
|
||||||
|
github.com/fluxcd/pkg/apis/event v0.5.1
|
||||||
|
github.com/fluxcd/pkg/apis/meta v1.1.1
|
||||||
|
github.com/fluxcd/pkg/git v0.12.2
|
||||||
|
github.com/fluxcd/pkg/git/gogit v0.12.0
|
||||||
|
github.com/fluxcd/pkg/runtime v0.39.0
|
||||||
|
github.com/fluxcd/source-controller/api v1.0.0-rc.5
|
||||||
|
github.com/fluxcd/test-infra/tftestenv v0.0.0-20230531151340-931581bd0a3e
|
||||||
|
github.com/go-git/go-git/v5 v5.7.0
|
||||||
|
github.com/google/go-containerregistry v0.14.0
|
||||||
|
github.com/hashicorp/terraform-json v0.16.0
|
||||||
|
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
|
||||||
|
github.com/onsi/gomega v1.27.8
|
||||||
|
github.com/whilp/git-urls v1.0.0
|
||||||
|
google.golang.org/grpc v1.55.0
|
||||||
|
k8s.io/api v0.27.3
|
||||||
|
k8s.io/apimachinery v0.27.3
|
||||||
|
k8s.io/client-go v0.27.3
|
||||||
|
sigs.k8s.io/controller-runtime v0.15.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
cloud.google.com/go v0.110.2 // indirect
|
||||||
|
cloud.google.com/go/compute v1.19.0 // indirect
|
||||||
|
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||||
|
cloud.google.com/go/iam v1.0.1 // indirect
|
||||||
|
github.com/Azure/azure-amqp-common-go/v4 v4.2.0 // indirect
|
||||||
|
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible // indirect
|
||||||
|
github.com/Azure/go-amqp v1.0.0 // indirect
|
||||||
|
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.9.21 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
|
||||||
|
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||||
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.1 // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
|
||||||
|
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||||
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||||
|
github.com/cloudflare/circl v1.3.3 // indirect
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/devigned/tab v0.1.1 // indirect
|
||||||
|
github.com/docker/cli v23.0.1+incompatible // indirect
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||||
|
github.com/docker/docker v23.0.1+incompatible // indirect
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||||
|
github.com/emicklei/go-restful/v3 v3.10.0 // indirect
|
||||||
|
github.com/emirpasic/gods v1.18.1 // indirect
|
||||||
|
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||||
|
github.com/fluxcd/pkg/apis/acl v0.1.0 // indirect
|
||||||
|
github.com/fluxcd/pkg/apis/kustomize v1.1.0 // indirect
|
||||||
|
github.com/fluxcd/pkg/ssh v0.7.4 // indirect
|
||||||
|
github.com/fluxcd/pkg/version v0.2.2 // indirect
|
||||||
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||||
|
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
||||||
|
github.com/go-logr/logr v1.2.4 // indirect
|
||||||
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
|
github.com/go-openapi/jsonreference v0.20.1 // indirect
|
||||||
|
github.com/go-openapi/swag v0.22.3 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
|
github.com/google/gnostic v0.6.9 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
|
github.com/google/s2a-go v0.1.4 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||||
|
github.com/googleapis/gax-go/v2 v2.9.1 // indirect
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
|
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||||
|
github.com/hashicorp/hc-install v0.5.0 // indirect
|
||||||
|
github.com/hashicorp/terraform-exec v0.18.1 // indirect
|
||||||
|
github.com/imdario/mergo v0.3.15 // indirect
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.16.0 // indirect
|
||||||
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect
|
||||||
|
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/sergi/go-diff v1.3.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||||
|
github.com/skeema/knownhosts v1.1.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||||
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
|
github.com/zclconf/go-cty v1.13.0 // indirect
|
||||||
|
go.opencensus.io v0.24.0 // indirect
|
||||||
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
|
golang.org/x/mod v0.10.0 // indirect
|
||||||
|
golang.org/x/net v0.10.0 // indirect
|
||||||
|
golang.org/x/oauth2 v0.8.0 // indirect
|
||||||
|
golang.org/x/sync v0.2.0 // indirect
|
||||||
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
|
golang.org/x/term v0.8.0 // indirect
|
||||||
|
golang.org/x/text v0.9.0 // indirect
|
||||||
|
golang.org/x/time v0.3.0 // indirect
|
||||||
|
golang.org/x/tools v0.9.1 // indirect
|
||||||
|
google.golang.org/api v0.124.0 // indirect
|
||||||
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||||
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
k8s.io/apiextensions-apiserver v0.27.3 // indirect
|
||||||
|
k8s.io/klog/v2 v2.100.1 // indirect
|
||||||
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect
|
||||||
|
k8s.io/utils v0.0.0-20230505201702-9f6742963106 // indirect
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
|
)
|
@ -0,0 +1,613 @@
|
|||||||
|
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.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
|
||||||
|
cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
|
||||||
|
cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ=
|
||||||
|
cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU=
|
||||||
|
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||||
|
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||||
|
cloud.google.com/go/iam v1.0.1 h1:lyeCAU6jpnVNrE9zGQkTl3WgNgK/X+uWwaw0kynZJMU=
|
||||||
|
cloud.google.com/go/iam v1.0.1/go.mod h1:yR3tmSL8BcZB4bxByRv2jkSIahVmCtfKZwLYGBalRE8=
|
||||||
|
cloud.google.com/go/kms v1.10.2 h1:8UePKEypK3SQ6g+4mn/s/VgE5L7XOh+FwGGRUqvY3Hw=
|
||||||
|
cloud.google.com/go/pubsub v1.31.0 h1:aXdyyJz90kA+bor9+6+xHAciMD5mj8v15WqFZ5E0sek=
|
||||||
|
cloud.google.com/go/pubsub v1.31.0/go.mod h1:dYmJ3K97NCQ/e4OwZ20rD4Ym3Bu8Gu9m/aJdWQjdcks=
|
||||||
|
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
|
||||||
|
github.com/Azure/azure-amqp-common-go/v4 v4.2.0 h1:q/jLx1KJ8xeI8XGfkOWMN9XrXzAfVTkyvCxPvHCjd2I=
|
||||||
|
github.com/Azure/azure-amqp-common-go/v4 v4.2.0/go.mod h1:GD3m/WPPma+621UaU6KNjKEo5Hl09z86viKwQjTpV0Q=
|
||||||
|
github.com/Azure/azure-event-hubs-go/v3 v3.6.0 h1:UXRi5KewXYoTiekVjrj0gyGfbyGvtbYdot6/4IMf4I4=
|
||||||
|
github.com/Azure/azure-event-hubs-go/v3 v3.6.0/go.mod h1:UgyRnRU7H5e33igaLHJTqbkoNR1uj0j3MA/n7dABU24=
|
||||||
|
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible h1:HzKLt3kIwMm4KeJYTdx9EbjRYTySD/t8i1Ee/W5EGXw=
|
||||||
|
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
|
||||||
|
github.com/Azure/go-amqp v1.0.0 h1:QfCugi1M+4F2JDTRgVnRw7PYXLXZ9hmqk3+9+oJh3OA=
|
||||||
|
github.com/Azure/go-amqp v1.0.0/go.mod h1:+bg0x3ce5+Q3ahCEXnCsGG3ETpDQe3MEVnOuT2ywPwc=
|
||||||
|
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||||
|
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM=
|
||||||
|
github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.9.21 h1:jjQnVFXPfekaqb8vIsv2G1lxshoW+oGv4MDlhRtnYZk=
|
||||||
|
github.com/Azure/go-autorest/autorest/adal v0.9.21/go.mod h1:zua7mBUaCc5YnSLKYgGJR/w5ePdMDA6H56upLsHzA9U=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk=
|
||||||
|
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
||||||
|
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw=
|
||||||
|
github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
|
||||||
|
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
|
||||||
|
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
|
||||||
|
github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
|
||||||
|
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
||||||
|
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||||
|
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
|
||||||
|
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
|
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||||
|
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||||
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek=
|
||||||
|
github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
|
||||||
|
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||||
|
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||||
|
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||||
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
|
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
|
||||||
|
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||||
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||||
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
|
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
|
||||||
|
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
|
||||||
|
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||||
|
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
|
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/devigned/tab v0.1.1 h1:3mD6Kb1mUOYeLpJvTVSDwSg5ZsfSxfvxGRTxRsJsITA=
|
||||||
|
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
|
||||||
|
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||||
|
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
|
||||||
|
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
github.com/docker/docker v23.0.1+incompatible h1:vjgvJZxprTTE1A37nm+CLNAdwu6xZekyoiVlUZEINcY=
|
||||||
|
github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||||
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
|
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.10.0 h1:X4gma4HM7hFm6WMeAsTfqA0GOfdNoCzBIkHGoRLGXuM=
|
||||||
|
github.com/emicklei/go-restful/v3 v3.10.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||||
|
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||||
|
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||||
|
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||||
|
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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
||||||
|
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
|
||||||
|
github.com/fluxcd/gitkit v0.6.0 h1:iNg5LTx6ePo+Pl0ZwqHTAkhbUHxGVSY3YCxCdw7VIFg=
|
||||||
|
github.com/fluxcd/helm-controller/api v0.34.1 h1:oL6GG7weRIqkTlTFRoTY3DJpxqKpAFEoDDsYoxQCa8g=
|
||||||
|
github.com/fluxcd/helm-controller/api v0.34.1/go.mod h1:1v1UqS5jOgWdMDzvJBgdcY40RminDUO6A0by4IkHd5s=
|
||||||
|
github.com/fluxcd/image-automation-controller/api v0.34.1 h1:Y2RFhmltELcSGm3lsGgmRcJCBf0SdGlH/PwCxewk4w0=
|
||||||
|
github.com/fluxcd/image-automation-controller/api v0.34.1/go.mod h1:vRJscxpWXuDMmBj8vlFM3pgpVHqh5hf65RVnCaOnSGo=
|
||||||
|
github.com/fluxcd/image-reflector-controller/api v0.28.0 h1:2a1UxPU1RHTxl+5YFFB0KuOCHrR3hL0B7fvAPJo2UXY=
|
||||||
|
github.com/fluxcd/image-reflector-controller/api v0.28.0/go.mod h1:bY28TT8Jv/pvdF/m+c64QCEiCY2BShMe22l1zRDYm4s=
|
||||||
|
github.com/fluxcd/kustomize-controller/api v1.0.0-rc.4 h1:e5dO5HaFISFNzhfi4zuPniE545vVnEi3VnSBcbxcZqU=
|
||||||
|
github.com/fluxcd/kustomize-controller/api v1.0.0-rc.4/go.mod h1:UTJu1JMr+rkabWkUWMNiOeFeDu+4ZKfJIK+oqEwOjzc=
|
||||||
|
github.com/fluxcd/notification-controller/api v1.0.0-rc.4 h1:bDqIirpscGUY0+1u+RKvTEmX43iiZ2xeQLz27FoJJD8=
|
||||||
|
github.com/fluxcd/notification-controller/api v1.0.0-rc.4/go.mod h1:XL5h5/x46e41rtNc8mwxTKX4kAtgTNuzJS0PV2c0iIQ=
|
||||||
|
github.com/fluxcd/pkg/apis/acl v0.1.0 h1:EoAl377hDQYL3WqanWCdifauXqXbMyFuK82NnX6pH4Q=
|
||||||
|
github.com/fluxcd/pkg/apis/acl v0.1.0/go.mod h1:zfEZzz169Oap034EsDhmCAGgnWlcWmIObZjYMusoXS8=
|
||||||
|
github.com/fluxcd/pkg/apis/event v0.5.1 h1:UrEmKwTK/lt42gMZunl8BQBMzjf8PSqGbWDs/GB839c=
|
||||||
|
github.com/fluxcd/pkg/apis/event v0.5.1/go.mod h1:GzBAzS8bq7751wvNkaSnr3kuwFVuWTPL20D77UgSNJQ=
|
||||||
|
github.com/fluxcd/pkg/apis/kustomize v1.1.0 h1:Fbv4dCB57r2+fiusozN7at8r7upTz58Z4wWw1njHPyU=
|
||||||
|
github.com/fluxcd/pkg/apis/kustomize v1.1.0/go.mod h1:CAe9Mjf9KVoTm1V4wpvq/FGXFDSnpBwfww/IG7mw3gM=
|
||||||
|
github.com/fluxcd/pkg/apis/meta v1.1.1 h1:sLAKLbEu7rRzJ+Mytffu3NcpfdbOBTa6hcpOQzFWm+M=
|
||||||
|
github.com/fluxcd/pkg/apis/meta v1.1.1/go.mod h1:soCfzjFWbm1mqybDcOywWKTCEYlH3skpoNGTboVk234=
|
||||||
|
github.com/fluxcd/pkg/git v0.12.2 h1:96xH3hy3WfwiD0DioyJZcGapYT3lmPc2s7jU5UM8buw=
|
||||||
|
github.com/fluxcd/pkg/git v0.12.2/go.mod h1:9TG4fEfGCF1XHLt9Xs7X2YOmkmWOiwfjH9tdGIQs8/8=
|
||||||
|
github.com/fluxcd/pkg/git/gogit v0.12.0 h1:0mCwQND0WpCVZYHLWcXJxRvKVcyWxH4JjMQFMaea8Q4=
|
||||||
|
github.com/fluxcd/pkg/git/gogit v0.12.0/go.mod h1:Kn+GfYfZBBIaXmQj39cQvrDxT/6y8leQxXZ5/B+YYTQ=
|
||||||
|
github.com/fluxcd/pkg/gittestserver v0.8.4 h1:rA/QUZnfH77ZZG+5xfMqjgEHJdzeeE6Nn1o8cops/bU=
|
||||||
|
github.com/fluxcd/pkg/runtime v0.39.0 h1:vgmzYS+DT0w8ikX9MqGsOdmMagoiKys2RMGdl/EDbgc=
|
||||||
|
github.com/fluxcd/pkg/runtime v0.39.0/go.mod h1:0A/0kZv/MPciAj5AoSEDKVeqUFEF6371q7o+zk6l81g=
|
||||||
|
github.com/fluxcd/pkg/ssh v0.7.4 h1:8GYneCKH2dxrHQBalcDgOCC2NtqD0JO91FlWgvnzrfo=
|
||||||
|
github.com/fluxcd/pkg/ssh v0.7.4/go.mod h1:9Syc8nVJaZEToPTU4E99j0jZ99w39oZtov+uiNX17sc=
|
||||||
|
github.com/fluxcd/pkg/version v0.2.2 h1:ZpVXECeLA5hIQMft11iLp6gN3cKcz6UNuVTQPw/bRdI=
|
||||||
|
github.com/fluxcd/pkg/version v0.2.2/go.mod h1:NGnh/no8S6PyfCDxRFrPY3T5BUnqP48MxfxNRU0z8C0=
|
||||||
|
github.com/fluxcd/source-controller/api v1.0.0-rc.5 h1:muoGOb/VitVEIOh877Ledi9AvibbyevPqvuH5byWU6g=
|
||||||
|
github.com/fluxcd/source-controller/api v1.0.0-rc.5/go.mod h1:W6tNXr3mRPhdc5+Jke9OZnuk/3THNzGzRJVhAtLfzss=
|
||||||
|
github.com/fluxcd/test-infra/tftestenv v0.0.0-20230531151340-931581bd0a3e h1:71jXb0t9pQAGleqRklVtdW38nXVTZ/KqeLSENnBldNk=
|
||||||
|
github.com/fluxcd/test-infra/tftestenv v0.0.0-20230531151340-931581bd0a3e/go.mod h1:liFlLEXgambGVdWSJ4JzbIHf1Vjpp1HwUyPazPIVZug=
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
|
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
|
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||||
|
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
|
||||||
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||||
|
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||||
|
github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
|
github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||||
|
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
||||||
|
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
|
||||||
|
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||||
|
github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
|
||||||
|
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
|
||||||
|
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
|
||||||
|
github.com/go-logr/logr v1.2.0/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/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo=
|
||||||
|
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/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8=
|
||||||
|
github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
|
||||||
|
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-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||||
|
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
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.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/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
|
github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0=
|
||||||
|
github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
|
||||||
|
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.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.3/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.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-containerregistry v0.14.0 h1:z58vMqHxuwvAsVwvKEkmVBz2TlgBgH5k6koEXBtlYkw=
|
||||||
|
github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||||
|
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
|
||||||
|
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k=
|
||||||
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.9.1 h1:DpTpJqzZ3NvX9zqjhIuI1oVzYZMvboZe+3LoeEIJjHM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.9.1/go.mod h1:4FG3gMrVZlyMp5itSYKMU9z/lBE7+SbnUOvzH2HqbEY=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg=
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||||
|
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-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||||
|
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
|
github.com/hashicorp/hc-install v0.5.0 h1:D9bl4KayIYKEeJ4vUDe9L5huqxZXczKaykSRcmQ0xY0=
|
||||||
|
github.com/hashicorp/hc-install v0.5.0/go.mod h1:JyzMfbzfSBSjoDCRPna1vi/24BEDxFaCPfdHtM5SCdo=
|
||||||
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
|
github.com/hashicorp/terraform-exec v0.18.1 h1:LAbfDvNQU1l0NOQlTuudjczVhHj061fNX5H8XZxHlH4=
|
||||||
|
github.com/hashicorp/terraform-exec v0.18.1/go.mod h1:58wg4IeuAJ6LVsLUeD2DWZZoc/bYi6dzhLHzxM41980=
|
||||||
|
github.com/hashicorp/terraform-json v0.16.0 h1:UKkeWRWb23do5LNAFlh/K3N0ymn1qTOO8c+85Albo3s=
|
||||||
|
github.com/hashicorp/terraform-json v0.16.0/go.mod h1:v0Ufk9jJnk6tcIZvScHvetlKfiNTC+WS21mnXIlc0B0=
|
||||||
|
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
|
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||||
|
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
||||||
|
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||||
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
|
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/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||||
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
|
||||||
|
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
|
||||||
|
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||||
|
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||||
|
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 h1:YH424zrwLTlyHSH/GzLMJeu5zhYVZSx5RQxGKm1h96s=
|
||||||
|
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY=
|
||||||
|
github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4=
|
||||||
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
|
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/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
|
||||||
|
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||||
|
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
|
||||||
|
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
|
||||||
|
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
|
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
||||||
|
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||||
|
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
|
||||||
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
|
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||||
|
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE=
|
||||||
|
github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||||
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
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/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0/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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
|
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
|
||||||
|
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
|
||||||
|
github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU=
|
||||||
|
github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
|
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
|
github.com/yuin/goldmark v1.1.27/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/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0=
|
||||||
|
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
|
||||||
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
|
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||||
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
|
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
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-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||||
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||||
|
golang.org/x/mod v0.10.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-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-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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||||
|
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||||
|
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-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-20201020160332-67f06af15bc9/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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||||
|
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/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-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.4.0/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 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||||
|
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/text v0.3.0/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.5/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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
|
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
|
golang.org/x/time v0.3.0/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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
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.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
|
||||||
|
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||||
|
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=
|
||||||
|
gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc=
|
||||||
|
google.golang.org/api v0.124.0 h1:dP6Ef1VgOGqQ8eiv4GiY8RhmeyqzovcXBYPDUYG8Syo=
|
||||||
|
google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4=
|
||||||
|
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.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||||
|
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-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
|
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
|
||||||
|
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
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.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
|
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||||
|
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
||||||
|
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
||||||
|
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.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=
|
||||||
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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-20200227125254-8fa46927fb4f/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/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||||
|
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
k8s.io/api v0.27.3 h1:yR6oQXXnUEBWEWcvPWS0jQL575KoAboQPfJAuKNrw5Y=
|
||||||
|
k8s.io/api v0.27.3/go.mod h1:C4BNvZnQOF7JA/0Xed2S+aUyJSfTGkGFxLXz9MnpIpg=
|
||||||
|
k8s.io/apiextensions-apiserver v0.27.3 h1:xAwC1iYabi+TDfpRhxh4Eapl14Hs2OftM2DN5MpgKX4=
|
||||||
|
k8s.io/apiextensions-apiserver v0.27.3/go.mod h1:BH3wJ5NsB9XE1w+R6SSVpKmYNyIiyIz9xAmBl8Mb+84=
|
||||||
|
k8s.io/apimachinery v0.27.3 h1:Ubye8oBufD04l9QnNtW05idcOe9Z3GQN8+7PqmuVcUM=
|
||||||
|
k8s.io/apimachinery v0.27.3/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||||
|
k8s.io/client-go v0.27.3 h1:7dnEGHZEJld3lYwxvLl7WoehK6lAq7GvgjxpA3nv1E8=
|
||||||
|
k8s.io/client-go v0.27.3/go.mod h1:2MBEKuTo6V1lbKy3z1euEGnhPfGZLKTS9tiJ2xodM48=
|
||||||
|
k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
|
||||||
|
k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
|
||||||
|
k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
|
||||||
|
k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
|
sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU=
|
||||||
|
sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk=
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
|
||||||
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
automationv1beta1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||||
|
reflectorv1beta2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestImageRepositoryAndAutomation(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
ctx := context.TODO()
|
||||||
|
branchName := "image-repository"
|
||||||
|
testID := branchName + "-" + randStringRunes(5)
|
||||||
|
imageURL := fmt.Sprintf("%s/podinfo", cfg.testRegistry)
|
||||||
|
|
||||||
|
manifest := fmt.Sprintf(`apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: podinfo
|
||||||
|
namespace: %[1]s
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: podinfo
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: podinfo
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: podinfod
|
||||||
|
image: %[2]s:%[3]s # {"$imagepolicy": "%[1]s:podinfo"}
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- podcli
|
||||||
|
- check
|
||||||
|
- http
|
||||||
|
- localhost:9898/readyz
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
`, testID, imageURL, oldPodinfoVersion)
|
||||||
|
|
||||||
|
repoUrl := getTransportURL(cfg.applicationRepository)
|
||||||
|
client, err := getRepository(ctx, t.TempDir(), repoUrl, defaultBranch, cfg.defaultAuthOpts)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
files[testID+"/podinfo.yaml"] = strings.NewReader(manifest)
|
||||||
|
|
||||||
|
err = commitAndPushAll(ctx, client, files, branchName)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
err = setUpFluxConfig(ctx, testID, nsConfig{
|
||||||
|
repoURL: repoUrl,
|
||||||
|
path: testID,
|
||||||
|
ref: &sourcev1.GitRepositoryRef{
|
||||||
|
Branch: branchName,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := tearDownFluxConfig(ctx, testID)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("failed to delete resources in '%s' namespace: %s", testID, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
err := verifyGitAndKustomization(ctx, testEnv.Client, testID, testID)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
|
||||||
|
imageRepository := reflectorv1beta2.ImageRepository{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "podinfo",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: reflectorv1beta2.ImageRepositorySpec{
|
||||||
|
Image: imageURL,
|
||||||
|
Interval: metav1.Duration{
|
||||||
|
Duration: 1 * time.Minute,
|
||||||
|
},
|
||||||
|
Provider: infraOpts.Provider,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &imageRepository)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &imageRepository)
|
||||||
|
|
||||||
|
imagePolicy := reflectorv1beta2.ImagePolicy{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "podinfo",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: reflectorv1beta2.ImagePolicySpec{
|
||||||
|
ImageRepositoryRef: meta.NamespacedObjectReference{
|
||||||
|
Name: imageRepository.Name,
|
||||||
|
},
|
||||||
|
Policy: reflectorv1beta2.ImagePolicyChoice{
|
||||||
|
SemVer: &reflectorv1beta2.SemVerPolicy{
|
||||||
|
Range: "6.0.x",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &imagePolicy)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &imagePolicy)
|
||||||
|
|
||||||
|
imageAutomation := automationv1beta1.ImageUpdateAutomation{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "podinfo",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: automationv1beta1.ImageUpdateAutomationSpec{
|
||||||
|
Interval: metav1.Duration{
|
||||||
|
Duration: 1 * time.Minute,
|
||||||
|
},
|
||||||
|
SourceRef: automationv1beta1.CrossNamespaceSourceReference{
|
||||||
|
Kind: "GitRepository",
|
||||||
|
Name: testID,
|
||||||
|
},
|
||||||
|
GitSpec: &automationv1beta1.GitSpec{
|
||||||
|
Checkout: &automationv1beta1.GitCheckoutSpec{
|
||||||
|
Reference: sourcev1.GitRepositoryRef{
|
||||||
|
Branch: branchName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Commit: automationv1beta1.CommitSpec{
|
||||||
|
Author: automationv1beta1.CommitUser{
|
||||||
|
Email: "imageautomation@example.com",
|
||||||
|
Name: "imageautomation",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Update: &automationv1beta1.UpdateStrategy{
|
||||||
|
Path: testID,
|
||||||
|
Strategy: automationv1beta1.UpdateStrategySetters,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &imageAutomation)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &imageAutomation)
|
||||||
|
|
||||||
|
// Wait for image repository to be ready
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
client, err := getRepository(ctx, t.TempDir(), repoUrl, branchName, cfg.defaultAuthOpts)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := os.ReadFile(filepath.Join(client.Path(), testID, "podinfo.yaml"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if bytes.Contains(b, []byte(newPodinfoVersion)) == false {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
|
notiv1 "github.com/fluxcd/notification-controller/api/v1"
|
||||||
|
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||||
|
events "github.com/fluxcd/pkg/apis/event/v1beta1"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNotification(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
|
||||||
|
ctx := context.TODO()
|
||||||
|
branchName := "test-notification"
|
||||||
|
testID := branchName + "-" + randStringRunes(5)
|
||||||
|
defer cfg.notificationCfg.closeChan()
|
||||||
|
|
||||||
|
// Setup Flux resources
|
||||||
|
manifest := `apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: foobar`
|
||||||
|
repoUrl := getTransportURL(cfg.applicationRepository)
|
||||||
|
client, err := getRepository(ctx, t.TempDir(), repoUrl, defaultBranch, cfg.defaultAuthOpts)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
files["configmap.yaml"] = strings.NewReader(manifest)
|
||||||
|
err = commitAndPushAll(ctx, client, files, branchName)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
namespace := corev1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &namespace)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &namespace)
|
||||||
|
|
||||||
|
provider := notiv1beta2.Provider{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testID,
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: notiv1beta2.ProviderSpec{
|
||||||
|
Type: cfg.notificationCfg.providerType,
|
||||||
|
Address: cfg.notificationCfg.providerAddress,
|
||||||
|
Channel: cfg.notificationCfg.providerChannel,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.notificationCfg.secret != nil {
|
||||||
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testID,
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
StringData: cfg.notificationCfg.secret,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Expect(testEnv.Create(ctx, &secret)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &secret)
|
||||||
|
|
||||||
|
provider.Spec.SecretRef = &meta.LocalObjectReference{
|
||||||
|
Name: testID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Expect(testEnv.Create(ctx, &provider)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &provider)
|
||||||
|
|
||||||
|
alert := notiv1beta2.Alert{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testID,
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
Spec: notiv1beta2.AlertSpec{
|
||||||
|
ProviderRef: meta.LocalObjectReference{
|
||||||
|
Name: provider.Name,
|
||||||
|
},
|
||||||
|
EventSources: []notiv1.CrossNamespaceObjectReference{
|
||||||
|
{
|
||||||
|
Kind: "Kustomization",
|
||||||
|
Name: testID,
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &alert)).ToNot(HaveOccurred())
|
||||||
|
defer testEnv.Delete(ctx, &alert)
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
nn := types.NamespacedName{Name: provider.Name, Namespace: provider.Namespace}
|
||||||
|
obj := ¬iv1beta2.Provider{}
|
||||||
|
err := testEnv.Get(ctx, nn, obj)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := checkReadyCondition(obj); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
nn = types.NamespacedName{Name: alert.Name, Namespace: alert.Namespace}
|
||||||
|
alertObj := ¬iv1beta2.Alert{}
|
||||||
|
err = testEnv.Get(ctx, nn, alertObj)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := checkReadyCondition(alertObj); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
|
||||||
|
modifyKsSpec := func(spec *kustomizev1.KustomizationSpec) {
|
||||||
|
spec.Interval = metav1.Duration{Duration: 30 * time.Second}
|
||||||
|
spec.HealthChecks = []meta.NamespacedObjectKindReference{
|
||||||
|
{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "ConfigMap",
|
||||||
|
Name: "foobar",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.Expect(setUpFluxConfig(ctx, testID, nsConfig{
|
||||||
|
repoURL: repoUrl,
|
||||||
|
ref: &sourcev1.GitRepositoryRef{
|
||||||
|
Branch: branchName,
|
||||||
|
},
|
||||||
|
path: "./",
|
||||||
|
modifyKsSpec: modifyKsSpec,
|
||||||
|
})).To(Succeed())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := tearDownFluxConfig(ctx, testID)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("failed to delete resources in '%s' namespace: %s", testID, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
err := verifyGitAndKustomization(ctx, testEnv, testID, testID)
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
|
||||||
|
// Wait to read event from notification channel.
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
select {
|
||||||
|
case eventJson := <-cfg.notificationCfg.notificationChan:
|
||||||
|
event := &events.Event{}
|
||||||
|
err := json.Unmarshal([]byte(eventJson), event)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("the received event type does not match Flux format, error: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.InvolvedObject.Kind == kustomizev1.KustomizationKind &&
|
||||||
|
event.InvolvedObject.Name == testID && event.InvolvedObject.Namespace == testID {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, testTimeout, 1*time.Second).Should(BeTrue())
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOCIHelmRelease(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
// Create namespace for test
|
||||||
|
testID := "oci-helm-" + randStringRunes(5)
|
||||||
|
namespace := corev1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &namespace)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &namespace)
|
||||||
|
|
||||||
|
repoURL := fmt.Sprintf("%s/charts/podinfo", cfg.testRegistry)
|
||||||
|
err := pushImagesFromURL(repoURL, "ghcr.io/stefanprodan/charts/podinfo:6.2.0", []string{"6.2.0"})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// Create HelmRepository and wait for it to sync
|
||||||
|
helmRepository := sourcev1.HelmRepository{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: testID, Namespace: testID},
|
||||||
|
Spec: sourcev1.HelmRepositorySpec{
|
||||||
|
URL: fmt.Sprintf("oci://%s", cfg.testRegistry),
|
||||||
|
Interval: metav1.Duration{
|
||||||
|
Duration: 5 * time.Minute,
|
||||||
|
},
|
||||||
|
Provider: infraOpts.Provider,
|
||||||
|
PassCredentials: true,
|
||||||
|
Type: "oci",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Expect(testEnv.Create(ctx, &helmRepository)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &helmRepository)
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
obj := &sourcev1.HelmRepository{}
|
||||||
|
nn := types.NamespacedName{Name: helmRepository.Name, Namespace: helmRepository.Namespace}
|
||||||
|
err := testEnv.Get(ctx, nn, obj)
|
||||||
|
if err != nil {
|
||||||
|
t.Logf("error getting helm repository %s", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := checkReadyCondition(obj); err != nil {
|
||||||
|
t.Logf("%v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
|
||||||
|
// create helm release
|
||||||
|
helmRelease := helmv2.HelmRelease{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: testID, Namespace: testID},
|
||||||
|
Spec: helmv2.HelmReleaseSpec{
|
||||||
|
Chart: helmv2.HelmChartTemplate{
|
||||||
|
Spec: helmv2.HelmChartTemplateSpec{
|
||||||
|
Interval: &metav1.Duration{
|
||||||
|
Duration: 10 * time.Minute,
|
||||||
|
},
|
||||||
|
Chart: "charts/podinfo",
|
||||||
|
Version: "6.2.0",
|
||||||
|
SourceRef: helmv2.CrossNamespaceObjectReference{
|
||||||
|
Kind: sourcev1.HelmRepositoryKind,
|
||||||
|
Name: helmRepository.Name,
|
||||||
|
Namespace: helmRepository.Namespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Expect(testEnv.Create(ctx, &helmRelease)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &helmRelease)
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
chart := &sourcev1.HelmChart{}
|
||||||
|
nn := types.NamespacedName{
|
||||||
|
Name: fmt.Sprintf("%s-%s", helmRelease.Name, helmRelease.Namespace),
|
||||||
|
Namespace: helmRelease.Namespace,
|
||||||
|
}
|
||||||
|
if err := testEnv.Get(ctx, nn, chart); err != nil {
|
||||||
|
t.Logf("error getting helm chart %s\n", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if err := checkReadyCondition(chart); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := &helmv2.HelmRelease{}
|
||||||
|
nn = types.NamespacedName{Name: helmRelease.Name, Namespace: helmRelease.Namespace}
|
||||||
|
if err := testEnv.Get(ctx, nn, obj); err != nil {
|
||||||
|
t.Logf("error getting helm release %s\n", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkReadyCondition(obj); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
"github.com/fluxcd/test-infra/tftestenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestKeyVaultSops(t *testing.T) {
|
||||||
|
g := NewWithT(t)
|
||||||
|
ctx := context.TODO()
|
||||||
|
branchName := "key-vault"
|
||||||
|
testID := branchName + "-" + randStringRunes(5)
|
||||||
|
secretYaml := `apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: "test"
|
||||||
|
stringData:
|
||||||
|
foo: "bar"`
|
||||||
|
|
||||||
|
repoUrl := getTransportURL(cfg.applicationRepository)
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
client, err := getRepository(ctx, tmpDir, repoUrl, defaultBranch, cfg.defaultAuthOpts)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
dir := client.Path() + "/key-vault-sops"
|
||||||
|
g.Expect(os.Mkdir(dir, 0o700)).To(Succeed())
|
||||||
|
|
||||||
|
filename := dir + "secret.enc.yaml"
|
||||||
|
f, err := os.Create(filename)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Write([]byte(secretYaml))
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
g.Expect(f.Sync()).To(Succeed())
|
||||||
|
|
||||||
|
err = tftestenv.RunCommand(ctx, client.Path(),
|
||||||
|
fmt.Sprintf("sops --encrypt --encrypted-regex '^(data|stringData)$' %s --in-place %s", cfg.sopsArgs, filename),
|
||||||
|
tftestenv.RunCommandOptions{})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
r, err := os.Open(filename)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
files["key-vault-sops/secret.enc.yaml"] = r
|
||||||
|
err = commitAndPushAll(ctx, client, files, branchName)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
modifyKsSpec := func(spec *kustomizev1.KustomizationSpec) {
|
||||||
|
spec.Decryption = &kustomizev1.Decryption{
|
||||||
|
Provider: "sops",
|
||||||
|
}
|
||||||
|
if cfg.sopsSecretData != nil {
|
||||||
|
spec.Decryption.SecretRef = &meta.LocalObjectReference{
|
||||||
|
Name: "sops-keys",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = setUpFluxConfig(ctx, testID, nsConfig{
|
||||||
|
ref: &sourcev1.GitRepositoryRef{
|
||||||
|
Branch: branchName,
|
||||||
|
},
|
||||||
|
repoURL: repoUrl,
|
||||||
|
path: "./key-vault-sops",
|
||||||
|
modifyKsSpec: modifyKsSpec,
|
||||||
|
protocol: cfg.defaultGitTransport,
|
||||||
|
})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
t.Cleanup(func() {
|
||||||
|
err := tearDownFluxConfig(ctx, testID)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to delete resources in '%s' namespace", testID)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if cfg.sopsSecretData != nil {
|
||||||
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "sops-keys",
|
||||||
|
Namespace: testID,
|
||||||
|
},
|
||||||
|
StringData: cfg.sopsSecretData,
|
||||||
|
}
|
||||||
|
g.Expect(testEnv.Create(ctx, &secret)).To(Succeed())
|
||||||
|
defer testEnv.Delete(ctx, &secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Eventually(func() bool {
|
||||||
|
err := verifyGitAndKustomization(ctx, testEnv.Client, testID, testID)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
nn := types.NamespacedName{Name: "test", Namespace: testID}
|
||||||
|
secret := &corev1.Secret{}
|
||||||
|
err = testEnv.Get(ctx, nn, secret)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(secret.Data["foo"]) == "bar" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}, testTimeout, testInterval).Should(BeTrue())
|
||||||
|
}
|
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
tfjson "github.com/hashicorp/terraform-json"
|
||||||
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
|
||||||
|
helmv2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||||
|
automationv1beta1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||||
|
reflectorv1beta2 "github.com/fluxcd/image-reflector-controller/api/v1beta2"
|
||||||
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
|
notiv1beta2 "github.com/fluxcd/notification-controller/api/v1beta2"
|
||||||
|
"github.com/fluxcd/pkg/git"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2"
|
||||||
|
"github.com/fluxcd/test-infra/tftestenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// azureTerraformPath is the path to the folder containing the
|
||||||
|
// terraform files for azure infra
|
||||||
|
azureTerraformPath = "./terraform/azure"
|
||||||
|
// gcpTerraformPath is the path to the folder containing the
|
||||||
|
// terraform files for gcp infra
|
||||||
|
gcpTerraformPath = "./terraform/gcp"
|
||||||
|
|
||||||
|
// kubeconfigPath is the path of the file containing the kubeconfig
|
||||||
|
kubeconfigPath = "./build/kubeconfig"
|
||||||
|
|
||||||
|
// default branch to be used when cloning git repositories
|
||||||
|
defaultBranch = "main"
|
||||||
|
|
||||||
|
// envVarGitRepoSSHPath is the environment variable that contains the path
|
||||||
|
// to the ssh key for the git repository
|
||||||
|
envVarGitRepoSSHPath = "GITREPO_SSH_PATH"
|
||||||
|
// envVarGitRepoSSHPubPath is the environment variable that contains the path
|
||||||
|
// to the ssh public key for the git repository
|
||||||
|
envVarGitRepoSSHPubPath = "GITREPO_SSH_PUB_PATH"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// supportedProviders are the providers supported by the test.
|
||||||
|
supportedProviders = []string{"azure", "gcp"}
|
||||||
|
|
||||||
|
// cfg is a struct containing different variables needed for the test.
|
||||||
|
cfg *testConfig
|
||||||
|
|
||||||
|
// infraOpts are the options for running the terraform environment
|
||||||
|
infraOpts tftestenv.Options
|
||||||
|
|
||||||
|
// versions to tag and push for the podinfo image
|
||||||
|
oldPodinfoVersion = "6.0.0"
|
||||||
|
newPodinfoVersion = "6.0.1"
|
||||||
|
podinfoTags = []string{oldPodinfoVersion, newPodinfoVersion}
|
||||||
|
|
||||||
|
// testEnv is the test environment. It contains test infrastructure and
|
||||||
|
// kubernetes client of the created cluster.
|
||||||
|
testEnv *tftestenv.Environment
|
||||||
|
|
||||||
|
// testTimeout is used as a timeout when testing a condition with gomega's eventually
|
||||||
|
testTimeout = 60 * time.Second
|
||||||
|
// testInterval is used as an interval when testing a condition with gomega's eventually
|
||||||
|
testInterval = 5 * time.Second
|
||||||
|
|
||||||
|
random *rand.Rand
|
||||||
|
|
||||||
|
letterRunes = []rune("abcdefghijklmnopqrstuvwxyz1234567890")
|
||||||
|
|
||||||
|
localImg = "ghcr.io/stefanprodan/podinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// testConfig hold different variable that will be needed by the different test functions.
|
||||||
|
type testConfig struct {
|
||||||
|
// authentication info for git repositories
|
||||||
|
gitPat string
|
||||||
|
gitUsername string
|
||||||
|
gitPrivateKey string
|
||||||
|
gitPublicKey string
|
||||||
|
defaultGitTransport git.TransportType
|
||||||
|
defaultAuthOpts *git.AuthOptions
|
||||||
|
knownHosts string
|
||||||
|
fleetInfraRepository gitUrl
|
||||||
|
applicationRepository gitUrl
|
||||||
|
|
||||||
|
// sopsArgs is the cloud provider dependent argument to pass to the sops cli
|
||||||
|
sopsArgs string
|
||||||
|
|
||||||
|
// notificationCfg contains the values needed to properly set up notification on the
|
||||||
|
// cluster.
|
||||||
|
notificationCfg notificationConfig
|
||||||
|
|
||||||
|
// sopsSecretData is the secret's data for the sops decryption
|
||||||
|
sopsSecretData map[string]string
|
||||||
|
// kustomizationYaml is the content of the kustomization.yaml for customizing the Flux manifests
|
||||||
|
kustomizationYaml string
|
||||||
|
|
||||||
|
// testRegistry is the registry of the cloud provider.
|
||||||
|
testRegistry string
|
||||||
|
}
|
||||||
|
|
||||||
|
// notificationConfig contains various fields for configuring
|
||||||
|
// providers and testing notifications for the different
|
||||||
|
// cloud providers.
|
||||||
|
type notificationConfig struct {
|
||||||
|
providerChannel string
|
||||||
|
providerType string
|
||||||
|
providerAddress string
|
||||||
|
secret map[string]string
|
||||||
|
notificationChan chan []byte
|
||||||
|
closeChan func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// gitUrl contains the http/ssh urls for the created git repositories
|
||||||
|
// on the various cloud providers.
|
||||||
|
type gitUrl struct {
|
||||||
|
http string
|
||||||
|
ssh string
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTestConfig gets the test configuration that contains different variables for running the tests
|
||||||
|
type getTestConfig func(ctx context.Context, output map[string]*tfjson.StateOutput) (*testConfig, error)
|
||||||
|
|
||||||
|
// registryLoginFunc is used to perform registry login against a provider based
|
||||||
|
// on the terraform state output values. It returns the test registry
|
||||||
|
// to test against, read from the terraform state output.
|
||||||
|
type registryLoginFunc func(ctx context.Context, output map[string]*tfjson.StateOutput) (string, error)
|
||||||
|
|
||||||
|
// providerConfig contains the test configurations for the different cloud providers
|
||||||
|
type providerConfig struct {
|
||||||
|
terraformPath string
|
||||||
|
createKubeconfig tftestenv.CreateKubeconfig
|
||||||
|
getTestConfig getTestConfig
|
||||||
|
// registryLogin is used to perform registry login.
|
||||||
|
registryLogin registryLoginFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utilruntime.Must(sourcev1.AddToScheme(scheme.Scheme))
|
||||||
|
utilruntime.Must(sourcev1beta2.AddToScheme(scheme.Scheme))
|
||||||
|
utilruntime.Must(kustomizev1.AddToScheme(scheme.Scheme))
|
||||||
|
utilruntime.Must(helmv2beta1.AddToScheme(scheme.Scheme))
|
||||||
|
utilruntime.Must(reflectorv1beta2.AddToScheme(scheme.Scheme))
|
||||||
|
utilruntime.Must(automationv1beta1.AddToScheme(scheme.Scheme))
|
||||||
|
utilruntime.Must(notiv1beta2.AddToScheme(scheme.Scheme))
|
||||||
|
|
||||||
|
random = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
infraOpts.Bindflags(flag.CommandLine)
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Validate the provider.
|
||||||
|
if infraOpts.Provider == "" {
|
||||||
|
log.Fatalf("-provider flag must be set to one of %v", supportedProviders)
|
||||||
|
}
|
||||||
|
var supported bool
|
||||||
|
for _, p := range supportedProviders {
|
||||||
|
if p == infraOpts.Provider {
|
||||||
|
supported = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !supported {
|
||||||
|
log.Fatalf("Unsupported provider %q, must be one of %v", infraOpts.Provider, supportedProviders)
|
||||||
|
}
|
||||||
|
// get provider specific configuration
|
||||||
|
providerCfg := getProviderConfig(infraOpts.Provider)
|
||||||
|
if providerCfg == nil {
|
||||||
|
log.Fatalf("Failed to get provider config for %q", infraOpts.Provider)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with non-zero exit code to indicate failure by default unless
|
||||||
|
// set by a successful test run.
|
||||||
|
exitCode := 1
|
||||||
|
|
||||||
|
// Setup Terraform binary and init state
|
||||||
|
log.Printf("Setting up %s e2e test infrastructure", infraOpts.Provider)
|
||||||
|
envOpts := []tftestenv.EnvironmentOption{
|
||||||
|
tftestenv.WithExisting(infraOpts.Existing),
|
||||||
|
tftestenv.WithRetain(infraOpts.Retain),
|
||||||
|
tftestenv.WithVerbose(infraOpts.Verbose),
|
||||||
|
tftestenv.WithCreateKubeconfig(providerCfg.createKubeconfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create terraform infrastructure
|
||||||
|
var err error
|
||||||
|
testEnv, err = tftestenv.New(ctx, scheme.Scheme, providerCfg.terraformPath, kubeconfigPath, envOpts...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to provision the test infrastructure: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := testEnv.Stop(ctx); err != nil {
|
||||||
|
log.Printf("Failed to stop environment: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the panic error before exit to surface the cause of panic.
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
log.Printf("panic: %v", err)
|
||||||
|
}
|
||||||
|
os.Exit(exitCode)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// get terrraform infrastructure
|
||||||
|
outputs, err := testEnv.StateOutput(ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to get the terraform state output: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// get provider specific test configuration
|
||||||
|
cfg, err = providerCfg.getTestConfig(ctx, outputs)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to get test config: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
regUrl, err := providerCfg.registryLogin(ctx, outputs)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to log into registry: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.testRegistry = regUrl
|
||||||
|
err = pushTestImages(ctx, cfg.testRegistry, podinfoTags)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to push test images: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpDir, err := os.MkdirTemp("", "*-flux-test")
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Failed to create tmp dir: %v", err))
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
err := os.RemoveAll(tmpDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error removing tmp dir: %s\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Println("Installing flux")
|
||||||
|
err = installFlux(ctx, tmpDir, kubeconfigPath)
|
||||||
|
defer func() {
|
||||||
|
log.Println("Uninstalling Flux")
|
||||||
|
if err := uninstallFlux(ctx); err != nil {
|
||||||
|
log.Printf("Failed to uninstall: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("error installing Flux: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Running e2e tests")
|
||||||
|
exitCode = m.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getProviderConfig(provider string) *providerConfig {
|
||||||
|
switch provider {
|
||||||
|
case "azure":
|
||||||
|
return &providerConfig{
|
||||||
|
terraformPath: azureTerraformPath,
|
||||||
|
createKubeconfig: createKubeConfigAKS,
|
||||||
|
getTestConfig: getTestConfigAKS,
|
||||||
|
registryLogin: registryLoginACR,
|
||||||
|
}
|
||||||
|
case "gcp":
|
||||||
|
return &providerConfig{
|
||||||
|
terraformPath: gcpTerraformPath,
|
||||||
|
createKubeconfig: createKubeConfigGKE,
|
||||||
|
getTestConfig: getTestConfigGKE,
|
||||||
|
registryLogin: registryLoginGCR,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushTestImages pushes the local podinfo image to the remote repository specified
|
||||||
|
// by repoURL. The image should be existing on the machine.
|
||||||
|
func pushTestImages(ctx context.Context, repoURL string, tags []string) error {
|
||||||
|
for _, tag := range tags {
|
||||||
|
remoteImg := fmt.Sprintf("%s/podinfo:%s", repoURL, tag)
|
||||||
|
err := tftestenv.RetagAndPush(ctx, fmt.Sprintf("%s:%s", localImg, tag), remoteImg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func randStringRunes(n int) string {
|
||||||
|
b := make([]rune, n)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = letterRunes[random.Intn(len(letterRunes))]
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
module "aks" {
|
||||||
|
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/azure/aks"
|
||||||
|
|
||||||
|
name = local.name
|
||||||
|
location = var.azure_location
|
||||||
|
tags = var.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "acr" {
|
||||||
|
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/azure/acr"
|
||||||
|
|
||||||
|
name = local.name
|
||||||
|
location = var.azure_location
|
||||||
|
aks_principal_id = [module.aks.principal_id]
|
||||||
|
resource_group = module.aks.resource_group
|
||||||
|
admin_enabled = true
|
||||||
|
tags = var.tags
|
||||||
|
|
||||||
|
depends_on = [module.aks]
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
resource "azuredevops_project" "e2e" {
|
||||||
|
name = local.name
|
||||||
|
visibility = "private"
|
||||||
|
version_control = "Git"
|
||||||
|
work_item_template = "Agile"
|
||||||
|
description = "Test Project for Flux E2E test - Managed by Terraform"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "azuredevops_git_repository" "fleet_infra" {
|
||||||
|
project_id = azuredevops_project.e2e.id
|
||||||
|
name = "fleet-infra-${local.name}"
|
||||||
|
default_branch = "refs/heads/main"
|
||||||
|
initialization {
|
||||||
|
init_type = "Clean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azuredevops_git_repository" "application" {
|
||||||
|
project_id = azuredevops_project.e2e.id
|
||||||
|
name = "application-${local.name}"
|
||||||
|
default_branch = "refs/heads/main"
|
||||||
|
initialization {
|
||||||
|
init_type = "Clean"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
resource "azurerm_eventhub_namespace" "this" {
|
||||||
|
name = local.name
|
||||||
|
location = var.azure_location
|
||||||
|
resource_group_name = module.aks.resource_group
|
||||||
|
sku = "Basic"
|
||||||
|
capacity = 1
|
||||||
|
tags = var.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
resource "azurerm_eventhub" "this" {
|
||||||
|
name = local.name
|
||||||
|
namespace_name = azurerm_eventhub_namespace.this.name
|
||||||
|
resource_group_name = module.aks.resource_group
|
||||||
|
partition_count = 1
|
||||||
|
message_retention = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azurerm_eventhub_authorization_rule" "this" {
|
||||||
|
name = local.name
|
||||||
|
resource_group_name = module.aks.resource_group
|
||||||
|
namespace_name = azurerm_eventhub_namespace.this.name
|
||||||
|
eventhub_name = azurerm_eventhub.this.name
|
||||||
|
listen = true
|
||||||
|
send = true
|
||||||
|
manage = false
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
resource "azurerm_key_vault" "this" {
|
||||||
|
name = local.name
|
||||||
|
resource_group_name = module.aks.resource_group
|
||||||
|
location = var.azure_location
|
||||||
|
tenant_id = data.azurerm_client_config.current.tenant_id
|
||||||
|
sku_name = "standard"
|
||||||
|
tags = var.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azurerm_key_vault_access_policy" "admin" {
|
||||||
|
key_vault_id = azurerm_key_vault.this.id
|
||||||
|
tenant_id = data.azurerm_client_config.current.tenant_id
|
||||||
|
object_id = data.azurerm_client_config.current.object_id
|
||||||
|
|
||||||
|
key_permissions = [
|
||||||
|
"Create",
|
||||||
|
"Update",
|
||||||
|
"Encrypt",
|
||||||
|
"Delete",
|
||||||
|
"Get",
|
||||||
|
"List",
|
||||||
|
"Purge",
|
||||||
|
"Recover",
|
||||||
|
"GetRotationPolicy",
|
||||||
|
"SetRotationPolicy"
|
||||||
|
]
|
||||||
|
|
||||||
|
secret_permissions = [
|
||||||
|
"Get",
|
||||||
|
"Delete",
|
||||||
|
"Purge",
|
||||||
|
"Recover"
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azurerm_key_vault_access_policy" "cluster_binding" {
|
||||||
|
key_vault_id = azurerm_key_vault.this.id
|
||||||
|
tenant_id = data.azurerm_client_config.current.tenant_id
|
||||||
|
object_id = module.aks.principal_id
|
||||||
|
|
||||||
|
key_permissions = [
|
||||||
|
"Decrypt",
|
||||||
|
"Encrypt",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "azurerm_key_vault_key" "sops" {
|
||||||
|
depends_on = [azurerm_key_vault_access_policy.admin]
|
||||||
|
|
||||||
|
name = "sops"
|
||||||
|
key_vault_id = azurerm_key_vault.this.id
|
||||||
|
key_type = "RSA"
|
||||||
|
key_size = 2048
|
||||||
|
tags = var.tags
|
||||||
|
|
||||||
|
key_opts = [
|
||||||
|
"decrypt",
|
||||||
|
"encrypt",
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
azurerm = {
|
||||||
|
source = "hashicorp/azurerm"
|
||||||
|
version = ">=3.20.0"
|
||||||
|
}
|
||||||
|
azuread = {
|
||||||
|
source = "hashicorp/azuread"
|
||||||
|
version = ">=2.28.0"
|
||||||
|
}
|
||||||
|
azuredevops = {
|
||||||
|
source = "microsoft/azuredevops"
|
||||||
|
version = ">=0.2.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "azurerm" {
|
||||||
|
features {}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "azuredevops" {
|
||||||
|
org_service_url = "https://dev.azure.com/${var.azuredevops_org}"
|
||||||
|
personal_access_token = var.azuredevops_pat
|
||||||
|
}
|
||||||
|
|
||||||
|
data "azurerm_client_config" "current" {}
|
||||||
|
|
||||||
|
resource "random_pet" "suffix" {
|
||||||
|
separator = "o"
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
name = "e2e${random_pet.suffix.id}"
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
output "aks_kubeconfig" {
|
||||||
|
description = "kubeconfig of the created AKS cluster"
|
||||||
|
value = module.aks.kubeconfig
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
output "azure_devops_access_token" {
|
||||||
|
sensitive = true
|
||||||
|
value = var.azuredevops_pat
|
||||||
|
}
|
||||||
|
|
||||||
|
output "fleet_infra_repository" {
|
||||||
|
value = {
|
||||||
|
http = azuredevops_git_repository.fleet_infra.remote_url
|
||||||
|
ssh = "ssh://git@ssh.dev.azure.com/v3/${var.azuredevops_org}/${azuredevops_git_repository.fleet_infra.project_id}/${azuredevops_git_repository.fleet_infra.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "application_repository" {
|
||||||
|
value = {
|
||||||
|
http = azuredevops_git_repository.application.remote_url
|
||||||
|
ssh = "ssh://git@ssh.dev.azure.com/v3/${var.azuredevops_org}/${azuredevops_git_repository.application.project_id}/${azuredevops_git_repository.application.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "aks_client_id" {
|
||||||
|
value = module.aks.kubelet_client_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "event_hub_sas" {
|
||||||
|
value = azurerm_eventhub_authorization_rule.this.primary_connection_string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
output "sops_id" {
|
||||||
|
value = azurerm_key_vault_key.sops.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "acr_url" {
|
||||||
|
value = module.acr.registry_url
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
variable "azuredevops_org" {
|
||||||
|
type = string
|
||||||
|
description = "Name of Azure DevOps organizations were the repositories will be created"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "azure_location" {
|
||||||
|
type = string
|
||||||
|
description = "Location of the resource group"
|
||||||
|
default = "eastus"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
type = map(string)
|
||||||
|
default = {}
|
||||||
|
description = "Tags for created Azure resources"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "azuredevops_pat" {
|
||||||
|
type = string
|
||||||
|
description = "Personal access token for Azure DevOps repository"
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
module "gke" {
|
||||||
|
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/gcp/gke"
|
||||||
|
|
||||||
|
name = local.name
|
||||||
|
tags = var.tags
|
||||||
|
}
|
||||||
|
|
||||||
|
module "gcr" {
|
||||||
|
source = "git::https://github.com/fluxcd/test-infra.git//tf-modules/gcp/gcr"
|
||||||
|
|
||||||
|
name = local.name
|
||||||
|
tags = var.tags
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
data "google_kms_key_ring" "keyring" {
|
||||||
|
name = var.gcp_keyring
|
||||||
|
location = "global"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "google_kms_crypto_key" "my_crypto_key" {
|
||||||
|
name = var.gcp_crypto_key
|
||||||
|
key_ring = data.google_kms_key_ring.keyring.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_kms_key_ring_iam_binding" "key_ring" {
|
||||||
|
key_ring_id = data.google_kms_key_ring.keyring.id
|
||||||
|
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
|
||||||
|
|
||||||
|
members = [
|
||||||
|
"serviceAccount:${data.google_project.project.number}-compute@developer.gserviceaccount.com",
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
provider "google" {
|
||||||
|
project = var.gcp_project_id
|
||||||
|
region = var.gcp_region
|
||||||
|
zone = var.gcp_zone
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "random_pet" "suffix" {}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
name = "e2e-${random_pet.suffix.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "google_project" "project" {}
|
@ -0,0 +1,32 @@
|
|||||||
|
output "gke_kubeconfig" {
|
||||||
|
value = module.gke.kubeconfig
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
output "gcp_project_id" {
|
||||||
|
value = var.gcp_project_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "gcp_region" {
|
||||||
|
value = var.gcp_region
|
||||||
|
}
|
||||||
|
|
||||||
|
output "artifact_registry_id" {
|
||||||
|
value = module.gcr.artifact_repository_id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "sops_id" {
|
||||||
|
value = data.google_kms_crypto_key.my_crypto_key.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "fleet_infra_repository" {
|
||||||
|
value = "ssh://${var.gcp_email}@source.developers.google.com:2022/p/${var.gcp_project_id}/r/${google_sourcerepo_repository.fleet-infra.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "application_repository" {
|
||||||
|
value = "ssh://${var.gcp_email}@source.developers.google.com:2022/p/${var.gcp_project_id}/r/${google_sourcerepo_repository.application.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
output "pubsub_topic" {
|
||||||
|
value = google_pubsub_topic.pubsub.name
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
resource "google_pubsub_topic" "pubsub" {
|
||||||
|
name = local.name
|
||||||
|
labels = var.tags
|
||||||
|
message_retention_duration = "7200s"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_pubsub_subscription" "sub" {
|
||||||
|
project = var.gcp_project_id
|
||||||
|
name = local.name
|
||||||
|
topic = google_pubsub_topic.pubsub.name
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
resource "google_sourcerepo_repository" "fleet-infra" {
|
||||||
|
name = "fleet-infra-${random_pet.suffix.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_sourcerepo_repository" "application" {
|
||||||
|
name = "application-${random_pet.suffix.id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_sourcerepo_repository_iam_binding" "application_binding" {
|
||||||
|
project = google_sourcerepo_repository.application.project
|
||||||
|
repository = google_sourcerepo_repository.application.name
|
||||||
|
role = "roles/source.admin"
|
||||||
|
members = [
|
||||||
|
"user:${var.gcp_email}",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "google_sourcerepo_repository_iam_binding" "fleet-infra_binding" {
|
||||||
|
project = google_sourcerepo_repository.fleet-infra.project
|
||||||
|
repository = google_sourcerepo_repository.fleet-infra.name
|
||||||
|
role = "roles/source.admin"
|
||||||
|
members = [
|
||||||
|
"user:${var.gcp_email}",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
|||||||
|
variable "gcp_project_id" {
|
||||||
|
type = string
|
||||||
|
description = "GCP project to create the resources in"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "gcp_email" {
|
||||||
|
type = string
|
||||||
|
description = "GCP user email"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "gcp_region" {
|
||||||
|
type = string
|
||||||
|
default = "us-central1"
|
||||||
|
description = "GCP region"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "gcp_zone" {
|
||||||
|
type = string
|
||||||
|
default = "us-central1"
|
||||||
|
description = "GCP zone"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "gcp_keyring" {
|
||||||
|
type = string
|
||||||
|
description = "GCP keyring that contains crypto key for encrypting secrets"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "gcp_crypto_key" {
|
||||||
|
type = string
|
||||||
|
description = "GCP crypto key for encrypting secrets"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "tags" {
|
||||||
|
type = map(string)
|
||||||
|
default = {}
|
||||||
|
description = "tags for created resources"
|
||||||
|
}
|
@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
extgogit "github.com/go-git/go-git/v5"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing"
|
||||||
|
"github.com/go-git/go-git/v5/plumbing/object"
|
||||||
|
"github.com/google/go-containerregistry/pkg/crane"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
kerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
"github.com/fluxcd/pkg/git"
|
||||||
|
"github.com/fluxcd/pkg/git/gogit"
|
||||||
|
"github.com/fluxcd/pkg/git/repository"
|
||||||
|
"github.com/fluxcd/pkg/runtime/conditions"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
"github.com/fluxcd/test-infra/tftestenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// installFlux adds the core Flux components to the cluster specified in the kubeconfig file.
|
||||||
|
func installFlux(ctx context.Context, tmpDir string, kubeconfigPath string) error {
|
||||||
|
// Create flux-system namespace
|
||||||
|
namespace := corev1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "flux-system",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := testEnv.Create(ctx, &namespace)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
repoURL := getTransportURL(cfg.fleetInfraRepository)
|
||||||
|
if cfg.kustomizationYaml != "" {
|
||||||
|
files := make(map[string]io.Reader)
|
||||||
|
files["clusters/e2e/flux-system/kustomization.yaml"] = strings.NewReader(cfg.kustomizationYaml)
|
||||||
|
files["clusters/e2e/flux-system/gotk-components.yaml"] = strings.NewReader("")
|
||||||
|
files["clusters/e2e/flux-system/gotk-sync.yaml"] = strings.NewReader("")
|
||||||
|
c, err := getRepository(ctx, tmpDir, repoURL, defaultBranch, cfg.defaultAuthOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = commitAndPushAll(ctx, c, files, defaultBranch)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bootstrapArgs string
|
||||||
|
if cfg.defaultGitTransport == git.SSH {
|
||||||
|
f, err := os.CreateTemp("", "flux-e2e-ssh-key-*")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.WriteFile(f.Name(), []byte(cfg.gitPrivateKey), 0o644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bootstrapArgs = fmt.Sprintf("--private-key-file=%s -s", f.Name())
|
||||||
|
} else {
|
||||||
|
bootstrapArgs = fmt.Sprintf("--token-auth --password=%s", cfg.gitPat)
|
||||||
|
}
|
||||||
|
|
||||||
|
bootstrapCmd := fmt.Sprintf("./build/flux bootstrap git --url=%s %s --kubeconfig=%s --path=clusters/e2e "+
|
||||||
|
" --components-extra image-reflector-controller,image-automation-controller",
|
||||||
|
repoURL, bootstrapArgs, kubeconfigPath)
|
||||||
|
|
||||||
|
return tftestenv.RunCommand(ctx, "./", bootstrapCmd, tftestenv.RunCommandOptions{
|
||||||
|
Timeout: 15 * time.Minute,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func uninstallFlux(ctx context.Context) error {
|
||||||
|
uninstallCmd := fmt.Sprintf("./build/flux uninstall --kubeconfig %s -s", kubeconfigPath)
|
||||||
|
if err := tftestenv.RunCommand(ctx, "./", uninstallCmd, tftestenv.RunCommandOptions{
|
||||||
|
Timeout: 15 * time.Minute,
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyGitAndKustomization checks that the gitrespository and kustomization combination are working properly.
|
||||||
|
func verifyGitAndKustomization(ctx context.Context, kubeClient client.Client, namespace, name string) error {
|
||||||
|
nn := types.NamespacedName{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
}
|
||||||
|
source := &sourcev1.GitRepository{}
|
||||||
|
if err := kubeClient.Get(ctx, nn, source); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkReadyCondition(source); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kustomization := &kustomizev1.Kustomization{}
|
||||||
|
if err := kubeClient.Get(ctx, nn, kustomization); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := checkReadyCondition(kustomization); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type nsConfig struct {
|
||||||
|
repoURL string
|
||||||
|
ref *sourcev1.GitRepositoryRef
|
||||||
|
protocol git.TransportType
|
||||||
|
objectName string
|
||||||
|
path string
|
||||||
|
modifyKsSpec func(spec *kustomizev1.KustomizationSpec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setUpFluxConfigs creates the namespace, then creates the git secret,
|
||||||
|
// git repository and kustomization in that namespace
|
||||||
|
func setUpFluxConfig(ctx context.Context, name string, opts nsConfig) error {
|
||||||
|
transport := cfg.defaultGitTransport
|
||||||
|
if opts.protocol != "" {
|
||||||
|
transport = opts.protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace := corev1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := testEnv.Create(ctx, &namespace); err != nil && !apierrors.IsAlreadyExists(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "git-credentials",
|
||||||
|
Namespace: name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
secret.StringData = map[string]string{
|
||||||
|
"username": cfg.gitUsername,
|
||||||
|
"password": cfg.gitPat,
|
||||||
|
}
|
||||||
|
|
||||||
|
if transport == git.SSH {
|
||||||
|
secret.StringData = map[string]string{
|
||||||
|
"identity": cfg.gitPrivateKey,
|
||||||
|
"identity.pub": cfg.gitPublicKey,
|
||||||
|
"known_hosts": cfg.knownHosts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := testEnv.Create(ctx, &secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ref := &sourcev1.GitRepositoryRef{
|
||||||
|
Branch: name,
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.ref != nil {
|
||||||
|
ref = opts.ref
|
||||||
|
}
|
||||||
|
|
||||||
|
gitSpec := &sourcev1.GitRepositorySpec{
|
||||||
|
Interval: metav1.Duration{
|
||||||
|
Duration: 1 * time.Minute,
|
||||||
|
},
|
||||||
|
Reference: ref,
|
||||||
|
SecretRef: &meta.LocalObjectReference{
|
||||||
|
Name: secret.Name,
|
||||||
|
},
|
||||||
|
URL: opts.repoURL,
|
||||||
|
}
|
||||||
|
|
||||||
|
source := &sourcev1.GitRepository{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace.Name},
|
||||||
|
Spec: *gitSpec,
|
||||||
|
}
|
||||||
|
if err := testEnv.Create(ctx, source); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ksSpec := &kustomizev1.KustomizationSpec{
|
||||||
|
Path: opts.path,
|
||||||
|
TargetNamespace: name,
|
||||||
|
SourceRef: kustomizev1.CrossNamespaceSourceReference{
|
||||||
|
Kind: sourcev1.GitRepositoryKind,
|
||||||
|
Name: source.Name,
|
||||||
|
Namespace: source.Namespace,
|
||||||
|
},
|
||||||
|
Interval: metav1.Duration{
|
||||||
|
Duration: 1 * time.Minute,
|
||||||
|
},
|
||||||
|
Prune: true,
|
||||||
|
}
|
||||||
|
if opts.modifyKsSpec != nil {
|
||||||
|
opts.modifyKsSpec(ksSpec)
|
||||||
|
}
|
||||||
|
kustomization := &kustomizev1.Kustomization{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace.Name},
|
||||||
|
Spec: *ksSpec,
|
||||||
|
}
|
||||||
|
|
||||||
|
return testEnv.Create(ctx, kustomization)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tearDownFluxConfig(ctx context.Context, name string) error {
|
||||||
|
var allErr []error
|
||||||
|
|
||||||
|
source := &sourcev1.GitRepository{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: name}}
|
||||||
|
if err := testEnv.Delete(ctx, source); err != nil {
|
||||||
|
allErr = append(allErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
kustomization := &kustomizev1.Kustomization{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: name}}
|
||||||
|
if err := testEnv.Delete(ctx, kustomization); err != nil {
|
||||||
|
allErr = append(allErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace := corev1.Namespace{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := testEnv.Delete(ctx, &namespace); err != nil {
|
||||||
|
allErr = append(allErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return kerrors.NewAggregate(allErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRepository and clones the git repository to the directory.
|
||||||
|
func getRepository(ctx context.Context, dir, repoURL, branchName string, authOpts *git.AuthOptions) (*gogit.Client, error) {
|
||||||
|
c, err := gogit.NewClient(dir, authOpts, gogit.WithSingleBranch(false), gogit.WithDiskStorage())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.Clone(ctx, repoURL, repository.CloneConfig{
|
||||||
|
CheckoutStrategy: repository.CheckoutStrategy{
|
||||||
|
Branch: branchName,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// commitAndPushAll checks out to the specified branch, creates the files, commits and then pushes them to
|
||||||
|
// the remote git repository.
|
||||||
|
func commitAndPushAll(ctx context.Context, client *gogit.Client, files map[string]io.Reader, branchName string) error {
|
||||||
|
err := client.SwitchBranch(ctx, branchName)
|
||||||
|
if err != nil && !errors.Is(err, plumbing.ErrReferenceNotFound) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.Commit(git.Commit{
|
||||||
|
Author: git.Signature{
|
||||||
|
Name: git.DefaultPublicKeyAuthUser,
|
||||||
|
Email: "test@example.com",
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
}, repository.WithFiles(files))
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, git.ErrNoStagedFiles) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.Push(ctx, repository.PushConfig{})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to push: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTagAndPush(ctx context.Context, client *gogit.Client, branchName, newTag string) error {
|
||||||
|
repo, err := extgogit.PlainOpen(client.Path())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ref, err := repo.Reference(plumbing.NewBranchReferenceName(branchName), false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, err := repo.TagObjects()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tags.ForEach(func(tag *object.Tag) error {
|
||||||
|
if tag.Name == newTag {
|
||||||
|
err = repo.DeleteTag(tag.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error deleting local tag: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete remote tag
|
||||||
|
if err := client.Push(ctx, repository.PushConfig{
|
||||||
|
Refspecs: []string{fmt.Sprintf(":refs/tags/%s", newTag)},
|
||||||
|
Force: true,
|
||||||
|
}); err != nil && !errors.Is(err, extgogit.NoErrAlreadyUpToDate) {
|
||||||
|
return fmt.Errorf("unable to delete existing tag: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sig := &object.Signature{
|
||||||
|
Name: git.DefaultPublicKeyAuthUser,
|
||||||
|
Email: "test@example.com",
|
||||||
|
When: time.Now(),
|
||||||
|
}
|
||||||
|
if _, err = repo.CreateTag(newTag, ref.Hash(), &extgogit.CreateTagOptions{
|
||||||
|
Tagger: sig,
|
||||||
|
Message: "create tag",
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("unable to create tag: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Push(ctx, repository.PushConfig{
|
||||||
|
Refspecs: []string{"refs/tags/*:refs/tags/*"},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func pushImagesFromURL(repoURL, imgURL string, tags []string) error {
|
||||||
|
img, err := crane.Pull(imgURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tag := range tags {
|
||||||
|
if err := crane.Push(img, fmt.Sprintf("%s:%s", repoURL, tag)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTransportURL(urls gitUrl) string {
|
||||||
|
if cfg.defaultGitTransport == git.SSH {
|
||||||
|
return urls.ssh
|
||||||
|
}
|
||||||
|
|
||||||
|
return urls.http
|
||||||
|
}
|
||||||
|
|
||||||
|
func authOpts(repoURL string, authData map[string][]byte) (*git.AuthOptions, error) {
|
||||||
|
u, err := url.Parse(repoURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return git.NewAuthOptions(*u, authData)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkReadyCondition checks for a Ready condition, it returns nil if the condition is true
|
||||||
|
// or an error (with the message if the Ready condition is present).
|
||||||
|
func checkReadyCondition(from conditions.Getter) error {
|
||||||
|
if conditions.IsReady(from) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
errMsg := fmt.Sprintf("object not ready")
|
||||||
|
readyMsg := conditions.GetMessage(from, meta.ReadyCondition)
|
||||||
|
if readyMsg != "" {
|
||||||
|
errMsg += ": " + readyMsg
|
||||||
|
}
|
||||||
|
return errors.New(errMsg)
|
||||||
|
}
|
Loading…
Reference in New Issue