From 435da22684b1fabbb5dfcd587d800149dc92a1c8 Mon Sep 17 00:00:00 2001 From: Charlie Conneely Date: Mon, 28 Aug 2023 12:09:12 +0100 Subject: [PATCH] Create 2023 Workshop v2 --- ...ource_genesyscloud_simple_routing_queue.go | 30 ++++-- ..._genesyscloud_simple_routing_queue_test.go | 4 +- ...syscloud_simple_routing_queue_init_test.go | 2 - ...genesyscloud_simple_routing_queue_proxy.go | 20 ++-- ...ource_genesyscloud_simple_routing_queue.go | 97 ++++++++++++++++--- ...enesyscloud_simple_routing_queue_schema.go | 21 +++- ..._genesyscloud_simple_routing_queue_test.go | 6 +- main.go | 28 +++--- 8 files changed, 152 insertions(+), 56 deletions(-) diff --git a/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue.go b/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue.go index 392ffeb40..94c28b335 100644 --- a/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue.go +++ b/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue.go @@ -2,9 +2,11 @@ package simple_routing_queue import ( "context" + "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" gcloud "terraform-provider-genesyscloud/genesyscloud" "time" ) @@ -16,22 +18,32 @@ import ( // dataSourceSimpleRoutingQueueRead retrieves by search term the id in question func dataSourceSimpleRoutingQueueRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // Get an instance of our proxy + // TODO 1: . Get an instance of our proxy + sdkConfig := meta.(*gcloud.ProviderMeta).ClientConfig + proxy := getSimpleRoutingQueueProxy(sdkConfig) - // Grab our queue name from the schema.ResourceData object + // TODO 2: Grab our queue name from the schema.ResourceData object + name := d.Get("name").(string) + log.Printf("Finding queue with name '%s'", name) return gcloud.WithRetries(ctx, 15*time.Second, func() *resource.RetryError { - - // Call to the proxy function getRoutingQueueIdByName(context.Context, string) + // TODO 3: Call to the proxy function getRoutingQueueIdByName(context.Context, string) // This function returns values in the following order: queueId (string), retryable (bool), err (error) + queueId, retryable, err := proxy.getRoutingQueueIdByName(ctx, name) - // If the error is not nil, and retryable equals false, return a resource.NonRetryableError - // letting the user know that an error occurred + // TODO 4: If the error is not nil, and retryable equals false, return a resource.NonRetryableError + // to let the user know that an error occurred + if err != nil && !retryable { + return resource.NonRetryableError(fmt.Errorf("error finding queue '%s': %v", name, err)) + } - // If retryable equals true, return a resource.RetryableError and let them know the queue could not be found - // with that name + // TODO 5: If retryable equals true, return a resource.RetryableError and let them know the queue could not be found with that name + if retryable { + return resource.RetryableError(fmt.Errorf("no queue found with name '%s'", name)) + } - // If we made it this far, we can set the queue ID in the schema.ResourceData object, and return nil + // TODO 6: If we made it this far, we can set the queue ID in the schema.ResourceData object, and return nil + d.SetId(queueId) return nil }) } diff --git a/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue_test.go b/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue_test.go index 16b1a131c..c65c33b7d 100644 --- a/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue_test.go +++ b/genesyscloud/simple_routing_queue/data_source_genesyscloud_simple_routing_queue_test.go @@ -20,14 +20,14 @@ func TestAccDataSourceSimpleRoutingQueue(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { gcloud.TestAccPreCheck(t) }, - ProviderFactories: gcloud.GetProviderFactories(nil, nil), + ProviderFactories: gcloud.GetProviderFactories(providerResources, providerDataSources), Steps: []resource.TestStep{ { Config: generateSimpleRoutingQueueResource( resourceId, simpleQueueName, "null", - "null", + "false", ) + generateSimpleRoutingQueueDataSource( dataSourceId, simpleQueueName, diff --git a/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_init_test.go b/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_init_test.go index 71507d6d6..c432dc0f7 100644 --- a/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_init_test.go +++ b/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_init_test.go @@ -31,7 +31,6 @@ func (r *registerTestInstance) registerTestResources() { defer r.resourceMapMutex.Unlock() providerResources[resourceName] = ResourceSimpleRoutingQueue() - } // registerTestDataSources registers all data sources used in the tests. @@ -40,7 +39,6 @@ func (r *registerTestInstance) registerTestDataSources() { defer r.datasourceMapMutex.Unlock() providerDataSources[resourceName] = DataSourceSimpleRoutingQueue() - } // initTestResources initializes all test resources and data sources. diff --git a/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_proxy.go b/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_proxy.go index db2b081aa..0d0c44ba0 100644 --- a/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_proxy.go +++ b/genesyscloud/simple_routing_queue/genesyscloud_simple_routing_queue_proxy.go @@ -7,9 +7,9 @@ import ( ) type createRoutingQueueFunc func(context.Context, *simpleRoutingQueueProxy, *platformclientv2.Createqueuerequest) (*platformclientv2.Queue, *platformclientv2.APIResponse, error) -type getRoutingQueueFunc func(context.Context, *simpleRoutingQueueProxy, string) (*platformclientv2.Queue, *platformclientv2.APIResponse, error) +type getRoutingQueueFunc func(context.Context, *simpleRoutingQueueProxy, string) (*platformclientv2.Queue, int, error) type updateRoutingQueueFunc func(context.Context, *simpleRoutingQueueProxy, string, *platformclientv2.Queuerequest) (*platformclientv2.Queue, *platformclientv2.APIResponse, error) -type deleteRoutingQueueFunc func(context.Context, *simpleRoutingQueueProxy, string, bool) (*platformclientv2.APIResponse, error) +type deleteRoutingQueueFunc func(context.Context, *simpleRoutingQueueProxy, string) (*platformclientv2.APIResponse, error) type getRoutingQueueIdByNameFunc func(context.Context, *simpleRoutingQueueProxy, string) (id string, retryable bool, err error) var internalProxy *simpleRoutingQueueProxy @@ -51,7 +51,7 @@ func (p *simpleRoutingQueueProxy) createRoutingQueue(ctx context.Context, queue } // getRoutingQueue retrieves a Genesys Cloud Routing Queue by ID -func (p *simpleRoutingQueueProxy) getRoutingQueue(ctx context.Context, id string) (*platformclientv2.Queue, *platformclientv2.APIResponse, error) { +func (p *simpleRoutingQueueProxy) getRoutingQueue(ctx context.Context, id string) (*platformclientv2.Queue, int, error) { return p.getRoutingQueueAttr(ctx, p, id) } @@ -66,8 +66,8 @@ func (p *simpleRoutingQueueProxy) updateRoutingQueue(ctx context.Context, id str } // deleteRoutingQueue deletes a Genesys Cloud Routing Queue -func (p *simpleRoutingQueueProxy) deleteRoutingQueue(ctx context.Context, id string, forceDelete bool) (*platformclientv2.APIResponse, error) { - return p.deleteRoutingQueueAttr(ctx, p, id, forceDelete) +func (p *simpleRoutingQueueProxy) deleteRoutingQueue(ctx context.Context, id string) (*platformclientv2.APIResponse, error) { + return p.deleteRoutingQueueAttr(ctx, p, id) } // createRoutingQueueFn is an implementation function for creating a Genesys Cloud Routing Queue @@ -79,12 +79,12 @@ func createRoutingQueueFn(ctx context.Context, proxy *simpleRoutingQueueProxy, q return sdkQueue, response, err } -func getRoutingQueueFn(ctx context.Context, proxy *simpleRoutingQueueProxy, id string) (*platformclientv2.Queue, *platformclientv2.APIResponse, error) { +func getRoutingQueueFn(ctx context.Context, proxy *simpleRoutingQueueProxy, id string) (*platformclientv2.Queue, int, error) { queue, response, err := proxy.routingApi.GetRoutingQueue(id) if err != nil { - return nil, nil, fmt.Errorf("failed to get routing queue by id '%s': %v", id, err) + return nil, response.StatusCode, fmt.Errorf("failed to get routing queue by id '%s': %v", id, err) } - return queue, response, err + return queue, 0, err } func getRoutingQueueIdByNameFn(ctx context.Context, proxy *simpleRoutingQueueProxy, name string) (string, bool, error) { @@ -115,8 +115,8 @@ func updateRoutingQueueFn(ctx context.Context, proxy *simpleRoutingQueueProxy, i return queue, response, err } -func deleteRoutingQueueFn(ctx context.Context, proxy *simpleRoutingQueueProxy, id string, forceDelete bool) (*platformclientv2.APIResponse, error) { - response, err := proxy.routingApi.DeleteRoutingQueue(id, forceDelete) +func deleteRoutingQueueFn(ctx context.Context, proxy *simpleRoutingQueueProxy, id string) (*platformclientv2.APIResponse, error) { + response, err := proxy.routingApi.DeleteRoutingQueue(id, true) if err != nil { return nil, fmt.Errorf("failed to delete queue '%s': %v", id, err) } diff --git a/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue.go b/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue.go index 90d1c6f57..c5c1c3657 100644 --- a/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue.go +++ b/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue.go @@ -6,9 +6,11 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/mypurecloud/platform-client-sdk-go/v105/platformclientv2" "log" gcloud "terraform-provider-genesyscloud/genesyscloud" "terraform-provider-genesyscloud/genesyscloud/consistency_checker" + "terraform-provider-genesyscloud/genesyscloud/util/resourcedata" "time" ) @@ -32,30 +34,66 @@ utils file in the package. This will keep the code manageable and easy to work // createSimpleRoutingQueue is used by the genesyscloud_simple_routing_queue resource to create a simple queue in Genesys cloud. func createSimpleRoutingQueue(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // Get an instance of the proxy (example can be found in the delete method below) + // TODO 1: Get an instance of the proxy (example can be found in the delete method below) + sdkConfig := meta.(*gcloud.ProviderMeta).ClientConfig + proxy := getSimpleRoutingQueueProxy(sdkConfig) + + // TODO 2: Create variables for each field in our schema.ResourceData object + name := d.Get("name").(string) + callingPartyName := d.Get("calling_party_name").(string) + enableTranscription := d.Get("enable_transcription").(bool) + + log.Printf("Creating simple queue %s", name) - // Create a queue struct using the Genesys Cloud platform go sdk + // TODO 3: Create a queue struct using the Genesys Cloud platform go sdk + queueCreate := &platformclientv2.Createqueuerequest{ + Name: &name, + CallingPartyName: &callingPartyName, + EnableTranscription: &enableTranscription, + } - // Call the proxy function to create our queue + // TODO 4: Call the proxy function to create our queue. The proxy function we want to use here is createRoutingQueue(ctx context.Context, queue *platformclientv2.Createqueuerequest) + // Note: We won't need the response object returned. Also, don't forget about error handling! + queueResp, _, err := proxy.createRoutingQueue(ctx, queueCreate) + if err != nil { + return diag.Errorf("failed to create queue %s: %v", name, err) + } + + // TODO 5: Set ID in the schema.ResourceData object + d.SetId(*queueResp.Id) return readSimpleRoutingQueue(ctx, d, meta) } // readSimpleRoutingQueue is used by the genesyscloud_simple_routing_queue resource to read a simple queue from Genesys cloud. func readSimpleRoutingQueue(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // Get an instance of the proxy + // TODO 1: Get an instance of the proxy + sdkConfig := meta.(*gcloud.ProviderMeta).ClientConfig + proxy := getSimpleRoutingQueueProxy(sdkConfig) + log.Printf("Reading simple queue %s", d.Id()) return gcloud.WithRetriesForRead(ctx, d, func() *resource.RetryError { - // Call the read queue function to find our queue, passing in the ID from the resource data ( d.Id() ) - // The returned value are: Queue, APIResponse, error - // If the error is not nil, we should pass the response to the function gcloud.IsStatus404(response) - // If the status is 404, return a resource.RetryableError. Otherwise, it should be a NonRetryableError + /* + TODO 2: Call the proxy function getRoutingQueue(ctx context.Context, id string) to find our queue, passing in the ID from the resource data object + The returned value are: Queue, Status Code (int), error + If the error is not nil, we should pass the status code to the function gcloud.IsStatus404ByInt(int) + If the status code is 404, return a resource.RetryableError. Otherwise, it should be a NonRetryableError + */ + currentQueue, respCode, err := proxy.getRoutingQueue(ctx, d.Id()) + if err != nil { + if gcloud.IsStatus404ByInt(respCode) { + return resource.RetryableError(fmt.Errorf("failed to read queue %s: %v", d.Id(), err)) + } + return resource.NonRetryableError(fmt.Errorf("failed to read queue %s: %v", d.Id(), err)) + } // Define consistency checker cc := consistency_checker.NewConsistencyCheck(ctx, d, meta, ResourceSimpleRoutingQueue()) - // Set our values in the schema resource data, based on the values - // in the Queue object returned from the API + // TODO 3: Set our values in the schema resource data, based on the values in the Queue object returned from the API + _ = d.Set("name", *currentQueue.Name) + resourcedata.SetNillableValue(d, "calling_party_name", currentQueue.CallingPartyName) + resourcedata.SetNillableValue(d, "enable_transcription", currentQueue.EnableTranscription) return cc.CheckState() }) @@ -63,31 +101,58 @@ func readSimpleRoutingQueue(ctx context.Context, d *schema.ResourceData, meta in // updateSimpleRoutingQueue is used by the genesyscloud_simple_routing_queue resource to update a simple queue in Genesys cloud. func updateSimpleRoutingQueue(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // Get an instance of the proxy + // TODO 1: Get an instance of the proxy + sdkConfig := meta.(*gcloud.ProviderMeta).ClientConfig + proxy := getSimpleRoutingQueueProxy(sdkConfig) - // Create a queue struct using the Genesys Cloud platform go sdk + log.Printf("Updating simple queue %s", d.Id()) - // Call the proxy function to update our queue, passing in the struct and the queue ID + // TODO 2: Create variables for each field in our schema.ResourceData object + name := d.Get("name").(string) + callingPartyName := d.Get("calling_party_name").(string) + enableTranscription := d.Get("enable_transcription").(bool) + + // TODO 3: Create a queue struct using the Genesys Cloud platform go sdk + queueUpdate := &platformclientv2.Queuerequest{ + Name: &name, + CallingPartyName: &callingPartyName, + EnableTranscription: &enableTranscription, + } + + // TODO 4: Call the proxy function updateRoutingQueue(context.Context, id string, *platformclientv2.Queuerequest) to update our queue + _, _, err := proxy.updateRoutingQueue(ctx, d.Id(), queueUpdate) + if err != nil { + return diag.Errorf("failed to update queue %s: %v", name, err) + } return readSimpleRoutingQueue(ctx, d, meta) } // deleteSimpleRoutingQueue is used by the genesyscloud_simple_routing_queue resource to delete a simple queue from Genesys cloud. func deleteSimpleRoutingQueue(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - // Get an instance of the proxy + // TODO 1: Get an instance of the proxy (done) sdkConfig := meta.(*gcloud.ProviderMeta).ClientConfig proxy := getSimpleRoutingQueueProxy(sdkConfig) - /* Call the delete queue proxy function, passing in our queue ID from the schema.ResourceData object */ + log.Printf("Deleting simple queue %s", d.Id()) + + /* + TODO 2: Call the proxy function deleteRoutingQueue(ctx context.Context, id string) + Again, we won't be needing the returned response object + */ + if _, err := proxy.deleteRoutingQueue(ctx, d.Id()); err != nil { + return diag.Errorf("failed to delete queue %s: %v", d.Id(), err) + } // Check that queue has been deleted by trying to get it from the API + time.Sleep(5 * time.Second) return gcloud.WithRetries(ctx, 30*time.Second, func() *resource.RetryError { _, respCode, err := proxy.getRoutingQueue(ctx, d.Id()) if err == nil { return resource.NonRetryableError(fmt.Errorf("error deleting routing queue %s: %s", d.Id(), err)) } - if gcloud.IsStatus404(respCode) { + if gcloud.IsStatus404ByInt(respCode) { // Success: Routing Queue deleted log.Printf("Deleted routing queue %s", d.Id()) return nil diff --git a/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_schema.go b/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_schema.go index 075c46f85..32c9f30cc 100644 --- a/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_schema.go +++ b/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_schema.go @@ -9,23 +9,35 @@ import ( const resourceName = "genesyscloud_simple_routing_queue" func SetRegistrar(l registrar.Registrar) { - l.RegisterResource(resourceName, ResourceSimpleRoutingQueue()) l.RegisterDataSource(resourceName, DataSourceSimpleRoutingQueue()) + l.RegisterResource(resourceName, ResourceSimpleRoutingQueue()) } func ResourceSimpleRoutingQueue() *schema.Resource { return &schema.Resource{ Description: "Genesys Cloud Simple Routing Queue", + // TODO: Specify our our functions that we defined in resource_genesyscloud_simple_routing_queue.go for performing CRUD operations. + // For example: + // ReadContext: gcloud.ReadWithPooledClient(readSimpleRoutingQueue) CreateContext: gcloud.CreateWithPooledClient(createSimpleRoutingQueue), ReadContext: gcloud.ReadWithPooledClient(readSimpleRoutingQueue), UpdateContext: gcloud.UpdateWithPooledClient(updateSimpleRoutingQueue), DeleteContext: gcloud.DeleteWithPooledClient(deleteSimpleRoutingQueue), + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, SchemaVersion: 1, Schema: map[string]*schema.Schema{ + /* + TODO: Define the following three fields: + 1. "name" | type: string | required | description: "The name of our routing queue." + 2. "calling_party_name" | type: string | optional | description: "The name to use for caller identification for outbound calls from this queue." + 3. "enable_transcription" | type: boolean | optional | description: "Indicates whether voice transcription is enabled for this queue." + Note: The field "enable_transcription" is also Computed. This lets the provider know that the API will compute and return a value, should + the user not specify one in the resource config. + */ "name": { Description: "The name for our routing queue.", Type: schema.TypeString, @@ -40,6 +52,7 @@ func ResourceSimpleRoutingQueue() *schema.Resource { Description: "Indicates whether voice transcription is enabled for this queue.", Type: schema.TypeBool, Optional: true, + Computed: true, }, }, } @@ -48,8 +61,14 @@ func ResourceSimpleRoutingQueue() *schema.Resource { func DataSourceSimpleRoutingQueue() *schema.Resource { return &schema.Resource{ Description: "Data source for Genesys Cloud Simple Routing Queues.", + // TODO: As above, specify the function dataSourceSimpleRoutingQueueRead as the ReadContext of this Resource object ReadContext: gcloud.ReadWithPooledClient(dataSourceSimpleRoutingQueueRead), + Schema: map[string]*schema.Schema{ + /* + TODO: Define the only field in our data source: + "name" | type: string | required | description: "The name of our routing queue." + */ "name": { Description: "The queue name.", Type: schema.TypeString, diff --git a/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_test.go b/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_test.go index 9fac9554e..85e1d6177 100644 --- a/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_test.go +++ b/genesyscloud/simple_routing_queue/resource_genesyscloud_simple_routing_queue_test.go @@ -33,7 +33,7 @@ func TestAccResourceSimpleRoutingQueue(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(fullResourcePath, "name", name), resource.TestCheckResourceAttr(fullResourcePath, "calling_party_name", callingPartyName), - resource.TestCheckResourceAttr(fullResourcePath, "enable_transcription", "true"), + resource.TestCheckResourceAttr(fullResourcePath, "enable_transcription", enableTranscription), ), }, }, @@ -42,10 +42,10 @@ func TestAccResourceSimpleRoutingQueue(t *testing.T) { func generateSimpleRoutingQueueResource(resourceId, name, callingPartyName, enableTranscription string) string { return fmt.Sprintf(` -resource "genesyscloud_simple_routing_queue" "%s" { +resource "%s" "%s" { name = "%s" calling_party_name = %s enable_transcription = %s } -`, resourceId, name, callingPartyName, enableTranscription) +`, resourceName, resourceId, name, callingPartyName, enableTranscription) } diff --git a/main.go b/main.go index 690c7ea27..42d4a7c48 100644 --- a/main.go +++ b/main.go @@ -76,23 +76,25 @@ type RegisterInstance struct { func registerResources() { - reg_instance := &RegisterInstance{} - - pat.SetRegistrar(reg_instance) - - ob.SetRegistrar(reg_instance) - gcloud.SetRegistrar(reg_instance) - obAttemptLimit.SetRegistrar(reg_instance) - obContactList.SetRegistrar(reg_instance) - obRuleset.SetRegistrar(reg_instance) - scripts.SetRegistrar(reg_instance) - externalContacts.SetRegistrar(reg_instance) - simpleRoutingQueue.SetRegistrar(reg_instance) + regInstance := &RegisterInstance{} + + pat.SetRegistrar(regInstance) + + ob.SetRegistrar(regInstance) + gcloud.SetRegistrar(regInstance) + obAttemptLimit.SetRegistrar(regInstance) + obContactList.SetRegistrar(regInstance) + obRuleset.SetRegistrar(regInstance) + scripts.SetRegistrar(regInstance) + externalContacts.SetRegistrar(regInstance) resourceExporter.SetRegisterExporter(resourceExporters) + /* TODO: Import the simple_routing_queue package and call it's SetRegistrar function, as above. */ + simpleRoutingQueue.SetRegistrar(regInstance) + // setting resources for Use cases like TF export where provider is used in resource classes. //tfexp.GetRegistrarresources() - tfexp.SetRegistrar(reg_instance) + tfexp.SetRegistrar(regInstance) registrar.SetResources(providerResources, providerDataSources) }