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: DevSpace Controller for AKS cluster #2086

Merged
merged 21 commits into from
Oct 29, 2018
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
15eab7b
:sparkles: (Devspace controller.) Init work for devspace controller.
metacpp Oct 3, 2018
27980f7
Merge branch 'master' into devspace
metacpp Oct 9, 2018
8a65b01
:sparkles: (Create operation for DevSpaces controller.) Add create op…
metacpp Oct 10, 2018
288bdeb
:sparkles: (DevSpaces controller.) RUD operations for devspaces contr…
metacpp Oct 13, 2018
c0ec4c5
:white_check_mark: (DevSpace controller test and doc.) Add doc and te…
metacpp Oct 16, 2018
e39fe29
Merge and resolve conflicts from master branch.
metacpp Oct 16, 2018
bfd7654
:bug: (DevSpace controller.) Schema update.
metacpp Oct 16, 2018
983d98a
:green_heart: (Go fmtcheck issue.) Fix go fmtcheck issue.
metacpp Oct 16, 2018
a8edf23
:green_heart: (Test fix.) Test fix for DevSpace controller.
metacpp Oct 16, 2018
93c8b26
Resolve conflicts from master branch.
metacpp Oct 16, 2018
0071ef1
Fix: the nil pointer issue in SKU expand function.
metacpp Oct 16, 2018
025db43
Fix: remove output of credential information from state file.
metacpp Oct 16, 2018
81bf9b9
Remove state import validation.
metacpp Oct 17, 2018
275d7e2
Merge branch 'master' into devspace
katbyte Oct 26, 2018
0bcdef4
Merge branch 'master' into devspace
metacpp Oct 29, 2018
a28ae97
Upgrade the DevSpace SDK to v21.3.0
metacpp Oct 29, 2018
3fe1835
Add `azure.ValidateResourceID` for `target_container_host_resource_id`
katbyte Oct 29, 2018
5076888
Add validation functions for fields.
metacpp Oct 29, 2018
2657475
Merge branch 'devspace' of github.com:terraform-providers/terraform-p…
metacpp Oct 29, 2018
24b87f2
Update CU operation functions for DevSpace to use Get instead of futu…
metacpp Oct 29, 2018
e2c0f46
Update azurerm/helpers/validate/devspace.go
katbyte Oct 29, 2018
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
12 changes: 12 additions & 0 deletions azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql"
"github.com/Azure/azure-sdk-for-go/services/preview/apimanagement/mgmt/2018-06-01-preview/apimanagement"
"github.com/Azure/azure-sdk-for-go/services/preview/authorization/mgmt/2018-01-01-preview/authorization"
"github.com/Azure/azure-sdk-for-go/services/preview/devspaces/mgmt/2018-06-01-preview/devspaces"
"github.com/Azure/azure-sdk-for-go/services/preview/dns/mgmt/2018-03-01-preview/dns"
"github.com/Azure/azure-sdk-for-go/services/preview/monitor/mgmt/2018-03-01/insights"
"github.com/Azure/azure-sdk-for-go/services/preview/msi/mgmt/2015-08-31-preview/msi"
Expand All @@ -61,6 +62,7 @@ import (
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage"
"github.com/Azure/azure-sdk-for-go/services/trafficmanager/mgmt/2017-05-01/trafficmanager"
"github.com/Azure/azure-sdk-for-go/services/web/mgmt/2018-02-01/web"

mainStorage "github.com/Azure/azure-sdk-for-go/storage"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/adal"
Expand Down Expand Up @@ -162,6 +164,9 @@ type ArmClient struct {
devTestVirtualMachinesClient dtl.VirtualMachinesClient
devTestVirtualNetworksClient dtl.VirtualNetworksClient

// DevSpace
devSpaceControllerClient devspaces.ControllersClient

// Databases
mysqlConfigurationsClient mysql.ConfigurationsClient
mysqlDatabasesClient mysql.DatabasesClient
Expand Down Expand Up @@ -507,6 +512,7 @@ func getArmClient(c *authentication.Config) (*ArmClient, error) {
client.registerDatabases(endpoint, c.SubscriptionID, auth, sender)
client.registerDataLakeStoreClients(endpoint, c.SubscriptionID, auth)
client.registerDeviceClients(endpoint, c.SubscriptionID, auth)
client.registerDevSpaceClients(endpoint, c.SubscriptionID, auth)
client.registerDevTestClients(endpoint, c.SubscriptionID, auth)
client.registerDNSClients(endpoint, c.SubscriptionID, auth)
client.registerEventGridClients(endpoint, c.SubscriptionID, auth)
Expand Down Expand Up @@ -835,6 +841,12 @@ func (c *ArmClient) registerDevTestClients(endpoint, subscriptionId string, auth
c.devTestVirtualNetworksClient = devTestVirtualNetworksClient
}

func (c *ArmClient) registerDevSpaceClients(endpoint, subscriptionId string, auth autorest.Authorizer) {
controllersClient := devspaces.NewControllersClientWithBaseURI(endpoint, subscriptionId)
c.configureClient(&controllersClient.Client, auth)
c.devSpaceControllerClient = controllersClient
}

func (c *ArmClient) registerDNSClients(endpoint, subscriptionId string, auth autorest.Authorizer) {
dn := dns.NewRecordSetsClientWithBaseURI(endpoint, subscriptionId)
c.configureClient(&dn.Client, auth)
Expand Down
26 changes: 26 additions & 0 deletions azurerm/helpers/validate/devspace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package validate

import (
"regexp"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func DevSpaceName() schema.SchemaValidateFunc {
return func(i interface{}, k string) (s []string, es []error) {
// Length should be between 3 and 31.
if s, es = validation.StringLenBetween(3, 31)(i, k); len(es) > 0 {
return s, es
}

// Naming rule.
regexStr := "^[a-zA-Z0-9](-?[a-zA-Z0-9])*$"
errMsg := "DevSpace name can only include alphanumeric characters, hyphens."
if s, es = validation.StringMatch(regexp.MustCompile(regexStr), errMsg)(i, k); len(es) > 0 {
return s, es
}

return nil, nil
katbyte marked this conversation as resolved.
Show resolved Hide resolved
}
}
31 changes: 31 additions & 0 deletions azurerm/helpers/validate/devspace_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package validate

import "testing"

func TestValidateDevSpaceName(t *testing.T) {
validNames := []string{
"valid-name",
"valid02-name",
"validName1",
}
for _, v := range validNames {
_, errors := DevSpaceName()(v, "valid")
if len(errors) != 0 {
t.Fatalf("%q should be a valid DevSpace Name: %q", v, errors)
}
}

invalidNames := []string{
"invalid!",
"!@£",
"-invalid",
"double-hyphen--invalid",
"invalid_name",
}
for _, v := range invalidNames {
_, errors := DevSpaceName()(v, "invalid")
if len(errors) == 0 {
t.Fatalf("%q should be an invalid DevSpace Name", v)
}
}
}
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_data_lake_store": resourceArmDataLakeStore(),
"azurerm_data_lake_store_file": resourceArmDataLakeStoreFile(),
"azurerm_data_lake_store_firewall_rule": resourceArmDataLakeStoreFirewallRule(),
"azurerm_devspace_controller": resourceArmDevSpaceController(),
"azurerm_dev_test_lab": resourceArmDevTestLab(),
"azurerm_dev_test_policy": resourceArmDevTestPolicy(),
"azurerm_dev_test_linux_virtual_machine": resourceArmDevTestLinuxVirtualMachine(),
Expand Down
271 changes: 271 additions & 0 deletions azurerm/resource_arm_devspace_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
package azurerm

import (
"fmt"
"log"

"github.com/Azure/azure-sdk-for-go/services/preview/devspaces/mgmt/2018-06-01-preview/devspaces"
"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/validate"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func resourceArmDevSpaceController() *schema.Resource {
return &schema.Resource{
Create: resourceArmDevSpaceControllerCreate,
Read: resourceArmDevSpaceControllerRead,
Update: resourceArmDevSpaceControllerUpdate,
Delete: resourceArmDevSpaceControllerDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validate.DevSpaceName(),
},
metacpp marked this conversation as resolved.
Show resolved Hide resolved

"location": locationSchema(),

"resource_group_name": resourceGroupNameSchema(),

"sku": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
"S1",
}, false),
},
"tier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{
string(devspaces.Standard),
}, false),
},
},
},
},

