Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: azurerm_app_service_certificate #4192

Merged
merged 6 commits into from
Sep 1, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -143,6 +143,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
260 changes: 260 additions & 0 deletions azurerm/resource_arm_app_service_certificate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
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(),

"friendly_name": {
katbyte marked this conversation as resolved.
Show resolved Hide resolved
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,
},
},

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

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

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

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

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

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

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

"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)
}

joakimhellum marked this conversation as resolved.
Show resolved Hide resolved
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)
d.Set("key_vault_id", props.KeyVaultID)
joakimhellum marked this conversation as resolved.
Show resolved Hide resolved
d.Set("key_vault_secret_name", props.KeyVaultSecretName)
}

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