From 559acdaf8e5dcc17eeb570487e528ff0be25ee34 Mon Sep 17 00:00:00 2001 From: Iain Adams Date: Wed, 22 Feb 2023 17:09:48 +0000 Subject: [PATCH 1/3] fixed #1031 adds provision on demand --- ...synchronization_job_provision_on_demand.md | 109 ++++++++++++++ .../services/synchronization/registration.go | 5 +- .../synchronization/synchronization.go | 35 +++++ ...zation_job_provision_on_demand_resource.go | 141 ++++++++++++++++++ ...n_job_provision_on_demand_resource_test.go | 87 +++++++++++ 5 files changed, 375 insertions(+), 2 deletions(-) create mode 100644 docs/resources/synchronization_job_provision_on_demand.md create mode 100644 internal/services/synchronization/synchronization_job_provision_on_demand_resource.go create mode 100644 internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go diff --git a/docs/resources/synchronization_job_provision_on_demand.md b/docs/resources/synchronization_job_provision_on_demand.md new file mode 100644 index 0000000000..9b509b3c79 --- /dev/null +++ b/docs/resources/synchronization_job_provision_on_demand.md @@ -0,0 +1,109 @@ +--- +subcategory: "Synchronization" +--- + +# Resource: azuread_synchronization_job_provision_on_demand + +Manages synchronization job on demand provisioning associated with a service principal (enterprise application) within Azure Active Directory. + +## API Permissions + +The following API permissions are required in order to use this resource. + +When authenticated with a service principal, this resource requires one of the following application roles: `Synchronization.ReadWrite.All` + +## Example Usage + +*Basic example* + +```terraform +data "azuread_client_config" "current" {} + +resource "azuread_group" "example" { + display_name = "example" + owners = [data.azuread_client_config.current.object_id] + security_enabled = true +} + +data "azuread_application_template" "example" { + display_name = "Azure Databricks SCIM Provisioning Connector" +} + +resource "azuread_application" "example" { + display_name = "example" + template_id = data.azuread_application_template.example.template_id + feature_tags { + enterprise = true + gallery = true + } +} + +resource "azuread_service_principal" "example" { + application_id = azuread_application.example.application_id + use_existing = true +} + +resource "azuread_synchronization_secret" "example" { + service_principal_id = azuread_service_principal.example.id + + credential { + key = "BaseAddress" + value = "https://adb-example.azuredatabricks.net/api/2.0/preview/scim" + } + credential { + key = "SecretToken" + value = "some-token" + } +} + +resource "azuread_synchronization_job" "example" { + service_principal_id = azuread_service_principal.example.id + template_id = "dataBricks" + enabled = true +} + +resource "azuread_synchronization_job_provision_on_demand" "example" { + service_principal_id = azuread_service_principal.example.id + synchronization_job_id = azuread_synchronization_job.example.id + parameter { + # see specific synchronization schema for rule id https://learn.microsoft.com/en-us/graph/api/synchronization-synchronizationschema-get?view=graph-rest-beta + rule_id = "" + subject { + object_id = azuread_group.example.object_id + object_type_name = "Group" + } + } +} + +``` + +## Argument Reference + +The following arguments are supported: + + +- `synchronization_job_id` (Required) Identifier of the synchronization template this job is based on. +- `parameter` (Required) One or more `parameter` blocks as documented below. +- `service_principal_id` (Required) The object ID of the service principal for the synchronization job. + +--- + +`parameter` block supports the following: + +* `rule_id` (Required) The identifier of the synchronizationRule to be applied. This rule ID is defined in the schema for a given synchronization job or template. +* `subject` (Required) One or more `subject` blocks as documented below. + +--- + +`subject` block supports the following: + +* `object_id` (String) The identifier of an object to which a synchronizationJob is to be applied. +* `object_type_name` (String) The type of the object to which a synchronizationJob is to be applied. + +## Attributes Reference + +No additional attributes are exported. + +## Import + +This resource does not support importing. diff --git a/internal/services/synchronization/registration.go b/internal/services/synchronization/registration.go index 51eca7e9b4..da1b7c7821 100644 --- a/internal/services/synchronization/registration.go +++ b/internal/services/synchronization/registration.go @@ -35,8 +35,9 @@ func (r Registration) SupportedDataSources() map[string]*pluginsdk.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { return map[string]*pluginsdk.Resource{ - "azuread_synchronization_job": synchronizationJobResource(), - "azuread_synchronization_secret": synchronizationSecretResource(), + "azuread_synchronization_job": synchronizationJobResource(), + "azuread_synchronization_job_provision_on_demand": synchronizationJobProvisionOnDemandResource(), + "azuread_synchronization_secret": synchronizationSecretResource(), } } diff --git a/internal/services/synchronization/synchronization.go b/internal/services/synchronization/synchronization.go index bc9ee184f1..484fd6af07 100644 --- a/internal/services/synchronization/synchronization.go +++ b/internal/services/synchronization/synchronization.go @@ -48,6 +48,41 @@ func expandSynchronizationSecretKeyStringValuePair(in []interface{}) *[]msgraph. return &result } +func expandSynchronizationJobApplicationParameters(in []interface{}) *[]msgraph.SynchronizationJobApplicationParameters { + result := make([]msgraph.SynchronizationJobApplicationParameters, 0) + + for _, raw := range in { + if raw == nil { + continue + } + item := raw.(map[string]interface{}) + + result = append(result, msgraph.SynchronizationJobApplicationParameters{ + Subjects: expandSynchronizationJobSubject(item["subjects"].([]interface{})), + RuleId: pointer.To(item["rule_id"].(string)), + }) + } + + return &result +} + +func expandSynchronizationJobSubject(in []interface{}) *[]msgraph.SynchronizationJobSubject { + result := make([]msgraph.SynchronizationJobSubject, 0) + for _, raw := range in { + if raw == nil { + continue + } + item := raw.(map[string]interface{}) + + result = append(result, msgraph.SynchronizationJobSubject{ + ObjectId: pointer.To(item["object_id"].(string)), + ObjectTypeName: pointer.To(item["object_type_name"].(string)), + }) + } + + return &result +} + func flattenSynchronizationSchedule(in *msgraph.SynchronizationSchedule) []map[string]interface{} { if in == nil { return []map[string]interface{}{} diff --git a/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go b/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go new file mode 100644 index 0000000000..5914c0b74a --- /dev/null +++ b/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go @@ -0,0 +1,141 @@ +package synchronization + +import ( + "context" + "errors" + "net/http" + "time" + + "github.com/hashicorp/go-azure-sdk/sdk/odata" + + "github.com/hashicorp/go-uuid" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azuread/internal/clients" + "github.com/hashicorp/terraform-provider-azuread/internal/tf" + "github.com/hashicorp/terraform-provider-azuread/internal/tf/validation" + "github.com/manicminer/hamilton/msgraph" +) + +func synchronizationJobProvisionOnDemandResource() *schema.Resource { + return &schema.Resource{ + CreateContext: synchronizationProvisionOnDemandResourceCreate, + ReadContext: synchronizationProvisionOnDemandResourceRead, + DeleteContext: synchronizationProvisionOnDemandResourceDelete, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(15 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), + }, + SchemaVersion: 0, + + Schema: map[string]*schema.Schema{ + "service_principal_id": { + Description: "The object ID of the service principal for which this synchronization job should be provisioned", + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateDiagFunc: validation.ValidateDiag(validation.IsUUID), + }, + "synchronization_job_id": { + Description: "The identifier for the synchronization jop.", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "parameter": { + Description: "Represents the objects that will be provisioned and the synchronization rules executed. The resource is primarily used for on-demand provisioning.", + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "The identifier of the synchronizationRule to be applied. This rule ID is defined in the schema for a given synchronization job or template.", + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "subject": { + Description: "The identifiers of one or more objects to which a synchronizationJob is to be applied.", + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "object_id": { + Description: "The identifier of an object to which a synchronization Job is to be applied. Can be one of the following: (1) An onPremisesDistinguishedName for synchronization from Active Directory to Azure AD. (2) The user ID for synchronization from Azure AD to a third-party. (3) The Worker ID of the Workday worker for synchronization from Workday to either Active Directory or Azure AD.", + Type: schema.TypeString, + Required: true, + }, + "object_type_name": { + Description: "The type of the object to which a synchronization Job is to be applied. Can be one of the following: `user` for synchronizing between Active Directory and Azure AD, `User` for synchronizing a user between Azure AD and a third-party application, `Worker` for synchronization a user between Workday and either Active Directory or Azure AD, `Group` for synchronizing a group between Azure AD and a third-party application.", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"Group", "user", "User", "Worker"}, false), + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func synchronizationProvisionOnDemandResourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + client := meta.(*clients.Client).ServicePrincipals.SynchronizationJobClient + spClient := meta.(*clients.Client).ServicePrincipals.ServicePrincipalsClient + objectId := d.Get("service_principal_id").(string) + jobId := d.Get("synchronization_job_id").(string) + + tf.LockByName(servicePrincipalResourceName, objectId) + defer tf.UnlockByName(servicePrincipalResourceName, objectId) + + servicePrincipal, status, err := spClient.Get(ctx, objectId, odata.Query{}) + if err != nil { + if status == http.StatusNotFound { + return tf.ErrorDiagPathF(nil, "service_principal_id", "Service principal with object ID %q was not found", objectId) + } + return tf.ErrorDiagPathF(err, "service_principal_id", "Retrieving service principal with object ID %q", objectId) + } + if servicePrincipal == nil || servicePrincipal.ID() == nil { + return tf.ErrorDiagF(errors.New("nil service principal or service principal with nil ID was returned"), "API error retrieving service principal with object ID %q", objectId) + } + + job, status, err := client.Get(ctx, jobId, objectId) + if err != nil { + if status == http.StatusNotFound { + return tf.ErrorDiagPathF(nil, "job_id", "Job with object ID %q was not found for service principle %q", jobId, objectId) + } + return tf.ErrorDiagPathF(err, "job_id", "Retrieving job with object ID %q for service principle %q", jobId, objectId) + } + if job == nil || job.ID == nil { + return tf.ErrorDiagF(errors.New("nil job or job with nil ID was returned"), "API error retrieving job with object ID %q/%s", objectId, jobId) + } + // Create a new synchronization job + synchronizationProvisionOnDemand := &msgraph.SynchronizationJobProvisionOnDemand{ + Parameters: expandSynchronizationJobApplicationParameters(d.Get("parameter").([]interface{})), + } + + _, err = client.ProvisionOnDemand(ctx, jobId, synchronizationProvisionOnDemand, *servicePrincipal.ID()) + if err != nil { + return tf.ErrorDiagF(err, "Creating synchronization job for service principal ID %q", *servicePrincipal.ID()) + } + + id, _ := uuid.GenerateUUID() + d.SetId(id) + + return synchronizationProvisionOnDemandResourceRead(ctx, d, meta) +} + +func synchronizationProvisionOnDemandResourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} + +func synchronizationProvisionOnDemandResourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + return nil +} diff --git a/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go b/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go new file mode 100644 index 0000000000..91a6d6ea96 --- /dev/null +++ b/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go @@ -0,0 +1,87 @@ +package synchronization_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-azuread/internal/acceptance" + "github.com/hashicorp/terraform-provider-azuread/internal/clients" +) + +type SynchronizationJobProvisionOnDemandResource struct{} + +func TestAccSynchronizationJobProvisionOnDemand_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azuread_synchronization_job_provision_on_demand", "test") + r := SynchronizationJobProvisionOnDemandResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + // The provisioned app isn't actually integrated so this will never work + Config: r.basic(data), + ExpectError: regexp.MustCompile("CredentialsMissing: Please configure provisioning by providing your admin credentials then retry the provision on-demand."), + }, + }) +} + +func (r SynchronizationJobProvisionOnDemandResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + return pointer.To(true), nil +} + +func (SynchronizationJobProvisionOnDemandResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azuread" {} + +data "azuread_client_config" "test" {} + +data "azuread_application_template" "test" { + display_name = "Azure Databricks SCIM Provisioning Connector" +} + +resource "azuread_application" "test" { + display_name = "acctestSynchronizationJob-%[1]d" + owners = [data.azuread_client_config.test.object_id] + template_id = data.azuread_application_template.test.template_id +} + +resource "azuread_service_principal" "test" { + application_id = azuread_application.test.application_id + owners = [data.azuread_client_config.test.object_id] + use_existing = true +} + +resource "azuread_synchronization_job" "test" { + service_principal_id = azuread_service_principal.test.id + template_id = "dataBricks" +} + +resource "azuread_group" "test" { + display_name = "acctestGroup-%[1]d" + security_enabled = true +} +`, data.RandomInteger) +} + +func (r SynchronizationJobProvisionOnDemandResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azuread_synchronization_job_provision_on_demand" "test" { + service_principal_id = azuread_service_principal.test.id + synchronization_job_id = trimprefix(azuread_synchronization_job.test.id, "${azuread_service_principal.test.id}/job/") + parameter { + rule_id = "03f7d90d-bf71-41b1-bda6-aaf0ddbee5d8" //no api to check this so assuming the rule id is the same globally :finger_crossed: + subject { + object_id = azuread_group.test.id + object_type_name = "Group" + } + } +} + + +`, r.template(data)) +} From d5333cb4bb924c4512fec101871fdf1807408b0d Mon Sep 17 00:00:00 2001 From: iwarapter Date: Thu, 9 May 2024 09:16:49 +0100 Subject: [PATCH 2/3] add triggers arguement to allow re-triggering use cases --- docs/resources/synchronization_job_provision_on_demand.md | 1 + .../synchronization_job_provision_on_demand_resource.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/resources/synchronization_job_provision_on_demand.md b/docs/resources/synchronization_job_provision_on_demand.md index 9b509b3c79..b97244b9da 100644 --- a/docs/resources/synchronization_job_provision_on_demand.md +++ b/docs/resources/synchronization_job_provision_on_demand.md @@ -85,6 +85,7 @@ The following arguments are supported: - `synchronization_job_id` (Required) Identifier of the synchronization template this job is based on. - `parameter` (Required) One or more `parameter` blocks as documented below. - `service_principal_id` (Required) The object ID of the service principal for the synchronization job. +- `triggers` (Optional) Map of arbitrary keys and values that, when changed, will trigger a re-invocation. To force a re-invocation without changing these keys/values, use the [`terraform taint` command](https://www.terraform.io/docs/commands/taint.html). --- diff --git a/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go b/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go index 5914c0b74a..98512bad6e 100644 --- a/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go +++ b/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go @@ -82,6 +82,12 @@ func synchronizationJobProvisionOnDemandResource() *schema.Resource { }, }, }, + "triggers": { + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, }, } } From faa7b0479c7daa13fd1af3dd6e730be1be36fed0 Mon Sep 17 00:00:00 2001 From: Tom Bamford Date: Thu, 9 May 2024 10:51:22 +0100 Subject: [PATCH 3/3] linting, tidying --- ...synchronization_job_provision_on_demand.md | 10 ++++----- .../synchronization/synchronization.go | 2 +- ...zation_job_provision_on_demand_resource.go | 22 ++++++++++++------- ...n_job_provision_on_demand_resource_test.go | 15 +++++++------ 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/docs/resources/synchronization_job_provision_on_demand.md b/docs/resources/synchronization_job_provision_on_demand.md index b97244b9da..828bbc1ac0 100644 --- a/docs/resources/synchronization_job_provision_on_demand.md +++ b/docs/resources/synchronization_job_provision_on_demand.md @@ -39,8 +39,8 @@ resource "azuread_application" "example" { } resource "azuread_service_principal" "example" { - application_id = azuread_application.example.application_id - use_existing = true + client_id = azuread_application.example.client_id + use_existing = true } resource "azuread_synchronization_secret" "example" { @@ -91,15 +91,15 @@ The following arguments are supported: `parameter` block supports the following: -* `rule_id` (Required) The identifier of the synchronizationRule to be applied. This rule ID is defined in the schema for a given synchronization job or template. +* `rule_id` (Required) The identifier of the synchronization rule to be applied. This rule ID is defined in the schema for a given synchronization job or template. * `subject` (Required) One or more `subject` blocks as documented below. --- `subject` block supports the following: -* `object_id` (String) The identifier of an object to which a synchronizationJob is to be applied. -* `object_type_name` (String) The type of the object to which a synchronizationJob is to be applied. +* `object_id` (String) The identifier of an object to which a synchronization job is to be applied. Can be one of the following: (1) An onPremisesDistinguishedName for synchronization from Active Directory to Azure AD. (2) The user ID for synchronization from Azure AD to a third-party. (3) The Worker ID of the Workday worker for synchronization from Workday to either Active Directory or Azure AD. +* `object_type_name` (String) The type of the object to which a synchronization job is to be applied. Can be one of the following: `user` for synchronizing between Active Directory and Azure AD, `User` for synchronizing a user between Azure AD and a third-party application, `Worker` for synchronization a user between Workday and either Active Directory or Azure AD, `Group` for synchronizing a group between Azure AD and a third-party application. ## Attributes Reference diff --git a/internal/services/synchronization/synchronization.go b/internal/services/synchronization/synchronization.go index 484fd6af07..a409c3158f 100644 --- a/internal/services/synchronization/synchronization.go +++ b/internal/services/synchronization/synchronization.go @@ -58,7 +58,7 @@ func expandSynchronizationJobApplicationParameters(in []interface{}) *[]msgraph. item := raw.(map[string]interface{}) result = append(result, msgraph.SynchronizationJobApplicationParameters{ - Subjects: expandSynchronizationJobSubject(item["subjects"].([]interface{})), + Subjects: expandSynchronizationJobSubject(item["subject"].([]interface{})), RuleId: pointer.To(item["rule_id"].(string)), }) } diff --git a/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go b/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go index 98512bad6e..a907becee2 100644 --- a/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go +++ b/internal/services/synchronization/synchronization_job_provision_on_demand_resource.go @@ -7,9 +7,7 @@ import ( "time" "github.com/hashicorp/go-azure-sdk/sdk/odata" - "github.com/hashicorp/go-uuid" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azuread/internal/clients" @@ -26,8 +24,8 @@ func synchronizationJobProvisionOnDemandResource() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(15 * time.Minute), - Read: schema.DefaultTimeout(5 * time.Minute), - Delete: schema.DefaultTimeout(5 * time.Minute), + Read: schema.DefaultTimeout(1 * time.Minute), + Delete: schema.DefaultTimeout(1 * time.Minute), }, SchemaVersion: 0, @@ -39,12 +37,14 @@ func synchronizationJobProvisionOnDemandResource() *schema.Resource { ForceNew: true, ValidateDiagFunc: validation.ValidateDiag(validation.IsUUID), }, + "synchronization_job_id": { Description: "The identifier for the synchronization jop.", Type: schema.TypeString, Required: true, ForceNew: true, }, + "parameter": { Description: "Represents the objects that will be provisioned and the synchronization rules executed. The resource is primarily used for on-demand provisioning.", Type: schema.TypeList, @@ -53,11 +53,12 @@ func synchronizationJobProvisionOnDemandResource() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "rule_id": { - Description: "The identifier of the synchronizationRule to be applied. This rule ID is defined in the schema for a given synchronization job or template.", + Description: "The identifier of the synchronization rule to be applied. This rule ID is defined in the schema for a given synchronization job or template.", Type: schema.TypeString, Required: true, ForceNew: true, }, + "subject": { Description: "The identifiers of one or more objects to which a synchronizationJob is to be applied.", Type: schema.TypeList, @@ -66,12 +67,13 @@ func synchronizationJobProvisionOnDemandResource() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "object_id": { - Description: "The identifier of an object to which a synchronization Job is to be applied. Can be one of the following: (1) An onPremisesDistinguishedName for synchronization from Active Directory to Azure AD. (2) The user ID for synchronization from Azure AD to a third-party. (3) The Worker ID of the Workday worker for synchronization from Workday to either Active Directory or Azure AD.", + Description: "The identifier of an object to which a synchronization job is to be applied. Can be one of the following: (1) An onPremisesDistinguishedName for synchronization from Active Directory to Azure AD. (2) The user ID for synchronization from Azure AD to a third-party. (3) The Worker ID of the Workday worker for synchronization from Workday to either Active Directory or Azure AD.", Type: schema.TypeString, Required: true, }, + "object_type_name": { - Description: "The type of the object to which a synchronization Job is to be applied. Can be one of the following: `user` for synchronizing between Active Directory and Azure AD, `User` for synchronizing a user between Azure AD and a third-party application, `Worker` for synchronization a user between Workday and either Active Directory or Azure AD, `Group` for synchronizing a group between Azure AD and a third-party application.", + Description: "The type of the object to which a synchronization job is to be applied. Can be one of the following: `user` for synchronizing between Active Directory and Azure AD, `User` for synchronizing a user between Azure AD and a third-party application, `Worker` for synchronization a user between Workday and either Active Directory or Azure AD, `Group` for synchronizing a group between Azure AD and a third-party application.", Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{"Group", "user", "User", "Worker"}, false), @@ -82,11 +84,14 @@ func synchronizationJobProvisionOnDemandResource() *schema.Resource { }, }, }, + "triggers": { Type: schema.TypeMap, Optional: true, ForceNew: true, - Elem: &schema.Schema{Type: schema.TypeString}, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, }, }, } @@ -122,6 +127,7 @@ func synchronizationProvisionOnDemandResourceCreate(ctx context.Context, d *sche if job == nil || job.ID == nil { return tf.ErrorDiagF(errors.New("nil job or job with nil ID was returned"), "API error retrieving job with object ID %q/%s", objectId, jobId) } + // Create a new synchronization job synchronizationProvisionOnDemand := &msgraph.SynchronizationJobProvisionOnDemand{ Parameters: expandSynchronizationJobApplicationParameters(d.Get("parameter").([]interface{})), diff --git a/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go b/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go index 91a6d6ea96..eafabcf8cc 100644 --- a/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go +++ b/internal/services/synchronization/synchronization_job_provision_on_demand_resource_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/hashicorp/go-azure-helpers/lang/pointer" - "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-azuread/internal/acceptance" "github.com/hashicorp/terraform-provider-azuread/internal/clients" @@ -23,12 +22,12 @@ func TestAccSynchronizationJobProvisionOnDemand_basic(t *testing.T) { { // The provisioned app isn't actually integrated so this will never work Config: r.basic(data), - ExpectError: regexp.MustCompile("CredentialsMissing: Please configure provisioning by providing your admin credentials then retry the provision on-demand."), + ExpectError: regexp.MustCompile("CredentialsMissing: Please configure provisioning"), }, }) } -func (r SynchronizationJobProvisionOnDemandResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { +func (r SynchronizationJobProvisionOnDemandResource) Exists(_ context.Context, _ *clients.Client, _ *terraform.InstanceState) (*bool, error) { return pointer.To(true), nil } @@ -49,9 +48,9 @@ resource "azuread_application" "test" { } resource "azuread_service_principal" "test" { - application_id = azuread_application.test.application_id - owners = [data.azuread_client_config.test.object_id] - use_existing = true + client_id = azuread_application.test.client_id + owners = [data.azuread_client_config.test.object_id] + use_existing = true } resource "azuread_synchronization_job" "test" { @@ -73,8 +72,10 @@ func (r SynchronizationJobProvisionOnDemandResource) basic(data acceptance.TestD resource "azuread_synchronization_job_provision_on_demand" "test" { service_principal_id = azuread_service_principal.test.id synchronization_job_id = trimprefix(azuread_synchronization_job.test.id, "${azuread_service_principal.test.id}/job/") + parameter { - rule_id = "03f7d90d-bf71-41b1-bda6-aaf0ddbee5d8" //no api to check this so assuming the rule id is the same globally :finger_crossed: + rule_id = "03f7d90d-bf71-41b1-bda6-aaf0ddbee5d8" // appears to be a global value + subject { object_id = azuread_group.test.id object_type_name = "Group"