Skip to content

Commit

Permalink
"azurerm_spring_cloud_app" - supports property https_only, `is_publ…
Browse files Browse the repository at this point in the history
…ic`, `persistent_disk` (#9957)

spring cloud app supports more properties: https_only, is_public, persistent_disk

https_only and persistent_disk could only be set by update, creat rest api will ignore those values
  • Loading branch information
njuCZ authored Jan 8, 2021
1 parent 69f442d commit 439486a
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 5 deletions.
136 changes: 131 additions & 5 deletions azurerm/internal/services/springcloud/spring_cloud_app_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import (

func resourceSpringCloudApp() *schema.Resource {
return &schema.Resource{
Create: resourceSpringCloudAppCreateUpdate,
Create: resourceSpringCloudAppCreate,
Read: resourceSpringCloudAppRead,
Update: resourceSpringCloudAppCreateUpdate,
Update: resourceSpringCloudAppUpdate,
Delete: resourceSpringCloudAppDelete,

Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error {
Expand Down Expand Up @@ -81,11 +81,51 @@ func resourceSpringCloudApp() *schema.Resource {
},
},
},

"is_public": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},

"https_only": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},

"persistent_disk": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"size_in_gb": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(0, 50),
},

"mount_path": {
Type: schema.TypeString,
Optional: true,
Default: "/persistent",
ValidateFunc: validate.MountPath,
},
},
},
},

"url": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceSpringCloudAppCreateUpdate(d *schema.ResourceData, meta interface{}) error {
func resourceSpringCloudAppCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).AppPlatform.AppsClient
servicesClient := meta.(*clients.Client).AppPlatform.ServicesClient
subscriptionId := meta.(*clients.Client).Account.SubscriptionId
Expand Down Expand Up @@ -117,19 +157,61 @@ func resourceSpringCloudAppCreateUpdate(d *schema.ResourceData, meta interface{}
app := appplatform.AppResource{
Location: serviceResp.Location,
Identity: expandSpringCloudAppIdentity(d.Get("identity").([]interface{})),
Properties: &appplatform.AppResourceProperties{
Public: utils.Bool(d.Get("is_public").(bool)),
},
}
future, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, name, app)
if err != nil {
return fmt.Errorf("creating/update Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
return fmt.Errorf("creating Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
}
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for creation of Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
}

// HTTPSOnly and PersistentDisk could only be set by update
app.Properties.HTTPSOnly = utils.Bool(d.Get("https_only").(bool))
app.Properties.PersistentDisk = expandSpringCloudAppPersistentDisk(d.Get("persistent_disk").([]interface{}))
future, err = client.CreateOrUpdate(ctx, resourceGroup, serviceName, name, app)
if err != nil {
return fmt.Errorf("update Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
}
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for creation/update of Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
return fmt.Errorf("waiting for update of Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
}

d.SetId(resourceId)
return resourceSpringCloudAppRead(d, meta)
}

func resourceSpringCloudAppUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).AppPlatform.AppsClient
ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d)
defer cancel()

name := d.Get("name").(string)
resourceGroup := d.Get("resource_group_name").(string)
serviceName := d.Get("service_name").(string)

app := appplatform.AppResource{
Identity: expandSpringCloudAppIdentity(d.Get("identity").([]interface{})),
Properties: &appplatform.AppResourceProperties{
Public: utils.Bool(d.Get("is_public").(bool)),
HTTPSOnly: utils.Bool(d.Get("https_only").(bool)),
PersistentDisk: expandSpringCloudAppPersistentDisk(d.Get("persistent_disk").([]interface{})),
},
}
future, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, name, app)
if err != nil {
return fmt.Errorf("update Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
}
if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("waiting for update of Spring Cloud App %q (Spring Cloud Service %q / Resource Group %q): %+v", name, serviceName, resourceGroup, err)
}

return resourceSpringCloudAppRead(d, meta)
}

func resourceSpringCloudAppRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).AppPlatform.AppsClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
Expand Down Expand Up @@ -158,6 +240,16 @@ func resourceSpringCloudAppRead(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("setting `identity`: %s", err)
}

if prop := resp.Properties; prop != nil {
d.Set("is_public", prop.Public)
d.Set("https_only", prop.HTTPSOnly)
d.Set("url", prop.URL)

if err := d.Set("persistent_disk", flattenSpringCloudAppPersistentDisk(prop.PersistentDisk)); err != nil {
return fmt.Errorf("setting `persistent_disk`: %s", err)
}
}

