-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GPE-14846: Add External Sources resource #1450
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
--- | ||
# generated by https://github.com/hashicorp/terraform-plugin-docs | ||
page_title: "genesyscloud_externalcontacts_external_source Data Source - terraform-provider-genesyscloud" | ||
subcategory: "" | ||
description: |- | ||
Genesys Cloud external contacts external source data source. Select an external source by name | ||
--- | ||
|
||
# genesyscloud_externalcontacts_external_source (Data Source) | ||
|
||
Genesys Cloud external contacts external source data source. Select an external source by name | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
data "genesyscloud_externalcontacts_external_source" "external_source" { | ||
name = "example-source-123" | ||
active = true | ||
link_configuration { | ||
uri_template = "https://some.host/{{externalId.value}}" | ||
} | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `name` (String) external source name | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
--- | ||
page_title: "genesyscloud_externalcontacts_external_source Resource - terraform-provider-genesyscloud" | ||
subcategory: "" | ||
description: |- | ||
Genesys Cloud external contacts external source | ||
--- | ||
# genesyscloud_externalcontacts_external_source (Resource) | ||
|
||
Genesys Cloud external contacts external source | ||
|
||
## API Usage | ||
The following Genesys Cloud APIs are used by this resource. Ensure your OAuth Client has been granted the necessary scopes and permissions to perform these operations: | ||
|
||
* [GET /api/v2/externalcontacts/externalsources](https://developer.genesys.cloud/devapps/api-explorer#get-api-v2-externalcontacts-externalsources) | ||
* [POST /api/v2/externalcontacts/externalsources](https://developer.genesys.cloud/devapps/api-explorer#post-api-v2-externalcontacts-externalsources) | ||
* [GET /api/v2/externalcontacts/externalsources/{externalSourceId}](https://developer.genesys.cloud/devapps/api-explorer#get-api-v2-externalcontacts-externalsources--externalSourceId-) | ||
* [PUT /api/v2/externalcontacts/externalsources/{externalSourceId}](https://developer.genesys.cloud/devapps/api-explorer#put-api-v2-externalcontacts-externalsources--externalSourceId-) | ||
* [DELETE /api/v2/externalcontacts/externalsources/{externalSourceId}](https://developer.genesys.cloud/devapps/api-explorer#delete-api-v2-externalcontacts-externalsources--externalSourceId-) | ||
|
||
## Example Usage | ||
|
||
```terraform | ||
resource "genesyscloud_externalcontacts_external_source" "external_source" { | ||
name = "some-external-source" | ||
active = true | ||
link_configuration { | ||
uri_template = "https://some.host/{{externalId.value}}" | ||
} | ||
} | ||
``` | ||
|
||
<!-- schema generated by tfplugindocs --> | ||
## Schema | ||
|
||
### Required | ||
|
||
- `name` (String) The name of the external source. | ||
|
||
### Optional | ||
|
||
- `active` (Boolean) Whether the external source is active. Defaults to `true`. | ||
- `link_configuration` (Block List, Max: 1) (see [below for nested schema](#nestedblock--link_configuration)) | ||
|
||
### Read-Only | ||
|
||
- `id` (String) The ID of this resource. | ||
|
||
<a id="nestedblock--link_configuration"></a> | ||
### Nested Schema for `link_configuration` | ||
|
||
Optional: | ||
|
||
- `uri_template` (String) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This string allows templating, with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If more values are supported in the future, we'll have to come back and modify the docs here, so it might be easier to be generic and let the response tell them what they did wrong. |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
data "genesyscloud_externalcontacts_external_source" "external_source" { | ||
name = "example-source-123" | ||
active = true | ||
link_configuration { | ||
uri_template = "https://some.host/{{externalId.value}}" | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
* [GET /api/v2/externalcontacts/externalsources](https://developer.genesys.cloud/devapps/api-explorer#get-api-v2-externalcontacts-externalsources) | ||
* [POST /api/v2/externalcontacts/externalsources](https://developer.genesys.cloud/devapps/api-explorer#post-api-v2-externalcontacts-externalsources) | ||
* [GET /api/v2/externalcontacts/externalsources/{externalSourceId}](https://developer.genesys.cloud/devapps/api-explorer#get-api-v2-externalcontacts-externalsources--externalSourceId-) | ||
* [PUT /api/v2/externalcontacts/externalsources/{externalSourceId}](https://developer.genesys.cloud/devapps/api-explorer#put-api-v2-externalcontacts-externalsources--externalSourceId-) | ||
* [DELETE /api/v2/externalcontacts/externalsources/{externalSourceId}](https://developer.genesys.cloud/devapps/api-explorer#delete-api-v2-externalcontacts-externalsources--externalSourceId-) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
resource "genesyscloud_externalcontacts_external_source" "external_source" { | ||
name = "some-external-source" | ||
active = true | ||
link_configuration { | ||
uri_template = "https://some.host/{{externalId.value}}" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
package external_contacts_external_source | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"terraform-provider-genesyscloud/genesyscloud/provider" | ||
rc "terraform-provider-genesyscloud/genesyscloud/resource_cache" | ||
"terraform-provider-genesyscloud/genesyscloud/util" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" | ||
) | ||
|
||
var ( | ||
dataSourceExternalSourceCache *rc.DataSourceCache | ||
) | ||
|
||
func dataSourceExternalContactsExternalSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
sdkConfig := meta.(*provider.ProviderMeta).ClientConfig | ||
proxy := newExternalContactsExternalSourceProxy(sdkConfig) | ||
|
||
name := d.Get("name").(string) | ||
|
||
if dataSourceExternalSourceCache == nil { | ||
log.Printf("Instantiating the %s data source cache object", ResourceType) | ||
dataSourceExternalSourceCache = rc.NewDataSourceCache(sdkConfig, hydrateExternalSourceCacheFn, getExternalSourceByNameFn) | ||
} | ||
return util.WithRetries(ctx, 15*time.Second, func() *retry.RetryError { | ||
externalSourceId, retryable, response, err := proxy.getExternalContactsExternalSourceIdByName(ctx, name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're not actually making use of the data source cache here. Take a look at this example to see how to make use of the functions |
||
|
||
if err != nil { | ||
if retryable { | ||
return retry.RetryableError(util.BuildWithRetriesApiDiagnosticError(ResourceType, fmt.Sprintf("No external sources found with the provided name %s", name), response)) | ||
} | ||
return retry.NonRetryableError(util.BuildWithRetriesApiDiagnosticError(ResourceType, fmt.Sprintf("Error searching exteral source %s | error: %s", name, err), response)) | ||
|
||
} | ||
|
||
d.SetId(externalSourceId) | ||
return nil | ||
}) | ||
} | ||
|
||
func hydrateExternalSourceCacheFn(c *rc.DataSourceCache, ctx context.Context) error { | ||
proxy := getExternalContactsExternalSourceProxy(c.ClientConfig) | ||
|
||
log.Printf("Hydrating cache for data source %s", ResourceType) | ||
|
||
allExternalSource, resp, err := proxy.getAllExternalContactsExternalSources(ctx, "") | ||
if err != nil { | ||
return fmt.Errorf("failed to get external source. Error: %s | API Response: %s", err.Error(), resp.String()) | ||
} | ||
|
||
if allExternalSource == nil || len(*allExternalSource) == 0 { | ||
log.Printf("no external source found. The cache will remain empty.") | ||
return nil | ||
} | ||
|
||
for _, externalSource := range *allExternalSource { | ||
c.Cache[*externalSource.Name] = *externalSource.Id | ||
} | ||
|
||
log.Printf("Cache hydration complete for data source %s", ResourceType) | ||
return nil | ||
} | ||
|
||
// returns the external source id (blank if not found) and diag | ||
func getExternalSourceByNameFn(c *rc.DataSourceCache, name string, ctx context.Context) (string, diag.Diagnostics) { | ||
proxy := getExternalContactsExternalSourceProxy(c.ClientConfig) | ||
externalSourceId := "" | ||
|
||
diag := util.WithRetries(ctx, 15*time.Second, func() *retry.RetryError { | ||
externalSourceID, retryable, response, err := proxy.getExternalContactsExternalSourceIdByName(ctx, name) | ||
if err != nil { | ||
errMsg := util.BuildWithRetriesApiDiagnosticError(ResourceType, fmt.Sprintf("error requesting external source %s | error %s", name, err), response) | ||
if !retryable { | ||
return retry.NonRetryableError(errMsg) | ||
} | ||
return retry.RetryableError(errMsg) | ||
} | ||
|
||
externalSourceId = externalSourceID | ||
return nil | ||
}) | ||
|
||
return externalSourceId, diag | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package external_contacts_external_source | ||
|
||
import ( | ||
"fmt" | ||
"terraform-provider-genesyscloud/genesyscloud/provider" | ||
"terraform-provider-genesyscloud/genesyscloud/util" | ||
"testing" | ||
|
||
"github.com/google/uuid" | ||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
) | ||
|
||
func TestAccDataSourceexternalSource(t *testing.T) { | ||
var ( | ||
resourceLabelData = "data_external_source" | ||
resourceLabel = "resource_external_source" | ||
|
||
resourcePath = ResourceType + "." + resourceLabel | ||
dataResourcePath = "data." + ResourceType + "." + resourceLabelData | ||
|
||
name = "some-external-source-" + uuid.NewString() | ||
active = true | ||
uri_template = "https://some.host/{{externalId.value}}" | ||
) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { util.TestAccPreCheck(t) }, | ||
ProviderFactories: provider.GetProviderFactories(providerResources, providerDataSources), | ||
Steps: []resource.TestStep{ | ||
{ | ||
// Create external source with name and active properties | ||
Config: GenerateBasicExternalSourceResource( | ||
resourceLabel, | ||
name, | ||
active, | ||
uri_template, | ||
) + generateExternalSourceDataSource( | ||
resourceLabelData, | ||
name, | ||
resourcePath, | ||
), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttrPair( | ||
dataResourcePath, "id", | ||
resourcePath, "id", | ||
), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func generateExternalSourceDataSource(resourceLabel, name, dependsOn string) string { | ||
return fmt.Sprintf(`data "%s" "%s" { | ||
name = "%s" | ||
depends_on = [%s] | ||
} | ||
`, ResourceType, resourceLabel, name, dependsOn) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package external_contacts_external_source | ||
|
||
import ( | ||
"sync" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||
) | ||
|
||
// providerDataSources holds a map of all registered datasources | ||
var providerDataSources map[string]*schema.Resource | ||
|
||
// providerResources holds a map of all registered resources | ||
var providerResources map[string]*schema.Resource | ||
|
||
type registerTestInstance struct { | ||
resourceMapMutex sync.RWMutex | ||
datasourceMapMutex sync.RWMutex | ||
} | ||
|
||
// registerTestResources registers all resources used in the tests | ||
func (r *registerTestInstance) registerTestResources() { | ||
r.resourceMapMutex.Lock() | ||
defer r.resourceMapMutex.Unlock() | ||
|
||
providerResources["genesyscloud_externalcontacts_external_source"] = ResourceExternalContactsExternalSource() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can use the constant |
||
} | ||
|
||
// registerTestDataSources registers all data sources used in the tests. | ||
func (r *registerTestInstance) registerTestDataSources() { | ||
r.datasourceMapMutex.Lock() | ||
defer r.datasourceMapMutex.Unlock() | ||
|
||
providerDataSources["genesyscloud_externalcontacts_external_source"] = DataSourceExternalContactsExternalSource() | ||
} | ||
|
||
// initTestResources initializes all test resources and data sources. | ||
func initTestResources() { | ||
providerDataSources = make(map[string]*schema.Resource) | ||
providerResources = make(map[string]*schema.Resource) | ||
|
||
regInstance := ®isterTestInstance{} | ||
|
||
regInstance.registerTestDataSources() | ||
regInstance.registerTestResources() | ||
} | ||
|
||
// TestMain is a "setup" function called by the testing framework when run the test | ||
func TestMain(m *testing.M) { | ||
// Run setup function before starting the test suite for external_contacts_external_source package | ||
initTestResources() | ||
|
||
// Run the test suite for the external_contacts_external_source package | ||
m.Run() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When creating new External Sources, the backing API will ignore the value from the request and always create resource with
active
set totrue
.I thought I'd call this out, in case this is a problem for TF provider or our users.
When running the provider locally with added trace logging, we can see this message:
2025-01-06T12:15:59.181Z [WARN] Provider "provider["genesys.com/mypurecloud/genesyscloud"]" produced an unexpected new value for genesyscloud_externalcontacts_external_source.inactive_external_source, but we are tolerating it because it is using the legacy plugin SDK.
The following problems may be the cause of any confusing errors from downstream operations:
- .active: was cty.False, but now cty.True
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A change is being proposed to address this in the backend, so that the
active
value from the request is honoured.