"host_suffix": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},

"target_container_host_resource_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: azure.ValidateResourceID,
},
metacpp marked this conversation as resolved.
Show resolved Hide resolved

"target_container_host_credentials_base64": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Sensitive: true,
ValidateFunc: validation.NoZeroValues,
metacpp marked this conversation as resolved.
Show resolved Hide resolved
},

"tags": tagsSchema(),

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

func resourceArmDevSpaceControllerCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).devSpaceControllerClient
ctx := meta.(*ArmClient).StopContext

log.Printf("[INFO] preparing arguments for DevSpace Controller creation")

name := d.Get("name").(string)
location := azureRMNormalizeLocation(d.Get("location").(string))
resGroupName := d.Get("resource_group_name").(string)
tags := d.Get("tags").(map[string]interface{})

sku := expandDevSpaceControllerSku(d)

hostSuffix := d.Get("host_suffix").(string)
tarCHResId := d.Get("target_container_host_resource_id").(string)
tarCHCredBase64 := d.Get("target_container_host_credentials_base64").(string)

controller := devspaces.Controller{
Location: &location,
Tags: expandTags(tags),
Sku: sku,
ControllerProperties: &devspaces.ControllerProperties{
HostSuffix: &hostSuffix,
TargetContainerHostResourceID: &tarCHResId,
TargetContainerHostCredentialsBase64: &tarCHCredBase64,
},
}

