Skip to content

Commit

Permalink
New Resource: azurerm_data_factory_linked_service_mysql (#3265)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbfrahry authored and katbyte committed Apr 16, 2019
1 parent 21e835c commit dcb1867
Show file tree
Hide file tree
Showing 9 changed files with 642 additions and 88 deletions.
53 changes: 53 additions & 0 deletions azurerm/data_factory.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,64 @@
package azurerm

import (
"fmt"
"log"
"regexp"
"sort"
"strings"

"github.com/Azure/azure-sdk-for-go/services/datafactory/mgmt/2018-06-01/datafactory"
"github.com/hashicorp/terraform/helper/schema"
)

func validateAzureRMDataFactoryLinkedServiceDatasetName(v interface{}, k string) (warnings []string, errors []error) {
value := v.(string)
if regexp.MustCompile(`^[-.+?/<>*%&:\\]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf("any of '-' '.', '+', '?', '/', '<', '>', '*', '%%', '&', ':', '\\', are not allowed in %q: %q", k, value))
}

return warnings, errors
}

func expandDataFactoryLinkedServiceIntegrationRuntime(integrationRuntimeName string) *datafactory.IntegrationRuntimeReference {
typeString := "IntegrationRuntimeReference"

return &datafactory.IntegrationRuntimeReference{
ReferenceName: &integrationRuntimeName,
Type: &typeString,
}
}

// Because the password isn't returned from the api in the connection string, we'll check all
// but the password string and return true if they match.
func azureRmDataFactoryLinkedServiceConnectionStringDiff(k, old string, new string, d *schema.ResourceData) bool {
oldSplit := strings.Split(strings.ToLower(old), ";")
newSplit := strings.Split(strings.ToLower(new), ";")

sort.Strings(oldSplit)
sort.Strings(newSplit)

// We need to remove the password from the new string since it isn't returned from the api
for i, v := range newSplit {
if strings.HasPrefix(v, "password") {
newSplit = append(newSplit[:i], newSplit[i+1:]...)
}
}

if len(oldSplit) != len(newSplit) {
return false
}

// We'll error out if we find any differences between the old and the new connection strings
for i := range oldSplit {
if !strings.EqualFold(oldSplit[i], newSplit[i]) {
return false
}
}

return true
}

func expandDataFactoryParameters(input map[string]interface{}) map[string]*datafactory.ParameterSpecification {
output := make(map[string]*datafactory.ParameterSpecification)

Expand Down
40 changes: 40 additions & 0 deletions azurerm/data_factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package azurerm

import "testing"

func TestAzureRmDataFactoryLinkedServiceConnectionStringDiff(t *testing.T) {
cases := []struct {
Old string
New string
NoDiff bool
}{
{
Old: "",
New: "",
NoDiff: true,
},
{
Old: "Integrated Security=False;Data Source=test;Initial Catalog=test;User ID=test",
New: "Integrated Security=False;Data Source=test;Initial Catalog=test;User ID=test;Password=test",
NoDiff: true,
},
{
Old: "Integrated Security=False;Data Source=test;Initial Catalog=test;User ID=test",
New: "Integrated Security=False;Data Source=test;Initial Catalog=test;User ID=test",
NoDiff: true,
},
{
Old: "Integrated Security=False;Data Source=test2;Initial Catalog=test;User ID=test",
New: "Integrated Security=False;Data Source=test;Initial Catalog=test;User ID=test;Password=test",
NoDiff: false,
},
}

for _, tc := range cases {
noDiff := azureRmDataFactoryLinkedServiceConnectionStringDiff("", tc.Old, tc.New, nil)

if noDiff != tc.NoDiff {
t.Fatalf("Expected azureRmDataFactoryLinkedServiceConnectionStringDiff to be '%t' for '%s' '%s' - got '%t'", tc.NoDiff, tc.Old, tc.New, noDiff)
}
}
}
1 change: 1 addition & 0 deletions azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ func Provider() terraform.ResourceProvider {
"azurerm_cosmosdb_account": resourceArmCosmosDBAccount(),
"azurerm_data_factory": resourceArmDataFactory(),
"azurerm_data_factory_dataset_sql_server_table": resourceArmDataFactoryDatasetSQLServerTable(),
"azurerm_data_factory_linked_service_mysql": resourceArmDataFactoryLinkedServiceMySQL(),
"azurerm_data_factory_linked_service_sql_server": resourceArmDataFactoryLinkedServiceSQLServer(),
"azurerm_data_factory_pipeline": resourceArmDataFactoryPipeline(),
"azurerm_data_lake_analytics_account": resourceArmDataLakeAnalyticsAccount(),
Expand Down
240 changes: 240 additions & 0 deletions azurerm/resource_arm_data_factory_linked_service_mysql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package azurerm

import (
"fmt"
"regexp"

"github.com/Azure/azure-sdk-for-go/services/datafactory/mgmt/2018-06-01/datafactory"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"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/utils"
)

func resourceArmDataFactoryLinkedServiceMySQL() *schema.Resource {
return &schema.Resource{
Create: resourceArmDataFactoryLinkedServiceMySQLCreateOrUpdate,
Read: resourceArmDataFactoryLinkedServiceMySQLRead,
Update: resourceArmDataFactoryLinkedServiceMySQLCreateOrUpdate,
Delete: resourceArmDataFactoryLinkedServiceMySQLDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

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

"data_factory_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(
regexp.MustCompile(`^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$`),
`Invalid name for Data Factory, see https://docs.microsoft.com/en-us/azure/data-factory/naming-rules`,
),
},

"resource_group_name": resourceGroupNameSchema(),

"connection_string": {
Type: schema.TypeString,
Required: true,
DiffSuppressFunc: azureRmDataFactoryLinkedServiceConnectionStringDiff,
ValidateFunc: validate.NoEmptyStrings,
},

"description": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validate.NoEmptyStrings,
},

