Skip to content

Commit

Permalink
Merge branch 'develop' into feature/SCALRCORE-26514
Browse files Browse the repository at this point in the history
  • Loading branch information
penja committed Jun 16, 2023
2 parents d529e14 + 7864b18 commit 1fea672
Show file tree
Hide file tree
Showing 9 changed files with 428 additions and 9 deletions.
17 changes: 15 additions & 2 deletions CHANGELOG.md
Expand Up @@ -7,18 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.1.0] - 2023-06-16

### Added

- **New resource:** `scalr_slack_integration` ([#249](https://github.com/Scalr/terraform-provider-scalr/pull/249))
- The provider now supports loading the credentials stored by `terraform login` ([#221](https://github.com/Scalr/terraform-provider-scalr/pull/221))

### Changed

- `scar_enviroment`: removed attribute `cloud_credentials` ([#247](https://github.com/Scalr/terraform-provider-scalr/pull/247))
- `data.scalr_enviroment`: removed attribute `cloud_credentials` ([#247](https://github.com/Scalr/terraform-provider-scalr/pull/247))

### Fixed

- `scalr_provider_configuration_default`: fixed a bug where unnecessary policy groups updates were occurring for the environment ([#248](https://github.com/Scalr/terraform-provider-scalr/pull/248))

### Required

- scalr-server >= `8.71.0`

## [1.0.6] - 2023-05-12

### Added

- The provider now supports loading the credentials stored by `terraform login` ([#221](https://github.com/Scalr/terraform-provider-scalr/pull/221))
- **New data source:** `scalr_environments` ([#225](https://github.com/Scalr/terraform-provider-scalr/pull/225))
- **New data source:** `scalr_workspaces` ([#225](https://github.com/Scalr/terraform-provider-scalr/pull/225))

Expand Down Expand Up @@ -680,7 +692,8 @@ Requires Scalr 8.0.1-beta.20200625 at least

- Initial release.

[Unreleased]: https://github.com/Scalr/terraform-provider-scalr/compare/v1.0.6...HEAD
[Unreleased]: https://github.com/Scalr/terraform-provider-scalr/compare/v1.1.0...HEAD
[1.1.0]: https://github.com/Scalr/terraform-provider-scalr/releases/tag/v1.1.0
[1.0.6]: https://github.com/Scalr/terraform-provider-scalr/releases/tag/v1.0.6
[1.0.5]: https://github.com/Scalr/terraform-provider-scalr/releases/tag/v1.0.5
[1.0.4]: https://github.com/Scalr/terraform-provider-scalr/releases/tag/v1.0.4
Expand Down
2 changes: 1 addition & 1 deletion GNUmakefile
Expand Up @@ -37,7 +37,7 @@ test:
$(BUILD_ENV) xargs -t -n4 go test $(TESTARGS) -timeout=30s -parallel=4

testacc:
$(BUILD_ENV) TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 15m -covermode atomic -coverprofile=covprofile
TF_ACC=1 go test -race $(TEST) -v $(TESTARGS) -timeout 15m -covermode atomic -coverprofile=covprofile

notify-upstream:
curl -X POST \
Expand Down
39 changes: 39 additions & 0 deletions docs/resources/scalr_slack_integration.md
@@ -0,0 +1,39 @@

# Resource `scalr_slack_integration`

Manage the state of Slack integrations in Scalr. Create, update and destroy.
Slack workspace should be connected to Scalr account before using this resource.

## Example Usage

Basic usage:

```hcl
resource "scalr_slack_integration" "test" {
name = "my-channel"
account_id = "acc-xxxx"
events = ["run_approval_required", "run_success", "run_errored"]
channel_id = "xxxx" # Can be found in slack UI (channel settings/info popup)
environments = ["env-xxxxx"]
workspaces = ["ws-xxxx", "ws-xxxx"]
}
```

## Argument Reference

* `name` - (Required) Name of the Slack integration.
* `channel_id` - (Required) Slack channel ID the event will be sent to.
* `events` - (Required) Terraform run events you would like to receive a Slack notifications for.
Supported values are `run_approval_required`, `run_success`, `run_errored`.
* `environments` - (Required) List of environments where events should be triggered.
* `workspaces` - (Optional) List of workspaces where events should be triggered.
Workspaces should be in provided environments. If no workspace is given for a specified environment,
events will trigger in all of its workspaces.
* `account_id` - (Optional) ID of the account.


## Attribute Reference

All arguments plus:

* `id` - The ID of the Slack integration.
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -5,7 +5,7 @@ require (
github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce
github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.1
github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734
github.com/scalr/go-scalr v0.0.0-20230601124243-269bd29a43a8
github.com/scalr/go-scalr v0.0.0-20230612172707-84e1dfe6bf84
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Expand Up @@ -242,8 +242,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/scalr/go-scalr v0.0.0-20230601124243-269bd29a43a8 h1:FG+CAdkX9RrKzMzo54JpPWLu/iEe28ufk9Ti12RR/yc=
github.com/scalr/go-scalr v0.0.0-20230601124243-269bd29a43a8/go.mod h1:p34SHb25YRvbgft7SUjSDYESeoQhWzAlxGXId/BbaSE=
github.com/scalr/go-scalr v0.0.0-20230612172707-84e1dfe6bf84 h1:YWMFr3mzpTvLKjgC3Hdgtzr+yzyVBLjO7ryp+Gma6dM=
github.com/scalr/go-scalr v0.0.0-20230612172707-84e1dfe6bf84/go.mod h1:p34SHb25YRvbgft7SUjSDYESeoQhWzAlxGXId/BbaSE=
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
Expand Down
1 change: 1 addition & 0 deletions scalr/provider.go
Expand Up @@ -101,6 +101,7 @@ func Provider() *schema.Provider {
"scalr_run_trigger": resourceScalrRunTrigger(),
"scalr_service_account": resourceScalrServiceAccount(),
"scalr_service_account_token": resourceScalrServiceAccountToken(),
"scalr_slack_integration": resourceScalrSlackIntegration(),
"scalr_tag": resourceScalrTag(),
"scalr_variable": resourceScalrVariable(),
"scalr_vcs_provider": resourceScalrVcsProvider(),
Expand Down
10 changes: 7 additions & 3 deletions scalr/resource_scalr_provider_configuration.go
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"sync"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down Expand Up @@ -783,15 +784,18 @@ func changeParameters(

for i := 0; i < numParallel; i++ {
go func() {
reqCtx, reqCancel := context.WithTimeout(context.Background(), time.Second*10)
defer reqCancel()

for t := range inputCh {
if t.createOption != nil {
parameter, err := client.ProviderConfigurationParameters.Create(ctx, configurationID, *t.createOption)
parameter, err := client.ProviderConfigurationParameters.Create(reqCtx, configurationID, *t.createOption)
resultCh <- result{created: parameter, err: err}
} else if t.updateOption != nil {
parameter, err := client.ProviderConfigurationParameters.Update(ctx, t.updateOption.ID, *t.updateOption)
parameter, err := client.ProviderConfigurationParameters.Update(reqCtx, t.updateOption.ID, *t.updateOption)
resultCh <- result{updated: parameter, err: err}
} else {
err := client.ProviderConfigurationParameters.Delete(ctx, *t.deleteId)
err := client.ProviderConfigurationParameters.Delete(reqCtx, *t.deleteId)
resultCh <- result{deleted: t.deleteId, err: err}
}
}
Expand Down
241 changes: 241 additions & 0 deletions scalr/resource_scalr_slack_integration.go
@@ -0,0 +1,241 @@
package scalr

import (
"context"
"errors"
"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/validation"
"github.com/scalr/go-scalr"
"log"
)

func resourceScalrSlackIntegration() *schema.Resource {
return &schema.Resource{
CreateContext: resourceScalrSlackIntegrationCreate,
ReadContext: resourceScalrSlackIntegrationRead,
UpdateContext: resourceScalrSlackIntegrationUpdate,
DeleteContext: resourceSlackIntegrationDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
"events": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(
validation.StringInSlice(
[]string{
scalr.SlackIntegrationEventRunApprovalRequired,
scalr.SlackIntegrationEventRunSuccess,
scalr.SlackIntegrationEventRunErrored,
},
false,
),
),
},
Required: true,
MinItems: 1,
},
"channel_id": {
Type: schema.TypeString,
Required: true,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
"account_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
DefaultFunc: scalrAccountIDDefaultFunc,
ForceNew: true,
},
"environments": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
Required: true,
MinItems: 1,
},
"workspaces": {
Type: schema.TypeSet,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
Optional: true,
},
},
}
}

func parseEvents(d *schema.ResourceData) []string {
events := d.Get("events").(*schema.Set).List()
eventValues := make([]string, 0)

for _, event := range events {
eventValues = append(eventValues, event.(string))
}

return eventValues
}

func parseEnvironments(d *schema.ResourceData) []*scalr.Environment {
environments := d.Get("environments").(*schema.Set).List()
environmentValues := make([]*scalr.Environment, 0)

for _, env := range environments {
environmentValues = append(environmentValues, &scalr.Environment{ID: env.(string)})
}

return environmentValues
}

func parseWorkspaces(d *schema.ResourceData) []*scalr.Workspace {
workspacesI, ok := d.GetOk("workspaces")
if !ok {
return nil
}
workspaces := workspacesI.(*schema.Set).List()
workspaceValues := make([]*scalr.Workspace, 0)

for _, ws := range workspaces {
workspaceValues = append(workspaceValues, &scalr.Workspace{ID: ws.(string)})
}

return workspaceValues
}

func resourceScalrSlackIntegrationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)
// Get attributes.
name := d.Get("name").(string)
accountID := d.Get("account_id").(string)

options := scalr.SlackIntegrationCreateOptions{
Name: &name,
ChannelId: scalr.String(d.Get("channel_id").(string)),
Events: parseEvents(d),
Account: &scalr.Account{ID: accountID},
Environments: parseEnvironments(d),
}
workspaces := parseWorkspaces(d)
if workspaces != nil {
options.Workspaces = workspaces
}

connection, err := scalrClient.SlackIntegrations.GetConnection(ctx, options.Account.ID)
if err != nil {
return diag.Errorf("Error creating slack integration %s: %v", name, err)
}

if connection.ID == "" {
return diag.Errorf(
"Error creating Slack integration: account %s does not have Slack connection configured."+
" Connect your Slack workspace to Scalr using UI first.",
accountID,
)
}

options.Connection = connection

log.Printf("[DEBUG] Create slack integration: %s", name)
integration, err := scalrClient.SlackIntegrations.Create(ctx, options)
if err != nil {
return diag.Errorf("Error creating slack integration %s: %v", name, err)
}
d.SetId(integration.ID)

return resourceScalrSlackIntegrationRead(ctx, d, meta)
}

func resourceScalrSlackIntegrationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)
integrationID := d.Id()

log.Printf("[DEBUG] Read slack integration with ID: %s", integrationID)
slackIntegration, err := scalrClient.SlackIntegrations.Read(ctx, integrationID)
if err != nil {
log.Printf("[DEBUG] slack integration %s no longer exists", integrationID)
d.SetId("")
return nil
}
_ = d.Set("name", slackIntegration.Name)
_ = d.Set("channel_id", slackIntegration.ChannelId)
_ = d.Set("events", slackIntegration.Events)
_ = d.Set("account_id", slackIntegration.Account.ID)

environmentIDs := make([]string, 0)
for _, environment := range slackIntegration.Environments {
environmentIDs = append(environmentIDs, environment.ID)
}

_ = d.Set("environments", environmentIDs)

wsIDs := make([]string, 0)
for _, ws := range slackIntegration.Workspaces {
wsIDs = append(wsIDs, ws.ID)
}
_ = d.Set("workspaces", wsIDs)

return nil
}

func resourceScalrSlackIntegrationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)
options := scalr.SlackIntegrationUpdateOptions{}

if d.HasChange("name") {
options.Name = scalr.String(d.Get("name").(string))
}

if d.HasChange("channel_id") {
options.ChannelId = scalr.String(d.Get("channel_id").(string))
}

if d.HasChange("events") {
events := parseEvents(d)
options.Events = events
}

if d.HasChange("environments") {
envs := parseEnvironments(d)
options.Environments = envs
}

workspaces := parseWorkspaces(d)
if workspaces != nil {
options.Workspaces = workspaces
}

log.Printf("[DEBUG] Update slack integration: %s", d.Id())
_, err := scalrClient.SlackIntegrations.Update(ctx, d.Id(), options)
if err != nil {
return diag.Errorf("Error updating slack integration %s: %v", d.Id(), err)
}

return nil
}

func resourceSlackIntegrationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
scalrClient := meta.(*scalr.Client)

log.Printf("[DEBUG] Delete slack integration: %s", d.Id())
err := scalrClient.SlackIntegrations.Delete(ctx, d.Id())
if err != nil {
if errors.Is(err, scalr.ErrResourceNotFound) {
return nil
}
return diag.Errorf("Error deleting slack integration %s: %v", d.Id(), err)
}

return nil
}

0 comments on commit 1fea672

Please sign in to comment.