Skip to content

Commit 173a05d

Browse files
authored
feat: Add plural_observability_webhook and plural_scm_webhook resources (#92)
1 parent 77ba502 commit 173a05d

File tree

10 files changed

+485
-3
lines changed

10 files changed

+485
-3
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "plural_observability_webhook Resource - terraform-provider-plural"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# plural_observability_webhook (Resource)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `name` (String) Human-readable name of this observability webhook.
21+
- `type` (String) Observability webhook type.
22+
23+
### Optional
24+
25+
- `secret` (String) Observability webhook secret.
26+
27+
### Read-Only
28+
29+
- `id` (String) Internal identifier of this observability webhook.
30+
- `url` (String) Observability webhook URL.

docs/resources/scm_webhook.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "plural_scm_webhook Resource - terraform-provider-plural"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# plural_scm_webhook (Resource)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `hmac` (String) Secret token for authenticating this webhook via hmac signature.
21+
- `owner` (String) Owner for this webhook in your SCM, eg. a GitHub org or GitLab group.
22+
- `type` (String) SCM webhook type.
23+
24+
### Read-Only
25+
26+
- `id` (String) Internal identifier of this SCM webhook.
27+
- `name` (String) Human-readable name of this SCM webhook.
28+
- `url` (String) SCM webhook URL.

example/webhooks/main.tf

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
terraform {
2+
required_providers {
3+
plural = {
4+
source = "pluralsh/plural"
5+
version = "0.2.25"
6+
}
7+
}
8+
}
9+
10+
provider "plural" {
11+
use_cli = true
12+
}
13+
14+
resource "plural_scm_webhook" "test" {
15+
type = "GITHUB"
16+
owner = "pluralsh"
17+
hmac = "test"
18+
}
19+
20+
resource "plural_scm_webhook" "duplicate" {
21+
type = "GITHUB"
22+
owner = "pluralsh"
23+
hmac = "test"
24+
}
25+
26+
resource "plural_observability_webhook" "test" {
27+
name = "test"
28+
type = "NEWRELIC"
29+
# secret = "test"
30+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/hashicorp/terraform-plugin-framework-validators v0.17.0
1111
github.com/hashicorp/terraform-plugin-log v0.9.0
1212
github.com/mitchellh/go-homedir v1.1.0
13-
github.com/pluralsh/console/go/client v1.37.0
13+
github.com/pluralsh/console/go/client v1.41.0
1414
github.com/pluralsh/plural-cli v0.12.3
1515
github.com/pluralsh/polly v0.2.0
1616
github.com/samber/lo v1.50.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -651,8 +651,8 @@ github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxu
651651
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
652652
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
653653
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
654-
github.com/pluralsh/console/go/client v1.37.0 h1:lO+WCfmw/p9aYn9zUDirkbRpmWLdT72k7z713XR74CY=
655-
github.com/pluralsh/console/go/client v1.37.0/go.mod h1:rPx6hufc/s17Wzy+7C4ZnA1nmn1JR0m4JeoxAQYj8+4=
654+
github.com/pluralsh/console/go/client v1.41.0 h1:crSRnRx0wQ4TloFmq8Q/tUgv1sRLXiHmp+xbAFCQQlc=
655+
github.com/pluralsh/console/go/client v1.41.0/go.mod h1:8XlMMN3LLAN9JZo69f8X/XN7Qt1+aaKpgTvvQGfSiEU=
656656
github.com/pluralsh/gqlclient v1.12.2 h1:BrEFAASktf4quFw57CIaLAd+NZUTLhG08fe6tnhBQN4=
657657
github.com/pluralsh/gqlclient v1.12.2/go.mod h1:OEjN9L63x8m3A3eQBv5kVkFgiY9fp2aZ0cgOF0uII58=
658658
github.com/pluralsh/plural-cli v0.12.3 h1:hwu8yMZ8YBby+H3XSMLyJbV6XkIv6yrF6M2LfEa/dMA=
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package model
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-framework/types"
5+
console "github.com/pluralsh/console/go/client"
6+
)
7+
8+
type ObservabilityWebhook struct {
9+
Id types.String `tfsdk:"id"`
10+
Name types.String `tfsdk:"name"`
11+
Type types.String `tfsdk:"type"`
12+
URL types.String `tfsdk:"url"`
13+
Secret types.String `tfsdk:"secret"`
14+
}
15+
16+
func (ow *ObservabilityWebhook) From(response *console.ObservabilityWebhookFragment) {
17+
ow.Id = types.StringValue(response.ID)
18+
ow.Name = types.StringValue(response.Name)
19+
ow.Type = types.StringValue(string(response.Type))
20+
ow.URL = types.StringValue(response.URL)
21+
}
22+
23+
func (ow *ObservabilityWebhook) Attributes() console.ObservabilityWebhookAttributes {
24+
return console.ObservabilityWebhookAttributes{
25+
Type: console.ObservabilityWebhookType(ow.Type.ValueString()),
26+
Name: ow.Name.ValueString(),
27+
Secret: ow.Secret.ValueStringPointer(),
28+
}
29+
}

internal/model/scm_webhook.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package model
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-framework/types"
5+
console "github.com/pluralsh/console/go/client"
6+
)
7+
8+
type SCMWebhook struct {
9+
Id types.String `tfsdk:"id"`
10+
Name types.String `tfsdk:"name"`
11+
Owner types.String `tfsdk:"owner"`
12+
Type types.String `tfsdk:"type"`
13+
URL types.String `tfsdk:"url"`
14+
Hmac types.String `tfsdk:"hmac"`
15+
}
16+
17+
func (scmw *SCMWebhook) From(response *console.ScmWebhookFragment) {
18+
scmw.Id = types.StringValue(response.ID)
19+
scmw.Name = types.StringValue(response.Name)
20+
scmw.Owner = types.StringValue(response.Owner)
21+
scmw.Type = types.StringValue(string(response.Type))
22+
scmw.URL = types.StringValue(response.URL)
23+
}
24+
25+
func (scmw *SCMWebhook) Attributes() console.ScmWebhookAttributes {
26+
return console.ScmWebhookAttributes{
27+
Type: console.ScmType(scmw.Type.ValueString()),
28+
Owner: scmw.Owner.ValueString(),
29+
Hmac: scmw.Hmac.ValueString(),
30+
}
31+
}

