From 8d27af53b8d3d759ac7adf6b60f5544bacfab241 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 13:26:11 +0100 Subject: [PATCH 01/40] add client for elastic job agent --- azurerm/internal/services/mssql/client/client.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/mssql/client/client.go b/azurerm/internal/services/mssql/client/client.go index eaa11c24737f..6d1fadb8f0d3 100644 --- a/azurerm/internal/services/mssql/client/client.go +++ b/azurerm/internal/services/mssql/client/client.go @@ -11,9 +11,10 @@ type Client struct { BackupShortTermRetentionPoliciesClient *sql.BackupShortTermRetentionPoliciesClient DatabasesClient *sql.DatabasesClient DatabaseExtendedBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient + DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient ElasticPoolsClient *sql.ElasticPoolsClient - DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient + JobAgentsClient *sql.JobAgentsClient RestorableDroppedDatabasesClient *sql.RestorableDroppedDatabasesClient ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient ServersClient *sql.ServersClient @@ -46,6 +47,9 @@ func NewClient(o *common.ClientOptions) *Client { elasticPoolsClient := sql.NewElasticPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&elasticPoolsClient.Client, o.ResourceManagerAuthorizer) + jobAgentsClient := sql.NewJobAgentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&jobAgentsClient.Client, o.ResourceManagerAuthorizer) + restorableDroppedDatabasesClient := sql.NewRestorableDroppedDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&restorableDroppedDatabasesClient.Client, o.ResourceManagerAuthorizer) @@ -78,6 +82,7 @@ func NewClient(o *common.ClientOptions) *Client { DatabaseThreatDetectionPoliciesClient: &databaseThreatDetectionPoliciesClient, DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient, ElasticPoolsClient: &elasticPoolsClient, + JobAgentsClient: &jobAgentsClient, RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient, ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, ServersClient: &serversClient, From 3fd3982115af6c4a369a16e5bfdf9d5454f859ff Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 14:06:04 +0100 Subject: [PATCH 02/40] add parse and validate files for job agent --- .../services/mssql/parse/job_agent.go | 75 ++++++++++ .../services/mssql/parse/job_agent_test.go | 128 ++++++++++++++++++ .../internal/services/mssql/resourceids.go | 1 + .../services/mssql/validate/job_agent_id.go | 23 ++++ .../mssql/validate/job_agent_id_test.go | 88 ++++++++++++ 5 files changed, 315 insertions(+) create mode 100644 azurerm/internal/services/mssql/parse/job_agent.go create mode 100644 azurerm/internal/services/mssql/parse/job_agent_test.go create mode 100644 azurerm/internal/services/mssql/validate/job_agent_id.go create mode 100644 azurerm/internal/services/mssql/validate/job_agent_id_test.go diff --git a/azurerm/internal/services/mssql/parse/job_agent.go b/azurerm/internal/services/mssql/parse/job_agent.go new file mode 100644 index 000000000000..54624e319f17 --- /dev/null +++ b/azurerm/internal/services/mssql/parse/job_agent.go @@ -0,0 +1,75 @@ +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 JobAgentId struct { + SubscriptionId string + ResourceGroup string + ServerName string + Name string +} + +func NewJobAgentID(subscriptionId, resourceGroup, serverName, name string) JobAgentId { + return JobAgentId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServerName: serverName, + Name: name, + } +} + +func (id JobAgentId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Server Name %q", id.ServerName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Job Agent", segmentsStr) +} + +func (id JobAgentId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Sql/servers/%s/jobAgents/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) +} + +// JobAgentID parses a JobAgent ID into an JobAgentId struct +func JobAgentID(input string) (*JobAgentId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := JobAgentId{ + 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.ServerName, err = id.PopSegment("servers"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("jobAgents"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/mssql/parse/job_agent_test.go b/azurerm/internal/services/mssql/parse/job_agent_test.go new file mode 100644 index 000000000000..5ecb815120dc --- /dev/null +++ b/azurerm/internal/services/mssql/parse/job_agent_test.go @@ -0,0 +1,128 @@ +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 = JobAgentId{} + +func TestJobAgentIDFormatter(t *testing.T) { + actual := NewJobAgentID("12345678-1234-9876-4563-123456789012", "group1", "server1", "jobagent1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestJobAgentID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *JobAgentId + }{ + + { + // 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 ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/", + Error: true, + }, + + { + // missing value for ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1", + Expected: &JobAgentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + ServerName: "server1", + Name: "jobagent1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.SQL/SERVERS/SERVER1/JOBAGENTS/JOBAGENT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := JobAgentID(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.ServerName != v.Expected.ServerName { + t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/mssql/resourceids.go b/azurerm/internal/services/mssql/resourceids.go index 81f03ada302f..9a1a6f05cf42 100644 --- a/azurerm/internal/services/mssql/resourceids.go +++ b/azurerm/internal/services/mssql/resourceids.go @@ -4,6 +4,7 @@ package mssql //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatabaseExtendedAuditingPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/databases/database1/extendedAuditingSettings/default //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatabaseVulnerabilityAssessmentRuleBaseline -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/databases/database1/vulnerabilityAssessments/default/rules/rule1/baselines/baseline1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ElasticPool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/elasticPools/pool1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=JobAgent -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=RecoverableDatabase -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/recoverabledatabases/database1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ServerExtendedAuditingPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/extendedAuditingSettings/default diff --git a/azurerm/internal/services/mssql/validate/job_agent_id.go b/azurerm/internal/services/mssql/validate/job_agent_id.go new file mode 100644 index 000000000000..5b69f42b0d30 --- /dev/null +++ b/azurerm/internal/services/mssql/validate/job_agent_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" +) + +func JobAgentID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.JobAgentID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/mssql/validate/job_agent_id_test.go b/azurerm/internal/services/mssql/validate/job_agent_id_test.go new file mode 100644 index 000000000000..6df6862cea3b --- /dev/null +++ b/azurerm/internal/services/mssql/validate/job_agent_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestJobAgentID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/", + Valid: false, + }, + + { + // missing value for ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.SQL/SERVERS/SERVER1/JOBAGENTS/JOBAGENT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := JobAgentID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From ecf579fb1492ee5df947f1673f11960dceb5ba3b Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 13:26:11 +0100 Subject: [PATCH 03/40] add client for elastic job agent --- azurerm/internal/services/mssql/client/client.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azurerm/internal/services/mssql/client/client.go b/azurerm/internal/services/mssql/client/client.go index 17ad92dadd52..8a716738425f 100644 --- a/azurerm/internal/services/mssql/client/client.go +++ b/azurerm/internal/services/mssql/client/client.go @@ -16,6 +16,7 @@ type Client struct { DatabasesClient *sql.DatabasesClient ElasticPoolsClient *sql.ElasticPoolsClient FirewallRulesClient *sql.FirewallRulesClient + JobAgentsClient *sql.JobAgentsClient RestorableDroppedDatabasesClient *sql.RestorableDroppedDatabasesClient ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient ServerConnectionPoliciesClient *sql.ServerConnectionPoliciesClient @@ -49,6 +50,9 @@ func NewClient(o *common.ClientOptions) *Client { elasticPoolsClient := sql.NewElasticPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&elasticPoolsClient.Client, o.ResourceManagerAuthorizer) + jobAgentsClient := sql.NewJobAgentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&jobAgentsClient.Client, o.ResourceManagerAuthorizer) + firewallRulesClient := sql.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&firewallRulesClient.Client, o.ResourceManagerAuthorizer) @@ -88,6 +92,7 @@ func NewClient(o *common.ClientOptions) *Client { DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient, ElasticPoolsClient: &elasticPoolsClient, FirewallRulesClient: &firewallRulesClient, + JobAgentsClient: &jobAgentsClient, RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient, ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, ServersClient: &serversClient, From 99bb248bd0cc7b1247eb0c21b976094dcf9f436a Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 14:06:04 +0100 Subject: [PATCH 04/40] add parse and validate files for job agent --- .../services/mssql/parse/job_agent.go | 75 ++++++++++ .../services/mssql/parse/job_agent_test.go | 128 ++++++++++++++++++ .../internal/services/mssql/resourceids.go | 1 + .../services/mssql/validate/job_agent_id.go | 23 ++++ .../mssql/validate/job_agent_id_test.go | 88 ++++++++++++ 5 files changed, 315 insertions(+) create mode 100644 azurerm/internal/services/mssql/parse/job_agent.go create mode 100644 azurerm/internal/services/mssql/parse/job_agent_test.go create mode 100644 azurerm/internal/services/mssql/validate/job_agent_id.go create mode 100644 azurerm/internal/services/mssql/validate/job_agent_id_test.go diff --git a/azurerm/internal/services/mssql/parse/job_agent.go b/azurerm/internal/services/mssql/parse/job_agent.go new file mode 100644 index 000000000000..54624e319f17 --- /dev/null +++ b/azurerm/internal/services/mssql/parse/job_agent.go @@ -0,0 +1,75 @@ +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 JobAgentId struct { + SubscriptionId string + ResourceGroup string + ServerName string + Name string +} + +func NewJobAgentID(subscriptionId, resourceGroup, serverName, name string) JobAgentId { + return JobAgentId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServerName: serverName, + Name: name, + } +} + +func (id JobAgentId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Server Name %q", id.ServerName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Job Agent", segmentsStr) +} + +func (id JobAgentId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Sql/servers/%s/jobAgents/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) +} + +// JobAgentID parses a JobAgent ID into an JobAgentId struct +func JobAgentID(input string) (*JobAgentId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := JobAgentId{ + 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.ServerName, err = id.PopSegment("servers"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("jobAgents"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/mssql/parse/job_agent_test.go b/azurerm/internal/services/mssql/parse/job_agent_test.go new file mode 100644 index 000000000000..5ecb815120dc --- /dev/null +++ b/azurerm/internal/services/mssql/parse/job_agent_test.go @@ -0,0 +1,128 @@ +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 = JobAgentId{} + +func TestJobAgentIDFormatter(t *testing.T) { + actual := NewJobAgentID("12345678-1234-9876-4563-123456789012", "group1", "server1", "jobagent1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestJobAgentID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *JobAgentId + }{ + + { + // 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 ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/", + Error: true, + }, + + { + // missing value for ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1", + Expected: &JobAgentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + ServerName: "server1", + Name: "jobagent1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.SQL/SERVERS/SERVER1/JOBAGENTS/JOBAGENT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := JobAgentID(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.ServerName != v.Expected.ServerName { + t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/mssql/resourceids.go b/azurerm/internal/services/mssql/resourceids.go index f613a45512a2..7664cca9be63 100644 --- a/azurerm/internal/services/mssql/resourceids.go +++ b/azurerm/internal/services/mssql/resourceids.go @@ -4,6 +4,7 @@ package mssql //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatabaseExtendedAuditingPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/databases/database1/extendedAuditingSettings/default //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatabaseVulnerabilityAssessmentRuleBaseline -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/databases/database1/vulnerabilityAssessments/default/rules/rule1/baselines/baseline1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ElasticPool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/elasticPools/pool1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=JobAgent -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FirewallRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/firewallRules/rule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=RecoverableDatabase -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/recoverabledatabases/database1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1 diff --git a/azurerm/internal/services/mssql/validate/job_agent_id.go b/azurerm/internal/services/mssql/validate/job_agent_id.go new file mode 100644 index 000000000000..5b69f42b0d30 --- /dev/null +++ b/azurerm/internal/services/mssql/validate/job_agent_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" +) + +func JobAgentID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.JobAgentID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/mssql/validate/job_agent_id_test.go b/azurerm/internal/services/mssql/validate/job_agent_id_test.go new file mode 100644 index 000000000000..6df6862cea3b --- /dev/null +++ b/azurerm/internal/services/mssql/validate/job_agent_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestJobAgentID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/", + Valid: false, + }, + + { + // missing value for ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.SQL/SERVERS/SERVER1/JOBAGENTS/JOBAGENT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := JobAgentID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From a81604b7c692c07282c3378b578736dc26f86521 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 11 Mar 2021 08:00:06 +0100 Subject: [PATCH 05/40] register mssql_job_agent add basic mssql_job_agent --- .../services/mssql/mssql_job_agent.go | 117 ++++++++++++++++++ .../internal/services/mssql/registration.go | 1 + 2 files changed, 118 insertions(+) create mode 100644 azurerm/internal/services/mssql/mssql_job_agent.go diff --git a/azurerm/internal/services/mssql/mssql_job_agent.go b/azurerm/internal/services/mssql/mssql_job_agent.go new file mode 100644 index 000000000000..b2f6812997e6 --- /dev/null +++ b/azurerm/internal/services/mssql/mssql_job_agent.go @@ -0,0 +1,117 @@ +package mssql + +import ( + "fmt" + "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "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/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "log" + "time" +) + +func resourceMsSqlJobAgent() *schema.Resource { + return &schema.Resource{ + Create: resourceMsSqlJobAgentCreateUpdate, + Read: resourceMsSqlJobAgentRead, + Update: resourceMsSqlJobAgentCreateUpdate, + Delete: resourceMsSqlJobAgentDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.JobAgentID(id) + return err + }), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + // ValidateFunc: azure.ValidateMsSqlServerName, + }, + + "database_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DatabaseID, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "tags": tags.Schema(), + }, + } +} + +func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).MSSQL.JobAgentsClient + //databaseClient := meta.(*clients.Client).MSSQL.ServersClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Job Agent creation.") + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + location := azure.NormalizeLocation(d.Get("location").(string)) + databaseId := d.Get("database_id").(string) + dbId, _ := parse.DatabaseID(databaseId) + + if d.IsNewResource() { + existing, err := client.Get(ctx, resGroup, dbId.ServerName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Failed to check for presence of existing Job Agent %q (MsSql Server %q / Resource Group %q): %s", name, dbId.ServerName, resGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_mssql_job_agent", *existing.ID) + } + } + + params := sql.JobAgent{ + Name: &name, + Location: utils.String(location), + JobAgentProperties: &sql.JobAgentProperties{ + DatabaseID: &databaseId, + }, + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + + future, err := client.CreateOrUpdate(ctx, resGroup, dbId.Name, name, params) + if err != nil { + return fmt.Errorf("creating MsSql Database %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation of Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) + } + + return nil +} + +func resourceMsSqlJobAgentRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceMsSqlJobAgentDelete(d *schema.ResourceData, meta interface{}) error { + return nil +} diff --git a/azurerm/internal/services/mssql/registration.go b/azurerm/internal/services/mssql/registration.go index 42dd58661974..173590cf7203 100644 --- a/azurerm/internal/services/mssql/registration.go +++ b/azurerm/internal/services/mssql/registration.go @@ -34,6 +34,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_mssql_database_extended_auditing_policy": resourceMsSqlDatabaseExtendedAuditingPolicy(), "azurerm_mssql_database_vulnerability_assessment_rule_baseline": resourceMsSqlDatabaseVulnerabilityAssessmentRuleBaseline(), "azurerm_mssql_elasticpool": resourceMsSqlElasticPool(), + "azurerm_mssql_job_agent": resourceMsSqlJobAgent(), "azurerm_mssql_firewall_rule": resourceMsSqlFirewallRule(), "azurerm_mssql_server": resourceMsSqlServer(), "azurerm_mssql_server_extended_auditing_policy": resourceMsSqlServerExtendedAuditingPolicy(), From 1165285e39611e10e495f22f2bce168571c4b096 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 12:03:51 +0200 Subject: [PATCH 06/40] add function to validate job agent name --- azurerm/internal/services/mssql/validate/mssql.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azurerm/internal/services/mssql/validate/mssql.go b/azurerm/internal/services/mssql/validate/mssql.go index f18c23b84e07..e1fcfd6f486c 100644 --- a/azurerm/internal/services/mssql/validate/mssql.go +++ b/azurerm/internal/services/mssql/validate/mssql.go @@ -49,3 +49,12 @@ func ValidateLongTermRetentionPoliciesIsoFormat(i interface{}, k string) (_ []st } return nil, nil } + +// Job Agent name must not contain any of ?<>*%&:\/? and must not end with a space or . +func ValidateMsSqlJobAgentName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `^[^?<>*%&:\/?]{0,127}[^?<>*%&:\/?. ]$`); !m { + return nil, append(regexErrs, fmt.Errorf("%q must not contain any of ?<>*%&:\\/?, must not end with a space or a period and can't have more than 128 characters.", k)) + } + + return nil, nil +} From a28178a6e74e6a0e417e12f9919c4c4551820b10 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 14:00:58 +0200 Subject: [PATCH 07/40] implement read, create&update and delete methods --- ...b_agent.go => mssql_job_agent_resource.go} | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) rename azurerm/internal/services/mssql/{mssql_job_agent.go => mssql_job_agent_resource.go} (65%) diff --git a/azurerm/internal/services/mssql/mssql_job_agent.go b/azurerm/internal/services/mssql/mssql_job_agent_resource.go similarity index 65% rename from azurerm/internal/services/mssql/mssql_job_agent.go rename to azurerm/internal/services/mssql/mssql_job_agent_resource.go index b2f6812997e6..78672c5e7190 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource.go @@ -2,6 +2,9 @@ package mssql import ( "fmt" + "log" + "time" + "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" @@ -13,8 +16,6 @@ import ( azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - "log" - "time" ) func resourceMsSqlJobAgent() *schema.Resource { @@ -38,10 +39,10 @@ func resourceMsSqlJobAgent() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - // ValidateFunc: azure.ValidateMsSqlServerName, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ValidateMsSqlJobAgentName, }, "database_id": { @@ -62,7 +63,6 @@ func resourceMsSqlJobAgent() *schema.Resource { func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.JobAgentsClient - //databaseClient := meta.(*clients.Client).MSSQL.ServersClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -96,22 +96,69 @@ func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.CreateOrUpdate(ctx, resGroup, dbId.Name, name, params) + future, err := client.CreateOrUpdate(ctx, resGroup, dbId.ServerName, name, params) if err != nil { - return fmt.Errorf("creating MsSql Database %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) + return fmt.Errorf("creating MsSql Job Agent %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { return fmt.Errorf("waiting for creation of Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) } - return nil + resp, err := client.Get(ctx, dbId.ResourceGroup, dbId.ServerName, name) + if err != nil { + return fmt.Errorf("reading request for Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) + } + + d.SetId(*resp.ID) + + return resourceMsSqlJobAgentRead(d, meta) } func resourceMsSqlJobAgentRead(d *schema.ResourceData, meta interface{}) error { - return nil + client := meta.(*clients.Client).MSSQL.JobAgentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.JobAgentID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("reading MsSql Job Agent %s (MsSql Server Name %q / Resource Group %q): %s", id.Name, id.ServerName, id.ResourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", id.ResourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + d.Set("database_id", resp.DatabaseID) + + return tags.FlattenAndSet(d, resp.Tags) } func resourceMsSqlJobAgentDelete(d *schema.ResourceData, meta interface{}) error { - return nil + client := meta.(*clients.Client).MSSQL.JobAgentsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.JobAgentID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) + if err != nil { + return fmt.Errorf("deleting Job Agent %s: %+v", id.Name, err) + } + + return future.WaitForCompletionRef(ctx, client.Client) } From 43471ca03e509f5a78505666edb137628d9d13a7 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 14:01:10 +0200 Subject: [PATCH 08/40] add basic test --- .../mssql/mssql_job_agent_resource_test.go | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 azurerm/internal/services/mssql/mssql_job_agent_resource_test.go diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go new file mode 100644 index 000000000000..3ccd8307ba0c --- /dev/null +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -0,0 +1,86 @@ +package mssql_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type MsSqlJobAgentResource struct{} + +func TestAccMsSqlJobAgent_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_job_agent", "test") + r := MsSqlJobAgentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (MsSqlJobAgentResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.JobAgentID(state.ID) + if err != nil { + return nil, err + } + + resp, err := client.MSSQL.JobAgentsClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil, fmt.Errorf("Job Agent %q (Resource Group %q) does not exist", id.Name, id.ResourceGroup) + } + return nil, fmt.Errorf("reading Job Agent %q (Resource Group %q): %v", id.Name, id.ResourceGroup, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (MsSqlJobAgentResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-jobagent-%[1]d" + location = "%[2]s" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestmssqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "4dministr4t0r" + administrator_login_password = "superSecur3!!!" +} + +resource "azurerm_mssql_database" "test" { + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" +} + +resource "azurerm_mssql_job_agent" "test" { + name = "acctestmssqljobagent%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id +} +`, data.RandomInteger, data.Locations.Primary) +} From c06c7a5bef86953811d77bdb471b3566806aefef Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 15:25:21 +0200 Subject: [PATCH 09/40] add update and requires import test --- .../mssql/mssql_job_agent_resource_test.go | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go index 3ccd8307ba0c..27f1fd9a7d18 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -32,6 +32,43 @@ func TestAccMsSqlJobAgent_basic(t *testing.T) { }) } +func TestAccMsSqlJobAgent_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_job_agent", "test") + r := MsSqlJobAgentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccMsSqlJobAgent_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_job_agent", "test") + r := MsSqlJobAgentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (MsSqlJobAgentResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.JobAgentID(state.ID) if err != nil { @@ -84,3 +121,56 @@ resource "azurerm_mssql_job_agent" "test" { } `, data.RandomInteger, data.Locations.Primary) } + +func (r MsSqlJobAgentResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_mssql_job_agent" "import" { + name = azurerm_mssql_job_agent.test.name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id +} +`, r.basic(data)) +} + +func (MsSqlJobAgentResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-jobagent-%[1]d" + location = "%[2]s" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestmssqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "4dministr4t0r" + administrator_login_password = "superSecur3!!!" +} + +resource "azurerm_mssql_database" "test" { + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" +} + +resource "azurerm_mssql_job_agent" "test" { + name = "acctestmssqljobagent%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id + + tags = { + ENV = "production" + } +} +`, data.RandomInteger, data.Locations.Primary) +} From 7095e33f7db6d789c3d673ec266c2d0b142ffcfd Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 8 Apr 2021 07:32:29 +0200 Subject: [PATCH 10/40] add documentation --- website/docs/r/mssql_job_agent.html.markdown | 82 ++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 website/docs/r/mssql_job_agent.html.markdown diff --git a/website/docs/r/mssql_job_agent.html.markdown b/website/docs/r/mssql_job_agent.html.markdown new file mode 100644 index 000000000000..314ffb947cf9 --- /dev/null +++ b/website/docs/r/mssql_job_agent.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "Database" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_mssql_job_agent" +description: |- + Manages an Elastic Job Agent. +--- + +# azurerm_mssql_job_agent + +Manages an Elastic Job Agent. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example" + location = "northeurope" +} + +resource "azurerm_mssql_server" "example" { + name = "example-server" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + version = "12.0" + administrator_login = "4dm1n157r470r" + administrator_login_password = "4-v3ry-53cr37-p455w0rd" +} + +resource "azurerm_mssql_database" "example" { + name = "example-db" + server_id = azurerm_mssql_server.example.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" +} + +resource "azurerm_mssql_job_agent" "example" { + name = "example-job-agent" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + database_id = azurerm_mssql_database.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Elastic Job Agent. Changing this forces a new Elastic Job Agent to be created. + +* `location` - (Required) The Azure Region where the Elastic Job Agent should exist. Changing this forces a new Elastic Job Agent to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Elastic Job Agent should exist. Changing this forces a new Elastic Job Agent to be created. + +* `database_id` - (Required) The ID of the database to store metadata for the Elastic Job Agent. Changing this forces a new Elastic Job Agent to be created. + +--- + +* `tags` - (Optional) A mapping of tags which should be assigned to the Database. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Elastic Job Agent. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 1 hour) Used when creating the Database. +* `read` - (Defaults to 5 minutes) Used when retrieving the Database. +* `update` - (Defaults to 1 hour) Used when updating the Database. +* `delete` - (Defaults to 1 hour) Used when deleting the Database. + +## Import + +Elastic Job Agents can be imported using the `id`, e.g. + +```shell +terraform import azurerm_mssql_job_agent.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Sql/servers/myserver1/jobAgents/myjobagent1 +``` From 1f28c0e8485fa2ee68ca1cb0ae069aa9abd419fe Mon Sep 17 00:00:00 2001 From: Javier Canizalez Date: Tue, 6 Apr 2021 13:16:30 -0600 Subject: [PATCH 11/40] `azurerm_media_service_account` - `storage_authentication_type` correctly accepts both `ManagedIdentity` and `System` #11222 --- .../services/media/media_services_account_resource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/media/media_services_account_resource.go b/azurerm/internal/services/media/media_services_account_resource.go index a6961219a1f6..cc0b2c767467 100644 --- a/azurerm/internal/services/media/media_services_account_resource.go +++ b/azurerm/internal/services/media/media_services_account_resource.go @@ -109,8 +109,8 @@ func resourceMediaServicesAccount() *schema.Resource { Optional: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{ - string(media.ManagedIdentityTypeSystemAssigned), - string(media.ManagedIdentityTypeSystemAssigned), + string(media.StorageAuthenticationSystem), + string(media.StorageAuthenticationManagedIdentity), }, true), }, From 45c7b51b274d344148a2a8b84e1da13ec74235b9 Mon Sep 17 00:00:00 2001 From: Matthew Frahry Date: Tue, 6 Apr 2021 12:17:08 -0700 Subject: [PATCH 12/40] Update changelog for #11222 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ec7a5154bfa..ea9ad87cb443 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ENHANCEMENTS: BUG FIXES: +* `azurerm_media_service_account` - `storage_authentication_type` correctly accepts both `ManagedIdentity` and `System` [GH-11222] * `azurerm_web_application_firewall_policy` - `http_listener_ids` and `path_based_rule_ids` are now Computed only [GH-11196] ## 2.54.0 (April 02, 2021) From 9fd604aec6dce1006c09a4c1ba94bda78ea5eb9d Mon Sep 17 00:00:00 2001 From: njucz Date: Tue, 6 Apr 2021 17:31:33 -0500 Subject: [PATCH 13/40] new resource "azurerm_spring_cloud_app_redis_association" (#11154) --- .../services/springcloud/client/client.go | 5 + .../parse/spring_cloud_app_association.go | 81 ++++++++ .../spring_cloud_app_association_test.go | 144 ++++++++++++++ .../services/springcloud/registration.go | 13 +- .../services/springcloud/resourceids.go | 1 + .../spring_cloud_app_association_import.go | 40 ++++ ...ng_cloud_app_redis_association_resource.go | 170 ++++++++++++++++ ...oud_app_redis_association_resource_test.go | 181 ++++++++++++++++++ .../spring_cloud_app_association_id.go | 23 +++ .../spring_cloud_app_association_id_test.go | 100 ++++++++++ .../spring_cloud_app_association_name.go | 25 +++ .../spring_cloud_app_association_name_test.go | 61 ++++++ ..._cloud_app_redis_association.html.markdown | 91 +++++++++ 13 files changed, 929 insertions(+), 6 deletions(-) create mode 100644 azurerm/internal/services/springcloud/parse/spring_cloud_app_association.go create mode 100644 azurerm/internal/services/springcloud/parse/spring_cloud_app_association_test.go create mode 100644 azurerm/internal/services/springcloud/spring_cloud_app_association_import.go create mode 100644 azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource.go create mode 100644 azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource_test.go create mode 100644 azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id.go create mode 100644 azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id_test.go create mode 100644 azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name.go create mode 100644 azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name_test.go create mode 100644 website/docs/r/spring_cloud_app_redis_association.html.markdown diff --git a/azurerm/internal/services/springcloud/client/client.go b/azurerm/internal/services/springcloud/client/client.go index afd249c77cbc..e759f0b2a200 100644 --- a/azurerm/internal/services/springcloud/client/client.go +++ b/azurerm/internal/services/springcloud/client/client.go @@ -7,6 +7,7 @@ import ( type Client struct { AppsClient *appplatform.AppsClient + BindingsClient *appplatform.BindingsClient CertificatesClient *appplatform.CertificatesClient ConfigServersClient *appplatform.ConfigServersClient CustomDomainsClient *appplatform.CustomDomainsClient @@ -19,6 +20,9 @@ func NewClient(o *common.ClientOptions) *Client { appsClient := appplatform.NewAppsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&appsClient.Client, o.ResourceManagerAuthorizer) + bindingsClient := appplatform.NewBindingsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&bindingsClient.Client, o.ResourceManagerAuthorizer) + certificatesClient := appplatform.NewCertificatesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&certificatesClient.Client, o.ResourceManagerAuthorizer) @@ -39,6 +43,7 @@ func NewClient(o *common.ClientOptions) *Client { return &Client{ AppsClient: &appsClient, + BindingsClient: &bindingsClient, CertificatesClient: &certificatesClient, ConfigServersClient: &configServersClient, CustomDomainsClient: &customDomainsClient, diff --git a/azurerm/internal/services/springcloud/parse/spring_cloud_app_association.go b/azurerm/internal/services/springcloud/parse/spring_cloud_app_association.go new file mode 100644 index 000000000000..f2bae8289815 --- /dev/null +++ b/azurerm/internal/services/springcloud/parse/spring_cloud_app_association.go @@ -0,0 +1,81 @@ +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 SpringCloudAppAssociationId struct { + SubscriptionId string + ResourceGroup string + SpringName string + AppName string + BindingName string +} + +func NewSpringCloudAppAssociationID(subscriptionId, resourceGroup, springName, appName, bindingName string) SpringCloudAppAssociationId { + return SpringCloudAppAssociationId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + SpringName: springName, + AppName: appName, + BindingName: bindingName, + } +} + +func (id SpringCloudAppAssociationId) String() string { + segments := []string{ + fmt.Sprintf("Binding Name %q", id.BindingName), + fmt.Sprintf("App Name %q", id.AppName), + fmt.Sprintf("Spring Name %q", id.SpringName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Spring Cloud App Association", segmentsStr) +} + +func (id SpringCloudAppAssociationId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.AppPlatform/Spring/%s/apps/%s/bindings/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName) +} + +// SpringCloudAppAssociationID parses a SpringCloudAppAssociation ID into an SpringCloudAppAssociationId struct +func SpringCloudAppAssociationID(input string) (*SpringCloudAppAssociationId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := SpringCloudAppAssociationId{ + 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.SpringName, err = id.PopSegment("Spring"); err != nil { + return nil, err + } + if resourceId.AppName, err = id.PopSegment("apps"); err != nil { + return nil, err + } + if resourceId.BindingName, err = id.PopSegment("bindings"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/springcloud/parse/spring_cloud_app_association_test.go b/azurerm/internal/services/springcloud/parse/spring_cloud_app_association_test.go new file mode 100644 index 000000000000..77e57c49a5b6 --- /dev/null +++ b/azurerm/internal/services/springcloud/parse/spring_cloud_app_association_test.go @@ -0,0 +1,144 @@ +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 = SpringCloudAppAssociationId{} + +func TestSpringCloudAppAssociationIDFormatter(t *testing.T) { + actual := NewSpringCloudAppAssociationID("12345678-1234-9876-4563-123456789012", "resGroup1", "spring1", "app1", "bind1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/bind1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestSpringCloudAppAssociationID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *SpringCloudAppAssociationId + }{ + + { + // 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 SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/", + Error: true, + }, + + { + // missing value for SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/", + Error: true, + }, + + { + // missing AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/", + Error: true, + }, + + { + // missing value for AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/", + Error: true, + }, + + { + // missing BindingName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/", + Error: true, + }, + + { + // missing value for BindingName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/bind1", + Expected: &SpringCloudAppAssociationId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + SpringName: "spring1", + AppName: "app1", + BindingName: "bind1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APPPLATFORM/SPRING/SPRING1/APPS/APP1/BINDINGS/BIND1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := SpringCloudAppAssociationID(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.SpringName != v.Expected.SpringName { + t.Fatalf("Expected %q but got %q for SpringName", v.Expected.SpringName, actual.SpringName) + } + if actual.AppName != v.Expected.AppName { + t.Fatalf("Expected %q but got %q for AppName", v.Expected.AppName, actual.AppName) + } + if actual.BindingName != v.Expected.BindingName { + t.Fatalf("Expected %q but got %q for BindingName", v.Expected.BindingName, actual.BindingName) + } + } +} diff --git a/azurerm/internal/services/springcloud/registration.go b/azurerm/internal/services/springcloud/registration.go index 4f958b31252b..11f212bfaad8 100644 --- a/azurerm/internal/services/springcloud/registration.go +++ b/azurerm/internal/services/springcloud/registration.go @@ -29,11 +29,12 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_spring_cloud_active_deployment": resourceSpringCloudActiveDeployment(), - "azurerm_spring_cloud_app": resourceSpringCloudApp(), - "azurerm_spring_cloud_certificate": resourceSpringCloudCertificate(), - "azurerm_spring_cloud_custom_domain": resourceSpringCloudCustomDomain(), - "azurerm_spring_cloud_java_deployment": resourceSpringCloudJavaDeployment(), - "azurerm_spring_cloud_service": resourceSpringCloudService(), + "azurerm_spring_cloud_active_deployment": resourceSpringCloudActiveDeployment(), + "azurerm_spring_cloud_app": resourceSpringCloudApp(), + "azurerm_spring_cloud_app_redis_association": resourceSpringCloudAppRedisAssociation(), + "azurerm_spring_cloud_certificate": resourceSpringCloudCertificate(), + "azurerm_spring_cloud_custom_domain": resourceSpringCloudCustomDomain(), + "azurerm_spring_cloud_java_deployment": resourceSpringCloudJavaDeployment(), + "azurerm_spring_cloud_service": resourceSpringCloudService(), } } diff --git a/azurerm/internal/services/springcloud/resourceids.go b/azurerm/internal/services/springcloud/resourceids.go index 955d4a2f14b1..456ed80c16c2 100644 --- a/azurerm/internal/services/springcloud/resourceids.go +++ b/azurerm/internal/services/springcloud/resourceids.go @@ -1,6 +1,7 @@ package springcloud //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudApp -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudAppAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/bind1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudDeployment -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/deploy1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudCertificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/certificates/cert1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudCustomDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/domains/domain.com diff --git a/azurerm/internal/services/springcloud/spring_cloud_app_association_import.go b/azurerm/internal/services/springcloud/spring_cloud_app_association_import.go new file mode 100644 index 000000000000..929e1bef5265 --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_app_association_import.go @@ -0,0 +1,40 @@ +package springcloud + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" +) + +const springCloudAppAssociationTypeRedis = "Microsoft.Cache" + +func importSpringCloudAppAssociation(resourceType string) func(d *schema.ResourceData, meta interface{}) (data []*schema.ResourceData, err error) { + return func(d *schema.ResourceData, meta interface{}) (data []*schema.ResourceData, err error) { + id, err := parse.SpringCloudAppAssociationID(d.Id()) + if err != nil { + return []*schema.ResourceData{}, err + } + + client := meta.(*clients.Client).AppPlatform.BindingsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + resp, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName) + if err != nil { + return []*schema.ResourceData{}, fmt.Errorf("retrieving %s: %+v", id, err) + } + + if resp.Properties == nil || resp.Properties.ResourceType == nil { + return []*schema.ResourceData{}, fmt.Errorf("retrieving %s: `properties` or `properties.resourceType` was nil", id) + } + + if *resp.Properties.ResourceType != resourceType { + return []*schema.ResourceData{}, fmt.Errorf(`spring Cloud App Association "type" mismatch, expected "%s", got "%s"`, resourceType, *resp.Properties.ResourceType) + } + + return []*schema.ResourceData{d}, nil + } +} diff --git a/azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource.go b/azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource.go new file mode 100644 index 000000000000..04e78936037c --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource.go @@ -0,0 +1,170 @@ +package springcloud + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/appplatform/mgmt/2020-11-01-preview/appplatform" + "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/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + redisValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/redis/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/validate" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +const springCloudAppRedisAssociationKeySSL = "useSsl" + +func resourceSpringCloudAppRedisAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceSpringCloudAppRedisAssociationCreateUpdate, + Read: resourceSpringCloudAppRedisAssociationRead, + Update: resourceSpringCloudAppRedisAssociationCreateUpdate, + Delete: resourceSpringCloudAppRedisAssociationDelete, + + Importer: azSchema.ValidateResourceIDPriorToImportThen(func(id string) error { + _, err := parse.SpringCloudAppAssociationID(id) + return err + }, importSpringCloudAppAssociation(springCloudAppAssociationTypeRedis)), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SpringCloudAppAssociationName, + }, + + "spring_cloud_app_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SpringCloudAppID, + }, + + "redis_cache_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: redisValidate.CacheID, + }, + + "redis_access_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "ssl_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + } +} + +func resourceSpringCloudAppRedisAssociationCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.BindingsClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + appId, err := parse.SpringCloudAppID(d.Get("spring_cloud_app_id").(string)) + if err != nil { + return err + } + + id := parse.NewSpringCloudAppAssociationID(appId.SubscriptionId, appId.ResourceGroup, appId.SpringName, appId.AppName, d.Get("name").(string)) + if d.IsNewResource() { + existing, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for present of existing %s: %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_spring_cloud_app_redis_association", id.ID()) + } + } + + bindingResource := appplatform.BindingResource{ + Properties: &appplatform.BindingResourceProperties{ + BindingParameters: map[string]interface{}{ + springCloudAppRedisAssociationKeySSL: d.Get("ssl_enabled").(bool), + }, + Key: utils.String(d.Get("redis_access_key").(string)), + ResourceID: utils.String(d.Get("redis_cache_id").(string)), + }, + } + + if _, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName, bindingResource); err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceSpringCloudAppRedisAssociationRead(d, meta) +} + +func resourceSpringCloudAppRedisAssociationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.BindingsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudAppAssociationID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] Spring Cloud App Association %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("reading %s: %+v", id, err) + } + + d.Set("name", id.BindingName) + d.Set("spring_cloud_app_id", parse.NewSpringCloudAppID(id.SubscriptionId, id.ResourceGroup, id.SpringName, id.AppName).ID()) + if props := resp.Properties; props != nil { + d.Set("redis_cache_id", props.ResourceID) + + enableSSL := "false" + if v, ok := props.BindingParameters[springCloudAppRedisAssociationKeySSL]; ok { + enableSSL = v.(string) + } + d.Set("ssl_enabled", strings.EqualFold(enableSSL, "true")) + } + return nil +} + +func resourceSpringCloudAppRedisAssociationDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).AppPlatform.BindingsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SpringCloudAppAssociationID(d.Id()) + if err != nil { + return err + } + + if _, err := client.Delete(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName); err != nil { + return fmt.Errorf("deleting %s: %+v", id, err) + } + + return nil +} diff --git a/azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource_test.go b/azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource_test.go new file mode 100644 index 000000000000..08362ab8c389 --- /dev/null +++ b/azurerm/internal/services/springcloud/spring_cloud_app_redis_association_resource_test.go @@ -0,0 +1,181 @@ +package springcloud_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type SpringCloudAppRedisAssociationResource struct { +} + +func TestAccSpringCloudAppRedisAssociation_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_app_redis_association", "test") + r := SpringCloudAppRedisAssociationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("redis_access_key"), + }) +} + +func TestAccSpringCloudAppRedisAssociation_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_app_redis_association", "test") + r := SpringCloudAppRedisAssociationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccSpringCloudAppRedisAssociation_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_app_redis_association", "test") + r := SpringCloudAppRedisAssociationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("redis_access_key"), + }) +} + +func TestAccSpringCloudAppRedisAssociation_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_app_redis_association", "test") + r := SpringCloudAppRedisAssociationResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("redis_access_key"), + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("redis_access_key"), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("redis_access_key"), + }) +} + +func (t SpringCloudAppRedisAssociationResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.SpringCloudAppAssociationID(state.ID) + if err != nil { + return nil, err + } + + resp, err := clients.AppPlatform.BindingsClient.Get(ctx, id.ResourceGroup, id.SpringName, id.AppName, id.BindingName) + if err != nil { + return nil, fmt.Errorf("reading %s: %+v", id, err) + } + + return utils.Bool(resp.Properties != nil), nil +} + +func (r SpringCloudAppRedisAssociationResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_app_redis_association" "test" { + name = "acctestscarb-%d" + spring_cloud_app_id = azurerm_spring_cloud_app.test.id + redis_cache_id = azurerm_redis_cache.test.id + redis_access_key = azurerm_redis_cache.test.primary_access_key +} +`, r.template(data), data.RandomInteger) +} + +func (r SpringCloudAppRedisAssociationResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_app_redis_association" "import" { + name = azurerm_spring_cloud_app_redis_association.test.name + spring_cloud_app_id = azurerm_spring_cloud_app_redis_association.test.spring_cloud_app_id + redis_cache_id = azurerm_spring_cloud_app_redis_association.test.redis_cache_id + redis_access_key = azurerm_spring_cloud_app_redis_association.test.redis_access_key +} +`, r.basic(data)) +} + +func (r SpringCloudAppRedisAssociationResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_app_redis_association" "test" { + name = "acctestscarb-%d" + spring_cloud_app_id = azurerm_spring_cloud_app.test.id + redis_cache_id = azurerm_redis_cache.test.id + redis_access_key = azurerm_redis_cache.test.secondary_access_key + ssl_enabled = false +} +`, r.template(data), data.RandomInteger) +} + +func (r SpringCloudAppRedisAssociationResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-spring-%d" + location = "%s" +} + +resource "azurerm_spring_cloud_service" "test" { + name = "acctest-sc-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_spring_cloud_app" "test" { + name = "acctest-sca-%d" + resource_group_name = azurerm_spring_cloud_service.test.resource_group_name + service_name = azurerm_spring_cloud_service.test.name +} + +resource "azurerm_redis_cache" "test" { + name = "acctestredis-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + capacity = 0 + family = "C" + sku_name = "Basic" + enable_non_ssl_port = true +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id.go b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id.go new file mode 100644 index 000000000000..04ce712df5cf --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/springcloud/parse" +) + +func SpringCloudAppAssociationID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.SpringCloudAppAssociationID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id_test.go b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id_test.go new file mode 100644 index 000000000000..8ca173ffb4b6 --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_id_test.go @@ -0,0 +1,100 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestSpringCloudAppAssociationID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/", + Valid: false, + }, + + { + // missing value for SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/", + Valid: false, + }, + + { + // missing AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/", + Valid: false, + }, + + { + // missing value for AppName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/", + Valid: false, + }, + + { + // missing BindingName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/", + Valid: false, + }, + + { + // missing value for BindingName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/bind1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APPPLATFORM/SPRING/SPRING1/APPS/APP1/BINDINGS/BIND1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := SpringCloudAppAssociationID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name.go b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name.go new file mode 100644 index 000000000000..0266facfc9d8 --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name.go @@ -0,0 +1,25 @@ +package validate + +import ( + "fmt" + "regexp" +) + +func SpringCloudAppAssociationName(i interface{}, k string) (_ []string, errors []error) { + v, ok := i.(string) + if !ok { + return nil, append(errors, fmt.Errorf("expected type of %s to be string", k)) + } + + // The name attribute rules are : + // 1. can contain only lowercase letters, numbers and hyphens. + // 2. The first character must be a letter. + // 3. The last character must be a letter or number + // 4. The value must be between 4 and 32 characters long + + if !regexp.MustCompile(`^([a-z])([a-z\d-]{2,30})([a-z\d])$`).MatchString(v) { + errors = append(errors, fmt.Errorf("%s must begin with a letter, end with a letter or number, contain only lowercase letters, numbers and hyphens. The value must be between 4 and 32 characters long", k)) + } + + return nil, errors +} diff --git a/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name_test.go b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name_test.go new file mode 100644 index 000000000000..989715239cc1 --- /dev/null +++ b/azurerm/internal/services/springcloud/validate/spring_cloud_app_association_name_test.go @@ -0,0 +1,61 @@ +package validate + +import "testing" + +func TestSpringCloudAppBindingName(t *testing.T) { + testData := []struct { + input string + expected bool + }{ + { + // empty + input: "", + expected: false, + }, + { + // basic example + input: "ab-c", + expected: true, + }, + { + // can't start with a number + input: "1abc", + expected: false, + }, + { + // can't contain underscore + input: "ab_c", + expected: false, + }, + { + // can't end with hyphen + input: "abc-", + expected: false, + }, + { + // can not short than 4 characters + input: "abc", + expected: false, + }, + { + // 32 chars + input: "abcdefghijklmnopqrstuvwxyzabcdef", + expected: true, + }, + { + // 33 chars + input: "abcdefghijklmnopqrstuvwxyzabcdefg", + expected: false, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q..", v.input) + + _, errors := SpringCloudAppAssociationName(v.input, "name") + actual := len(errors) == 0 + if v.expected != actual { + t.Fatalf("Expected %t but got %t", v.expected, actual) + } + } +} diff --git a/website/docs/r/spring_cloud_app_redis_association.html.markdown b/website/docs/r/spring_cloud_app_redis_association.html.markdown new file mode 100644 index 000000000000..e44ae8efc1d5 --- /dev/null +++ b/website/docs/r/spring_cloud_app_redis_association.html.markdown @@ -0,0 +1,91 @@ +--- +subcategory: "Spring Cloud" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_spring_cloud_app_redis_association" +description: |- + Associates a [Spring Cloud Application](spring_cloud_app.html) with a [Redis Cache](redis_cache.html). +--- + +# azurerm_spring_cloud_app_redis_association + +Associates a [Spring Cloud Application](spring_cloud_app.html) with a [Redis Cache](redis_cache.html). + +## Example Usage + +```hcl +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_spring_cloud_service" "example" { + name = "example-springcloud" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location +} + +resource "azurerm_spring_cloud_app" "example" { + name = "example-springcloudapp" + resource_group_name = azurerm_resource_group.example.name + service_name = azurerm_spring_cloud_service.example.name +} + +resource "azurerm_redis_cache" "example" { + name = "example-cache" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + capacity = 0 + family = "C" + sku_name = "Basic" + enable_non_ssl_port = true +} + +resource "azurerm_spring_cloud_app_redis_association" "example" { + name = "example-bind" + spring_cloud_app_id = azurerm_spring_cloud_app.example.id + redis_cache_id = azurerm_redis_cache.example.id + redis_access_key = azurerm_redis_cache.example.primary_access_key + ssl_enabled = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Specifies the name of the Spring Cloud Application Association. Changing this forces a new resource to be created. + +* `spring_cloud_app_id` - (Required) Specifies the Spring Cloud Application resource ID in which the Association is created. Changing this forces a new resource to be created. + +* `redis_cache_id` - (Required) Specifies the Redis Cache resource ID. Changing this forces a new resource to be created. + +* `redis_access_key` - (Required) Specifies the Redis Cache access key. + +* `ssl_enabled` - (Optional) Should SSL be used when connecting to Redis? Defaults to `true`. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Spring Cloud Application Redis Association. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Spring Cloud Application Redis Association. +* `read` - (Defaults to 5 minutes) Used when retrieving the Spring Cloud Application Redis Association. +* `update` - (Defaults to 30 minutes) Used when updating the Spring Cloud Application Redis Association. +* `delete` - (Defaults to 30 minutes) Used when deleting the Spring Cloud Application Redis Association. + +## Import + +Spring Cloud Application Redis Association can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_spring_cloud_app_redis_association.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myresourcegroup/providers/Microsoft.AppPlatform/Spring/myservice/apps/myapp/bindings/bind1 +``` From b7a515b6365dbbd050711a7f33c9c0667a082dea Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 6 Apr 2021 15:32:08 -0700 Subject: [PATCH 14/40] CHANGELOG.md for #11154 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea9ad87cb443..2b623b9768dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ FEATURES: * **New Resource:** `azurerm_communication_service` [GH-11066] * **New Resource:** `azurerm_express_route_port` [GH-10074] +* **New Resource:** `azurerm_spring_cloud_app_redis_association` [GH-11154] ENHANCEMENTS: From 981e50d46f222272ead21f7318e903c4e6fe5ef2 Mon Sep 17 00:00:00 2001 From: jan-mrm <67435696+jan-mrm@users.noreply.github.com> Date: Wed, 7 Apr 2021 02:22:43 +0200 Subject: [PATCH 15/40] New resource: azurerm_api_management_email_template (#10914) * implementation of resource api management email template * added missing ForceNew and documentation for template_name to have proper behaviour. added acc tests. * implemented review findings * removed exporting of apim email template parameters --- .../api_management_email_template_resource.go | 191 ++++++++++++++++++ ...management_email_template_resource_test.go | 191 ++++++++++++++++++ .../services/apimanagement/client/client.go | 5 + .../apimanagement/parse/email_template.go | 75 +++++++ .../parse/email_template_test.go | 128 ++++++++++++ .../services/apimanagement/registration.go | 1 + .../services/apimanagement/resourceids.go | 1 + .../validate/email_template_id.go | 23 +++ .../validate/email_template_id_test.go | 88 ++++++++ ...pi_management_email_template.html.markdown | 92 +++++++++ 10 files changed, 795 insertions(+) create mode 100644 azurerm/internal/services/apimanagement/api_management_email_template_resource.go create mode 100644 azurerm/internal/services/apimanagement/api_management_email_template_resource_test.go create mode 100644 azurerm/internal/services/apimanagement/parse/email_template.go create mode 100644 azurerm/internal/services/apimanagement/parse/email_template_test.go create mode 100644 azurerm/internal/services/apimanagement/validate/email_template_id.go create mode 100644 azurerm/internal/services/apimanagement/validate/email_template_id_test.go create mode 100644 website/docs/r/api_management_email_template.html.markdown diff --git a/azurerm/internal/services/apimanagement/api_management_email_template_resource.go b/azurerm/internal/services/apimanagement/api_management_email_template_resource.go new file mode 100644 index 000000000000..614bec058176 --- /dev/null +++ b/azurerm/internal/services/apimanagement/api_management_email_template_resource.go @@ -0,0 +1,191 @@ +package apimanagement + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2019-12-01/apimanagement" + "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/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/schemaz" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceApiManagementEmailTemplate() *schema.Resource { + return &schema.Resource{ + Create: resourceApiManagementEmailTemplateCreateUpdate, + Read: resourceApiManagementEmailTemplateRead, + Update: resourceApiManagementEmailTemplateCreateUpdate, + Delete: resourceApiManagementEmailTemplateDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "resource_group_name": azure.SchemaResourceGroupName(), + + "api_management_name": schemaz.SchemaApiManagementName(), + + // There is an open issue for the capitalization of the template names: https://github.com/Azure/azure-rest-api-specs/issues/13341 + "template_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + strings.Title(string(apimanagement.AccountClosedDeveloper)), + strings.Title(string(apimanagement.ApplicationApprovedNotificationMessage)), + strings.Title(string(apimanagement.ConfirmSignUpIdentityDefault)), + strings.Title(string(apimanagement.EmailChangeIdentityDefault)), + strings.Title(string(apimanagement.InviteUserNotificationMessage)), + strings.Title(string(apimanagement.NewCommentNotificationMessage)), + strings.Title(string(apimanagement.NewDeveloperNotificationMessage)), + strings.Title(string(apimanagement.NewIssueNotificationMessage)), + strings.Title(string(apimanagement.PasswordResetByAdminNotificationMessage)), + strings.Title(string(apimanagement.PasswordResetIdentityDefault)), + strings.Title(string(apimanagement.PurchaseDeveloperNotificationMessage)), + strings.Title(string(apimanagement.QuotaLimitApproachingDeveloperNotificationMessage)), + strings.Title(string(apimanagement.RejectDeveloperNotificationMessage)), + strings.Title(string(apimanagement.RequestDeveloperNotificationMessage)), + }, false), + }, + "body": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "subject": { + Type: schema.TypeString, + Required: true, + }, + // Computed: + "title": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceApiManagementEmailTemplateCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.EmailTemplateClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + defer cancel() + + resourceGroup := d.Get("resource_group_name").(string) + serviceName := d.Get("api_management_name").(string) + templateName := apimanagement.TemplateName(d.Get("template_name").(string)) + + id := parse.NewEmailTemplateID(subscriptionId, resourceGroup, serviceName, d.Get("template_name").(string)) + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, serviceName, templateName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for presence of existing %s: %s", id, err) + } + } + + // in case the template has been edited (is not default anymore) this errors and the resource should be imported manually into the state (terraform import). + if !utils.ResponseWasNotFound(existing.Response) && (existing.IsDefault != nil && !*existing.IsDefault) { + return tf.ImportAsExistsError("azurerm_api_management_email_template", id.ID()) + } + } + + subject := d.Get("subject").(string) + body := d.Get("body").(string) + + emailTemplateUpdateParameters := apimanagement.EmailTemplateUpdateParameters{ + EmailTemplateUpdateParameterProperties: &apimanagement.EmailTemplateUpdateParameterProperties{ + Subject: utils.String(subject), + Body: utils.String(body), + }, + } + + if _, err := client.CreateOrUpdate(ctx, resourceGroup, serviceName, templateName, emailTemplateUpdateParameters, ""); err != nil { + return fmt.Errorf("creating/updating %s: %+v", id, err) + } + + d.SetId(id.ID()) + + return resourceApiManagementEmailTemplateRead(d, meta) +} + +func resourceApiManagementEmailTemplateRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.EmailTemplateClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.EmailTemplateID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + serviceName := id.ServiceName + + templateName := apimanagement.TemplateName(id.TemplateName) + + resp, err := client.Get(ctx, resourceGroup, serviceName, templateName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] %s does not exist - removing from state!", *id) + d.SetId("") + return nil + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + + d.Set("resource_group_name", resourceGroup) + d.Set("api_management_name", serviceName) + d.Set("template_name", templateName) + if properties := resp.EmailTemplateContractProperties; properties != nil { + d.Set("title", properties.Title) + d.Set("description", properties.Description) + d.Set("subject", properties.Subject) + d.Set("body", properties.Body) + } + + return nil +} + +func resourceApiManagementEmailTemplateDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).ApiManagement.EmailTemplateClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.EmailTemplateID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + serviceName := id.ServiceName + templateName := apimanagement.TemplateName(id.TemplateName) + + if resp, err := client.Delete(ctx, resourceGroup, serviceName, templateName, ""); err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("deleting %s: %s", *id, err) + } + } + + return nil +} diff --git a/azurerm/internal/services/apimanagement/api_management_email_template_resource_test.go b/azurerm/internal/services/apimanagement/api_management_email_template_resource_test.go new file mode 100644 index 000000000000..3b109567e763 --- /dev/null +++ b/azurerm/internal/services/apimanagement/api_management_email_template_resource_test.go @@ -0,0 +1,191 @@ +package apimanagement_test + +import ( + "context" + "fmt" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/apimanagement/mgmt/2019-12-01/apimanagement" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type ApiManagementEmailTemplateResource struct { +} + +func TestAccApiManagementEmailTemplate_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_email_template", "test") + r := ApiManagementEmailTemplateResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccApiManagementEmailTemplate_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_email_template", "test") + r := ApiManagementEmailTemplateResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccApiManagementEmailTemplate_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_api_management_email_template", "test") + r := ApiManagementEmailTemplateResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("subject").HasValue("Please confirm your new customized $OrganizationName API account with this customized email"), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("subject").HasValue("Please confirm your new customized $OrganizationName API account with this customized and updated email"), + ), + }, + data.ImportStep(), + }) +} + +func (ApiManagementEmailTemplateResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.EmailTemplateID(state.ID) + if err != nil { + return nil, err + } + + _, err = clients.ApiManagement.EmailTemplateClient.Get(ctx, id.ResourceGroup, id.ServiceName, apimanagement.TemplateName(id.TemplateName)) + if err != nil { + return nil, fmt.Errorf("reading %s: %+v", *id, err) + } + + return utils.Bool(true), nil +} + +func (r ApiManagementEmailTemplateResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_email_template" "test" { + template_name = "ConfirmSignUpIdentityDefault" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + subject = "Please confirm your new customized $OrganizationName API account with this customized email" + body = < + + + + Customized Letter Title + + + + + + +
+

