Skip to content

Commit

Permalink
New Resource: azurerm_app_service_certificate (#4192)
Browse files Browse the repository at this point in the history
Reference to #1136
  • Loading branch information
Joakim Bakke Hellum authored and katbyte committed Sep 1, 2019
1 parent 38d2a70 commit 7d608fe
Show file tree
Hide file tree
Showing 8 changed files with 570 additions and 0 deletions.
5 changes: 5 additions & 0 deletions azurerm/internal/services/web/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
type Client struct {
AppServicePlansClient *web.AppServicePlansClient
AppServicesClient *web.AppsClient
CertificatesClient *web.CertificatesClient
}

func BuildClient(o *common.ClientOptions) *Client {
Expand All @@ -18,8 +19,12 @@ func BuildClient(o *common.ClientOptions) *Client {
AppServicesClient := web.NewAppsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&AppServicesClient.Client, o.ResourceManagerAuthorizer)

CertificatesClient := web.NewCertificatesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&CertificatesClient.Client, o.ResourceManagerAuthorizer)

return &Client{
AppServicePlansClient: &AppServicePlansClient,
AppServicesClient: &AppServicesClient,
CertificatesClient: &CertificatesClient,
}
}
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_api_management_subscription": resourceArmApiManagementSubscription(),
"azurerm_api_management_user": resourceArmApiManagementUser(),
"azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(),
"azurerm_app_service_certificate": resourceArmAppServiceCertificate(),
"azurerm_app_service_custom_hostname_binding": resourceArmAppServiceCustomHostnameBinding(),
"azurerm_app_service_plan": resourceArmAppServicePlan(),
"azurerm_app_service_slot": resourceArmAppServiceSlot(),
Expand Down
258 changes: 258 additions & 0 deletions azurerm/resource_arm_app_service_certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
package azurerm

import (
"encoding/base64"
"fmt"
"log"
"time"

"github.com/Azure/azure-sdk-for-go/services/web/mgmt/2018-02-01/web"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmAppServiceCertificate() *schema.Resource {
return &schema.Resource{
Create: resourceArmAppServiceCertificateCreateUpdate,
Read: resourceArmAppServiceCertificateRead,
Update: resourceArmAppServiceCertificateCreateUpdate,
Delete: resourceArmAppServiceCertificateDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.NoEmptyStrings,
},

"location": azure.SchemaLocation(),

"resource_group_name": azure.SchemaResourceGroupName(),

"pfx_blob": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ForceNew: true,
ValidateFunc: validate.Base64String(),
},

"password": {
Type: schema.TypeString,
Optional: true,
Sensitive: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},

"key_vault_secret_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: azure.ValidateKeyVaultChildId,
ConflictsWith: []string{"pfx_blob", "password"},
},

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

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

"host_names": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

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

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

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

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

"tags": tags.Schema(),
},
}
}

func resourceArmAppServiceCertificateCreateUpdate(d *schema.ResourceData, meta interface{}) error {
vaultClient := meta.(*ArmClient).keyvault.VaultsClient
client := meta.(*ArmClient).web.CertificatesClient
ctx := meta.(*ArmClient).StopContext

log.Printf("[INFO] preparing arguments for App Service Certificate creation.")

name := d.Get("name").(string)
resourceGroup := d.Get("resource_group_name").(string)
location := azure.NormalizeLocation(d.Get("location").(string))
pfxBlob := d.Get("pfx_blob").(string)
password := d.Get("password").(string)
keyVaultSecretId := d.Get("key_vault_secret_id").(string)
t := d.Get("tags").(map[string]interface{})

if pfxBlob == "" && keyVaultSecretId == "" {
return fmt.Errorf("Either `pfx_blob` or `key_vault_secret_id` must be set")
}

if requireResourcesToBeImported && d.IsNewResource() {
existing, err := client.Get(ctx, resourceGroup, name)
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("Error checking for presence of existing App Service Certificate %q (Resource Group %q): %s", name, resourceGroup, err)
}
}

