From 4fda063fbc0f7b0cb99a3ea9a468d191a99f8d3e Mon Sep 17 00:00:00 2001 From: eamouhadi Date: Thu, 22 Jun 2023 08:36:14 -0700 Subject: [PATCH 1/5] change cc api --- client.go | 18 ++-- data_source_role.go | 37 ++------ data_source_source_entitlements.go | 2 +- resource_role.go | 31 +++++- schema_role.go | 49 +++------- schema_role_access_profiles.go | 30 ++++++ schema_source_entitlement.go | 39 ++------ structure_role.go | 137 ++++++++++++++++++++++----- structure_role_test.go | 66 ++++++++----- structure_source_entitlement.go | 23 ++--- structure_source_entitlement_test.go | 66 ++++++------- type_entitlement.go | 64 +++++++------ type_role.go | 72 +++++++++----- 13 files changed, 377 insertions(+), 257 deletions(-) create mode 100644 schema_role_access_profiles.go diff --git a/client.go b/client.go index 400b6d7..879d48a 100644 --- a/client.go +++ b/client.go @@ -174,8 +174,8 @@ func (c *Client) GetAccessProfile(ctx context.Context, id string) (*AccessProfil return &res, nil } -func (c *Client) GetSourceEntitlements(ctx context.Context, id string) (*SourceEntitlements, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/cc/api/entitlement/list?CISApplicationId=%s", c.BaseURL, id), nil) +func (c *Client) GetSourceEntitlements(ctx context.Context, id string) ([]*SourceEntitlement, error) { + req, err := http.NewRequest("GET", fmt.Sprintf("%s/beta/entitlement?filters=source.id eq \"%s\"", c.BaseURL, id), nil) if err != nil { log.Printf("Creation of new http request failed: %+v\n", err) return nil, err @@ -183,14 +183,14 @@ func (c *Client) GetSourceEntitlements(ctx context.Context, id string) (*SourceE req = req.WithContext(ctx) - res := SourceEntitlements{} + var res []*SourceEntitlement if err := c.sendRequest(req, &res); err != nil { log.Printf("Failed Source Entitlements get response:%+v\n", res) log.Fatal(err) return nil, err } - return &res, nil + return res, nil } func (c *Client) CreateAccessProfile(ctx context.Context, accessProfile *AccessProfile) (*AccessProfile, error) { @@ -268,7 +268,7 @@ func (c *Client) DeleteAccessProfile(ctx context.Context, accessProfile *AccessP } func (c *Client) GetRole(ctx context.Context, id string) (*Role, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/cc/api/role/get?id=%s", c.BaseURL, id), nil) + req, err := http.NewRequest("GET", fmt.Sprintf("%s/v3/roles/%s", c.BaseURL, id), nil) if err != nil { log.Printf("Creation of new http request failed: %+v\n", err) return nil, err @@ -294,7 +294,7 @@ func (c *Client) CreateRole(ctx context.Context, role *Role) (*Role, error) { return nil, err } - req, err := http.NewRequest("POST", fmt.Sprintf("%s/cc/api/role/create", c.BaseURL), bytes.NewBuffer(body)) + req, err := http.NewRequest("POST", fmt.Sprintf("%s/v3/roles", c.BaseURL), bytes.NewBuffer(body)) if err != nil { log.Printf("New request failed:%+v\n", err) return nil, err @@ -315,18 +315,18 @@ func (c *Client) CreateRole(ctx context.Context, role *Role) (*Role, error) { return &res, nil } -func (c *Client) UpdateRole(ctx context.Context, role *Role) (*Role, error) { +func (c *Client) UpdateRole(ctx context.Context, role []*UpdateRole, id interface{}) (*Role, error) { body, err := json.Marshal(&role) if err != nil { return nil, err } - req, err := http.NewRequest("POST", fmt.Sprintf("%s/cc/api/role/update/?id=%s", c.BaseURL, role.ID), bytes.NewBuffer(body)) + req, err := http.NewRequest("PATCH", fmt.Sprintf("%s/v3/roles/%s", c.BaseURL, id), bytes.NewBuffer(body)) if err != nil { log.Printf("Creation of new http request failed:%+v\n", err) return nil, err } - req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Content-Type", "application/json-patch+json; charset=utf-8") req.Header.Set("Accept", "application/json; charset=utf-8") req = req.WithContext(ctx) diff --git a/data_source_role.go b/data_source_role.go index 5518ab9..c95e83e 100644 --- a/data_source_role.go +++ b/data_source_role.go @@ -15,57 +15,36 @@ func dataSourceRole() *schema.Resource { Type: schema.TypeString, Required: true, }, - "access_profile_ids": { + "accessProfiles": { Type: schema.TypeList, Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, + Elem: &schema.Resource{ + Schema: roleAccessProfilesFields(), }, }, - "approval_schemes": { - Type: schema.TypeString, - Computed: true, - }, - "denied_comments_required": { - Type: schema.TypeBool, - Computed: true, - }, "description": { Type: schema.TypeString, Computed: true, }, - "disabled": { + "enabled": { Type: schema.TypeBool, Computed: true, }, - "display_name": { - Type: schema.TypeString, - Computed: true, - }, - "identity_count": { - Type: schema.TypeInt, - Computed: true, - }, "name": { Type: schema.TypeString, Computed: true, }, "owner": { - Type: schema.TypeString, - Computed: true, - }, - "request_comments_required": { - Type: schema.TypeBool, + Type: schema.TypeList, Computed: true, + Elem: &schema.Resource{ + Schema: sourceOwnerFields(), + }, }, "requestable": { Type: schema.TypeBool, Computed: true, }, - "revoke_request_approval_schemes": { - Type: schema.TypeString, - Computed: true, - }, }, } } diff --git a/data_source_source_entitlements.go b/data_source_source_entitlements.go index 96e74fa..9a6f326 100644 --- a/data_source_source_entitlements.go +++ b/data_source_source_entitlements.go @@ -33,7 +33,7 @@ func dataSourceSourceEntitlementRead(d *schema.ResourceData, meta interface{}) e return err } - entitlement := getEntitlement(sourceEntitlements.Items, d.Get("name").(string)) + entitlement := getEntitlement(sourceEntitlements, d.Get("name").(string)) return flattenSourceEntitlement(d, entitlement) } diff --git a/resource_role.go b/resource_role.go index 5d680e8..b38f476 100644 --- a/resource_role.go +++ b/resource_role.go @@ -71,6 +71,33 @@ func resourceRoleRead(d *schema.ResourceData, m interface{}) error { return nil } +func resourceUpdateRoleRead(d *schema.ResourceData, m interface{}) error { + log.Printf("[INFO] Refreshing Role ID %s", d.Id()) + client, err := m.(*Config).IdentityNowClient() + if err != nil { + return err + } + + role, err := client.GetRole(context.Background(), d.Id()) + if err != nil { + // non-panicking type assertion, 2nd arg is boolean indicating type match + _, notFound := err.(*NotFoundError) + if notFound { + log.Printf("[INFO] Role ID %s not found.", d.Id()) + d.SetId("") + return nil + } + return err + } + + err = flattenRole(d, role) + if err != nil { + return err + } + + return nil +} + func resourceRoleUpdate(d *schema.ResourceData, m interface{}) error { log.Printf("[INFO] Updating Role ID %s", d.Id()) client, err := m.(*Config).IdentityNowClient() @@ -80,13 +107,13 @@ func resourceRoleUpdate(d *schema.ResourceData, m interface{}) error { log.Printf("disabled in role: %s\n", d.Get("disabled")) - updatedRole, err := expandRole(d) + updatedRole, id, err := expandUpdateRole(d) log.Printf("role after expand: %v\n", updatedRole) if err != nil { return err } - _, err = client.UpdateRole(context.Background(), updatedRole) + _, err = client.UpdateRole(context.Background(), updatedRole, id) if err != nil { return err } diff --git a/schema_role.go b/schema_role.go index efa6b5c..03ff02c 100644 --- a/schema_role.go +++ b/schema_role.go @@ -4,40 +4,11 @@ import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" func roleFields() map[string]*schema.Schema { s := map[string]*schema.Schema{ - "access_profile_ids": { - Type: schema.TypeList, - Optional: true, - Description: "Access Profile Ids.", - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "approval_schemes": { - Type: schema.TypeString, - Optional: true, - Description: "required approvers person or group. e.g. manager,owner", - }, - "denied_comments_required": { - Type: schema.TypeBool, - Optional: true, - }, "description": { Type: schema.TypeString, Required: true, Description: "Role description.", }, - "disabled": { - Type: schema.TypeBool, - Optional: true, - }, - "display_name": { - Type: schema.TypeString, - Optional: true, - }, - "identity_count": { - Type: schema.TypeInt, - Optional: true, - }, "name": { Type: schema.TypeString, Required: true, @@ -45,20 +16,26 @@ func roleFields() map[string]*schema.Schema { Description: "Role name", }, "owner": { - Type: schema.TypeString, - Required: true, - Description: "Owner of Role name", + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: sourceOwnerFields(), + }, }, - "request_comments_required": { - Type: schema.TypeBool, + "accessProfiles": { + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: roleAccessProfilesFields(), + }, }, "requestable": { Type: schema.TypeBool, Optional: true, }, - "revoke_request_approval_schemes": { - Type: schema.TypeString, + "enabled": { + Type: schema.TypeBool, Optional: true, }, } diff --git a/schema_role_access_profiles.go b/schema_role_access_profiles.go new file mode 100644 index 0000000..881fadf --- /dev/null +++ b/schema_role_access_profiles.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +// Schemas + +func roleAccessProfilesFields() map[string]*schema.Schema { + s := map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "Id of role", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "Name of AccessProfile", + }, + "type": { + Type: schema.TypeString, + Optional: true, + Default: "ACCESS_PROFILE", + Description: "Access Profile Type", + }, + } + + return s +} diff --git a/schema_source_entitlement.go b/schema_source_entitlement.go index 493025b..c40ecc8 100644 --- a/schema_source_entitlement.go +++ b/schema_source_entitlement.go @@ -16,19 +16,19 @@ func sourceEntitlementFields() map[string]*schema.Schema { }, "source_name": { Type: schema.TypeString, - Computed: true, + Required: true, Description: "source name", }, + "source_schema_object_type": { + Type: schema.TypeString, + Computed: true, + }, "attribute": { Type: schema.TypeString, Computed: true, Description: "attribute", }, - "created_time": { - Type: schema.TypeString, - Computed: true, - }, - "deleted_time": { + "created": { Type: schema.TypeString, Computed: true, }, @@ -36,30 +36,11 @@ func sourceEntitlementFields() map[string]*schema.Schema { Type: schema.TypeString, Computed: true, }, - "direct_permissions": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "display_name": { + "modified": { Type: schema.TypeString, Computed: true, }, - "displayable_name": { - Type: schema.TypeString, - Computed: true, - }, - "last_modified_time": { - Type: schema.TypeString, - Computed: true, - }, - "owner_id": { - Type: schema.TypeString, - Computed: true, - }, - "owner_uid": { + "owner": { Type: schema.TypeString, Computed: true, }, @@ -67,8 +48,8 @@ func sourceEntitlementFields() map[string]*schema.Schema { Type: schema.TypeBool, Computed: true, }, - "schema": { - Type: schema.TypeString, + "requestable": { + Type: schema.TypeBool, Computed: true, }, "value": { diff --git a/structure_role.go b/structure_role.go index 3379b83..4faad68 100644 --- a/structure_role.go +++ b/structure_role.go @@ -13,21 +13,64 @@ func flattenRole(d *schema.ResourceData, in *Role) error { } d.SetId(in.ID) - d.Set("access_profile_ids", toArrayInterface(in.AccessProfileIds)) - d.Set("approval_schemes", in.ApprovalSchemes) - d.Set("denied_comments_required", in.DeniedCommentsRequired) d.Set("description", in.Description) - d.Set("disabled", in.Disabled) - d.Set("display_name", in.DisplayName) - d.Set("identity_count", in.IdentityCount) d.Set("name", in.Name) - d.Set("owner", in.Owner) - d.Set("request_comments_required", in.RequestCommentsRequired) d.Set("requestable", in.Requestable) - d.Set("revoke_request_approval_schemes", in.RevokeRequestApprovalSchemes) + d.Set("enabled", in.Enabled) + + if in.RoleOwner != nil { + v, ok := d.Get("owner").(interface{}) + if !ok { + v = []interface{}{} + } + + d.Set("owner", flattenObjectRole(in.RoleOwner, v)) + } + if in.AccessProfiles != nil { + v, ok := d.Get("schemas").([]interface{}) + if !ok { + v = []interface{}{} + } + + d.Set("schemas", flattenObjectRoles(in.AccessProfiles, v)) + } return nil } +func flattenObjectRole(in *ObjectInfo, p interface{}) interface{} { + var obj map[string]interface{} + if p == nil { + obj = make(map[string]interface{}) + } else { + obj = p.(map[string]interface{}) + } + + if in == nil { + return []interface{}{} + } + obj["type"] = in.Type + obj["id"] = in.ID + obj["name"] = in.Name + + return []interface{}{obj} +} + +func flattenObjectRoles(in []*ObjectInfo, p []interface{}) []interface{} { + if in == nil { + return []interface{}{} + } + + out := make([]interface{}, 0, len(in)) + for i := range in { + var obj = make(map[string]interface{}) + obj["type"] = in[i].Type + obj["id"] = in[i].ID + obj["name"] = in[i].Name + out = append(out, obj) + } + return out +} + // Expanders func expandRole(in *schema.ResourceData) (*Role, error) { @@ -39,36 +82,78 @@ func expandRole(in *schema.ResourceData) (*Role, error) { obj.ID = v } - obj.ApprovalSchemes = in.Get("approval_schemes").(string) obj.Description = in.Get("description").(string) - obj.DisplayName = in.Get("display_name").(string) obj.Name = in.Get("name").(string) - obj.Owner = in.Get("owner").(string) - obj.RevokeRequestApprovalSchemes = in.Get("revoke_request_approval_schemes").(string) - if v, ok := in.Get("access_profile_ids").([]interface{}); ok { - obj.AccessProfileIds = toArrayString(v) + if v, ok := in.Get("requestable").(bool); ok { + obj.Requestable = &v } - if v, ok := in.Get("identity_count").(int); ok { - obj.IdentityCount = v + if v, ok := in.Get("owner").([]interface{}); ok && len(v) > 0 { + obj.RoleOwner = expandObjectRole(v) } - if v, ok := in.Get("denied_comments_required").(bool); ok { - obj.DeniedCommentsRequired = &v + if v, ok := in.Get("accessProfiles").([]interface{}); ok && len(v) > 0 { + obj.AccessProfiles = expandObjectRoles(v) } - if v, ok := in.Get("disabled").(bool); ok { - obj.Disabled = &v + if v, ok := in.Get("enabled").(bool); ok { + obj.Enabled = &v } - if v, ok := in.Get("request_comments_required").(bool); ok { - obj.RequestCommentsRequired = &v + return &obj, nil +} + +func expandUpdateRole(in *schema.ResourceData) ([]*UpdateRole, interface{}, error) { + updatableFields := []string{"name", "description", "enabled", "owner", "accessProfiles", "requestable"} + var id interface{} + if in == nil { + return nil, nil, fmt.Errorf("[ERROR] Expanding Role: Schema Resource data is nil") } - if v, ok := in.Get("requestable").(bool); ok { - obj.Requestable = &v + if v := in.Id(); len(v) > 0 { + id = v } - return &obj, nil + out := []*UpdateRole{} + + for i := range updatableFields { + obj := UpdateRole{} + if v, ok := in.Get(fmt.Sprintf("/%s", updatableFields[i])).([]interface{}); ok { + obj.Op = "replace" + obj.Path = fmt.Sprintf("/%s", updatableFields[i]) + obj.Value = v + } + out = append(out, &obj) + } + + return out, id, nil +} + +func expandObjectRole(p interface{}) *ObjectInfo { + obj := ObjectInfo{} + + if p == nil { + return &obj + } + in := p.(map[string]interface{}) + + obj.ID = in["id"].(string) + obj.Name = in["name"].(string) + obj.Type = in["type"].(string) + + return &obj +} + +func expandObjectRoles(p []interface{}) []*ObjectInfo { + if len(p) == 0 || p[0] == nil { + return []*ObjectInfo{} + } + out := make([]*ObjectInfo, 0, len(p)) + for i := range p { + in := p[i].(map[string]interface{}) + obj := expandObjectRole(in) + out = append(out, obj) + } + return out } diff --git a/structure_role_test.go b/structure_role_test.go index 7f5a5b4..a1f8d89 100644 --- a/structure_role_test.go +++ b/structure_role_test.go @@ -15,32 +15,50 @@ func init() { TRUE := true FALSE := false testRoleConf = &Role{ - AccessProfileIds: []string{"1234", "5678"}, - ApprovalSchemes: "manager", - DeniedCommentsRequired: &TRUE, - Description: "test description", - Disabled: &FALSE, - DisplayName: "test name", - IdentityCount: 1, - Name: "test name", - Owner: "test_identity", - RequestCommentsRequired: &FALSE, - Requestable: &FALSE, - RevokeRequestApprovalSchemes: "test", + Description: "test description", + Enabled: &TRUE, + Name: "test name", + RoleOwner: &ObjectInfo{ + ID: "2c9180887412345678948078d29f2e46", + Name: "SRE Test", + Type: "IDENTITY", + }, + AccessProfiles: []*ObjectInfo{ + { + ID: "2c918088747654398948078d29f2e46", + Name: "Test Developer", + Type: "ACCESS_PROFILE", + }, + { + ID: "2c918009437654398948078d29f2e46", + Name: "Test Operator", + Type: "ACCESS_PROFILE", + }, + }, + Requestable: &FALSE, } testRoleInterface = map[string]interface{}{ - "access_profile_ids": []interface{}{"1234", "5678"}, - "approval_schemes": "manager", - "denied_comments_required": true, - "description": "test description", - "disabled": false, - "display_name": "test name", - "identity_count": 1, - "name": "test name", - "owner": "test_identity", - "request_comments_required": false, - "requestable": false, - "revoke_request_approval_schemes": "test", + //"accessProfiles": []map[string]interface{}{ + // { + // "id": "2c918088747654398948078d29f2e46", + // "name": "Test Developer", + // "type": "ACCESS_PROFILE", + // }, + // { + // "id": "2c918009437654398948078d29f2e46", + // "name": "Test Operator", + // "type": "ACCESS_PROFILE", + // }, + //}, + "owner": map[string]interface{}{ + "id": "2c9180887412345678948078d29f2e46", + "name": "SRE Test", + "type": "IDENTITY", + }, + "description": "test description", + "enabled": true, + "name": "test name", + "requestable": false, } } diff --git a/structure_source_entitlement.go b/structure_source_entitlement.go index 674c3a3..c73ff7c 100644 --- a/structure_source_entitlement.go +++ b/structure_source_entitlement.go @@ -4,33 +4,30 @@ import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" // Flatteners -func flattenSourceEntitlement(d *schema.ResourceData, in *Items) error { +func flattenSourceEntitlement(d *schema.ResourceData, in *SourceEntitlement) error { if in == nil { return nil } d.SetId(in.ID) - d.Set("source_id", in.SourceID) - d.Set("source_name", in.SourceName) + d.Set("source_id", in.Source.ID) + d.Set("source_name", in.Source.Name) d.Set("attribute", in.Attribute) - d.Set("created_time", in.CreatedTime) - d.Set("deleted_time", in.DeletedTime) + d.Set("created", in.Created) d.Set("description", in.Description) d.Set("direct_permissions", toArrayString(in.DirectPermissions)) - d.Set("display_name", in.DisplayName) - d.Set("displayable_name", in.DisplayableName) - d.Set("last_modified_time", in.LastModifiedTime) - d.Set("owner_id", in.OwnerID) - d.Set("owner_uid", in.OwnerUID) + d.Set("name", in.Name) + d.Set("modified", in.Modified) + d.Set("owner", in.Owner) d.Set("privileged", in.Privileged) - d.Set("schema", in.Schema) + d.Set("source_schema_object_type", in.SourceSchemaObjectType) d.Set("value", in.Value) return nil } -func getEntitlement(entitlements []*Items, name string) *Items { +func getEntitlement(entitlements []*SourceEntitlement, name string) *SourceEntitlement { for i := range entitlements { - if entitlements[i].DisplayableName == name { + if entitlements[i].Name == name { return entitlements[i] } } diff --git a/structure_source_entitlement_test.go b/structure_source_entitlement_test.go index 9e4f2ce..ca58359 100644 --- a/structure_source_entitlement_test.go +++ b/structure_source_entitlement_test.go @@ -7,50 +7,46 @@ import ( ) var ( - testEntitlementConf *Items + testEntitlementConf []*SourceEntitlement testEntitlementInterface map[string]interface{} ) func init() { - testEntitlementConf = &Items{ - SourceID: "2c9180887412345678948078d29f2e46", - SourceName: "Active Directory test", - Attribute: "memberOf", - CreatedTime: nil, - DeletedTime: "05/21/2020", - Description: "test description", - DirectPermissions: []interface{}{"test"}, - DisplayName: "test name", - DisplayableName: "test name", - LastModifiedTime: "06/20/2020", - OwnerID: "1234", - OwnerUID: "123a4", - Privileged: false, - Schema: "group", - Value: "CN=example,OU=Groups,DC=test,DC=com", - } - testEntitlementInterface = map[string]interface{}{ - "source_id": "2c9180887412345678948078d29f2e46", - "source_name": "Active Directory test", - "attribute": "memberOf", - "deleted_time": "05/21/2020", - "description": "test description", - "direct_permissions": []interface{}{"test"}, - "display_name": "test name", - "displayable_name": "test name", - "last_modified_time": "06/20/2020", - "owner_id": "1234", - "owner_uid": "123a4", - "privileged": false, - "schema": "group", - "value": "CN=example,OU=Groups,DC=test,DC=com", + testEntitlementConf = []*SourceEntitlement{ + { + Source: &SourceInfo{ + ID: "2c9180887412345678948078d29f2e46", + Name: "Active Directory test", + }, + Attribute: "memberOf", + Created: nil, + Description: "test description", + Name: "test name", + Modified: "06/20/2020", + Owner: nil, + Privileged: false, + SourceSchemaObjectType: "group", + Value: "CN=example,OU=Groups,DC=test,DC=com", + }, } + testEntitlementInterface = + map[string]interface{}{ + "source_name": "Active Directory test", + "source_id": "2c9180887412345678948078d29f2e46", + "attribute": "memberOf", + "description": "test description", + "name": "test name", + "modified": "06/20/2020", + "privileged": false, + "source_schema_object_type": "group", + "value": "CN=example,OU=Groups,DC=test,DC=com", + } } func TestFlattenSourceEntitlement(t *testing.T) { cases := []struct { - Input *Items + Input []*SourceEntitlement ExpectedOutput map[string]interface{} }{ { @@ -61,7 +57,7 @@ func TestFlattenSourceEntitlement(t *testing.T) { for _, tc := range cases { output := schema.TestResourceDataRaw(t, sourceEntitlementFields(), tc.ExpectedOutput) - err := flattenSourceEntitlement(output, tc.Input) + err := flattenSourceEntitlement(output, tc.Input[0]) if err != nil { t.Fatalf("[ERROR] on flattener: %#v", err) } diff --git a/type_entitlement.go b/type_entitlement.go index a3a54ed..bb87971 100644 --- a/type_entitlement.go +++ b/type_entitlement.go @@ -1,36 +1,38 @@ package main -type SourceEntitlements struct { - SourceID string `json:"id"` - EntitlementsCount int `json:"count,omitempty"` - Items []*Items `json:"items,omitempty"` +type SourceEntitlement struct { + Attribute string `json:"attribute,omitempty"` + Value string `json:"value,omitempty"` + Description interface{} `json:"description,omitempty"` + SourceSchemaObjectType string `json:"sourceSchemaObjectType,omitempty"` + Privileged bool `json:"privileged,omitempty"` + CloudGoverned bool `json:"cloudGoverned,omitempty"` + Requestable bool `json:"requestable,omitempty"` + Attributes *Attributes `json:"attributes,omitempty"` + Source *SourceInfo `json:"source,omitempty"` + Owner interface{} `json:"owner,omitempty"` + DirectPermissions []interface{} `json:"directPermissions,omitempty"` + Segments []interface{} `json:"segments,omitempty"` + ManuallyUpdatedFields []interface{} `json:"manuallyUpdatedFields,omitempty"` + Modified interface{} `json:"modified,omitempty"` + Created interface{} `json:"created,omitempty"` + ID string `json:"id"` + Name string `json:"name"` } -type Items struct { - SourceID string `json:"applicationId"` - SourceName string `json:"applicationName"` - Attribute string `json:"attribute,omitempty"` - Attributes struct { - DisplayName string `json:"displayName,omitempty"` - GroupTypes interface{} `json:"groupTypes,omitempty"` - MailEnabled bool `json:"mailEnabled,omitempty"` - MailNickname string `json:"mailNickname,omitempty"` - Owners interface{} `json:"owners,omitempty"` - ProxyAddresses interface{} `json:"proxyAddresses,omitempty"` - SecurityEnabled bool `json:"securityEnabled,omitempty"` - TeamsEnabled bool `json:"teamsEnabled,omitempty"` - } `json:"attributes,omitempty"` - CreatedTime interface{} `json:"createdTime,omitempty"` - DeletedTime interface{} `json:"deletedTime,omitempty"` - Description interface{} `json:"description,omitempty"` - DirectPermissions []interface{} `json:"directPermissions,omitempty"` - DisplayName interface{} `json:"displayName"` - DisplayableName string `json:"displayableName"` - ID string `json:"id"` - LastModifiedTime interface{} `json:"lastModifiedTime,omitempty"` - OwnerID interface{} `json:"ownerId,omitempty"` - OwnerUID interface{} `json:"ownerUid,omitempty"` - Privileged bool `json:"privileged,omitempty"` - Schema string `json:"schema,omitempty"` - Value string `json:"value,omitempty"` +type Attributes struct { + GroupType string `json:"groupType,omitempty"` + SAMAccountName string `json:"sAMAccountName,omitempty"` + ObjectGuid interface{} `json:"objectguid,omitempty"` + GroupScope interface{} `json:"GroupScope,omitempty"` + Description interface{} `json:"description,omitempty"` + ObjectSid interface{} `json:"objectSid,omitempty"` + Cn interface{} `json:"cn,omitempty"` + MsDSPrincipalName interface{} `json:"msDS-PrincipalName,omitempty"` +} + +type SourceInfo struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` } diff --git a/type_role.go b/type_role.go index 94582b4..926c0d0 100644 --- a/type_role.go +++ b/type_role.go @@ -1,26 +1,54 @@ package main type Role struct { - AccessProfileIds []string `json:"accessProfileIds,omitempty"` - ApprovalSchemes string `json:"approvalSchemes,omitempty"` - DeniedCommentsRequired *bool `json:"deniedCommentsRequired,omitempty"` - Description string `json:"description"` - Disabled *bool `json:"disabled,omitempty"` - DisplayName string `json:"displayName,omitempty"` - ID string `json:"id,omitempty"` - IdentityCount int `json:"identityCount,omitempty"` - Name string `json:"name"` - Owner string `json:"owner"` - RequestCommentsRequired *bool `json:"requestCommentsRequired,omitempty"` - Requestable *bool `json:"requestable,omitempty"` - RevokeRequestApprovalSchemes string `json:"revokeRequestApprovalSchemes,omitempty"` - Selector struct { - AliasList []interface{} `json:"aliasList,omitempty"` - ComplexRoleCriterion interface{} `json:"complexRoleCriterion,omitempty"` - EntitlementIds []interface{} `json:"entitlementIds,omitempty"` - RuleID interface{} `json:"ruleId,omitempty"` - SourceID interface{} `json:"sourceId,omitempty"` - Type string `json:"type,omitempty"` - ValueMap []interface{} `json:"valueMap,omitempty"` - } `json:"selector,omitempty"` + Description string `json:"description"` + ID string `json:"id,omitempty"` + Name string `json:"name"` + Requestable *bool `json:"requestable,omitempty"` + RoleOwner *ObjectInfo `json:"owner,omitempty"` + AccessProfiles []*ObjectInfo `json:"accessProfiles,omitempty"` + LegacyMembershipInfo interface{} `json:"legacyMembershipInfo,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Segments []interface{} `json:"segments,omitempty"` + Membership struct { + Type string `json:"type,omitempty"` + Criteria struct { + Operation string `json:"operation,omitempty"` + Key interface{} `json:"key,omitempty"` + StringValue string `json:"stringValue,omitempty"` + Children []*RoleChildren `json:"children,omitempty"` + } `json:"criteria,omitempty"` + } `json:"membership,omitempty"` + AccessRequestConfig struct { + CommentsRequired *bool `json:"commentsRequired,omitempty"` + DenialCommentsRequired *bool `json:"denialCommentsRequired,omitempty"` + ApprovalSchemes []interface{} `json:"approvalSchemes,omitempty"` + } `json:"accessRequestConfig,omitempty"` + RevocationRequestConfig struct { + ApprovalSchemes []interface{} `json:"approvalSchemes,omitempty"` + } `json:"revocationRequestConfig,omitempty"` +} +type ObjectInfo struct { + ID interface{} `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Name string `json:"name"` +} + +type RoleChildren struct { + Operation string `json:"operation,omitempty"` + Key *RoleKey `json:"key,omitempty"` + StringValue string `json:"stringValue,omitempty"` + Children *RoleChildren `json:"children,omitempty"` +} + +type RoleKey struct { + Type string `json:"type,omitempty"` + Property interface{} `json:"property,omitempty"` + SourceId interface{} `json:"sourceId,omitempty"` +} + +type UpdateRole struct { + Op string `json:"op"` + Path string `json:"path"` + Value []interface{} `json:"value"` } From dbf8ba062c37ef6283796b1c7dfe56601f758ce2 Mon Sep 17 00:00:00 2001 From: eamouhadi Date: Thu, 3 Aug 2023 08:59:04 -0700 Subject: [PATCH 2/5] update account schema api to use v3 version --- client.go | 82 +++++----- import_account_schema_attribute.go | 10 +- provider.go | 2 +- resource_account_schema.go | 145 +++++++++++++++++ resource_account_schema_attribute.go | 148 ----------------- ...a_attribute.go => schema_account_schema.go | 45 +++--- schema_account_schema_attributes.go | 46 ++++++ structure_account_schema.go | 62 ++++++++ structure_account_schema_attribute.go | 105 ++++++------ structure_account_schema_attribute_test.go | 92 ----------- structure_account_schema_test.go | 150 ++++++++++++++++++ structure_role.go | 4 +- type_account_schema.go | 38 ++--- util.go | 11 -- 14 files changed, 541 insertions(+), 399 deletions(-) create mode 100644 resource_account_schema.go delete mode 100644 resource_account_schema_attribute.go rename schema_account_schema_attribute.go => schema_account_schema.go (58%) create mode 100644 schema_account_schema_attributes.go create mode 100644 structure_account_schema.go delete mode 100644 structure_account_schema_attribute_test.go create mode 100644 structure_account_schema_test.go diff --git a/client.go b/client.go index 879d48a..fad5b47 100644 --- a/client.go +++ b/client.go @@ -431,8 +431,8 @@ func (c *Client) ManageAccountAggregationSchedule(ctx context.Context, scheduleA return &res, nil } -func (c *Client) GetAccountSchemaAttributes(ctx context.Context, sourceId string) (*AccountSchema, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/cc/api/source/getAccountSchema/%s", c.BaseURL, sourceId), nil) +func (c *Client) GetAccountSchema(ctx context.Context, sourceId string, id string) (*AccountSchema, error) { + req, err := http.NewRequest("GET", fmt.Sprintf("%s/v3/sources/%s/schemas/%s", c.BaseURL, sourceId, id), nil) if err != nil { log.Printf("Creation of new http request failed: %+v\n", err) return nil, err @@ -450,32 +450,22 @@ func (c *Client) GetAccountSchemaAttributes(ctx context.Context, sourceId string return &res, nil } -func (c *Client) CreateAccountSchemaAttribute(ctx context.Context, attribute *AccountSchemaAttribute) (*AccountSchemaAttribute, error) { - endpoint := fmt.Sprintf("%s/cc/api/source/createSchemaAttribute/%s", c.BaseURL, attribute.SourceID) - data := url.Values{} - data.Set("name", attribute.Name) - data.Set("description", attribute.Description) - data.Set("type", attribute.Type) - data.Set("objectType", attribute.ObjectType) - data.Set("displayAttribute", fmt.Sprintf("%t", attribute.DisplayAttribute)) - data.Set("entitlement", fmt.Sprintf("%t", attribute.Entitlement)) - data.Set("identityAttribute", fmt.Sprintf("%t", attribute.IdentityAttribute)) - data.Set("managed", fmt.Sprintf("%t", attribute.Managed)) - data.Set("minable", fmt.Sprintf("%t", attribute.Minable)) - data.Set("multi", fmt.Sprintf("%t", attribute.Multi)) - - req, err := http.NewRequest("POST", endpoint, strings.NewReader(data.Encode())) - +func (c *Client) CreateAccountSchema(ctx context.Context, accountSchema *AccountSchema) (*AccountSchema, error) { + body, err := json.Marshal(&accountSchema) if err != nil { return nil, err } + req, err := http.NewRequest("POST", fmt.Sprintf("%s/v3/sources/%s/schemas", c.BaseURL, accountSchema.SourceID), bytes.NewBuffer(body)) + if err != nil { + log.Printf("New request failed:%+v\n", err) + return nil, err + } - req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") + req.Header.Set("Content-Type", "application/json; charset=utf-8") req.Header.Set("Accept", "application/json; charset=utf-8") req = req.WithContext(ctx) - - res := AccountSchemaAttribute{} + res := AccountSchema{} if err := c.sendRequest(req, &res); err != nil { log.Printf("Failed Account Schema Attribute creation. response:%+v\n", res) log.Fatal(err) @@ -485,43 +475,55 @@ func (c *Client) CreateAccountSchemaAttribute(ctx context.Context, attribute *Ac return &res, nil } -func (c *Client) UpdateAccountSchemaAttribute(ctx context.Context, attribute *AccountSchemaAttribute) (*AccountSchemaAttribute, error) { - _, errDelete := c.DeleteAccountSchemaAttribute(ctx, attribute) - if errDelete != nil { - return nil, errDelete +func (c *Client) UpdateAccountSchema(ctx context.Context, accountSchema *AccountSchema) (*AccountSchema, error) { + body, err := json.Marshal(&accountSchema) + if err != nil { + return nil, err } - res, errCreate := c.CreateAccountSchemaAttribute(ctx, attribute) - if errCreate != nil { - return nil, errDelete + req, err := http.NewRequest("PUT", fmt.Sprintf("%s/v3/sources/%s/schemas/%s", c.BaseURL, accountSchema.SourceID, accountSchema.ID), bytes.NewBuffer(body)) + if err != nil { + log.Printf("New request failed:%+v\n", err) + return nil, err } - return res, nil + + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Accept", "application/json; charset=utf-8") + + req = req.WithContext(ctx) + res := AccountSchema{} + if err := c.sendRequest(req, &res); err != nil { + log.Printf("Failed Account Schema Attribute updating. response:%+v\n", res) + log.Fatal(err) + return nil, err + } + + return &res, nil } -func (c *Client) DeleteAccountSchemaAttribute(ctx context.Context, attribute *AccountSchemaAttribute) (*AccountSchemaAttribute, error) { - endpoint := fmt.Sprintf("%s/cc/api/source/deleteSchemaAttribute/%s", c.BaseURL, attribute.SourceID) - data := url.Values{} - data.Set("names", attribute.Name) - data.Set("objectType", attribute.ObjectType) +func (c *Client) DeleteAccountSchema(ctx context.Context, accountSchema *AccountSchema) error { + endpoint := fmt.Sprintf("%s/v3/sources/%s/schemas/%s", c.BaseURL, accountSchema.SourceID, accountSchema.ID) - req, err := http.NewRequest("POST", endpoint, strings.NewReader(data.Encode())) + client := &http.Client{} + + req, err := http.NewRequest("DELETE", endpoint, nil) if err != nil { - return nil, err + return err } req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") req.Header.Set("Accept", "application/json; charset=utf-8") req = req.WithContext(ctx) + res, err := client.Do(req) - res := AccountSchemaAttribute{} - if err := c.sendRequest(req, &res); err != nil { + if err != nil { log.Printf("Failed Account Schema Attribute deletion. response:%+v\n", res) log.Fatal(err) - return nil, err + return err } - return &res, nil + return nil } func (c *Client) CreatePasswordPolicy(ctx context.Context, attributes *PasswordPolicy) (*PasswordPolicy, error) { diff --git a/import_account_schema_attribute.go b/import_account_schema_attribute.go index 1dae238..b8da408 100644 --- a/import_account_schema_attribute.go +++ b/import_account_schema_attribute.go @@ -2,14 +2,8 @@ package main import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" -func resourceAccountSchemaAttributeImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { - sourceID, name, err := splitAccountSchemaAttributeID(d.Id()) - if err != nil { - return []*schema.ResourceData{}, err - } - d.Set("source_id", sourceID) - d.Set("name", name) - err = resourceAccountSchemaAttributeRead(d, meta) +func resourceAccountSchemaImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + err := resourceAccountSchemaRead(d, meta) if err != nil { return []*schema.ResourceData{}, err } diff --git a/provider.go b/provider.go index 539d8fc..d4950ea 100644 --- a/provider.go +++ b/provider.go @@ -43,7 +43,7 @@ func Provider() terraform.ResourceProvider { "identitynow_access_profile": resourceAccessProfile(), "identitynow_role": resourceRole(), "identitynow_account_aggregation_schedule": resourceScheduleAccountAggregation(), - "identitynow_account_schema_attribute": resourceAccountSchemaAttribute(), + "identitynow_account_schema_attribute": resourceAccountSchema(), "identitynow_password_policy": resourcePasswordPolicy(), }, diff --git a/resource_account_schema.go b/resource_account_schema.go new file mode 100644 index 0000000..6c81577 --- /dev/null +++ b/resource_account_schema.go @@ -0,0 +1,145 @@ +package main + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "log" +) + +func resourceAccountSchema() *schema.Resource { + return &schema.Resource{ + Create: resourceAccountSchemaCreate, + Read: resourceAccountSchemaRead, + Update: resourceAccountSchemaUpdate, + Delete: resourceAccountSchemaDelete, + Importer: &schema.ResourceImporter{ + State: resourceAccountSchemaImport, + }, + + Schema: accountSchemaFields(), + } +} + +func resourceAccountSchemaCreate(d *schema.ResourceData, m interface{}) error { + attribute, err := expandAccountSchema(d) + if err != nil { + return err + } + + log.Printf("[INFO] Creating Account Schema Attribute %s", attribute.Name) + + client, err := m.(*Config).IdentityNowClient() + if err != nil { + return err + } + + newAttribute, err := client.CreateAccountSchema(context.Background(), attribute) + if err != nil { + return err + } + + newAttribute.SourceID = attribute.SourceID + + err = flattenAccountSchema(d, newAttribute) + if err != nil { + return err + } + + return resourceAccountSchemaRead(d, m) +} + +func resourceAccountSchemaRead(d *schema.ResourceData, m interface{}) error { + sourceId := d.Get("source_id").(string) + schemaId := d.Get("schema_id").(string) + attrName := d.Get("name").(string) + log.Printf("[INFO] Refreshing Account Schema for Source %s", sourceId) + client, err := m.(*Config).IdentityNowClient() + if err != nil { + return err + } + + accountSchema, err := client.GetAccountSchema(context.Background(), sourceId, schemaId) + if err != nil { + // non-panicking type assertion, 2nd arg is boolean indicating type match + _, notFound := err.(*NotFoundError) + if notFound { + log.Printf("Source ID %s not found.", sourceId) + d.SetId("") + return nil + } + return err + } + if accountSchema.Attributes == nil { + log.Printf("Attribute %s not found in Account Schema.", attrName) + d.SetId("") + } + + accountSchema.SourceID = sourceId + + err = flattenAccountSchema(d, accountSchema) + if err != nil { + return err + } + + return nil +} + +func resourceAccountSchemaUpdate(d *schema.ResourceData, m interface{}) error { + log.Printf("[INFO] Updating %s for Account Schema for source ID %s", d.Get("name").(string), d.Get("source_id").(string)) + client, err := m.(*Config).IdentityNowClient() + if err != nil { + return err + } + + updatedAttribute, err := expandAccountSchema(d) + if err != nil { + return err + } + + _, err = client.UpdateAccountSchema(context.Background(), updatedAttribute) + if err != nil { + return err + } + + return resourceAccountSchemaRead(d, m) +} + +func resourceAccountSchemaDelete(d *schema.ResourceData, m interface{}) error { + sourceId := d.Get("source_id").(string) + schemaId := d.Get("schema_id").(string) + name := d.Get("name").(string) + log.Printf("[INFO] Deleting %s from Account Schema for source ID %s", name, sourceId) + + client, err := m.(*Config).IdentityNowClient() + if err != nil { + return err + } + + accountSchema, err := client.GetAccountSchema(context.Background(), sourceId, schemaId) + if err != nil { + // non-panicking type assertion, 2nd arg is boolean indicating type match + _, notFound := err.(*NotFoundError) + if notFound { + log.Printf("Source ID %s not found.", sourceId) + d.SetId("") + return nil + } + return err + } + + if accountSchema.Attributes == nil { + log.Printf("Attribute %s not found in Account Schema.", name) + d.SetId("") + } + + accountSchema.SourceID = sourceId + + err = client.DeleteAccountSchema(context.Background(), accountSchema) + if err != nil { + return fmt.Errorf("error removing Account Schema from source %s. Error: %s", sourceId, err) + } + + d.SetId("") + return nil +} diff --git a/resource_account_schema_attribute.go b/resource_account_schema_attribute.go deleted file mode 100644 index 840658e..0000000 --- a/resource_account_schema_attribute.go +++ /dev/null @@ -1,148 +0,0 @@ -package main - -import ( - "context" - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "log" -) - -func resourceAccountSchemaAttribute() *schema.Resource { - return &schema.Resource{ - Create: resourceAccountSchemaAttributeCreate, - Read: resourceAccountSchemaAttributeRead, - Update: resourceAccountSchemaAttributeUpdate, - Delete: resourceAccountSchemaAttributeDelete, - Importer: &schema.ResourceImporter{ - State: resourceAccountSchemaAttributeImport, - }, - - Schema: accountSchemaAttributeFields(), - } -} - -func resourceAccountSchemaAttributeCreate(d *schema.ResourceData, m interface{}) error { - attribute, err := expandAccountSchemaAttribute(d) - if err != nil { - return err - } - - log.Printf("[INFO] Creating Account Schema Attribute %s", attribute.Name) - - client, err := m.(*Config).IdentityNowClient() - if err != nil { - return err - } - - newAttribute, err := client.CreateAccountSchemaAttribute(context.Background(), attribute) - if err != nil { - return err - } - - newAttribute.ObjectType = attribute.ObjectType - newAttribute.SourceID = attribute.SourceID - - err = flattenAccountSchemaAttribute(d, newAttribute) - if err != nil { - return err - } - - return resourceAccountSchemaAttributeRead(d, m) -} - -func resourceAccountSchemaAttributeRead(d *schema.ResourceData, m interface{}) error { - sourceId := d.Get("source_id").(string) - attrName := d.Get("name").(string) - log.Printf("[INFO] Refreshing Account Schema for Source %s", sourceId) - client, err := m.(*Config).IdentityNowClient() - if err != nil { - return err - } - - attributes, err := client.GetAccountSchemaAttributes(context.Background(), sourceId) - if err != nil { - // non-panicking type assertion, 2nd arg is boolean indicating type match - _, notFound := err.(*NotFoundError) - if notFound { - log.Printf("Source ID %s not found.", sourceId) - d.SetId("") - return nil - } - return err - } - attribute := getAccountSchemaAttribute(attributes, attrName) - if attribute == nil { - log.Printf("Attribute %s not found in Account Schema.", attrName) - d.SetId("") - } - - attribute.SourceID = sourceId - attribute.ObjectType = attributes.ObjectType - - err = flattenAccountSchemaAttribute(d, attribute) - if err != nil { - return err - } - - return nil -} - -func resourceAccountSchemaAttributeUpdate(d *schema.ResourceData, m interface{}) error { - log.Printf("[INFO] Updating Attribute %s for Account Schema for source ID %s", d.Get("name").(string), d.Get("source_id").(string)) - client, err := m.(*Config).IdentityNowClient() - if err != nil { - return err - } - - updatedAttribute, err := expandAccountSchemaAttribute(d) - if err != nil { - return err - } - - _, err = client.UpdateAccountSchemaAttribute(context.Background(), updatedAttribute) - if err != nil { - return err - } - - return resourceAccountSchemaAttributeRead(d, m) -} - -func resourceAccountSchemaAttributeDelete(d *schema.ResourceData, m interface{}) error { - sourceId := d.Get("source_id").(string) - attrName := d.Get("name").(string) - log.Printf("[INFO] Deleting Attribute %s from Account Schema for source ID %s", attrName, sourceId) - - client, err := m.(*Config).IdentityNowClient() - if err != nil { - return err - } - - attributes, err := client.GetAccountSchemaAttributes(context.Background(), sourceId) - if err != nil { - // non-panicking type assertion, 2nd arg is boolean indicating type match - _, notFound := err.(*NotFoundError) - if notFound { - log.Printf("Source ID %s not found.", sourceId) - d.SetId("") - return nil - } - return err - } - attribute := getAccountSchemaAttribute(attributes, attrName) - - if attribute == nil { - log.Printf("Attribute %s not found in Account Schema.", attrName) - d.SetId("") - } - - attribute.ObjectType = attributes.ObjectType - attribute.SourceID = sourceId - - _, err = client.DeleteAccountSchemaAttribute(context.Background(), attribute) - if err != nil { - return fmt.Errorf("error removing attribute %s from Account Schema", err) - } - - d.SetId("") - return nil -} diff --git a/schema_account_schema_attribute.go b/schema_account_schema.go similarity index 58% rename from schema_account_schema_attribute.go rename to schema_account_schema.go index 224781e..e1dad36 100644 --- a/schema_account_schema_attribute.go +++ b/schema_account_schema.go @@ -2,62 +2,61 @@ package main import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" -func accountSchemaAttributeFields() map[string]*schema.Schema { +func accountSchemaFields() map[string]*schema.Schema { s := map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - - "type": { Type: schema.TypeString, Optional: true, }, - "object_type": { + "source_id": { Type: schema.TypeString, Required: true, }, - "source_id": { + "schema_id": { Type: schema.TypeString, Required: true, - ForceNew: true, }, - "description": { + "display_attribute": { Type: schema.TypeString, Optional: true, }, - "display_attribute": { - Type: schema.TypeBool, + "identity_attribute": { + Type: schema.TypeString, Optional: true, }, - - "identity_attribute": { - Type: schema.TypeBool, + "native_object_type": { + Type: schema.TypeString, + Optional: true, + }, + "hierarchy_attribute": { + Type: schema.TypeString, Optional: true, }, - "managed": { + "include_permissions": { Type: schema.TypeBool, Optional: true, }, - "minable": { - Type: schema.TypeBool, + "attributes": { + Type: schema.TypeList, Optional: true, + Elem: &schema.Resource{ + Schema: accountSchemaAttributesFields(), + }, }, - "multi": { - Type: schema.TypeBool, + "modified": { + Type: schema.TypeString, Optional: true, }, - "entitlement": { - Type: schema.TypeBool, + "created": { + Type: schema.TypeString, Optional: true, }, } diff --git a/schema_account_schema_attributes.go b/schema_account_schema_attributes.go new file mode 100644 index 0000000..cfaf3d4 --- /dev/null +++ b/schema_account_schema_attributes.go @@ -0,0 +1,46 @@ +package main + +import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + +func accountSchemaAttributesFields() map[string]*schema.Schema { + s := map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "type": { + Type: schema.TypeString, + Optional: true, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + }, + + "schema": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: sourceSchemaFields(), + }, + }, + + "is_group": { + Type: schema.TypeBool, + Optional: true, + }, + + "is_multi_valued": { + Type: schema.TypeBool, + Optional: true, + }, + + "is_entitlement": { + Type: schema.TypeBool, + Optional: true, + }, + } + return s +} diff --git a/structure_account_schema.go b/structure_account_schema.go new file mode 100644 index 0000000..02319a9 --- /dev/null +++ b/structure_account_schema.go @@ -0,0 +1,62 @@ +package main + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +// Flatteners + +func flattenAccountSchema(d *schema.ResourceData, in *AccountSchema) error { + if in == nil { + return nil + } + + d.Set("name", in.ID) + d.Set("name", in.Name) + d.Set("source_id", in.SourceID) + d.Set("schema_id", in.ID) + d.Set("native_object_type", in.NativeObjectType) + d.Set("identity_attribute", in.IdentityAttribute) + d.Set("display_attribute", in.DisplayAttribute) + d.Set("hierarchy_attribute", in.HierarchyAttribute) + d.Set("include_permissions", in.IncludePermissions) + d.Set("modified", in.Modified) + d.Set("created", in.Created) + if in.Attributes != nil { + v, ok := d.Get("attributes").([]interface{}) + if !ok { + v = []interface{}{} + } + + d.Set("attributes", flattenAccountSchemaAttributes(in.Attributes, v)) + } + return nil +} + +// Expanders +func expandAccountSchema(in *schema.ResourceData) (*AccountSchema, error) { + obj := AccountSchema{} + if in == nil { + return nil, fmt.Errorf("[ERROR] Expanding Account Schema: Schema Resource data is nil") + } + if v := in.Id(); len(v) > 0 { + obj.ID = v + } + obj.Name = in.Get("name").(string) + obj.SourceID = in.Get("source_id").(string) + obj.ID = in.Get("schema_id").(string) + obj.NativeObjectType = in.Get("native_object_type").(string) + obj.IdentityAttribute = in.Get("identity_attribute").(string) + obj.DisplayAttribute = in.Get("display_attribute").(string) + obj.HierarchyAttribute = in.Get("hierarchy_attribute").(string) + obj.Modified = in.Get("modified").(string) + obj.Created = in.Get("created").(string) + if v, ok := in.Get("include_permissions").(bool); ok { + obj.IncludePermissions = v + } + if v, ok := in.Get("attributes").([]interface{}); ok && len(v) > 0 { + obj.Attributes = expandAccountSchemaAttributes(v) + } + return &obj, nil +} diff --git a/structure_account_schema_attribute.go b/structure_account_schema_attribute.go index ef633f7..801444e 100644 --- a/structure_account_schema_attribute.go +++ b/structure_account_schema_attribute.go @@ -1,74 +1,67 @@ package main -import ( - "fmt" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" -) - // Flatteners -func flattenAccountSchemaAttribute(d *schema.ResourceData, in *AccountSchemaAttribute) error { +func flattenAccountSchemaAttributes(in []*AccountSchemaAttribute, p []interface{}) []interface{} { if in == nil { - return nil - } - - d.SetId(fmt.Sprintf("%s-%s", in.SourceID, in.Name)) - d.Set("name", in.Name) - d.Set("type", in.Type) - d.Set("object_type", in.ObjectType) - d.Set("source_id", in.SourceID) - d.Set("description", in.Description) - d.Set("display_attribute", in.DisplayAttribute) - d.Set("entitlement", in.Entitlement) - d.Set("identity_attribute", in.IdentityAttribute) - d.Set("managed", in.Managed) - d.Set("minable", in.Minable) - d.Set("multi", in.Multi) - return nil -} - -// Expanders - -func expandAccountSchemaAttribute(in *schema.ResourceData) (*AccountSchemaAttribute, error) { - obj := AccountSchemaAttribute{} - if in == nil { - return nil, fmt.Errorf("[ERROR] Expanding Account Schema Attribute: Schema Resource data is nil") - } - if v := in.Id(); len(v) > 0 { - obj.ID = v - } - - obj.Name = in.Get("name").(string) - obj.Type = in.Get("type").(string) - obj.ObjectType = in.Get("object_type").(string) - obj.SourceID = in.Get("source_id").(string) - obj.Description = in.Get("description").(string) - - if v, ok := in.Get("display_attribute").(bool); ok { - obj.DisplayAttribute = v + return []interface{}{} } - if v, ok := in.Get("entitlement").(bool); ok { - obj.Entitlement = v - } + out := make([]interface{}, 0, len(in)) - if v, ok := in.Get("identity_attribute").(bool); ok { - obj.IdentityAttribute = v + for i := range in { + var obj = make(map[string]interface{}) + obj["name"] = in[i].Name + obj["type"] = in[i].Type + obj["description"] = in[i].Description + obj["is_multi_valued"] = in[i].IsMultiValued + obj["is_entitlement"] = in[i].IsEntitlement + obj["is_group"] = in[i].IsGroup + if in[i].Schema != nil { + v, ok := obj["schema"].([]interface{}) + if !ok { + v = []interface{}{} + } + var newInSchema []*Schema + newInSchema = append(newInSchema, in[i].Schema) + obj["schema"] = flattenSourceSchema(newInSchema, v)[0] + } + out = append(out, obj) } + return out +} - if v, ok := in.Get("managed").(bool); ok { - obj.Managed = v +// Expanders +func expandAccountSchemaAttributes(p []interface{}) []*AccountSchemaAttribute { + if len(p) == 0 || p[0] == nil { + return []*AccountSchemaAttribute{} } + out := make([]*AccountSchemaAttribute, 0, len(p)) + for i := range p { + obj := AccountSchemaAttribute{} + in := p[i].(map[string]interface{}) + obj.Name = in["name"].(string) + obj.Type = in["type"].(string) + obj.Description = in["description"].(string) - if v, ok := in.Get("minable").(bool); ok { - obj.Minable = v - } + if v, ok := in["is_multi_valued"].(bool); ok { + obj.IsMultiValued = v + } + if v, ok := in["is_entitlement"].(bool); ok { + obj.IsEntitlement = v + } - if v, ok := in.Get("multi").(bool); ok { - obj.Multi = v + if v, ok := in["is_group"].(bool); ok { + obj.IsGroup = v + } + if v, ok := in["schema"].(*Schema); ok { + var vList []interface{} + vList[0] = v + obj.Schema = expandSourceSchema(vList)[0] + } } - return &obj, nil + return out } func getAccountSchemaAttribute(accountSchema *AccountSchema, name string) *AccountSchemaAttribute { diff --git a/structure_account_schema_attribute_test.go b/structure_account_schema_attribute_test.go deleted file mode 100644 index cf224cb..0000000 --- a/structure_account_schema_attribute_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package main - -import ( - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "reflect" - "testing" -) - -var ( - testAccountSchemaAttributeConf *AccountSchemaAttribute - testAccountSchemaAttributeInterface map[string]interface{} -) - -func init() { - testAccountSchemaAttributeConf = &AccountSchemaAttribute{ - Description: "test description", - DisplayAttribute: false, - Entitlement: true, - IdentityAttribute: false, - Managed: false, - Minable: false, - Multi: false, - Name: "test", - Type: "string", - ObjectType: "account", - SourceID: "1234", - } - testAccountSchemaAttributeInterface = map[string]interface{}{ - "description": "test description", - "display_attribute": false, - "entitlement": true, - "identity_attribute": false, - "managed": false, - "minable": false, - "multi": false, - "name": "test", - "type": "string", - "object_type": "account", - "source_id": "1234", - } -} - -func TestFlattenAccountSchemaAttribute(t *testing.T) { - cases := []struct { - Input *AccountSchemaAttribute - ExpectedOutput map[string]interface{} - }{ - { - testAccountSchemaAttributeConf, - testAccountSchemaAttributeInterface, - }, - } - for _, tc := range cases { - output := schema.TestResourceDataRaw(t, accountSchemaAttributeFields(), tc.ExpectedOutput) - err := flattenAccountSchemaAttribute(output, tc.Input) - if err != nil { - t.Fatalf("[ERROR] on flattener: %#v", err) - } - expectedOutput := map[string]interface{}{} - for k := range tc.ExpectedOutput { - expectedOutput[k] = output.Get(k) - } - if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { - t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", - tc.ExpectedOutput, expectedOutput) - } - } -} - -func TestExpandAccountSchemaAttribute(t *testing.T) { - cases := []struct { - Input map[string]interface{} - ExpectedOutput *AccountSchemaAttribute - }{ - { - testAccountSchemaAttributeInterface, - testAccountSchemaAttributeConf, - }, - } - - for _, tc := range cases { - inputResourceData := schema.TestResourceDataRaw(t, accountSchemaAttributeFields(), tc.Input) - output, err := expandAccountSchemaAttribute(inputResourceData) - if err != nil { - t.Fatalf("[ERROR] on flattener: %#v", err) - } - if !reflect.DeepEqual(output, tc.ExpectedOutput) { - t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", - tc.ExpectedOutput, output) - } - } -} diff --git a/structure_account_schema_test.go b/structure_account_schema_test.go new file mode 100644 index 0000000..3f94a18 --- /dev/null +++ b/structure_account_schema_test.go @@ -0,0 +1,150 @@ +package main + +import ( + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "reflect" + "testing" +) + +var ( + testAccountSchemaConf *AccountSchema + testAccountSchemaInterface map[string]interface{} +) + +func init() { + testAccountSchemaConf = &AccountSchema{ + DisplayAttribute: "distinguishedName", + IdentityAttribute: "sAMAccountName", + NativeObjectType: "User", + Name: "account", + SourceID: "2c9180835d191a86015d28455b4a2329", + ID: "2c9180835d191a86015d28455b4a1234", + HierarchyAttribute: "memberOf", + IncludePermissions: false, + Created: "2019-12-24T22:32:58.104Z", + Modified: "2019-12-31T20:22:28.104Z", + Attributes: []*AccountSchemaAttribute{ + { + Name: "sAMAccountName", + Type: "STRING", + IsEntitlement: true, + IsGroup: false, + IsMultiValued: false, + }, + { + Name: "employeeId", + Type: "STRING", + IsEntitlement: false, + IsGroup: false, + IsMultiValued: false, + Description: "Employee Id", + }, + { + Name: "memberOf", + Type: "STRING", + Schema: &Schema{ + Type: "CONNECTOR_SCHEMA", + ID: "2c9180887671ff8c01767b4671fc7d60", + Name: "group", + }, + Description: "Group membership", + IsMultiValued: true, + IsEntitlement: true, + IsGroup: true, + }, + }, + } + testAccountSchemaInterface = map[string]interface{}{ + "source_id": "2c9180835d191a86015d28455b4a2329", + "schema_id": "2c9180835d191a86015d28455b4a1234", + "name": "account", + "native_object_type": "User", + "identity_attribute": "sAMAccountName", + "display_attribute": "distinguishedName", + "hierarchy_attribute": "memberOf", + "include_permissions": false, + "attributes": []interface{}{ + map[string]interface{}{ + "name": "sAMAccountName", + "type": "STRING", + "is_multiValued": false, + "is_entitlement": false, + "is_group": false, + }, + map[string]interface{}{ + "name": "employeeId", + "type": "STRING", + "is_multi_valued": false, + "is_entitlement": false, + "is_group": false, + "description": "Employee ID", + }, + map[string]interface{}{ + "name": "memberOf", + "type": "STRING", + "schema": map[string]interface{}{ + "type": "CONNECTOR_SCHEMA", + "id": "2c9180887671ff8c01767b4671fc7d60", + "name": "group", + }, + "description": "Group membership", + "is_multi_valued": true, + "is_entitlement": true, + "is_group": true, + }, + }, + "created": "2019-12-24T22:32:58.104Z", + "modified": "2019-12-31T20:22:28.104Z", + } +} + +func TestFlattenAccountSchemaAttribute(t *testing.T) { + cases := []struct { + Input *AccountSchema + ExpectedOutput map[string]interface{} + }{ + { + testAccountSchemaConf, + testAccountSchemaInterface, + }, + } + for _, tc := range cases { + output := schema.TestResourceDataRaw(t, accountSchemaFields(), tc.ExpectedOutput) + err := flattenAccountSchema(output, tc.Input) + if err != nil { + t.Fatalf("[ERROR] on flattener: %#v", err) + } + expectedOutput := map[string]interface{}{} + for k := range tc.ExpectedOutput { + expectedOutput[k] = output.Get(k) + } + if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { + t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", + tc.ExpectedOutput, expectedOutput) + } + } +} + +func TestExpandAccountSchemaAttribute(t *testing.T) { + cases := []struct { + Input map[string]interface{} + ExpectedOutput *AccountSchema + }{ + { + testAccountSchemaInterface, + testAccountSchemaConf, + }, + } + + for _, tc := range cases { + inputResourceData := schema.TestResourceDataRaw(t, accountSchemaFields(), tc.Input) + output, err := expandAccountSchema(inputResourceData) + if err != nil { + t.Fatalf("[ERROR] on flattener: %#v", err) + } + if !reflect.DeepEqual(output, tc.ExpectedOutput) { + t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", + tc.ExpectedOutput, output) + } + } +} diff --git a/structure_role.go b/structure_role.go index 4faad68..7cca053 100644 --- a/structure_role.go +++ b/structure_role.go @@ -27,12 +27,12 @@ func flattenRole(d *schema.ResourceData, in *Role) error { d.Set("owner", flattenObjectRole(in.RoleOwner, v)) } if in.AccessProfiles != nil { - v, ok := d.Get("schemas").([]interface{}) + v, ok := d.Get("access_profiles").([]interface{}) if !ok { v = []interface{}{} } - d.Set("schemas", flattenObjectRoles(in.AccessProfiles, v)) + d.Set("access_profiles", flattenObjectRoles(in.AccessProfiles, v)) } return nil } diff --git a/type_account_schema.go b/type_account_schema.go index 336a594..39a5904 100644 --- a/type_account_schema.go +++ b/type_account_schema.go @@ -1,25 +1,27 @@ package main type AccountSchema struct { - Attributes []*AccountSchemaAttribute `json:"attributes,omitempty"` - DisplayAttribute string `json:"displayAttribute,omitempty"` - GroupAttribute string `json:"groupAttribute,omitempty"` - IdentityAttribute string `json:"identityAttribute,omitempty"` - NativeObjectType string `json:"nativeObjectType,omitempty"` - ObjectType string `json:"objectType,omitempty"` + Attributes []*AccountSchemaAttribute `json:"attributes,omitempty"` + DisplayAttribute string `json:"displayAttribute,omitempty"` + IdentityAttribute string `json:"identityAttribute,omitempty"` + NativeObjectType string `json:"nativeObjectType,omitempty"` + Features []interface{} `json:"features,omitempty"` + Configuration interface{} `json:"configuration,omitempty"` + HierarchyAttribute string `json:"hierarchyAttribute,omitempty"` + IncludePermissions bool `json:"includePermissions,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Created string `json:"created,omitempty"` + Modified string `json:"modified,omitempty"` + SourceID string `json:"sourceId,omitempty"` } type AccountSchemaAttribute struct { - ID string `json:"id,omitempty"` - Description string `json:"description,omitempty"` - DisplayAttribute bool `json:"displayAttribute,omitempty"` - Entitlement bool `json:"entitlement,omitempty"` - IdentityAttribute bool `json:"identityAttribute,omitempty"` - Managed bool `json:"managed,omitempty"` - Minable bool `json:"minable,omitempty"` - Multi bool `json:"multi,omitempty"` - Name string `json:"name"` - Type string `json:"type,omitempty"` - ObjectType string `json:"objectType"` - SourceID string `json:"sourceId,omitempty"` + Description string `json:"description,omitempty"` + IsEntitlement bool `json:"isEntitlement,omitempty"` + IsMultiValued bool `json:"isMultiValued,omitempty"` + IsGroup bool `json:"isGroup,omitempty"` + Name string `json:"name"` + Type string `json:"type,omitempty"` + Schema *Schema `json:"schema,omitempty"` } diff --git a/util.go b/util.go index a58ad9b..3d1ab4f 100644 --- a/util.go +++ b/util.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "net/url" - "strings" ) func toArrayInterface(in []string) []interface{} { @@ -27,16 +26,6 @@ func toArrayString(in []interface{}) []string { return out } -func splitAccountSchemaAttributeID(id string) (sourceId string, name string, err error) { - separator := "-" - - result := strings.Split(id, separator) - if len(result) == 2 { - return result[0], result[1], nil - } - return "", "", fmt.Errorf("[ERROR Getting source id and name. id: %s", id) -} - func setPasswordPolicyUrlValues(attributes *PasswordPolicy) (url.Values, error) { data := url.Values{} data.Set("name", attributes.Name) From e3416bd77db109d4059794af6ed09ccbb7be5d11 Mon Sep 17 00:00:00 2001 From: eamouhadi Date: Thu, 10 Aug 2023 09:57:07 -0700 Subject: [PATCH 3/5] fix unit tests --- data_source_role.go | 2 +- schema_role.go | 2 +- structure_account_schema_attribute.go | 49 +++++++++++++++++++++----- structure_account_schema_test.go | 45 +++++++++++++----------- structure_role.go | 50 ++++++--------------------- structure_role_test.go | 34 +++++++++--------- type_account_schema.go | 20 +++++++---- 7 files changed, 109 insertions(+), 93 deletions(-) diff --git a/data_source_role.go b/data_source_role.go index c95e83e..f05f4e2 100644 --- a/data_source_role.go +++ b/data_source_role.go @@ -15,7 +15,7 @@ func dataSourceRole() *schema.Resource { Type: schema.TypeString, Required: true, }, - "accessProfiles": { + "access_profiles": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ diff --git a/schema_role.go b/schema_role.go index 03ff02c..86e98c5 100644 --- a/schema_role.go +++ b/schema_role.go @@ -23,7 +23,7 @@ func roleFields() map[string]*schema.Schema { Schema: sourceOwnerFields(), }, }, - "accessProfiles": { + "access_profiles": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ diff --git a/structure_account_schema_attribute.go b/structure_account_schema_attribute.go index 801444e..ba19099 100644 --- a/structure_account_schema_attribute.go +++ b/structure_account_schema_attribute.go @@ -22,15 +22,32 @@ func flattenAccountSchemaAttributes(in []*AccountSchemaAttribute, p []interface{ if !ok { v = []interface{}{} } - var newInSchema []*Schema - newInSchema = append(newInSchema, in[i].Schema) - obj["schema"] = flattenSourceSchema(newInSchema, v)[0] + obj["schema"] = flattenAccountSchemaAttributesSchema(in[i].Schema, v) } out = append(out, obj) } return out } +func flattenAccountSchemaAttributesSchema(in *AccountSchemaAttributeSchema, p []interface{}) interface{} { + var obj map[string]interface{} + if len(p) == 0 || p[0] == nil { + obj = make(map[string]interface{}) + } else { + obj = p[0].(map[string]interface{}) + } + + if in == nil { + return []interface{}{} + } + + obj["type"] = in.Type + obj["id"] = in.ID + obj["name"] = in.Name + + return []interface{}{obj} +} + // Expanders func expandAccountSchemaAttributes(p []interface{}) []*AccountSchemaAttribute { if len(p) == 0 || p[0] == nil { @@ -42,7 +59,9 @@ func expandAccountSchemaAttributes(p []interface{}) []*AccountSchemaAttribute { in := p[i].(map[string]interface{}) obj.Name = in["name"].(string) obj.Type = in["type"].(string) - obj.Description = in["description"].(string) + if v, ok := in["description"].(string); ok { + obj.Description = v + } if v, ok := in["is_multi_valued"].(bool); ok { obj.IsMultiValued = v @@ -54,16 +73,30 @@ func expandAccountSchemaAttributes(p []interface{}) []*AccountSchemaAttribute { if v, ok := in["is_group"].(bool); ok { obj.IsGroup = v } - if v, ok := in["schema"].(*Schema); ok { - var vList []interface{} - vList[0] = v - obj.Schema = expandSourceSchema(vList)[0] + if v, ok := in["schema"].([]interface{}); ok && len(v) > 0 { + obj.Schema = expandAccountSchemaAttributesSchema(v) } + out = append(out, &obj) } return out } +func expandAccountSchemaAttributesSchema(p []interface{}) *AccountSchemaAttributeSchema { + obj := AccountSchemaAttributeSchema{} + + if len(p) == 0 || p[0] == nil { + return &obj + } + in := p[0].(map[string]interface{}) + + obj.ID = in["id"].(string) + obj.Name = in["name"].(string) + obj.Type = in["type"].(string) + + return &obj +} + func getAccountSchemaAttribute(accountSchema *AccountSchema, name string) *AccountSchemaAttribute { attributes := accountSchema.Attributes for i := range attributes { diff --git a/structure_account_schema_test.go b/structure_account_schema_test.go index 3f94a18..5e872d9 100644 --- a/structure_account_schema_test.go +++ b/structure_account_schema_test.go @@ -37,20 +37,20 @@ func init() { IsEntitlement: false, IsGroup: false, IsMultiValued: false, - Description: "Employee Id", + Description: "Employee ID", }, { - Name: "memberOf", - Type: "STRING", - Schema: &Schema{ - Type: "CONNECTOR_SCHEMA", - ID: "2c9180887671ff8c01767b4671fc7d60", - Name: "group", - }, + Name: "memberOf", + Type: "STRING", Description: "Group membership", IsMultiValued: true, IsEntitlement: true, IsGroup: true, + Schema: &AccountSchemaAttributeSchema{ + Type: "CONNECTOR_SCHEMA", + ID: "2c9180887671ff8c01767b4671fc7d60", + Name: "group", + }, }, }, } @@ -65,11 +65,13 @@ func init() { "include_permissions": false, "attributes": []interface{}{ map[string]interface{}{ - "name": "sAMAccountName", - "type": "STRING", - "is_multiValued": false, - "is_entitlement": false, - "is_group": false, + "name": "sAMAccountName", + "type": "STRING", + "is_multi_valued": false, + "is_entitlement": true, + "is_group": false, + "description": "", + "schema": []interface{}{}, }, map[string]interface{}{ "name": "employeeId", @@ -78,19 +80,22 @@ func init() { "is_entitlement": false, "is_group": false, "description": "Employee ID", + "schema": []interface{}{}, }, map[string]interface{}{ - "name": "memberOf", - "type": "STRING", - "schema": map[string]interface{}{ - "type": "CONNECTOR_SCHEMA", - "id": "2c9180887671ff8c01767b4671fc7d60", - "name": "group", - }, + "name": "memberOf", + "type": "STRING", "description": "Group membership", "is_multi_valued": true, "is_entitlement": true, "is_group": true, + "schema": []interface{}{ + map[string]interface{}{ + "type": "CONNECTOR_SCHEMA", + "id": "2c9180887671ff8c01767b4671fc7d60", + "name": "group", + }, + }, }, }, "created": "2019-12-24T22:32:58.104Z", diff --git a/structure_role.go b/structure_role.go index 7cca053..7499caa 100644 --- a/structure_role.go +++ b/structure_role.go @@ -19,12 +19,12 @@ func flattenRole(d *schema.ResourceData, in *Role) error { d.Set("enabled", in.Enabled) if in.RoleOwner != nil { - v, ok := d.Get("owner").(interface{}) + v, ok := d.Get("owner").([]interface{}) if !ok { v = []interface{}{} } - - d.Set("owner", flattenObjectRole(in.RoleOwner, v)) + roleOwnerList := []*ObjectInfo{in.RoleOwner} + d.Set("owner", flattenObjectRoles(roleOwnerList, v)) } if in.AccessProfiles != nil { v, ok := d.Get("access_profiles").([]interface{}) @@ -37,24 +37,6 @@ func flattenRole(d *schema.ResourceData, in *Role) error { return nil } -func flattenObjectRole(in *ObjectInfo, p interface{}) interface{} { - var obj map[string]interface{} - if p == nil { - obj = make(map[string]interface{}) - } else { - obj = p.(map[string]interface{}) - } - - if in == nil { - return []interface{}{} - } - obj["type"] = in.Type - obj["id"] = in.ID - obj["name"] = in.Name - - return []interface{}{obj} -} - func flattenObjectRoles(in []*ObjectInfo, p []interface{}) []interface{} { if in == nil { return []interface{}{} @@ -90,10 +72,10 @@ func expandRole(in *schema.ResourceData) (*Role, error) { } if v, ok := in.Get("owner").([]interface{}); ok && len(v) > 0 { - obj.RoleOwner = expandObjectRole(v) + obj.RoleOwner = expandObjectRoles(v)[0] } - if v, ok := in.Get("accessProfiles").([]interface{}); ok && len(v) > 0 { + if v, ok := in.Get("access_profiles").([]interface{}); ok && len(v) > 0 { obj.AccessProfiles = expandObjectRoles(v) } @@ -130,30 +112,18 @@ func expandUpdateRole(in *schema.ResourceData) ([]*UpdateRole, interface{}, erro return out, id, nil } -func expandObjectRole(p interface{}) *ObjectInfo { - obj := ObjectInfo{} - - if p == nil { - return &obj - } - in := p.(map[string]interface{}) - - obj.ID = in["id"].(string) - obj.Name = in["name"].(string) - obj.Type = in["type"].(string) - - return &obj -} - func expandObjectRoles(p []interface{}) []*ObjectInfo { if len(p) == 0 || p[0] == nil { return []*ObjectInfo{} } out := make([]*ObjectInfo, 0, len(p)) for i := range p { + obj := ObjectInfo{} in := p[i].(map[string]interface{}) - obj := expandObjectRole(in) - out = append(out, obj) + obj.ID = in["id"].(string) + obj.Name = in["name"].(string) + obj.Type = in["type"].(string) + out = append(out, &obj) } return out } diff --git a/structure_role_test.go b/structure_role_test.go index a1f8d89..31ddc0a 100644 --- a/structure_role_test.go +++ b/structure_role_test.go @@ -38,22 +38,24 @@ func init() { Requestable: &FALSE, } testRoleInterface = map[string]interface{}{ - //"accessProfiles": []map[string]interface{}{ - // { - // "id": "2c918088747654398948078d29f2e46", - // "name": "Test Developer", - // "type": "ACCESS_PROFILE", - // }, - // { - // "id": "2c918009437654398948078d29f2e46", - // "name": "Test Operator", - // "type": "ACCESS_PROFILE", - // }, - //}, - "owner": map[string]interface{}{ - "id": "2c9180887412345678948078d29f2e46", - "name": "SRE Test", - "type": "IDENTITY", + "access_profiles": []interface{}{ + map[string]interface{}{ + "id": "2c918088747654398948078d29f2e46", + "name": "Test Developer", + "type": "ACCESS_PROFILE", + }, + map[string]interface{}{ + "id": "2c918009437654398948078d29f2e46", + "name": "Test Operator", + "type": "ACCESS_PROFILE", + }, + }, + "owner": []interface{}{ + map[string]interface{}{ + "id": "2c9180887412345678948078d29f2e46", + "name": "SRE Test", + "type": "IDENTITY", + }, }, "description": "test description", "enabled": true, diff --git a/type_account_schema.go b/type_account_schema.go index 39a5904..6661c85 100644 --- a/type_account_schema.go +++ b/type_account_schema.go @@ -17,11 +17,17 @@ type AccountSchema struct { } type AccountSchemaAttribute struct { - Description string `json:"description,omitempty"` - IsEntitlement bool `json:"isEntitlement,omitempty"` - IsMultiValued bool `json:"isMultiValued,omitempty"` - IsGroup bool `json:"isGroup,omitempty"` - Name string `json:"name"` - Type string `json:"type,omitempty"` - Schema *Schema `json:"schema,omitempty"` + Description string `json:"description,omitempty"` + IsEntitlement bool `json:"isEntitlement,omitempty"` + IsMultiValued bool `json:"isMultiValued,omitempty"` + IsGroup bool `json:"isGroup,omitempty"` + Name string `json:"name"` + Type string `json:"type,omitempty"` + Schema *AccountSchemaAttributeSchema `json: "schema,omitempty"` +} + +type AccountSchemaAttributeSchema struct { + Type string `json:"type,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` } From e96789a09b95e68d95e031839ebadeed1a41d3a3 Mon Sep 17 00:00:00 2001 From: eamouhadi Date: Sun, 10 Sep 2023 22:11:54 -0700 Subject: [PATCH 4/5] update account schema api --- client.go | 61 ++++++++++++++++++++++--------------- resource_account_schema.go | 35 ++++++++++++++------- structure_account_schema.go | 5 ++- type_account_schema.go | 2 +- type_entitlement.go | 1 - 5 files changed, 65 insertions(+), 39 deletions(-) diff --git a/client.go b/client.go index fad5b47..88d8f2a 100644 --- a/client.go +++ b/client.go @@ -175,7 +175,7 @@ func (c *Client) GetAccessProfile(ctx context.Context, id string) (*AccessProfil } func (c *Client) GetSourceEntitlements(ctx context.Context, id string) ([]*SourceEntitlement, error) { - req, err := http.NewRequest("GET", fmt.Sprintf("%s/beta/entitlement?filters=source.id eq \"%s\"", c.BaseURL, id), nil) + req, err := http.NewRequest("GET", fmt.Sprintf("%s/beta/entitlements?filters=source.id", c.BaseURL)+url.QueryEscape(" eq ")+fmt.Sprintf("\"%s\"", id), nil) if err != nil { log.Printf("Creation of new http request failed: %+v\n", err) return nil, err @@ -446,34 +446,45 @@ func (c *Client) GetAccountSchema(ctx context.Context, sourceId string, id strin log.Fatal(err) return nil, err } + res.SourceID = sourceId return &res, nil } -func (c *Client) CreateAccountSchema(ctx context.Context, accountSchema *AccountSchema) (*AccountSchema, error) { - body, err := json.Marshal(&accountSchema) - if err != nil { - return nil, err - } - req, err := http.NewRequest("POST", fmt.Sprintf("%s/v3/sources/%s/schemas", c.BaseURL, accountSchema.SourceID), bytes.NewBuffer(body)) - if err != nil { - log.Printf("New request failed:%+v\n", err) - return nil, err - } - - req.Header.Set("Content-Type", "application/json; charset=utf-8") - req.Header.Set("Accept", "application/json; charset=utf-8") - - req = req.WithContext(ctx) - res := AccountSchema{} - if err := c.sendRequest(req, &res); err != nil { - log.Printf("Failed Account Schema Attribute creation. response:%+v\n", res) - log.Fatal(err) - return nil, err - } - - return &res, nil -} +//func (c *Client) CreateAccountSchema(ctx context.Context, accountSchema *AccountSchema) (*AccountSchema, error) { +//for _, value := range updateAccountSchema { +// log.Printf("arrBody: %+v, value: %+v", value, value.Value) +//} +//log.Printf("arrBody type: %+v", reflect.TypeOf(updateAccountSchema)) +//body, err := json.Marshal(&updateAccountSchema) +//log.Printf("body: %+v", string(body)) +// +//if err != nil { +// return nil, err +//} +//req, err := http.NewRequest("PATCH", fmt.Sprintf("%s/v3/sources/%s/schemas/%s", c.BaseURL, sourceId, schemaId), bytes.NewBuffer(body)) +//if err != nil { +// log.Printf("New request failed:%+v\n", err) +// return nil, err +//} +// +//req.Header.Set("Content-Type", "application/json-patch+json; charset=utf-8") +//req.Header.Set("Accept", "application/json; charset=utf-8") +// +//req = req.WithContext(ctx) +//res := AccountSchema{} +//if err := c.sendRequest(req, &res); err != nil { +// log.Printf("get body: %+v\n", req.GetBody) +// +// log.Printf("Failed Account Schema Attribute creation. response:%+v\n", res) +// log.Fatal(err) +// return nil, err +//} +//for _, value := range updateAccountSchema { +// log.Printf("arrBody: %+v, value: %+v", value, value.Value) +//} +//return &res, nil +//} func (c *Client) UpdateAccountSchema(ctx context.Context, accountSchema *AccountSchema) (*AccountSchema, error) { body, err := json.Marshal(&accountSchema) diff --git a/resource_account_schema.go b/resource_account_schema.go index 6c81577..a88d53e 100644 --- a/resource_account_schema.go +++ b/resource_account_schema.go @@ -22,26 +22,40 @@ func resourceAccountSchema() *schema.Resource { } func resourceAccountSchemaCreate(d *schema.ResourceData, m interface{}) error { - attribute, err := expandAccountSchema(d) + accountSchema, err := expandAccountSchema(d) if err != nil { return err } - log.Printf("[INFO] Creating Account Schema Attribute %s", attribute.Name) + log.Printf("[INFO] Creating Account Schema Attribute %v", accountSchema.Attributes) client, err := m.(*Config).IdentityNowClient() if err != nil { return err } - - newAttribute, err := client.CreateAccountSchema(context.Background(), attribute) + newAccountSchema, err := client.GetAccountSchema(context.Background(), accountSchema.SourceID, accountSchema.ID) + if err != nil { + // non-panicking type assertion, 2nd arg is boolean indicating type match + _, notFound := err.(*NotFoundError) + if notFound { + log.Printf("Source ID %s not found.", accountSchema.SourceID) + d.SetId("") + return nil + } + return err + } + newAccountSchema.SourceID = accountSchema.SourceID + for i := range accountSchema.Attributes { + newAccountSchema.Attributes = append(newAccountSchema.Attributes, accountSchema.Attributes[i]) + } + accountSchemaResponse, err := client.UpdateAccountSchema(context.Background(), newAccountSchema) if err != nil { return err } - newAttribute.SourceID = attribute.SourceID + accountSchemaResponse.SourceID = accountSchema.SourceID - err = flattenAccountSchema(d, newAttribute) + err = flattenAccountSchema(d, accountSchemaResponse) if err != nil { return err } @@ -76,7 +90,6 @@ func resourceAccountSchemaRead(d *schema.ResourceData, m interface{}) error { } accountSchema.SourceID = sourceId - err = flattenAccountSchema(d, accountSchema) if err != nil { return err @@ -86,18 +99,18 @@ func resourceAccountSchemaRead(d *schema.ResourceData, m interface{}) error { } func resourceAccountSchemaUpdate(d *schema.ResourceData, m interface{}) error { - log.Printf("[INFO] Updating %s for Account Schema for source ID %s", d.Get("name").(string), d.Get("source_id").(string)) - client, err := m.(*Config).IdentityNowClient() + updatedAccountSchema, err := expandAccountSchema(d) if err != nil { return err } - updatedAttribute, err := expandAccountSchema(d) + log.Printf("[INFO] Updating %s for Account Schema for source ID %s", d.Get("name").(string), d.Get("source_id").(string)) + client, err := m.(*Config).IdentityNowClient() if err != nil { return err } - _, err = client.UpdateAccountSchema(context.Background(), updatedAttribute) + _, err = client.UpdateAccountSchema(context.Background(), updatedAccountSchema) if err != nil { return err } diff --git a/structure_account_schema.go b/structure_account_schema.go index 02319a9..8cae5b5 100644 --- a/structure_account_schema.go +++ b/structure_account_schema.go @@ -3,6 +3,7 @@ package main import ( "fmt" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "log" ) // Flatteners @@ -12,7 +13,7 @@ func flattenAccountSchema(d *schema.ResourceData, in *AccountSchema) error { return nil } - d.Set("name", in.ID) + d.SetId(in.ID) d.Set("name", in.Name) d.Set("source_id", in.SourceID) d.Set("schema_id", in.ID) @@ -31,6 +32,8 @@ func flattenAccountSchema(d *schema.ResourceData, in *AccountSchema) error { d.Set("attributes", flattenAccountSchemaAttributes(in.Attributes, v)) } + + log.Printf("d *schema.ResourceData in flatten: %+v", d) return nil } diff --git a/type_account_schema.go b/type_account_schema.go index 6661c85..c1ce363 100644 --- a/type_account_schema.go +++ b/type_account_schema.go @@ -23,7 +23,7 @@ type AccountSchemaAttribute struct { IsGroup bool `json:"isGroup,omitempty"` Name string `json:"name"` Type string `json:"type,omitempty"` - Schema *AccountSchemaAttributeSchema `json: "schema,omitempty"` + Schema *AccountSchemaAttributeSchema `json:"schema,omitempty"` } type AccountSchemaAttributeSchema struct { diff --git a/type_entitlement.go b/type_entitlement.go index bb87971..ef28248 100644 --- a/type_entitlement.go +++ b/type_entitlement.go @@ -13,7 +13,6 @@ type SourceEntitlement struct { Owner interface{} `json:"owner,omitempty"` DirectPermissions []interface{} `json:"directPermissions,omitempty"` Segments []interface{} `json:"segments,omitempty"` - ManuallyUpdatedFields []interface{} `json:"manuallyUpdatedFields,omitempty"` Modified interface{} `json:"modified,omitempty"` Created interface{} `json:"created,omitempty"` ID string `json:"id"` From e5c574f4f9214d266c7a8ed181a3a2f6288b63e5 Mon Sep 17 00:00:00 2001 From: eamouhadi Date: Mon, 11 Sep 2023 09:38:08 -0700 Subject: [PATCH 5/5] update CHANGELOG.md --- CHANGELOG.md | 3 +++ scripts/build.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88b594c..17ba764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.4.0 +* upgrade: upgrade cc api +* ## 0.3.4 BUG FIXES: diff --git a/scripts/build.sh b/scripts/build.sh index ec1a6a6..01ad07e 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -6,7 +6,7 @@ set -euo pipefail # TF will not longer attempt to look for any versions of this provider on the remote registry. # When finished with development, you can remove the folder from your laptop to start using the public provider again. # https://www.terraform.io/docs/commands/cli-config.html#implied-local-mirror-directories -VERSION=0.3.1 +VERSION=0.4.1 go build -o terraform-provider-identitynow mkdir -p ~/.terraform.d/plugins/registry.terraform.io/openaxon/identitynow/${VERSION}/darwin_amd64 mv terraform-provider-identitynow ~/.terraform.d/plugins/registry.terraform.io/openaxon/identitynow/${VERSION}/darwin_amd64/terraform-provider-identitynow_v${VERSION} \ No newline at end of file