Skip to content

Commit

Permalink
Create 2023 Workshop v2
Browse files Browse the repository at this point in the history
  • Loading branch information
charliecon committed Sep 7, 2023
1 parent b08671e commit 435da22
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ func (r *registerTestInstance) registerTestResources() {
defer r.resourceMapMutex.Unlock()

providerResources[resourceName] = ResourceSimpleRoutingQueue()

}

// registerTestDataSources registers all data sources used in the tests.
Expand All @@ -40,7 +39,6 @@ func (r *registerTestInstance) registerTestDataSources() {
defer r.datasourceMapMutex.Unlock()

providerDataSources[resourceName] = DataSourceSimpleRoutingQueue()

}

// initTestResources initializes all test resources and data sources.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}

Expand All @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -32,62 +34,125 @@ 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()
})
}

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
},
},
}
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
),
},
},
Expand All @@ -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)
}
Loading

0 comments on commit 435da22

Please sign in to comment.