Skip to content

Commit e0896c4

Browse files
authored
snow approval channel (#116)
* snow approval channel * bump versions of marketplace actions in test workflow
1 parent 6dcd5d1 commit e0896c4

File tree

7 files changed

+450
-6
lines changed

7 files changed

+450
-6
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ jobs:
1919
runs-on: ubuntu-latest
2020
timeout-minutes: 5
2121
steps:
22-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
23-
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
22+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23+
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
2424
with:
2525
go-version-file: "go.mod"
2626
cache: true
2727
- run: go mod download
2828
- run: go build -v .
2929
- name: Run linters
30-
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
30+
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
3131
with:
3232
version: latest
3333

@@ -66,12 +66,12 @@ jobs:
6666
- "1.3.*"
6767
- "1.4.*"
6868
steps:
69-
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
70-
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
69+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
70+
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
7171
with:
7272
go-version-file: "go.mod"
7373
cache: true
74-
- uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3
74+
- uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2
7575
with:
7676
terraform_version: ${{ matrix.terraform }}
7777
terraform_wrapper: false

client/models.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ type ApprovalChannel struct {
527527
type ApprovalChannelDetails struct {
528528
Type string `json:"type"`
529529
Approvers []Approver `json:"approvers"`
530+
Approver *Approver `json:"approver,omitempty"`
530531
Headers *string `json:"headers,omitempty"`
531532
BaseUrl *string `json:"base_url,omitempty"`
532533
UserName *string `json:"user_name,omitempty"`
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "torque_servicenow_approval_channel Resource - terraform-provider-torque"
4+
subcategory: ""
5+
description: |-
6+
Creates a new ServiceNow approval channel.
7+
---
8+
9+
# torque_servicenow_approval_channel (Resource)
10+
11+
Creates a new ServiceNow approval channel.
12+
13+
## Example Usage
14+
15+
```terraform
16+
terraform {
17+
required_providers {
18+
torque = {
19+
source = "qualitorque/torque"
20+
}
21+
}
22+
}
23+
24+
provider "torque" {
25+
host = "https://portal.qtorque.io/"
26+
space = "space"
27+
token = "111111111111"
28+
}
29+
30+
resource "torque_servicenow_approval_channel" "channel" {
31+
name = "name"
32+
description = "description"
33+
base_url = "base_url"
34+
username = "username"
35+
password = "password"
36+
headers = "json"
37+
approver = "approver@company.com"
38+
}
39+
```
40+
41+
<!-- schema generated by tfplugindocs -->
42+
## Schema
43+
44+
### Required
45+
46+
- `approver` (String) ServiceNow Approver
47+
- `base_url` (String) ServiceNow Instance Base URL
48+
- `name` (String) Name of the approval channel.
49+
- `password` (String, Sensitive) ServiceNow Password
50+
- `user_name` (String) ServiceNow Username
51+
52+
### Optional
53+
54+
- `description` (String) Description of the approval channel
55+
- `headers` (String) Custom Headers (JSON) - JSON formatted string that represents the custom headers, for example {header:'val'}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
terraform {
2+
required_providers {
3+
torque = {
4+
source = "qualitorque/torque"
5+
}
6+
}
7+
}
8+
9+
provider "torque" {
10+
host = "https://portal.qtorque.io/"
11+
space = "space"
12+
token = "111111111111"
13+
}
14+
15+
resource "torque_servicenow_approval_channel" "channel" {
16+
name = "name"
17+
description = "description"
18+
base_url = "base_url"
19+
username = "username"
20+
password = "password"
21+
headers = "json"
22+
approver = "approver@company.com"
23+
}

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ func (p *torqueProvider) Resources(ctx context.Context) []func() resource.Resour
239239
resources.NewTorqueDeploymentEngineResource,
240240
resources.NewTorqueEmailApprovalChannelResource,
241241
resources.NewTorqueTeamsApprovalChannelResource,
242+
resources.NewTorqueServiceNowApprovalChannelResource,
242243
}
243244
}
244245

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package resources
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework/path"
8+
"github.com/hashicorp/terraform-plugin-framework/resource"
9+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
10+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
11+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
12+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
13+
"github.com/hashicorp/terraform-plugin-framework/types"
14+
"github.com/qualitorque/terraform-provider-torque/client"
15+
)
16+
17+
// Ensure provider defined types fully satisfy framework interfaces.
18+
var _ resource.Resource = &TorqueServiceNowApprovalChannelResource{}
19+
var _ resource.ResourceWithImportState = &TorqueServiceNowApprovalChannelResource{}
20+
21+
func NewTorqueServiceNowApprovalChannelResource() resource.Resource {
22+
return &TorqueServiceNowApprovalChannelResource{}
23+
}
24+
25+
// TorqueServiceNowApprovalChannelResource defines the resource implementation.
26+
type TorqueServiceNowApprovalChannelResource struct {
27+
client *client.Client
28+
}
29+
30+
// TorqueServiceNowApprovalChannelResourceModel describes the resource data model.
31+
type TorqueServiceNowApprovalChannelResourceModel struct {
32+
Name types.String `tfsdk:"name"`
33+
Description types.String `tfsdk:"description"`
34+
Approver types.String `tfsdk:"approver"`
35+
BaseUrl types.String `tfsdk:"base_url"`
36+
UserName types.String `tfsdk:"user_name"`
37+
Password types.String `tfsdk:"password"`
38+
Headers types.String `tfsdk:"headers"`
39+
}
40+
41+
const (
42+
servicenow_approval_channel_type = "ServiceNow"
43+
)
44+
45+
func (r *TorqueServiceNowApprovalChannelResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
46+
resp.TypeName = "torque_servicenow_approval_channel"
47+
}
48+
49+
func (r *TorqueServiceNowApprovalChannelResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
50+
resp.Schema = schema.Schema{
51+
// This description is used by the documentation generator and the language server.
52+
MarkdownDescription: "Creates a new ServiceNow approval channel.",
53+
Attributes: map[string]schema.Attribute{
54+
"name": schema.StringAttribute{
55+
MarkdownDescription: "Name of the approval channel.",
56+
Optional: false,
57+
Computed: false,
58+
Required: true,
59+
PlanModifiers: []planmodifier.String{
60+
stringplanmodifier.RequiresReplace(),
61+
},
62+
},
63+
"description": schema.StringAttribute{
64+
MarkdownDescription: "Description of the approval channel",
65+
Optional: true,
66+
Computed: true,
67+
Required: false,
68+
Default: stringdefault.StaticString(""),
69+
},
70+
"base_url": schema.StringAttribute{
71+
MarkdownDescription: "ServiceNow Instance Base URL",
72+
Optional: false,
73+
Computed: false,
74+
Required: true,
75+
},
76+
"user_name": schema.StringAttribute{
77+
MarkdownDescription: "ServiceNow Username",
78+
Optional: false,
79+
Computed: false,
80+
Required: true,
81+
},
82+
"password": schema.StringAttribute{
83+
MarkdownDescription: "ServiceNow Password",
84+
Optional: false,
85+
Computed: false,
86+
Required: true,
87+
Sensitive: true,
88+
},
89+
"headers": schema.StringAttribute{
90+
MarkdownDescription: "Custom Headers (JSON) - JSON formatted string that represents the custom headers, for example {header:'val'}",
91+
Optional: true,
92+
Computed: false,
93+
Required: false,
94+
},
95+
"approver": schema.StringAttribute{
96+
MarkdownDescription: "ServiceNow Approver",
97+
Optional: false,
98+
Computed: false,
99+
Required: true,
100+
},
101+
},
102+
}
103+
}
104+
func (r *TorqueServiceNowApprovalChannelResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
105+
// Prevent panic if the provider has not been configured.
106+
if req.ProviderData == nil {
107+
return
108+
}
109+
110+
client, ok := req.ProviderData.(*client.Client)
111+
112+
if !ok {
113+
resp.Diagnostics.AddError(
114+
"Unexpected Resource Configure Type",
115+
fmt.Sprintf("Expected *http.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
116+
)
117+
118+
return
119+
}
120+
121+
r.client = client
122+
}
123+
124+
func (r *TorqueServiceNowApprovalChannelResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
125+
var data TorqueServiceNowApprovalChannelResourceModel
126+
var details client.ApprovalChannelDetails
127+
details.Approver = &client.Approver{}
128+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
129+
130+
if resp.Diagnostics.HasError() {
131+
return
132+
}
133+
134+
details.Approver.UserEmail = data.Approver.ValueString()
135+
details.Type = servicenow_approval_channel_type
136+
details.BaseUrl = data.BaseUrl.ValueStringPointer()
137+
details.UserName = data.UserName.ValueStringPointer()
138+
details.Password = data.Password.ValueStringPointer()
139+
details.Headers = data.Headers.ValueStringPointer()
140+
err := r.client.CreateApprovalChannel(data.Name.ValueString(), data.Description.ValueString(), details)
141+
if err != nil {
142+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create Approval Channel, got error: %s", err))
143+
return
144+
}
145+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
146+
}
147+
148+
func (r *TorqueServiceNowApprovalChannelResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
149+
var data TorqueServiceNowApprovalChannelResourceModel
150+
151+
diags := req.State.Get(ctx, &data)
152+
resp.Diagnostics.Append(diags...)
153+
if resp.Diagnostics.HasError() {
154+
return
155+
}
156+
approval_channel, err := r.client.GetApprovalChannel(data.Name.ValueString())
157+
if err != nil {
158+
resp.Diagnostics.AddError(
159+
"Error Reading Approval Channel details",
160+
"Could not read Approval Channel "+data.Name.ValueString()+": "+err.Error(),
161+
)
162+
return
163+
}
164+
data.Name = types.StringValue(approval_channel.Name)
165+
data.Description = types.StringValue(approval_channel.Description)
166+
data.BaseUrl = types.StringPointerValue(approval_channel.Details.BaseUrl)
167+
168+
data.Headers = types.StringPointerValue(approval_channel.Details.Headers)
169+
data.Approver = types.StringPointerValue(&approval_channel.Details.Approver.UserEmail)
170+
171+
diags = resp.State.Set(ctx, &data)
172+
resp.Diagnostics.Append(diags...)
173+
if resp.Diagnostics.HasError() {
174+
return
175+
}
176+
}
177+
178+
func (r *TorqueServiceNowApprovalChannelResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
179+
var data TorqueServiceNowApprovalChannelResourceModel
180+
var details client.ApprovalChannelDetails
181+
details.Approver = &client.Approver{}
182+
183+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
184+
185+
details.Approver.UserEmail = data.Approver.ValueString()
186+
details.Type = servicenow_approval_channel_type
187+
details.BaseUrl = data.BaseUrl.ValueStringPointer()
188+
details.UserName = data.UserName.ValueStringPointer()
189+
details.Password = data.Password.ValueStringPointer()
190+
details.Headers = data.Headers.ValueStringPointer()
191+
err := r.client.UpdateApprovalChannel(data.Name.ValueString(), data.Description.ValueString(), details)
192+
if err != nil {
193+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update Approval Channel, got error: %s", err))
194+
return
195+
}
196+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
197+
}
198+
199+
func (r *TorqueServiceNowApprovalChannelResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
200+
var data TorqueServiceNowApprovalChannelResourceModel
201+
202+
// Read Terraform prior state data into the model.
203+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
204+
205+
if resp.Diagnostics.HasError() {
206+
return
207+
}
208+
209+
err := r.client.DeleteApprovalChannel(data.Name.ValueString())
210+
if err != nil {
211+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete Approval Channel, got error: %s", err))
212+
return
213+
}
214+
215+
}
216+
217+
func (r *TorqueServiceNowApprovalChannelResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
218+
resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp)
219+
}

0 commit comments

Comments
 (0)