Skip to content

Commit

Permalink
New resource/Data Source: azurerm_ssh_public_key (#9842)
Browse files Browse the repository at this point in the history
Added new resource and data source azurerm_ssh_public_key to support creation/retrieving SSH Public Keys

Fixes #9822

docs.microsoft.com/en-us/rest/api/compute/sshpublickeys
Documentation Updated + Acceptance test added and passed.
  • Loading branch information
AliAllomani authored Jan 7, 2021
1 parent bfdc8b2 commit 1aba922
Show file tree
Hide file tree
Showing 13 changed files with 868 additions and 0 deletions.
5 changes: 5 additions & 0 deletions azurerm/internal/services/compute/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Client struct {
VMScaleSetVMsClient *compute.VirtualMachineScaleSetVMsClient
VMClient *compute.VirtualMachinesClient
VMImageClient *compute.VirtualMachineImagesClient
SSHPublicKeysClient *compute.SSHPublicKeysClient
}

func NewClient(o *common.ClientOptions) *Client {
Expand Down Expand Up @@ -98,6 +99,9 @@ func NewClient(o *common.ClientOptions) *Client {
vmClient := compute.NewVirtualMachinesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&vmClient.Client, o.ResourceManagerAuthorizer)

sshPublicKeysClient := compute.NewSSHPublicKeysClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&sshPublicKeysClient.Client, o.ResourceManagerAuthorizer)

return &Client{
AvailabilitySetsClient: &availabilitySetsClient,
DedicatedHostsClient: &dedicatedHostsClient,
Expand All @@ -121,5 +125,6 @@ func NewClient(o *common.ClientOptions) *Client {
VMScaleSetVMsClient: &vmScaleSetVMsClient,
VMClient: &vmClient,
VMImageClient: &vmImageClient,
SSHPublicKeysClient: &sshPublicKeysClient,
}
}
69 changes: 69 additions & 0 deletions azurerm/internal/services/compute/parse/ssh_public_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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 SSHPublicKeyId struct {
SubscriptionId string
ResourceGroup string
Name string
}

func NewSSHPublicKeyID(subscriptionId, resourceGroup, name string) SSHPublicKeyId {
return SSHPublicKeyId{
SubscriptionId: subscriptionId,
ResourceGroup: resourceGroup,
Name: name,
}
}

func (id SSHPublicKeyId) String() string {
segments := []string{
fmt.Sprintf("Name %q", id.Name),
fmt.Sprintf("Resource Group %q", id.ResourceGroup),
}
segmentsStr := strings.Join(segments, " / ")
return fmt.Sprintf("%s: (%s)", "S S H Public Key", segmentsStr)
}

func (id SSHPublicKeyId) ID() string {
fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/sshPublicKeys/%s"
return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.Name)
}

// SSHPublicKeyID parses a SSHPublicKey ID into an SSHPublicKeyId struct
func SSHPublicKeyID(input string) (*SSHPublicKeyId, error) {
id, err := azure.ParseAzureResourceID(input)
if err != nil {
return nil, err
}

resourceId := SSHPublicKeyId{
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.Name, err = id.PopSegment("sshPublicKeys"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &resourceId, nil
}
112 changes: 112 additions & 0 deletions azurerm/internal/services/compute/parse/ssh_public_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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 = SSHPublicKeyId{}

func TestSSHPublicKeyIDFormatter(t *testing.T) {
actual := NewSSHPublicKeyID("12345678-1234-9876-4563-123456789012", "resGroup1", "sshpublickey1").ID()
expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/sshPublicKeys/sshpublickey1"
if actual != expected {
t.Fatalf("Expected %q but got %q", expected, actual)
}
}

func TestSSHPublicKeyID(t *testing.T) {
testData := []struct {
Input string
Error bool
Expected *SSHPublicKeyId
}{

{
// 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 Name
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/",
Error: true,
},

{
// missing value for Name
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/sshPublicKeys/",
Error: true,
},

{
// valid
Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/sshPublicKeys/sshpublickey1",
Expected: &SSHPublicKeyId{
SubscriptionId: "12345678-1234-9876-4563-123456789012",
ResourceGroup: "resGroup1",
Name: "sshpublickey1",
},
},

{
// upper-cased
Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.COMPUTE/SSHPUBLICKEYS/SSHPUBLICKEY1",
Error: true,
},
}

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

actual, err := SSHPublicKeyID(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.Name != v.Expected.Name {
t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name)
}
}
}
2 changes: 2 additions & 0 deletions azurerm/internal/services/compute/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource {
"azurerm_snapshot": dataSourceArmSnapshot(),
"azurerm_virtual_machine": dataSourceArmVirtualMachine(),
"azurerm_virtual_machine_scale_set": dataSourceArmVirtualMachineScaleSet(),
"azurerm_ssh_public_key": dataSourceArmSshPublicKey(),
}
}

Expand Down Expand Up @@ -67,6 +68,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource {
"azurerm_virtual_machine_scale_set_extension": resourceArmVirtualMachineScaleSetExtension(),
"azurerm_windows_virtual_machine": resourceWindowsVirtualMachine(),
"azurerm_windows_virtual_machine_scale_set": resourceArmWindowsVirtualMachineScaleSet(),
"azurerm_ssh_public_key": resourceSshPublicKey(),
}

return resources
Expand Down
1 change: 1 addition & 0 deletions azurerm/internal/services/compute/resourceids.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ package compute
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualMachineExtension -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachines/machine1/extensions/extension1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualMachineScaleSet -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=VirtualMachineScaleSetExtension -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/virtualMachineScaleSets/scaleSet1/extensions/extension1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SSHPublicKey -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/sshPublicKeys/sshpublickey1
//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DiskAccess -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.Compute/diskAccesses/diskAccess1
74 changes: 74 additions & 0 deletions azurerm/internal/services/compute/ssh_public_key_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package compute

import (
"fmt"
"regexp"
"time"

"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/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func dataSourceArmSshPublicKey() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmSshPublicKeyRead,

Timeouts: &schema.ResourceTimeout{
Read: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{

"name": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringMatch(
regexp.MustCompile("^[-a-zA-Z0-9(_)]{1,128}$"),
"Public SSH Key name must be 1 - 128 characters long, can contain letters, numbers, underscores, and hyphens (but the first and last character must be a letter or number).",
),
},

"resource_group_name": azure.SchemaResourceGroupNameForDataSource(),

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

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

func dataSourceArmSshPublicKeyRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).Compute.SSHPublicKeysClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

resGroup := d.Get("resource_group_name").(string)
name := d.Get("name").(string)

resp, err := client.Get(ctx, resGroup, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("Error: SSH Public Key %q (Resource Group %q) was not found", name, resGroup)
}
return fmt.Errorf("[ERROR] Error making Read request on Azure SSH Public Key %q (Resource Group %q): %s", name, resGroup, err)
}

d.SetId(*resp.ID)

d.Set("name", name)
d.Set("resource_group_name", resGroup)

if props := resp.SSHPublicKeyResourceProperties; props != nil {
d.Set("public_key", props.PublicKey)
}

return tags.FlattenAndSet(d, resp.Tags)
}
Loading

0 comments on commit 1aba922

Please sign in to comment.