diff --git a/azurerm/internal/services/cosmos/client/client.go b/azurerm/internal/services/cosmos/client/client.go index 72dec52fcf60..d56d2278eed3 100644 --- a/azurerm/internal/services/cosmos/client/client.go +++ b/azurerm/internal/services/cosmos/client/client.go @@ -12,6 +12,7 @@ type Client struct { MongoDbClient *documentdb.MongoDBResourcesClient NotebookWorkspaceClient *documentdb.NotebookWorkspacesClient SqlClient *documentdb.SQLResourcesClient + SqlResourceClient *documentdb.SQLResourcesClient TableClient *documentdb.TableResourcesClient } @@ -34,6 +35,9 @@ func NewClient(o *common.ClientOptions) *Client { sqlClient := documentdb.NewSQLResourcesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&sqlClient.Client, o.ResourceManagerAuthorizer) + sqlResourceClient := documentdb.NewSQLResourcesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&sqlResourceClient.Client, o.ResourceManagerAuthorizer) + tableClient := documentdb.NewTableResourcesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&tableClient.Client, o.ResourceManagerAuthorizer) @@ -44,6 +48,7 @@ func NewClient(o *common.ClientOptions) *Client { MongoDbClient: &mongoDbClient, NotebookWorkspaceClient: ¬ebookWorkspaceClient, SqlClient: &sqlClient, + SqlResourceClient: &sqlResourceClient, TableClient: &tableClient, } } diff --git a/azurerm/internal/services/cosmos/cosmosdb_sql_trigger_resource.go b/azurerm/internal/services/cosmos/cosmosdb_sql_trigger_resource.go new file mode 100644 index 000000000000..eddcf57aa332 --- /dev/null +++ b/azurerm/internal/services/cosmos/cosmosdb_sql_trigger_resource.go @@ -0,0 +1,184 @@ +package cosmos + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2021-01-15/documentdb" + "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" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/cosmos/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/cosmos/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" +) + +func resourceCosmosDbSQLTrigger() *schema.Resource { + return &schema.Resource{ + Create: resourceCosmosDbSQLTriggerCreateUpdate, + Read: resourceCosmosDbSQLTriggerRead, + Update: resourceCosmosDbSQLTriggerCreateUpdate, + Delete: resourceCosmosDbSQLTriggerDelete, + + 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), + }, + + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := parse.SqlTriggerID(id) + return err + }), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.CosmosEntityName, + }, + + "container_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SqlContainerID, + }, + + "body": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + + "operation": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(documentdb.All), + string(documentdb.Create), + string(documentdb.Update), + string(documentdb.Delete), + string(documentdb.Replace), + }, false), + }, + + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(documentdb.Pre), + string(documentdb.Post), + }, false), + }, + }, + } +} +func resourceCosmosDbSQLTriggerCreateUpdate(d *schema.ResourceData, meta interface{}) error { + subscriptionId := meta.(*clients.Client).Account.SubscriptionId + client := meta.(*clients.Client).Cosmos.SqlResourceClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + containerId, _ := parse.SqlContainerID(d.Get("container_id").(string)) + body := d.Get("body").(string) + triggerOperation := d.Get("operation").(string) + triggerType := d.Get("type").(string) + + id := parse.NewSqlTriggerID(subscriptionId, containerId.ResourceGroup, containerId.DatabaseAccountName, containerId.SqlDatabaseName, containerId.ContainerName, name) + + if d.IsNewResource() { + existing, err := client.GetSQLTrigger(ctx, id.ResourceGroup, id.DatabaseAccountName, id.SqlDatabaseName, id.ContainerName, id.TriggerName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing CosmosDb SQLTrigger %q: %+v", id, err) + } + } + if !utils.ResponseWasNotFound(existing.Response) { + return tf.ImportAsExistsError("azurerm_cosmosdb_sql_trigger", id.ID()) + } + } + + createUpdateSqlTriggerParameters := documentdb.SQLTriggerCreateUpdateParameters{ + SQLTriggerCreateUpdateProperties: &documentdb.SQLTriggerCreateUpdateProperties{ + Resource: &documentdb.SQLTriggerResource{ + ID: &name, + Body: &body, + TriggerType: documentdb.TriggerType(triggerType), + TriggerOperation: documentdb.TriggerOperation(triggerOperation), + }, + Options: &documentdb.CreateUpdateOptions{}, + }, + } + future, err := client.CreateUpdateSQLTrigger(ctx, id.ResourceGroup, id.DatabaseAccountName, id.SqlDatabaseName, id.ContainerName, name, createUpdateSqlTriggerParameters) + if err != nil { + return fmt.Errorf("creating/updating CosmosDb SQLTrigger %q: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation/update of the CosmosDb SQLTrigger %q: %+v", id, err) + } + + d.SetId(id.ID()) + return resourceCosmosDbSQLTriggerRead(d, meta) +} + +func resourceCosmosDbSQLTriggerRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cosmos.SqlResourceClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SqlTriggerID(d.Id()) + if err != nil { + return err + } + + resp, err := client.GetSQLTrigger(ctx, id.ResourceGroup, id.DatabaseAccountName, id.SqlDatabaseName, id.ContainerName, id.TriggerName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[INFO] CosmosDb SQLTrigger %q does not exist - removing from state", d.Id()) + d.SetId("") + return nil + } + return fmt.Errorf("retrieving CosmosDb SQLTrigger %q: %+v", id, err) + } + containerId := parse.NewSqlContainerID(id.SubscriptionId, id.ResourceGroup, id.DatabaseAccountName, id.SqlDatabaseName, id.ContainerName) + d.Set("name", id.TriggerName) + d.Set("container_id", containerId.ID()) + if props := resp.SQLTriggerGetProperties; props != nil { + if props.Resource != nil { + d.Set("body", props.Resource.Body) + d.Set("operation", props.Resource.TriggerOperation) + d.Set("type", props.Resource.TriggerType) + } + } + return nil +} + +func resourceCosmosDbSQLTriggerDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Cosmos.SqlResourceClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SqlTriggerID(d.Id()) + if err != nil { + return err + } + + future, err := client.DeleteSQLTrigger(ctx, id.ResourceGroup, id.DatabaseAccountName, id.SqlDatabaseName, id.ContainerName, id.TriggerName) + if err != nil { + return fmt.Errorf("deleting CosmosDb SQLResourcesSQLTrigger %q: %+v", id, err) + } + + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for deletion of the CosmosDb SQLResourcesSQLTrigger %q: %+v", id, err) + } + return nil +} diff --git a/azurerm/internal/services/cosmos/cosmosdb_sql_trigger_resource_test.go b/azurerm/internal/services/cosmos/cosmosdb_sql_trigger_resource_test.go new file mode 100644 index 000000000000..63978db320f7 --- /dev/null +++ b/azurerm/internal/services/cosmos/cosmosdb_sql_trigger_resource_test.go @@ -0,0 +1,184 @@ +package cosmos_test + +import ( + "context" + "fmt" + "testing" + + "github.com/Azure/azure-sdk-for-go/services/cosmos-db/mgmt/2021-01-15/documentdb" + "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/cosmos/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type CosmosDbSQLTriggerResource struct{} + +func TestAccCosmosDbSQLTrigger_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_sql_trigger", "test") + r := CosmosDbSQLTriggerResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccCosmosDbSQLTrigger_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_sql_trigger", "test") + r := CosmosDbSQLTriggerResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func TestAccCosmosDbSQLTrigger_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_cosmosdb_sql_trigger", "test") + r := CosmosDbSQLTriggerResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.update(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func (r CosmosDbSQLTriggerResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.SqlTriggerID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.Cosmos.SqlResourceClient.GetSQLTrigger(ctx, id.ResourceGroup, id.DatabaseAccountName, id.SqlDatabaseName, id.ContainerName, id.TriggerName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving CosmosDb SQLTrigger %q: %+v", id, err) + } + return utils.Bool(true), nil +} + +func (r CosmosDbSQLTriggerResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-cosmos-%[2]d" + location = "%[1]s" +} + +resource "azurerm_cosmosdb_account" "test" { + name = "acctest-cosmos-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + offer_type = "Standard" + kind = "%[3]s" + + consistency_policy { + consistency_level = "%[4]s" + } + + geo_location { + location = azurerm_resource_group.test.location + failover_priority = 0 + } +} + +resource "azurerm_cosmosdb_sql_database" "test" { + name = "acctest-sql-database-%[2]d" + resource_group_name = azurerm_cosmosdb_account.test.resource_group_name + account_name = azurerm_cosmosdb_account.test.name +} + +resource "azurerm_cosmosdb_sql_container" "test" { + name = "acctest-sql-container-%[2]d" + resource_group_name = azurerm_cosmosdb_account.test.resource_group_name + account_name = azurerm_cosmosdb_account.test.name + database_name = azurerm_cosmosdb_sql_database.test.name + partition_key_path = "/definition/id" +} + `, data.Locations.Primary, data.RandomInteger, string(documentdb.GlobalDocumentDB), string(documentdb.Session)) +} + +func (r CosmosDbSQLTriggerResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cosmosdb_sql_trigger" "test" { + name = "acctest-%d" + container_id = azurerm_cosmosdb_sql_container.test.id + body = "function trigger(){}" + operation = "All" + type = "Pre" +} +`, template, data.RandomInteger) +} + +func (r CosmosDbSQLTriggerResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cosmosdb_sql_trigger" "import" { + name = azurerm_cosmosdb_sql_trigger.test.name + container_id = azurerm_cosmosdb_sql_trigger.test.container_id + body = "function trigger(){}" + operation = "All" + type = "Pre" +} +`, config) +} + +func (r CosmosDbSQLTriggerResource) update(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_cosmosdb_sql_trigger" "test" { + name = "acctest-%d" + container_id = azurerm_cosmosdb_sql_container.test.id + body = <