diff --git a/docs/resources/sso.md b/docs/resources/sso.md index f7c9fab10..51cc21e0b 100644 --- a/docs/resources/sso.md +++ b/docs/resources/sso.md @@ -91,12 +91,12 @@ Required: - `client_id` (String) Client ID for OIDC authentication. - `client_secret` (String, Sensitive) Client secret for OIDC authentication (sensitive). -- `email` (String) User's email address retrieved from identity provider. -- `first_name` (String) User's first name retrieved from identity provider. +- `email` (String) The name of the claim that returns the user's email address from the identity provider. +- `first_name` (String) The name of the claim that returns the user's first name from the identity provider. - `issuer_url` (String) URL of the OIDC issuer. -- `last_name` (String) User's last name retrieved from identity provider. +- `last_name` (String) The name of the claim that returns the user's last name from the identity provider. - `scopes` (Set of String) Scopes requested during OIDC authentication. -- `spectro_team` (String) The SpectroCloud team the user belongs to. +- `spectro_team` (String) The name of the claim that returns the user's group memberships from the Identity Provider. The values of this claim will map to SpectroCloud teams. Optional: @@ -115,10 +115,10 @@ Read-Only: Required: -- `email` (String) User's email address retrieved from identity provider. -- `first_name` (String) User's first name retrieved from identity provider. -- `last_name` (String) User's last name retrieved from identity provider. -- `spectro_team` (String) The SpectroCloud team the user belongs to. +- `email` (String) The name of the claim that returns the user's email address from the identity provider. +- `first_name` (String) The name of the claim that returns the user's first name from the identity provider. +- `last_name` (String) The name of the claim that returns the user's last name from the identity provider. +- `spectro_team` (String) The name of the claim that returns the user's group memberships from the Identity Provider. The values of this claim will map to SpectroCloud teams. diff --git a/spectrocloud/resource_cluster_eks.go b/spectrocloud/resource_cluster_eks.go index 17ac28d5d..6c824081e 100644 --- a/spectrocloud/resource_cluster_eks.go +++ b/spectrocloud/resource_cluster_eks.go @@ -830,15 +830,18 @@ func toEksCluster(c *client.V1Client, d *schema.ResourceData) (*models.V1Spectro cluster.Spec.CloudConfig.EndpointAccess = access machinePoolConfigs := make([]*models.V1EksMachinePoolConfigEntity, 0) - // Following same logic as UI for setting up control plane for managed cluster - cpPool := map[string]interface{}{ - "control_plane": true, - "name": "cp-pool", - "az_subnets": cloudConfig["az_subnets"], - "capacity_type": "spot", - "count": 0, + // Following same logic as UI for setting up control plane for static cluster + // Only add cp-pool for dynamic cluster provisioning when az_subnets is not empty and has more than one element + if cloudConfig["az_subnets"] != nil && len(cloudConfig["az_subnets"].(map[string]interface{})) > 0 { + cpPool := map[string]interface{}{ + "control_plane": true, + "name": "cp-pool", + "az_subnets": cloudConfig["az_subnets"], + "capacity_type": "spot", + "count": 0, + } + machinePoolConfigs = append(machinePoolConfigs, toMachinePoolEks(cpPool)) } - machinePoolConfigs = append(machinePoolConfigs, toMachinePoolEks(cpPool)) for _, machinePool := range d.Get("machine_pool").([]interface{}) { mp := toMachinePoolEks(machinePool) machinePoolConfigs = append(machinePoolConfigs, mp) diff --git a/spectrocloud/resource_cluster_eks_expand_test.go b/spectrocloud/resource_cluster_eks_expand_test.go index 9ab8bbc0e..4285f9998 100644 --- a/spectrocloud/resource_cluster_eks_expand_test.go +++ b/spectrocloud/resource_cluster_eks_expand_test.go @@ -6,6 +6,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/spectrocloud/palette-sdk-go/api/models" + "github.com/spectrocloud/palette-sdk-go/client" "github.com/stretchr/testify/assert" "github.com/spectrocloud/terraform-provider-spectrocloud/types" @@ -94,18 +95,73 @@ func TestToEksCluster(t *testing.T) { }, }) - //client := &client.V1Client{} - // - //cluster, err := toEksCluster(client, d) - // - //assert.NoError(t, err, "Expected no error from toEksCluster") - //assert.Equal(t, "test-cluster", cluster.Metadata.Name, "Unexpected cluster name") - // - //assert.NotNil(t, cluster.Spec.Machinepoolconfig, "Expected MachinePools to be non-nil") - //assert.Equal(t, 2, len(cluster.Spec.Machinepoolconfig), "Expected one machine pool in the cluster") - // - //assert.Equal(t, "test-pool", *cluster.Spec.Machinepoolconfig[1].PoolConfig.Name, "Unexpected machine pool name") - //assert.Equal(t, int64(10), cluster.Spec.Machinepoolconfig[1].CloudConfig.RootDeviceSize, "Unexpected disk size") + client := &client.V1Client{} + + cluster, err := toEksCluster(client, d) + + assert.NoError(t, err, "Expected no error from toEksCluster") + assert.Equal(t, "test-cluster", cluster.Metadata.Name, "Unexpected cluster name") + + assert.NotNil(t, cluster.Spec.Machinepoolconfig, "Expected MachinePools to be non-nil") + // Without az_subnets, no cp-pool should be added + assert.Equal(t, 1, len(cluster.Spec.Machinepoolconfig), "Expected one machine pool in the cluster (no cp-pool)") + + assert.Equal(t, "test-pool", *cluster.Spec.Machinepoolconfig[0].PoolConfig.Name, "Unexpected machine pool name") + assert.Equal(t, int64(10), cluster.Spec.Machinepoolconfig[0].CloudConfig.RootDeviceSize, "Unexpected disk size") +} + +func TestToEksClusterWithAzSubnets(t *testing.T) { + // Setup a dummy ResourceData for testing with az_subnets + d := resourceClusterEks().TestResourceData() + + /* set the values of the ResourceData */ + d.Set("name", "test-cluster-az") + d.Set("context", "project") + d.Set("tags", []interface{}{"tag1:value1", "tag2:value2"}) + d.Set("cloud_account_id", "test-cloud-id") + d.Set("cloud_config", []interface{}{ + map[string]interface{}{ + "ssh_key_name": "test-ssh-key", + "region": "us-west-1", + "vpc_id": "test-vpc-id", + "endpoint_access": "public", + "public_access_cidrs": []interface{}{"0.0.0.0/0"}, + "encryption_config_arn": "arn:test:encryption", + "az_subnets": map[string]interface{}{ + "us-west-1a": "subnet-12345", + "us-west-1b": "subnet-67890", + }, + }, + }) + d.Set("machine_pool", []interface{}{ + map[string]interface{}{ + "name": "test-pool", + "disk_size_gb": 10, + "count": 2, + "instance_type": "t2.micro", + "capacity_type": "on-demand", + "update_strategy": "RollingUpdateScaleOut", + }, + }) + + client := &client.V1Client{} + + cluster, err := toEksCluster(client, d) + + assert.NoError(t, err, "Expected no error from toEksCluster") + assert.Equal(t, "test-cluster-az", cluster.Metadata.Name, "Unexpected cluster name") + + assert.NotNil(t, cluster.Spec.Machinepoolconfig, "Expected MachinePools to be non-nil") + // With az_subnets having more than one element, cp-pool should be added + assert.Equal(t, 2, len(cluster.Spec.Machinepoolconfig), "Expected two machine pools in the cluster (cp-pool + test-pool)") + + // Check that cp-pool is the first one + assert.Equal(t, "cp-pool", *cluster.Spec.Machinepoolconfig[0].PoolConfig.Name, "Expected first machine pool to be cp-pool") + assert.True(t, cluster.Spec.Machinepoolconfig[0].PoolConfig.IsControlPlane, "Expected first machine pool to be control plane") + + // Check that test-pool is the second one + assert.Equal(t, "test-pool", *cluster.Spec.Machinepoolconfig[1].PoolConfig.Name, "Expected second machine pool to be test-pool") + assert.Equal(t, int64(10), cluster.Spec.Machinepoolconfig[1].CloudConfig.RootDeviceSize, "Unexpected disk size") } func TestToMachinePoolEks(t *testing.T) { diff --git a/spectrocloud/resource_sso.go b/spectrocloud/resource_sso.go index 6581187a9..4572edfb3 100644 --- a/spectrocloud/resource_sso.go +++ b/spectrocloud/resource_sso.go @@ -152,35 +152,30 @@ func resourceSSO() *schema.Resource { "first_name": { Type: schema.TypeString, Required: true, - Description: "User's first name retrieved from identity provider.", + Description: "The name of the claim that returns the user's first name from the identity provider.", }, "last_name": { Type: schema.TypeString, Required: true, - Description: "User's last name retrieved from identity provider.", + Description: "The name of the claim that returns the user's last name from the identity provider.", }, "email": { Type: schema.TypeString, Required: true, - Description: "User's email address retrieved from identity provider.", + Description: "The name of the claim that returns the user's email address from the identity provider.", ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { v := val.(string) if v == "" { errs = append(errs, fmt.Errorf("%q must not be empty", key)) return } - emailRegex := `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$` - matched, err := regexp.MatchString(emailRegex, v) - if err != nil || !matched { - errs = append(errs, fmt.Errorf("%q must be a valid email address", key)) - } return }, }, "spectro_team": { Type: schema.TypeString, Required: true, - Description: "The SpectroCloud team the user belongs to.", + Description: "The name of the claim that returns the user's group memberships from the Identity Provider. The values of this claim will map to SpectroCloud teams.", }, "user_info_endpoint": { Type: schema.TypeList, @@ -192,35 +187,30 @@ func resourceSSO() *schema.Resource { "first_name": { Type: schema.TypeString, Required: true, - Description: "User's first name retrieved from identity provider.", + Description: "The name of the claim that returns the user's first name from the identity provider.", }, "last_name": { Type: schema.TypeString, Required: true, - Description: "User's last name retrieved from identity provider.", + Description: "The name of the claim that returns the user's last name from the identity provider.", }, "email": { Type: schema.TypeString, Required: true, - Description: "User's email address retrieved from identity provider.", + Description: "The name of the claim that returns the user's email address from the identity provider.", ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { v := val.(string) if v == "" { errs = append(errs, fmt.Errorf("%q must not be empty", key)) return } - emailRegex := `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$` - matched, err := regexp.MatchString(emailRegex, v) - if err != nil || !matched { - errs = append(errs, fmt.Errorf("%q must be a valid email address", key)) - } return }, }, "spectro_team": { Type: schema.TypeString, Required: true, - Description: "The SpectroCloud team the user belongs to.", + Description: "The name of the claim that returns the user's group memberships from the Identity Provider. The values of this claim will map to SpectroCloud teams.", }, }, }, @@ -314,11 +304,6 @@ func resourceSSO() *schema.Resource { errs = append(errs, fmt.Errorf("%q must not be empty", key)) return } - emailRegex := `^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$` - matched, err := regexp.MatchString(emailRegex, v) - if err != nil || !matched { - errs = append(errs, fmt.Errorf("%q must be a valid email address", key)) - } return }, }, diff --git a/spectrocloud/resource_sso_test.go b/spectrocloud/resource_sso_test.go index 93c36f468..4ff096f68 100644 --- a/spectrocloud/resource_sso_test.go +++ b/spectrocloud/resource_sso_test.go @@ -51,17 +51,17 @@ func TestToOIDC(t *testing.T) { "insecure_skip_tls_verify": true, "issuer_url": "https://issuer.com", "logout_url": "https://example.com/logout", - "email": "user@example.com", - "first_name": "John", - "last_name": "Doe", - "spectro_team": "devops", + "email": "email", + "first_name": "given_name", + "last_name": "family_name", + "spectro_team": "groups", "scopes": schema.NewSet(schema.HashString, []interface{}{"openid", "profile"}), "user_info_endpoint": []interface{}{ map[string]interface{}{ - "email": "user@example.com", - "first_name": "John", - "last_name": "Doe", - "spectro_team": "devops", + "email": "email", + "first_name": "given_name", + "last_name": "family_name", + "spectro_team": "groups", }, }, }, @@ -83,14 +83,14 @@ func TestToOIDC(t *testing.T) { assert.Equal(t, true, *result.IssuerTLS.InsecureSkipVerify) assert.Equal(t, "https://issuer.com", result.IssuerURL) assert.Equal(t, "https://example.com/logout", result.LogoutURL) - assert.Equal(t, "user@example.com", result.RequiredClaims.Email) - assert.Equal(t, "John", result.RequiredClaims.FirstName) - assert.Equal(t, "Doe", result.RequiredClaims.LastName) - assert.Equal(t, "devops", result.RequiredClaims.SpectroTeam) - assert.Equal(t, "user@example.com", result.UserInfo.Claims.Email) - assert.Equal(t, "John", result.UserInfo.Claims.FirstName) - assert.Equal(t, "Doe", result.UserInfo.Claims.LastName) - assert.Equal(t, "devops", result.UserInfo.Claims.SpectroTeam) + assert.Equal(t, "email", result.RequiredClaims.Email) + assert.Equal(t, "given_name", result.RequiredClaims.FirstName) + assert.Equal(t, "family_name", result.RequiredClaims.LastName) + assert.Equal(t, "groups", result.RequiredClaims.SpectroTeam) + assert.Equal(t, "email", result.UserInfo.Claims.Email) + assert.Equal(t, "given_name", result.UserInfo.Claims.FirstName) + assert.Equal(t, "family_name", result.UserInfo.Claims.LastName) + assert.Equal(t, "groups", result.UserInfo.Claims.SpectroTeam) assert.Equal(t, true, *result.UserInfo.UseUserInfo) } @@ -146,18 +146,18 @@ func TestFlattenOidc(t *testing.T) { IssuerURL: "https://issuer.com", LogoutURL: "https://example.com/logout", RequiredClaims: &models.V1TenantOidcClaims{ - Email: "user@example.com", - FirstName: "John", - LastName: "Doe", - SpectroTeam: "devops", + Email: "email", + FirstName: "given_name", + LastName: "family_name", + SpectroTeam: "groups", }, Scopes: []string{"openid", "profile"}, UserInfo: &models.V1OidcUserInfo{ Claims: &models.V1TenantOidcClaims{ - Email: "user@example.com", - FirstName: "John", - LastName: "Doe", - SpectroTeam: "devops", + Email: "email", + FirstName: "given_name", + LastName: "family_name", + SpectroTeam: "groups", }, }, } @@ -174,17 +174,17 @@ func TestFlattenOidc(t *testing.T) { assert.Equal(t, true, flattened["insecure_skip_tls_verify"]) assert.Equal(t, "https://issuer.com", flattened["issuer_url"]) assert.Equal(t, "https://example.com/logout", flattened["logout_url"]) - assert.Equal(t, "user@example.com", flattened["email"]) - assert.Equal(t, "John", flattened["first_name"]) - assert.Equal(t, "Doe", flattened["last_name"]) - assert.Equal(t, "devops", flattened["spectro_team"]) + assert.Equal(t, "email", flattened["email"]) + assert.Equal(t, "given_name", flattened["first_name"]) + assert.Equal(t, "family_name", flattened["last_name"]) + assert.Equal(t, "groups", flattened["spectro_team"]) assert.Equal(t, []interface{}{"openid", "profile"}, flattened["scopes"]) userInfo := flattened["user_info_endpoint"].([]interface{})[0].(map[string]interface{}) - assert.Equal(t, "user@example.com", userInfo["email"]) - assert.Equal(t, "John", userInfo["first_name"]) - assert.Equal(t, "Doe", userInfo["last_name"]) - assert.Equal(t, "devops", userInfo["spectro_team"]) + assert.Equal(t, "email", userInfo["email"]) + assert.Equal(t, "given_name", userInfo["first_name"]) + assert.Equal(t, "family_name", userInfo["last_name"]) + assert.Equal(t, "groups", userInfo["spectro_team"]) } func TestToSAML(t *testing.T) {