internal/provider/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ func (p *PluralProvider) Resources(_ context.Context) []func() resource.Resource
196196
r.NewStackRunTriggerResource,
197197
r.NewSharedSecretResource,
198198
r.NewOIDCProviderResourceResource,
199+
r.NewSCMWebhookResource,
200+
r.NewObservabilityWebhookResource,
199201
}
200202
}
201203

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package resource
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"terraform-provider-plural/internal/common"
8+
"terraform-provider-plural/internal/model"
9+
10+
"terraform-provider-plural/internal/client"
11+
12+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
13+
"github.com/hashicorp/terraform-plugin-framework/path"
14+
"github.com/hashicorp/terraform-plugin-framework/resource"
15+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
16+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
17+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
18+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
19+
gqlclient "github.com/pluralsh/console/go/client"
20+
"github.com/pluralsh/polly/algorithms"
21+
)
22+
23+
var _ resource.Resource = &ObservabilityWebhookResource{}
24+
var _ resource.ResourceWithImportState = &ObservabilityWebhookResource{}
25+
26+
func NewObservabilityWebhookResource() resource.Resource {
27+
return &ObservabilityWebhookResource{}
28+
}
29+
30+
// ObservabilityWebhookResource defines the observability webhook resource implementation.
31+
type ObservabilityWebhookResource struct {
32+
client *client.Client
33+
}
34+
35+
func (r *ObservabilityWebhookResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
36+
resp.TypeName = req.ProviderTypeName + "_observability_webhook"
37+
}
38+
39+
func (r *ObservabilityWebhookResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
40+
resp.Schema = schema.Schema{
41+
Attributes: map[string]schema.Attribute{
42+
"id": schema.StringAttribute{
43+
Computed: true,
44+
Description: "Internal identifier of this observability webhook.",
45+
MarkdownDescription: "Internal identifier of this observability webhook.",
46+
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
47+
},
48+
"name": schema.StringAttribute{
49+
Description: "Human-readable name of this observability webhook.",
50+
MarkdownDescription: "Human-readable name of this observability webhook.",
51+
Required: true,
52+
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
53+
},
54+
"type": schema.StringAttribute{
55+
Description: "Observability webhook type.",
56+
MarkdownDescription: "Observability webhook type.",
57+
Required: true,
58+
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
59+
Validators: []validator.String{
60+
stringvalidator.OneOf(
61+
algorithms.Map(gqlclient.AllObservabilityWebhookType,
62+
func(t gqlclient.ObservabilityWebhookType) string { return string(t) })...),
63+
},
64+
},
65+
"url": schema.StringAttribute{
66+
Description: "Observability webhook URL.",
67+
MarkdownDescription: "Observability webhook URL.",
68+
Computed: true,
69+
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
70+
},
71+
"secret": schema.StringAttribute{
72+
Description: "Observability webhook secret.",
73+
MarkdownDescription: "Observability webhook secret.",
74+
Optional: true,
75+
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
76+
},
77+
},
78+
}
79+
}
80+
81+
func (r *ObservabilityWebhookResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
82+
if req.ProviderData == nil {
83+
return
84+
}
85+
86+
data, ok := req.ProviderData.(*common.ProviderData)
87+
if !ok {
88+
resp.Diagnostics.AddError(
89+
"Unexpected Observability Webhook Resource Configure Type",
90+
fmt.Sprintf("Expected *common.ProviderData, got: %T. Please report this issue to the provider developers.", req.ProviderData),
91+
)
92+
93+
return
94+
}
95+
96+
r.client = data.Client
97+
}
98+
99+
func (r *ObservabilityWebhookResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
100+
data := new(model.ObservabilityWebhook)
101+
resp.Diagnostics.Append(req.Plan.Get(ctx, data)...)
102+
if resp.Diagnostics.HasError() {
103+
return
104+
}
105+
106+
sc, err := r.client.UpsertObservabilityWebhook(ctx, data.Attributes())
107+
if err != nil {
108+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create observability webhook, got error: %s", err))
109+
return
110+
}
111+
112+
data.From(sc.UpsertObservabilityWebhook)
113+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
114+
}
115+
116+
func (r *ObservabilityWebhookResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
117+
data := new(model.ObservabilityWebhook)
118+
resp.Diagnostics.Append(req.State.Get(ctx, data)...)
119+
if resp.Diagnostics.HasError() {
120+
return
121+
}
122+
123+
response, err := r.client.GetObservabilityWebhook(ctx, nil, data.Name.ValueStringPointer())
124+
if err != nil {
125+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read observability webhook, got error: %s", err))
126+
return
127+
}
128+
if response.ObservabilityWebhook == nil {
129+
resp.Diagnostics.AddError("Client Error", "Unable to find observability webhook, got no error")
130+
return
131+
}
132+
133+
data.From(response.ObservabilityWebhook)
134+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
135+
}
136+
137+
func (r *ObservabilityWebhookResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
138+
data := new(model.ObservabilityWebhook)
139+
resp.Diagnostics.Append(req.Plan.Get(ctx, data)...)
140+
if resp.Diagnostics.HasError() {
141+
return
142+
}
143+
144+
_, err := r.client.UpsertObservabilityWebhook(ctx, data.Attributes())
145+
if err != nil {
146+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update observability webhook, got error: %s", err))
147+
return
148+
}
149+
150+
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
151+
}
152+
153+
func (r *ObservabilityWebhookResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
154+
data := new(model.ObservabilityWebhook)
155+
resp.Diagnostics.Append(req.State.Get(ctx, data)...)
156+
if resp.Diagnostics.HasError() {
157+
return
158+
}
159+
160+
_, err := r.client.DeleteObservabilityWebhook(ctx, data.Id.ValueString())
161+
if err != nil {
162+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete observability webhook, got error: %s", err))
163+
return
164+
}
165+
}
166+
167+
func (r *ObservabilityWebhookResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
168+
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
169+
}

0 commit comments

Comments
 (0)