diff --git a/env0/data_kubernetes_credentials.go b/env0/data_kubernetes_credentials.go new file mode 100644 index 00000000..c72918c1 --- /dev/null +++ b/env0/data_kubernetes_credentials.go @@ -0,0 +1,55 @@ +package env0 + +import ( + "context" + "fmt" + + "github.com/env0/terraform-provider-env0/client" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataKubernetesCredentials(credentialsType CloudType) *schema.Resource { + return &schema.Resource{ + ReadContext: dataKuberentesCredentialsRead(credentialsType), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Description: fmt.Sprintf("the name of %s credentials", credentialsType), + Optional: true, + ExactlyOneOf: []string{"name", "id"}, + }, + "id": { + Type: schema.TypeString, + Description: fmt.Sprintf("the id of %s credentials", credentialsType), + Optional: true, + ExactlyOneOf: []string{"name", "id"}, + }, + }, + } +} + +func dataKuberentesCredentialsRead(credentialsType CloudType) func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var credentials client.Credentials + var err error + + id, ok := d.GetOk("id") + if ok { + credentials, err = getCredentialsById(id.(string), credentialsTypeToPrefixList[credentialsType], meta) + } else { + credentials, err = getCredentialsByName(d.Get("name").(string), credentialsTypeToPrefixList[credentialsType], meta) + } + + if err != nil { + return DataGetFailure(fmt.Sprintf("%s credentials", credentialsType), id, err) + } + + if err := writeResourceData(&credentials, d); err != nil { + return diag.Errorf("schema resource data serialization failed: %v", err) + } + + return nil + } +} diff --git a/env0/data_kubernetes_credentials_test.go b/env0/data_kubernetes_credentials_test.go new file mode 100644 index 00000000..ebd2160e --- /dev/null +++ b/env0/data_kubernetes_credentials_test.go @@ -0,0 +1,129 @@ +package env0 + +import ( + "fmt" + "regexp" + "testing" + + "github.com/env0/terraform-provider-env0/client" + "github.com/env0/terraform-provider-env0/client/http" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestKubernetesCredentialsDataSource(t *testing.T) { + tests := [][]string{ + {"env0_aws_eks_credentials", string(client.AwsEksCredentialsType)}, + {"env0_azure_aks_credentials", string(client.AzureAksCredentialsType)}, + {"env0_gcp_gke_credentials", string(client.GcpGkeCredentialsType)}, + {"env0_kubeconfig_credentials", string(client.KubeconfigCredentialsType)}, + } + + for _, test := range tests { + credentials := client.Credentials{ + Id: "id0", + Name: "name0", + Type: test[1], + } + + credentialsOther1 := client.Credentials{ + Id: "id1", + Name: "name1", + Type: test[1], + } + + credentialsOther2 := client.Credentials{ + Id: "id2", + Name: "name2", + Type: test[1], + } + + byName := map[string]interface{}{"name": credentials.Name} + byId := map[string]interface{}{"id": credentials.Id} + + resourceType := test[0] + resourceName := "test" + accessor := dataSourceAccessor(resourceType, resourceName) + + getValidTestCase := func(input map[string]interface{}) resource.TestCase { + return resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: dataSourceConfigCreate(resourceType, resourceName, input), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(accessor, "id", credentials.Id), + resource.TestCheckResourceAttr(accessor, "name", credentials.Name), + ), + }, + }, + } + } + + getErrorTestCase := func(input map[string]interface{}, expectedError string) resource.TestCase { + return resource.TestCase{ + Steps: []resource.TestStep{ + { + Config: dataSourceConfigCreate(resourceType, resourceName, input), + ExpectError: regexp.MustCompile(expectedError), + }, + }, + } + } + + mockGetCredentials := func(returnValue client.Credentials) func(mockFunc *client.MockApiClientInterface) { + return func(mock *client.MockApiClientInterface) { + mock.EXPECT().CloudCredentials(credentials.Id).AnyTimes().Return(returnValue, nil) + } + } + + mockListCredentials := func(returnValue []client.Credentials) func(mockFunc *client.MockApiClientInterface) { + return func(mock *client.MockApiClientInterface) { + mock.EXPECT().CloudCredentialsList().AnyTimes().Return(returnValue, nil) + } + } + + t.Run("by id", func(t *testing.T) { + runUnitTest(t, + getValidTestCase(byId), + mockGetCredentials(credentials), + ) + }) + + t.Run("by name - "+test[0], func(t *testing.T) { + runUnitTest(t, + getValidTestCase(byName), + mockListCredentials([]client.Credentials{credentials, credentialsOther1, credentialsOther2}), + ) + }) + + t.Run("throw error when no name or id is supplied - "+test[0], func(t *testing.T) { + runUnitTest(t, + getErrorTestCase(map[string]interface{}{}, "one of `id,name` must be specified"), + func(mock *client.MockApiClientInterface) {}, + ) + }) + + t.Run("throw error when by name and more than one is returned - "+test[0], func(t *testing.T) { + runUnitTest(t, + getErrorTestCase(byName, "found multiple credentials"), + mockListCredentials([]client.Credentials{credentials, credentialsOther1, credentialsOther2, credentials}), + ) + }) + + t.Run("Throw error when by name and not found - "+test[0], func(t *testing.T) { + runUnitTest(t, + getErrorTestCase(byName, "not found"), + mockListCredentials([]client.Credentials{credentialsOther1, credentialsOther2}), + ) + }) + + t.Run("Throw error when by id and not found - "+test[0], func(t *testing.T) { + runUnitTest(t, + getErrorTestCase(byId, fmt.Sprintf("id %s not found", credentials.Id)), + func(mock *client.MockApiClientInterface) { + mock.EXPECT().CloudCredentials(credentials.Id).AnyTimes().Return(client.Credentials{}, http.NewMockFailedResponseError(404)) + }, + ) + }) + } + +} diff --git a/env0/provider.go b/env0/provider.go index 262c91bd..681b29fe 100644 --- a/env0/provider.go +++ b/env0/provider.go @@ -75,6 +75,10 @@ func Provider(version string) plugin.ProviderFunc { "env0_azure_credentials": dataCredentials(AZURE_TYPE), "env0_azure_oidc_credentials": dataOidcCredentials(AZURE_OIDC_TYPE), "env0_vault_oidc_credentials": dataOidcCredentials(VAULT_OIDC_TYPE), + "env0_aws_eks_credentials": dataKubernetesCredentials(AWS_EKS_TYPE), + "env0_azure_aks_credentials": dataKubernetesCredentials(AZURE_AKS_TYPE), + "env0_gcp_gke_credentials": dataKubernetesCredentials(GCP_GKE_TYPE), + "env0_kubeconfig_credentials": dataKubernetesCredentials(KUBECONFIG_TYPE), "env0_team": dataTeam(), "env0_teams": dataTeams(), "env0_environment": dataEnvironment(), diff --git a/examples/data-sources/env0_aws_eks_credentials/data-source.tf b/examples/data-sources/env0_aws_eks_credentials/data-source.tf new file mode 100644 index 00000000..572db5a6 --- /dev/null +++ b/examples/data-sources/env0_aws_eks_credentials/data-source.tf @@ -0,0 +1,13 @@ +resource "env0_aws_eks_credentials" "example" { + name = "example" + cluster_name = "my-cluster" + cluster_region = "us-east-2" +} + +data "env0_aws_eks_credentials" "by_id" { + id = env0_aws_eks_credentials.example.id +} + +data "env0_aws_eks_credentials" "by_name" { + name = env0_aws_eks_credentials.example.name +} diff --git a/examples/resources/env0_aws_eks_credentials/import.sh b/examples/resources/env0_aws_eks_credentials/import.sh new file mode 100644 index 00000000..88950cca --- /dev/null +++ b/examples/resources/env0_aws_eks_credentials/import.sh @@ -0,0 +1,2 @@ +terraform import env0_aws_eks_credentials.by_id d31a6b30-5f69-4d24-937c-22322754934e +terraform import env0_aws_eks_credentials.by_name "credentials name" diff --git a/examples/resources/env0_aws_eks_credentials/resource.tf b/examples/resources/env0_aws_eks_credentials/resource.tf new file mode 100644 index 00000000..d280133a --- /dev/null +++ b/examples/resources/env0_aws_eks_credentials/resource.tf @@ -0,0 +1,14 @@ +resource "env0_aws_eks_credentials" "credentials" { + name = "example" + cluster_name = "my-cluster" + cluster_region = "us-east-2" +} + +data "env0_project" "project" { + name = "my-project" +} + +resource "env0_cloud_credentials_project_assignment" "assignment" { + credential_id = env0_aws_eks_credentials.credentials.id + project_id = data.env0_project.project.id +} diff --git a/tests/integration/024_cloud_credentials/main.tf b/tests/integration/024_cloud_credentials/main.tf index f3c3f21b..7e344fde 100644 --- a/tests/integration/024_cloud_credentials/main.tf +++ b/tests/integration/024_cloud_credentials/main.tf @@ -4,6 +4,10 @@ resource "random_string" "random" { min_lower = 8 } +resource "env0_project" "project" { + name = "credentials-project-${random_string.random.result}" +} + resource "env0_aws_credentials" "aws_cred1" { name = "Test Role arn1 ${random_string.random.result}" arn = "Role ARN1" @@ -67,6 +71,16 @@ resource "env0_aws_eks_credentials" "aws_eks_credentials" { cluster_region = "us-east-2" } +resource "env0_cloud_credentials_project_assignment" "eks_to_project_assignment" { + credential_id = env0_aws_eks_credentials.aws_eks_credentials.id + project_id = env0_project.project.id +} + +data "env0_aws_eks_credentials" "aws_eks_credentials" { + depends_on = [env0_aws_eks_credentials.aws_eks_credentials] + name = "aws-eks-${random_string.random.result}" +} + resource "env0_azure_aks_credentials" "azure_aks_credentials" { name = "azure-aks-${random_string.random.result}" cluster_name = "my-cluster"