"integration_runtime_name": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validate.NoEmptyStrings,
},

"parameters": {
Type: schema.TypeMap,
Optional: true,
},

"annotations": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

"additional_properties": {
Type: schema.TypeMap,
Optional: true,
},
},
}
}

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

name := d.Get("name").(string)
dataFactoryName := d.Get("data_factory_name").(string)
resourceGroup := d.Get("resource_group_name").(string)

if requireResourcesToBeImported && d.IsNewResource() {
existing, err := client.Get(ctx, resourceGroup, dataFactoryName, name, "")
if err != nil {
if !utils.ResponseWasNotFound(existing.Response) {
return fmt.Errorf("Error checking for presence of existing Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): %+v", name, dataFactoryName, resourceGroup, err)
}
}

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

connectionString := d.Get("connection_string").(string)
secureString := datafactory.SecureString{
Value: &connectionString,
Type: datafactory.TypeSecureString,
}

mysqlProperties := &datafactory.MySQLLinkedServiceTypeProperties{
ConnectionString: &secureString,
}

description := d.Get("description").(string)

mysqlLinkedService := &datafactory.MySQLLinkedService{
Description: &description,
MySQLLinkedServiceTypeProperties: mysqlProperties,
Type: datafactory.TypeMySQL,
}

if v, ok := d.GetOk("parameters"); ok {
mysqlLinkedService.Parameters = expandDataFactoryParameters(v.(map[string]interface{}))
}

if v, ok := d.GetOk("integration_runtime_name"); ok {
mysqlLinkedService.ConnectVia = expandDataFactoryLinkedServiceIntegrationRuntime(v.(string))
}

if v, ok := d.GetOk("additional_properties"); ok {
mysqlLinkedService.AdditionalProperties = v.(map[string]interface{})
}

if v, ok := d.GetOk("annotations"); ok {
annotations := v.([]interface{})
mysqlLinkedService.Annotations = &annotations
}

linkedService := datafactory.LinkedServiceResource{
Properties: mysqlLinkedService,
}

if _, err := client.CreateOrUpdate(ctx, resourceGroup, dataFactoryName, name, linkedService, ""); err != nil {
return fmt.Errorf("Error creating/updating Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): %+v", name, dataFactoryName, resourceGroup, err)
}

resp, err := client.Get(ctx, resourceGroup, dataFactoryName, name, "")
if err != nil {
return fmt.Errorf("Error retrieving Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): %+v", name, dataFactoryName, resourceGroup, err)
}

if resp.ID == nil {
return fmt.Errorf("Cannot read Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): %+v", name, dataFactoryName, resourceGroup, err)
}

d.SetId(*resp.ID)

return resourceArmDataFactoryLinkedServiceMySQLRead(d, meta)
}

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

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
dataFactoryName := id.Path["factories"]
name := id.Path["linkedservices"]

resp, err := client.Get(ctx, resourceGroup, dataFactoryName, name, "")
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
d.SetId("")
return nil
}

return fmt.Errorf("Error retrieving Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): %+v", name, dataFactoryName, resourceGroup, err)
}

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

mysql, ok := resp.Properties.AsMySQLLinkedService()
if !ok {
return fmt.Errorf("Error classifiying Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): Expected: %q Received: %q", name, dataFactoryName, resourceGroup, datafactory.TypeMySQL, *resp.Type)
}

d.Set("additional_properties", mysql.AdditionalProperties)

if mysql.Description != nil {
d.Set("description", *mysql.Description)
}

annotations := flattenDataFactoryAnnotations(mysql.Annotations)
if err := d.Set("annotations", annotations); err != nil {
return fmt.Errorf("Error setting `annotations`: %+v", err)
}

parameters := flattenDataFactoryParameters(mysql.Parameters)
if err := d.Set("parameters", parameters); err != nil {
return fmt.Errorf("Error setting `parameters`: %+v", err)
}

if connectVia := mysql.ConnectVia; connectVia != nil {
if connectVia.ReferenceName != nil {
d.Set("integration_runtime_name", connectVia.ReferenceName)
}
}

return nil
}

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

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
dataFactoryName := id.Path["factories"]
name := id.Path["linkedservices"]

response, err := client.Delete(ctx, resourceGroup, dataFactoryName, name)
if err != nil {
if !utils.ResponseWasNotFound(response) {
return fmt.Errorf("Error deleting Data Factory Linked Service MySQL %q (Data Factory %q / Resource Group %q): %+v", name, dataFactoryName, resourceGroup, err)
}
}

return nil
}
Loading

0 comments on commit dcb1867

Please sign in to comment.