Skip to content

Commit

Permalink
fixed #1031 adds provision on demand
Browse files Browse the repository at this point in the history
  • Loading branch information
iwarapter committed Feb 22, 2023
1 parent c9de27e commit b0c1284
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 1 deletion.
59 changes: 59 additions & 0 deletions docs/resources/synchronization_job_provision_on_demand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "azuread_synchronization_job_provision_on_demand Resource - terraform-provider-azuread"
subcategory: ""
description: |-
---

# azuread_synchronization_job_provision_on_demand (Resource)





<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `job_id` (String) Identifier of the synchronization template this job is based on.
- `parameters` (Block List, Min: 1) (see [below for nested schema](#nestedblock--parameters))
- `service_principal_id` (String) The object ID of the service principal for which this synchronization job should be created

### Optional

- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))

### Read-Only

- `id` (String) The ID of this resource.

<a id="nestedblock--parameters"></a>
### Nested Schema for `parameters`

Required:

- `rule_id` (String) Whether or not the synchronization job is enabled
- `subjects` (Block List, Min: 1) (see [below for nested schema](#nestedblock--parameters--subjects))

<a id="nestedblock--parameters--subjects"></a>
### Nested Schema for `parameters.subjects`

Required:

- `object_id` (String)
- `object_type_name` (String)



<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Optional:

- `create` (String)
- `delete` (String)
- `read` (String)


3 changes: 3 additions & 0 deletions internal/services/serviceprincipals/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ func NewClient(o *common.ClientOptions) *Client {
synchronizationJobClient := msgraph.NewSynchronizationJobClient(o.TenantID)
o.ConfigureClient(&synchronizationJobClient.BaseClient)

// Synchronization doesn't yet exist in v1.0
synchronizationJobClient.BaseClient.ApiVersion = msgraph.VersionBeta

return &Client{
DelegatedPermissionGrantsClient: delegatedPermissionGrantsClient,
DirectoryObjectsClient: directoryObjectsClient,
Expand Down
1 change: 1 addition & 0 deletions internal/services/serviceprincipals/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ func (r Registration) SupportedResources() map[string]*schema.Resource {
"azuread_service_principal_token_signing_certificate": servicePrincipalTokenSigningCertificateResource(),
"azuread_synchronization_job": synchronizationJobResource(),
"azuread_synchronization_secret": synchronizationSecretResource(),
"azuread_synchronization_job_provision_on_demand": synchronizationProvisionOnDemandResource(),
}
}
35 changes: 35 additions & 0 deletions internal/services/serviceprincipals/synchronization.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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: utils.String(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: utils.String(item["object_id"].(string)),
ObjectTypeName: utils.String(item["object_type_name"].(string)),
})
}

return &result
}

func flattenSynchronizationSchedule(in *msgraph.SynchronizationSchedule) []map[string]interface{} {
if in == nil {
return []map[string]interface{}{}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package serviceprincipals

import (
"context"
"errors"
"net/http"
"time"

"github.com/hashicorp/go-uuid"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/manicminer/hamilton/msgraph"
"github.com/manicminer/hamilton/odata"

"github.com/hashicorp/terraform-provider-azuread/internal/clients"
"github.com/hashicorp/terraform-provider-azuread/internal/tf"
"github.com/hashicorp/terraform-provider-azuread/internal/validate"
)

func synchronizationProvisionOnDemandResource() *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: validate.UUID,
},
"job_id": {
Description: "The identifier for the synchronization jop.",
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"parameters": {
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,
},
"subjects": {
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 synchronizationJob is to be applied. Can be one of the following:\nAn onPremisesDistinguishedName for synchronization from Active Directory to Azure AD.\nThe user ID for synchronization from Azure AD to a third-party.\nThe 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 synchronizationJob is to be applied. Can be one of the following:\nuser for synchronizing between Active Directory and Azure AD.\nUser for synchronizing a user between Azure AD and a third-party application.\nWorker for synchronization a user between Workday and either Active Directory or Azure AD.\nGroup for synchronizing a group between Azure AD and a third-party application.",
Type: schema.TypeString,
Required: true,
},
},
},
},
},
},
},
},
}
}

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("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("parameters").([]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
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b0c1284

Please sign in to comment.