future, err := client.Create(ctx, resGroupName, name, controller)
if err != nil {
return fmt.Errorf("Error creating DevSpace Controller %q (Resource Group %q): %+v", name, resGroupName, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for creation of DevSpace Controller %q (Resource Group %q): %+v", name, resGroupName, err)
}

result, err := client.Get(ctx, resGroupName, name)
if err != nil {
return fmt.Errorf("Error retrieving DevSpace %q (Resource Group %q): %+v", name, resGroupName, err)
}

if result.ID == nil {
return fmt.Errorf("Cannot read DevSpace Controller %q (Resource Group %q) ID", name, resGroupName)
}
d.SetId(*result.ID)

return resourceArmDevSpaceControllerRead(d, meta)
}

func resourceArmDevSpaceControllerRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).devSpaceControllerClient
ctx := meta.(*ArmClient).StopContext

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroupName := id.ResourceGroup
name := id.Path["controllers"]

result, err := client.Get(ctx, resGroupName, name)
if err != nil {
if utils.ResponseWasNotFound(result.Response) {
log.Printf("[DEBUG] DevSpace Controller %q was not found in Resource Group %q - removing from state!", name, resGroupName)
d.SetId("")
return nil
}

return fmt.Errorf("Error making Read request on DevSpace Controller Lab %q (Resource Group %q): %+v", name, resGroupName, err)
}

d.Set("name", result.Name)
d.Set("resource_group_name", resGroupName)
if location := result.Location; location != nil {
d.Set("location", azureRMNormalizeLocation(*location))
}

d.Set("sku", flattenDevSpaceControllerSku(result.Sku))
metacpp marked this conversation as resolved.
Show resolved Hide resolved

if props := result.ControllerProperties; props != nil {
if props.HostSuffix != nil {
d.Set("host_suffix", props.HostSuffix)
}

if props.DataPlaneFqdn != nil {
d.Set("data_plane_fqdn", props.DataPlaneFqdn)
}

if props.TargetContainerHostResourceID != nil {
d.Set("target_container_host_resource_id", props.TargetContainerHostResourceID)
}
metacpp marked this conversation as resolved.
Show resolved Hide resolved
}

flattenAndSetTags(d, result.Tags)

return nil
}

func resourceArmDevSpaceControllerUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).devSpaceControllerClient
ctx := meta.(*ArmClient).StopContext

log.Printf("[INFO] preparing arguments for DevSpace Controller updating")

name := d.Get("name").(string)
resGroupName := d.Get("resource_group_name").(string)
tags := d.Get("tags").(map[string]interface{})

params := devspaces.ControllerUpdateParameters{
Tags: expandTags(tags),
}

result, err := client.Update(ctx, resGroupName, name, params)
if err != nil {
metacpp marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("Error updating DevSpace Controller %q (Resource Group %q): %+v", name, resGroupName, err)
}

if result.ID == nil {
return fmt.Errorf("Cannot read DevSpace Controller %q (Resource Group %q) ID", name, resGroupName)
}
d.SetId(*result.ID)

return resourceArmDevSpaceControllerRead(d, meta)
}

func resourceArmDevSpaceControllerDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).devSpaceControllerClient
ctx := meta.(*ArmClient).StopContext

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resGroupName := id.ResourceGroup
name := id.Path["controllers"]

future, err := client.Delete(ctx, resGroupName, name)
if err != nil {
return fmt.Errorf("Error deleting DevSpace Controller %q (Resource Group %q): %+v", name, resGroupName, err)
}

if err = future.WaitForCompletionRef(ctx, client.Client); err != nil {
return fmt.Errorf("Error waiting for the deletion of DevSpace Controller %q (Resource Group %q): %+v", name, resGroupName, err)
}

return nil
}

func expandDevSpaceControllerSku(d *schema.ResourceData) *devspaces.Sku {
if _, ok := d.GetOk("sku"); !ok {
return nil
}

skuConfigs := d.Get("sku").([]interface{})
skuConfig := skuConfigs[0].(map[string]interface{})
skuName := skuConfig["name"].(string)
skuTier := devspaces.SkuTier(skuConfig["tier"].(string))

return &devspaces.Sku{
Name: &skuName,
Tier: skuTier,
}
}

func flattenDevSpaceControllerSku(skuObj *devspaces.Sku) []interface{} {
if skuObj == nil {
return []interface{}{}
}

skuConfig := make(map[string]interface{}, 0)
skuConfig["name"] = *skuObj.Name
metacpp marked this conversation as resolved.
Show resolved Hide resolved
skuConfig["tier"] = skuObj.Tier

return []interface{}{skuConfig}
}
Loading