diff --git a/.circleci/config.yml b/.circleci/config.yml index 283d7d63b..49c181441 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,69 +1,13 @@ version: 2.1 -workflows: - build: - jobs: - - build: - context: - - vault-plugin-secrets-terraform - jobs: build: docker: - - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 - - image: circleci/mongo:latest - environment: - - MONGO_INITDB_ROOT_USERNAME: root - - MONGO_INITDB_ROOT_PASSWORD: mongodb - - MONGO_INITDB_DATABASE: admin - - image: circleci/mysql:latest - environment: - - MYSQL_ROOT_PASSWORD=mysql - - image: hashicorp/vault:latest - environment: - - VAULT_DEV_ROOT_TOKEN_ID=root - - image: mcr.microsoft.com/mssql/server:2017-latest-ubuntu - environment: - - ACCEPT_EULA=Y - - SA_PASSWORD=yourStrong1000Password - working_directory: /tmp/go/src/github.com/hashicorp/terraform-provider-vault + - image: cimg/base:2022.03 steps: - - checkout - - run: - name: Wait for containers to starts - command: dockerize -wait http://127.0.0.1:8200 -wait tcp://127.0.0.1:3306 -wait tcp://127.0.0.1:1433 -timeout 30s - - run: - name: "Set Environment Variables" - command: | - echo 'GO111MODULE=on' >> $BASH_ENV - echo 'export GOBIN=$GOPATH/bin' >> $BASH_ENV - - run: - name: "Run Tests" - no_output_timeout: 30m - command: | - make test TESTARGS='-v' - - run: - name: "Run Acceptance Tests" - no_output_timeout: 35m - command: | - export VAULT_TOKEN="root" - export VAULT_ADDR="http://127.0.0.1:8200" - export TF_ACC_TERRAFORM_VERSION="1.0.7" - export MYSQL_URL="root:mysql@tcp(127.0.0.1:3306)/" - export MYSQL_CONNECTION_URL="{{username}}:{{password}}@tcp(127.0.0.1:3306)/" - export MYSQL_CONNECTION_USERNAME="root" - export MYSQL_CONNECTION_PASSWORD="mysql" - export MONGODB_URL="mongodb://root:mongodb@127.0.0.1:27017/admin?ssl=false" - export MSSQL_URL="sqlserver://sa:yourStrong1000Password@127.0.0.1:1433" - # This will be removed after VAULT-4324 is fixed - make testacc TESTARGS='-v' SKIP_MSSQL_MULTI_CI=true SKIP_RAFT_TESTS=true - - run: - name: "Run Build" - command: | - go build - run: - name: "Generate Coverage Report" + name: "Moved to GitHub Actions" command: | - cd cmd/coverage/ - go build - ./coverage -openapi-doc=/tmp/go/src/github.com/hashicorp/terraform-provider-vault/testdata/openapi.json + sudo apt-get update && sudo apt-get install -y figlet + figlet 'Moved to GitHub Actions' + echo 'See https://github.com/hashicorp/terraform-provider-vault/actions' diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..90e8d7f30 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,79 @@ +name: Build + +on: push + +jobs: + go-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.go-version.outputs.version }} + steps: + - uses: actions/checkout@v3 + - id: go-version + run: echo "::set-output name=version::$(cat ./.go-version)" + build: + needs: [go-version] + runs-on: ubuntu-latest + container: + image: "docker.mirror.hashicorp.services/golang:${{ needs.go-version.outputs.version }}" + steps: + - uses: actions/checkout@v3 + - name: Build + run: | + make build + acceptance: + needs: [go-version, build] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # TODO: enable 1.9 job once the provider is Vault version aware + #image: ["vault-enterprise:1.9-ent", "vault-enterprise:1.10-ent"] + image: ["vault-enterprise:1.10-ent"] + container: + image: "docker.mirror.hashicorp.services/golang:${{ needs.go-version.outputs.version }}" + services: + vault: + image: hashicorp/${{ matrix.image }} + env: + VAULT_DEV_ROOT_TOKEN_ID: root + VAULT_LICENSE: ${{ secrets.VAULT_LICENSE }} + mysql: + image: docker.mirror.hashicorp.services/mysql:latest + env: + MYSQL_ROOT_PASSWORD: mysql + mssql: + image: mcr.microsoft.com/mssql/server:2017-latest-ubuntu + env: + ACCEPT_EULA: Y + SA_PASSWORD: ${{ secrets.MSSQL_SA_PASSWORD }} + mongo: + image: docker.mirror.hashicorp.services/mongo:latest + env: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: mongodb + MONGO_INITDB_DATABASE: admin + postgres: + image: docker.mirror.hashicorp.services/postgres:latest + env: + POSTGRES_PASSWORD: secret + POSTGRES_DB: database + steps: + - uses: actions/checkout@v3 + - name: Acceptance Tests + env: + VAULT_TOKEN: "root" + VAULT_ADDR: "http://vault:8200" + TF_ACC_TERRAFORM_VERSION: "1.0.7" + MYSQL_URL: "root:mysql@tcp(mysql:3306)/" + MYSQL_CONNECTION_URL: "{{username}}:{{password}}@tcp(mysql:3306)/" + MYSQL_CONNECTION_USERNAME: "root" + MYSQL_CONNECTION_PASSWORD: "mysql" + MONGODB_URL: "mongodb://root:mongodb@mongo:27017/admin?ssl=false" + MSSQL_URL: "sqlserver://sa:${{ secrets.MSSQL_SA_PASSWORD }}@mssql:1433" + POSTGRES_URL: "postgres://postgres:secret@postgres:5432/database?sslmode=disable" + run: | + make testacc-ent TESTARGS='-v' SKIP_MSSQL_MULTI_CI=true SKIP_RAFT_TESTS=true + - name: "Generate Vault API Path Coverage Report" + run: | + go run cmd/coverage/main.go -openapi-doc=./testdata/openapi.json diff --git a/.go-version b/.go-version index ff278344b..ada2e4fce 100644 --- a/.go-version +++ b/.go-version @@ -1 +1 @@ -1.17.5 +1.17.10 diff --git a/GNUmakefile b/Makefile similarity index 100% rename from GNUmakefile rename to Makefile diff --git a/codegen/generate.go b/codegen/generate.go index 0889f08ce..072ada3b2 100644 --- a/codegen/generate.go +++ b/codegen/generate.go @@ -2,9 +2,11 @@ package codegen import ( "bufio" + "bytes" "errors" "fmt" "os" + "os/exec" "path/filepath" "strings" @@ -14,7 +16,7 @@ import ( // generatedDirPerms uses 0775 because it is the same as for // the "vault" directory, which is at "drwxrwxr-x". -const generatedDirPerms os.FileMode = 0775 +const generatedDirPerms os.FileMode = 0o775 var errUnsupported = errors.New("code and doc generation for this item is unsupported") @@ -172,11 +174,11 @@ we eventually cover all >500 of them and add tests. */ func codeFilePath(tfTp tfType, endpoint string) (string, error) { filename := fmt.Sprintf("%ss%s.go", tfTp.String(), endpoint) - homeDirPath, err := pathToHomeDir() + repoRoot, err := getRepoRoot() if err != nil { return "", err } - path := filepath.Join(homeDirPath, "generated", filename) + path := filepath.Join(repoRoot, "generated", filename) return stripCurlyBraces(path), nil } @@ -211,11 +213,11 @@ we eventually cover all >500 of them and add tests. func docFilePath(tfTp tfType, endpoint string) (string, error) { endpoint = normalizeDocEndpoint(endpoint) filename := fmt.Sprintf("%s/%s.html.md", tfTp.DocType(), endpoint) - homeDirPath, err := pathToHomeDir() + repoRoot, err := getRepoRoot() if err != nil { return "", err } - return filepath.Join(homeDirPath, "website", "docs", filename), nil + return filepath.Join(repoRoot, "website", "docs", filename), nil } // normalizeDocEndpoint changes the raw endpoint into the format we expect for @@ -248,15 +250,12 @@ func stripCurlyBraces(path string) string { return path } -// pathToHomeDir yields the path to the terraform-vault-provider -// home directory on the machine on which it's running. -// ex. /home/your-name/go/src/github.com/hashicorp/terraform-provider-vault -func pathToHomeDir() (string, error) { - repoName := "terraform-provider-vault" - wd, err := os.Getwd() +// getRepoRoot relative to CWD. +func getRepoRoot() (string, error) { + out, err := exec.Command("git", "rev-parse", "--show-toplevel").Output() if err != nil { return "", err } - pathParts := strings.Split(wd, repoName) - return pathParts[0] + repoName, nil + + return string(bytes.TrimRight(out, "\n")), nil } diff --git a/codegen/generate_test.go b/codegen/generate_test.go index d303ba786..3a8e76828 100644 --- a/codegen/generate_test.go +++ b/codegen/generate_test.go @@ -5,7 +5,7 @@ import ( ) func TestCodeFilePath(t *testing.T) { - homeDirPath, err := pathToHomeDir() + repoRoot, err := getRepoRoot() if err != nil { t.Fatal(err) } @@ -45,21 +45,21 @@ func TestCodeFilePath(t *testing.T) { if err != nil { t.Fatal(err) } - if actualDataSourceFilePath != homeDirPath+testCase.expectedDataSourceFilePath { - t.Fatalf("expected %q but received %q", homeDirPath+testCase.expectedDataSourceFilePath, actualDataSourceFilePath) + if actualDataSourceFilePath != repoRoot+testCase.expectedDataSourceFilePath { + t.Fatalf("expected %q but received %q", repoRoot+testCase.expectedDataSourceFilePath, actualDataSourceFilePath) } actualResourceFilePath, err := codeFilePath(tfTypeResource, testCase.input) if err != nil { t.Fatal(err) } - if actualResourceFilePath != homeDirPath+testCase.expectedResourceFilePath { - t.Fatalf("expected %q but received %q", homeDirPath+testCase.expectedResourceFilePath, actualResourceFilePath) + if actualResourceFilePath != repoRoot+testCase.expectedResourceFilePath { + t.Fatalf("expected %q but received %q", repoRoot+testCase.expectedResourceFilePath, actualResourceFilePath) } } } func TestDocFilePath(t *testing.T) { - homeDirPath, err := pathToHomeDir() + repoRoot, err := getRepoRoot() if err != nil { t.Fatal(err) } @@ -95,15 +95,15 @@ func TestDocFilePath(t *testing.T) { if err != nil { t.Fatal(err) } - if actualDataSourceDocPath != homeDirPath+testCase.expectedDataSourceFilePath { - t.Fatalf("expected %q but received %q", homeDirPath+testCase.expectedDataSourceFilePath, actualDataSourceDocPath) + if actualDataSourceDocPath != repoRoot+testCase.expectedDataSourceFilePath { + t.Fatalf("expected %q but received %q", repoRoot+testCase.expectedDataSourceFilePath, actualDataSourceDocPath) } actualResourceDocPath, err := docFilePath(tfTypeResource, testCase.input) if err != nil { t.Fatal(err) } - if actualResourceDocPath != homeDirPath+testCase.expectedResourceFilePath { - t.Fatalf("expected %q but received %q", homeDirPath+testCase.expectedResourceFilePath, actualResourceDocPath) + if actualResourceDocPath != repoRoot+testCase.expectedResourceFilePath { + t.Fatalf("expected %q but received %q", repoRoot+testCase.expectedResourceFilePath, actualResourceDocPath) } } } diff --git a/codegen/templates.go b/codegen/templates.go index 5c6764f49..d068de146 100644 --- a/codegen/templates.go +++ b/codegen/templates.go @@ -35,7 +35,7 @@ var ( ) func newTemplateHandler(logger hclog.Logger) (*templateHandler, error) { - homeDirPath, err := pathToHomeDir() + repoRoot, err := getRepoRoot() if err != nil { return nil, err } @@ -44,7 +44,7 @@ func newTemplateHandler(logger hclog.Logger) (*templateHandler, error) { // cache them to be used repeatedly. templates := make(map[templateType]*template.Template, len(templateRegistry)) for tmplType, pathFromHomeDir := range templateRegistry { - pathToFile := filepath.Join(homeDirPath, pathFromHomeDir) + pathToFile := filepath.Join(repoRoot, pathFromHomeDir) templateBytes, err := ioutil.ReadFile(pathToFile) if err != nil { return nil, errwrap.Wrapf("error reading "+pathToFile+": {{err}}", err) diff --git a/generated/resources/transform/template/name_test.go b/generated/resources/transform/template/name_test.go index 3413aa0b9..d7529f04e 100644 --- a/generated/resources/transform/template/name_test.go +++ b/generated/resources/transform/template/name_test.go @@ -65,7 +65,7 @@ func TestTemplateName(t *testing.T) { resource.TestCheckResourceAttr("vault_transform_template_name.test", "pattern", `(\d{9})`), resource.TestCheckResourceAttr("vault_transform_template_name.test", "alphabet", "builtin/numeric"), resource.TestCheckResourceAttr("vault_transform_template_name.test", "encode_format", ""), - resource.TestCheckNoResourceAttr("vault_transform_template_name.test", "decode_formats"), + resource.TestCheckResourceAttr("vault_transform_template_name.test", "decode_formats.#", "0"), ), }, { diff --git a/go.mod b/go.mod index 3f139084e..79909f2df 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect github.com/aws/aws-sdk-go v1.41.8 github.com/containerd/containerd v1.6.2 // indirect + github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f github.com/denisenkom/go-mssqldb v0.11.0 github.com/docker/distribution v2.8.1+incompatible // indirect github.com/go-sql-driver/mysql v1.6.0 diff --git a/go.sum b/go.sum index 3966f7909..8b1c66ad8 100644 --- a/go.sum +++ b/go.sum @@ -454,6 +454,7 @@ github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+ github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/couchbase/gocb/v2 v2.3.3/go.mod h1:h4b3UYDnGI89hMW9VypVjAr+EE0Ki4jjlXJrVdmSZhQ= github.com/couchbase/gocbcore/v10 v10.0.4/go.mod h1:s6dwBFs4c3+cAzZbo1q0VW+QasudhHJuehE8b8U2YNg= diff --git a/testutil/testutil.go b/testutil/testutil.go index 96da012ad..54fd43871 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -11,6 +11,7 @@ import ( "reflect" "testing" + "github.com/coreos/pkg/multierror" "github.com/hashicorp/go-retryablehttp" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -289,3 +290,42 @@ func TestHTTPServer(t *testing.T, handler http.Handler) (*api.Config, net.Listen return config, ln } + +func GetDynamicTCPListeners(host string, count int) ([]net.Listener, func() error, error) { + _, p, err := net.SplitHostPort(host) + if err != nil { + pErr := err.(*net.AddrError) + if pErr.Err != "missing port in address" { + return nil, nil, err + } + } + if p != "" { + return nil, nil, fmt.Errorf("host %q contains a port", host) + } + + addr := host + ":0" + listeners := make([]net.Listener, count) + for i := 0; i < count; i++ { + ln, err := net.Listen("tcp", addr) + if err != nil { + return nil, nil, err + } + listeners[i] = ln + } + + closer := func() error { + errs := multierror.Error{} + for _, ln := range listeners { + if err := ln.Close(); err != nil { + errs = append(errs, err) + } + } + + if len(errs) > 0 { + return errs + } + return nil + } + + return listeners, closer, nil +} diff --git a/vault/data_identity_oidc_openid_config_test.go b/vault/data_identity_oidc_openid_config_test.go index 7a0d135ce..a01d3152d 100644 --- a/vault/data_identity_oidc_openid_config_test.go +++ b/vault/data_identity_oidc_openid_config_test.go @@ -4,6 +4,7 @@ import ( "fmt" "net/url" "os" + "strings" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -13,52 +14,63 @@ import ( ) func TestDataSourceIdentityOIDCOpenIDConfig(t *testing.T) { + testutil.SkipTestAcc(t) + testutil.TestAccPreCheck(t) + providerName := acctest.RandomWithPrefix("test-provider") keyName := acctest.RandomWithPrefix("test-key") clientName := acctest.RandomWithPrefix("test-client") - resourceName := "data.vault_identity_oidc_openid_config.config" - vaultAddrEnv := os.Getenv("VAULT_ADDR") - parsedUrl, err := url.Parse(vaultAddrEnv) + u, err := url.Parse(os.Getenv("VAULT_ADDR")) + if err != nil { + t.Fatal(err) + } + + if u.Hostname() == "localhost" { + u.Host = fmt.Sprintf("%s:%s", "127.0.0.1", u.Port()) + } + + base, err := u.Parse(fmt.Sprintf("/v1/identity/oidc/provider/%s/", providerName)) if err != nil { t.Fatal(err) } - host := parsedUrl.Host - if host == "localhost:8200" { - host = "127.0.0.1:8200" + resourceName := "data.vault_identity_oidc_openid_config.config" + checks := []resource.TestCheckFunc{ + resource.TestCheckResourceAttr(resourceName, "name", providerName), + resource.TestCheckResourceAttr(resourceName, "issuer", strings.TrimRight(base.String(), "/")), + resource.TestCheckResourceAttr(resourceName, "request_uri_parameter_supported", "false"), + resource.TestCheckResourceAttr(resourceName, "id_token_signing_alg_values_supported.#", "7"), + resource.TestCheckResourceAttr(resourceName, "scopes_supported.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scopes_supported.0", "openid"), } - issuer := "http://%s/v1/identity/oidc/provider/%s" - jwksURI := "http://%s/v1/identity/oidc/provider/%s/.well-known/keys" - authorizationEndpoint := "http://%s/ui/vault/identity/oidc/provider/%s/authorize" - tokenEndpoint := "http://%s/v1/identity/oidc/provider/%s/token" - userInfoEndpoint := "http://%s/v1/identity/oidc/provider/%s/userinfo" + expectedURLs := map[string]string{ + "jwks_uri": ".well-known/keys", + "token_endpoint": "token", + "userinfo_endpoint": "userinfo", + "authorization_endpoint": fmt.Sprintf("/ui/vault/identity/oidc/provider/%s/authorize", providerName), + } + for k, v := range expectedURLs { + i, err := base.Parse(v) + if err != nil { + t.Fatal(err) + } + checks = append(checks, resource.TestCheckResourceAttr(resourceName, k, i.String())) + } resource.Test(t, resource.TestCase{ Providers: testProviders, - PreCheck: func() { testutil.TestAccPreCheck(t) }, Steps: []resource.TestStep{ { - Config: testDataSourceIdentityOIDCOpenIDConfig_config(keyName, clientName, providerName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "name", providerName), - resource.TestCheckResourceAttr(resourceName, "issuer", fmt.Sprintf(issuer, host, providerName)), - resource.TestCheckResourceAttr(resourceName, "jwks_uri", fmt.Sprintf(jwksURI, host, providerName)), - resource.TestCheckResourceAttr(resourceName, "authorization_endpoint", fmt.Sprintf(authorizationEndpoint, host, providerName)), - resource.TestCheckResourceAttr(resourceName, "token_endpoint", fmt.Sprintf(tokenEndpoint, host, providerName)), - resource.TestCheckResourceAttr(resourceName, "userinfo_endpoint", fmt.Sprintf(userInfoEndpoint, host, providerName)), - resource.TestCheckResourceAttr(resourceName, "request_uri_parameter_supported", "false"), - resource.TestCheckResourceAttr(resourceName, "id_token_signing_alg_values_supported.#", "7"), - resource.TestCheckResourceAttr(resourceName, "scopes_supported.#", "1"), - resource.TestCheckResourceAttr(resourceName, "scopes_supported.0", "openid"), - ), + Config: testDataSourceIdentityOIDCOpenIDConfig_config(keyName, clientName, providerName, u.Host), + Check: resource.ComposeTestCheckFunc(checks...), }, }, }) } -func testDataSourceIdentityOIDCOpenIDConfig_config(keyName, clientName, providerName string) string { +func testDataSourceIdentityOIDCOpenIDConfig_config(keyName, clientName, providerName, issuerHost string) string { return fmt.Sprintf(` resource "vault_identity_oidc_key" "key" { name = "%s" @@ -68,27 +80,30 @@ resource "vault_identity_oidc_key" "key" { } resource "vault_identity_oidc_client" "app" { - name = "%s" - key = vault_identity_oidc_key.key.name - redirect_uris = [ - "http://127.0.0.1:9200/v1/auth-methods/oidc:authenticate:callback", - "http://127.0.0.1:8251/callback", - "http://127.0.0.1:8080/callback" - ] + name = "%s" + key = vault_identity_oidc_key.key.name id_token_ttl = 2400 access_token_ttl = 7200 + + redirect_uris = [ + "http://127.0.0.1:9200/v1/auth-methods/oidc:authenticate:callback", + "http://127.0.0.1:8251/callback", + "http://127.0.0.1:8080/callback" + ] } resource "vault_identity_oidc_provider" "test" { - name = "%s" + name = "%s" https_enabled = false - issuer_host = "127.0.0.1:8200" + issuer_host = "%s" + allowed_client_ids = [ - vault_identity_oidc_client.app.client_id + vault_identity_oidc_client.app.client_id ] } data "vault_identity_oidc_openid_config" "config" { name = vault_identity_oidc_provider.test.name -}`, keyName, clientName, providerName) +} +`, keyName, clientName, providerName, issuerHost) } diff --git a/vault/resource_database_secret_backend_connection.go b/vault/resource_database_secret_backend_connection.go index 89cba15f5..4f56add6c 100644 --- a/vault/resource_database_secret_backend_connection.go +++ b/vault/resource_database_secret_backend_connection.go @@ -482,6 +482,7 @@ func getDatabaseSchema(typ schema.ValueType) schemaMap { Description: "Connection parameters for the hana-database-plugin plugin.", Elem: connectionStringResource(&connectionStringConfig{ excludeUsernameTemplate: true, + includeDisableEscaping: true, includeUserPass: true, }), MaxItems: 1, @@ -538,7 +539,8 @@ func getDatabaseSchema(typ schema.ValueType) schemaMap { Optional: true, Description: "Connection parameters for the postgresql-database-plugin plugin.", Elem: connectionStringResource(&connectionStringConfig{ - includeUserPass: true, + includeUserPass: true, + includeDisableEscaping: true, }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEnginePostgres.Name(), dbEngineTypes), @@ -558,7 +560,8 @@ func getDatabaseSchema(typ schema.ValueType) schemaMap { Optional: true, Description: "Connection parameters for the redshift-database-plugin plugin.", Elem: connectionStringResource(&connectionStringConfig{ - includeUserPass: true, + includeUserPass: true, + includeDisableEscaping: true, }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineRedshift.Name(), dbEngineTypes), @@ -1500,7 +1503,8 @@ func getDBCommonConfig(d *schema.ResourceData, resp *api.Secret, } func getDBConnectionConfig(d *schema.ResourceData, engine *dbEngine, idx int, - resp *api.Secret) (map[string]interface{}, error) { + resp *api.Secret, +) (map[string]interface{}, error) { var result map[string]interface{} prefix := engine.ResourcePrefix(idx) diff --git a/vault/resource_database_secret_backend_connection_test.go b/vault/resource_database_secret_backend_connection_test.go index 8ca4af264..f7fa5f231 100644 --- a/vault/resource_database_secret_backend_connection_test.go +++ b/vault/resource_database_secret_backend_connection_test.go @@ -30,7 +30,7 @@ const testDefaultDatabaseSecretBackendResource = "vault_database_secret_backend_ // Currently we have to configure the Vault server with a plugin_directory, // copy/build a db plugin and install it with a unique name, then register it in vault. -func TestAccDatabaseSecretBackendConnection_import(t *testing.T) { +func TestAccDatabaseSecretBackendConnection_postgresql_import(t *testing.T) { MaybeSkipDBTests(t, dbEnginePostgres) // TODO: make these fatal once we auto provision the required test infrastructure. diff --git a/vault/resource_kmip_secret_backend.go b/vault/resource_kmip_secret_backend.go index 5d29a7200..32e560178 100644 --- a/vault/resource_kmip_secret_backend.go +++ b/vault/resource_kmip_secret_backend.go @@ -3,6 +3,7 @@ package vault import ( "fmt" "log" + "time" "github.com/hashicorp/terraform-provider-vault/util" @@ -133,17 +134,39 @@ func kmipSecretBackendUpdate(d *schema.ResourceData, meta interface{}) error { path := d.Id() if !d.IsNewResource() && d.HasChange("path") { - newPath := d.Get("path").(string) + src := path + dest := d.Get("path").(string) - log.Printf("[DEBUG] Remount %s to %s in Vault", path, newPath) + log.Printf("[DEBUG] Remount %s to %s in Vault", src, dest) - err := client.Sys().Remount(path, newPath) + err := client.Sys().Remount(src, dest) if err != nil { return fmt.Errorf("error remounting in Vault: %s", err) } - d.SetId(newPath) - path = newPath + // There is something similar in resource_mount.go, but in the call to TuneMount(). + var tries int + for { + if tries > 10 { + return fmt.Errorf( + "mount %q did did not become available after %d tries, interval=1s", dest, tries) + } + + enabled, err := util.CheckMountEnabled(client, dest) + if err != nil { + return err + } + if !enabled { + tries++ + time.Sleep(1 * time.Second) + continue + } + + break + } + + path = dest + d.SetId(path) } log.Printf("[DEBUG] Updating mount %s in Vault", path) diff --git a/vault/resource_kmip_secret_backend_test.go b/vault/resource_kmip_secret_backend_test.go index c155dbe0b..49bb65d0a 100644 --- a/vault/resource_kmip_secret_backend_test.go +++ b/vault/resource_kmip_secret_backend_test.go @@ -2,7 +2,6 @@ package vault import ( "fmt" - "net" "strings" "testing" @@ -15,23 +14,21 @@ import ( ) func TestAccKMIPSecretBackend_basic(t *testing.T) { + testutil.SkipTestAccEnt(t) + path := acctest.RandomWithPrefix("tf-test-kmip") resourceName := "vault_kmip_secret_backend.test" - ln1, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } - ln2, err := net.Listen("tcp", "127.0.0.1:0") + lns, closer, err := testutil.GetDynamicTCPListeners("127.0.0.1", 2) if err != nil { t.Fatal(err) } - addr1 := ln1.Addr().String() - addr2 := ln2.Addr().String() + addr1, addr2 := lns[0].Addr().String(), lns[1].Addr().String() - ln1.Close() - ln2.Close() + if err = closer(); err != nil { + t.Fatal(err) + } resource.Test(t, resource.TestCase{ Providers: testProviders, @@ -44,7 +41,7 @@ func TestAccKMIPSecretBackend_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "listen_addrs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "listen_addrs.0", addr1), + resource.TestCheckTypeSetElemAttr(resourceName, "listen_addrs.*", addr1), resource.TestCheckResourceAttr(resourceName, "server_ips.#", "1"), resource.TestCheckResourceAttr(resourceName, "server_ips.0", "127.0.0.1"), resource.TestCheckResourceAttr(resourceName, "tls_ca_key_type", "ec"), @@ -61,8 +58,8 @@ func TestAccKMIPSecretBackend_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "listen_addrs.#", "2"), - resource.TestCheckResourceAttr(resourceName, "listen_addrs.0", addr1), - resource.TestCheckResourceAttr(resourceName, "listen_addrs.1", addr2), + resource.TestCheckTypeSetElemAttr(resourceName, "listen_addrs.*", addr1), + resource.TestCheckTypeSetElemAttr(resourceName, "listen_addrs.*", addr2), resource.TestCheckResourceAttr(resourceName, "server_ips.#", "2"), resource.TestCheckResourceAttr(resourceName, "server_ips.0", "127.0.0.1"), resource.TestCheckResourceAttr(resourceName, "server_ips.1", "192.168.1.1"), @@ -79,18 +76,22 @@ func TestAccKMIPSecretBackend_basic(t *testing.T) { } func TestAccKMIPSecretBackend_remount(t *testing.T) { + testutil.SkipTestAccEnt(t) + path := acctest.RandomWithPrefix("tf-test-kmip") remountPath := acctest.RandomWithPrefix("tf-test-kmip-updated") resourceName := "vault_kmip_secret_backend.test" - ln1, err := net.Listen("tcp", "127.0.0.1:0") + lns, closer, err := testutil.GetDynamicTCPListeners("127.0.0.1", 1) if err != nil { t.Fatal(err) } - addr1 := ln1.Addr().String() + addr1 := lns[0].Addr().String() - ln1.Close() + if err = closer(); err != nil { + t.Fatal(err) + } resource.Test(t, resource.TestCase{ Providers: testProviders, @@ -103,7 +104,7 @@ func TestAccKMIPSecretBackend_remount(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "listen_addrs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "listen_addrs.0", addr1), + resource.TestCheckTypeSetElemAttr(resourceName, "listen_addrs.*", addr1), resource.TestCheckResourceAttr(resourceName, "server_ips.#", "1"), resource.TestCheckResourceAttr(resourceName, "server_ips.0", "127.0.0.1"), resource.TestCheckResourceAttr(resourceName, "tls_ca_key_type", "ec"), @@ -120,7 +121,7 @@ func TestAccKMIPSecretBackend_remount(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "path", remountPath), resource.TestCheckResourceAttr(resourceName, "description", "test description"), resource.TestCheckResourceAttr(resourceName, "listen_addrs.#", "1"), - resource.TestCheckResourceAttr(resourceName, "listen_addrs.0", addr1), + resource.TestCheckTypeSetElemAttr(resourceName, "listen_addrs.*", addr1), resource.TestCheckResourceAttr(resourceName, "server_ips.#", "1"), resource.TestCheckResourceAttr(resourceName, "server_ips.0", "127.0.0.1"), resource.TestCheckResourceAttr(resourceName, "tls_ca_key_type", "ec"), diff --git a/vault/resource_kmip_secret_role_test.go b/vault/resource_kmip_secret_role_test.go index f693cf05b..a7d585c97 100644 --- a/vault/resource_kmip_secret_role_test.go +++ b/vault/resource_kmip_secret_role_test.go @@ -14,15 +14,29 @@ import ( ) func TestAccKMIPSecretRole_basic(t *testing.T) { + testutil.SkipTestAccEnt(t) + path := acctest.RandomWithPrefix("tf-test-kmip") resourceName := "vault_kmip_secret_role.test" + + lns, closer, err := testutil.GetDynamicTCPListeners("127.0.0.1", 1) + if err != nil { + t.Fatal(err) + } + + if err = closer(); err != nil { + t.Fatal(err) + } + + addr1 := lns[0].Addr().String() + resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestEntPreCheck(t) }, CheckDestroy: testAccKMIPSecretRoleCheckDestroy, Steps: []resource.TestStep{ { - Config: testKMIPSecretRole_initialConfig(path), + Config: testKMIPSecretRole_initialConfig(path, addr1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "scope", "scope-1"), @@ -46,7 +60,7 @@ func TestAccKMIPSecretRole_basic(t *testing.T) { ), }, { - Config: testKMIPSecretRole_updatedConfig(path), + Config: testKMIPSecretRole_updatedConfig(path, addr1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "scope", "scope-1"), @@ -74,6 +88,19 @@ func TestAccKMIPSecretRole_basic(t *testing.T) { } func TestAccKMIPSecretRole_remount(t *testing.T) { + testutil.SkipTestAccEnt(t) + + lns, closer, err := testutil.GetDynamicTCPListeners("127.0.0.1", 1) + if err != nil { + t.Fatal(err) + } + + if err = closer(); err != nil { + t.Fatal(err) + } + + addr1 := lns[0].Addr().String() + path := acctest.RandomWithPrefix("tf-test-kmip") remountPath := acctest.RandomWithPrefix("tf-test-kmip-remount") resourceName := "vault_kmip_secret_role.test" @@ -83,7 +110,7 @@ func TestAccKMIPSecretRole_remount(t *testing.T) { CheckDestroy: testAccKMIPSecretRoleCheckDestroy, Steps: []resource.TestStep{ { - Config: testKMIPSecretRole_initialConfig(path), + Config: testKMIPSecretRole_initialConfig(path, addr1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "scope", "scope-1"), @@ -107,7 +134,7 @@ func TestAccKMIPSecretRole_remount(t *testing.T) { ), }, { - Config: testKMIPSecretRole_initialConfig(remountPath), + Config: testKMIPSecretRole_initialConfig(remountPath, addr1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "path", remountPath), resource.TestCheckResourceAttr(resourceName, "scope", "scope-1"), @@ -159,10 +186,11 @@ func testAccKMIPSecretRoleCheckDestroy(s *terraform.State) error { return nil } -func testKMIPSecretRole_initialConfig(path string) string { +func testKMIPSecretRole_initialConfig(path string, listenAddr string) string { return fmt.Sprintf(` resource "vault_kmip_secret_backend" "kmip" { path = "%s" + listen_addrs = ["%s"] description = "test description" } @@ -181,13 +209,14 @@ resource "vault_kmip_secret_role" "test" { operation_get = true operation_get_attributes = true } -`, path) +`, path, listenAddr) } -func testKMIPSecretRole_updatedConfig(path string) string { +func testKMIPSecretRole_updatedConfig(path string, listenAddr string) string { return fmt.Sprintf(` resource "vault_kmip_secret_backend" "kmip" { path = "%s" + listen_addrs = ["%s"] description = "test description" } @@ -209,5 +238,5 @@ resource "vault_kmip_secret_role" "test" { operation_create = true operation_destroy = true } -`, path) +`, path, listenAddr) } diff --git a/vault/resource_kmip_secret_scope_test.go b/vault/resource_kmip_secret_scope_test.go index 79978a0f9..de3fe02d6 100644 --- a/vault/resource_kmip_secret_scope_test.go +++ b/vault/resource_kmip_secret_scope_test.go @@ -14,23 +14,36 @@ import ( ) func TestAccKMIPSecretScope_remount(t *testing.T) { + testutil.SkipTestAccEnt(t) + path := acctest.RandomWithPrefix("tf-test-kmip") remountPath := acctest.RandomWithPrefix("tf-test-kmip-updated") resourceName := "vault_kmip_secret_scope.test" + + lns, closer, err := testutil.GetDynamicTCPListeners("127.0.0.1", 1) + if err != nil { + t.Fatal(err) + } + + if err = closer(); err != nil { + t.Fatal(err) + } + + addr1 := lns[0].Addr().String() resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestEntPreCheck(t) }, CheckDestroy: testAccKMIPSecretScopeCheckDestroy, Steps: []resource.TestStep{ { - Config: testKMIPSecretScope_initialConfig(path), + Config: testKMIPSecretScope_initialConfig(path, addr1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "path", path), resource.TestCheckResourceAttr(resourceName, "scope", "test"), ), }, { - Config: testKMIPSecretScope_initialConfig(remountPath), + Config: testKMIPSecretScope_initialConfig(remountPath, addr1), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "path", remountPath), resource.TestCheckResourceAttr(resourceName, "scope", "test"), @@ -64,15 +77,16 @@ func testAccKMIPSecretScopeCheckDestroy(s *terraform.State) error { return nil } -func testKMIPSecretScope_initialConfig(path string) string { +func testKMIPSecretScope_initialConfig(path string, listenAddr string) string { return fmt.Sprintf(` resource "vault_kmip_secret_backend" "kmip" { path = "%s" + listen_addrs = ["%s"] description = "test description" } resource "vault_kmip_secret_scope" "test" { path = vault_kmip_secret_backend.kmip.path scope = "test" -}`, path) +}`, path, listenAddr) } diff --git a/vault/resource_quota_lease_count_test.go b/vault/resource_quota_lease_count_test.go index 746e7ab91..e9770b6ca 100644 --- a/vault/resource_quota_lease_count_test.go +++ b/vault/resource_quota_lease_count_test.go @@ -2,7 +2,6 @@ package vault import ( "fmt" - "strconv" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -13,42 +12,40 @@ import ( "github.com/hashicorp/terraform-provider-vault/testutil" ) -func randomQuotaLeaseString() string { - whole := acctest.RandIntRange(1000, 2000) - return strconv.Itoa(whole + 1000) -} - func TestQuotaLeaseCount(t *testing.T) { name := acctest.RandomWithPrefix("tf-test") - leaseCount := randomQuotaLeaseString() - newLeaseCount := randomQuotaLeaseString() + ns := "ns-" + name + leaseCount := "1001" + newLeaseCount := "2001" + resourceName := "vault_quota_lease_count.foobar" + resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestEntPreCheck(t) }, CheckDestroy: testQuotaLeaseCountCheckDestroy([]string{leaseCount, newLeaseCount}), Steps: []resource.TestStep{ { - Config: testQuotaLeaseCount_Config(name, "", leaseCount), + Config: testQuotaLeaseCountConfig(ns, name, "", leaseCount), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "name", name), - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "path", ""), - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "max_leases", leaseCount), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "path", ns+"/"), + resource.TestCheckResourceAttr(resourceName, "max_leases", leaseCount), ), }, { - Config: testQuotaLeaseCount_Config(name, "", newLeaseCount), + Config: testQuotaLeaseCountConfig(ns, name, "", newLeaseCount), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "name", name), - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "path", ""), - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "max_leases", newLeaseCount), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "path", ns+"/"), + resource.TestCheckResourceAttr(resourceName, "max_leases", newLeaseCount), ), }, { - Config: testQuotaLeaseCount_Config(name, "sys/", newLeaseCount), + Config: testQuotaLeaseCountConfig(ns, name, "sys/", newLeaseCount), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "name", name), - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "path", "sys/"), - resource.TestCheckResourceAttr("vault_quota_lease_count.foobar", "max_leases", newLeaseCount), + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "path", ns+"/sys/"), + resource.TestCheckResourceAttr(resourceName, "max_leases", newLeaseCount), ), }, }, @@ -75,12 +72,16 @@ func testQuotaLeaseCountCheckDestroy(leaseCounts []string) resource.TestCheckFun } // Caution: Don't set test max_leases values too low or other tests running concurrently might fail -func testQuotaLeaseCount_Config(name, path, max_leases string) string { +func testQuotaLeaseCountConfig(ns, name, path, maxLeases string) string { return fmt.Sprintf(` -resource "vault_quota_lease_count" "foobar" { - name = "%s" +resource "vault_namespace" "test" { path = "%s" +} + +resource "vault_quota_lease_count" "foobar" { + name = "%s" + path = "${vault_namespace.test.path}/%s" max_leases = %s } -`, name, path, max_leases) +`, ns, name, path, maxLeases) } diff --git a/vault/resource_raft_autopilot_test.go b/vault/resource_raft_autopilot_test.go index 7ea54b434..67f330172 100644 --- a/vault/resource_raft_autopilot_test.go +++ b/vault/resource_raft_autopilot_test.go @@ -2,7 +2,6 @@ package vault import ( "fmt" - "os" "strconv" "testing" @@ -18,9 +17,7 @@ func TestAccRaftAutopilotConfig_basic(t *testing.T) { Providers: testProviders, PreCheck: func() { testutil.TestAccPreCheck(t) - if _, ok := os.LookupEnv("SKIP_RAFT_TESTS"); ok { - t.Skip("Warning: SKIP_RAFT_TESTS set, skipping test") - } + testutil.SkipTestEnvSet(t, "SKIP_RAFT_TESTS") }, CheckDestroy: testAccRaftAutopilotConfigCheckDestroy, Steps: []resource.TestStep{ diff --git a/vault/resource_raft_snapshot_agent_config_test.go b/vault/resource_raft_snapshot_agent_config_test.go index b80632c60..81c10ba91 100644 --- a/vault/resource_raft_snapshot_agent_config_test.go +++ b/vault/resource_raft_snapshot_agent_config_test.go @@ -15,8 +15,11 @@ import ( func TestAccRaftSnapshotAgentConfig_basic(t *testing.T) { name := acctest.RandomWithPrefix("tf-test-raft-snapshot") resource.Test(t, resource.TestCase{ - Providers: testProviders, - PreCheck: func() { testutil.TestEntPreCheck(t) }, + Providers: testProviders, + PreCheck: func() { + testutil.SkipTestEnvSet(t, "SKIP_RAFT_TESTS") + testutil.TestEntPreCheck(t) + }, CheckDestroy: testAccRaftSnapshotAgentConfigCheckDestroy, Steps: []resource.TestStep{ { @@ -95,7 +98,10 @@ func TestAccRaftSnapshotAgentConfig_basic(t *testing.T) { func TestAccRaftSnapshotAgentConfig_import(t *testing.T) { name := acctest.RandomWithPrefix("tf-test-raft-snapshot") resource.Test(t, resource.TestCase{ - PreCheck: func() { testutil.TestEntPreCheck(t) }, + PreCheck: func() { + testutil.SkipTestEnvSet(t, "SKIP_RAFT_TESTS") + testutil.TestEntPreCheck(t) + }, Providers: testProviders, CheckDestroy: testAccRaftSnapshotAgentConfigCheckDestroy, Steps: []resource.TestStep{