diff --git a/test/functional/shared/resources/recipe_terraform_test.go b/test/functional/shared/resources/recipe_terraform_test.go index ec02155b161..7e8bb552b02 100644 --- a/test/functional/shared/resources/recipe_terraform_test.go +++ b/test/functional/shared/resources/recipe_terraform_test.go @@ -137,6 +137,98 @@ func Test_TerraformRecipe_KubernetesRedis(t *testing.T) { test.Test(t) } +// Test_TerraformRecipe_KubernetesPostgres covers the following terraform recipe scenario: +// +// - Create an extender resource using a Terraform recipe that deploys Postgres on Kubernetes. +// - The recipe deployment creates a Kubernetes deployment and a Kubernetes service and a postgres db. +func Test_TerraformRecipe_KubernetesPostgres(t *testing.T) { + template := "testdata/corerp-resources-terraform-postgres.bicep" + appName := "corerp-resources-terraform-pg-app" + envName := "corerp-resources-terraform-pg-env" + extenderName := "pgs-resources-terraform-pgsapp" + userName := "postgres" + password := "abc-123-hgd-@#$'" + + secretSuffix, err := getSecretSuffix("/planes/radius/local/resourcegroups/kind-radius/providers/Applications.Core/extenders/"+extenderName, envName, appName) + require.NoError(t, err) + + test := shared.NewRPTest(t, appName, []shared.TestStep{ + { + Executor: step.NewDeployExecutor(template, testutil.GetTerraformRecipeModuleServerURL(), "userName="+userName, "password="+password), + RPResources: &validation.RPResourceSet{ + Resources: []validation.RPResource{ + { + Name: envName, + Type: validation.EnvironmentsResource, + }, + { + Name: appName, + Type: validation.ApplicationsResource, + }, + { + Name: extenderName, + Type: validation.ExtendersResource, + App: appName, + OutputResources: []validation.OutputResourceResponse{ + {ID: "/planes/kubernetes/local/namespaces/corerp-resources-terraform-pg-app/providers/apps/Deployment/postgres"}, + {ID: "/planes/kubernetes/local/namespaces/corerp-resources-terraform-pg-app/providers/core/Service/postgres"}, + {ID: "/planes/kubernetes/local/namespaces/corerp-resources-terraform-pg-app/providers/core/Pod/postgres"}, + }, + }, + }, + }, + K8sObjects: &validation.K8sObjectSet{ + Namespaces: map[string][]validation.K8sObject{ + appName: { + validation.NewK8sServiceForResource(appName, "postgres"). + ValidateLabels(false), + validation.NewK8sPodForResource(appName, "postgres"). + ValidateLabels(false), + }, + secretNamespace: { + validation.NewK8sSecretForResourceWithResourceName(secretPrefix + secretSuffix). + ValidateLabels(false), + }, + }, + }, + SkipObjectValidation: true, + SkipResourceDeletion: true, + PostStepVerify: func(ctx context.Context, t *testing.T, test shared.RPTest) { + secret, err := test.Options.K8sClient.CoreV1().Secrets(secretNamespace). + Get(ctx, secretPrefix+secretSuffix, metav1.GetOptions{}) + require.NoError(t, err) + require.Equal(t, secretNamespace, secret.Namespace) + require.Equal(t, secretPrefix+secretSuffix, secret.Name) + + pg, err := test.Options.ManagementClient.ShowResource(ctx, "Applications.Core/extenders", extenderName) + require.NoError(t, err) + require.NotNil(t, pg) + status := pg.Properties["status"].(map[string]any) + recipe := status["recipe"].(map[string]interface{}) + require.Equal(t, "terraform", recipe["templateKind"].(string)) + expectedTemplatePath := strings.Replace(testutil.GetTerraformRecipeModuleServerURL()+"/postgres.zip", "moduleServer=", "", 1) + require.Equal(t, expectedTemplatePath, recipe["templatePath"].(string)) + + // At present, it is not possible to verify the template version in functional tests + // This is verified by UTs though + + // Manually delete Kubernetes the secret that stores the Terraform state file now. The next step in the test will be the deletion + // of the portable resource that uses this secret for Terraform recipe. This is to verify that the test and portable resource + // deletion will not fail even though the secret is already deleted. + err = test.Options.K8sClient.CoreV1().Secrets(secretNamespace).Delete(ctx, secretPrefix+secretSuffix, metav1.DeleteOptions{}) + require.NoError(t, err) + }, + }, + }) + + test.PostDeleteVerify = func(ctx context.Context, t *testing.T, test shared.RPTest) { + resourceID := "/planes/radius/local/resourcegroups/kind-radius/providers/Applications.Core/extenders/" + extenderName + testSecretDeletion(t, ctx, test, appName, envName, resourceID) + } + + test.Test(t) +} + func Test_TerraformRecipe_Context(t *testing.T) { template := "testdata/corerp-resources-terraform-context.bicep" name := "corerp-resources-terraform-context" diff --git a/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep b/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep new file mode 100644 index 00000000000..69258a000f4 --- /dev/null +++ b/test/functional/shared/resources/testdata/corerp-resources-terraform-postgres.bicep @@ -0,0 +1,75 @@ +import radius as radius + +@description('The URL of the server hosting test Terraform modules.') +param moduleServer string + +@description('Username for Postgres db.') +param userName string + +@description('Password for Postgres db.') +@secure() +param password string + +resource env 'Applications.Core/environments@2023-10-01-preview' = { + name: 'corerp-resources-terraform-pg-env' + location: 'global' + properties: { + compute: { + kind: 'kubernetes' + resourceId: 'self' + namespace: 'corerp-resources-terraform-pg-env' + } + recipeConfig: { + terraform:{ + providers:{ + postgresql:[{ + username: userName + port: 5432 + password: password + sslmode: 'disable' + }] + } + } + env: { + PGHOST: 'postgres.corerp-resources-terraform-pg-app.svc.cluster.local' + } + } + recipes: { + 'Applications.Core/extenders': { + default: { + templateKind: 'terraform' + templatePath: '${moduleServer}/postgres.zip' + } + } + } + } +} + +resource app 'Applications.Core/applications@2023-10-01-preview' = { + name: 'corerp-resources-terraform-pg-app' + location: 'global' + properties: { + environment: env.id + extensions: [ + { + kind: 'kubernetesNamespace' + namespace: 'corerp-resources-terraform-pg-app' + } + ] + } +} + +resource pgsapp 'Applications.Core/extenders@2023-10-01-preview' = { + name: 'pgs-resources-terraform-pgsapp' + properties: { + application: app.id + environment: env.id + recipe: { + name: 'default' + parameters: { + password: password + } + } + } +} + \ No newline at end of file diff --git a/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf b/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf index b3f6537add6..29c412f5a91 100644 --- a/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf +++ b/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/main.tf @@ -14,7 +14,7 @@ terraform { resource "kubernetes_deployment" "postgres" { metadata { name = "postgres" - namespace = "postgresns" + namespace = var.context.runtime.kubernetes.namespace } spec { @@ -53,7 +53,7 @@ resource "kubernetes_deployment" "postgres" { resource "kubernetes_service" "postgres" { metadata { name = "postgres" - namespace = "postgresns" + namespace = var.context.runtime.kubernetes.namespace } spec { @@ -68,17 +68,12 @@ resource "kubernetes_service" "postgres" { } } -variable "port" { - default = 5432 -} - -provider "postgresql" { - host = var.host - port = var.port - password = var.password - sslmode = "disable" +resource "time_sleep" "wait_20_seconds" { + depends_on = [kubernetes_service.postgres] + create_duration = "20s" } resource postgresql_database "pg_db_test" { + depends_on = [time_sleep.wait_20_seconds] name = "pg_db_test" -} \ No newline at end of file +} diff --git a/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/variables.tf b/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/variables.tf index 8dfe44cb502..0a8c5d972ae 100644 --- a/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/variables.tf +++ b/test/functional/shared/resources/testdata/recipes/test-terraform-recipes/postgres/variables.tf @@ -1,8 +1,10 @@ + +variable "context" { + description = "This variable contains Radius recipe context." + type = any +} + variable "password" { description = "The password for the PostgreSQL database" type = string } - -variable "host" { - default = "localhost" -} \ No newline at end of file