├── .github ├── ISSUE_TEMPLATE │ ├── Bug_Report.yml │ ├── Feature_Request.yml │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── go.yml │ └── release.yml ├── .gitignore ├── .goreleaser.yml ├── CHANGELOG.md ├── GNUmakefile ├── LICENSE ├── README.md ├── client.go ├── config.go ├── data_source_Identity.go ├── data_source_access_profile.go ├── data_source_role.go ├── data_source_source.go ├── data_source_source_entitlements.go ├── error_not_found.go ├── examples ├── README.md ├── active_directory_source.tf ├── aws_iam_source.tf ├── azure_active_directory_source.tf ├── data.tf ├── provider.tf ├── role_and_access_profile.tf └── variables.tf ├── go.mod ├── go.sum ├── import_account_schema_attribute.go ├── import_resource_role.go ├── import_resource_source.go ├── main.go ├── provider.go ├── provider_test.go ├── resource_access_profile.go ├── resource_access_profile_test.go ├── resource_account_schema.go ├── resource_password_policy.go ├── resource_role.go ├── resource_role_test.go ├── resource_schedule_account_aggregation.go ├── resource_source.go ├── resource_source_test.go ├── schema_Identity.go ├── schema_access_profile.go ├── schema_account_aggregation_schedule.go ├── schema_account_schema.go ├── schema_account_schema_attributes.go ├── schema_password_policy.go ├── schema_password_policy_connected_services.go ├── schema_role.go ├── schema_role_access_profiles.go ├── schema_source.go ├── schema_source_account_correlation_config.go ├── schema_source_cluster.go ├── schema_source_connector_attributes.go ├── schema_source_domain_settings.go ├── schema_source_entitlement.go ├── schema_source_forest_settings.go ├── schema_source_group_search_dns.go ├── schema_source_management_workgroup.go ├── schema_source_owner.go ├── schema_source_password_policies.go ├── schema_source_schema.go ├── schema_source_search_dns.go ├── scripts ├── build.sh ├── gotestacc.sh └── gotestacc_vars.sh ├── structure_Identity.go ├── structure_access_profile.go ├── structure_access_profile_test.go ├── structure_account_aggregation_schedule.go ├── structure_account_aggregation_schedule_test.go ├── structure_account_schema.go ├── structure_account_schema_attribute.go ├── structure_account_schema_test.go ├── structure_identity_test.go ├── structure_password_policy.go ├── structure_password_policy_connected_services.go ├── structure_password_policy_connected_services_test.go ├── structure_password_policy_test.go ├── structure_role.go ├── structure_role_test.go ├── structure_source.go ├── structure_source_account_correlation_config.go ├── structure_source_account_correlation_config_test.go ├── structure_source_cluster.go ├── structure_source_cluster_test.go ├── structure_source_connector_attributes.go ├── structure_source_connector_attributes_test.go ├── structure_source_domain_settings.go ├── structure_source_domain_settings_test.go ├── structure_source_entitlement.go ├── structure_source_entitlement_test.go ├── structure_source_forest_settings.go ├── structure_source_forest_settings_test.go ├── structure_source_group_search_dns.go ├── structure_source_group_search_dns_test.go ├── structure_source_management_workgroup.go ├── structure_source_management_workgroup_test.go ├── structure_source_owner.go ├── structure_source_owner_test.go ├── structure_source_password_policies.go ├── structure_source_password_policies_test.go ├── structure_source_schema_test.go ├── structure_source_schemas.go ├── structure_source_search_dns.go ├── structure_source_search_dns_test.go ├── structure_source_test.go ├── type_Identity.go ├── type_access_profile.go ├── type_account_aggregaion_schedule.go ├── type_account_schema.go ├── type_entitlement.go ├── type_oauth_token.go ├── type_password_policy.go ├── type_role.go ├── type_source.go ├── util.go └── website ├── allowed-subcategories └── docs ├── d └── source.html.markdown ├── index.html.markdown └── r └── source.html.markdown /.github/ISSUE_TEMPLATE/Bug_Report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: If something isn't working as expected. 3 | labels: [bug] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for taking the time to fill out a bug report. 9 | 10 | If you are not running the latest version of Terraform or the provider, please upgrade because your issue may have already been fixed. [Terraform documentation on provider versioning](https://www.terraform.io/docs/configuration/providers.html#provider-versions). 11 | 12 | Please also note the following potential times when an issue might be in Terraform core: 13 | 14 | * [Configuration Language](https://www.terraform.io/docs/configuration/index.html) or resource ordering issues 15 | * [State](https://www.terraform.io/docs/state/index.html) and [State Backend](https://www.terraform.io/docs/backends/index.html) issues 16 | * [Provisioner](https://www.terraform.io/docs/provisioners/index.html) issues 17 | * [Registry](https://registry.terraform.io/) issues 18 | * Spans resources across multiple providers 19 | 20 | If you are running into one of these scenarios, we recommend opening an issue in the [Terraform core repository](https://github.com/hashicorp/terraform/) instead. 21 | - type: checkboxes 22 | attributes: 23 | label: Is there an existing issue for this? 24 | description: Please search to see if an issue already exists for the bug you encountered. 25 | options: 26 | - label: I have searched the existing issues 27 | required: true 28 | - type: textarea 29 | id: community 30 | attributes: 31 | label: Community Note 32 | description: This note is for the community, please leave and skip this. 33 | value: | 34 | 35 | 36 | * Please vote on this issue by adding a :thumbsup: [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request 37 | * Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request 38 | * If you are interested in working on this issue or have submitted a pull request, please leave a comment 39 | 40 | 41 | validations: 42 | required: true 43 | - type: input 44 | id: terraform 45 | attributes: 46 | label: Terraform Version 47 | description: Which Terraform version are you using? 48 | placeholder: 1.0.0 49 | validations: 50 | required: true 51 | - type: input 52 | id: identitynow 53 | attributes: 54 | label: IdentityNow Provider Version 55 | description: Which IdentityNow Provider version are you using? 56 | placeholder: 0.3.1 57 | validations: 58 | required: true 59 | - type: input 60 | id: resource 61 | attributes: 62 | label: Affected Resource(s)/Data Source(s) 63 | description: Please list the affected resources and/or data sources. 64 | placeholder: identitynow_XXXXX 65 | validations: 66 | required: true 67 | - type: textarea 68 | id: config 69 | attributes: 70 | label: Terraform Configuration Files 71 | description: | 72 | Please provide a minimal Terraform configuration that can reproduce the issue. 73 | 74 | For large Terraform configs, please use a service like Dropbox and share a link to the ZIP file. 75 | For security, you can also encrypt the files using our GPG public key: https://keybase.io/hashicorp 76 | render: hcl 77 | validations: 78 | required: true 79 | - type: textarea 80 | id: debug 81 | attributes: 82 | label: Debug Output/Panic Output 83 | description: | 84 | For long debug logs please provide a link to a GitHub Gist containing the complete debug output. Please do NOT paste the debug output in the issue; just paste a link to the Gist. 85 | 86 | To obtain the debug output, see the [Terraform documentation on debugging](https://www.terraform.io/docs/internals/debugging.html). 87 | render: shell 88 | validations: 89 | required: true 90 | - type: textarea 91 | id: expected 92 | attributes: 93 | label: Expected Behaviour 94 | description: What should have happened? 95 | - type: textarea 96 | id: actual 97 | attributes: 98 | label: Actual Behaviour 99 | description: What actually happened? 100 | - type: textarea 101 | id: reproduce 102 | attributes: 103 | label: Steps to Reproduce 104 | description: | 105 | Please list the steps required to reproduce the issue, e.g. 106 | 107 | 1. `terraform apply` 108 | - type: textarea 109 | id: references 110 | attributes: 111 | label: References 112 | description: | 113 | Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests 114 | 115 | Are there any other GitHub issues (open or closed) or pull requests that should be linked here? Such as vendor documentation? -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_Request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: I have a suggestion (and might want to implement myself)! 3 | title: "Support for [thing]" 4 | body: 5 | - type: checkboxes 6 | attributes: 7 | label: Is there an existing issue for this? 8 | description: Please search to see if an issue already exists for the feature you are requesting. 9 | options: 10 | - label: I have searched the existing issues 11 | required: true 12 | - type: textarea 13 | id: community 14 | attributes: 15 | label: Community Note 16 | description: This note is for the community, please leave and skip this. 17 | value: | 18 | 19 | 20 | * Please vote on this issue by adding a :thumbsup: [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request 21 | * Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request 22 | * If you are interested in working on this issue or have submitted a pull request, please leave a comment 23 | 24 | 25 | validations: 26 | required: true 27 | - type: textarea 28 | id: description 29 | attributes: 30 | label: Description 31 | description: Please leave a helpful description of the feature request here. 32 | validations: 33 | required: true 34 | - type: input 35 | id: resource 36 | attributes: 37 | label: New or Affected Resource(s)/Data Source(s) 38 | description: Please list the new or affected resources and/or data sources. 39 | placeholder: identitynow_XXXXX 40 | validations: 41 | required: true 42 | - type: textarea 43 | id: config 44 | attributes: 45 | label: Potential Terraform Configuration 46 | description: Please provide an example of what the new resource or enhancement could look like in a Terraform config. 47 | render: hcl 48 | - type: textarea 49 | id: references 50 | attributes: 51 | label: References 52 | description: | 53 | Information about referencing Github Issues: https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests 54 | 55 | Are there any other GitHub issues (open or closed) or pull requests that should be linked here? Vendor blog posts or documentation? For example: 56 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Which issue this PR fixes / why we need it 2 | 3 | *(optional, in `fixes #(, fixes #, ...)` format, will close that issue when PR gets merged)* 4 | 5 | - fixes # 6 | 7 | ### Checklist 8 | 9 | - [ ] README.md was updated 10 | - [ ] CHANGELOG.md was updated -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | build: 12 | name: Build 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.x 17 | uses: actions/setup-go@v4 18 | with: 19 | go-version: ^1.20 20 | 21 | - name: Check out code into the Go module directory 22 | uses: actions/checkout@v3 23 | 24 | - name: Get dependencies 25 | run: | 26 | go get -v -t -d ./... 27 | if [ -f Gopkg.toml ]; then 28 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 29 | dep ensure 30 | fi 31 | 32 | - name: Build 33 | run: go build -v ./... 34 | 35 | - name: Test 36 | run: go test -v ./... 37 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action can publish assets for release when a tag is created. 2 | # Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # This uses an action (paultyng/ghaction-import-gpg) that assumes you set your 5 | # private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE` 6 | # secret. If you would rather own your own GPG handling, please fork this action 7 | # or use an alternative one for key handling. 8 | # 9 | # You will need to pass the `--batch` flag to `gpg` in your signing step 10 | # in `goreleaser` to indicate this is being used in a non-interactive mode. 11 | # 12 | name: release 13 | on: 14 | push: 15 | tags: 16 | - 'v*' 17 | jobs: 18 | goreleaser: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - 22 | name: Checkout 23 | uses: actions/checkout@v3 24 | - 25 | name: Unshallow 26 | run: git fetch --prune --unshallow 27 | - 28 | name: Set up Go 29 | uses: actions/setup-go@v4 30 | with: 31 | go-version: ^1.20 32 | - 33 | name: Import GPG key 34 | id: import_gpg 35 | uses: paultyng/ghaction-import-gpg@v2.1.0 36 | env: 37 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 38 | PASSPHRASE: ${{ secrets.PASSPHRASE }} 39 | - 40 | name: Run GoReleaser 41 | uses: goreleaser/goreleaser-action@v4 42 | with: 43 | version: latest 44 | args: release --clean 45 | env: 46 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 48 | 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .swp 2 | .terraform 3 | *.backup 4 | **/generated 5 | .DS_Store 6 | .idea/workspace.xml 7 | .idea/tasks.xml 8 | crash.log 9 | .vagrant 10 | *.hattip 11 | plan.txt 12 | output.txt 13 | launch.json 14 | config.yaml 15 | *_plan.log 16 | file_targets_out.txt 17 | *.out 18 | settings.json 19 | .secrets/* 20 | .unlocked/* 21 | unlocked 22 | .venv/ 23 | 24 | # Intellij 25 | .idea 26 | *.iml 27 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | # Visit https://goreleaser.com for documentation on how to customize this 4 | # behavior. 5 | before: 6 | hooks: 7 | # this is just an example and not a requirement for provider building/publishing 8 | - go mod tidy 9 | builds: 10 | - env: 11 | # goreleaser does not work with CGO, it could also complicate 12 | # usage by users in CI/CD systems like Terraform Cloud where 13 | # they are unable to install libraries. 14 | - CGO_ENABLED=0 15 | mod_timestamp: '{{ .CommitTimestamp }}' 16 | flags: 17 | - -trimpath 18 | ldflags: 19 | - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' 20 | goos: 21 | - freebsd 22 | - windows 23 | - linux 24 | - darwin 25 | goarch: 26 | - amd64 27 | - '386' 28 | - arm 29 | - arm64 30 | ignore: 31 | - goos: darwin 32 | goarch: '386' 33 | - goos: darwin 34 | goarch: 'arm' 35 | - goos: windows 36 | goarch: 'arm' 37 | - goos: freebsd 38 | goarch: 'arm64' 39 | - goos: windows 40 | goarch: 'arm64' 41 | binary: '{{ .ProjectName }}_v{{ .Version }}' 42 | archives: 43 | - format: zip 44 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' 45 | checksum: 46 | name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' 47 | algorithm: sha256 48 | signs: 49 | - artifacts: checksum 50 | args: 51 | # if you are using this is a GitHub action or some other automated pipeline, you 52 | # need to pass the batch flag to indicate its not interactive. 53 | - "--batch" 54 | - "--local-user" 55 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 56 | - "--output" 57 | - "${signature}" 58 | - "--detach-sign" 59 | - "${artifact}" 60 | release: 61 | # If you want to manually examine the release before its live, uncomment this line: 62 | # draft: true 63 | changelog: 64 | disable: true 65 | 66 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.4.0 2 | * upgrade: upgrade cc api 3 | * 4 | ## 0.3.4 5 | 6 | BUG FIXES: 7 | * fix: build for darwin_arm64 8 | * skip: 0.3.4 due to incorrecly release 9 | 10 | ## 0.3.2 11 | 12 | BUG FIXES: 13 | * fix: update type as required for updateSource ([#5](https://github.com/OpenAxon/terraform-provider-identitynow/pull/5)) 14 | 15 | ## 0.3.1 (December 25, 2020) 16 | 17 | Initial release 18 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | test: 2 | @go test 3 | 4 | testacc: 5 | @sh -c "'$(CURDIR)/scripts/gotestacc.sh'" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | To find how you can declare resources see [examples folder](./examples/) 2 | 3 | ### Limitations: 4 | - Sources get created first, but an aggregation has to run before the rest of the plan can complete successfully because the entitlement data lookups will fail until the aggregation has pulled the entitlements from the source into IdentityNow. 5 | 6 | - After creating the source, you also need to go into the UI and press the "Test Connection" button to verify the source. This unlocks the ability to apply `identitynow_account_schema_attribute` and `identitynow_account_aggregation_schedule`. 7 | 8 | - Password policies can be created, but there is a bug in Idn that makes the association to the source not work. For now, you have to go into the UI and make the association. Sailpoint ticket: https://support.sailpoint.com/hc/en-us/requests/82917 9 | 10 | - Create/enable/disable profiles cannot be managed with Terraform yet. The API for them is highly unusual and not amenable to automation. 11 | 12 | - Due to a bug in IdentityNow, Encrypted field in ConnectorAttributes block cannot be left null. 13 | 14 | # Development 15 | Edit the Go files that make up the provider, and rebuild the provider. 16 | 17 | ```bash 18 | ./scripts/build.sh 19 | ``` 20 | 21 | This script places the provider binary in an implied local mirror directory ($HOME/.terraform.d/plugins/). See build.sh 22 | for more comments about ensuring that Terraform uses the local mirror rather than searching the remote registry. 23 | 24 | # Testing the Provider 25 | 26 | In order to test the provider, you can simply run `make test`. 27 | ```sh 28 | $ make test 29 | ``` 30 | In order to run the full suite of Acceptance test identitynow url, client id and secret, owner name and id, cluster name and id are needed to make the API call to create IdentityNow source for test. 31 | 32 | To run acceptance tests, first you need to update the `script/gotestacc_vars.sh` with above variables values and then simply run `make testacc`. 33 | 34 | ```sh 35 | $ make testacc 36 | ``` 37 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | // Config is the configuration parameters for an IdentityNow API 9 | type Config struct { 10 | URL string `json:"url"` 11 | ClientId string `json:"cacert"` 12 | ClientSecret string `json:"tokenKey"` 13 | } 14 | 15 | func (c *Config) IdentityNowClient() (*Client, error) { 16 | client := NewClient(c.URL, c.ClientId, c.ClientSecret) 17 | ctx := context.Background() 18 | 19 | if err := client.GetToken(ctx); err != nil { 20 | return nil, err 21 | } 22 | if len(client.accessToken) == 0 { 23 | return nil, fmt.Errorf("access token is empty") 24 | } 25 | return client, nil 26 | } 27 | -------------------------------------------------------------------------------- /data_source_Identity.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | "log" 7 | ) 8 | 9 | func dataSourceIdentity() *schema.Resource { 10 | return &schema.Resource{ 11 | Read: dataSourceIdentityRead, 12 | 13 | Schema: identityFields(), 14 | } 15 | } 16 | 17 | func dataSourceIdentityRead(d *schema.ResourceData, meta interface{}) error { 18 | log.Printf("[INFO] Getting Data source for Identity. Identity alias %s", d.Get("alias").(string)) 19 | client, err := meta.(*Config).IdentityNowClient() 20 | if err != nil { 21 | return err 22 | } 23 | 24 | identity, err := client.GetIdentity(context.Background(), d.Get("alias").(string)) 25 | if err != nil { 26 | // non-panicking type assertion, 2nd arg is boolean indicating type match 27 | _, notFound := err.(*NotFoundError) 28 | if notFound { 29 | log.Printf("[INFO] Data source for Identity alias %s not found.", d.Get("alias").(string)) 30 | return nil 31 | } 32 | return err 33 | } 34 | 35 | return flattenIdentity(d, identity[0]) 36 | } 37 | -------------------------------------------------------------------------------- /data_source_access_profile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 8 | ) 9 | 10 | func dataSourceAccessProfile() *schema.Resource { 11 | return &schema.Resource{ 12 | Read: dataSourceAccessProfileRead, 13 | 14 | Schema: map[string]*schema.Schema{ 15 | "id": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | Description: "Source id", 19 | }, 20 | "name": { 21 | Type: schema.TypeString, 22 | Computed: true, 23 | Description: "Access Profile name", 24 | }, 25 | "description": { 26 | Type: schema.TypeString, 27 | Computed: true, 28 | Description: "Access Profile description", 29 | }, 30 | 31 | "source": { 32 | Type: schema.TypeList, 33 | Computed: true, 34 | Elem: &schema.Resource{ 35 | Schema: accessProfileSourceFields(), 36 | }, 37 | }, 38 | 39 | "owner": { 40 | Type: schema.TypeList, 41 | Computed: true, 42 | Elem: &schema.Resource{ 43 | Schema: sourceOwnerFields(), 44 | }, 45 | }, 46 | 47 | "entitlements": { 48 | Type: schema.TypeList, 49 | Computed: true, 50 | Elem: &schema.Resource{ 51 | Schema: accessProfileEntitlementsFields(), 52 | }, 53 | }, 54 | 55 | "enabled": { 56 | Type: schema.TypeBool, 57 | Computed: true, 58 | }, 59 | 60 | "requestable": { 61 | Type: schema.TypeBool, 62 | Computed: true, 63 | }, 64 | }, 65 | } 66 | } 67 | 68 | func dataSourceAccessProfileRead(d *schema.ResourceData, meta interface{}) error { 69 | log.Printf("[INFO] Data source for Access Profile ID %s", d.Get("id").(string)) 70 | client, err := meta.(*Config).IdentityNowClient() 71 | if err != nil { 72 | return err 73 | } 74 | 75 | accessProfile, err := client.GetAccessProfile(context.Background(), d.Get("id").(string)) 76 | if err != nil { 77 | // non-panicking type assertion, 2nd arg is boolean indicating type match 78 | _, notFound := err.(*NotFoundError) 79 | if notFound { 80 | log.Printf("[INFO] Data source for Access Profile ID %s not found.", d.Get("id").(string)) 81 | return nil 82 | } 83 | return err 84 | } 85 | 86 | return flattenAccessProfile(d, accessProfile) 87 | } 88 | -------------------------------------------------------------------------------- /data_source_role.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | "log" 7 | ) 8 | 9 | func dataSourceRole() *schema.Resource { 10 | return &schema.Resource{ 11 | Read: dataSourceRoleRead, 12 | 13 | Schema: map[string]*schema.Schema{ 14 | "id": { 15 | Type: schema.TypeString, 16 | Required: true, 17 | }, 18 | "access_profiles": { 19 | Type: schema.TypeList, 20 | Computed: true, 21 | Elem: &schema.Resource{ 22 | Schema: roleAccessProfilesFields(), 23 | }, 24 | }, 25 | "description": { 26 | Type: schema.TypeString, 27 | Computed: true, 28 | }, 29 | "enabled": { 30 | Type: schema.TypeBool, 31 | Computed: true, 32 | }, 33 | "name": { 34 | Type: schema.TypeString, 35 | Computed: true, 36 | }, 37 | "owner": { 38 | Type: schema.TypeList, 39 | Computed: true, 40 | Elem: &schema.Resource{ 41 | Schema: sourceOwnerFields(), 42 | }, 43 | }, 44 | "requestable": { 45 | Type: schema.TypeBool, 46 | Computed: true, 47 | }, 48 | }, 49 | } 50 | } 51 | 52 | func dataSourceRoleRead(d *schema.ResourceData, meta interface{}) error { 53 | log.Printf("[INFO] Getting Data source for Role ID %s", d.Get("id").(string)) 54 | client, err := meta.(*Config).IdentityNowClient() 55 | if err != nil { 56 | return err 57 | } 58 | 59 | role, err := client.GetRole(context.Background(), d.Get("id").(string)) 60 | if err != nil { 61 | // non-panicking type assertion, 2nd arg is boolean indicating type match 62 | _, notFound := err.(*NotFoundError) 63 | if notFound { 64 | log.Printf("[INFO] Data source for Role ID %s not found.", d.Get("id").(string)) 65 | return nil 66 | } 67 | return err 68 | } 69 | 70 | return flattenRole(d, role) 71 | } 72 | -------------------------------------------------------------------------------- /data_source_source.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 8 | ) 9 | 10 | func dataSourceSource() *schema.Resource { 11 | return &schema.Resource{ 12 | Read: dataSourceSourceRead, 13 | 14 | Schema: map[string]*schema.Schema{ 15 | "id": { 16 | Type: schema.TypeString, 17 | Required: true, 18 | Description: "Source id", 19 | }, 20 | "name": { 21 | Type: schema.TypeString, 22 | Computed: true, 23 | Description: "Source name", 24 | }, 25 | "description": { 26 | Type: schema.TypeString, 27 | Computed: true, 28 | Description: "Source description", 29 | }, 30 | "connector": { 31 | Type: schema.TypeString, 32 | Computed: true, 33 | Description: "Source connector type", 34 | }, 35 | "delete_threshold": { 36 | Type: schema.TypeInt, 37 | Computed: true, 38 | }, 39 | "authoritative": { 40 | Type: schema.TypeBool, 41 | Computed: true, 42 | Description: "True if this source is authoritative", 43 | }, 44 | "owner": { 45 | Type: schema.TypeList, 46 | MaxItems: 1, 47 | Computed: true, 48 | Elem: &schema.Resource{ 49 | Schema: sourceOwnerFields(), 50 | }, 51 | }, 52 | "schemas": { 53 | Type: schema.TypeList, 54 | Computed: true, 55 | Elem: &schema.Resource{ 56 | Schema: sourceSchemaFields(), 57 | }, 58 | }, 59 | "cluster": { 60 | Type: schema.TypeList, 61 | MaxItems: 1, 62 | Computed: true, 63 | Elem: &schema.Resource{ 64 | Schema: sourceClusterFields(), 65 | }, 66 | }, 67 | "account_correlation_config": { 68 | Type: schema.TypeList, 69 | MaxItems: 1, 70 | Computed: true, 71 | Elem: &schema.Resource{ 72 | Schema: sourceAccountCorrelationConfigFields(), 73 | }, 74 | }, 75 | "connector_attributes": { 76 | Type: schema.TypeList, 77 | MaxItems: 1, 78 | Computed: true, 79 | Elem: &schema.Resource{ 80 | Schema: sourceConnectorAttributesFields(), 81 | }, 82 | }, 83 | }, 84 | } 85 | } 86 | 87 | func dataSourceSourceRead(d *schema.ResourceData, meta interface{}) error { 88 | log.Printf("[INFO] Data source for Source ID %s", d.Get("id").(string)) 89 | client, err := meta.(*Config).IdentityNowClient() 90 | if err != nil { 91 | return err 92 | } 93 | 94 | source, err := client.GetSource(context.Background(), d.Get("id").(string)) 95 | if err != nil { 96 | // non-panicking type assertion, 2nd arg is boolean indicating type match 97 | _, notFound := err.(*NotFoundError) 98 | if notFound { 99 | log.Printf("[INFO] Data source for Source ID %s not found.", d.Get("id").(string)) 100 | return nil 101 | } 102 | return err 103 | } 104 | 105 | return flattenSource(d, source) 106 | } 107 | -------------------------------------------------------------------------------- /data_source_source_entitlements.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 8 | ) 9 | 10 | func dataSourceSourceEntitlement() *schema.Resource { 11 | return &schema.Resource{ 12 | Read: dataSourceSourceEntitlementRead, 13 | 14 | Schema: sourceEntitlementFields(), 15 | } 16 | } 17 | 18 | func dataSourceSourceEntitlementRead(d *schema.ResourceData, meta interface{}) error { 19 | log.Printf("[INFO] Getting Data source for Entitlements. Source ID %s", d.Get("source_id").(string)) 20 | client, err := meta.(*Config).IdentityNowClient() 21 | if err != nil { 22 | return err 23 | } 24 | 25 | sourceEntitlements, err := client.GetSourceEntitlement(context.Background(), d.Get("source_id").(string), d.Get("name").(string)) 26 | if err != nil { 27 | // non-panicking type assertion, 2nd arg is boolean indicating type match 28 | _, notFound := err.(*NotFoundError) 29 | if notFound { 30 | log.Printf("[INFO] Data source for Source ID %s not found.", d.Get("source_id").(string)) 31 | return nil 32 | } 33 | return err 34 | } 35 | 36 | return flattenSourceEntitlement(d, sourceEntitlements[0]) 37 | } 38 | -------------------------------------------------------------------------------- /error_not_found.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type NotFoundError struct { 4 | message string 5 | } 6 | 7 | func (e *NotFoundError) Error() string { return e.message } 8 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | Example command to run plan and apply for resources: 2 | 3 | `terraform plan -var="api_client_id=" -var="api_client_secret="` 4 | 5 | `terraform apply -var="api_client_id=" -var="api_client_secret="` 6 | 7 | To list resources: 8 | 9 | ``` 10 | $ terraform state list 11 | data.identitynow_identity.john_doe 12 | data.identitynow_source_entitlement.aad_operator 13 | data.identitynow_source_entitlement.ad_developer 14 | identitynow_access_profile.ad_access_profile_developers 15 | identitynow_access_profile.aad_access_profile_operators 16 | identitynow_account_aggregation_schedule.account_aggregation 17 | identitynow_account_schema_attribute.account_schema_employeeId_attribute 18 | identitynow_password_policy.password_policy 19 | identitynow_role.operator_developer_role 20 | identitynow_source.active_directory_source 21 | identitynow_source.aws_iam_source 22 | identitynow_source.azure_ad_source 23 | ``` 24 | -------------------------------------------------------------------------------- /examples/active_directory_source.tf: -------------------------------------------------------------------------------- 1 | resource "identitynow_source" "active_directory_source" { 2 | name = "Active Directory Source" 3 | description = "The Active Directory connector created by terraform" 4 | connector = "active-directory" 5 | 6 | owner { 7 | id = data.identitynow_identity.john_doe.external_id 8 | name = data.identitynow_identity.john_doe.name 9 | type = "IDENTITY" 10 | } 11 | 12 | cluster { 13 | id = "" 14 | name = "" 15 | } 16 | 17 | password_policies { 18 | id = identitynow_password_policy.password-policy.id 19 | name = identitynow_password_policy.password-policy.name 20 | type = "PASSWORD_POLICY" 21 | } 22 | 23 | connector_attributes { 24 | iq_service_host = "iqservice.example.com" 25 | iq_service_port = "5052" 26 | iq_service_user = "" 27 | iq_service_password = "" 28 | use_tls_for_iq_service = true 29 | encrypted = "IQServicePassword" 30 | forest_settings { 31 | user = "" 32 | password = "" 33 | gc_server = "ad1.example.com:3269" 34 | forest_name = "example.com" 35 | use_ssl = true 36 | authorization_type = "simple" 37 | } 38 | forest_settings { 39 | user = "" 40 | password = "" 41 | gc_server = "ad2.example.com:3269" 42 | forest_name = "example.com" 43 | use_ssl = true 44 | authorization_type = "simple" 45 | } 46 | domain_settings { 47 | user = "" 48 | password = "" 49 | servers = [ 50 | "ad1.example.com:3269", 51 | "ad2.example.com:3269"] 52 | port = "636" 53 | forest_name = "example.com" 54 | authorization_type = "simple" 55 | domain_dn = "DC=example,DC=com" 56 | use_ssl = true 57 | } 58 | search_dns { 59 | search_dn = "OU=Users,DC=example,DC=com" 60 | iterate_search_filter = "(objectclass=person)" 61 | search_scope = "SUBTREE" 62 | } 63 | search_dns { 64 | search_dn = "OU=OffboardedUsers,DC=example,DC=com" 65 | iterate_search_filter = "(objectclass=person)" 66 | search_scope = "SUBTREE" 67 | } 68 | group_search_dns { 69 | search_dn = "OU=Groups,DC=example,DC=com" 70 | iterate_search_filter = "(objectclass=group)" 71 | search_scope = "SUBTREE" 72 | } 73 | } 74 | 75 | lifecycle { 76 | ignore_changes = [ 77 | connector_attributes[0].iq_service_password, 78 | connector_attributes[0].forest_settings[0].password, 79 | connector_attributes[0].forest_settings[1].password, 80 | connector_attributes[0].domain_settings[0].password, 81 | management_workgroup[0].name, 82 | ] 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /examples/aws_iam_source.tf: -------------------------------------------------------------------------------- 1 | resource "identitynow_source" "aws_iam_source" { 2 | name = "AWS IAM Source" 3 | description = "The AWS IAM connector created by terraform" 4 | connector = "aws" 5 | 6 | owner { 7 | id = data.identitynow_identity.john_doe.external_id 8 | name = data.identitynow_identity.john_doe.name 9 | type = "IDENTITY" 10 | } 11 | 12 | cluster { 13 | id = "" 14 | name = "" 15 | } 16 | 17 | connector_attributes { 18 | include_aws_account_id_list = "123456789012" #list of aws accounts id separated with `,` 19 | kid = "" 20 | secret = "ACCESS_KEY_SECRET>" 21 | role_name = "" 22 | connector_class = "openconnector.connector.aws.AWSConnectorSDK" 23 | encrypted = "secret" 24 | } 25 | 26 | lifecycle { 27 | ignore_changes = [ 28 | connector_attributes[0].secret, 29 | owner[0].name, 30 | management_workgroup[0].name, 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/azure_active_directory_source.tf: -------------------------------------------------------------------------------- 1 | resource "identitynow_source" "azure_ad_source" { 2 | name = "Azure Active Directory Source" 3 | description = "The Azure Active Directory connector created by terraform" 4 | connector = "azure-active-directory" 5 | 6 | owner { 7 | id = data.identitynow_identity.john_doe.external_id 8 | name = data.identitynow_identity.john_doe.name 9 | type = "IDENTITY" 10 | } 11 | 12 | cluster { 13 | id = "" 14 | name = "" 15 | } 16 | 17 | #only if there is any management group defined for source 18 | management_workgroup { 19 | id = "" 20 | name = "" 21 | type = "GOVERNANCE_GROUP" 22 | } 23 | 24 | password_policies { 25 | id = identitynow_password_policy.password-policy.id 26 | name = identitynow_password_policy.password-policy.name 27 | type = "PASSWORD_POLICY" 28 | } 29 | 30 | connector_attributes { 31 | grant_type = "CLIENT_CREDENTIALS" 32 | client_id = "" 33 | client_secret = " 0 && 115 | foundRole.ID != rs.Primary.ID { 116 | return fmt.Errorf("role still exist") 117 | } 118 | } 119 | return nil 120 | } 121 | 122 | func testAccCheckRoleExist(name string, role Role) resource.TestCheckFunc { 123 | return func(state *terraform.State) error { 124 | rs, ok := state.RootModule().Resources[name] 125 | 126 | if !ok { 127 | return fmt.Errorf("not found: %s", name) 128 | } 129 | 130 | if rs.Primary.ID == "" { 131 | return fmt.Errorf("no role ID is set") 132 | } 133 | 134 | client, err := testAccProvider.Meta().(*Config).IdentityNowClient() 135 | if err != nil { 136 | return err 137 | } 138 | 139 | foundRole, err := client.GetRole(context.Background(), rs.Primary.ID) 140 | if err != nil { 141 | log.Fatal(err) 142 | } 143 | // we expect a single Source by this ID. If we find zero 144 | // then we consider this an error 145 | if len(foundRole.ID) == 0 || 146 | foundRole.ID != rs.Primary.ID || err != nil { 147 | return fmt.Errorf("role not found") 148 | } 149 | role = *foundRole 150 | 151 | return nil 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /resource_schedule_account_aggregation.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | schema "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 7 | "log" 8 | ) 9 | 10 | func resourceScheduleAccountAggregation() *schema.Resource { 11 | return &schema.Resource{ 12 | Create: resourceAccountAggregationScheduleCreateUpdate, 13 | Read: resourceAccountAggregationScheduleRead, 14 | Update: resourceAccountAggregationScheduleCreateUpdate, 15 | Delete: resourceAccountAggregationScheduleDelete, 16 | 17 | Schema: accountAggregationScheduleFields(), 18 | } 19 | } 20 | 21 | func resourceAccountAggregationScheduleCreateUpdate(d *schema.ResourceData, m interface{}) error { 22 | accountAggregationSchedule, err := expandAccountAggregationSchedule(d) 23 | if err != nil { 24 | return err 25 | } 26 | 27 | log.Printf("[INFO] Performing Account Aggregation Schedule for source ID %s", accountAggregationSchedule.SourceID) 28 | 29 | client, err := m.(*Config).IdentityNowClient() 30 | if err != nil { 31 | return err 32 | } 33 | 34 | newAccountAggregationSchedule, err := client.ManageAccountAggregationSchedule(context.Background(), accountAggregationSchedule, true) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | newAccountAggregationSchedule.SourceID = accountAggregationSchedule.SourceID 40 | 41 | err = flattenAccountAggregationSchedule(d, newAccountAggregationSchedule) 42 | if err != nil { 43 | return err 44 | } 45 | 46 | return resourceAccountAggregationScheduleRead(d, m) 47 | } 48 | 49 | func resourceAccountAggregationScheduleRead(d *schema.ResourceData, m interface{}) error { 50 | log.Printf("[INFO] Refreshing Account Aggregation Schedule for source ID %s", d.Id()) 51 | client, err := m.(*Config).IdentityNowClient() 52 | if err != nil { 53 | return err 54 | } 55 | 56 | accountAggregationSchedule, err := client.GetAccountAggregationSchedule(context.Background(), d.Id()) 57 | if accountAggregationSchedule.CronExpressions != nil { 58 | accountAggregationSchedule.SourceID = d.Id() 59 | } 60 | if err != nil { 61 | // non-panicking type assertion, 2nd arg is boolean indicating type match 62 | _, notFound := err.(*NotFoundError) 63 | if notFound { 64 | log.Printf("[INFO] Account Aggregation Schedule for Source ID %s not found.", d.Id()) 65 | d.SetId("") 66 | return nil 67 | } 68 | return err 69 | } 70 | 71 | err = flattenAccountAggregationSchedule(d, accountAggregationSchedule) 72 | if err != nil { 73 | return err 74 | } 75 | 76 | return nil 77 | } 78 | 79 | func resourceAccountAggregationScheduleDelete(d *schema.ResourceData, m interface{}) error { 80 | log.Printf("[INFO] Deleting Account Aggregation for Source ID %s", d.Id()) 81 | 82 | client, err := m.(*Config).IdentityNowClient() 83 | if err != nil { 84 | return err 85 | } 86 | 87 | accountAggregationSchedule, err := client.GetAccountAggregationSchedule(context.Background(), d.Id()) 88 | if err != nil { 89 | // non-panicking type assertion, 2nd arg is boolean indicating type match 90 | _, notFound := err.(*NotFoundError) 91 | if notFound { 92 | log.Printf("[INFO] Account Aggregation Schedule for source ID %s not found.", d.Id()) 93 | d.SetId("") 94 | return nil 95 | } 96 | return err 97 | } 98 | 99 | if accountAggregationSchedule.CronExpressions != nil { 100 | accountAggregationSchedule.SourceID = d.Id() 101 | _, err = client.ManageAccountAggregationSchedule(context.Background(), accountAggregationSchedule, false) 102 | if err != nil { 103 | return fmt.Errorf("Error removing Account Aggregation Schedule for source ID: %s. \nError: %s", d.Id(), err) 104 | } 105 | 106 | d.SetId("") 107 | } 108 | 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /resource_source.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 7 | "log" 8 | ) 9 | 10 | func resourceSource() *schema.Resource { 11 | return &schema.Resource{ 12 | Create: resourceSourceCreate, 13 | Read: resourceSourceRead, 14 | Update: resourceSourceUpdate, 15 | Delete: resourceSourceDelete, 16 | 17 | Importer: &schema.ResourceImporter{ 18 | State: resourceSourceImport, 19 | }, 20 | 21 | Schema: sourceFields(), 22 | } 23 | } 24 | 25 | func resourceSourceCreate(d *schema.ResourceData, m interface{}) error { 26 | source, err := expandSource(d) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | log.Printf("[INFO] Creating Source %s", source.Name) 32 | 33 | c, err := m.(*Config).IdentityNowClient() 34 | if err != nil { 35 | return err 36 | } 37 | 38 | newSource, err := c.CreateSource(context.Background(), source) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | err = flattenSource(d, newSource) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return resourceSourceRead(d, m) 49 | } 50 | 51 | func resourceSourceRead(d *schema.ResourceData, m interface{}) error { 52 | log.Printf("[INFO] Refreshing source ID %s", d.Id()) 53 | client, err := m.(*Config).IdentityNowClient() 54 | if err != nil { 55 | return err 56 | } 57 | 58 | source, err := client.GetSource(context.Background(), d.Id()) 59 | if err != nil { 60 | // non-panicking type assertion, 2nd arg is boolean indicating type match 61 | _, notFound := err.(*NotFoundError) 62 | if notFound { 63 | log.Printf("[INFO] Source ID %s not found.", d.Id()) 64 | d.SetId("") 65 | return nil 66 | } 67 | return err 68 | } 69 | 70 | err = flattenSource(d, source) 71 | if err != nil { 72 | return err 73 | } 74 | 75 | return nil 76 | } 77 | 78 | func resourceSourceUpdate(d *schema.ResourceData, m interface{}) error { 79 | log.Printf("[INFO] Updating Source ID %s", d.Id()) 80 | client, err := m.(*Config).IdentityNowClient() 81 | if err != nil { 82 | return err 83 | } 84 | 85 | updatedSource, err := expandSource(d) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | _, err = client.UpdateSource(context.Background(), updatedSource) 91 | if err != nil { 92 | return err 93 | } 94 | 95 | return resourceSourceRead(d, m) 96 | } 97 | 98 | func resourceSourceDelete(d *schema.ResourceData, m interface{}) error { 99 | log.Printf("[INFO] Deleting Source ID %s", d.Id()) 100 | 101 | client, err := m.(*Config).IdentityNowClient() 102 | if err != nil { 103 | return err 104 | } 105 | 106 | source, err := client.GetSource(context.Background(), d.Id()) 107 | if err != nil { 108 | // non-panicking type assertion, 2nd arg is boolean indicating type match 109 | _, notFound := err.(*NotFoundError) 110 | if notFound { 111 | log.Printf("[INFO] Source ID %s not found.", d.Id()) 112 | d.SetId("") 113 | return nil 114 | } 115 | return err 116 | } 117 | 118 | err = client.DeleteSource(context.Background(), source) 119 | if err != nil { 120 | return fmt.Errorf("Error removing Source: %s", err) 121 | } 122 | 123 | d.SetId("") 124 | return nil 125 | } 126 | -------------------------------------------------------------------------------- /schema_Identity.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func identityFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "alias": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | }, 11 | 12 | "name": { 13 | Type: schema.TypeString, 14 | Computed: true, 15 | Description: "Identity name", 16 | }, 17 | "description": { 18 | Type: schema.TypeString, 19 | Computed: true, 20 | }, 21 | 22 | "email_address": { 23 | Type: schema.TypeString, 24 | Computed: true, 25 | }, 26 | 27 | "enabled": { 28 | Type: schema.TypeBool, 29 | Computed: true, 30 | }, 31 | 32 | "is_manager": { 33 | Type: schema.TypeBool, 34 | Computed: true, 35 | }, 36 | 37 | "identity_status": { 38 | Type: schema.TypeString, 39 | Computed: true, 40 | }, 41 | 42 | "attributes": { 43 | Type: schema.TypeList, 44 | Optional: true, 45 | MaxItems: 1, 46 | Elem: &schema.Resource{ 47 | Schema: identityAttributesFields(), 48 | }, 49 | }, 50 | } 51 | return s 52 | } 53 | 54 | func identityAttributesFields() map[string]*schema.Schema { 55 | s := map[string]*schema.Schema{ 56 | "adp_id": { 57 | Type: schema.TypeString, 58 | Optional: true, 59 | }, 60 | "lastname": { 61 | Type: schema.TypeString, 62 | Optional: true, 63 | }, 64 | "firstname": { 65 | Type: schema.TypeString, 66 | Optional: true, 67 | }, 68 | "phone": { 69 | Type: schema.TypeString, 70 | Optional: true, 71 | }, 72 | "user_type": { 73 | Type: schema.TypeString, 74 | Optional: true, 75 | }, 76 | "uid": { 77 | Type: schema.TypeString, 78 | Optional: true, 79 | }, 80 | "email": { 81 | Type: schema.TypeString, 82 | Optional: true, 83 | }, 84 | "workday_id": { 85 | Type: schema.TypeString, 86 | Optional: true, 87 | }, 88 | } 89 | return s 90 | } 91 | -------------------------------------------------------------------------------- /schema_access_profile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | func accessProfileFields() map[string]*schema.Schema { 8 | s := map[string]*schema.Schema{ 9 | "name": { 10 | Type: schema.TypeString, 11 | Required: true, 12 | Description: "Access Profile name", 13 | }, 14 | "description": { 15 | Type: schema.TypeString, 16 | Required: true, 17 | Description: "Access Profile description", 18 | }, 19 | 20 | "source": { 21 | Type: schema.TypeList, 22 | Required: true, 23 | MaxItems: 1, 24 | Elem: &schema.Resource{ 25 | Schema: accessProfileSourceFields(), 26 | }, 27 | }, 28 | 29 | "owner": { 30 | Type: schema.TypeList, 31 | Required: true, 32 | MaxItems: 1, 33 | Elem: &schema.Resource{ 34 | Schema: sourceOwnerFields(), 35 | }, 36 | }, 37 | 38 | "entitlements": { 39 | Type: schema.TypeList, 40 | Optional: true, 41 | Elem: &schema.Resource{ 42 | Schema: accessProfileEntitlementsFields(), 43 | }, 44 | }, 45 | 46 | "enabled": { 47 | Type: schema.TypeBool, 48 | Optional: true, 49 | }, 50 | 51 | "requestable": { 52 | Type: schema.TypeBool, 53 | Computed: true, 54 | }, 55 | } 56 | return s 57 | } 58 | 59 | func accessProfileSourceFields() map[string]*schema.Schema { 60 | s := map[string]*schema.Schema{ 61 | "id": { 62 | Type: schema.TypeString, 63 | Required: true, 64 | Description: "Id of source", 65 | }, 66 | "name": { 67 | Type: schema.TypeString, 68 | Required: true, 69 | Description: "Name of source", 70 | }, 71 | "type": { 72 | Type: schema.TypeString, 73 | Optional: true, 74 | Default: "SOURCE", 75 | Description: "Type of source", 76 | }, 77 | } 78 | 79 | return s 80 | } 81 | 82 | func accessProfileEntitlementsFields() map[string]*schema.Schema { 83 | s := map[string]*schema.Schema{ 84 | "id": { 85 | Type: schema.TypeString, 86 | Required: true, 87 | Description: "Id of entitlement", 88 | }, 89 | "name": { 90 | Type: schema.TypeString, 91 | Required: true, 92 | Description: "Name of entitlement", 93 | }, 94 | "type": { 95 | Type: schema.TypeString, 96 | Optional: true, 97 | Default: "ENTITLEMENT", 98 | Description: "Type of entitlement", 99 | }, 100 | } 101 | 102 | return s 103 | } 104 | -------------------------------------------------------------------------------- /schema_account_aggregation_schedule.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | func accountAggregationScheduleFields() map[string]*schema.Schema { 8 | s := map[string]*schema.Schema{ 9 | "source_id": { 10 | Type: schema.TypeString, 11 | Required: true, 12 | Description: "Source ID", 13 | }, 14 | 15 | "cron_expressions": { 16 | Type: schema.TypeList, 17 | Required: true, 18 | Description: "Account aggregation scheduling in cron Expression format.", 19 | Elem: &schema.Schema{ 20 | Type: schema.TypeString, 21 | }, 22 | }, 23 | } 24 | return s 25 | } 26 | -------------------------------------------------------------------------------- /schema_account_schema.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func accountSchemaFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "name": { 8 | Type: schema.TypeString, 9 | Optional: true, 10 | }, 11 | 12 | "source_id": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | }, 16 | 17 | "schema_id": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | }, 21 | 22 | "display_attribute": { 23 | Type: schema.TypeString, 24 | Optional: true, 25 | }, 26 | 27 | "identity_attribute": { 28 | Type: schema.TypeString, 29 | Optional: true, 30 | }, 31 | "native_object_type": { 32 | Type: schema.TypeString, 33 | Optional: true, 34 | }, 35 | "hierarchy_attribute": { 36 | Type: schema.TypeString, 37 | Optional: true, 38 | }, 39 | 40 | "include_permissions": { 41 | Type: schema.TypeBool, 42 | Optional: true, 43 | }, 44 | 45 | "attributes": { 46 | Type: schema.TypeList, 47 | Optional: true, 48 | Elem: &schema.Resource{ 49 | Schema: accountSchemaAttributesFields(), 50 | }, 51 | }, 52 | 53 | "modified": { 54 | Type: schema.TypeString, 55 | Optional: true, 56 | }, 57 | 58 | "created": { 59 | Type: schema.TypeString, 60 | Optional: true, 61 | }, 62 | } 63 | return s 64 | } 65 | -------------------------------------------------------------------------------- /schema_account_schema_attributes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func accountSchemaAttributesFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "name": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | }, 11 | 12 | "type": { 13 | Type: schema.TypeString, 14 | Optional: true, 15 | }, 16 | 17 | "description": { 18 | Type: schema.TypeString, 19 | Optional: true, 20 | }, 21 | 22 | "schema": { 23 | Type: schema.TypeList, 24 | Optional: true, 25 | Elem: &schema.Resource{ 26 | Schema: sourceSchemaFields(), 27 | }, 28 | }, 29 | 30 | "is_group": { 31 | Type: schema.TypeBool, 32 | Optional: true, 33 | }, 34 | 35 | "is_multi_valued": { 36 | Type: schema.TypeBool, 37 | Optional: true, 38 | }, 39 | 40 | "is_entitlement": { 41 | Type: schema.TypeBool, 42 | Optional: true, 43 | }, 44 | } 45 | return s 46 | } 47 | -------------------------------------------------------------------------------- /schema_password_policy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func passwordPolicyFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "account_id_min_word_length": { 8 | Type: schema.TypeInt, 9 | Optional: true, 10 | Description: "Char length that disallow account ID fragments", 11 | Default: -1, 12 | }, 13 | "account_name_min_word_length": { 14 | Type: schema.TypeInt, 15 | Optional: true, 16 | Description: "Char length that disallow display name fragments", 17 | Default: -1, 18 | }, 19 | "connected_services": { 20 | Type: schema.TypeList, 21 | Computed: true, 22 | Elem: &schema.Resource{ 23 | Schema: passwordPolicyConnectedServicesFields(), 24 | }, 25 | }, 26 | "date_created": { 27 | Type: schema.TypeString, 28 | Computed: true, 29 | }, 30 | "default_policy": { 31 | Type: schema.TypeBool, 32 | Optional: true, 33 | Description: "Is the password policy default policy?", 34 | }, 35 | "description": { 36 | Type: schema.TypeString, 37 | Optional: true, 38 | Description: "Password policy description", 39 | }, 40 | "enable_password_expiration": { 41 | Type: schema.TypeBool, 42 | Optional: true, 43 | }, 44 | "first_expiration_reminder": { 45 | Type: schema.TypeInt, 46 | Optional: true, 47 | }, 48 | "last_updated": { 49 | Type: schema.TypeString, 50 | Computed: true, 51 | }, 52 | "max_length": { 53 | Type: schema.TypeInt, 54 | Optional: true, 55 | Description: "password max length", 56 | }, 57 | "max_repeated_chars": { 58 | Type: schema.TypeInt, 59 | Optional: true, 60 | }, 61 | "min_alpha": { 62 | Type: schema.TypeInt, 63 | Optional: true, 64 | Description: "minimum letters in password", 65 | }, 66 | "min_character_types": { 67 | Type: schema.TypeInt, 68 | Optional: true, 69 | Default: -1, 70 | }, 71 | "min_length": { 72 | Type: schema.TypeInt, 73 | Optional: true, 74 | Description: "minimum password length", 75 | }, 76 | "min_lower": { 77 | Type: schema.TypeInt, 78 | Optional: true, 79 | Description: "minimum number of lowercase characters in password", 80 | }, 81 | "min_numeric": { 82 | Type: schema.TypeInt, 83 | Optional: true, 84 | Description: "minimum number in password", 85 | }, 86 | "min_special": { 87 | Type: schema.TypeInt, 88 | Optional: true, 89 | Description: "minimum number of special characters in password", 90 | }, 91 | "min_upper": { 92 | Type: schema.TypeInt, 93 | Optional: true, 94 | Description: "minimum number of uppercase characters in password", 95 | }, 96 | "name": { 97 | Type: schema.TypeString, 98 | ForceNew: true, 99 | Required: true, 100 | Description: "Password policy name", 101 | }, 102 | "password_expiration": { 103 | Type: schema.TypeInt, 104 | Optional: true, 105 | Default: 90, 106 | }, 107 | "require_strong_auth_off_network": { 108 | Type: schema.TypeBool, 109 | Optional: true, 110 | }, 111 | "require_strong_auth_untrusted_geographies": { 112 | Type: schema.TypeBool, 113 | Optional: true, 114 | }, 115 | "require_strong_authn": { 116 | Type: schema.TypeBool, 117 | Optional: true, 118 | }, 119 | "use_account_attributes": { 120 | Type: schema.TypeBool, 121 | Optional: true, 122 | Description: "Prevent use of account attributes?", 123 | }, 124 | "use_dictionary": { 125 | Type: schema.TypeBool, 126 | Optional: true, 127 | Description: "Prevent use of words in this site's password dictionary?", 128 | }, 129 | "use_history": { 130 | Type: schema.TypeInt, 131 | Optional: true, 132 | }, 133 | "use_identity_attributes": { 134 | Type: schema.TypeBool, 135 | Optional: true, 136 | Description: "Prevent use of identity attributes?", 137 | }, 138 | "validate_against_account_id": { 139 | Type: schema.TypeBool, 140 | Optional: true, 141 | Description: "Disallow account ID fragments?", 142 | }, 143 | "validate_against_account_name": { 144 | Type: schema.TypeBool, 145 | Optional: true, 146 | Description: "Disallow account name fragments?", 147 | }, 148 | "source_ids": { 149 | Type: schema.TypeList, 150 | Optional: true, 151 | Description: "List of sources", 152 | Elem: &schema.Schema{ 153 | Type: schema.TypeString, 154 | }, 155 | }, 156 | } 157 | return s 158 | } 159 | -------------------------------------------------------------------------------- /schema_password_policy_connected_services.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func passwordPolicyConnectedServicesFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | Description: "Source id", 11 | }, 12 | "external_id": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | Description: "Source external id", 16 | }, 17 | "name": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | Description: "Source name", 21 | }, 22 | "supports_password_set_date": { 23 | Type: schema.TypeBool, 24 | Optional: true, 25 | Default: false, 26 | }, 27 | "app_count": { 28 | Type: schema.TypeInt, 29 | Optional: true, 30 | Default: 0, 31 | }, 32 | } 33 | return s 34 | } 35 | -------------------------------------------------------------------------------- /schema_role.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func roleFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "description": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | Description: "Role description.", 11 | }, 12 | "name": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | Description: "Role name", 17 | }, 18 | "owner": { 19 | Type: schema.TypeList, 20 | Required: true, 21 | MaxItems: 1, 22 | Elem: &schema.Resource{ 23 | Schema: sourceOwnerFields(), 24 | }, 25 | }, 26 | "access_profiles": { 27 | Type: schema.TypeList, 28 | Optional: true, 29 | Elem: &schema.Resource{ 30 | Schema: roleAccessProfilesFields(), 31 | }, 32 | }, 33 | "requestable": { 34 | Type: schema.TypeBool, 35 | Optional: true, 36 | }, 37 | "enabled": { 38 | Type: schema.TypeBool, 39 | Optional: true, 40 | }, 41 | } 42 | return s 43 | } 44 | -------------------------------------------------------------------------------- /schema_role_access_profiles.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func roleAccessProfilesFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Id of role", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | Description: "Name of AccessProfile", 20 | }, 21 | "type": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Default: "ACCESS_PROFILE", 25 | Description: "Access Profile Type", 26 | }, 27 | } 28 | 29 | return s 30 | } 31 | -------------------------------------------------------------------------------- /schema_source.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | func sourceFields() map[string]*schema.Schema { 8 | s := map[string]*schema.Schema{ 9 | "name": { 10 | Type: schema.TypeString, 11 | Required: true, 12 | Description: "Source name", 13 | }, 14 | "description": { 15 | Type: schema.TypeString, 16 | Required: true, 17 | Description: "Source description", 18 | }, 19 | "type": { 20 | Type: schema.TypeString, 21 | Optional: true, 22 | Description: "Specifies the type of system being managed", 23 | }, 24 | "connector": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | ForceNew: true, 28 | Description: "Source connector type", 29 | }, 30 | "delete_threshold": { 31 | Type: schema.TypeInt, 32 | Optional: true, 33 | Default: 10, 34 | }, 35 | "authoritative": { 36 | Type: schema.TypeBool, 37 | Optional: true, 38 | Description: "True if this source is authoritative", 39 | Default: false, 40 | }, 41 | "owner": { 42 | Type: schema.TypeList, 43 | MaxItems: 1, 44 | Required: true, 45 | Elem: &schema.Resource{ 46 | Schema: sourceOwnerFields(), 47 | }, 48 | }, 49 | "schemas": { 50 | Type: schema.TypeList, 51 | Computed: true, 52 | Elem: &schema.Resource{ 53 | Schema: sourceSchemaFields(), 54 | }, 55 | }, 56 | "cluster": { 57 | Type: schema.TypeList, 58 | MaxItems: 1, 59 | Optional: true, 60 | Elem: &schema.Resource{ 61 | Schema: sourceClusterFields(), 62 | }, 63 | }, 64 | "account_correlation_config": { 65 | Type: schema.TypeList, 66 | MaxItems: 1, 67 | Computed: true, 68 | Elem: &schema.Resource{ 69 | Schema: sourceAccountCorrelationConfigFields(), 70 | }, 71 | }, 72 | "connector_attributes": { 73 | Type: schema.TypeList, 74 | MaxItems: 1, 75 | Optional: true, 76 | Elem: &schema.Resource{ 77 | Schema: sourceConnectorAttributesFields(), 78 | }, 79 | }, 80 | "management_workgroup": { 81 | Type: schema.TypeList, 82 | Optional: true, 83 | Elem: &schema.Resource{ 84 | Schema: sourceManagementWorkgroupFields(), 85 | }, 86 | }, 87 | "password_policies": { 88 | Type: schema.TypeList, 89 | Optional: true, 90 | Elem: &schema.Resource{ 91 | Schema: sourcePasswordPoliciesFields(), 92 | }, 93 | }, 94 | } 95 | 96 | //for k, v := range commonAnnotationLabelFields() { 97 | // s[k] = v 98 | //} 99 | 100 | return s 101 | } 102 | -------------------------------------------------------------------------------- /schema_source_account_correlation_config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceAccountCorrelationConfigFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "id": { 12 | Type: schema.TypeString, 13 | Optional: true, 14 | Description: "Id of account correlation config", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Optional: true, 19 | Description: "Name of account correlation config", 20 | }, 21 | "type": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Description: "Type of account correlation config", 25 | }, 26 | } 27 | 28 | return s 29 | } 30 | -------------------------------------------------------------------------------- /schema_source_cluster.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceClusterFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Id of cluster", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | Description: "Name of cluster", 20 | }, 21 | "type": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Default: "CLUSTER", 25 | Description: "Type of cluster", 26 | }, 27 | } 28 | 29 | return s 30 | } 31 | -------------------------------------------------------------------------------- /schema_source_connector_attributes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceConnectorAttributesFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "grant_type": { 12 | Type: schema.TypeString, 13 | Optional: true, 14 | Description: "Authentication grant type to use for communication to connected system", 15 | }, 16 | "client_id": { 17 | Type: schema.TypeString, 18 | Optional: true, 19 | Description: "Client id for the connector client credentials", 20 | }, 21 | "client_secret": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Description: "Client id for the connector client credentials", 25 | Sensitive: true, 26 | }, 27 | "cloud_external_id": { 28 | Type: schema.TypeString, 29 | Computed: true, 30 | Description: "Cloud external ID (related to the main id?)", 31 | }, 32 | "domain_name": { 33 | Type: schema.TypeString, 34 | Optional: true, 35 | Description: "Domain name for the connector client credentials", 36 | }, 37 | "ms_graph_resource_base": { 38 | Type: schema.TypeString, 39 | Optional: true, 40 | Description: "Base resource URL that is used for Microsoft Graph API REST calls", 41 | }, 42 | "ms_graph_token_base": { 43 | Type: schema.TypeString, 44 | Optional: true, 45 | Description: "Base token URL that is used to get access token for Microsoft Graph API REST calls", 46 | }, 47 | "azure_ad_graph_resource_base": { 48 | Type: schema.TypeString, 49 | Optional: true, 50 | Description: "Base resource URL that is used for Azure AD Graph API REST calls", 51 | }, 52 | "azure_ad_graph_token_base": { 53 | Type: schema.TypeString, 54 | Optional: true, 55 | Description: "Base token URL that is used to get an access token for Azure AD Graph API REST calls", 56 | }, 57 | "iq_service_host": { 58 | Type: schema.TypeString, 59 | Optional: true, 60 | Description: "IQService host url for on-prem Active Directory.", 61 | }, 62 | "iq_service_port": { 63 | Type: schema.TypeString, 64 | Optional: true, 65 | Description: "IQService port for on-prem Active Directory.", 66 | }, 67 | "use_tls_for_iq_service": { 68 | Type: schema.TypeBool, 69 | Optional: true, 70 | Description: "Use TLS for IQService for on-prem Active Directory.", 71 | }, 72 | "iq_service_user": { 73 | Type: schema.TypeString, 74 | Optional: true, 75 | Sensitive: true, 76 | Description: "Service Account username for IQService host.", 77 | }, 78 | "iq_service_password": { 79 | Type: schema.TypeString, 80 | Optional: true, 81 | Sensitive: true, 82 | Description: "Service Account password for IQService host.", 83 | }, 84 | "forest_settings": { 85 | Type: schema.TypeList, 86 | Optional: true, 87 | Elem: &schema.Resource{ 88 | Schema: sourceForestSettingsFields(), 89 | }, 90 | }, 91 | "domain_settings": { 92 | Type: schema.TypeList, 93 | Optional: true, 94 | Elem: &schema.Resource{ 95 | Schema: sourceDomainSettingsFields(), 96 | }, 97 | }, 98 | "search_dns": { 99 | Type: schema.TypeList, 100 | Optional: true, 101 | Elem: &schema.Resource{ 102 | Schema: sourceSearchDNsFields(), 103 | }, 104 | }, 105 | "authorization_type": { 106 | Type: schema.TypeString, 107 | Optional: true, 108 | Description: "Authorization type (none, simple, strong)", 109 | }, 110 | "api_version": { 111 | Type: schema.TypeString, 112 | Optional: true, 113 | Description: "Azure API version to use for Azure Active Directory connector", 114 | }, 115 | "exclude_aws_account_id_list": { 116 | Type: schema.TypeString, 117 | Optional: true, 118 | Description: "List of AWS account ids separated with comma to exclude from aggregation.", 119 | }, 120 | "include_aws_account_id_list": { 121 | Type: schema.TypeString, 122 | Optional: true, 123 | Description: "List of AWS account ids separated with comma to include in aggregation.", 124 | }, 125 | "kid": { 126 | Type: schema.TypeString, 127 | Optional: true, 128 | Description: "Access Key ID for AWS IAM service account.", 129 | }, 130 | "secret": { 131 | Type: schema.TypeString, 132 | Optional: true, 133 | Sensitive: true, 134 | Description: "Secret Access Key for AWS IAM service account.", 135 | }, 136 | "role_name": { 137 | Type: schema.TypeString, 138 | Optional: true, 139 | Description: "Secret Access Key for AWS IAM service account.", 140 | }, 141 | "manage_all_accounts_iam_data": { 142 | Type: schema.TypeBool, 143 | Optional: true, 144 | Description: "True if IAM source is managing all iam users.", 145 | }, 146 | "connector_class": { 147 | Type: schema.TypeString, 148 | Optional: true, 149 | }, 150 | "encrypted": { 151 | Type: schema.TypeString, 152 | Optional: true, 153 | }, 154 | "group_search_dns": { 155 | Type: schema.TypeList, 156 | Optional: true, 157 | Elem: &schema.Resource{ 158 | Schema: sourceGroupSearchDNFields(), 159 | }, 160 | }, 161 | } 162 | 163 | return s 164 | } 165 | -------------------------------------------------------------------------------- /schema_source_domain_settings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceDomainSettingsFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "password": { 12 | Type: schema.TypeString, 13 | Optional: true, 14 | Description: "Service Account password to login to on-prem active directory.", 15 | Sensitive: true, 16 | }, 17 | "user": { 18 | Type: schema.TypeString, 19 | Optional: true, 20 | Description: "Service Account user to login to on-prem active directory.", 21 | Sensitive: true, 22 | }, 23 | "servers": { 24 | Type: schema.TypeList, 25 | Optional: true, 26 | Description: "Active directory servers.", 27 | Elem: &schema.Schema{ 28 | Type: schema.TypeString, 29 | }, 30 | }, 31 | "port": { 32 | Type: schema.TypeString, 33 | Optional: true, 34 | Description: "Active Directory host port.", 35 | }, 36 | "forest_name": { 37 | Type: schema.TypeString, 38 | Optional: true, 39 | Description: "Active Directory forest name.", 40 | }, 41 | "domain_dn": { 42 | Type: schema.TypeString, 43 | Optional: true, 44 | Description: "Active Directory domain controller.", 45 | }, 46 | "use_ssl": { 47 | Type: schema.TypeBool, 48 | Optional: true, 49 | Description: "Use ssl to connect to Active directory.", 50 | }, 51 | "authorization_type": { 52 | Type: schema.TypeString, 53 | Optional: true, 54 | Description: "Active Directory authorization type.", 55 | }, 56 | } 57 | return s 58 | } 59 | -------------------------------------------------------------------------------- /schema_source_entitlement.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func sourceEntitlementFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "name": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | Description: "Source entitlements name", 11 | }, 12 | "source_id": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | Description: "source id", 16 | }, 17 | "source_name": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | Description: "source name", 21 | }, 22 | "source_schema_object_type": { 23 | Type: schema.TypeString, 24 | Computed: true, 25 | }, 26 | "attribute": { 27 | Type: schema.TypeString, 28 | Computed: true, 29 | Description: "attribute", 30 | }, 31 | "created": { 32 | Type: schema.TypeString, 33 | Computed: true, 34 | }, 35 | "description": { 36 | Type: schema.TypeString, 37 | Computed: true, 38 | }, 39 | "modified": { 40 | Type: schema.TypeString, 41 | Computed: true, 42 | }, 43 | "owner": { 44 | Type: schema.TypeString, 45 | Computed: true, 46 | }, 47 | "privileged": { 48 | Type: schema.TypeBool, 49 | Computed: true, 50 | }, 51 | "requestable": { 52 | Type: schema.TypeBool, 53 | Computed: true, 54 | }, 55 | "value": { 56 | Type: schema.TypeString, 57 | Computed: true, 58 | }, 59 | } 60 | 61 | return s 62 | } 63 | -------------------------------------------------------------------------------- /schema_source_forest_settings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceForestSettingsFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "password": { 12 | Type: schema.TypeString, 13 | Optional: true, 14 | Description: "Service Account password to login to on-prem active directory.", 15 | Sensitive: true, 16 | }, 17 | "user": { 18 | Type: schema.TypeString, 19 | Optional: true, 20 | Description: "Service Account user to login to on-prem active directory.", 21 | Sensitive: true, 22 | }, 23 | "gc_server": { 24 | Type: schema.TypeString, 25 | Optional: true, 26 | Description: "Active directory server.", 27 | }, 28 | "forest_name": { 29 | Type: schema.TypeString, 30 | Optional: true, 31 | Description: "Active Directory forest name.", 32 | }, 33 | "use_ssl": { 34 | Type: schema.TypeBool, 35 | Optional: true, 36 | Description: "Use ssl to connect to Active directory.", 37 | }, 38 | "authorization_type": { 39 | Type: schema.TypeString, 40 | Optional: true, 41 | Description: "Active Directory authorization type.", 42 | }, 43 | } 44 | 45 | return s 46 | } 47 | -------------------------------------------------------------------------------- /schema_source_group_search_dns.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceGroupSearchDNFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "search_dn": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | }, 15 | "search_scope": { 16 | Type: schema.TypeString, 17 | Optional: true, 18 | }, 19 | "iterate_search_filter": { 20 | Type: schema.TypeString, 21 | Required: true, 22 | }, 23 | } 24 | 25 | return s 26 | } 27 | -------------------------------------------------------------------------------- /schema_source_management_workgroup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceManagementWorkgroupFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Id of management group", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | Description: "Name of management group", 20 | }, 21 | "type": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Default: "GOVERNANCE_GROUP", 25 | Description: "Type of management group", 26 | }, 27 | } 28 | 29 | return s 30 | } 31 | -------------------------------------------------------------------------------- /schema_source_owner.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceOwnerFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Id of owner", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | Description: "Name of owner", 20 | }, 21 | "type": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Default: "IDENTITY", 25 | Description: "Type of owner", 26 | }, 27 | } 28 | 29 | return s 30 | } 31 | -------------------------------------------------------------------------------- /schema_source_password_policies.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func sourcePasswordPoliciesFields() map[string]*schema.Schema { 6 | s := map[string]*schema.Schema{ 7 | "id": { 8 | Type: schema.TypeString, 9 | Required: true, 10 | Description: "Id of password policy", 11 | }, 12 | "name": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | Description: "Name of password policy", 16 | }, 17 | "type": { 18 | Type: schema.TypeString, 19 | Optional: true, 20 | Default: "IDENTITY", 21 | Description: "Type of password policy", 22 | }, 23 | } 24 | 25 | return s 26 | } 27 | -------------------------------------------------------------------------------- /schema_source_schema.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceSchemaFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Id of schema", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | Description: "Name of schema", 20 | }, 21 | "type": { 22 | Type: schema.TypeString, 23 | Required: true, 24 | Description: "Type of schema", 25 | }, 26 | } 27 | 28 | return s 29 | } 30 | -------------------------------------------------------------------------------- /schema_source_search_dns.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | ) 6 | 7 | // Schemas 8 | 9 | func sourceSearchDNsFields() map[string]*schema.Schema { 10 | s := map[string]*schema.Schema{ 11 | "search_dn": { 12 | Type: schema.TypeString, 13 | Optional: true, 14 | Description: "Active Directory search domain criteria.", 15 | }, 16 | "iterate_search_filter": { 17 | Type: schema.TypeString, 18 | Optional: true, 19 | Description: "Active Directory search filter.", 20 | }, 21 | "group_membership_search_dn": { 22 | Type: schema.TypeString, 23 | Optional: true, 24 | Description: "Active Directory group membership search criteria.", 25 | }, 26 | "group_member_filter_string": { 27 | Type: schema.TypeString, 28 | Optional: true, 29 | Description: "Active Directory group membership search filter.", 30 | }, 31 | "search_scope": { 32 | Type: schema.TypeString, 33 | Optional: true, 34 | Description: "Active Directory search scope.", 35 | }, 36 | "primary_group_search_dn": { 37 | Type: schema.TypeString, 38 | Optional: true, 39 | Description: "Active Directory primary group search.", 40 | }, 41 | } 42 | 43 | return s 44 | } 45 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Set the version to something with the format x.y.z, ideally not a version already published externally 5 | # Once the directory ~/.terraform.d/plugins/registry.terraform.io/openaxon/identitynow is created, 6 | # TF will not longer attempt to look for any versions of this provider on the remote registry. 7 | # When finished with development, you can remove the folder from your laptop to start using the public provider again. 8 | # https://www.terraform.io/docs/commands/cli-config.html#implied-local-mirror-directories 9 | VERSION=0.4.1 10 | go build -o terraform-provider-identitynow 11 | mkdir -p ~/.terraform.d/plugins/registry.terraform.io/openaxon/identitynow/${VERSION}/darwin_amd64 12 | mv terraform-provider-identitynow ~/.terraform.d/plugins/registry.terraform.io/openaxon/identitynow/${VERSION}/darwin_amd64/terraform-provider-identitynow_v${VERSION} -------------------------------------------------------------------------------- /scripts/gotestacc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo "==>Running acceptance testing..." 6 | 7 | source $(dirname $0)/gotestacc_vars.sh 8 | 9 | TF_ACC=1 go test -cover -tags=test ./... -v -timeout 120m -------------------------------------------------------------------------------- /scripts/gotestacc_vars.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | export IDENTITYNOW_URL= 6 | 7 | export IDENTITYNOW_CLIENT_ID= 8 | 9 | export IDENTITYNOW_CLIENT_SECRET= 10 | 11 | export IDENTITYNOW_OWNER_ID= 12 | 13 | export IDENTITYNOW_EXTERNAL_OWNER_ID= 14 | 15 | export IDENTITYNOW_EXTERNAL_OWNER_NAME= 16 | 17 | export IDENTITYNOW_CLUSTER_ID= 18 | 19 | export IDENTITYNOW_CLUSTER_NAME= 20 | 21 | export IDENTITYNOW_SOURCE_ID= 22 | 23 | export IDENTITYNOW_SOURCE_ENTITLEMENT= -------------------------------------------------------------------------------- /structure_Identity.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | func flattenIdentity(d *schema.ResourceData, in *Identity) error { 6 | if in == nil { 7 | return nil 8 | } 9 | d.SetId(in.ID) 10 | d.Set("alias", in.Alias) 11 | d.Set("name", in.Name) 12 | d.Set("description", in.Description) 13 | d.Set("enabled", in.Enabled) 14 | d.Set("isManager", in.IsManager) 15 | d.Set("emailAddress", in.EmailAddress) 16 | d.Set("identityStatus", in.IdentityStatus) 17 | 18 | if in.IdentityAttributes != nil { 19 | v, ok := d.Get("attributes").(interface{}) 20 | if !ok { 21 | v = []interface{}{} 22 | } 23 | d.Set("attributes", flattenIdentityAttributes(in.IdentityAttributes, v)) 24 | } 25 | 26 | return nil 27 | } 28 | 29 | func flattenIdentityAttributes(in *IdentityAttributes, p interface{}) interface{} { 30 | if in == nil { 31 | return []interface{}{} 32 | } 33 | var obj = make(map[string]interface{}) 34 | obj["adpId"] = in.AdpID 35 | obj["lastname"] = in.LastName 36 | obj["firstname"] = in.FirstName 37 | obj["phone"] = in.Phone 38 | obj["userType"] = in.UserType 39 | obj["uid"] = in.UID 40 | obj["email"] = in.Email 41 | obj["workdayId"] = in.WorkdayId 42 | 43 | return obj 44 | } 45 | -------------------------------------------------------------------------------- /structure_access_profile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | ) 7 | 8 | // Flatteners 9 | 10 | func flattenAccessProfile(d *schema.ResourceData, in *AccessProfile) error { 11 | if in == nil { 12 | return nil 13 | } 14 | 15 | d.SetId(in.ID) 16 | d.Set("name", in.Name) 17 | d.Set("description", in.Description) 18 | d.Set("enabled", in.Enabled) 19 | d.Set("requestable", in.Requestable) 20 | 21 | if in.AccessProfileOwner != nil { 22 | v, ok := d.Get("owner").([]interface{}) 23 | if !ok { 24 | v = []interface{}{} 25 | } 26 | accessProfileOwnerList := []*ObjectInfo{in.AccessProfileOwner} 27 | d.Set("owner", flattenObjectAccessProfile(accessProfileOwnerList, v)) 28 | } 29 | if in.AccessProfileSource != nil { 30 | v, ok := d.Get("source").([]interface{}) 31 | if !ok { 32 | v = []interface{}{} 33 | } 34 | accessProfileSourceList := []*ObjectInfo{in.AccessProfileSource} 35 | d.Set("source", flattenObjectAccessProfile(accessProfileSourceList, v)) 36 | } 37 | if in.Entitlements != nil { 38 | v, ok := d.Get("entitlements").([]interface{}) 39 | if !ok { 40 | v = []interface{}{} 41 | } 42 | 43 | d.Set("entitlements", flattenObjectRoles(in.Entitlements, v)) 44 | } 45 | return nil 46 | } 47 | 48 | func flattenObjectAccessProfile(in []*ObjectInfo, p []interface{}) []interface{} { 49 | if in == nil { 50 | return []interface{}{} 51 | } 52 | 53 | out := make([]interface{}, 0, len(in)) 54 | for i := range in { 55 | var obj = make(map[string]interface{}) 56 | obj["type"] = in[i].Type 57 | obj["id"] = in[i].ID 58 | obj["name"] = in[i].Name 59 | out = append(out, obj) 60 | } 61 | return out 62 | } 63 | 64 | // Expanders 65 | 66 | func expandAccessProfile(in *schema.ResourceData) (*AccessProfile, error) { 67 | obj := AccessProfile{} 68 | if in == nil { 69 | return nil, fmt.Errorf("[ERROR] Expanding Access Profile: Schema Resource data is nil") 70 | } 71 | 72 | obj.Name = in.Get("name").(string) 73 | obj.Description = in.Get("description").(string) 74 | 75 | if v, ok := in.Get("enabled").(bool); ok { 76 | obj.Enabled = &v 77 | } 78 | 79 | if v, ok := in.Get("owner").([]interface{}); ok && len(v) > 0 { 80 | obj.AccessProfileOwner = expandObjectAccessProfile(v)[0] 81 | } 82 | 83 | if v, ok := in.Get("source").([]interface{}); ok && len(v) > 0 { 84 | obj.AccessProfileSource = expandObjectAccessProfile(v)[0] 85 | } 86 | 87 | if v, ok := in.Get("entitlements").([]interface{}); ok && len(v) > 0 { 88 | obj.Entitlements = expandObjectRoles(v) 89 | } 90 | 91 | return &obj, nil 92 | } 93 | 94 | func expandUpdateAccessProfile(in *schema.ResourceData) ([]*UpdateAccessProfile, interface{}, error) { 95 | updatableFields := []string{"name", "description", "enabled", "owner", "entitlements", "requestable", "source"} 96 | var id interface{} 97 | if in == nil { 98 | return nil, nil, fmt.Errorf("[ERROR] Expanding Role: Schema Resource data is nil") 99 | } 100 | 101 | if v := in.Id(); len(v) > 0 { 102 | id = v 103 | } 104 | 105 | out := []*UpdateAccessProfile{} 106 | 107 | for i := range updatableFields { 108 | obj := UpdateAccessProfile{} 109 | if v, ok := in.Get(fmt.Sprintf("/%s", updatableFields[i])).([]interface{}); ok { 110 | obj.Op = "replace" 111 | obj.Path = fmt.Sprintf("/%s", updatableFields[i]) 112 | obj.Value = v 113 | } 114 | out = append(out, &obj) 115 | } 116 | 117 | return out, id, nil 118 | } 119 | 120 | func expandObjectAccessProfile(p []interface{}) []*ObjectInfo { 121 | if len(p) == 0 || p[0] == nil { 122 | return []*ObjectInfo{} 123 | } 124 | out := make([]*ObjectInfo, 0, len(p)) 125 | for i := range p { 126 | obj := ObjectInfo{} 127 | in := p[i].(map[string]interface{}) 128 | obj.ID = in["id"].(string) 129 | obj.Name = in["name"].(string) 130 | obj.Type = in["type"].(string) 131 | out = append(out, &obj) 132 | } 133 | return out 134 | } 135 | -------------------------------------------------------------------------------- /structure_access_profile_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testAccessProfileConf *AccessProfile 11 | testAccessProfileInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | FALSE := false 16 | testAccessProfileConf = &AccessProfile{ 17 | Name: "test name", 18 | Description: "test Description", 19 | AccessProfileOwner: &ObjectInfo{ 20 | ID: "2c9180887412345678948078d29f2e46", 21 | Name: "SRE Test", 22 | Type: "IDENTITY", 23 | }, 24 | AccessProfileSource: &ObjectInfo{ 25 | ID: "2c91808374bc866a0178948078d29f2e46", 26 | Name: "Product platform, Azure portal, AzureUSGovernment", 27 | Type: "SOURCE", 28 | }, 29 | Entitlements: []*ObjectInfo{ 30 | { 31 | ID: "2c918088747654398948078d29f2e46", 32 | Name: "Operators_AG1", 33 | Type: "ENTITLEMENT", 34 | }, 35 | { 36 | ID: "2c918009437654398948078d29f2e46", 37 | Name: "Integrator_AG1", 38 | Type: "ENTITLEMENT", 39 | }, 40 | }, 41 | Enabled: &FALSE, 42 | } 43 | testAccessProfileInterface = map[string]interface{}{ 44 | "name": "test name", 45 | "description": "test Description", 46 | "source": []interface{}{ 47 | map[string]interface{}{ 48 | "id": "2c91808374bc866a0178948078d29f2e46", 49 | "name": "Product platform, Azure portal, AzureUSGovernment", 50 | "type": "SOURCE", 51 | }, 52 | }, 53 | "owner": []interface{}{ 54 | map[string]interface{}{ 55 | "id": "2c9180887412345678948078d29f2e46", 56 | "name": "SRE Test", 57 | "type": "IDENTITY", 58 | }, 59 | }, 60 | "entitlements": []interface{}{ 61 | map[string]interface{}{ 62 | "id": "2c918088747654398948078d29f2e46", 63 | "name": "Operators_AG1", 64 | "type": "ENTITLEMENT", 65 | }, 66 | map[string]interface{}{ 67 | "id": "2c918009437654398948078d29f2e46", 68 | "name": "Integrator_AG1", 69 | "type": "ENTITLEMENT", 70 | }, 71 | }, 72 | "enabled": false, 73 | } 74 | } 75 | 76 | func TestFlattenAccessProfile(t *testing.T) { 77 | cases := []struct { 78 | Input *AccessProfile 79 | ExpectedOutput map[string]interface{} 80 | }{ 81 | { 82 | testAccessProfileConf, 83 | testAccessProfileInterface, 84 | }, 85 | } 86 | for _, tc := range cases { 87 | output := schema.TestResourceDataRaw(t, accessProfileFields(), tc.ExpectedOutput) 88 | err := flattenAccessProfile(output, tc.Input) 89 | if err != nil { 90 | t.Fatalf("[ERROR] on flattener: %#v", err) 91 | } 92 | expectedOutput := map[string]interface{}{} 93 | for k := range tc.ExpectedOutput { 94 | expectedOutput[k] = output.Get(k) 95 | } 96 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 97 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 98 | tc.ExpectedOutput, expectedOutput) 99 | } 100 | } 101 | } 102 | 103 | func TestExpandAccessProfile(t *testing.T) { 104 | cases := []struct { 105 | Input map[string]interface{} 106 | ExpectedOutput *AccessProfile 107 | }{ 108 | { 109 | testAccessProfileInterface, 110 | testAccessProfileConf, 111 | }, 112 | } 113 | 114 | for _, tc := range cases { 115 | inputResourceData := schema.TestResourceDataRaw(t, accessProfileFields(), tc.Input) 116 | output, err := expandAccessProfile(inputResourceData) 117 | if err != nil { 118 | t.Fatalf("[ERROR] on flattener: %#v", err) 119 | } 120 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 121 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 122 | tc.ExpectedOutput, output) 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /structure_account_aggregation_schedule.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | ) 7 | 8 | // Flatteners 9 | 10 | func flattenAccountAggregationSchedule(d *schema.ResourceData, in *AccountAggregationSchedule) error { 11 | if in == nil { 12 | return nil 13 | } 14 | 15 | d.SetId(in.SourceID) 16 | d.Set("cron_expressions", toArrayInterface(in.CronExpressions)) 17 | return nil 18 | } 19 | 20 | // Expanders 21 | 22 | func expandAccountAggregationSchedule(in *schema.ResourceData) (*AccountAggregationSchedule, error) { 23 | obj := AccountAggregationSchedule{} 24 | if in == nil { 25 | return nil, fmt.Errorf("[ERROR] Expanding Schedule Account Aggregation: Schema Resource data is nil") 26 | } 27 | 28 | obj.SourceID = in.Get("source_id").(string) 29 | 30 | if v, ok := in.Get("cron_expressions").([]interface{}); ok && len(v) > 0 { 31 | obj.CronExpressions = toArrayString(v) 32 | } 33 | 34 | return &obj, nil 35 | } 36 | -------------------------------------------------------------------------------- /structure_account_aggregation_schedule_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testAccountAggregationScheduleConf *AccountAggregationSchedule 11 | testAccountAggregationScheduleInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | testAccountAggregationScheduleConf = &AccountAggregationSchedule{ 16 | SourceID: "1234", 17 | CronExpressions: []string{"0 0 1,2,3,4 * * ?"}, 18 | } 19 | testAccountAggregationScheduleInterface = map[string]interface{}{ 20 | "source_id": "1234", 21 | "cron_expressions": []interface{}{"0 0 1,2,3,4 * * ?"}, 22 | } 23 | } 24 | 25 | func TestFlattenAccountAggregationSchedule(t *testing.T) { 26 | cases := []struct { 27 | Input *AccountAggregationSchedule 28 | ExpectedOutput map[string]interface{} 29 | }{ 30 | { 31 | testAccountAggregationScheduleConf, 32 | testAccountAggregationScheduleInterface, 33 | }, 34 | } 35 | for _, tc := range cases { 36 | output := schema.TestResourceDataRaw(t, accountAggregationScheduleFields(), tc.ExpectedOutput) 37 | err := flattenAccountAggregationSchedule(output, tc.Input) 38 | if err != nil { 39 | t.Fatalf("[ERROR] on flattener: %#v", err) 40 | } 41 | expectedOutput := map[string]interface{}{} 42 | for k := range tc.ExpectedOutput { 43 | expectedOutput[k] = output.Get(k) 44 | } 45 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 46 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 47 | tc.ExpectedOutput, expectedOutput) 48 | } 49 | } 50 | } 51 | 52 | func TestExpandAccountAggregationSchedule(t *testing.T) { 53 | cases := []struct { 54 | Input map[string]interface{} 55 | ExpectedOutput *AccountAggregationSchedule 56 | }{ 57 | { 58 | testAccountAggregationScheduleInterface, 59 | testAccountAggregationScheduleConf, 60 | }, 61 | } 62 | 63 | for _, tc := range cases { 64 | inputResourceData := schema.TestResourceDataRaw(t, accountAggregationScheduleFields(), tc.Input) 65 | output, err := expandAccountAggregationSchedule(inputResourceData) 66 | if err != nil { 67 | t.Fatalf("[ERROR] on flattener: %#v", err) 68 | } 69 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 70 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 71 | tc.ExpectedOutput, output) 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /structure_account_schema.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | "log" 7 | ) 8 | 9 | // Flatteners 10 | 11 | func flattenAccountSchema(d *schema.ResourceData, in *AccountSchema) error { 12 | if in == nil { 13 | return nil 14 | } 15 | 16 | d.SetId(in.ID) 17 | d.Set("name", in.Name) 18 | d.Set("source_id", in.SourceID) 19 | d.Set("schema_id", in.ID) 20 | d.Set("native_object_type", in.NativeObjectType) 21 | d.Set("identity_attribute", in.IdentityAttribute) 22 | d.Set("display_attribute", in.DisplayAttribute) 23 | d.Set("hierarchy_attribute", in.HierarchyAttribute) 24 | d.Set("include_permissions", in.IncludePermissions) 25 | d.Set("modified", in.Modified) 26 | d.Set("created", in.Created) 27 | if in.Attributes != nil { 28 | v, ok := d.Get("attributes").([]interface{}) 29 | if !ok { 30 | v = []interface{}{} 31 | } 32 | 33 | d.Set("attributes", flattenAccountSchemaAttributes(in.Attributes, v)) 34 | } 35 | 36 | log.Printf("d *schema.ResourceData in flatten: %+v", d) 37 | return nil 38 | } 39 | 40 | // Expanders 41 | func expandAccountSchema(in *schema.ResourceData) (*AccountSchema, error) { 42 | obj := AccountSchema{} 43 | if in == nil { 44 | return nil, fmt.Errorf("[ERROR] Expanding Account Schema: Schema Resource data is nil") 45 | } 46 | if v := in.Id(); len(v) > 0 { 47 | obj.ID = v 48 | } 49 | obj.Name = in.Get("name").(string) 50 | obj.SourceID = in.Get("source_id").(string) 51 | obj.ID = in.Get("schema_id").(string) 52 | obj.NativeObjectType = in.Get("native_object_type").(string) 53 | obj.IdentityAttribute = in.Get("identity_attribute").(string) 54 | obj.DisplayAttribute = in.Get("display_attribute").(string) 55 | obj.HierarchyAttribute = in.Get("hierarchy_attribute").(string) 56 | obj.Modified = in.Get("modified").(string) 57 | obj.Created = in.Get("created").(string) 58 | if v, ok := in.Get("include_permissions").(bool); ok { 59 | obj.IncludePermissions = v 60 | } 61 | if v, ok := in.Get("attributes").([]interface{}); ok && len(v) > 0 { 62 | obj.Attributes = expandAccountSchemaAttributes(v) 63 | } 64 | return &obj, nil 65 | } 66 | -------------------------------------------------------------------------------- /structure_account_schema_attribute.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenAccountSchemaAttributes(in []*AccountSchemaAttribute, p []interface{}) []interface{} { 6 | if in == nil { 7 | return []interface{}{} 8 | } 9 | 10 | out := make([]interface{}, 0, len(in)) 11 | 12 | for i := range in { 13 | var obj = make(map[string]interface{}) 14 | obj["name"] = in[i].Name 15 | obj["type"] = in[i].Type 16 | obj["description"] = in[i].Description 17 | obj["is_multi_valued"] = in[i].IsMultiValued 18 | obj["is_entitlement"] = in[i].IsEntitlement 19 | obj["is_group"] = in[i].IsGroup 20 | if in[i].Schema != nil { 21 | v, ok := obj["schema"].([]interface{}) 22 | if !ok { 23 | v = []interface{}{} 24 | } 25 | obj["schema"] = flattenAccountSchemaAttributesSchema(in[i].Schema, v) 26 | } 27 | out = append(out, obj) 28 | } 29 | return out 30 | } 31 | 32 | func flattenAccountSchemaAttributesSchema(in *AccountSchemaAttributeSchema, p []interface{}) interface{} { 33 | var obj map[string]interface{} 34 | if len(p) == 0 || p[0] == nil { 35 | obj = make(map[string]interface{}) 36 | } else { 37 | obj = p[0].(map[string]interface{}) 38 | } 39 | 40 | if in == nil { 41 | return []interface{}{} 42 | } 43 | 44 | obj["type"] = in.Type 45 | obj["id"] = in.ID 46 | obj["name"] = in.Name 47 | 48 | return []interface{}{obj} 49 | } 50 | 51 | // Expanders 52 | func expandAccountSchemaAttributes(p []interface{}) []*AccountSchemaAttribute { 53 | if len(p) == 0 || p[0] == nil { 54 | return []*AccountSchemaAttribute{} 55 | } 56 | out := make([]*AccountSchemaAttribute, 0, len(p)) 57 | for i := range p { 58 | obj := AccountSchemaAttribute{} 59 | in := p[i].(map[string]interface{}) 60 | obj.Name = in["name"].(string) 61 | obj.Type = in["type"].(string) 62 | if v, ok := in["description"].(string); ok { 63 | obj.Description = v 64 | } 65 | 66 | if v, ok := in["is_multi_valued"].(bool); ok { 67 | obj.IsMultiValued = v 68 | } 69 | if v, ok := in["is_entitlement"].(bool); ok { 70 | obj.IsEntitlement = v 71 | } 72 | 73 | if v, ok := in["is_group"].(bool); ok { 74 | obj.IsGroup = v 75 | } 76 | if v, ok := in["schema"].([]interface{}); ok && len(v) > 0 { 77 | obj.Schema = expandAccountSchemaAttributesSchema(v) 78 | } 79 | out = append(out, &obj) 80 | } 81 | 82 | return out 83 | } 84 | 85 | func expandAccountSchemaAttributesSchema(p []interface{}) *AccountSchemaAttributeSchema { 86 | obj := AccountSchemaAttributeSchema{} 87 | 88 | if len(p) == 0 || p[0] == nil { 89 | return &obj 90 | } 91 | in := p[0].(map[string]interface{}) 92 | 93 | obj.ID = in["id"].(string) 94 | obj.Name = in["name"].(string) 95 | obj.Type = in["type"].(string) 96 | 97 | return &obj 98 | } 99 | 100 | func getAccountSchemaAttribute(accountSchema *AccountSchema, name string) *AccountSchemaAttribute { 101 | attributes := accountSchema.Attributes 102 | for i := range attributes { 103 | if attributes[i].Name == name { 104 | return attributes[i] 105 | } 106 | } 107 | return nil 108 | } 109 | -------------------------------------------------------------------------------- /structure_account_schema_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testAccountSchemaConf *AccountSchema 11 | testAccountSchemaInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | testAccountSchemaConf = &AccountSchema{ 16 | DisplayAttribute: "distinguishedName", 17 | IdentityAttribute: "sAMAccountName", 18 | NativeObjectType: "User", 19 | Name: "account", 20 | SourceID: "2c9180835d191a86015d28455b4a2329", 21 | ID: "2c9180835d191a86015d28455b4a1234", 22 | HierarchyAttribute: "memberOf", 23 | IncludePermissions: false, 24 | Created: "2019-12-24T22:32:58.104Z", 25 | Modified: "2019-12-31T20:22:28.104Z", 26 | Attributes: []*AccountSchemaAttribute{ 27 | { 28 | Name: "sAMAccountName", 29 | Type: "STRING", 30 | IsEntitlement: true, 31 | IsGroup: false, 32 | IsMultiValued: false, 33 | }, 34 | { 35 | Name: "employeeId", 36 | Type: "STRING", 37 | IsEntitlement: false, 38 | IsGroup: false, 39 | IsMultiValued: false, 40 | Description: "Employee ID", 41 | }, 42 | { 43 | Name: "memberOf", 44 | Type: "STRING", 45 | Description: "Group membership", 46 | IsMultiValued: true, 47 | IsEntitlement: true, 48 | IsGroup: true, 49 | Schema: &AccountSchemaAttributeSchema{ 50 | Type: "CONNECTOR_SCHEMA", 51 | ID: "2c9180887671ff8c01767b4671fc7d60", 52 | Name: "group", 53 | }, 54 | }, 55 | }, 56 | } 57 | testAccountSchemaInterface = map[string]interface{}{ 58 | "source_id": "2c9180835d191a86015d28455b4a2329", 59 | "schema_id": "2c9180835d191a86015d28455b4a1234", 60 | "name": "account", 61 | "native_object_type": "User", 62 | "identity_attribute": "sAMAccountName", 63 | "display_attribute": "distinguishedName", 64 | "hierarchy_attribute": "memberOf", 65 | "include_permissions": false, 66 | "attributes": []interface{}{ 67 | map[string]interface{}{ 68 | "name": "sAMAccountName", 69 | "type": "STRING", 70 | "is_multi_valued": false, 71 | "is_entitlement": true, 72 | "is_group": false, 73 | "description": "", 74 | "schema": []interface{}{}, 75 | }, 76 | map[string]interface{}{ 77 | "name": "employeeId", 78 | "type": "STRING", 79 | "is_multi_valued": false, 80 | "is_entitlement": false, 81 | "is_group": false, 82 | "description": "Employee ID", 83 | "schema": []interface{}{}, 84 | }, 85 | map[string]interface{}{ 86 | "name": "memberOf", 87 | "type": "STRING", 88 | "description": "Group membership", 89 | "is_multi_valued": true, 90 | "is_entitlement": true, 91 | "is_group": true, 92 | "schema": []interface{}{ 93 | map[string]interface{}{ 94 | "type": "CONNECTOR_SCHEMA", 95 | "id": "2c9180887671ff8c01767b4671fc7d60", 96 | "name": "group", 97 | }, 98 | }, 99 | }, 100 | }, 101 | "created": "2019-12-24T22:32:58.104Z", 102 | "modified": "2019-12-31T20:22:28.104Z", 103 | } 104 | } 105 | 106 | func TestFlattenAccountSchemaAttribute(t *testing.T) { 107 | cases := []struct { 108 | Input *AccountSchema 109 | ExpectedOutput map[string]interface{} 110 | }{ 111 | { 112 | testAccountSchemaConf, 113 | testAccountSchemaInterface, 114 | }, 115 | } 116 | for _, tc := range cases { 117 | output := schema.TestResourceDataRaw(t, accountSchemaFields(), tc.ExpectedOutput) 118 | err := flattenAccountSchema(output, tc.Input) 119 | if err != nil { 120 | t.Fatalf("[ERROR] on flattener: %#v", err) 121 | } 122 | expectedOutput := map[string]interface{}{} 123 | for k := range tc.ExpectedOutput { 124 | expectedOutput[k] = output.Get(k) 125 | } 126 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 127 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 128 | tc.ExpectedOutput, expectedOutput) 129 | } 130 | } 131 | } 132 | 133 | func TestExpandAccountSchemaAttribute(t *testing.T) { 134 | cases := []struct { 135 | Input map[string]interface{} 136 | ExpectedOutput *AccountSchema 137 | }{ 138 | { 139 | testAccountSchemaInterface, 140 | testAccountSchemaConf, 141 | }, 142 | } 143 | 144 | for _, tc := range cases { 145 | inputResourceData := schema.TestResourceDataRaw(t, accountSchemaFields(), tc.Input) 146 | output, err := expandAccountSchema(inputResourceData) 147 | if err != nil { 148 | t.Fatalf("[ERROR] on flattener: %#v", err) 149 | } 150 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 151 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 152 | tc.ExpectedOutput, output) 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /structure_identity_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | reflect "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testIdentityConf *Identity 11 | testIdentityInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | testIdentityConf = &Identity{ 16 | Alias: "test_alias", 17 | Name: "Test Name", 18 | Description: "test description", 19 | EmailAddress: "test@email.com", 20 | IdentityStatus: "ACTIVE", 21 | Enabled: true, 22 | IsManager: false, 23 | IdentityAttributes: &IdentityAttributes{ 24 | AdpID: "12345", 25 | LastName: "Name", 26 | FirstName: "Test", 27 | Phone: "+11234567890", 28 | UserType: "Employee", 29 | UID: "tname", 30 | Email: "test@email.com", 31 | WorkdayId: "567890", 32 | }, 33 | } 34 | testIdentityInterface = map[string]interface{}{ 35 | "alias": "test_alias", 36 | "name": "Test Name", 37 | "description": "test description", 38 | "email_address": "test@email.com", 39 | "identity_status": "ACTIVE", 40 | "enabled": true, 41 | "is_manager": false, 42 | "attributes": []interface{}{ 43 | map[string]interface{}{ 44 | "adp_id": "12345", 45 | "lastname": "Name", 46 | "firstname": "Test", 47 | "phone": "11234567890", 48 | "user_type": "Employee", 49 | "uid": "tname", 50 | "email": "test@email.com", 51 | "workday_id": "567890", 52 | }, 53 | }, 54 | } 55 | } 56 | 57 | func TestFlattenIdentity(t *testing.T) { 58 | cases := []struct { 59 | Input *Identity 60 | ExpectedOutput map[string]interface{} 61 | }{ 62 | { 63 | testIdentityConf, 64 | testIdentityInterface, 65 | }, 66 | } 67 | for _, tc := range cases { 68 | output := schema.TestResourceDataRaw(t, identityFields(), tc.ExpectedOutput) 69 | err := flattenIdentity(output, tc.Input) 70 | if err != nil { 71 | t.Fatalf("[ERROR] on flattener: %#v", err) 72 | } 73 | expectedOutput := map[string]interface{}{} 74 | for k := range tc.ExpectedOutput { 75 | expectedOutput[k] = output.Get(k) 76 | } 77 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 78 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 79 | tc.ExpectedOutput, expectedOutput) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /structure_password_policy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | ) 7 | 8 | func flattenPasswordPolicy(d *schema.ResourceData, in *PasswordPolicy) error { 9 | if in == nil { 10 | return nil 11 | } 12 | 13 | d.SetId(in.ID) 14 | d.Set("account_id_min_word_length", in.AccountIDMinWordLength) 15 | d.Set("account_name_min_word_length", in.AccountNameMinWordLength) 16 | d.Set("default_policy", in.DefaultPolicy) 17 | d.Set("description", in.Description) 18 | d.Set("enable_password_expiration", in.EnablePasswordExpiration) 19 | d.Set("first_expiration_reminder", in.FirstExpirationReminder) 20 | d.Set("max_length", in.MaxLength) 21 | d.Set("max_repeated_chars", in.MaxRepeatedChars) 22 | d.Set("min_alpha", in.MinAlpha) 23 | d.Set("min_character_types", in.MinCharacterTypes) 24 | d.Set("min_length", in.MinLength) 25 | d.Set("min_lower", in.MinLower) 26 | d.Set("min_numeric", in.MinNumeric) 27 | d.Set("min_special", in.MinSpecial) 28 | d.Set("min_upper", in.MinUpper) 29 | d.Set("name", in.Name) 30 | d.Set("password_expiration", in.PasswordExpiration) 31 | d.Set("require_strong_auth_off_network", in.RequireStrongAuthOffNetwork) 32 | d.Set("require_strong_auth_untrusted_geographies", in.RequireStrongAuthUntrustedGeographies) 33 | d.Set("require_strong_authn", in.RequireStrongAuthn) 34 | d.Set("use_account_attributes", in.UseAccountAttributes) 35 | d.Set("use_dictionary", in.UseDictionary) 36 | d.Set("use_history", in.UseHistory) 37 | d.Set("use_identity_attributes", in.UseIdentityAttributes) 38 | d.Set("validate_against_account_id", in.ValidateAgainstAccountID) 39 | d.Set("validate_against_account_name", in.ValidateAgainstAccountName) 40 | d.Set("source_ids", toArrayInterface(in.SourceIDs)) 41 | 42 | if in.ConnectedServices != nil { 43 | d.Set("connected_services", flattenPasswordPolicyConnectedServices(in.ConnectedServices)) 44 | } 45 | return nil 46 | } 47 | 48 | func expandPasswordPolicy(in *schema.ResourceData) (*PasswordPolicy, error) { 49 | obj := PasswordPolicy{} 50 | if in == nil { 51 | return nil, fmt.Errorf("[ERROR] Expanding Password Policy: Schema Resource data is nil") 52 | } 53 | if v := in.Id(); len(v) > 0 { 54 | obj.ID = v 55 | } 56 | 57 | obj.Name = in.Get("name").(string) 58 | obj.Description = in.Get("description").(string) 59 | 60 | if v, ok := in.Get("account_name_min_word_length").(int); ok { 61 | obj.AccountNameMinWordLength = &v 62 | } 63 | 64 | if v, ok := in.Get("account_id_min_word_length").(int); ok { 65 | obj.AccountIDMinWordLength = &v 66 | } 67 | 68 | if v, ok := in.Get("connected_services").([]interface{}); ok && len(v) > 0 { 69 | obj.ConnectedServices = expandPasswordPolicyConnectedServices(v) 70 | } 71 | 72 | if v, ok := in.Get("default_policy").(bool); ok { 73 | obj.DefaultPolicy = &v 74 | } 75 | 76 | if v, ok := in.Get("enable_password_expiration").(bool); ok { 77 | obj.EnablePasswordExpiration = &v 78 | } 79 | 80 | if v, ok := in.Get("first_expiration_reminder").(int); ok { 81 | obj.FirstExpirationReminder = &v 82 | } 83 | 84 | if v, ok := in.Get("max_length").(int); ok { 85 | obj.MaxLength = &v 86 | } 87 | 88 | if v, ok := in.Get("max_repeated_chars").(int); ok { 89 | obj.MaxRepeatedChars = &v 90 | } 91 | 92 | if v, ok := in.Get("min_alpha").(int); ok { 93 | obj.MinAlpha = &v 94 | } 95 | 96 | if v, ok := in.Get("min_character_types").(int); ok { 97 | obj.MinCharacterTypes = &v 98 | } 99 | 100 | if v, ok := in.Get("min_length").(int); ok { 101 | obj.MinLength = &v 102 | } 103 | 104 | if v, ok := in.Get("min_lower").(int); ok { 105 | obj.MinLower = &v 106 | } 107 | 108 | if v, ok := in.Get("min_numeric").(int); ok { 109 | obj.MinNumeric = &v 110 | } 111 | 112 | if v, ok := in.Get("min_special").(int); ok { 113 | obj.MinSpecial = &v 114 | } 115 | 116 | if v, ok := in.Get("min_upper").(int); ok { 117 | obj.MinUpper = &v 118 | } 119 | 120 | if v, ok := in.Get("password_expiration").(int); ok { 121 | obj.PasswordExpiration = &v 122 | } 123 | 124 | if v, ok := in.Get("require_strong_auth_off_network").(bool); ok { 125 | obj.RequireStrongAuthOffNetwork = &v 126 | } 127 | 128 | if v, ok := in.Get("require_strong_auth_untrusted_geographies").(bool); ok { 129 | obj.RequireStrongAuthUntrustedGeographies = &v 130 | } 131 | 132 | if v, ok := in.Get("require_strong_authn").(bool); ok { 133 | obj.RequireStrongAuthn = &v 134 | } 135 | 136 | if v, ok := in.Get("use_account_attributes").(bool); ok { 137 | obj.UseAccountAttributes = &v 138 | } 139 | 140 | if v, ok := in.Get("use_dictionary").(bool); ok { 141 | obj.UseDictionary = &v 142 | } 143 | 144 | if v, ok := in.Get("use_history").(int); ok { 145 | obj.UseHistory = &v 146 | } 147 | 148 | if v, ok := in.Get("use_identity_attributes").(bool); ok { 149 | obj.UseIdentityAttributes = &v 150 | } 151 | 152 | if v, ok := in.Get("validate_against_account_id").(bool); ok { 153 | obj.ValidateAgainstAccountID = &v 154 | } 155 | 156 | if v, ok := in.Get("validate_against_account_name").(bool); ok { 157 | obj.ValidateAgainstAccountName = &v 158 | } 159 | 160 | if v, ok := in.Get("source_ids").([]interface{}); ok && len(v) > 0 { 161 | obj.SourceIDs = toArrayString(v) 162 | } 163 | 164 | return &obj, nil 165 | } 166 | -------------------------------------------------------------------------------- /structure_password_policy_connected_services.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func flattenPasswordPolicyConnectedServices(in []*ConnectedServices) []interface{} { 4 | if in == nil { 5 | return []interface{}{} 6 | } 7 | 8 | out := make([]interface{}, 0, len(in)) 9 | for i := range in { 10 | var obj = make(map[string]interface{}) 11 | obj["id"] = in[i].ID 12 | obj["external_id"] = in[i].ExternalID 13 | obj["name"] = in[i].Name 14 | obj["app_count"] = in[i].AppCount 15 | obj["supports_password_set_date"] = in[i].SupportsPasswordSetDate 16 | out = append(out, obj) 17 | } 18 | 19 | return out 20 | } 21 | 22 | func expandPasswordPolicyConnectedServices(p []interface{}) []*ConnectedServices { 23 | if len(p) == 0 || p[0] == nil { 24 | return []*ConnectedServices{} 25 | } 26 | out := make([]*ConnectedServices, 0, len(p)) 27 | for i := range p { 28 | obj := ConnectedServices{} 29 | in := p[i].(map[string]interface{}) 30 | obj.ID = in["id"].(string) 31 | obj.ExternalID = in["external_id"].(string) 32 | obj.Name = in["name"].(string) 33 | obj.AppCount = in["app_count"].(int) 34 | obj.SupportsPasswordSetDate = in["supports_password_set_date"].(bool) 35 | out = append(out, &obj) 36 | } 37 | 38 | return out 39 | } 40 | -------------------------------------------------------------------------------- /structure_password_policy_connected_services_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testConnectedServicesConf []*ConnectedServices 10 | testConnectedServicesInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testConnectedServicesConf = []*ConnectedServices{ 15 | { 16 | ID: "123", 17 | ExternalID: "123abc", 18 | Name: "some name", 19 | AppCount: 1, 20 | SupportsPasswordSetDate: false, 21 | }, 22 | { 23 | ID: "456", 24 | ExternalID: "456abc", 25 | Name: "some other name", 26 | AppCount: 1, 27 | SupportsPasswordSetDate: false, 28 | }, 29 | } 30 | testConnectedServicesInterface = []interface{}{ 31 | map[string]interface{}{ 32 | "id": "123", 33 | "external_id": "123abc", 34 | "name": "some name", 35 | "app_count": 1, 36 | "supports_password_set_date": false, 37 | }, 38 | map[string]interface{}{ 39 | "id": "456", 40 | "external_id": "456abc", 41 | "name": "some other name", 42 | "app_count": 1, 43 | "supports_password_set_date": false, 44 | }, 45 | } 46 | } 47 | 48 | func TestFlattenPasswordPolicyConnectedServices(t *testing.T) { 49 | 50 | cases := []struct { 51 | Input []*ConnectedServices 52 | ExpectedOutput []interface{} 53 | }{ 54 | { 55 | testConnectedServicesConf, 56 | testConnectedServicesInterface, 57 | }, 58 | } 59 | 60 | for _, tc := range cases { 61 | output := flattenPasswordPolicyConnectedServices(tc.Input) 62 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 63 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 64 | tc.ExpectedOutput, output) 65 | } 66 | } 67 | } 68 | 69 | func TestExpandPasswordPolicyConnectedServices(t *testing.T) { 70 | cases := []struct { 71 | Input []interface{} 72 | ExpectedOutput []*ConnectedServices 73 | }{ 74 | { 75 | testConnectedServicesInterface, 76 | testConnectedServicesConf, 77 | }, 78 | } 79 | 80 | for _, tc := range cases { 81 | output := expandPasswordPolicyConnectedServices(tc.Input) 82 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 83 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 84 | tc.ExpectedOutput, output) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /structure_password_policy_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testPassPolicyConf *PasswordPolicy 11 | testPassPolicyInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | TRUE := true 16 | FALSE := false 17 | num1 := 5 18 | num2 := 1 19 | testPassPolicyConf = &PasswordPolicy{ 20 | AccountIDMinWordLength: &num1, 21 | AccountNameMinWordLength: &num1, 22 | DefaultPolicy: &FALSE, 23 | Description: "some description", 24 | EnablePasswordExpiration: &FALSE, 25 | FirstExpirationReminder: &num1, 26 | MaxLength: &num2, 27 | MaxRepeatedChars: &num2, 28 | MinAlpha: &num2, 29 | MinCharacterTypes: &num2, 30 | MinLength: &num2, 31 | MinLower: &num2, 32 | MinNumeric: &num2, 33 | MinSpecial: &num2, 34 | MinUpper: &num2, 35 | Name: "some name", 36 | PasswordExpiration: &num1, 37 | RequireStrongAuthOffNetwork: &TRUE, 38 | RequireStrongAuthUntrustedGeographies: &TRUE, 39 | RequireStrongAuthn: &TRUE, 40 | UseAccountAttributes: &TRUE, 41 | UseDictionary: &TRUE, 42 | UseHistory: &num2, 43 | UseIdentityAttributes: &TRUE, 44 | ValidateAgainstAccountID: &TRUE, 45 | ValidateAgainstAccountName: &FALSE, 46 | } 47 | testPassPolicyInterface = map[string]interface{}{ 48 | "account_id_min_word_length": num1, 49 | "account_name_min_word_length": num1, 50 | "default_policy": FALSE, 51 | "description": "some description", 52 | "enable_password_expiration": FALSE, 53 | "first_expiration_reminder": num1, 54 | "max_length": num2, 55 | "max_repeated_chars": num2, 56 | "min_alpha": num2, 57 | "min_character_types": num2, 58 | "min_length": num2, 59 | "min_lower": num2, 60 | "min_numeric": num2, 61 | "min_special": num2, 62 | "min_upper": num2, 63 | "name": "some name", 64 | "password_expiration": num1, 65 | "require_strong_auth_off_network": TRUE, 66 | "require_strong_auth_untrusted_geographies": TRUE, 67 | "require_strong_authn": TRUE, 68 | "use_account_attributes": TRUE, 69 | "use_dictionary": TRUE, 70 | "use_history": num2, 71 | "use_identity_attributes": TRUE, 72 | "validate_against_account_id": TRUE, 73 | "validate_against_account_name": FALSE, 74 | } 75 | } 76 | 77 | func TestFlattenPasswordPolicy(t *testing.T) { 78 | cases := []struct { 79 | Input *PasswordPolicy 80 | ExpectedOutput map[string]interface{} 81 | }{ 82 | { 83 | testPassPolicyConf, 84 | testPassPolicyInterface, 85 | }, 86 | } 87 | for _, tc := range cases { 88 | output := schema.TestResourceDataRaw(t, passwordPolicyFields(), tc.ExpectedOutput) 89 | err := flattenPasswordPolicy(output, tc.Input) 90 | if err != nil { 91 | t.Fatalf("[ERROR] on flattener: %#v", err) 92 | } 93 | expectedOutput := map[string]interface{}{} 94 | for k := range tc.ExpectedOutput { 95 | expectedOutput[k] = output.Get(k) 96 | } 97 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 98 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 99 | tc.ExpectedOutput, expectedOutput) 100 | } 101 | } 102 | } 103 | 104 | func TestExpandPasswordPolicy(t *testing.T) { 105 | cases := []struct { 106 | Input map[string]interface{} 107 | ExpectedOutput *PasswordPolicy 108 | }{ 109 | { 110 | testPassPolicyInterface, 111 | testPassPolicyConf, 112 | }, 113 | } 114 | 115 | for _, tc := range cases { 116 | inputResourceData := schema.TestResourceDataRaw(t, passwordPolicyFields(), tc.Input) 117 | output, err := expandPasswordPolicy(inputResourceData) 118 | if err != nil { 119 | t.Fatalf("[ERROR] on flattener: %#v", err) 120 | } 121 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 122 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 123 | tc.ExpectedOutput, output) 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /structure_role.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 6 | ) 7 | 8 | // Flatteners 9 | 10 | func flattenRole(d *schema.ResourceData, in *Role) error { 11 | if in == nil { 12 | return nil 13 | } 14 | 15 | d.SetId(in.ID) 16 | d.Set("description", in.Description) 17 | d.Set("name", in.Name) 18 | d.Set("requestable", in.Requestable) 19 | d.Set("enabled", in.Enabled) 20 | 21 | if in.RoleOwner != nil { 22 | v, ok := d.Get("owner").([]interface{}) 23 | if !ok { 24 | v = []interface{}{} 25 | } 26 | roleOwnerList := []*ObjectInfo{in.RoleOwner} 27 | d.Set("owner", flattenObjectRoles(roleOwnerList, v)) 28 | } 29 | if in.AccessProfiles != nil { 30 | v, ok := d.Get("access_profiles").([]interface{}) 31 | if !ok { 32 | v = []interface{}{} 33 | } 34 | 35 | d.Set("access_profiles", flattenObjectRoles(in.AccessProfiles, v)) 36 | } 37 | return nil 38 | } 39 | 40 | func flattenObjectRoles(in []*ObjectInfo, p []interface{}) []interface{} { 41 | if in == nil { 42 | return []interface{}{} 43 | } 44 | 45 | out := make([]interface{}, 0, len(in)) 46 | for i := range in { 47 | var obj = make(map[string]interface{}) 48 | obj["type"] = in[i].Type 49 | obj["id"] = in[i].ID 50 | obj["name"] = in[i].Name 51 | out = append(out, obj) 52 | } 53 | return out 54 | } 55 | 56 | // Expanders 57 | 58 | func expandRole(in *schema.ResourceData) (*Role, error) { 59 | obj := Role{} 60 | if in == nil { 61 | return nil, fmt.Errorf("[ERROR] Expanding Role: Schema Resource data is nil") 62 | } 63 | if v := in.Id(); len(v) > 0 { 64 | obj.ID = v 65 | } 66 | 67 | obj.Description = in.Get("description").(string) 68 | obj.Name = in.Get("name").(string) 69 | 70 | if v, ok := in.Get("requestable").(bool); ok { 71 | obj.Requestable = &v 72 | } 73 | 74 | if v, ok := in.Get("owner").([]interface{}); ok && len(v) > 0 { 75 | obj.RoleOwner = expandObjectRoles(v)[0] 76 | } 77 | 78 | if v, ok := in.Get("access_profiles").([]interface{}); ok && len(v) > 0 { 79 | obj.AccessProfiles = expandObjectRoles(v) 80 | } 81 | 82 | if v, ok := in.Get("enabled").(bool); ok { 83 | obj.Enabled = &v 84 | } 85 | 86 | return &obj, nil 87 | } 88 | 89 | func expandUpdateRole(in *schema.ResourceData) ([]*UpdateRole, interface{}, error) { 90 | updatableFields := []string{"name", "description", "enabled", "owner", "accessProfiles", "requestable"} 91 | var id interface{} 92 | if in == nil { 93 | return nil, nil, fmt.Errorf("[ERROR] Expanding Role: Schema Resource data is nil") 94 | } 95 | 96 | if v := in.Id(); len(v) > 0 { 97 | id = v 98 | } 99 | 100 | out := []*UpdateRole{} 101 | 102 | for i := range updatableFields { 103 | obj := UpdateRole{} 104 | if v, ok := in.Get(fmt.Sprintf("/%s", updatableFields[i])).([]interface{}); ok { 105 | obj.Op = "replace" 106 | obj.Path = fmt.Sprintf("/%s", updatableFields[i]) 107 | obj.Value = v 108 | } 109 | out = append(out, &obj) 110 | } 111 | 112 | return out, id, nil 113 | } 114 | 115 | func expandObjectRoles(p []interface{}) []*ObjectInfo { 116 | if len(p) == 0 || p[0] == nil { 117 | return []*ObjectInfo{} 118 | } 119 | out := make([]*ObjectInfo, 0, len(p)) 120 | for i := range p { 121 | obj := ObjectInfo{} 122 | in := p[i].(map[string]interface{}) 123 | obj.ID = in["id"].(string) 124 | obj.Name = in["name"].(string) 125 | obj.Type = in["type"].(string) 126 | out = append(out, &obj) 127 | } 128 | return out 129 | } 130 | -------------------------------------------------------------------------------- /structure_role_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | reflect "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testRoleConf *Role 11 | testRoleInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | TRUE := true 16 | FALSE := false 17 | testRoleConf = &Role{ 18 | Description: "test description", 19 | Enabled: &TRUE, 20 | Name: "test name", 21 | RoleOwner: &ObjectInfo{ 22 | ID: "2c9180887412345678948078d29f2e46", 23 | Name: "SRE Test", 24 | Type: "IDENTITY", 25 | }, 26 | AccessProfiles: []*ObjectInfo{ 27 | { 28 | ID: "2c918088747654398948078d29f2e46", 29 | Name: "Test Developer", 30 | Type: "ACCESS_PROFILE", 31 | }, 32 | { 33 | ID: "2c918009437654398948078d29f2e46", 34 | Name: "Test Operator", 35 | Type: "ACCESS_PROFILE", 36 | }, 37 | }, 38 | Requestable: &FALSE, 39 | } 40 | testRoleInterface = map[string]interface{}{ 41 | "access_profiles": []interface{}{ 42 | map[string]interface{}{ 43 | "id": "2c918088747654398948078d29f2e46", 44 | "name": "Test Developer", 45 | "type": "ACCESS_PROFILE", 46 | }, 47 | map[string]interface{}{ 48 | "id": "2c918009437654398948078d29f2e46", 49 | "name": "Test Operator", 50 | "type": "ACCESS_PROFILE", 51 | }, 52 | }, 53 | "owner": []interface{}{ 54 | map[string]interface{}{ 55 | "id": "2c9180887412345678948078d29f2e46", 56 | "name": "SRE Test", 57 | "type": "IDENTITY", 58 | }, 59 | }, 60 | "description": "test description", 61 | "enabled": true, 62 | "name": "test name", 63 | "requestable": false, 64 | } 65 | } 66 | 67 | func TestFlattenRole(t *testing.T) { 68 | cases := []struct { 69 | Input *Role 70 | ExpectedOutput map[string]interface{} 71 | }{ 72 | { 73 | testRoleConf, 74 | testRoleInterface, 75 | }, 76 | } 77 | for _, tc := range cases { 78 | output := schema.TestResourceDataRaw(t, roleFields(), tc.ExpectedOutput) 79 | err := flattenRole(output, tc.Input) 80 | if err != nil { 81 | t.Fatalf("[ERROR] on flattener: %#v", err) 82 | } 83 | expectedOutput := map[string]interface{}{} 84 | for k := range tc.ExpectedOutput { 85 | expectedOutput[k] = output.Get(k) 86 | } 87 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 88 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 89 | tc.ExpectedOutput, expectedOutput) 90 | } 91 | } 92 | } 93 | 94 | func TestExpandRole(t *testing.T) { 95 | cases := []struct { 96 | Input map[string]interface{} 97 | ExpectedOutput *Role 98 | }{ 99 | { 100 | testRoleInterface, 101 | testRoleConf, 102 | }, 103 | } 104 | 105 | for _, tc := range cases { 106 | inputResourceData := schema.TestResourceDataRaw(t, roleFields(), tc.Input) 107 | output, err := expandRole(inputResourceData) 108 | if err != nil { 109 | t.Fatalf("[ERROR] on flattener: %#v", err) 110 | } 111 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 112 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 113 | tc.ExpectedOutput, output) 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /structure_source.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 7 | ) 8 | 9 | // Flatteners 10 | 11 | func flattenSource(d *schema.ResourceData, in *Source) error { 12 | if in == nil { 13 | return nil 14 | } 15 | 16 | d.SetId(in.ID) 17 | d.Set("name", in.Name) 18 | d.Set("description", in.Description) 19 | d.Set("connector", in.Connector) 20 | d.Set("delete_threshold", in.DeleteThreshold) 21 | d.Set("authoritative", in.Authoritative) 22 | d.Set("type", in.Type) 23 | 24 | if in.Owner != nil { 25 | v, ok := d.Get("owner").([]interface{}) 26 | if !ok { 27 | v = []interface{}{} 28 | } 29 | 30 | d.Set("owner", flattenSourceOwner(in.Owner, v)) 31 | } 32 | 33 | if in.Cluster != nil { 34 | v, ok := d.Get("cluster").([]interface{}) 35 | if !ok { 36 | v = []interface{}{} 37 | } 38 | 39 | d.Set("cluster", flattenSourceCluster(in.Cluster, v)) 40 | } 41 | 42 | if in.AccountCorrelationConfig != nil { 43 | v, ok := d.Get("account_correlation_config").([]interface{}) 44 | if !ok { 45 | v = []interface{}{} 46 | } 47 | 48 | d.Set("account_correlation_config", flattenSourceAccountCorrelationConfig(in.AccountCorrelationConfig, v)) 49 | } 50 | 51 | if in.ConnectorAttributes != nil { 52 | v, ok := d.Get("connector_attributes").([]interface{}) 53 | if !ok { 54 | v = []interface{}{} 55 | } 56 | 57 | d.Set("connector_attributes", flattenSourceConnectorAttributes(in.ConnectorAttributes, v)) 58 | } 59 | 60 | if in.Schemas != nil { 61 | v, ok := d.Get("schemas").([]interface{}) 62 | if !ok { 63 | v = []interface{}{} 64 | } 65 | 66 | d.Set("schemas", flattenSourceSchema(in.Schemas, v)) 67 | } 68 | 69 | if in.ManagementWorkgroup != nil { 70 | v, ok := d.Get("ManagementWorkgroup").([]interface{}) 71 | if !ok { 72 | v = []interface{}{} 73 | } 74 | 75 | d.Set("management_workgroup", flattenSourceManagementWorkgroup(in.ManagementWorkgroup, v)) 76 | } 77 | 78 | if in.PasswordPolicies != nil { 79 | d.Set("password_policies", flattenSourcePasswordPolicies(in.PasswordPolicies)) 80 | } 81 | 82 | return nil 83 | } 84 | 85 | // Expanders 86 | 87 | func expandSource(in *schema.ResourceData) (*Source, error) { 88 | obj := Source{} 89 | if in == nil { 90 | return nil, fmt.Errorf("[ERROR] Expanding source: Schema Resource data is nil") 91 | } 92 | if v := in.Id(); len(v) > 0 { 93 | obj.ID = v 94 | } 95 | 96 | obj.Name = in.Get("name").(string) 97 | obj.Description = in.Get("description").(string) 98 | obj.Connector = in.Get("connector").(string) 99 | obj.Type = in.Get("type").(string) 100 | 101 | if v, ok := in.Get("authoritative").(bool); ok { 102 | obj.Authoritative = v 103 | } 104 | 105 | if v, ok := in.Get("delete_threshold").(int); ok { 106 | obj.DeleteThreshold = v 107 | } 108 | 109 | if v, ok := in.Get("owner").([]interface{}); ok && len(v) > 0 { 110 | obj.Owner = expandSourceOwner(v) 111 | } 112 | 113 | if v, ok := in.Get("schemas").([]interface{}); ok && len(v) > 0 { 114 | obj.Schemas = expandSourceSchema(v) 115 | } 116 | 117 | if v, ok := in.Get("cluster").([]interface{}); ok && len(v) > 0 { 118 | obj.Cluster = expandSourceCluster(v) 119 | } 120 | 121 | if v, ok := in.Get("account_correlation_config").([]interface{}); ok && len(v) > 0 { 122 | obj.AccountCorrelationConfig = expandSourceAccountCorrelationConfig(v) 123 | } 124 | 125 | if v, ok := in.Get("connector_attributes").([]interface{}); ok && len(v) > 0 { 126 | obj.ConnectorAttributes = expandSourceConnectorAttributes(v) 127 | } 128 | 129 | if v, ok := in.Get("management_workgroup").([]interface{}); ok && len(v) > 0 { 130 | obj.ManagementWorkgroup = expandSourceManagementWorkgroup(v) 131 | } 132 | 133 | if v, ok := in.Get("password_policies").([]interface{}); ok && len(v) > 0 { 134 | obj.PasswordPolicies = expandSourcePasswordPolicies(v) 135 | } 136 | 137 | return &obj, nil 138 | } 139 | -------------------------------------------------------------------------------- /structure_source_account_correlation_config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceAccountCorrelationConfig(in *AccountCorrelationConfig, p []interface{}) []interface{} { 6 | var obj map[string]interface{} 7 | if len(p) == 0 || p[0] == nil { 8 | obj = make(map[string]interface{}) 9 | } else { 10 | obj = p[0].(map[string]interface{}) 11 | } 12 | 13 | if in == nil { 14 | return []interface{}{} 15 | } 16 | 17 | obj["type"] = in.Type 18 | obj["id"] = in.ID 19 | obj["name"] = in.Name 20 | 21 | return []interface{}{obj} 22 | 23 | } 24 | 25 | // Expanders 26 | 27 | func expandSourceAccountCorrelationConfig(p []interface{}) *AccountCorrelationConfig { 28 | obj := AccountCorrelationConfig{} 29 | 30 | if len(p) == 0 || p[0] == nil { 31 | return &obj 32 | } 33 | in := p[0].(map[string]interface{}) 34 | 35 | obj.ID = in["id"].(string) 36 | obj.Name = in["name"].(string) 37 | obj.Type = in["type"].(string) 38 | 39 | return &obj 40 | } 41 | -------------------------------------------------------------------------------- /structure_source_account_correlation_config_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testAccountCorrelationConfigConf *AccountCorrelationConfig 10 | testAccountCorrelationConfigInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testAccountCorrelationConfigConf = &AccountCorrelationConfig{ 15 | Type: "TYPE", 16 | ID: "1234-id", 17 | Name: "test-name", 18 | } 19 | testAccountCorrelationConfigInterface = []interface{}{ 20 | map[string]interface{}{ 21 | "type": "TYPE", 22 | "id": "1234-id", 23 | "name": "test-name", 24 | }, 25 | } 26 | } 27 | 28 | func TestFlattenSourceAccountCorrelationConfig(t *testing.T) { 29 | 30 | cases := []struct { 31 | Input *AccountCorrelationConfig 32 | ExpectedOutput []interface{} 33 | }{ 34 | { 35 | testAccountCorrelationConfigConf, 36 | testAccountCorrelationConfigInterface, 37 | }, 38 | } 39 | 40 | for _, tc := range cases { 41 | output := flattenSourceAccountCorrelationConfig(tc.Input, []interface{}{}) 42 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 43 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 44 | tc.ExpectedOutput, output) 45 | } 46 | } 47 | } 48 | 49 | func TestExpandSourceAccountCorrelationConfig(t *testing.T) { 50 | cases := []struct { 51 | Input []interface{} 52 | ExpectedOutput *AccountCorrelationConfig 53 | }{ 54 | { 55 | testAccountCorrelationConfigInterface, 56 | testAccountCorrelationConfigConf, 57 | }, 58 | } 59 | 60 | for _, tc := range cases { 61 | output := expandSourceAccountCorrelationConfig(tc.Input) 62 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 63 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 64 | tc.ExpectedOutput, output) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /structure_source_cluster.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceCluster(in *Cluster, p []interface{}) []interface{} { 6 | var obj map[string]interface{} 7 | if len(p) == 0 || p[0] == nil { 8 | obj = make(map[string]interface{}) 9 | } else { 10 | obj = p[0].(map[string]interface{}) 11 | } 12 | 13 | if in == nil { 14 | return []interface{}{} 15 | } 16 | 17 | obj["type"] = in.Type 18 | obj["id"] = in.ID 19 | obj["name"] = in.Name 20 | 21 | return []interface{}{obj} 22 | 23 | } 24 | 25 | // Expanders 26 | 27 | func expandSourceCluster(p []interface{}) *Cluster { 28 | obj := Cluster{} 29 | 30 | if len(p) == 0 || p[0] == nil { 31 | return &obj 32 | } 33 | in := p[0].(map[string]interface{}) 34 | 35 | obj.ID = in["id"].(string) 36 | obj.Name = in["name"].(string) 37 | obj.Type = in["type"].(string) 38 | 39 | return &obj 40 | } 41 | -------------------------------------------------------------------------------- /structure_source_cluster_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testClusterConf *Cluster 10 | testClusterInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testClusterConf = &Cluster{ 15 | Type: "CLUSTER", 16 | ID: "1234-id", 17 | Name: "test-name", 18 | } 19 | testClusterInterface = []interface{}{ 20 | map[string]interface{}{ 21 | "type": "CLUSTER", 22 | "id": "1234-id", 23 | "name": "test-name", 24 | }, 25 | } 26 | } 27 | 28 | func TestFlattenSourceCluster(t *testing.T) { 29 | 30 | cases := []struct { 31 | Input *Cluster 32 | ExpectedOutput []interface{} 33 | }{ 34 | { 35 | testClusterConf, 36 | testClusterInterface, 37 | }, 38 | } 39 | 40 | for _, tc := range cases { 41 | output := flattenSourceCluster(tc.Input, []interface{}{}) 42 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 43 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 44 | tc.ExpectedOutput, output) 45 | } 46 | } 47 | } 48 | 49 | func TestExpandSourceCluster(t *testing.T) { 50 | cases := []struct { 51 | Input []interface{} 52 | ExpectedOutput *Cluster 53 | }{ 54 | { 55 | testClusterInterface, 56 | testClusterConf, 57 | }, 58 | } 59 | 60 | for _, tc := range cases { 61 | output := expandSourceCluster(tc.Input) 62 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 63 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 64 | tc.ExpectedOutput, output) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /structure_source_connector_attributes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceConnectorAttributes(in *ConnectorAttributes, p []interface{}) []interface{} { 6 | var obj map[string]interface{} 7 | if len(p) == 0 || p[0] == nil { 8 | obj = make(map[string]interface{}) 9 | } else { 10 | obj = p[0].(map[string]interface{}) 11 | } 12 | 13 | if in == nil { 14 | return []interface{}{} 15 | } 16 | 17 | obj["grant_type"] = in.GrantType 18 | obj["client_id"] = in.ClientID 19 | obj["client_secret"] = in.ClientSecret 20 | obj["domain_name"] = in.DomainName 21 | obj["cloud_external_id"] = in.CloudExternalID 22 | obj["ms_graph_resource_base"] = in.MsGraphResourceBase 23 | obj["ms_graph_token_base"] = in.MsGraphTokenBase 24 | obj["azure_ad_graph_resource_base"] = in.AzureADGraphResourceBase 25 | obj["azure_ad_graph_token_base"] = in.AzureADGraphTokenBase 26 | obj["iq_service_host"] = in.IQServiceHost 27 | obj["iq_service_port"] = in.IQServicePort 28 | obj["use_tls_for_iq_service"] = in.UseTLSForIQService 29 | obj["iq_service_user"] = in.IQServiceUser 30 | obj["iq_service_password"] = in.IQServicePassword 31 | obj["authorization_type"] = in.AuthorizationType 32 | obj["api_version"] = in.ApiVersion 33 | obj["exclude_aws_account_id_list"] = in.ExcludeAWSAccountIdList 34 | obj["include_aws_account_id_list"] = in.IncludeAWSAccountIdList 35 | obj["kid"] = in.Kid 36 | obj["secret"] = in.Secret 37 | obj["role_name"] = in.RoleName 38 | obj["manage_all_accounts_iam_data"] = in.ManageAllAccountsIAMData 39 | obj["connector_class"] = in.ConnectorClass 40 | obj["encrypted"] = in.Encrypted 41 | 42 | if in.DomainSettings != nil { 43 | obj["domain_settings"] = flattenSourceDomainSettings(in.DomainSettings) 44 | } 45 | 46 | if in.ForestSettings != nil { 47 | obj["forest_settings"] = flattenSourceForestSettings(in.ForestSettings) 48 | } 49 | 50 | if in.SearchDNs != nil { 51 | obj["search_dns"] = flattenSourceSearchDNs(in.SearchDNs) 52 | } 53 | 54 | if in.GroupSearchDNs != nil { 55 | obj["group_search_dns"] = flattenSourceGroupSearchDNs(in.GroupSearchDNs) 56 | } 57 | 58 | return []interface{}{obj} 59 | 60 | } 61 | 62 | // Expanders 63 | 64 | func expandSourceConnectorAttributes(p []interface{}) *ConnectorAttributes { 65 | obj := ConnectorAttributes{} 66 | 67 | if len(p) == 0 || p[0] == nil { 68 | return &obj 69 | } 70 | in := p[0].(map[string]interface{}) 71 | 72 | obj.GrantType = in["grant_type"].(string) 73 | obj.ClientID = in["client_id"].(string) 74 | obj.ClientSecret = in["client_secret"].(string) 75 | obj.DomainName = in["domain_name"].(string) 76 | obj.CloudExternalID = in["cloud_external_id"].(string) 77 | obj.MsGraphResourceBase = in["ms_graph_resource_base"].(string) 78 | obj.MsGraphTokenBase = in["ms_graph_token_base"].(string) 79 | obj.AzureADGraphResourceBase = in["azure_ad_graph_resource_base"].(string) 80 | obj.AzureADGraphTokenBase = in["azure_ad_graph_token_base"].(string) 81 | obj.IQServiceHost = in["iq_service_host"].(string) 82 | obj.IQServicePort = in["iq_service_port"].(string) 83 | obj.UseTLSForIQService = in["use_tls_for_iq_service"].(bool) 84 | obj.IQServiceUser = in["iq_service_user"].(string) 85 | obj.IQServicePassword = in["iq_service_password"].(string) 86 | obj.AuthorizationType = in["authorization_type"].(string) 87 | obj.ApiVersion = in["api_version"].(string) 88 | obj.ExcludeAWSAccountIdList = in["exclude_aws_account_id_list"].(string) 89 | obj.IncludeAWSAccountIdList = in["include_aws_account_id_list"].(string) 90 | obj.Kid = in["kid"].(string) 91 | obj.Secret = in["secret"].(string) 92 | obj.RoleName = in["role_name"].(string) 93 | obj.ManageAllAccountsIAMData = in["manage_all_accounts_iam_data"].(bool) 94 | obj.ConnectorClass = in["connector_class"].(string) 95 | obj.Encrypted = in["encrypted"].(string) 96 | 97 | if v, ok := in["forest_settings"].([]interface{}); ok && len(v) > 0 { 98 | obj.ForestSettings = expandSourceForestSettings(v) 99 | } 100 | 101 | if v, ok := in["domain_settings"].([]interface{}); ok && len(v) > 0 { 102 | obj.DomainSettings = expandSourceDomainSettings(v) 103 | } 104 | 105 | if v, ok := in["search_dns"].([]interface{}); ok && len(v) > 0 { 106 | obj.SearchDNs = expandSourceSearchDNs(v) 107 | } 108 | 109 | if v, ok := in["group_search_dns"].([]interface{}); ok && len(v) > 0 { 110 | obj.GroupSearchDNs = expandSourceGroupSearchDNs(v) 111 | } 112 | 113 | return &obj 114 | } 115 | -------------------------------------------------------------------------------- /structure_source_connector_attributes_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testConnectorAttributesConf *ConnectorAttributes 10 | testConnectorAttributesInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testConnectorAttributesConf = &ConnectorAttributes{ 15 | GrantType: "grant-type-value", 16 | ClientID: "client-id-value", 17 | ClientSecret: "client-secret-value", 18 | DomainName: "domain-name-value", 19 | CloudExternalID: "cloud-external-value", 20 | MsGraphResourceBase: "ms-graph-resource-base-value", 21 | MsGraphTokenBase: "ms-graph-token-base-value", 22 | AzureADGraphResourceBase: "azure-ad-graph-resource-base-value", 23 | AzureADGraphTokenBase: "azure-ad-graph-token-base", 24 | IQServicePort: "1234", 25 | IQServicePassword: "iq-service-password-value", 26 | IQServiceUser: "iq-service-user-value", 27 | IQServiceHost: "iq-service-host.com", 28 | UseTLSForIQService: true, 29 | AuthorizationType: "simple", 30 | ApiVersion: "1.6", 31 | ExcludeAWSAccountIdList: "123456789,987654321", 32 | IncludeAWSAccountIdList: "234567890", 33 | Kid: "kid", 34 | Secret: "secret", 35 | RoleName: "role-name-123", 36 | ManageAllAccountsIAMData: true, 37 | ConnectorClass: "openconnector.connector.aws.AWSConnectorSDK", 38 | Encrypted: "test", 39 | } 40 | testConnectorAttributesInterface = []interface{}{ 41 | map[string]interface{}{ 42 | "grant_type": "grant-type-value", 43 | "client_id": "client-id-value", 44 | "client_secret": "client-secret-value", 45 | "domain_name": "domain-name-value", 46 | "cloud_external_id": "cloud-external-value", 47 | "ms_graph_resource_base": "ms-graph-resource-base-value", 48 | "ms_graph_token_base": "ms-graph-token-base-value", 49 | "azure_ad_graph_resource_base": "azure-ad-graph-resource-base-value", 50 | "azure_ad_graph_token_base": "azure-ad-graph-token-base", 51 | "use_tls_for_iq_service": true, 52 | "iq_service_port": "1234", 53 | "iq_service_password": "iq-service-password-value", 54 | "iq_service_user": "iq-service-user-value", 55 | "iq_service_host": "iq-service-host.com", 56 | "authorization_type": "simple", 57 | "api_version": "1.6", 58 | "exclude_aws_account_id_list": "123456789,987654321", 59 | "include_aws_account_id_list": "234567890", 60 | "kid": "kid", 61 | "secret": "secret", 62 | "role_name": "role-name-123", 63 | "manage_all_accounts_iam_data": true, 64 | "connector_class": "openconnector.connector.aws.AWSConnectorSDK", 65 | "encrypted": "test", 66 | }, 67 | } 68 | } 69 | 70 | func TestFlattenSourceConnectorAttributes(t *testing.T) { 71 | 72 | cases := []struct { 73 | Input *ConnectorAttributes 74 | ExpectedOutput []interface{} 75 | }{ 76 | { 77 | testConnectorAttributesConf, 78 | testConnectorAttributesInterface, 79 | }, 80 | } 81 | 82 | for _, tc := range cases { 83 | output := flattenSourceConnectorAttributes(tc.Input, []interface{}{}) 84 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 85 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 86 | tc.ExpectedOutput, output) 87 | } 88 | } 89 | } 90 | 91 | func TestExpandSourceConnectorAttributes(t *testing.T) { 92 | cases := []struct { 93 | Input []interface{} 94 | ExpectedOutput *ConnectorAttributes 95 | }{ 96 | { 97 | testConnectorAttributesInterface, 98 | testConnectorAttributesConf, 99 | }, 100 | } 101 | 102 | for _, tc := range cases { 103 | output := expandSourceConnectorAttributes(tc.Input) 104 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 105 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 106 | tc.ExpectedOutput, output) 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /structure_source_domain_settings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceDomainSettings(in []*DomainSettings) []interface{} { 6 | if in == nil { 7 | return []interface{}{} 8 | } 9 | 10 | out := make([]interface{}, 0, len(in)) 11 | for i := range in { 12 | var obj = make(map[string]interface{}) 13 | obj["password"] = in[i].Password 14 | obj["forest_name"] = in[i].ForestName 15 | obj["port"] = in[i].Port 16 | obj["user"] = in[i].User 17 | obj["use_ssl"] = in[i].UseSSL 18 | obj["authorization_type"] = in[i].AuthorizationType 19 | obj["domain_dn"] = in[i].DomainDN 20 | obj["servers"] = toArrayInterface(in[i].Servers) 21 | out = append(out, obj) 22 | } 23 | 24 | return out 25 | 26 | } 27 | 28 | // Expanders 29 | 30 | func expandSourceDomainSettings(p []interface{}) []*DomainSettings { 31 | if len(p) == 0 || p[0] == nil { 32 | return []*DomainSettings{} 33 | } 34 | out := make([]*DomainSettings, 0, len(p)) 35 | for i := range p { 36 | obj := DomainSettings{} 37 | in := p[i].(map[string]interface{}) 38 | obj.Password = in["password"].(string) 39 | obj.ForestName = in["forest_name"].(string) 40 | obj.User = in["user"].(string) 41 | obj.UseSSL = in["use_ssl"].(bool) 42 | obj.AuthorizationType = in["authorization_type"].(string) 43 | if v, ok := in["servers"].([]interface{}); ok && len(v) > 0 { 44 | obj.Servers = toArrayString(v) 45 | } 46 | obj.Port = in["port"].(string) 47 | obj.DomainDN = in["domain_dn"].(string) 48 | out = append(out, &obj) 49 | } 50 | 51 | return out 52 | } 53 | -------------------------------------------------------------------------------- /structure_source_domain_settings_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testDomainSettingsConf []*DomainSettings 10 | testDomainSettingsInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testDomainSettingsConf = []*DomainSettings{ 15 | { 16 | Password: "test-password", 17 | ForestName: "test-forest-name", 18 | Port: "1234", 19 | User: "test-user", 20 | UseSSL: true, 21 | AuthorizationType: "test-authorization-type", 22 | DomainDN: "DC=test,DC=domain,DC=com", 23 | Servers: []string{"test1-server.com", "test2-server.com"}, 24 | }, 25 | } 26 | testDomainSettingsInterface = []interface{}{ 27 | map[string]interface{}{ 28 | "password": "test-password", 29 | "forest_name": "test-forest-name", 30 | "port": "1234", 31 | "user": "test-user", 32 | "use_ssl": true, 33 | "authorization_type": "test-authorization-type", 34 | "domain_dn": "DC=test,DC=domain,DC=com", 35 | "servers": []interface{}{"test1-server.com", "test2-server.com"}, 36 | }, 37 | } 38 | } 39 | 40 | func TestFlattenSourceDomainSettings(t *testing.T) { 41 | 42 | cases := []struct { 43 | Input []*DomainSettings 44 | ExpectedOutput []interface{} 45 | }{ 46 | { 47 | testDomainSettingsConf, 48 | testDomainSettingsInterface, 49 | }, 50 | } 51 | 52 | for _, tc := range cases { 53 | output := flattenSourceDomainSettings(tc.Input) 54 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 55 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 56 | tc.ExpectedOutput, output) 57 | } 58 | } 59 | } 60 | 61 | func TestExpandSourceDomainSettings(t *testing.T) { 62 | cases := []struct { 63 | Input []interface{} 64 | ExpectedOutput []*DomainSettings 65 | }{ 66 | { 67 | testDomainSettingsInterface, 68 | testDomainSettingsConf, 69 | }, 70 | } 71 | 72 | for _, tc := range cases { 73 | output := expandSourceDomainSettings(tc.Input) 74 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 75 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 76 | tc.ExpectedOutput, output) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /structure_source_entitlement.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 4 | 5 | // Flatteners 6 | 7 | func flattenSourceEntitlement(d *schema.ResourceData, in *SourceEntitlement) error { 8 | if in == nil { 9 | return nil 10 | } 11 | d.SetId(in.ID) 12 | d.Set("source_id", in.Source.ID) 13 | d.Set("source_name", in.Source.Name) 14 | d.Set("attribute", in.Attribute) 15 | d.Set("created", in.Created) 16 | d.Set("description", in.Description) 17 | d.Set("direct_permissions", toArrayString(in.DirectPermissions)) 18 | d.Set("name", in.Name) 19 | d.Set("modified", in.Modified) 20 | d.Set("owner", in.Owner) 21 | d.Set("privileged", in.Privileged) 22 | d.Set("source_schema_object_type", in.SourceSchemaObjectType) 23 | d.Set("value", in.Value) 24 | 25 | return nil 26 | } 27 | 28 | func getEntitlement(entitlements []*SourceEntitlement, name string) *SourceEntitlement { 29 | for i := range entitlements { 30 | if entitlements[i].Name == name { 31 | return entitlements[i] 32 | } 33 | } 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /structure_source_entitlement_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testEntitlementConf []*SourceEntitlement 11 | testEntitlementInterface map[string]interface{} 12 | ) 13 | 14 | func init() { 15 | testEntitlementConf = []*SourceEntitlement{ 16 | { 17 | Source: &SourceInfo{ 18 | ID: "2c9180887412345678948078d29f2e46", 19 | Name: "Active Directory test", 20 | }, 21 | Attribute: "memberOf", 22 | Created: nil, 23 | Description: "test description", 24 | Name: "test name", 25 | Modified: "06/20/2020", 26 | Owner: nil, 27 | Privileged: false, 28 | SourceSchemaObjectType: "group", 29 | Value: "CN=example,OU=Groups,DC=test,DC=com", 30 | }, 31 | } 32 | testEntitlementInterface = 33 | map[string]interface{}{ 34 | "source_name": "Active Directory test", 35 | "source_id": "2c9180887412345678948078d29f2e46", 36 | "attribute": "memberOf", 37 | "description": "test description", 38 | "name": "test name", 39 | "modified": "06/20/2020", 40 | "privileged": false, 41 | "source_schema_object_type": "group", 42 | "value": "CN=example,OU=Groups,DC=test,DC=com", 43 | } 44 | } 45 | 46 | func TestFlattenSourceEntitlement(t *testing.T) { 47 | 48 | cases := []struct { 49 | Input []*SourceEntitlement 50 | ExpectedOutput map[string]interface{} 51 | }{ 52 | { 53 | testEntitlementConf, 54 | testEntitlementInterface, 55 | }, 56 | } 57 | 58 | for _, tc := range cases { 59 | output := schema.TestResourceDataRaw(t, sourceEntitlementFields(), tc.ExpectedOutput) 60 | err := flattenSourceEntitlement(output, tc.Input[0]) 61 | if err != nil { 62 | t.Fatalf("[ERROR] on flattener: %#v", err) 63 | } 64 | expectedOutput := map[string]interface{}{} 65 | for k := range tc.ExpectedOutput { 66 | expectedOutput[k] = output.Get(k) 67 | } 68 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 69 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 70 | tc.ExpectedOutput, expectedOutput) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /structure_source_forest_settings.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceForestSettings(in []*ForestSettings) []interface{} { 6 | if in == nil { 7 | return []interface{}{} 8 | } 9 | 10 | out := make([]interface{}, 0, len(in)) 11 | for i := range in { 12 | var obj = make(map[string]interface{}) 13 | obj["password"] = in[i].Password 14 | obj["gc_server"] = in[i].GcServer 15 | obj["forest_name"] = in[i].ForestName 16 | obj["user"] = in[i].User 17 | obj["use_ssl"] = in[i].UseSSL 18 | obj["authorization_type"] = in[i].AuthorizationType 19 | out = append(out, obj) 20 | } 21 | 22 | return out 23 | 24 | } 25 | 26 | // Expanders 27 | 28 | func expandSourceForestSettings(p []interface{}) []*ForestSettings { 29 | if len(p) == 0 || p[0] == nil { 30 | return []*ForestSettings{} 31 | } 32 | out := make([]*ForestSettings, 0, len(p)) 33 | 34 | for i := range p { 35 | obj := ForestSettings{} 36 | in := p[i].(map[string]interface{}) 37 | obj.Password = in["password"].(string) 38 | obj.GcServer = in["gc_server"].(string) 39 | obj.ForestName = in["forest_name"].(string) 40 | obj.User = in["user"].(string) 41 | obj.UseSSL = in["use_ssl"].(bool) 42 | obj.AuthorizationType = in["authorization_type"].(string) 43 | out = append(out, &obj) 44 | } 45 | 46 | return out 47 | } 48 | -------------------------------------------------------------------------------- /structure_source_forest_settings_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testForestSettingsConf []*ForestSettings 10 | testForestSettingsInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testForestSettingsConf = []*ForestSettings{ 15 | { 16 | Password: "test-password", 17 | ForestName: "test-forest-name", 18 | GcServer: "test1-server.com:1234", 19 | User: "test-user", 20 | UseSSL: true, 21 | AuthorizationType: "test-authorization-type", 22 | }, 23 | } 24 | testForestSettingsInterface = []interface{}{ 25 | map[string]interface{}{ 26 | "password": "test-password", 27 | "forest_name": "test-forest-name", 28 | "gc_server": "test1-server.com:1234", 29 | "user": "test-user", 30 | "use_ssl": true, 31 | "authorization_type": "test-authorization-type", 32 | }, 33 | } 34 | } 35 | 36 | func TestFlattenSourceForestSettings(t *testing.T) { 37 | 38 | cases := []struct { 39 | Input []*ForestSettings 40 | ExpectedOutput []interface{} 41 | }{ 42 | { 43 | testForestSettingsConf, 44 | testForestSettingsInterface, 45 | }, 46 | } 47 | 48 | for _, tc := range cases { 49 | output := flattenSourceForestSettings(tc.Input) 50 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 51 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 52 | tc.ExpectedOutput, output) 53 | } 54 | } 55 | } 56 | 57 | func TestExpandSourceForestSettings(t *testing.T) { 58 | cases := []struct { 59 | Input []interface{} 60 | ExpectedOutput []*ForestSettings 61 | }{ 62 | { 63 | testForestSettingsInterface, 64 | testForestSettingsConf, 65 | }, 66 | } 67 | 68 | for _, tc := range cases { 69 | output := expandSourceForestSettings(tc.Input) 70 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 71 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 72 | tc.ExpectedOutput, output) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /structure_source_group_search_dns.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func flattenSourceGroupSearchDNs(in []*GroupSearchDNs) []interface{} { 4 | if in == nil { 5 | return []interface{}{} 6 | } 7 | 8 | out := make([]interface{}, 0, len(in)) 9 | for i := range in { 10 | var obj = make(map[string]interface{}) 11 | obj["search_dn"] = in[i].SearchDN 12 | obj["search_scope"] = in[i].SearchScope 13 | obj["iterate_search_filter"] = in[i].IterateSearchFilter 14 | out = append(out, obj) 15 | } 16 | 17 | return out 18 | 19 | } 20 | 21 | // Expanders 22 | 23 | func expandSourceGroupSearchDNs(p []interface{}) []*GroupSearchDNs { 24 | if len(p) == 0 || p[0] == nil { 25 | return []*GroupSearchDNs{} 26 | } 27 | out := make([]*GroupSearchDNs, 0, len(p)) 28 | for i := range p { 29 | obj := GroupSearchDNs{} 30 | in := p[i].(map[string]interface{}) 31 | obj.SearchDN = in["search_dn"].(string) 32 | obj.SearchScope = in["search_scope"].(string) 33 | obj.IterateSearchFilter = in["iterate_search_filter"].(string) 34 | out = append(out, &obj) 35 | } 36 | 37 | return out 38 | } 39 | -------------------------------------------------------------------------------- /structure_source_group_search_dns_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testGroupSearchDNsConf []*GroupSearchDNs 10 | testGroupSearchDNsInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testGroupSearchDNsConf = []*GroupSearchDNs{ 15 | { 16 | SearchDN: "test-search-dn", 17 | SearchScope: "test-search-scope", 18 | IterateSearchFilter: "test-iterate-search-filter", 19 | }, 20 | } 21 | testGroupSearchDNsInterface = []interface{}{ 22 | map[string]interface{}{ 23 | "search_dn": "test-search-dn", 24 | "search_scope": "test-search-scope", 25 | "iterate_search_filter": "test-iterate-search-filter", 26 | }, 27 | } 28 | } 29 | 30 | func TestFlattenSourceGroupSearchDNs(t *testing.T) { 31 | 32 | cases := []struct { 33 | Input []*GroupSearchDNs 34 | ExpectedOutput []interface{} 35 | }{ 36 | { 37 | testGroupSearchDNsConf, 38 | testGroupSearchDNsInterface, 39 | }, 40 | } 41 | 42 | for _, tc := range cases { 43 | output := flattenSourceGroupSearchDNs(tc.Input) 44 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 45 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 46 | tc.ExpectedOutput, output) 47 | } 48 | } 49 | } 50 | 51 | func TestExpandSourceGroupSearchDNs(t *testing.T) { 52 | cases := []struct { 53 | Input []interface{} 54 | ExpectedOutput []*GroupSearchDNs 55 | }{ 56 | { 57 | testGroupSearchDNsInterface, 58 | testGroupSearchDNsConf, 59 | }, 60 | } 61 | 62 | for _, tc := range cases { 63 | output := expandSourceGroupSearchDNs(tc.Input) 64 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 65 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 66 | tc.ExpectedOutput, output) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /structure_source_management_workgroup.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceManagementWorkgroup(in *ManagementWorkgroup, p []interface{}) []interface{} { 6 | var obj map[string]interface{} 7 | if len(p) == 0 || p[0] == nil { 8 | obj = make(map[string]interface{}) 9 | } else { 10 | obj = p[0].(map[string]interface{}) 11 | } 12 | 13 | if in == nil { 14 | return []interface{}{} 15 | } 16 | 17 | obj["type"] = in.Type 18 | obj["id"] = in.ID 19 | obj["name"] = in.Name 20 | 21 | return []interface{}{obj} 22 | 23 | } 24 | 25 | // Expanders 26 | 27 | func expandSourceManagementWorkgroup(p []interface{}) *ManagementWorkgroup { 28 | obj := ManagementWorkgroup{} 29 | 30 | if len(p) == 0 || p[0] == nil { 31 | return &obj 32 | } 33 | in := p[0].(map[string]interface{}) 34 | 35 | obj.ID = in["id"].(string) 36 | obj.Name = in["name"].(string) 37 | obj.Type = in["type"].(string) 38 | 39 | return &obj 40 | } 41 | -------------------------------------------------------------------------------- /structure_source_management_workgroup_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testManagementWorkgroupConf *ManagementWorkgroup 10 | testManagementWorkgroupInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testManagementWorkgroupConf = &ManagementWorkgroup{ 15 | Type: "GOVERNANCE_GROUP", 16 | ID: "1234-id", 17 | Name: "test-name", 18 | } 19 | testManagementWorkgroupInterface = []interface{}{ 20 | map[string]interface{}{ 21 | "type": "GOVERNANCE_GROUP", 22 | "id": "1234-id", 23 | "name": "test-name", 24 | }, 25 | } 26 | } 27 | 28 | func TestFlattenSourceManagementWorkgroup(t *testing.T) { 29 | 30 | cases := []struct { 31 | Input *ManagementWorkgroup 32 | ExpectedOutput []interface{} 33 | }{ 34 | { 35 | testManagementWorkgroupConf, 36 | testManagementWorkgroupInterface, 37 | }, 38 | } 39 | 40 | for _, tc := range cases { 41 | output := flattenSourceManagementWorkgroup(tc.Input, []interface{}{}) 42 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 43 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 44 | tc.ExpectedOutput, output) 45 | } 46 | } 47 | } 48 | 49 | func TestExpandSourceManagementWorkgroup(t *testing.T) { 50 | cases := []struct { 51 | Input []interface{} 52 | ExpectedOutput *ManagementWorkgroup 53 | }{ 54 | { 55 | testManagementWorkgroupInterface, 56 | testManagementWorkgroupConf, 57 | }, 58 | } 59 | 60 | for _, tc := range cases { 61 | output := expandSourceManagementWorkgroup(tc.Input) 62 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 63 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 64 | tc.ExpectedOutput, output) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /structure_source_owner.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceOwner(in *Owner, p []interface{}) []interface{} { 6 | var obj map[string]interface{} 7 | if len(p) == 0 || p[0] == nil { 8 | obj = make(map[string]interface{}) 9 | } else { 10 | obj = p[0].(map[string]interface{}) 11 | } 12 | 13 | if in == nil { 14 | return []interface{}{} 15 | } 16 | 17 | obj["type"] = in.Type 18 | obj["id"] = in.ID 19 | obj["name"] = in.Name 20 | 21 | return []interface{}{obj} 22 | 23 | } 24 | 25 | // Expanders 26 | 27 | func expandSourceOwner(p []interface{}) *Owner { 28 | obj := Owner{} 29 | 30 | if len(p) == 0 || p[0] == nil { 31 | return &obj 32 | } 33 | in := p[0].(map[string]interface{}) 34 | 35 | obj.ID = in["id"].(string) 36 | obj.Name = in["name"].(string) 37 | obj.Type = in["type"].(string) 38 | 39 | return &obj 40 | } 41 | -------------------------------------------------------------------------------- /structure_source_owner_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testOwnerConf *Owner 10 | testOwnerInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testOwnerConf = &Owner{ 15 | Type: "IDENTITY", 16 | ID: "1234-id", 17 | Name: "test-name", 18 | } 19 | testOwnerInterface = []interface{}{ 20 | map[string]interface{}{ 21 | "type": "IDENTITY", 22 | "id": "1234-id", 23 | "name": "test-name", 24 | }, 25 | } 26 | } 27 | 28 | func TestFlattenSourceOwner(t *testing.T) { 29 | 30 | cases := []struct { 31 | Input *Owner 32 | ExpectedOutput []interface{} 33 | }{ 34 | { 35 | testOwnerConf, 36 | testOwnerInterface, 37 | }, 38 | } 39 | 40 | for _, tc := range cases { 41 | output := flattenSourceOwner(tc.Input, []interface{}{}) 42 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 43 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 44 | tc.ExpectedOutput, output) 45 | } 46 | } 47 | } 48 | 49 | func TestExpandSourceOwner(t *testing.T) { 50 | cases := []struct { 51 | Input []interface{} 52 | ExpectedOutput *Owner 53 | }{ 54 | { 55 | testOwnerInterface, 56 | testOwnerConf, 57 | }, 58 | } 59 | 60 | for _, tc := range cases { 61 | output := expandSourceOwner(tc.Input) 62 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 63 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 64 | tc.ExpectedOutput, output) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /structure_source_password_policies.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func flattenSourcePasswordPolicies(in []*SourcePasswordPolicies) []interface{} { 4 | if in == nil { 5 | return []interface{}{} 6 | } 7 | 8 | out := make([]interface{}, 0, len(in)) 9 | for i := range in { 10 | var obj = make(map[string]interface{}) 11 | obj["id"] = in[i].ID 12 | obj["name"] = in[i].Name 13 | obj["type"] = in[i].Type 14 | out = append(out, obj) 15 | } 16 | 17 | return out 18 | 19 | } 20 | 21 | // Expanders 22 | 23 | func expandSourcePasswordPolicies(p []interface{}) []*SourcePasswordPolicies { 24 | if len(p) == 0 || p[0] == nil { 25 | return []*SourcePasswordPolicies{} 26 | } 27 | out := make([]*SourcePasswordPolicies, 0, len(p)) 28 | for i := range p { 29 | obj := SourcePasswordPolicies{} 30 | in := p[i].(map[string]interface{}) 31 | obj.ID = in["id"].(string) 32 | obj.Name = in["name"].(string) 33 | obj.Type = in["type"].(string) 34 | out = append(out, &obj) 35 | } 36 | 37 | return out 38 | } 39 | -------------------------------------------------------------------------------- /structure_source_password_policies_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testSourcePassPoliciesConf []*SourcePasswordPolicies 10 | testSourcePassPoliciesInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testSourcePassPoliciesConf = []*SourcePasswordPolicies{ 15 | { 16 | Type: "PASSWORD_POLICY", 17 | ID: "1234-id", 18 | Name: "test-name", 19 | }, 20 | } 21 | testSourcePassPoliciesInterface = []interface{}{ 22 | map[string]interface{}{ 23 | "type": "PASSWORD_POLICY", 24 | "id": "1234-id", 25 | "name": "test-name", 26 | }, 27 | } 28 | } 29 | 30 | func TestFlattenSourcePasswordPolicies(t *testing.T) { 31 | 32 | cases := []struct { 33 | Input []*SourcePasswordPolicies 34 | ExpectedOutput []interface{} 35 | }{ 36 | { 37 | testSourcePassPoliciesConf, 38 | testSourcePassPoliciesInterface, 39 | }, 40 | } 41 | 42 | for _, tc := range cases { 43 | output := flattenSourcePasswordPolicies(tc.Input) 44 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 45 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 46 | tc.ExpectedOutput, output) 47 | } 48 | } 49 | } 50 | 51 | func TestExpandSourcePasswordPolicies(t *testing.T) { 52 | cases := []struct { 53 | Input []interface{} 54 | ExpectedOutput []*SourcePasswordPolicies 55 | }{ 56 | { 57 | testSourcePassPoliciesInterface, 58 | testSourcePassPoliciesConf, 59 | }, 60 | } 61 | 62 | for _, tc := range cases { 63 | output := expandSourcePasswordPolicies(tc.Input) 64 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 65 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 66 | tc.ExpectedOutput, output) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /structure_source_schema_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testSchemasConf []*Schema 10 | testSchemasInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testSchemasConf = []*Schema{ 15 | { 16 | Type: "TYPE", 17 | ID: "1234-id", 18 | Name: "test-name", 19 | }, 20 | } 21 | testSchemasInterface = []interface{}{ 22 | map[string]interface{}{ 23 | "type": "TYPE", 24 | "id": "1234-id", 25 | "name": "test-name", 26 | }, 27 | } 28 | } 29 | 30 | func TestFlattenSourceSchemas(t *testing.T) { 31 | 32 | cases := []struct { 33 | Input []*Schema 34 | ExpectedOutput []interface{} 35 | }{ 36 | { 37 | testSchemasConf, 38 | testSchemasInterface, 39 | }, 40 | } 41 | 42 | for _, tc := range cases { 43 | output := flattenSourceSchema(tc.Input, []interface{}{}) 44 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 45 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 46 | tc.ExpectedOutput, output) 47 | } 48 | } 49 | } 50 | 51 | func TestExpandSourceSchemas(t *testing.T) { 52 | cases := []struct { 53 | Input []interface{} 54 | ExpectedOutput []*Schema 55 | }{ 56 | { 57 | testSchemasInterface, 58 | testSchemasConf, 59 | }, 60 | } 61 | 62 | for _, tc := range cases { 63 | output := expandSourceSchema(tc.Input) 64 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 65 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 66 | tc.ExpectedOutput, output) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /structure_source_schemas.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceSchema(in []*Schema, p []interface{}) []interface{} { 6 | if in == nil { 7 | return []interface{}{} 8 | } 9 | 10 | out := make([]interface{}, 0, len(in)) 11 | for i := range in { 12 | var obj = make(map[string]interface{}) 13 | obj["type"] = in[i].Type 14 | obj["id"] = in[i].ID 15 | obj["name"] = in[i].Name 16 | out = append(out, obj) 17 | } 18 | 19 | return out 20 | } 21 | 22 | // Expanders 23 | 24 | func expandSourceSchema(p []interface{}) []*Schema { 25 | if len(p) == 0 || p[0] == nil { 26 | return []*Schema{} 27 | } 28 | out := make([]*Schema, 0, len(p)) 29 | for i := range p { 30 | obj := Schema{} 31 | in := p[i].(map[string]interface{}) 32 | obj.ID = in["id"].(string) 33 | obj.Name = in["name"].(string) 34 | obj.Type = in["type"].(string) 35 | out = append(out, &obj) 36 | } 37 | 38 | return out 39 | } 40 | -------------------------------------------------------------------------------- /structure_source_search_dns.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // Flatteners 4 | 5 | func flattenSourceSearchDNs(in []*SearchDNs) []interface{} { 6 | if in == nil { 7 | return []interface{}{} 8 | } 9 | 10 | out := make([]interface{}, 0, len(in)) 11 | 12 | for i := range in { 13 | var obj = make(map[string]interface{}) 14 | obj["group_membership_search_dn"] = in[i].GroupMembershipSearchDN 15 | obj["search_dn"] = in[i].SearchDN 16 | obj["group_member_filter_string"] = in[i].GroupMemberFilterString 17 | obj["search_scope"] = in[i].SearchScope 18 | obj["primary_group_search_dn"] = in[i].PrimaryGroupSearchDN 19 | obj["iterate_search_filter"] = in[i].IterateSearchFilter 20 | out = append(out, obj) 21 | } 22 | 23 | return out 24 | 25 | } 26 | 27 | // Expanders 28 | 29 | func expandSourceSearchDNs(p []interface{}) []*SearchDNs { 30 | if len(p) == 0 || p[0] == nil { 31 | return []*SearchDNs{} 32 | } 33 | out := make([]*SearchDNs, 0, len(p)) 34 | for i := range p { 35 | obj := SearchDNs{} 36 | in := p[i].(map[string]interface{}) 37 | obj.GroupMembershipSearchDN = in["group_membership_search_dn"].(string) 38 | obj.SearchDN = in["search_dn"].(string) 39 | obj.GroupMemberFilterString = in["group_member_filter_string"].(string) 40 | obj.SearchScope = in["search_scope"].(string) 41 | obj.PrimaryGroupSearchDN = in["primary_group_search_dn"].(string) 42 | obj.IterateSearchFilter = in["iterate_search_filter"].(string) 43 | out = append(out, &obj) 44 | } 45 | 46 | return out 47 | } 48 | -------------------------------------------------------------------------------- /structure_source_search_dns_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | testSearchDNsConf []*SearchDNs 10 | testSearchDNsInterface []interface{} 11 | ) 12 | 13 | func init() { 14 | testSearchDNsConf = []*SearchDNs{ 15 | { 16 | SearchDN: "OU=Users,DC=example,DC=com", 17 | IterateSearchFilter: "(objectclass=person)", 18 | GroupMemberFilterString: "group_member_filter_string_value", 19 | SearchScope: "SUBTREE", 20 | PrimaryGroupSearchDN: "primary_group_search_dn_value", 21 | GroupMembershipSearchDN: "group_membership_search_dn_value", 22 | }, 23 | } 24 | testSearchDNsInterface = []interface{}{ 25 | map[string]interface{}{ 26 | "search_dn": "OU=Users,DC=example,DC=com", 27 | "iterate_search_filter": "(objectclass=person)", 28 | "group_member_filter_string": "group_member_filter_string_value", 29 | "primary_group_search_dn": "primary_group_search_dn_value", 30 | "group_membership_search_dn": "group_membership_search_dn_value", 31 | "search_scope": "SUBTREE", 32 | }, 33 | } 34 | } 35 | 36 | func TestFlattenSourceSearchDNs(t *testing.T) { 37 | 38 | cases := []struct { 39 | Input []*SearchDNs 40 | ExpectedOutput []interface{} 41 | }{ 42 | { 43 | testSearchDNsConf, 44 | testSearchDNsInterface, 45 | }, 46 | } 47 | 48 | for _, tc := range cases { 49 | output := flattenSourceSearchDNs(tc.Input) 50 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 51 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 52 | tc.ExpectedOutput, output) 53 | } 54 | } 55 | } 56 | 57 | func TestExpandSourceSearchDNs(t *testing.T) { 58 | cases := []struct { 59 | Input []interface{} 60 | ExpectedOutput []*SearchDNs 61 | }{ 62 | { 63 | testSearchDNsInterface, 64 | testSearchDNsConf, 65 | }, 66 | } 67 | 68 | for _, tc := range cases { 69 | output := expandSourceSearchDNs(tc.Input) 70 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 71 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 72 | tc.ExpectedOutput, output) 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /structure_source_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/helper/schema" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | testSourceConf *Source 11 | testSourceInterface map[string]interface{} 12 | d *schema.ResourceData 13 | ) 14 | 15 | func init() { 16 | testSourceConf = &Source{ 17 | Name: "foo", 18 | Description: "test description", 19 | Connector: "active-directory", 20 | DeleteThreshold: 10, 21 | Authoritative: false, 22 | } 23 | testSourceInterface = map[string]interface{}{ 24 | "name": "foo", 25 | "description": "test description", 26 | "connector": "active-directory", 27 | "delete_threshold": 10, 28 | "authoritative": false, 29 | } 30 | } 31 | 32 | func TestFlattenSource(t *testing.T) { 33 | cases := []struct { 34 | Input *Source 35 | ExpectedOutput map[string]interface{} 36 | }{ 37 | { 38 | testSourceConf, 39 | testSourceInterface, 40 | }, 41 | } 42 | 43 | for _, tc := range cases { 44 | output := schema.TestResourceDataRaw(t, sourceFields(), tc.ExpectedOutput) 45 | err := flattenSource(output, tc.Input) 46 | if err != nil { 47 | t.Fatalf("[ERROR] on flattener: %#v", err) 48 | } 49 | expectedOutput := map[string]interface{}{} 50 | for k := range tc.ExpectedOutput { 51 | expectedOutput[k] = output.Get(k) 52 | } 53 | if !reflect.DeepEqual(expectedOutput, tc.ExpectedOutput) { 54 | t.Fatalf("Unexpected output from flattener.\nExpected: %#v\nGiven: %#v", 55 | tc.ExpectedOutput, expectedOutput) 56 | } 57 | } 58 | } 59 | 60 | func TestExpandSource(t *testing.T) { 61 | cases := []struct { 62 | Input map[string]interface{} 63 | ExpectedOutput *Source 64 | }{ 65 | { 66 | testSourceInterface, 67 | testSourceConf, 68 | }, 69 | } 70 | 71 | for _, tc := range cases { 72 | inputResourceData := schema.TestResourceDataRaw(t, sourceFields(), tc.Input) 73 | output, err := expandSource(inputResourceData) 74 | if err != nil { 75 | t.Fatalf("[ERROR] on flattener: %#v", err) 76 | } 77 | if !reflect.DeepEqual(output, tc.ExpectedOutput) { 78 | t.Fatalf("Unexpected output from expander.\nExpected: %#v\nGiven: %#v", 79 | tc.ExpectedOutput, output) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /type_Identity.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Identity struct { 4 | ID string `json:"id,omitempty"` 5 | Name string `json:"name,omitempty"` 6 | Description string `json:"description,omitempty"` 7 | IsManager bool `json:"isManager,omitempty"` 8 | Alias string `json:"alias"` 9 | EmailAddress string `json:"emailAddress,omitempty"` 10 | IdentityStatus string `json:"identityStatus,omitempty"` 11 | Enabled bool `json:"enabled,omitempty"` 12 | IdentityAttributes *IdentityAttributes `json:"attributes,omitempty"` 13 | } 14 | 15 | type IdentityAttributes struct { 16 | AdpID string `json:"adpId,omitempty"` 17 | LastName string `json:"lastname,omitempty"` 18 | FirstName string `json:"firstname,omitempty"` 19 | Phone string `json:"phone,omitempty"` 20 | UserType string `json:"userType,omitempty"` 21 | UID string `json:"uid,omitempty"` 22 | Email string `json:"email,omitempty"` 23 | WorkdayId string `json:"workdayId,omitempty"` 24 | } 25 | -------------------------------------------------------------------------------- /type_access_profile.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type AccessProfile struct { 4 | Description string `json:"description"` 5 | Enabled *bool `json:"enabled,omitempty"` 6 | Entitlements []*ObjectInfo `json:"entitlements,omitempty"` 7 | ID string `json:"id,omitempty"` 8 | Name string `json:"name,omitempty"` 9 | AccessProfileOwner *ObjectInfo `json:"owner,omitempty"` 10 | AccessProfileSource *ObjectInfo `json:"source,omitempty"` 11 | Requestable *bool `json:"requestable,omitempty"` 12 | AccessRequestConfig *AccessRequestConfigList `json:"accessRequestConfig,omitempty"` 13 | } 14 | 15 | type AccessRequestConfigList struct { 16 | CommentsRequired *bool `json:"commentsRequired,omitempty"` 17 | DenialCommentsRequired *bool `json:"denialCommentsRequired,omitempty"` 18 | ApprovalSchemes interface{} `json:"approvalSchemes,omitempty"` 19 | ReauthorizationRequired *bool `json:"reauthorizationRequired,omitempty"` 20 | } 21 | 22 | type UpdateAccessProfile struct { 23 | Op string `json:"op"` 24 | Path string `json:"path"` 25 | Value []interface{} `json:"value"` 26 | } 27 | -------------------------------------------------------------------------------- /type_account_aggregaion_schedule.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type AccountAggregationSchedule struct { 4 | Arguments struct { 5 | Method string `json:"method,omitempty"` 6 | Path string `json:"path,omitempty"` 7 | Service string `json:"service,omitempty"` 8 | } `json:"arguments"` 9 | SourceID string `json:"source_id,omitempty"` 10 | CronExpressions []string `json:"cronExpressions,omitempty"` 11 | Description string `json:"description,omitempty"` 12 | LastExecution interface{} `json:"lastExecution,omitempty"` 13 | Name string `json:"name,omitempty"` 14 | NewState interface{} `json:"newState,omitempty"` 15 | NextExecution int64 `json:"nextExecution,omitempty"` 16 | State interface{} `json:"state,omitempty"` 17 | Type string `json:"type,omitempty"` 18 | } 19 | -------------------------------------------------------------------------------- /type_account_schema.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type AccountSchema struct { 4 | Attributes []*AccountSchemaAttribute `json:"attributes,omitempty"` 5 | DisplayAttribute string `json:"displayAttribute,omitempty"` 6 | IdentityAttribute string `json:"identityAttribute,omitempty"` 7 | NativeObjectType string `json:"nativeObjectType,omitempty"` 8 | Features []interface{} `json:"features,omitempty"` 9 | Configuration interface{} `json:"configuration,omitempty"` 10 | HierarchyAttribute string `json:"hierarchyAttribute,omitempty"` 11 | IncludePermissions bool `json:"includePermissions,omitempty"` 12 | ID string `json:"id"` 13 | Name string `json:"name"` 14 | Created string `json:"created,omitempty"` 15 | Modified string `json:"modified,omitempty"` 16 | SourceID string `json:"sourceId,omitempty"` 17 | } 18 | 19 | type AccountSchemaAttribute struct { 20 | Description string `json:"description,omitempty"` 21 | IsEntitlement bool `json:"isEntitlement,omitempty"` 22 | IsMultiValued bool `json:"isMultiValued,omitempty"` 23 | IsGroup bool `json:"isGroup,omitempty"` 24 | Name string `json:"name"` 25 | Type string `json:"type,omitempty"` 26 | Schema *AccountSchemaAttributeSchema `json:"schema,omitempty"` 27 | } 28 | 29 | type AccountSchemaAttributeSchema struct { 30 | Type string `json:"type,omitempty"` 31 | ID string `json:"id,omitempty"` 32 | Name string `json:"name,omitempty"` 33 | } 34 | -------------------------------------------------------------------------------- /type_entitlement.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type SourceEntitlement struct { 4 | Attribute string `json:"attribute,omitempty"` 5 | Value string `json:"value,omitempty"` 6 | Description interface{} `json:"description,omitempty"` 7 | SourceSchemaObjectType string `json:"sourceSchemaObjectType,omitempty"` 8 | Privileged bool `json:"privileged,omitempty"` 9 | CloudGoverned bool `json:"cloudGoverned,omitempty"` 10 | Requestable bool `json:"requestable,omitempty"` 11 | Attributes *Attributes `json:"attributes,omitempty"` 12 | Source *SourceInfo `json:"source,omitempty"` 13 | Owner interface{} `json:"owner,omitempty"` 14 | DirectPermissions []interface{} `json:"directPermissions,omitempty"` 15 | Segments []interface{} `json:"segments,omitempty"` 16 | Modified interface{} `json:"modified,omitempty"` 17 | Created interface{} `json:"created,omitempty"` 18 | ID string `json:"id"` 19 | Name string `json:"name"` 20 | } 21 | 22 | type Attributes struct { 23 | GroupType string `json:"groupType,omitempty"` 24 | SAMAccountName string `json:"sAMAccountName,omitempty"` 25 | ObjectGuid interface{} `json:"objectguid,omitempty"` 26 | GroupScope interface{} `json:"GroupScope,omitempty"` 27 | Description interface{} `json:"description,omitempty"` 28 | ObjectSid interface{} `json:"objectSid,omitempty"` 29 | Cn interface{} `json:"cn,omitempty"` 30 | MsDSPrincipalName interface{} `json:"msDS-PrincipalName,omitempty"` 31 | } 32 | 33 | type SourceInfo struct { 34 | ID string `json:"id"` 35 | Name string `json:"name"` 36 | Type string `json:"type"` 37 | } 38 | -------------------------------------------------------------------------------- /type_oauth_token.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type OauthToken struct { 4 | AccessToken string `json:"access_token"` 5 | TokenType string `json:"token_type"` 6 | ExpiresIn int `json:"expires_in"` 7 | Scope string `json:"scope"` 8 | TenantID string `json:"tenant_id"` 9 | Pod string `json:"pod"` 10 | StrongAuthSupported bool `json:"strong_auth_supported"` 11 | Org string `json:"org"` 12 | IdentityID string `json:"identity_id"` 13 | UserName string `json:"user_name"` 14 | StrongAuth bool `json:"strong_auth"` 15 | Jti string `json:"jti"` 16 | } 17 | -------------------------------------------------------------------------------- /type_password_policy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type PasswordPolicy struct { 4 | AccountIDMinWordLength *int `json:"accountIdMinWordLength,omitempty"` 5 | AccountNameMinWordLength *int `json:"accountNameMinWordLength,omitempty"` 6 | ConnectedServices []*ConnectedServices `json:"connectedServices,omitempty"` 7 | DateCreated interface{} `json:"dateCreated,omitempty"` 8 | DefaultPolicy *bool `json:"defaultPolicy,omitempty"` 9 | Description string `json:"description,omitempty"` 10 | EnablePasswordExpiration *bool `json:"enablePasswdExpiration,omitempty"` 11 | FirstExpirationReminder *int `json:"firstExpirationReminder,omitempty"` 12 | ID string `json:"id,omitempty"` 13 | LastUpdated interface{} `json:"lastUpdated,omitempty"` 14 | MaxLength *int `json:"maxLength,omitempty"` 15 | MaxRepeatedChars *int `json:"maxRepeatedChars,omitempty"` 16 | MinAlpha *int `json:"minAlpha,omitempty"` 17 | MinCharacterTypes *int `json:"minCharacterTypes,omitempty"` 18 | MinLength *int `json:"minLength,omitempty"` 19 | MinLower *int `json:"minLower,omitempty"` 20 | MinNumeric *int `json:"minNumeric,omitempty"` 21 | MinSpecial *int `json:"minSpecial,omitempty"` 22 | MinUpper *int `json:"minUpper,omitempty"` 23 | Name string `json:"name"` 24 | PasswordExpiration *int `json:"passwordExpiration,omitempty"` 25 | RequireStrongAuthOffNetwork *bool `json:"requireStrongAuthOffNetwork,omitempty"` 26 | RequireStrongAuthUntrustedGeographies *bool `json:"requireStrongAuthUntrustedGeographies,omitempty"` 27 | RequireStrongAuthn *bool `json:"requireStrongAuthn,omitempty"` 28 | UseAccountAttributes *bool `json:"useAccountAttributes,omitempty"` 29 | UseDictionary *bool `json:"useDictionary,omitempty"` 30 | UseHistory *int `json:"useHistory,omitempty"` 31 | UseIdentityAttributes *bool `json:"useIdentityAttributes,omitempty"` 32 | ValidateAgainstAccountID *bool `json:"validateAgainstAccountId,omitempty"` 33 | ValidateAgainstAccountName *bool `json:"validateAgainstAccountName,omitempty"` 34 | SourceIDs []string `json:"sourceIds,omitempty"` 35 | } 36 | 37 | type ConnectedServices struct { 38 | ID string `json:"id,omitempty"` 39 | ExternalID string `json:"externalId"` 40 | Name string `json:"name"` 41 | SupportsPasswordSetDate bool `json:"supportsPasswordSetDate,omitempty"` 42 | AppCount int `json:"appCount,omitempty"` 43 | } 44 | -------------------------------------------------------------------------------- /type_role.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Role struct { 4 | Description string `json:"description"` 5 | ID string `json:"id,omitempty"` 6 | Name string `json:"name"` 7 | Requestable *bool `json:"requestable,omitempty"` 8 | RoleOwner *ObjectInfo `json:"owner,omitempty"` 9 | AccessProfiles []*ObjectInfo `json:"accessProfiles,omitempty"` 10 | LegacyMembershipInfo interface{} `json:"legacyMembershipInfo,omitempty"` 11 | Enabled *bool `json:"enabled,omitempty"` 12 | Segments []interface{} `json:"segments,omitempty"` 13 | Membership *struct { 14 | Type string `json:"type,omitempty"` 15 | Criteria struct { 16 | Operation string `json:"operation,omitempty"` 17 | Key interface{} `json:"key,omitempty"` 18 | StringValue string `json:"stringValue,omitempty"` 19 | Children []*RoleChildren `json:"children,omitempty"` 20 | } `json:"criteria,omitempty"` 21 | } `json:"membership,omitempty"` 22 | AccessRequestConfig struct { 23 | CommentsRequired *bool `json:"commentsRequired,omitempty"` 24 | DenialCommentsRequired *bool `json:"denialCommentsRequired,omitempty"` 25 | ApprovalSchemes []interface{} `json:"approvalSchemes,omitempty"` 26 | } `json:"accessRequestConfig,omitempty"` 27 | RevocationRequestConfig struct { 28 | ApprovalSchemes []interface{} `json:"approvalSchemes,omitempty"` 29 | } `json:"revocationRequestConfig,omitempty"` 30 | } 31 | type ObjectInfo struct { 32 | ID interface{} `json:"id,omitempty"` 33 | Type string `json:"type,omitempty"` 34 | Name string `json:"name"` 35 | } 36 | 37 | type RoleChildren struct { 38 | Operation string `json:"operation,omitempty"` 39 | Key *RoleKey `json:"key,omitempty"` 40 | StringValue string `json:"stringValue,omitempty"` 41 | Children *RoleChildren `json:"children,omitempty"` 42 | } 43 | 44 | type RoleKey struct { 45 | Type string `json:"type,omitempty"` 46 | Property interface{} `json:"property,omitempty"` 47 | SourceId interface{} `json:"sourceId,omitempty"` 48 | } 49 | 50 | type UpdateRole struct { 51 | Op string `json:"op"` 52 | Path string `json:"path"` 53 | Value []interface{} `json:"value"` 54 | } 55 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/url" 7 | "reflect" 8 | "strings" 9 | ) 10 | 11 | func toArrayInterface(in []string) []interface{} { 12 | out := make([]interface{}, len(in)) 13 | for i, v := range in { 14 | out[i] = v 15 | } 16 | return out 17 | } 18 | 19 | func toArrayString(in []interface{}) []string { 20 | out := make([]string, len(in)) 21 | for i, v := range in { 22 | if v == nil { 23 | out[i] = "" 24 | continue 25 | } 26 | out[i] = v.(string) 27 | } 28 | return out 29 | } 30 | 31 | func setPasswordPolicyUrlValues(attributes *PasswordPolicy) (url.Values, error) { 32 | data := url.Values{} 33 | data.Set("name", attributes.Name) 34 | data.Set("description", attributes.Description) 35 | 36 | if attributes.AccountIDMinWordLength != nil { 37 | data.Set("accountIdMinWordLength", fmt.Sprintf("%v", *attributes.AccountIDMinWordLength)) 38 | } 39 | if attributes.AccountNameMinWordLength != nil { 40 | data.Set("accountNameMinWordLength", fmt.Sprintf("%v", *attributes.AccountNameMinWordLength)) 41 | } 42 | if attributes.EnablePasswordExpiration != nil { 43 | data.Set("enablePasswdExpiration", fmt.Sprintf("%v", *attributes.EnablePasswordExpiration)) 44 | } 45 | if attributes.FirstExpirationReminder != nil { 46 | data.Set("firstExpirationReminder", fmt.Sprintf("%v", *attributes.FirstExpirationReminder)) 47 | } 48 | if attributes.MaxLength != nil { 49 | data.Set("maxLength", fmt.Sprintf("%v", *attributes.MaxLength)) 50 | } 51 | if attributes.MaxRepeatedChars != nil { 52 | data.Set("maxRepeatedChars", fmt.Sprintf("%v", *attributes.MaxRepeatedChars)) 53 | } 54 | if attributes.MinLength != nil { 55 | data.Set("minLength", fmt.Sprintf("%v", *attributes.MinLength)) 56 | log.Printf("minLength: %v", *attributes.MinLength) 57 | } 58 | if attributes.MinAlpha != nil { 59 | data.Set("minAlpha", fmt.Sprintf("%v", *attributes.MinAlpha)) 60 | log.Printf("minAlpha: %v", *attributes.MinAlpha) 61 | } 62 | if attributes.MinUpper != nil { 63 | data.Set("minUpper", fmt.Sprintf("%v", *attributes.MinUpper)) 64 | } 65 | if attributes.MinLower != nil { 66 | data.Set("minLower", fmt.Sprintf("%v", *attributes.MinLower)) 67 | } 68 | if attributes.MinNumeric != nil { 69 | data.Set("minNumeric", fmt.Sprintf("%v", *attributes.MinNumeric)) 70 | } 71 | if attributes.MinSpecial != nil { 72 | data.Set("minSpecial", fmt.Sprintf("%v", *attributes.MinSpecial)) 73 | } 74 | if attributes.MinCharacterTypes != nil { 75 | data.Set("minCharacterTypes", fmt.Sprintf("%v", *attributes.MinCharacterTypes)) 76 | } 77 | 78 | if attributes.PasswordExpiration != nil { 79 | data.Set("passwordExpiration", fmt.Sprintf("%v", *attributes.PasswordExpiration)) 80 | } 81 | if attributes.RequireStrongAuthOffNetwork != nil { 82 | data.Set("requireStrongAuthOffNetwork", fmt.Sprintf("%v", *attributes.RequireStrongAuthUntrustedGeographies)) 83 | } 84 | if attributes.RequireStrongAuthUntrustedGeographies != nil { 85 | data.Set("requireStrongAuthUntrustedGeographies", fmt.Sprintf("%v", *attributes.RequireStrongAuthUntrustedGeographies)) 86 | } 87 | if attributes.RequireStrongAuthn != nil { 88 | data.Set("requireStrongAuthn", fmt.Sprintf("%v", *attributes.RequireStrongAuthUntrustedGeographies)) 89 | } 90 | if attributes.UseAccountAttributes != nil { 91 | data.Set("useAccountAttributes", fmt.Sprintf("%v", *attributes.UseAccountAttributes)) 92 | } 93 | if attributes.UseDictionary != nil { 94 | data.Set("useDictionary", fmt.Sprintf("%v", *attributes.UseDictionary)) 95 | } 96 | if attributes.UseHistory != nil { 97 | data.Set("useHistory", fmt.Sprintf("%v", *attributes.UseHistory)) 98 | } 99 | if attributes.UseIdentityAttributes != nil { 100 | data.Set("useIdentityAttributes", fmt.Sprintf("%v", *attributes.UseIdentityAttributes)) 101 | } 102 | if attributes.ValidateAgainstAccountID != nil { 103 | data.Set("validateAgainstAccountId", fmt.Sprintf("%v", *attributes.ValidateAgainstAccountID)) 104 | } 105 | if attributes.ValidateAgainstAccountName != nil { 106 | data.Set("validateAgainstAccountName", fmt.Sprintf("%v", *attributes.ValidateAgainstAccountName)) 107 | } 108 | return data, nil 109 | } 110 | func splitAccountSchemaID(id string) (sourceId string, schemaId string, err error) { 111 | separator := "-" 112 | 113 | result := strings.Split(id, separator) 114 | if len(result) == 2 { 115 | return result[0], result[1], nil 116 | } 117 | return "", "", fmt.Errorf("[ERROR Getting source id and name. id: %s", id) 118 | } 119 | 120 | func isEmptyValue(value interface{}) bool { 121 | if value == nil { 122 | return true 123 | } 124 | val := reflect.ValueOf(value) 125 | 126 | switch val.Kind() { 127 | case reflect.Array, reflect.Slice, reflect.Map, reflect.String: 128 | return val.Len() == 0 129 | case reflect.Ptr, reflect.Interface: 130 | return val.IsNil() 131 | default: 132 | // Check zero value for other types 133 | zeroValue := reflect.Zero(val.Type()).Interface() 134 | return reflect.DeepEqual(value, zeroValue) 135 | } 136 | } 137 | 138 | func getJSONFieldName(field reflect.StructField) string { 139 | // Get the JSON tag value 140 | jsonTag := field.Tag.Get("json") 141 | if jsonTag == "" || jsonTag == "-" { // Handle empty or ignored fields 142 | return "" 143 | } 144 | 145 | // Split the tag by commas and return the first part (the field name) 146 | name := strings.Split(jsonTag, ",")[0] 147 | return name 148 | } 149 | -------------------------------------------------------------------------------- /website/allowed-subcategories: -------------------------------------------------------------------------------- 1 | Source 2 | Access Profile 3 | Account 4 | Identity -------------------------------------------------------------------------------- /website/docs/d/source.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | subcategory: "Source" 3 | layout: "identitynow" 4 | page_title: "IdentityNow: Data Source: identitynow_source" 5 | description: |- 6 | Gets information about an existing Source. 7 | --- 8 | 9 | # Data Source: identitynow_source 10 | 11 | Use this data source to access information about an existing Source. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | data "identitynow_source" "example" { 17 | name = "example" 18 | } 19 | 20 | output "identitynow_source_description" { 21 | value = data.identitynow_source.description 22 | } 23 | ``` 24 | 25 | ## Arguments Reference 26 | 27 | The following arguments are supported: 28 | 29 | * TBU 30 | 31 | ## Attributes Reference 32 | 33 | In addition to the Arguments listed above - the following Attributes are exported: 34 | 35 | * TBU 36 | 37 | ## Timeouts 38 | 39 | The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: 40 | 41 | * `read` - (Defaults to 5 minutes) Used when retrieving the Source. -------------------------------------------------------------------------------- /website/docs/index.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: "identitynow" 3 | page_title: "Provider: IdentityNow" 4 | description: |- 5 | The IdentityNow Provider is used to interact with the many resources supported by [IdentityNow API](https://developer.sailpoint.com/idn/api/v3). 6 | 7 | --- 8 | 9 | # IdentityNow Provider 10 | 11 | The IdentityNow Provider can be used to configure infrastructure in [SailPoint IdentityNow](https://www.sailpoint.com/products/identitynow/) using the official API's. Documentation regarding the [Data Sources](/docs/configuration/data-sources.html) and [Resources](/docs/configuration/resources.html) supported by the IdentityNow Provider can be found in the navigation to the left. 12 | 13 | Interested in the provider's latest features, or want to make sure you're up to date? Check out the [changelog](https://github.com/OpenAxon/terraform-provider-identitynow/blob/master/CHANGELOG.md) for version information and release notes. 14 | 15 | ## Authenticating to IdentityNow 16 | 17 | The IdentityNow Provider follows the [Client Credentials Grant Flow](https://developer.sailpoint.com/idn/api/authentication/#client-credentials-grant-flow), using the Client ID and Client Secret obtained from the personal access token. 18 | 19 | ## Example Usage 20 | 21 | ```hcl 22 | # We strongly recommend using the required_providers block to set the 23 | # IdentityNow Provider source and version being used 24 | terraform { 25 | required_providers { 26 | identitynow = { 27 | source = "OpenAxon/identitynow" 28 | version = "=0.3.1" 29 | } 30 | } 31 | } 32 | 33 | # Configure the IdentityNow Provider 34 | provider "identitynow" { 35 | api_url = ".api.identitynow.com" 36 | client_id = "" 37 | client_secret = "" 38 | } 39 | 40 | # Create a source 41 | resource "identitynow_source" "example" { 42 | name = "example-resources" 43 | # ... 44 | } 45 | ``` 46 | 47 | ## Features and Bug Requests 48 | 49 | The IdentityNow provider's bugs and feature requests can be found in the [GitHub repo issues](https://github.com/OpenAxon/terraform-provider-identitynow/issues). 50 | Please avoid "me too" or "+1" comments. Instead, use a thumbs up [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) 51 | on enhancement requests. Provider maintainers will often prioritize work based on the number of thumbs on an issue. 52 | 53 | Community input is appreciated on outstanding issues! We love to hear what use 54 | cases you have for new features, and want to provide the best possible 55 | experience for you using the IdentityNow provider. 56 | 57 | If you have a bug or feature request without an existing issue 58 | 59 | * if an existing resource or field is working in an unexpected way, [file a bug](https://github.com/OpenAxon/terraform-provider-identitynow/issues/new?template=Bug_Report.md). 60 | 61 | * if you'd like the provider to support a new resource or field, [file an enhancement/feature request](https://github.com/OpenAxon/terraform-provider-identitynow/issues/new?template=Feature_Request.md). 62 | 63 | The provider maintainers will often use the assignee field on an issue to mark 64 | who is working on it. 65 | 66 | * An issue assigned to an individual maintainer indicates that the maintainer is working 67 | on the issue 68 | 69 | * If you're interested in working on an issue please leave a comment on that issue 70 | 71 | 72 | ## Argument Reference 73 | 74 | The following arguments are supported: 75 | 76 | * `api_url` - (Required) The URL to the IdentityNow API. 77 | 78 | * `client_id` - (Required) API client used to authenticate with the IdentityNow API. 79 | 80 | * `client_secret` - (Required) API client secret used to authenticate with the IdentityNow API. 81 | -------------------------------------------------------------------------------- /website/docs/r/source.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | subcategory: "Source" 3 | layout: "identitynow" 4 | page_title: "IdentityNow: identitynow_source" 5 | description: |- 6 | Manages an IdentityNow Source. 7 | --- 8 | 9 | # identitynow_source 10 | 11 | Manages an IdentityNow Source. 12 | 13 | ## Example Usage 14 | 15 | ```hcl 16 | resource "identitynow_source" "example" { 17 | TBU 18 | } 19 | ``` 20 | 21 | ## Arguments Reference 22 | 23 | The following arguments are supported: 24 | 25 | * TBU 26 | 27 | ## Attributes Reference 28 | 29 | In addition to the Arguments listed above - the following Attributes are exported: 30 | 31 | * TBU 32 | 33 | ## Timeouts 34 | 35 | The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: 36 | 37 | * `create` - (Defaults to 30 minutes) Used when creating the Source. 38 | * `read` - (Defaults to 5 minutes) Used when retrieving the Source. 39 | * `update` - (Defaults to 30 minutes) Used when updating the Source. 40 | * `delete` - (Defaults to 30 minutes) Used when deleting the Source. 41 | 42 | ## Import 43 | 44 | TBU --------------------------------------------------------------------------------