if existing.ID != nil && *existing.ID != "" {
return tf.ImportAsExistsError("azurerm_app_service_certificate", *existing.ID)
}
}

certificate := web.Certificate{
CertificateProperties: &web.CertificateProperties{
Password: utils.String(password),
},
Location: utils.String(location),
Tags: tags.Expand(t),
}

if pfxBlob != "" {
decodedPfxBlob, err := base64.StdEncoding.DecodeString(pfxBlob)
if err != nil {
return fmt.Errorf("Could not decode PFX blob: %+v", err)
}
certificate.CertificateProperties.PfxBlob = &decodedPfxBlob
}

if keyVaultSecretId != "" {
parsedSecretId, err := azure.ParseKeyVaultChildID(keyVaultSecretId)
if err != nil {
return err
}

keyVaultBaseUrl := parsedSecretId.KeyVaultBaseUrl

keyVaultId, err := azure.GetKeyVaultIDFromBaseUrl(ctx, vaultClient, keyVaultBaseUrl)
if err != nil {
return fmt.Errorf("Error retrieving the Resource ID for the Key Vault at URL %q: %s", keyVaultBaseUrl, err)
}
if keyVaultId == nil {
return fmt.Errorf("Unable to determine the Resource ID for the Key Vault at URL %q", keyVaultBaseUrl)
}

certificate.CertificateProperties.KeyVaultID = keyVaultId
certificate.CertificateProperties.KeyVaultSecretName = utils.String(parsedSecretId.Name)
}

if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, certificate); err != nil {
return fmt.Errorf("Error creating/updating App Service Certificate %q (Resource Group %q): %s", name, resourceGroup, err)
}

read, err := client.Get(ctx, resourceGroup, name)
if err != nil {
return fmt.Errorf("Error retrieving App Service Certificate %q (Resource Group %q): %s", name, resourceGroup, err)
}
if read.ID == nil {
return fmt.Errorf("Cannot read App Service Certificate %q (Resource Group %q) ID", name, resourceGroup)
}

d.SetId(*read.ID)

return resourceArmAppServiceCertificateRead(d, meta)
}

func resourceArmAppServiceCertificateRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).web.CertificatesClient

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}

resourceGroup := id.ResourceGroup
name := id.Path["certificates"]

ctx := meta.(*ArmClient).StopContext
resp, err := client.Get(ctx, resourceGroup, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
log.Printf("[DEBUG] App Service Certificate %q (Resource Group %q) was not found - removing from state", name, resourceGroup)
d.SetId("")
return nil
}
return fmt.Errorf("Error making Read request on App Service Certificate %q (Resource Group %q): %+v", name, resourceGroup, err)
}

d.Set("name", resp.Name)
d.Set("resource_group_name", resourceGroup)

if location := resp.Location; location != nil {
d.Set("location", azure.NormalizeLocation(*location))
}

if props := resp.CertificateProperties; props != nil {
d.Set("friendly_name", props.FriendlyName)
d.Set("subject_name", props.SubjectName)
d.Set("host_names", props.HostNames)
d.Set("issuer", props.Issuer)
d.Set("issue_date", props.IssueDate.Format(time.RFC3339))
d.Set("expiration_date", props.ExpirationDate.Format(time.RFC3339))
d.Set("thumbprint", props.Thumbprint)
}

flattenAndSetTags(d, resp.Tags)

return nil
}

func resourceArmAppServiceCertificateDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).web.CertificatesClient

id, err := azure.ParseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
name := id.Path["certificates"]

log.Printf("[DEBUG] Deleting App Service Certificate %q (Resource Group %q)", name, resourceGroup)

ctx := meta.(*ArmClient).StopContext
resp, err := client.Delete(ctx, resourceGroup, name)
if err != nil {
if !utils.ResponseWasNotFound(resp) {
return fmt.Errorf("Error deleting App Service Certificate %q (Resource Group %q): %s)", name, resourceGroup, err)
}
}

return nil
}
Loading

0 comments on commit 7d608fe

Please sign in to comment.