diff --git a/azurerm/internal/services/springcloud/client/client.go b/azurerm/internal/services/springcloud/client/client.go index c0f8ce3d3212..47ee58c6f217 100644 --- a/azurerm/internal/services/springcloud/client/client.go +++ b/azurerm/internal/services/springcloud/client/client.go @@ -10,6 +10,7 @@ type Client struct { CertificatesClient *appplatform.CertificatesClient ConfigServersClient *appplatform.ConfigServersClient MonitoringSettingsClient *appplatform.MonitoringSettingsClient + DeploymentsClient *appplatform.DeploymentsClient ServicesClient *appplatform.ServicesClient } @@ -23,6 +24,9 @@ func NewClient(o *common.ClientOptions) *Client { configServersClient := appplatform.NewConfigServersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&configServersClient.Client, o.ResourceManagerAuthorizer) + deploymentsClient := appplatform.NewDeploymentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&deploymentsClient.Client, o.ResourceManagerAuthorizer) + monitoringSettingsClient := appplatform.NewMonitoringSettingsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&monitoringSettingsClient.Client, o.ResourceManagerAuthorizer) @@ -33,6 +37,7 @@ func NewClient(o *common.ClientOptions) *Client { AppsClient: &appsClient, CertificatesClient: &certificatesClient, ConfigServersClient: &configServersClient, + DeploymentsClient: &deploymentsClient, MonitoringSettingsClient: &monitoringSettingsClient, ServicesClient: &servicesClient, } diff --git a/azurerm/internal/services/springcloud/parse/spring_cloud_deployment.go b/azurerm/internal/services/springcloud/parse/spring_cloud_deployment.go new file mode 100644 index 000000000000..ae1843cd841c --- /dev/null +++ b/azurerm/internal/services/springcloud/parse/spring_cloud_deployment.go @@ -0,0 +1,81 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type SpringCloudDeploymentId struct { + SubscriptionId string + ResourceGroup string + SpringName string + AppName string + DeploymentName string +} + +func NewSpringCloudDeploymentID(subscriptionId, resourceGroup, springName, appName, deploymentName string) SpringCloudDeploymentId { + return SpringCloudDeploymentId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + SpringName: springName, + AppName: appName, + DeploymentName: deploymentName, + } +} + +func (id SpringCloudDeploymentId) String() string { + segments := []string{ + fmt.Sprintf("Deployment Name %q", id.DeploymentName), + fmt.Sprintf("App Name %q", id.AppName), + fmt.Sprintf("Spring Name %q", id.SpringName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Spring Cloud Deployment", segmentsStr) +} + +func (id SpringCloudDeploymentId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.AppPlatform/Spring/%s/apps/%s/deployments/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.SpringName, id.AppName, id.DeploymentName) +} + +// SpringCloudDeploymentID parses a SpringCloudDeployment ID into an SpringCloudDeploymentId struct +func SpringCloudDeploymentID(input string) (*SpringCloudDeploymentId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := SpringCloudDeploymentId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.SpringName, err = id.PopSegment("Spring"); err != nil { + return nil, err + } + if resourceId.AppName, err = id.PopSegment("apps"); err != nil { + return nil, err + } + if resourceId.DeploymentName, err = id.PopSegment("deployments"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/springcloud/parse/spring_cloud_deployment_test.go b/azurerm/internal/services/springcloud/parse/spring_cloud_deployment_test.go new file mode 100644 index 000000000000..cfa29bf777fa --- /dev/null +++ b/azurerm/internal/services/springcloud/parse/spring_cloud_deployment_test.go @@ -0,0 +1,144 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = SpringCloudDeploymentId{} + +func TestSpringCloudDeploymentIDFormatter(t *testing.T) { + actual := NewSpringCloudDeploymentID("12345678-1234-9876-4563-123456789012", "resGroup1", "spring1", "app1", "deploy1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/deploy1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestSpringCloudDeploymentID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *SpringCloudDeploymentId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/", + Error: true, + }, + + { + // missing value for SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/", + Error: true, + }, + + { + // missing AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/", + Error: true, + }, + + { + // missing value for AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/", + Error: true, + }, + + { + // missing DeploymentName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/", + Error: true, + }, + + { + // missing value for DeploymentName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/deploy1", + Expected: &SpringCloudDeploymentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + SpringName: "spring1", + AppName: "app1", + DeploymentName: "deploy1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APPPLATFORM/SPRING/SPRING1/APPS/APP1/DEPLOYMENTS/DEPLOY1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := SpringCloudDeploymentID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.SpringName != v.Expected.SpringName { + t.Fatalf("Expected %q but got %q for SpringName", v.Expected.SpringName, actual.SpringName) + } + if actual.AppName != v.Expected.AppName { + t.Fatalf("Expected %q but got %q for AppName", v.Expected.AppName, actual.AppName) + } + if actual.DeploymentName != v.Expected.DeploymentName { + t.Fatalf("Expected %q but got %q for DeploymentName", v.Expected.DeploymentName, actual.DeploymentName) + } + } +} diff --git a/azurerm/internal/services/springcloud/registration.go b/azurerm/internal/services/springcloud/registration.go index aa4586828a92..e5a02f9c637d 100644 --- a/azurerm/internal/services/springcloud/registration.go +++ b/azurerm/internal/services/springcloud/registration.go @@ -28,8 +28,10 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_spring_cloud_app": resourceSpringCloudApp(), - "azurerm_spring_cloud_certificate": resourceSpringCloudCertificate(), - "azurerm_spring_cloud_service": resourceSpringCloudService(), + "azurerm_spring_cloud_active_deployment": resourceSpringCloudActiveDeployment(), + "azurerm_spring_cloud_app": resourceSpringCloudApp(), + "azurerm_spring_cloud_certificate": resourceSpringCloudCertificate(), + "azurerm_spring_cloud_java_deployment": resourceSpringCloudJavaDeployment(), + "azurerm_spring_cloud_service": resourceSpringCloudService(), } } diff --git a/azurerm/internal/services/springcloud/resourceids.go b/azurerm/internal/services/springcloud/resourceids.go index 63641a7f2712..77cc9d46b6df 100644 --- a/azurerm/internal/services/springcloud/resourceids.go +++ b/azurerm/internal/services/springcloud/resourceids.go @@ -1,5 +1,6 @@ package springcloud //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudApp -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudDeployment -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/deploy1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudCertificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/certificates/cert1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudService -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1 diff --git a/azurerm/internal/services/springcloud/spring_cloud_active_deployment_resource.go b/azurerm/internal/services/springcloud/spring_cloud_active_deployment_resource.go new file mode 100644 index 000000000000..60cc965f9918 --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_active_deployment_resource.go @@ -0,0 +1,182 @@ +package springcloud + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/appplatform/mgmt/2020-07-01/appplatform" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/validate" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceSpringCloudActiveDeployment() *schema.Resource { + return &schema.Resource{ + Create: resourceSpringCloudActiveDeploymentCreate, + Read: resourceSpringCloudActiveDeploymentRead, + Update: resourceSpringCloudActiveDeploymentUpdate, + Delete: resourceSpringCloudActiveDeploymentDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.SpringCloudAppID(id) + return err + }), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "spring_cloud_app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SpringCloudAppID, + }, + + "deployment_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.SpringCloudDeploymentName, + }, + }, + } +} + +func resourceSpringCloudActiveDeploymentCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.AppsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + deploymentName := d.Get("deployment_name").(string) + appId, err := parse.SpringCloudAppID(d.Get("spring_cloud_app_id").(string)) + if err != nil { + return err + } + + resourceId := parse.NewSpringCloudAppID(appId.SubscriptionId, appId.ResourceGroup, appId.SpringName, appId.AppName).ID() + existing, err := client.Get(ctx, appId.ResourceGroup, appId.SpringName, appId.AppName, "") + if err != nil { + return fmt.Errorf("making Read request on AzureRM Spring Cloud App %q (Spring Cloud service %q / resource group %q): %+v", appId.AppName, appId.SpringName, appId.ResourceGroup, err) + } + + if existing.Properties != nil && existing.Properties.ActiveDeploymentName != nil && *existing.Properties.ActiveDeploymentName != "" { + return tf.ImportAsExistsError("azurerm_spring_cloud_active_deployment", resourceId) + } + + if existing.Properties == nil { + existing.Properties = &appplatform.AppResourceProperties{} + } + existing.Properties.ActiveDeploymentName = &deploymentName + + future, err := client.CreateOrUpdate(ctx, appId.ResourceGroup, appId.SpringName, appId.AppName, existing) + if err != nil { + return fmt.Errorf("setting active deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", deploymentName, appId.SpringName, appId.AppName, appId.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for setting active deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", deploymentName, appId.SpringName, appId.AppName, appId.ResourceGroup, err) + } + + d.SetId(resourceId) + + return resourceSpringCloudActiveDeploymentRead(d, meta) +} + +func resourceSpringCloudActiveDeploymentUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.AppsClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudAppID(d.Id()) + if err != nil { + return err + } + + deploymentName := d.Get("deployment_name").(string) + app := appplatform.AppResource{ + Properties: &appplatform.AppResourceProperties{ + ActiveDeploymentName: utils.String(deploymentName), + }, + } + + future, err := client.Update(ctx, id.ResourceGroup, id.SpringName, id.AppName, app) + if err != nil { + return fmt.Errorf("updating Active Deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", deploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for Update of Active Deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", deploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + return resourceSpringCloudActiveDeploymentRead(d, meta) +} + +func resourceSpringCloudActiveDeploymentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.AppsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudAppID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, "") + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Spring Cloud App %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("reading Active Deployment for Spring Cloud App %q (Spring Cloud Service %q / resource Group %q): %+v", id.AppName, id.SpringName, id.ResourceGroup, err) + } + + if resp.Properties == nil || resp.Properties.ActiveDeploymentName == nil { + log.Printf("[DEBUG] Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q) doesn't have Active Deployment - removing from state!", id.AppName, id.SpringName, id.ResourceGroup) + d.SetId("") + return nil + } + + d.Set("spring_cloud_app_id", id.ID()) + d.Set("deployment_name", resp.Properties.ActiveDeploymentName) + + return nil +} + +func resourceSpringCloudActiveDeploymentDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.AppsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudAppID(d.Id()) + if err != nil { + return err + } + + app := appplatform.AppResource{ + Properties: &appplatform.AppResourceProperties{ + ActiveDeploymentName: utils.String(""), + }, + } + + future, err := client.Update(ctx, id.ResourceGroup, id.SpringName, id.AppName, app) + if err != nil { + return fmt.Errorf("deleting Active Deployment (Spring Cloud Service %q / App %q / Resource Group %q): %+v", id.SpringName, id.AppName, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deleting active deployment (Spring Cloud Service %q / App %q / Resource Group %q): %+v", id.SpringName, id.AppName, id.ResourceGroup, err) + } + + return nil +} diff --git a/azurerm/internal/services/springcloud/spring_cloud_active_deployment_resource_test.go b/azurerm/internal/services/springcloud/spring_cloud_active_deployment_resource_test.go new file mode 100644 index 000000000000..14aae3246e15 --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_active_deployment_resource_test.go @@ -0,0 +1,152 @@ +package springcloud_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type SpringCloudActiveDeploymentResource struct { +} + +func TestAccSpringCloudActiveDeployment_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_active_deployment", "test") + r := SpringCloudActiveDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSpringCloudActiveDeployment_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_active_deployment", "test") + r := SpringCloudActiveDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccSpringCloudActiveDeployment_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_active_deployment", "test") + r := SpringCloudActiveDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r SpringCloudActiveDeploymentResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.SpringCloudAppID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.AppPlatform.AppsClient.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, "") + if err != nil { + return nil, fmt.Errorf("reading Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", id.AppName, id.SpringName, id.ResourceGroup, err) + } + + return utils.Bool(resp.Properties != nil && resp.Properties.ActiveDeploymentName != nil), nil +} + +func (r SpringCloudActiveDeploymentResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_active_deployment" "test" { + spring_cloud_app_id = azurerm_spring_cloud_app.test.id + deployment_name = azurerm_spring_cloud_java_deployment.test.name +} +`, r.template(data)) +} + +func (r SpringCloudActiveDeploymentResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_active_deployment" "import" { + spring_cloud_app_id = azurerm_spring_cloud_active_deployment.test.spring_cloud_app_id + deployment_name = azurerm_spring_cloud_active_deployment.test.deployment_name +} +`, r.basic(data)) +} + +func (r SpringCloudActiveDeploymentResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_java_deployment" "test2" { + name = "acctest-scjd2%s" + spring_cloud_app_id = azurerm_spring_cloud_app.test.id +} + +resource "azurerm_spring_cloud_active_deployment" "test" { + spring_cloud_app_id = azurerm_spring_cloud_app.test.id + deployment_name = azurerm_spring_cloud_java_deployment.test2.name +} +`, r.template(data), data.RandomString) +} + +func (SpringCloudActiveDeploymentResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-spring-%d" + location = "%s" +} + +resource "azurerm_spring_cloud_service" "test" { + name = "acctest-sc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_spring_cloud_app" "test" { + name = "acctest-sca-%d" + resource_group_name = azurerm_spring_cloud_service.test.resource_group_name + service_name = azurerm_spring_cloud_service.test.name +} + +resource "azurerm_spring_cloud_java_deployment" "test" { + name = "acctest-scjd%s" + spring_cloud_app_id = azurerm_spring_cloud_app.test.id +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomString) +} diff --git a/azurerm/internal/services/springcloud/spring_cloud_java_deployment_resource.go b/azurerm/internal/services/springcloud/spring_cloud_java_deployment_resource.go new file mode 100644 index 000000000000..b6c7caa606fd --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_java_deployment_resource.go @@ -0,0 +1,242 @@ +package springcloud + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/appplatform/mgmt/2020-07-01/appplatform" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/validate" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceSpringCloudJavaDeployment() *schema.Resource { + return &schema.Resource{ + Create: resourceSpringCloudJavaDeploymentCreateUpdate, + Read: resourceSpringCloudJavaDeploymentRead, + Update: resourceSpringCloudJavaDeploymentCreateUpdate, + Delete: resourceSpringCloudJavaDeploymentDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.SpringCloudDeploymentID(id) + return err + }), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SpringCloudDeploymentName, + }, + + "spring_cloud_app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SpringCloudAppID, + }, + + "cpu": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntBetween(1, 4), + }, + + "environment_variables": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "instance_count": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntBetween(1, 500), + }, + + "jvm_options": { + Type: schema.TypeString, + Optional: true, + }, + + "memory_in_gb": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validation.IntBetween(1, 8), + }, + + "runtime_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(appplatform.Java8), + string(appplatform.Java11), + }, false), + Default: string(appplatform.Java8), + }, + }, + } +} + +func resourceSpringCloudJavaDeploymentCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.DeploymentsClient + servicesClient := meta.(*clients.Client).AppPlatform.ServicesClient + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + appId, err := parse.SpringCloudAppID(d.Get("spring_cloud_app_id").(string)) + if err != nil { + return err + } + + id := parse.NewSpringCloudDeploymentID(subscriptionId, appId.ResourceGroup, appId.SpringName, appId.AppName, d.Get("name").(string)) + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.DeploymentName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing Spring Cloud Deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", id.DeploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_spring_cloud_java_deployment", id.ID()) + } + } + + service, err := servicesClient.Get(ctx, appId.ResourceGroup, appId.SpringName) + if err != nil { + return fmt.Errorf("checking for presence of existing Spring Cloud Service %q (Resource Group %q): %+v", appId.SpringName, appId.ResourceGroup, err) + } + if service.Sku == nil || service.Sku.Name == nil || service.Sku.Tier == nil { + return fmt.Errorf("invalid `sku` for Spring Cloud Service %q (Resource Group %q)", appId.SpringName, appId.ResourceGroup) + } + + deployment := appplatform.DeploymentResource{ + Sku: &appplatform.Sku{ + Name: service.Sku.Name, + Tier: service.Sku.Tier, + Capacity: utils.Int32(int32(d.Get("instance_count").(int))), + }, + Properties: &appplatform.DeploymentResourceProperties{ + Source: &appplatform.UserSourceInfo{ + Type: appplatform.Jar, + RelativePath: utils.String(""), + }, + DeploymentSettings: &appplatform.DeploymentSettings{ + CPU: utils.Int32(int32(d.Get("cpu").(int))), + MemoryInGB: utils.Int32(int32(d.Get("memory_in_gb").(int))), + JvmOptions: utils.String(d.Get("jvm_options").(string)), + EnvironmentVariables: expandSpringCloudDeploymentEnvironmentVariables(d.Get("environment_variables").(map[string]interface{})), + RuntimeVersion: appplatform.RuntimeVersion(d.Get("runtime_version").(string)), + }, + }, + } + + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.DeploymentName, deployment) + if err != nil { + return fmt.Errorf("creating/update Spring Cloud Deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", id.DeploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation/update of Spring Cloud Deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", id.DeploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + d.SetId(id.ID()) + + return resourceSpringCloudJavaDeploymentRead(d, meta) +} + +func resourceSpringCloudJavaDeploymentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.DeploymentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudDeploymentID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.DeploymentName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Spring Cloud deployment %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("reading Spring Cloud Deployment %q (Spring Cloud Service %q / App %q / resource Group %q): %+v", id.DeploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + d.Set("name", id.DeploymentName) + d.Set("spring_cloud_app_id", parse.NewSpringCloudAppID(id.SubscriptionId, id.ResourceGroup, id.SpringName, id.AppName).ID()) + if resp.Sku != nil { + d.Set("instance_count", resp.Sku.Capacity) + } + if resp.Properties != nil && resp.Properties.DeploymentSettings != nil { + settings := resp.Properties.DeploymentSettings + d.Set("cpu", settings.CPU) + d.Set("memory_in_gb", settings.MemoryInGB) + d.Set("jvm_options", settings.JvmOptions) + d.Set("environment_variables", flattenSpringCloudDeploymentEnvironmentVariables(settings.EnvironmentVariables)) + d.Set("runtime_version", settings.RuntimeVersion) + } + + return nil +} + +func resourceSpringCloudJavaDeploymentDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.DeploymentsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudDeploymentID(d.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.DeploymentName); err != nil { + return fmt.Errorf("deleting Spring Cloud Deployment %q (Spring Cloud Service %q / App %q / resource Group %q): %+v", id.DeploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + return nil +} + +func expandSpringCloudDeploymentEnvironmentVariables(envMap map[string]interface{}) map[string]*string { + output := make(map[string]*string, len(envMap)) + + for k, v := range envMap { + output[k] = utils.String(v.(string)) + } + + return output +} + +func flattenSpringCloudDeploymentEnvironmentVariables(envMap map[string]*string) map[string]interface{} { + output := make(map[string]interface{}, len(envMap)) + for i, v := range envMap { + if v == nil { + continue + } + output[i] = *v + } + return output +} diff --git a/azurerm/internal/services/springcloud/spring_cloud_java_deployment_resource_test.go b/azurerm/internal/services/springcloud/spring_cloud_java_deployment_resource_test.go new file mode 100644 index 000000000000..a221a2f65874 --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_java_deployment_resource_test.go @@ -0,0 +1,174 @@ +package springcloud_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type SpringCloudJavaDeploymentResource struct { +} + +func TestAccSpringCloudJavaDeployment_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_java_deployment", "test") + r := SpringCloudJavaDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSpringCloudJavaDeployment_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_java_deployment", "test") + r := SpringCloudJavaDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccSpringCloudJavaDeployment_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_java_deployment", "test") + r := SpringCloudJavaDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSpringCloudJavaDeployment_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_java_deployment", "test") + r := SpringCloudJavaDeploymentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r SpringCloudJavaDeploymentResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.SpringCloudDeploymentID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.AppPlatform.DeploymentsClient.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.DeploymentName) + if err != nil { + return nil, fmt.Errorf("reading Spring Cloud Deployment %q (Spring Cloud Service %q / App %q / Resource Group %q): %+v", id.DeploymentName, id.SpringName, id.AppName, id.ResourceGroup, err) + } + + return utils.Bool(resp.Properties != nil), nil +} + +func (r SpringCloudJavaDeploymentResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_java_deployment" "test" { + name = "acctest-scjd%s" + spring_cloud_app_id = azurerm_spring_cloud_app.test.id +} +`, r.template(data), data.RandomString) +} + +func (r SpringCloudJavaDeploymentResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_java_deployment" "import" { + name = azurerm_spring_cloud_java_deployment.test.name + spring_cloud_app_id = azurerm_spring_cloud_java_deployment.test.spring_cloud_app_id +} +`, r.basic(data)) +} + +func (r SpringCloudJavaDeploymentResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_java_deployment" "test" { + name = "acctest-scjd%s" + spring_cloud_app_id = azurerm_spring_cloud_app.test.id + cpu = 2 + memory_in_gb = 4 + instance_count = 2 + jvm_options = "-XX:+PrintGC" + runtime_version = "Java_11" + + environment_variables = { + "Foo" : "Bar" + "Env" : "Staging" + } +} +`, r.template(data), data.RandomString) +} + +func (SpringCloudJavaDeploymentResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-spring-%d" + location = "%s" +} + +resource "azurerm_spring_cloud_service" "test" { + name = "acctest-sc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_spring_cloud_app" "test" { + name = "acctest-sca-%d" + resource_group_name = azurerm_spring_cloud_service.test.resource_group_name + service_name = azurerm_spring_cloud_service.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_id.go b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_id.go new file mode 100644 index 000000000000..aca91b0e499d --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" +) + +func SpringCloudDeploymentID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.SpringCloudDeploymentID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_id_test.go b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_id_test.go new file mode 100644 index 000000000000..3eb80af43e92 --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestSpringCloudDeploymentID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/", + Valid: false, + }, + + { + // missing value for SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/", + Valid: false, + }, + + { + // missing AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/", + Valid: false, + }, + + { + // missing value for AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/", + Valid: false, + }, + + { + // missing DeploymentName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/", + Valid: false, + }, + + { + // missing value for DeploymentName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/deploy1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APPPLATFORM/SPRING/SPRING1/APPS/APP1/DEPLOYMENTS/DEPLOY1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := SpringCloudDeploymentID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_name.go b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_name.go new file mode 100644 index 000000000000..9cd4d04b3c79 --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_name.go @@ -0,0 +1,25 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func SpringCloudDeploymentName(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, append(errors, fmt.Errorf("expected type of %s to be string", k)) + } + + // The name attribute rules are : + // 1. can contain only lowercase letters, numbers and hyphens. + // 2. The first character must be a letter. + // 3. The last character must be a letter or number + // 4. The value must be between 4 and 32 characters long + + if !regexp.MustCompile(`^([a-z])([a-z\d-]{2,30})([a-z\d])$`).MatchString(v) { + errors = append(errors, fmt.Errorf("%s must begin with a letter, end with a letter or number, contain only lowercase letters, numbers and hyphens. The value must be between 4 and 32 characters long.", k)) + } + + return nil, errors +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_name_test.go b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_name_test.go new file mode 100644 index 000000000000..c2d842f91d14 --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_deployment_name_test.go @@ -0,0 +1,61 @@ +package validate + +import "testing" + +func TestSpringCloudDeploymentName(t *testing.T) { + testData := []struct { + input string + expected bool + }{ + { + // empty + input: "", + expected: false, + }, + { + // basic example + input: "ab-c", + expected: true, + }, + { + // can't start with a number + input: "1abc", + expected: false, + }, + { + // can't contain underscore + input: "ab_c", + expected: false, + }, + { + // can't end with hyphen + input: "abc-", + expected: false, + }, + { + // can not short than 4 characters + input: "abc", + expected: false, + }, + { + // 32 chars + input: "abcdefghijklmnopqrstuvwxyzabcdef", + expected: true, + }, + { + // 33 chars + input: "abcdefghijklmnopqrstuvwxyzabcdefg", + expected: false, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q..", v.input) + + _, errors := SpringCloudDeploymentName(v.input, "name") + actual := len(errors) == 0 + if v.expected != actual { + t.Fatalf("Expected %t but got %t", v.expected, actual) + } + } +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 74cda79c1a43..81731cae76ed 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -967,6 +967,10 @@
  • Spring Cloud