return nil
}

Expand Down Expand Up @@ -190,6 +282,17 @@ func expandSpringCloudAppIdentity(input []interface{}) *appplatform.ManagedIdent
}
}

func expandSpringCloudAppPersistentDisk(input []interface{}) *appplatform.PersistentDisk {
if len(input) == 0 || input[0] == nil {
return nil
}
raw := input[0].(map[string]interface{})
return &appplatform.PersistentDisk{
SizeInGB: utils.Int32(int32(raw["size_in_gb"].(int))),
MountPath: utils.String(raw["mount_path"].(string)),
}
}

func flattenSpringCloudAppIdentity(identity *appplatform.ManagedIdentityProperties) []interface{} {
if identity == nil {
return make([]interface{}, 0)
Expand All @@ -213,3 +316,26 @@ func flattenSpringCloudAppIdentity(identity *appplatform.ManagedIdentityProperti
},
}
}

func flattenSpringCloudAppPersistentDisk(input *appplatform.PersistentDisk) []interface{} {
if input == nil {
return make([]interface{}, 0)
}

sizeInGB := 0
if input.SizeInGB != nil {
sizeInGB = int(*input.SizeInGB)
}

mountPath := ""
if input.MountPath != nil {
mountPath = *input.MountPath
}

return []interface{}{
map[string]interface{}{
"size_in_gb": sizeInGB,
"mount_path": mountPath,
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func TestAccSpringCloudApp_complete(t *testing.T) {
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("identity.0.principal_id").Exists(),
check.That(data.ResourceName).Key("identity.0.tenant_id").Exists(),
check.That(data.ResourceName).Key("url").Exists(),
),
},
data.ImportStep(),
Expand Down Expand Up @@ -141,10 +142,17 @@ 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
is_public = true
https_only = true
identity {
type = "SystemAssigned"
}
persistent_disk {
size_in_gb = 50
mount_path = "/persistent"
}
}
`, r.template(data), data.RandomInteger)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package validate

import (
"fmt"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
)

func MountPath(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))
}
if len(v) < 2 || len(v) > 255 {
errors = append(errors, fmt.Errorf("%s should equal or great than 2 and euqal or less than 255", k))
} else if m, _ := validate.RegExHelper(i, k, `^(?:\/(?:[a-zA-Z][a-zA-Z0-9]*))+$`); !m {
errors = append(errors, fmt.Errorf("%s is not valid, must match the regular expression ^(?:\\/(?:[a-zA-Z][a-zA-Z0-9]*))+$", k))
}
return nil, errors
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package validate

import "testing"

func TestMountPath(t *testing.T) {
testData := []struct {
input string
expected bool
}{
{
// empty
input: "",
expected: false,
},
{
// basic example
input: "/persistent",
expected: true,
},
{
// invalid path
input: "//sdf",
expected: false,
},
{
// can not short than 2 characters
input: "/",
expected: false,
},
{
// 256 characters
input: "/abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu",
expected: false,
},
}

for _, v := range testData {
t.Logf("[DEBUG] Testing %q..", v.input)

_, errors := MountPath(v.input, "name")
actual := len(errors) == 0
if v.expected != actual {
t.Fatalf("Expected %t but got %t", v.expected, actual)
}
}
}
16 changes: 16 additions & 0 deletions website/docs/r/spring_cloud_app.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,34 @@ The following arguments are supported:

* `identity` - (Optional) An `identity` block as defined below.

* `is_public` - (Optional) Does the Spring Cloud Application have public endpoint? Defaults to `false`.

* `https_only` - (Optional) Is only https allowed? Defaults to `false`.

* `persistent_disk` - (Optional) An `persistent_disk` block as defined below.

---

An `identity` block supports the following:

* `type` - (Required) Specifies the identity type of the Spring Cloud Application. Possible value is `SystemAssigned`.

---

An `persistent_disk` block supports the following:

* `size_in_gb` - (Required) Specifies the size of the persistent disk in GB. Possible values are between `0` and `50`.

* `mount_path` - (Optional) Specifies the mount path of the persistent disk. Defaults to `/persistent`.

## Attributes Reference

The following attributes are exported:

* `id` - The ID of the Spring Cloud Application.

* `url` - The public endpoint of the Spring Cloud Application.

---

An `identity` block exports the following:
Expand Down

0 comments on commit 439486a

Please sign in to comment.