Dear $DevFirstName $DevLastName,

+

+

Thank you for joining the $OrganizationName API program! We host a growing number of cool APIs and strive to provide an awesome experience for API developers.

+

This email is automatically created using a customized template witch is stored configuration as code.

+
+ + +EOF +} +`, r.template(data)) +} + +func (r ApiManagementEmailTemplateResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_email_template" "import" { + template_name = azurerm_api_management_email_template.test.template_name + api_management_name = azurerm_api_management_email_template.test.api_management_name + resource_group_name = azurerm_api_management_email_template.test.resource_group_name + subject = azurerm_api_management_email_template.test.subject + body = azurerm_api_management_email_template.test.body +} +`, r.basic(data)) +} + +func (r ApiManagementEmailTemplateResource) update(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_api_management_email_template" "test" { + template_name = "ConfirmSignUpIdentityDefault" + api_management_name = azurerm_api_management.test.name + resource_group_name = azurerm_resource_group.test.name + subject = "Please confirm your new customized $OrganizationName API account with this customized and updated email" + body = < + + + + Customized Letter Title + + + + + + +
+

Dear $DevFirstName $DevLastName,

+

+

Thank you for joining the $OrganizationName API program! We host a growing number of cool APIs and strive to provide an awesome experience for API developers.

+

This email is automatically created using a customized template witch is stored configuration as code.

+
+ + +EOF +} +`, r.template(data)) +} + +func (ApiManagementEmailTemplateResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_api_management" "test" { + name = "acctestAM-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + publisher_name = "pub1" + publisher_email = "pub1@email.com" + sku_name = "Developer_1" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} diff --git a/azurerm/internal/services/apimanagement/client/client.go b/azurerm/internal/services/apimanagement/client/client.go index 6e57496be1b7..1e7214f53829 100644 --- a/azurerm/internal/services/apimanagement/client/client.go +++ b/azurerm/internal/services/apimanagement/client/client.go @@ -17,6 +17,7 @@ type Client struct { BackendClient *apimanagement.BackendClient CertificatesClient *apimanagement.CertificateClient DiagnosticClient *apimanagement.DiagnosticClient + EmailTemplateClient *apimanagement.EmailTemplateClient GroupClient *apimanagement.GroupClient GroupUsersClient *apimanagement.GroupUserClient IdentityProviderClient *apimanagement.IdentityProviderClient @@ -70,6 +71,9 @@ func NewClient(o *common.ClientOptions) *Client { diagnosticClient := apimanagement.NewDiagnosticClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&diagnosticClient.Client, o.ResourceManagerAuthorizer) + emailTemplateClient := apimanagement.NewEmailTemplateClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&emailTemplateClient.Client, o.ResourceManagerAuthorizer) + groupClient := apimanagement.NewGroupClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&groupClient.Client, o.ResourceManagerAuthorizer) @@ -133,6 +137,7 @@ func NewClient(o *common.ClientOptions) *Client { BackendClient: &backendClient, CertificatesClient: &certificatesClient, DiagnosticClient: &diagnosticClient, + EmailTemplateClient: &emailTemplateClient, GroupClient: &groupClient, GroupUsersClient: &groupUsersClient, IdentityProviderClient: &identityProviderClient, diff --git a/azurerm/internal/services/apimanagement/parse/email_template.go b/azurerm/internal/services/apimanagement/parse/email_template.go new file mode 100644 index 000000000000..b9b101cb188c --- /dev/null +++ b/azurerm/internal/services/apimanagement/parse/email_template.go @@ -0,0 +1,75 @@ +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 EmailTemplateId struct { + SubscriptionId string + ResourceGroup string + ServiceName string + TemplateName string +} + +func NewEmailTemplateID(subscriptionId, resourceGroup, serviceName, templateName string) EmailTemplateId { + return EmailTemplateId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServiceName: serviceName, + TemplateName: templateName, + } +} + +func (id EmailTemplateId) String() string { + segments := []string{ + fmt.Sprintf("Template Name %q", id.TemplateName), + fmt.Sprintf("Service Name %q", id.ServiceName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Email Template", segmentsStr) +} + +func (id EmailTemplateId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ApiManagement/service/%s/templates/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServiceName, id.TemplateName) +} + +// EmailTemplateID parses a EmailTemplate ID into an EmailTemplateId struct +func EmailTemplateID(input string) (*EmailTemplateId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := EmailTemplateId{ + 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.ServiceName, err = id.PopSegment("service"); err != nil { + return nil, err + } + if resourceId.TemplateName, err = id.PopSegment("templates"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/apimanagement/parse/email_template_test.go b/azurerm/internal/services/apimanagement/parse/email_template_test.go new file mode 100644 index 000000000000..67c7d528009f --- /dev/null +++ b/azurerm/internal/services/apimanagement/parse/email_template_test.go @@ -0,0 +1,128 @@ +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 = EmailTemplateId{} + +func TestEmailTemplateIDFormatter(t *testing.T) { + actual := NewEmailTemplateID("12345678-1234-9876-4563-123456789012", "resGroup1", "service1", "template1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/templates/template1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestEmailTemplateID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *EmailTemplateId + }{ + + { + // 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 ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Error: true, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Error: true, + }, + + { + // missing TemplateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Error: true, + }, + + { + // missing value for TemplateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/templates/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/templates/template1", + Expected: &EmailTemplateId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + ServiceName: "service1", + TemplateName: "template1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/TEMPLATES/TEMPLATE1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := EmailTemplateID(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.ServiceName != v.Expected.ServiceName { + t.Fatalf("Expected %q but got %q for ServiceName", v.Expected.ServiceName, actual.ServiceName) + } + if actual.TemplateName != v.Expected.TemplateName { + t.Fatalf("Expected %q but got %q for TemplateName", v.Expected.TemplateName, actual.TemplateName) + } + } +} diff --git a/azurerm/internal/services/apimanagement/registration.go b/azurerm/internal/services/apimanagement/registration.go index 69b1e9417d09..c53a745b87c4 100644 --- a/azurerm/internal/services/apimanagement/registration.go +++ b/azurerm/internal/services/apimanagement/registration.go @@ -46,6 +46,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_api_management_certificate": resourceApiManagementCertificate(), "azurerm_api_management_custom_domain": resourceApiManagementCustomDomain(), "azurerm_api_management_diagnostic": resourceApiManagementDiagnostic(), + "azurerm_api_management_email_template": resourceApiManagementEmailTemplate(), "azurerm_api_management_group": resourceApiManagementGroup(), "azurerm_api_management_group_user": resourceApiManagementGroupUser(), "azurerm_api_management_identity_provider_aad": resourceApiManagementIdentityProviderAAD(), diff --git a/azurerm/internal/services/apimanagement/resourceids.go b/azurerm/internal/services/apimanagement/resourceids.go index b03b9aea7d11..92beb576d3dc 100644 --- a/azurerm/internal/services/apimanagement/resourceids.go +++ b/azurerm/internal/services/apimanagement/resourceids.go @@ -13,6 +13,7 @@ package apimanagement //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Certificate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/certificates/certificate1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=CustomDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/customDomains/customdomain //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Diagnostic -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/diagnostics/diagnostic1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=EmailTemplate -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/templates/template1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Group -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/groups/group1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=GroupUser -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/groups/group1/users/user1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=IdentityProvider -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/identityProviders/identityProvider1 diff --git a/azurerm/internal/services/apimanagement/validate/email_template_id.go b/azurerm/internal/services/apimanagement/validate/email_template_id.go new file mode 100644 index 000000000000..6616da718b16 --- /dev/null +++ b/azurerm/internal/services/apimanagement/validate/email_template_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/apimanagement/parse" +) + +func EmailTemplateID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.EmailTemplateID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/apimanagement/validate/email_template_id_test.go b/azurerm/internal/services/apimanagement/validate/email_template_id_test.go new file mode 100644 index 000000000000..3af1b223d39e --- /dev/null +++ b/azurerm/internal/services/apimanagement/validate/email_template_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestEmailTemplateID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/", + Valid: false, + }, + + { + // missing value for ServiceName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/", + Valid: false, + }, + + { + // missing TemplateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/", + Valid: false, + }, + + { + // missing value for TemplateName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/templates/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ApiManagement/service/service1/templates/template1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.APIMANAGEMENT/SERVICE/SERVICE1/TEMPLATES/TEMPLATE1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := EmailTemplateID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/r/api_management_email_template.html.markdown b/website/docs/r/api_management_email_template.html.markdown new file mode 100644 index 000000000000..38bbd30481ca --- /dev/null +++ b/website/docs/r/api_management_email_template.html.markdown @@ -0,0 +1,92 @@ +--- +subcategory: "API Management" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_api_management_email_template" +description: |- + Manages a API Management Email Template. +--- + +# azurerm_api_management_email_template + +Manages a API Management Email Template. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_api_management" "example" { + name = "example-apim" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + publisher_name = "My Company" + publisher_email = "company@terraform.io" + + sku_name = "Developer_1" +} + +resource "azurerm_api_management_email_template" "example" { + template_name = "ConfirmSignUpIdentityDefault" + resource_group_name = azurerm_resource_group.example.resource_group_name + api_management_name = azurerm_api_management.example.name + subject = "Customized confirmation email for your new $OrganizationName API account" + body = < + + + + Customized Letter Title + + +

Dear $DevFirstName $DevLastName,

+ + +EOF +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `template_name` - (Required) The name of the Email Template. Possible values are `AccountClosedDeveloper`, `ApplicationApprovedNotificationMessage`, `ConfirmSignUpIdentityDefault`, `EmailChangeIdentityDefault`, `InviteUserNotificationMessage`, `NewCommentNotificationMessage`, `NewDeveloperNotificationMessage`, `NewIssueNotificationMessage`, `PasswordResetByAdminNotificationMessage`, `PasswordResetIdentityDefault`, `PurchaseDeveloperNotificationMessage`, `QuotaLimitApproachingDeveloperNotificationMessage`, `RejectDeveloperNotificationMessage`, `RequestDeveloperNotificationMessage`. Changing this forces a new API Management Email Template to be created. + +* `api_management_name` - (Required) The name of the API Management Service in which the Email Template should exist. Changing this forces a new API Management Email Template to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the API Management Email Template should exist. Changing this forces a new API Management Email Template to be created. + +* `subject` - (Required) The subject of the Email. + +* `body` - (Required) The body of the Email. Its format has to be a well-formed HTML document. + +-> **NOTE:** In `subject` and `body` predefined parameters can be used. The available parameters depend on the template. Schema to use a parameter: `$` followed by the `parameter.name` - `$`. The available parameters can be seen in the Notification templates section of the API-Management Service instance within the Azure Portal. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the API Management Email Template. + +* `title` - The title of the Email Template. + +* `description` - The description of the Email Template. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the API Management Email Template. +* `read` - (Defaults to 5 minutes) Used when retrieving the API Management Email Template. +* `update` - (Defaults to 30 minutes) Used when updating the API Management Email Template. +* `delete` - (Defaults to 30 minutes) Used when deleting the API Management Email Template. + +## Import + +API Management Email Templates can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_api_management_email_template.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.ApiManagement/service/instance1/templates/template1 +``` From 97deefd54195a8f511c3c6cb64cdbb5c880742c0 Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Wed, 7 Apr 2021 01:23:40 +0100 Subject: [PATCH 16/40] Update changelog for #10914 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b623b9768dd..308e8b1dde47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ FEATURES: +* **New Resource:** `azurerm_api_management_email_template` [GH-10914] * **New Resource:** `azurerm_communication_service` [GH-11066] * **New Resource:** `azurerm_express_route_port` [GH-10074] * **New Resource:** `azurerm_spring_cloud_app_redis_association` [GH-11154] From 7f4a2b007fde489be425afaf79a6e72ef3bc1840 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 16:33:09 +0200 Subject: [PATCH 17/40] d/dns_zone: not setting the resource id until after we've looked it up This data source is a special case where the Resource Group name can either be specified or looked up, so we need to set the ID once we're sure we've got the Resource Group, else the segment will be empty in the Resource ID. Fixes #11220 --- azurerm/internal/services/dns/dns_zone_data_source.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/azurerm/internal/services/dns/dns_zone_data_source.go b/azurerm/internal/services/dns/dns_zone_data_source.go index 6f89b99ab594..c6e4b8feddf4 100644 --- a/azurerm/internal/services/dns/dns_zone_data_source.go +++ b/azurerm/internal/services/dns/dns_zone_data_source.go @@ -66,8 +66,6 @@ func dataSourceDnsZoneRead(d *schema.ResourceData, meta interface{}) error { name := d.Get("name").(string) resourceGroup := d.Get("resource_group_name").(string) - resourceId := parse.NewDnsZoneID(subscriptionId, resourceGroup, name) - var ( resp dns.Zone err error @@ -94,10 +92,7 @@ func dataSourceDnsZoneRead(d *schema.ResourceData, meta interface{}) error { resp = *zone } - if resp.ID == nil || *resp.ID == "" { - return fmt.Errorf("failed reading ID for DNS Zone %q (Resource Group %q)", name, resourceGroup) - } - + resourceId := parse.NewDnsZoneID(subscriptionId, resourceGroup, name) d.SetId(resourceId.ID()) d.Set("name", name) From 380ec4373c4caf8b9bb9230a9924094e6e4a30f2 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Wed, 7 Apr 2021 12:09:42 +0200 Subject: [PATCH 18/40] updating to include #11221 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 308e8b1dde47..94441245710c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ ENHANCEMENTS: BUG FIXES: +* Data Source: `azurerm_dns_zone` - fixing a bug where the Resource ID wouldn't contain the Resource Group name when looking this up [GH-11221] * `azurerm_media_service_account` - `storage_authentication_type` correctly accepts both `ManagedIdentity` and `System` [GH-11222] * `azurerm_web_application_firewall_policy` - `http_listener_ids` and `path_based_rule_ids` are now Computed only [GH-11196] From 1def5cde02e6449f5b1181b6171ef217608238d3 Mon Sep 17 00:00:00 2001 From: Heng Lu Date: Fri, 2 Apr 2021 12:05:23 +0800 Subject: [PATCH 19/40] fix kubernates cluster acc tests --- .../kubernetes_cluster_node_pool_resource_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/containers/kubernetes_cluster_node_pool_resource_test.go b/azurerm/internal/services/containers/kubernetes_cluster_node_pool_resource_test.go index 1f2c81364ce6..335374da4709 100644 --- a/azurerm/internal/services/containers/kubernetes_cluster_node_pool_resource_test.go +++ b/azurerm/internal/services/containers/kubernetes_cluster_node_pool_resource_test.go @@ -434,21 +434,21 @@ func testAccKubernetesClusterNodePool_nodeLabels(t *testing.T) { { Config: r.nodeLabelsConfig(data, labels1), Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("node_labels.#").HasValue("1"), + check.That(data.ResourceName).Key("node_labels.%").HasValue("1"), check.That(data.ResourceName).Key("node_labels.key").HasValue("value"), ), }, { Config: r.nodeLabelsConfig(data, labels2), Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("node_labels.#").HasValue("1"), + check.That(data.ResourceName).Key("node_labels.%").HasValue("1"), check.That(data.ResourceName).Key("node_labels.key2").HasValue("value2"), ), }, { Config: r.nodeLabelsConfig(data, labels3), Check: resource.ComposeTestCheckFunc( - check.That(data.ResourceName).Key("node_labels.#").HasValue("0"), + check.That(data.ResourceName).Key("node_labels.%").HasValue("0"), ), }, }) @@ -1591,7 +1591,7 @@ resource "azurerm_kubernetes_cluster" "test" { windows_profile { admin_username = "azureuser" - admin_password = "P@55W0rd1234!" + admin_password = "P@55W0rd1234!h@2h1C0rP" } network_profile { From 5d2185145fae1513ede038bbbbe180a4837de300 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Wed, 7 Apr 2021 18:58:43 +0200 Subject: [PATCH 20/40] docs: adding a heads up about the breaking api change rolling out 2021-04-09 (#11237) More details are in #11231, although it's hard for us to do much about this ahead of time unfortunately due to the inability to test these changes (and confirm which breaking changes are necessary), as such giving some notice this is happening is the most helpful thing we can do at the moment. --- website/docs/r/cdn_endpoint.html.markdown | 2 ++ website/docs/r/cdn_profile.html.markdown | 2 ++ website/docs/r/frontdoor.html.markdown | 2 ++ .../docs/r/frontdoor_custom_https_configuration.html.markdown | 2 ++ website/docs/r/frontdoor_firewall_policy.html.markdown | 2 ++ 5 files changed, 10 insertions(+) diff --git a/website/docs/r/cdn_endpoint.html.markdown b/website/docs/r/cdn_endpoint.html.markdown index 71180adff08e..a1a995d7ba36 100644 --- a/website/docs/r/cdn_endpoint.html.markdown +++ b/website/docs/r/cdn_endpoint.html.markdown @@ -10,6 +10,8 @@ description: |- A CDN Endpoint is the entity within a CDN Profile containing configuration information regarding caching behaviours and origins. The CDN Endpoint is exposed using the URL format .azureedge.net. +!> **Be Aware:** Azure is rolling out a breaking change on Friday 9th April which may cause issues with the CDN/FrontDoor resources. [More information is available in this Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) - however unfortunately this may necessitate a breaking change to the CDN and FrontDoor resources, more information will be posted [in the Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) as the necessary changes are identified. + ## Example Usage ```hcl diff --git a/website/docs/r/cdn_profile.html.markdown b/website/docs/r/cdn_profile.html.markdown index 4c855e8b8264..cb31704e81c5 100644 --- a/website/docs/r/cdn_profile.html.markdown +++ b/website/docs/r/cdn_profile.html.markdown @@ -10,6 +10,8 @@ description: |- Manages a CDN Profile to create a collection of CDN Endpoints. +!> **Be Aware:** Azure is rolling out a breaking change on Friday 9th April which may cause issues with the CDN/FrontDoor resources. [More information is available in this Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) - however unfortunately this may necessitate a breaking change to the CDN and FrontDoor resources, more information will be posted [in the Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) as the necessary changes are identified. + ## Example Usage ```hcl diff --git a/website/docs/r/frontdoor.html.markdown b/website/docs/r/frontdoor.html.markdown index 42c2de79eee5..ac3b64af4934 100644 --- a/website/docs/r/frontdoor.html.markdown +++ b/website/docs/r/frontdoor.html.markdown @@ -17,6 +17,8 @@ Below are some of the key scenarios that Azure Front Door Service addresses: * Use Front Door to improve application performance with SSL offload and routing requests to the fastest available application backend. * Use Front Door for application layer security and DDoS protection for your application. +!> **Be Aware:** Azure is rolling out a breaking change on Friday 9th April which may cause issues with the CDN/FrontDoor resources. [More information is available in this Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) - however unfortunately this may necessitate a breaking change to the CDN and FrontDoor resources, more information will be posted [in the Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) as the necessary changes are identified. + ## Example Usage ```hcl diff --git a/website/docs/r/frontdoor_custom_https_configuration.html.markdown b/website/docs/r/frontdoor_custom_https_configuration.html.markdown index a8f9fc2ca26a..8e4cee7109ad 100644 --- a/website/docs/r/frontdoor_custom_https_configuration.html.markdown +++ b/website/docs/r/frontdoor_custom_https_configuration.html.markdown @@ -16,6 +16,8 @@ Manages the Custom Https Configuration for an Azure Front Door Frontend Endpoint -> **NOTE:** UPCOMING BREAKING CHANGE: In order to address the ordering issue we have changed the design on how to retrieve existing sub resources such as frontend endpoints. Existing design will be deprecated and will result in an incorrect configuration. Please refer to the updated documentation below for more information. +!> **Be Aware:** Azure is rolling out a breaking change on Friday 9th April which may cause issues with the CDN/FrontDoor resources. [More information is available in this Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) - however unfortunately this may necessitate a breaking change to the CDN and FrontDoor resources, more information will be posted [in the Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) as the necessary changes are identified. + ```hcl resource "azurerm_resource_group" "example" { name = "FrontDoorExampleResourceGroup" diff --git a/website/docs/r/frontdoor_firewall_policy.html.markdown b/website/docs/r/frontdoor_firewall_policy.html.markdown index 66fd38cca165..d00e833912d1 100644 --- a/website/docs/r/frontdoor_firewall_policy.html.markdown +++ b/website/docs/r/frontdoor_firewall_policy.html.markdown @@ -10,6 +10,8 @@ description: |- Manages an Azure Front Door Web Application Firewall Policy instance. +!> **Be Aware:** Azure is rolling out a breaking change on Friday 9th April which may cause issues with the CDN/FrontDoor resources. [More information is available in this Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) - however unfortunately this may necessitate a breaking change to the CDN and FrontDoor resources, more information will be posted [in the Github issue](https://github.com/terraform-providers/terraform-provider-azurerm/issues/11231) as the necessary changes are identified. + ## Example Usage ```hcl From c727172968227d233ada79e2eeb8f72817e21cb3 Mon Sep 17 00:00:00 2001 From: Vladimir Lazarenko Date: Wed, 7 Apr 2021 22:15:01 +0200 Subject: [PATCH 21/40] `azurerm_eventgrid_data_connection`: add support for `table_name`, `mapping_rule_name` and `data_format` (#11157) zurerm_eventgrid_data_connection: add support for table_name, mapping_rule_name and data_format $ make acctests SERVICE='kusto' TESTARGS='-run=TestAccKustoEventGridDataConnection_mappingRule' TESTTIMEOUT='600m' ==> Checking that code complies with gofmt requirements... ==> Checking that Custom Timeouts are used... ==> Checking that acceptance test packages are used... TF_ACC=1 go test -v ./azurerm/internal/services/kusto -run=TestAccKustoEventGridDataConnection_mappingRule -timeout 600m -ldflags="-X=github.com/terraform-providers/terraform-provider-azurerm/version.ProviderVersion=acc" 2021/03/30 16:20:12 [DEBUG] not using binary driver name, it's no longer needed 2021/03/30 16:20:12 [DEBUG] not using binary driver name, it's no longer needed === RUN TestAccKustoEventGridDataConnection_mappingRule === PAUSE TestAccKustoEventGridDataConnection_mappingRule === CONT TestAccKustoEventGridDataConnection_mappingRule --- PASS: TestAccKustoEventGridDataConnection_mappingRule (1647.62s) PASS ok github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/kusto 1648.919s Fixes #10977 --- ...usto_eventgrid_data_connection_resource.go | 45 +++++++++++++++++++ ...eventgrid_data_connection_resource_test.go | 42 ++++++++++++++++- ...to_eventgrid_data_connection.html.markdown | 8 ++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource.go b/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource.go index 9588f79de433..b0a52ea78f74 100644 --- a/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource.go +++ b/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource.go @@ -102,6 +102,36 @@ func resourceKustoEventGridDataConnection() *schema.Resource { Optional: true, Default: false, }, + + "table_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.EntityName, + }, + + "mapping_rule_name": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.EntityName, + }, + + "data_format": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(kusto.AVRO), + string(kusto.CSV), + string(kusto.JSON), + string(kusto.MULTIJSON), + string(kusto.PSV), + string(kusto.RAW), + string(kusto.SCSV), + string(kusto.SINGLEJSON), + string(kusto.SOHSV), + string(kusto.TSV), + string(kusto.TXT), + }, false), + }, }, } } @@ -139,6 +169,18 @@ func resourceKustoEventGridDataConnectionCreateUpdate(d *schema.ResourceData, me }, } + if tableName, ok := d.GetOk("table_name"); ok { + dataConnection.EventGridConnectionProperties.TableName = utils.String(tableName.(string)) + } + + if mappingRuleName, ok := d.GetOk("mapping_rule_name"); ok { + dataConnection.EventGridConnectionProperties.MappingRuleName = utils.String(mappingRuleName.(string)) + } + + if df, ok := d.GetOk("data_format"); ok { + dataConnection.EventGridConnectionProperties.DataFormat = kusto.EventGridDataFormat(df.(string)) + } + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ClusterName, id.DatabaseName, id.Name, dataConnection) if err != nil { return fmt.Errorf("creating %s: %+v", id, err) @@ -185,6 +227,9 @@ func resourceKustoEventGridDataConnectionRead(d *schema.ResourceData, meta inter d.Set("eventhub_consumer_group_name", props.ConsumerGroup) d.Set("skip_first_record", props.IgnoreFirstRecord) d.Set("blob_storage_event_type", props.BlobStorageEventType) + d.Set("table_name", props.TableName) + d.Set("mapping_rule_name", props.MappingRuleName) + d.Set("data_format", props.DataFormat) } } diff --git a/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource_test.go b/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource_test.go index 153eccfe7449..fef0870802d5 100644 --- a/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource_test.go +++ b/azurerm/internal/services/kusto/kusto_eventgrid_data_connection_resource_test.go @@ -62,6 +62,21 @@ func TestAccKustoEventGridDataConnection_complete(t *testing.T) { }) } +func TestAccKustoEventGridDataConnection_mappingRule(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kusto_eventgrid_data_connection", "test") + r := KustoEventGridDataConnectionResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.mappingRule(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccKustoEventGridDataConnection_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_kusto_eventgrid_data_connection", "test") r := KustoEventGridDataConnectionResource{} @@ -168,6 +183,31 @@ resource "azurerm_kusto_eventgrid_data_connection" "test" { `, r.template(data), data.RandomInteger) } +func (r KustoEventGridDataConnectionResource) mappingRule(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_kusto_eventgrid_data_connection" "test" { + name = "acctestkrgdc-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + cluster_name = azurerm_kusto_cluster.test.name + database_name = azurerm_kusto_database.test.name + storage_account_id = azurerm_storage_account.test.id + eventhub_id = azurerm_eventhub.test.id + eventhub_consumer_group_name = azurerm_eventhub_consumer_group.test.name + + blob_storage_event_type = "Microsoft.Storage.BlobRenamed" + skip_first_record = true + + mapping_rule_name = "Json_Mapping" + data_format = "MULTIJSON" + + depends_on = [azurerm_eventgrid_event_subscription.test] +} +`, r.template(data), data.RandomInteger) +} + func (KustoEventGridDataConnectionResource) template(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -175,7 +215,7 @@ provider "azurerm" { } resource "azurerm_resource_group" "test" { - name = "acctestRG-SecurityCenter-%d" + name = "acctestRG-%d" location = "%s" } diff --git a/website/docs/r/kusto_eventgrid_data_connection.html.markdown b/website/docs/r/kusto_eventgrid_data_connection.html.markdown index 6ab2222bbc4b..25a39149293e 100644 --- a/website/docs/r/kusto_eventgrid_data_connection.html.markdown +++ b/website/docs/r/kusto_eventgrid_data_connection.html.markdown @@ -120,8 +120,16 @@ The following arguments are supported: Values are `Microsoft.Storage.BlobCreated` and `Microsoft.Storage.BlobRenamed`. Defaults to `Microsoft.Storage.BlobCreated`. +* `data_format` - (Optional) Specifies the data format of the EventHub messages. Allowed values: `AVRO`, `CSV`, `JSON`, `MULTIJSON`, `PSV`, `RAW`, `SCSV`, `SINGLEJSON`, `SOHSV`, `TSV` and `TXT` + +* `mapping_rule_name` - (Optional) Specifies the mapping rule used for the message ingestion. Mapping rule must exist before resource is created. + +* `table_name` - (Optional) Specifies the target table name used for the message ingestion. Table must exist before resource is created. + * `skip_first_record` - (Optional) is the first record of every file ignored? Defaults to `false`. + + ## Attributes Reference The following attributes are exported: From 2464be05826b680e06d3cda726621e6b23aa7a47 Mon Sep 17 00:00:00 2001 From: kt Date: Wed, 7 Apr 2021 13:16:03 -0700 Subject: [PATCH 22/40] CHANGELOG.md for #11157 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94441245710c..4517200e067e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,10 @@ FEATURES: ENHANCEMENTS: +* `azurerm_eventgrid_data_connection` - support for the `table_name`, `mapping_rule_name`, and `data_format` properties [GH-11157] * `azurerm_hpc_cache_nfs_target` - support for the `access_policy_name` property [GH-11186] * `azurerm_private_endpoint` - allows for an alias to specified [GH-10779] - BUG FIXES: * Data Source: `azurerm_dns_zone` - fixing a bug where the Resource ID wouldn't contain the Resource Group name when looking this up [GH-11221] From c80e5f14d750b70b5417a594686f62d2df6fa54a Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 13:26:11 +0100 Subject: [PATCH 23/40] add client for elastic job agent --- azurerm/internal/services/mssql/client/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/mssql/client/client.go b/azurerm/internal/services/mssql/client/client.go index 8a716738425f..0ee810e4f8d3 100644 --- a/azurerm/internal/services/mssql/client/client.go +++ b/azurerm/internal/services/mssql/client/client.go @@ -11,8 +11,8 @@ type Client struct { BackupLongTermRetentionPoliciesClient *sql.BackupLongTermRetentionPoliciesClient BackupShortTermRetentionPoliciesClient *sql.BackupShortTermRetentionPoliciesClient DatabaseExtendedBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient - DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient + DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient DatabasesClient *sql.DatabasesClient ElasticPoolsClient *sql.ElasticPoolsClient FirewallRulesClient *sql.FirewallRulesClient @@ -91,8 +91,8 @@ func NewClient(o *common.ClientOptions) *Client { DatabaseThreatDetectionPoliciesClient: &databaseThreatDetectionPoliciesClient, DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient, ElasticPoolsClient: &elasticPoolsClient, - FirewallRulesClient: &firewallRulesClient, JobAgentsClient: &jobAgentsClient, + FirewallRulesClient: &firewallRulesClient, RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient, ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, ServersClient: &serversClient, From 2d98381f2e5f5023c833c040d90ea10eb2635656 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 8 Apr 2021 08:03:13 +0200 Subject: [PATCH 24/40] fix formatting errors --- .../mssql/mssql_job_agent_resource_test.go | 18 +++++++++--------- ...roup_subscription_association.html.markdown | 2 +- website/docs/r/mssql_job_agent.html.markdown | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go index 27f1fd9a7d18..802b131625b3 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -107,10 +107,10 @@ resource "azurerm_mssql_server" "test" { } resource "azurerm_mssql_database" "test" { - name = "acctestmssqldb%[1]d" - server_id = azurerm_mssql_server.test.id - collation = "SQL_Latin1_General_CP1_CI_AS" - sku_name = "S1" + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" } resource "azurerm_mssql_job_agent" "test" { @@ -156,10 +156,10 @@ resource "azurerm_mssql_server" "test" { } resource "azurerm_mssql_database" "test" { - name = "acctestmssqldb%[1]d" - server_id = azurerm_mssql_server.test.id - collation = "SQL_Latin1_General_CP1_CI_AS" - sku_name = "S1" + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" } resource "azurerm_mssql_job_agent" "test" { @@ -169,7 +169,7 @@ resource "azurerm_mssql_job_agent" "test" { database_id = azurerm_mssql_database.test.id tags = { - ENV = "production" + ENV = "production" } } `, data.RandomInteger, data.Locations.Primary) diff --git a/website/docs/r/management_group_subscription_association.html.markdown b/website/docs/r/management_group_subscription_association.html.markdown index 8ed1707c985b..508d4964fd2c 100644 --- a/website/docs/r/management_group_subscription_association.html.markdown +++ b/website/docs/r/management_group_subscription_association.html.markdown @@ -57,4 +57,4 @@ Managements can be imported using the `resource id`, e.g. ```shell terraform import azurerm_management_group_subscription_association.example /managementGroup/MyManagementGroup/subscription/12345678-1234-1234-1234-123456789012 -``` \ No newline at end of file +``` diff --git a/website/docs/r/mssql_job_agent.html.markdown b/website/docs/r/mssql_job_agent.html.markdown index 314ffb947cf9..9c9ffc5dbe48 100644 --- a/website/docs/r/mssql_job_agent.html.markdown +++ b/website/docs/r/mssql_job_agent.html.markdown @@ -28,10 +28,10 @@ resource "azurerm_mssql_server" "example" { } resource "azurerm_mssql_database" "example" { - name = "example-db" - server_id = azurerm_mssql_server.example.id - collation = "SQL_Latin1_General_CP1_CI_AS" - sku_name = "S1" + name = "example-db" + server_id = azurerm_mssql_server.example.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" } resource "azurerm_mssql_job_agent" "example" { From aeade7c07fc1e93501f53c013d1cf06ebd7ebf34 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 8 Apr 2021 09:55:24 +0200 Subject: [PATCH 25/40] fix incorrect usage of % in string --- azurerm/internal/services/mssql/validate/mssql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/mssql/validate/mssql.go b/azurerm/internal/services/mssql/validate/mssql.go index e1fcfd6f486c..8624d2985eb8 100644 --- a/azurerm/internal/services/mssql/validate/mssql.go +++ b/azurerm/internal/services/mssql/validate/mssql.go @@ -53,7 +53,7 @@ func ValidateLongTermRetentionPoliciesIsoFormat(i interface{}, k string) (_ []st // Job Agent name must not contain any of ?<>*%&:\/? and must not end with a space or . func ValidateMsSqlJobAgentName(i interface{}, k string) (_ []string, errors []error) { if m, regexErrs := validate.RegExHelper(i, k, `^[^?<>*%&:\/?]{0,127}[^?<>*%&:\/?. ]$`); !m { - return nil, append(regexErrs, fmt.Errorf("%q must not contain any of ?<>*%&:\\/?, must not end with a space or a period and can't have more than 128 characters.", k)) + return nil, append(regexErrs, fmt.Errorf("%q must not contain any of ?<>*%%&:\\/?, must not end with a space or a period and can't have more than 128 characters", k)) } return nil, nil From 534e5455b62880295bc78fefaec5c8d8707606b7 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 13:26:11 +0100 Subject: [PATCH 26/40] add client for elastic job agent --- azurerm/internal/services/mssql/client/client.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azurerm/internal/services/mssql/client/client.go b/azurerm/internal/services/mssql/client/client.go index 17ad92dadd52..8a716738425f 100644 --- a/azurerm/internal/services/mssql/client/client.go +++ b/azurerm/internal/services/mssql/client/client.go @@ -16,6 +16,7 @@ type Client struct { DatabasesClient *sql.DatabasesClient ElasticPoolsClient *sql.ElasticPoolsClient FirewallRulesClient *sql.FirewallRulesClient + JobAgentsClient *sql.JobAgentsClient RestorableDroppedDatabasesClient *sql.RestorableDroppedDatabasesClient ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient ServerConnectionPoliciesClient *sql.ServerConnectionPoliciesClient @@ -49,6 +50,9 @@ func NewClient(o *common.ClientOptions) *Client { elasticPoolsClient := sql.NewElasticPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&elasticPoolsClient.Client, o.ResourceManagerAuthorizer) + jobAgentsClient := sql.NewJobAgentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&jobAgentsClient.Client, o.ResourceManagerAuthorizer) + firewallRulesClient := sql.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&firewallRulesClient.Client, o.ResourceManagerAuthorizer) @@ -88,6 +92,7 @@ func NewClient(o *common.ClientOptions) *Client { DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient, ElasticPoolsClient: &elasticPoolsClient, FirewallRulesClient: &firewallRulesClient, + JobAgentsClient: &jobAgentsClient, RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient, ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, ServersClient: &serversClient, From 94211a5224f087b7e5610c1fff7e4db1ff155885 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 14:06:04 +0100 Subject: [PATCH 27/40] add parse and validate files for job agent --- .../services/mssql/parse/job_agent.go | 75 ++++++++++ .../services/mssql/parse/job_agent_test.go | 128 ++++++++++++++++++ .../internal/services/mssql/resourceids.go | 1 + .../services/mssql/validate/job_agent_id.go | 23 ++++ .../mssql/validate/job_agent_id_test.go | 88 ++++++++++++ 5 files changed, 315 insertions(+) create mode 100644 azurerm/internal/services/mssql/parse/job_agent.go create mode 100644 azurerm/internal/services/mssql/parse/job_agent_test.go create mode 100644 azurerm/internal/services/mssql/validate/job_agent_id.go create mode 100644 azurerm/internal/services/mssql/validate/job_agent_id_test.go diff --git a/azurerm/internal/services/mssql/parse/job_agent.go b/azurerm/internal/services/mssql/parse/job_agent.go new file mode 100644 index 000000000000..54624e319f17 --- /dev/null +++ b/azurerm/internal/services/mssql/parse/job_agent.go @@ -0,0 +1,75 @@ +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 JobAgentId struct { + SubscriptionId string + ResourceGroup string + ServerName string + Name string +} + +func NewJobAgentID(subscriptionId, resourceGroup, serverName, name string) JobAgentId { + return JobAgentId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + ServerName: serverName, + Name: name, + } +} + +func (id JobAgentId) String() string { + segments := []string{ + fmt.Sprintf("Name %q", id.Name), + fmt.Sprintf("Server Name %q", id.ServerName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Job Agent", segmentsStr) +} + +func (id JobAgentId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Sql/servers/%s/jobAgents/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.ServerName, id.Name) +} + +// JobAgentID parses a JobAgent ID into an JobAgentId struct +func JobAgentID(input string) (*JobAgentId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := JobAgentId{ + 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.ServerName, err = id.PopSegment("servers"); err != nil { + return nil, err + } + if resourceId.Name, err = id.PopSegment("jobAgents"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/mssql/parse/job_agent_test.go b/azurerm/internal/services/mssql/parse/job_agent_test.go new file mode 100644 index 000000000000..5ecb815120dc --- /dev/null +++ b/azurerm/internal/services/mssql/parse/job_agent_test.go @@ -0,0 +1,128 @@ +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 = JobAgentId{} + +func TestJobAgentIDFormatter(t *testing.T) { + actual := NewJobAgentID("12345678-1234-9876-4563-123456789012", "group1", "server1", "jobagent1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestJobAgentID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *JobAgentId + }{ + + { + // 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 ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/", + Error: true, + }, + + { + // missing value for ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/", + Error: true, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/", + Error: true, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1", + Expected: &JobAgentId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "group1", + ServerName: "server1", + Name: "jobagent1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.SQL/SERVERS/SERVER1/JOBAGENTS/JOBAGENT1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := JobAgentID(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.ServerName != v.Expected.ServerName { + t.Fatalf("Expected %q but got %q for ServerName", v.Expected.ServerName, actual.ServerName) + } + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + } +} diff --git a/azurerm/internal/services/mssql/resourceids.go b/azurerm/internal/services/mssql/resourceids.go index f613a45512a2..7664cca9be63 100644 --- a/azurerm/internal/services/mssql/resourceids.go +++ b/azurerm/internal/services/mssql/resourceids.go @@ -4,6 +4,7 @@ package mssql //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatabaseExtendedAuditingPolicy -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/databases/database1/extendedAuditingSettings/default //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=DatabaseVulnerabilityAssessmentRuleBaseline -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/databases/database1/vulnerabilityAssessments/default/rules/rule1/baselines/baseline1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ElasticPool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/elasticPools/pool1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=JobAgent -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=FirewallRule -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/firewallRules/rule1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=RecoverableDatabase -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/recoverabledatabases/database1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Server -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1 diff --git a/azurerm/internal/services/mssql/validate/job_agent_id.go b/azurerm/internal/services/mssql/validate/job_agent_id.go new file mode 100644 index 000000000000..5b69f42b0d30 --- /dev/null +++ b/azurerm/internal/services/mssql/validate/job_agent_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" +) + +func JobAgentID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.JobAgentID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/mssql/validate/job_agent_id_test.go b/azurerm/internal/services/mssql/validate/job_agent_id_test.go new file mode 100644 index 000000000000..6df6862cea3b --- /dev/null +++ b/azurerm/internal/services/mssql/validate/job_agent_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestJobAgentID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/", + Valid: false, + }, + + { + // missing value for ServerName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/", + Valid: false, + }, + + { + // missing Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/", + Valid: false, + }, + + { + // missing value for Name + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/group1/providers/Microsoft.Sql/servers/server1/jobAgents/jobagent1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/GROUP1/PROVIDERS/MICROSOFT.SQL/SERVERS/SERVER1/JOBAGENTS/JOBAGENT1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := JobAgentID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From 8ba1408e010f9fbcbdd25365f850b9b6c47786c3 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 11 Mar 2021 08:00:06 +0100 Subject: [PATCH 28/40] register mssql_job_agent add basic mssql_job_agent --- .../services/mssql/mssql_job_agent.go | 117 ++++++++++++++++++ .../internal/services/mssql/registration.go | 1 + 2 files changed, 118 insertions(+) create mode 100644 azurerm/internal/services/mssql/mssql_job_agent.go diff --git a/azurerm/internal/services/mssql/mssql_job_agent.go b/azurerm/internal/services/mssql/mssql_job_agent.go new file mode 100644 index 000000000000..b2f6812997e6 --- /dev/null +++ b/azurerm/internal/services/mssql/mssql_job_agent.go @@ -0,0 +1,117 @@ +package mssql + +import ( + "fmt" + "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "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/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" + "log" + "time" +) + +func resourceMsSqlJobAgent() *schema.Resource { + return &schema.Resource{ + Create: resourceMsSqlJobAgentCreateUpdate, + Read: resourceMsSqlJobAgentRead, + Update: resourceMsSqlJobAgentCreateUpdate, + Delete: resourceMsSqlJobAgentDelete, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.JobAgentID(id) + return err + }), + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + // ValidateFunc: azure.ValidateMsSqlServerName, + }, + + "database_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.DatabaseID, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "location": azure.SchemaLocation(), + + "tags": tags.Schema(), + }, + } +} + +func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).MSSQL.JobAgentsClient + //databaseClient := meta.(*clients.Client).MSSQL.ServersClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Job Agent creation.") + + name := d.Get("name").(string) + resGroup := d.Get("resource_group_name").(string) + location := azure.NormalizeLocation(d.Get("location").(string)) + databaseId := d.Get("database_id").(string) + dbId, _ := parse.DatabaseID(databaseId) + + if d.IsNewResource() { + existing, err := client.Get(ctx, resGroup, dbId.ServerName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Failed to check for presence of existing Job Agent %q (MsSql Server %q / Resource Group %q): %s", name, dbId.ServerName, resGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_mssql_job_agent", *existing.ID) + } + } + + params := sql.JobAgent{ + Name: &name, + Location: utils.String(location), + JobAgentProperties: &sql.JobAgentProperties{ + DatabaseID: &databaseId, + }, + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + } + + future, err := client.CreateOrUpdate(ctx, resGroup, dbId.Name, name, params) + if err != nil { + return fmt.Errorf("creating MsSql Database %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation of Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) + } + + return nil +} + +func resourceMsSqlJobAgentRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceMsSqlJobAgentDelete(d *schema.ResourceData, meta interface{}) error { + return nil +} diff --git a/azurerm/internal/services/mssql/registration.go b/azurerm/internal/services/mssql/registration.go index 42dd58661974..173590cf7203 100644 --- a/azurerm/internal/services/mssql/registration.go +++ b/azurerm/internal/services/mssql/registration.go @@ -34,6 +34,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_mssql_database_extended_auditing_policy": resourceMsSqlDatabaseExtendedAuditingPolicy(), "azurerm_mssql_database_vulnerability_assessment_rule_baseline": resourceMsSqlDatabaseVulnerabilityAssessmentRuleBaseline(), "azurerm_mssql_elasticpool": resourceMsSqlElasticPool(), + "azurerm_mssql_job_agent": resourceMsSqlJobAgent(), "azurerm_mssql_firewall_rule": resourceMsSqlFirewallRule(), "azurerm_mssql_server": resourceMsSqlServer(), "azurerm_mssql_server_extended_auditing_policy": resourceMsSqlServerExtendedAuditingPolicy(), From 54f398ded647b4667fb47a83f71631b4520f40b4 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 12:03:51 +0200 Subject: [PATCH 29/40] add function to validate job agent name --- azurerm/internal/services/mssql/validate/mssql.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/azurerm/internal/services/mssql/validate/mssql.go b/azurerm/internal/services/mssql/validate/mssql.go index f18c23b84e07..e1fcfd6f486c 100644 --- a/azurerm/internal/services/mssql/validate/mssql.go +++ b/azurerm/internal/services/mssql/validate/mssql.go @@ -49,3 +49,12 @@ func ValidateLongTermRetentionPoliciesIsoFormat(i interface{}, k string) (_ []st } return nil, nil } + +// Job Agent name must not contain any of ?<>*%&:\/? and must not end with a space or . +func ValidateMsSqlJobAgentName(i interface{}, k string) (_ []string, errors []error) { + if m, regexErrs := validate.RegExHelper(i, k, `^[^?<>*%&:\/?]{0,127}[^?<>*%&:\/?. ]$`); !m { + return nil, append(regexErrs, fmt.Errorf("%q must not contain any of ?<>*%&:\\/?, must not end with a space or a period and can't have more than 128 characters.", k)) + } + + return nil, nil +} From 233623e5b826a319df411f90e5a62d6e91928214 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 14:00:58 +0200 Subject: [PATCH 30/40] implement read, create&update and delete methods --- ...b_agent.go => mssql_job_agent_resource.go} | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) rename azurerm/internal/services/mssql/{mssql_job_agent.go => mssql_job_agent_resource.go} (65%) diff --git a/azurerm/internal/services/mssql/mssql_job_agent.go b/azurerm/internal/services/mssql/mssql_job_agent_resource.go similarity index 65% rename from azurerm/internal/services/mssql/mssql_job_agent.go rename to azurerm/internal/services/mssql/mssql_job_agent_resource.go index b2f6812997e6..78672c5e7190 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource.go @@ -2,6 +2,9 @@ package mssql import ( "fmt" + "log" + "time" + "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v3.0/sql" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" @@ -13,8 +16,6 @@ import ( azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" - "log" - "time" ) func resourceMsSqlJobAgent() *schema.Resource { @@ -38,10 +39,10 @@ func resourceMsSqlJobAgent() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - // ValidateFunc: azure.ValidateMsSqlServerName, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ValidateMsSqlJobAgentName, }, "database_id": { @@ -62,7 +63,6 @@ func resourceMsSqlJobAgent() *schema.Resource { func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.JobAgentsClient - //databaseClient := meta.(*clients.Client).MSSQL.ServersClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -96,22 +96,69 @@ func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.CreateOrUpdate(ctx, resGroup, dbId.Name, name, params) + future, err := client.CreateOrUpdate(ctx, resGroup, dbId.ServerName, name, params) if err != nil { - return fmt.Errorf("creating MsSql Database %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) + return fmt.Errorf("creating MsSql Job Agent %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { return fmt.Errorf("waiting for creation of Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) } - return nil + resp, err := client.Get(ctx, dbId.ResourceGroup, dbId.ServerName, name) + if err != nil { + return fmt.Errorf("reading request for Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) + } + + d.SetId(*resp.ID) + + return resourceMsSqlJobAgentRead(d, meta) } func resourceMsSqlJobAgentRead(d *schema.ResourceData, meta interface{}) error { - return nil + client := meta.(*clients.Client).MSSQL.JobAgentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.JobAgentID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("reading MsSql Job Agent %s (MsSql Server Name %q / Resource Group %q): %s", id.Name, id.ServerName, id.ResourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", id.ResourceGroup) + if location := resp.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + d.Set("database_id", resp.DatabaseID) + + return tags.FlattenAndSet(d, resp.Tags) } func resourceMsSqlJobAgentDelete(d *schema.ResourceData, meta interface{}) error { - return nil + client := meta.(*clients.Client).MSSQL.JobAgentsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.JobAgentID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) + if err != nil { + return fmt.Errorf("deleting Job Agent %s: %+v", id.Name, err) + } + + return future.WaitForCompletionRef(ctx, client.Client) } From 74102aa110b23f68623c54563ecc6ca086dba76c Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 14:01:10 +0200 Subject: [PATCH 31/40] add basic test --- .../mssql/mssql_job_agent_resource_test.go | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 azurerm/internal/services/mssql/mssql_job_agent_resource_test.go diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go new file mode 100644 index 000000000000..3ccd8307ba0c --- /dev/null +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -0,0 +1,86 @@ +package mssql_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/mssql/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type MsSqlJobAgentResource struct{} + +func TestAccMsSqlJobAgent_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_job_agent", "test") + r := MsSqlJobAgentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (MsSqlJobAgentResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.JobAgentID(state.ID) + if err != nil { + return nil, err + } + + resp, err := client.MSSQL.JobAgentsClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil, fmt.Errorf("Job Agent %q (Resource Group %q) does not exist", id.Name, id.ResourceGroup) + } + return nil, fmt.Errorf("reading Job Agent %q (Resource Group %q): %v", id.Name, id.ResourceGroup, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (MsSqlJobAgentResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-jobagent-%[1]d" + location = "%[2]s" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestmssqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "4dministr4t0r" + administrator_login_password = "superSecur3!!!" +} + +resource "azurerm_mssql_database" "test" { + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" +} + +resource "azurerm_mssql_job_agent" "test" { + name = "acctestmssqljobagent%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id +} +`, data.RandomInteger, data.Locations.Primary) +} From e33b5c83ff043ed36efdb3c5a9142d07a8299360 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 13:26:11 +0100 Subject: [PATCH 32/40] add client for elastic job agent --- azurerm/internal/services/mssql/client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/mssql/client/client.go b/azurerm/internal/services/mssql/client/client.go index 8a716738425f..0e0bf6cf5d74 100644 --- a/azurerm/internal/services/mssql/client/client.go +++ b/azurerm/internal/services/mssql/client/client.go @@ -11,8 +11,8 @@ type Client struct { BackupLongTermRetentionPoliciesClient *sql.BackupLongTermRetentionPoliciesClient BackupShortTermRetentionPoliciesClient *sql.BackupShortTermRetentionPoliciesClient DatabaseExtendedBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient - DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient + DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient DatabasesClient *sql.DatabasesClient ElasticPoolsClient *sql.ElasticPoolsClient FirewallRulesClient *sql.FirewallRulesClient From d74b9e7a24919b1850d42eb03348c3532c5ee044 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 7 Apr 2021 15:25:21 +0200 Subject: [PATCH 33/40] add update and requires import test --- .../mssql/mssql_job_agent_resource_test.go | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go index 3ccd8307ba0c..27f1fd9a7d18 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -32,6 +32,43 @@ func TestAccMsSqlJobAgent_basic(t *testing.T) { }) } +func TestAccMsSqlJobAgent_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_job_agent", "test") + r := MsSqlJobAgentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccMsSqlJobAgent_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_job_agent", "test") + r := MsSqlJobAgentResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (MsSqlJobAgentResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.JobAgentID(state.ID) if err != nil { @@ -84,3 +121,56 @@ resource "azurerm_mssql_job_agent" "test" { } `, data.RandomInteger, data.Locations.Primary) } + +func (r MsSqlJobAgentResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_mssql_job_agent" "import" { + name = azurerm_mssql_job_agent.test.name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id +} +`, r.basic(data)) +} + +func (MsSqlJobAgentResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-jobagent-%[1]d" + location = "%[2]s" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestmssqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "4dministr4t0r" + administrator_login_password = "superSecur3!!!" +} + +resource "azurerm_mssql_database" "test" { + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" +} + +resource "azurerm_mssql_job_agent" "test" { + name = "acctestmssqljobagent%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id + + tags = { + ENV = "production" + } +} +`, data.RandomInteger, data.Locations.Primary) +} From 9b86a6f21503aee2b1d82697c80ff0990971f0ed Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 8 Apr 2021 07:32:29 +0200 Subject: [PATCH 34/40] add documentation --- website/docs/r/mssql_job_agent.html.markdown | 82 ++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 website/docs/r/mssql_job_agent.html.markdown diff --git a/website/docs/r/mssql_job_agent.html.markdown b/website/docs/r/mssql_job_agent.html.markdown new file mode 100644 index 000000000000..314ffb947cf9 --- /dev/null +++ b/website/docs/r/mssql_job_agent.html.markdown @@ -0,0 +1,82 @@ +--- +subcategory: "Database" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_mssql_job_agent" +description: |- + Manages an Elastic Job Agent. +--- + +# azurerm_mssql_job_agent + +Manages an Elastic Job Agent. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example" + location = "northeurope" +} + +resource "azurerm_mssql_server" "example" { + name = "example-server" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + version = "12.0" + administrator_login = "4dm1n157r470r" + administrator_login_password = "4-v3ry-53cr37-p455w0rd" +} + +resource "azurerm_mssql_database" "example" { + name = "example-db" + server_id = azurerm_mssql_server.example.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" +} + +resource "azurerm_mssql_job_agent" "example" { + name = "example-job-agent" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + database_id = azurerm_mssql_database.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Elastic Job Agent. Changing this forces a new Elastic Job Agent to be created. + +* `location` - (Required) The Azure Region where the Elastic Job Agent should exist. Changing this forces a new Elastic Job Agent to be created. + +* `resource_group_name` - (Required) The name of the Resource Group where the Elastic Job Agent should exist. Changing this forces a new Elastic Job Agent to be created. + +* `database_id` - (Required) The ID of the database to store metadata for the Elastic Job Agent. Changing this forces a new Elastic Job Agent to be created. + +--- + +* `tags` - (Optional) A mapping of tags which should be assigned to the Database. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Elastic Job Agent. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 1 hour) Used when creating the Database. +* `read` - (Defaults to 5 minutes) Used when retrieving the Database. +* `update` - (Defaults to 1 hour) Used when updating the Database. +* `delete` - (Defaults to 1 hour) Used when deleting the Database. + +## Import + +Elastic Job Agents can be imported using the `id`, e.g. + +```shell +terraform import azurerm_mssql_job_agent.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Sql/servers/myserver1/jobAgents/myjobagent1 +``` From a8e85ce719028cc5549b6ab4a2344619120ccba3 Mon Sep 17 00:00:00 2001 From: rob Date: Wed, 6 Jan 2021 13:26:11 +0100 Subject: [PATCH 35/40] add client for elastic job agent --- azurerm/internal/services/mssql/client/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/mssql/client/client.go b/azurerm/internal/services/mssql/client/client.go index 0e0bf6cf5d74..0ee810e4f8d3 100644 --- a/azurerm/internal/services/mssql/client/client.go +++ b/azurerm/internal/services/mssql/client/client.go @@ -91,8 +91,8 @@ func NewClient(o *common.ClientOptions) *Client { DatabaseThreatDetectionPoliciesClient: &databaseThreatDetectionPoliciesClient, DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient, ElasticPoolsClient: &elasticPoolsClient, - FirewallRulesClient: &firewallRulesClient, JobAgentsClient: &jobAgentsClient, + FirewallRulesClient: &firewallRulesClient, RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient, ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, ServersClient: &serversClient, From b495bf128dce154b07af8742d1b86fcc4bec33b2 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 8 Apr 2021 08:03:13 +0200 Subject: [PATCH 36/40] fix formatting errors --- .../mssql/mssql_job_agent_resource_test.go | 18 +++++++++--------- ...roup_subscription_association.html.markdown | 2 +- website/docs/r/mssql_job_agent.html.markdown | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go index 27f1fd9a7d18..802b131625b3 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -107,10 +107,10 @@ resource "azurerm_mssql_server" "test" { } resource "azurerm_mssql_database" "test" { - name = "acctestmssqldb%[1]d" - server_id = azurerm_mssql_server.test.id - collation = "SQL_Latin1_General_CP1_CI_AS" - sku_name = "S1" + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" } resource "azurerm_mssql_job_agent" "test" { @@ -156,10 +156,10 @@ resource "azurerm_mssql_server" "test" { } resource "azurerm_mssql_database" "test" { - name = "acctestmssqldb%[1]d" - server_id = azurerm_mssql_server.test.id - collation = "SQL_Latin1_General_CP1_CI_AS" - sku_name = "S1" + name = "acctestmssqldb%[1]d" + server_id = azurerm_mssql_server.test.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" } resource "azurerm_mssql_job_agent" "test" { @@ -169,7 +169,7 @@ resource "azurerm_mssql_job_agent" "test" { database_id = azurerm_mssql_database.test.id tags = { - ENV = "production" + ENV = "production" } } `, data.RandomInteger, data.Locations.Primary) diff --git a/website/docs/r/management_group_subscription_association.html.markdown b/website/docs/r/management_group_subscription_association.html.markdown index 8ed1707c985b..508d4964fd2c 100644 --- a/website/docs/r/management_group_subscription_association.html.markdown +++ b/website/docs/r/management_group_subscription_association.html.markdown @@ -57,4 +57,4 @@ Managements can be imported using the `resource id`, e.g. ```shell terraform import azurerm_management_group_subscription_association.example /managementGroup/MyManagementGroup/subscription/12345678-1234-1234-1234-123456789012 -``` \ No newline at end of file +``` diff --git a/website/docs/r/mssql_job_agent.html.markdown b/website/docs/r/mssql_job_agent.html.markdown index 314ffb947cf9..9c9ffc5dbe48 100644 --- a/website/docs/r/mssql_job_agent.html.markdown +++ b/website/docs/r/mssql_job_agent.html.markdown @@ -28,10 +28,10 @@ resource "azurerm_mssql_server" "example" { } resource "azurerm_mssql_database" "example" { - name = "example-db" - server_id = azurerm_mssql_server.example.id - collation = "SQL_Latin1_General_CP1_CI_AS" - sku_name = "S1" + name = "example-db" + server_id = azurerm_mssql_server.example.id + collation = "SQL_Latin1_General_CP1_CI_AS" + sku_name = "S1" } resource "azurerm_mssql_job_agent" "example" { From f6d858eda07a5c9bc33f88e6a27b6ae1c9d2badb Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 8 Apr 2021 09:55:24 +0200 Subject: [PATCH 37/40] fix incorrect usage of % in string --- azurerm/internal/services/mssql/validate/mssql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/mssql/validate/mssql.go b/azurerm/internal/services/mssql/validate/mssql.go index e1fcfd6f486c..8624d2985eb8 100644 --- a/azurerm/internal/services/mssql/validate/mssql.go +++ b/azurerm/internal/services/mssql/validate/mssql.go @@ -53,7 +53,7 @@ func ValidateLongTermRetentionPoliciesIsoFormat(i interface{}, k string) (_ []st // Job Agent name must not contain any of ?<>*%&:\/? and must not end with a space or . func ValidateMsSqlJobAgentName(i interface{}, k string) (_ []string, errors []error) { if m, regexErrs := validate.RegExHelper(i, k, `^[^?<>*%&:\/?]{0,127}[^?<>*%&:\/?. ]$`); !m { - return nil, append(regexErrs, fmt.Errorf("%q must not contain any of ?<>*%&:\\/?, must not end with a space or a period and can't have more than 128 characters.", k)) + return nil, append(regexErrs, fmt.Errorf("%q must not contain any of ?<>*%%&:\\/?, must not end with a space or a period and can't have more than 128 characters", k)) } return nil, nil From a06ef2b9d490e1cb81d85ab789523cc479f47fdc Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 15 Apr 2021 10:04:50 +0200 Subject: [PATCH 38/40] remove obsolete resource_group_name property --- .../services/mssql/mssql_job_agent_resource.go | 14 +++++--------- .../mssql/mssql_job_agent_resource_test.go | 3 --- website/docs/r/mssql_job_agent.html.markdown | 3 --- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource.go b/azurerm/internal/services/mssql/mssql_job_agent_resource.go index 78672c5e7190..2a111fe9590f 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource.go @@ -52,8 +52,6 @@ func resourceMsSqlJobAgent() *schema.Resource { ValidateFunc: validate.DatabaseID, }, - "resource_group_name": azure.SchemaResourceGroupName(), - "location": azure.SchemaLocation(), "tags": tags.Schema(), @@ -69,16 +67,15 @@ func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) log.Printf("[INFO] preparing arguments for Job Agent creation.") name := d.Get("name").(string) - resGroup := d.Get("resource_group_name").(string) location := azure.NormalizeLocation(d.Get("location").(string)) databaseId := d.Get("database_id").(string) dbId, _ := parse.DatabaseID(databaseId) if d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, dbId.ServerName, name) + existing, err := client.Get(ctx, dbId.ResourceGroup, dbId.ServerName, name) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Failed to check for presence of existing Job Agent %q (MsSql Server %q / Resource Group %q): %s", name, dbId.ServerName, resGroup, err) + return fmt.Errorf("Failed to check for presence of existing Job Agent %q (MsSql Server %q / Resource Group %q): %s", name, dbId.ServerName, dbId.ResourceGroup, err) } } @@ -96,18 +93,18 @@ func resourceMsSqlJobAgentCreateUpdate(d *schema.ResourceData, meta interface{}) Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } - future, err := client.CreateOrUpdate(ctx, resGroup, dbId.ServerName, name, params) + future, err := client.CreateOrUpdate(ctx, dbId.ResourceGroup, dbId.ServerName, name, params) if err != nil { return fmt.Errorf("creating MsSql Job Agent %q (Sql Server %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) + return fmt.Errorf("waiting for creation of Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) } resp, err := client.Get(ctx, dbId.ResourceGroup, dbId.ServerName, name) if err != nil { - return fmt.Errorf("reading request for Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, resGroup, err) + return fmt.Errorf("reading request for Job Agent %q (MsSql Server Name %q / Resource Group %q): %+v", name, dbId.ServerName, dbId.ResourceGroup, err) } d.SetId(*resp.ID) @@ -135,7 +132,6 @@ func resourceMsSqlJobAgentRead(d *schema.ResourceData, meta interface{}) error { } d.Set("name", resp.Name) - d.Set("resource_group_name", id.ResourceGroup) if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go index 802b131625b3..be0376cb70fa 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -115,7 +115,6 @@ resource "azurerm_mssql_database" "test" { resource "azurerm_mssql_job_agent" "test" { name = "acctestmssqljobagent%[1]d" - resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location database_id = azurerm_mssql_database.test.id } @@ -128,7 +127,6 @@ func (r MsSqlJobAgentResource) requiresImport(data acceptance.TestData) string { resource "azurerm_mssql_job_agent" "import" { name = azurerm_mssql_job_agent.test.name - resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location database_id = azurerm_mssql_database.test.id } @@ -164,7 +162,6 @@ resource "azurerm_mssql_database" "test" { resource "azurerm_mssql_job_agent" "test" { name = "acctestmssqljobagent%[1]d" - resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location database_id = azurerm_mssql_database.test.id diff --git a/website/docs/r/mssql_job_agent.html.markdown b/website/docs/r/mssql_job_agent.html.markdown index 9c9ffc5dbe48..32cc87969745 100644 --- a/website/docs/r/mssql_job_agent.html.markdown +++ b/website/docs/r/mssql_job_agent.html.markdown @@ -36,7 +36,6 @@ resource "azurerm_mssql_database" "example" { resource "azurerm_mssql_job_agent" "example" { name = "example-job-agent" - resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location database_id = azurerm_mssql_database.example.id } @@ -50,8 +49,6 @@ The following arguments are supported: * `location` - (Required) The Azure Region where the Elastic Job Agent should exist. Changing this forces a new Elastic Job Agent to be created. -* `resource_group_name` - (Required) The name of the Resource Group where the Elastic Job Agent should exist. Changing this forces a new Elastic Job Agent to be created. - * `database_id` - (Required) The ID of the database to store metadata for the Elastic Job Agent. Changing this forces a new Elastic Job Agent to be created. --- From 5adf0d92714d1d467fc763c35b754bd5ac9bb277 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 15 Apr 2021 11:33:33 +0200 Subject: [PATCH 39/40] fix formatting --- .../mssql/mssql_job_agent_resource_test.go | 18 +++++++++--------- website/docs/r/mssql_job_agent.html.markdown | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go index be0376cb70fa..980cdc391770 100644 --- a/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go +++ b/azurerm/internal/services/mssql/mssql_job_agent_resource_test.go @@ -114,9 +114,9 @@ resource "azurerm_mssql_database" "test" { } resource "azurerm_mssql_job_agent" "test" { - name = "acctestmssqljobagent%[1]d" - location = azurerm_resource_group.test.location - database_id = azurerm_mssql_database.test.id + name = "acctestmssqljobagent%[1]d" + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id } `, data.RandomInteger, data.Locations.Primary) } @@ -126,9 +126,9 @@ func (r MsSqlJobAgentResource) requiresImport(data acceptance.TestData) string { %s resource "azurerm_mssql_job_agent" "import" { - name = azurerm_mssql_job_agent.test.name - location = azurerm_resource_group.test.location - database_id = azurerm_mssql_database.test.id + name = azurerm_mssql_job_agent.test.name + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id } `, r.basic(data)) } @@ -161,9 +161,9 @@ resource "azurerm_mssql_database" "test" { } resource "azurerm_mssql_job_agent" "test" { - name = "acctestmssqljobagent%[1]d" - location = azurerm_resource_group.test.location - database_id = azurerm_mssql_database.test.id + name = "acctestmssqljobagent%[1]d" + location = azurerm_resource_group.test.location + database_id = azurerm_mssql_database.test.id tags = { ENV = "production" diff --git a/website/docs/r/mssql_job_agent.html.markdown b/website/docs/r/mssql_job_agent.html.markdown index 32cc87969745..40d5246f6151 100644 --- a/website/docs/r/mssql_job_agent.html.markdown +++ b/website/docs/r/mssql_job_agent.html.markdown @@ -35,9 +35,9 @@ resource "azurerm_mssql_database" "example" { } resource "azurerm_mssql_job_agent" "example" { - name = "example-job-agent" - location = azurerm_resource_group.example.location - database_id = azurerm_mssql_database.example.id + name = "example-job-agent" + location = azurerm_resource_group.example.location + database_id = azurerm_mssql_database.example.id } ``` From b9535542e1a4703e035cbaacc32524f7de70919e Mon Sep 17 00:00:00 2001 From: rob Date: Fri, 16 Apr 2021 07:41:24 +0200 Subject: [PATCH 40/40] fix vendor dependencies --- .../monitor/mgmt/2020-10-01/insights/CHANGELOG.md | 2 +- .../mgmt/2020-10-01/insights/activitylogalerts.go | 15 +++++++++++++-- .../monitor/mgmt/2020-10-01/insights/client.go | 15 +++++++++++++-- .../monitor/mgmt/2020-10-01/insights/models.go | 15 +++++++++++++-- .../monitor/mgmt/2020-10-01/insights/version.go | 15 +++++++++++++-- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/CHANGELOG.md index d84071f310fd..236162157ab8 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/CHANGELOG.md +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/CHANGELOG.md @@ -1,5 +1,5 @@ Generated from https://github.com/Azure/azure-rest-api-specs/tree/8240593bde5350e6762015523ccd57cb61e32da5/specification/monitor/resource-manager/readme.md tag: `package-2020-10` -Code generator @microsoft.azure/autorest.go@2.1.178 +Code generator @microsoft.azure/autorest.go@2.1.175 diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/activitylogalerts.go b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/activitylogalerts.go index efb62a1d3abf..1a531833aa5e 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/activitylogalerts.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/activitylogalerts.go @@ -1,7 +1,18 @@ package insights -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. // // Code generated by Microsoft (R) AutoRest Code Generator. // Changes may cause incorrect behavior and will be lost if the code is regenerated. diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/client.go b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/client.go index 4226d9cb54f8..1b91772388d4 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/client.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/client.go @@ -3,8 +3,19 @@ // Monitor Management Client package insights -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. // // Code generated by Microsoft (R) AutoRest Code Generator. // Changes may cause incorrect behavior and will be lost if the code is regenerated. diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/models.go b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/models.go index ccd567218fd5..1ffaa3132ebd 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/models.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/models.go @@ -1,7 +1,18 @@ package insights -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. // // Code generated by Microsoft (R) AutoRest Code Generator. // Changes may cause incorrect behavior and will be lost if the code is regenerated. diff --git a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/version.go b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/version.go index d58311ed5cc5..a6c4b7c8e4cd 100644 --- a/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/version.go +++ b/vendor/github.com/Azure/azure-sdk-for-go/services/monitor/mgmt/2020-10-01/insights/version.go @@ -2,8 +2,19 @@ package insights import "github.com/Azure/azure-sdk-for-go/version" -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. +// Copyright (c) Microsoft and contributors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// +// See the License for the specific language governing permissions and +// limitations under the License. // // Code generated by Microsoft (R) AutoRest Code Generator. // Changes may cause incorrect behavior and will be lost if the code is regenerated.