Skip to content

Commit 631c313

Browse files
feat: add datasources for some notification profiles [ENG-5557] (#98)
[ENG-5557](https://stacklet.atlassian.net/browse/ENG-5557) ### what add support for fetching notification profiles for - email - servicenow - symphony Other ones will be added in a followup branch ### why provide access to notifications profiles ### testing testing in sandbox, will add tests once resources are also available ### docs updated here [ENG-5557]: https://stacklet.atlassian.net/browse/ENG-5557?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent 435a868 commit 631c313

File tree

16 files changed

+560
-0
lines changed

16 files changed

+560
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stacklet_configuration_profile_email Data Source - terraform-provider-stacklet"
4+
subcategory: ""
5+
description: |-
6+
Retrieve information about the email configuration profile.
7+
---
8+
9+
# stacklet_configuration_profile_email (Data Source)
10+
11+
Retrieve information about the email configuration profile.
12+
13+
## Example Usage
14+
15+
```terraform
16+
data "stacklet_configuration_profile_email" "example" {}
17+
```
18+
19+
<!-- schema generated by tfplugindocs -->
20+
## Schema
21+
22+
### Read-Only
23+
24+
- `from` (String) The email from field value.
25+
- `id` (String) The GraphQL Node ID of the configuration profile.
26+
- `profile` (String) The profile name.
27+
- `smtp` (Attributes) SMTP configuration. (see [below for nested schema](#nestedatt--smtp))
28+
29+
<a id="nestedatt--smtp"></a>
30+
### Nested Schema for `smtp`
31+
32+
Read-Only:
33+
34+
- `port` (String) SMTP server port.
35+
- `server` (String) SMTP server hostname or IP address.
36+
- `ssl` (Boolean) Whether SSL/TLS is enabled.
37+
- `username` (String) Authentication username.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stacklet_configuration_profile_servicenow Data Source - terraform-provider-stacklet"
4+
subcategory: ""
5+
description: |-
6+
Retrieve information about the ServiceNow configuration profile.
7+
---
8+
9+
# stacklet_configuration_profile_servicenow (Data Source)
10+
11+
Retrieve information about the ServiceNow configuration profile.
12+
13+
## Example Usage
14+
15+
```terraform
16+
data "stacklet_configuration_profile_servicenow" "example" {}
17+
```
18+
19+
<!-- schema generated by tfplugindocs -->
20+
## Schema
21+
22+
### Read-Only
23+
24+
- `closed_state` (String) The state for closed tickets.
25+
- `endpoint` (String) The ServiceNow instance endpoint.
26+
- `id` (String) The GraphQL Node ID of the configuration profile.
27+
- `issue_type` (String) The type of issue to use for tickets.
28+
- `profile` (String) The profile name.
29+
- `username` (String) The ServiceNow instance authentication username.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stacklet_configuration_profile_symphony Data Source - terraform-provider-stacklet"
4+
subcategory: ""
5+
description: |-
6+
Retrieve information about the Symphony configuration profile.
7+
---
8+
9+
# stacklet_configuration_profile_symphony (Data Source)
10+
11+
Retrieve information about the Symphony configuration profile.
12+
13+
## Example Usage
14+
15+
```terraform
16+
data "stacklet_configuration_profile_symphony" "example" {}
17+
```
18+
19+
<!-- schema generated by tfplugindocs -->
20+
## Schema
21+
22+
### Read-Only
23+
24+
- `agent_domain` (String) The Symphony agent domain.
25+
- `id` (String) The GraphQL Node ID of the configuration profile.
26+
- `profile` (String) The profile name.
27+
- `service_account` (String) The Symphony service account.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data "stacklet_configuration_profile_email" "example" {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data "stacklet_configuration_profile_servicenow" "example" {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
data "stacklet_configuration_profile_symphony" "example" {}

internal/api/api.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type API struct {
1414
AccountGroup accountGroupAPI
1515
AccountGroupMapping accountGroupMappingAPI
1616
Binding bindingAPI
17+
ConfigurationProfile configurationProfileAPI
1718
Platform platformAPI
1819
Policy policyAPI
1920
PolicyCollection policyCollectionAPI
@@ -31,6 +32,7 @@ func New(c *graphql.Client) *API {
3132
AccountGroup: accountGroupAPI{c},
3233
AccountGroupMapping: accountGroupMappingAPI{c},
3334
Binding: bindingAPI{c},
35+
ConfigurationProfile: configurationProfileAPI{c},
3436
Platform: platformAPI{c},
3537
Policy: policyAPI{c},
3638
PolicyCollection: policyCollectionAPI{c},
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright (c) 2025 - Stacklet, Inc.
2+
3+
package api
4+
5+
import (
6+
"context"
7+
8+
"github.com/hasura/go-graphql-client"
9+
)
10+
11+
// ConfigurationProfile is the data returned for configuration profiles.
12+
type ConfigurationProfile struct {
13+
ID string
14+
Profile string
15+
Record struct {
16+
TypeName string `graphql:"__typename"`
17+
EmailConfiguration EmailConfiguration `graphql:"... on EmailConfiguration"`
18+
ServiceNowConfiguration ServiceNowConfiguration `graphql:"... on ServiceNowConfiguration"`
19+
SymphonyConfiguration SymphonyConfiguration `graphql:"... on SymphonyConfiguration"`
20+
}
21+
}
22+
23+
// EmailConfiguration is the configuration for email profiles.
24+
type EmailConfiguration struct {
25+
FromEmail string
26+
SesRegion *string
27+
SMTP *SMTPConfiguration `graphql:"smtp"`
28+
}
29+
30+
// SMTPConfiguration is the SMTP server configuration.
31+
type SMTPConfiguration struct {
32+
Server string
33+
Port string
34+
SSL *bool `graphql:"ssl"`
35+
Username *string
36+
}
37+
38+
// ServiceNowConfiguration is the configuration for ServiceNow profiles.
39+
type ServiceNowConfiguration struct {
40+
Endpoint string
41+
User string
42+
Password string
43+
IssueType string
44+
ClosedState string
45+
}
46+
47+
// SymphonyConfiguration is the configuration for Symphony profiles.
48+
type SymphonyConfiguration struct {
49+
AgentDomain string
50+
ServiceAccount string
51+
}
52+
53+
type configurationProfileAPI struct {
54+
c *graphql.Client
55+
}
56+
57+
// Read returns data for a configuration profile.
58+
func (a configurationProfileAPI) Read(ctx context.Context, name ConfigurationProfileName) (*ConfigurationProfile, error) {
59+
var query struct {
60+
Configuration ConfigurationProfile `graphql:"profile(name: $name, scope: $scope)"`
61+
}
62+
variables := map[string]any{
63+
"name": graphql.String(string(name)),
64+
"scope": graphql.String("0"), // always use the global scope
65+
}
66+
if err := a.c.Query(ctx, &query, variables); err != nil {
67+
return nil, NewAPIError(err)
68+
}
69+
70+
if query.Configuration.ID == "" {
71+
return nil, NotFound{"Configuration profile not found"}
72+
}
73+
74+
return &query.Configuration, nil
75+
}

internal/api/enums.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,18 @@ var REPORT_SOURCES = []ReportSource{
3737
ReportSourceControl,
3838
ReportSourcePolicy,
3939
}
40+
41+
// ConfigurationProfileName is the name for a configuration profile.
42+
//
43+
// This is defined as a type since profiles are looked up by names matching
44+
// type.
45+
type ConfigurationProfileName string
46+
47+
const (
48+
ConfigurationProfileEmail = ConfigurationProfileName("email")
49+
ConfigurationProfileSlack = ConfigurationProfileName("slack")
50+
ConfigurationProfileTeams = ConfigurationProfileName("teams")
51+
ConfigurationProfileServiceNow = ConfigurationProfileName("servicenow")
52+
ConfigurationProfileJira = ConfigurationProfileName("jira")
53+
ConfigurationProfileSymphony = ConfigurationProfileName("symphony")
54+
)
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) 2025 - Stacklet, Inc.
2+
3+
package datasources
4+
5+
import (
6+
"context"
7+
8+
"github.com/hashicorp/terraform-plugin-framework/attr"
9+
"github.com/hashicorp/terraform-plugin-framework/datasource"
10+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
11+
"github.com/hashicorp/terraform-plugin-framework/types"
12+
13+
"github.com/stacklet/terraform-provider-stacklet/internal/api"
14+
"github.com/stacklet/terraform-provider-stacklet/internal/errors"
15+
"github.com/stacklet/terraform-provider-stacklet/internal/models"
16+
"github.com/stacklet/terraform-provider-stacklet/internal/providerdata"
17+
)
18+
19+
var (
20+
_ datasource.DataSource = &configurationProfileEmailDataSource{}
21+
)
22+
23+
func NewConfigurationProfileEmailDataSource() datasource.DataSource {
24+
return &configurationProfileEmailDataSource{}
25+
}
26+
27+
type configurationProfileEmailDataSource struct {
28+
api *api.API
29+
}
30+
31+
func (d *configurationProfileEmailDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
32+
resp.TypeName = req.ProviderTypeName + "_configuration_profile_email"
33+
}
34+
35+
func (d *configurationProfileEmailDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
36+
resp.Schema = schema.Schema{
37+
Description: "Retrieve information about the email configuration profile.",
38+
Attributes: map[string]schema.Attribute{
39+
"id": schema.StringAttribute{
40+
Description: "The GraphQL Node ID of the configuration profile.",
41+
Computed: true,
42+
},
43+
"profile": schema.StringAttribute{
44+
Description: "The profile name.",
45+
Computed: true,
46+
},
47+
"from": schema.StringAttribute{
48+
Description: "The email from field value.",
49+
Computed: true,
50+
},
51+
"smtp": schema.SingleNestedAttribute{
52+
Description: "SMTP configuration.",
53+
Computed: true,
54+
Attributes: map[string]schema.Attribute{
55+
"server": schema.StringAttribute{
56+
Description: "SMTP server hostname or IP address.",
57+
Computed: true,
58+
},
59+
"port": schema.StringAttribute{
60+
Description: "SMTP server port.",
61+
Computed: true,
62+
},
63+
"ssl": schema.BoolAttribute{
64+
Description: "Whether SSL/TLS is enabled.",
65+
Computed: true,
66+
},
67+
"username": schema.StringAttribute{
68+
Description: "Authentication username.",
69+
Computed: true,
70+
},
71+
},
72+
},
73+
},
74+
}
75+
}
76+
77+
func (d *configurationProfileEmailDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
78+
if pd, err := providerdata.GetDataSourceProviderData(req); err != nil {
79+
errors.AddDiagError(&resp.Diagnostics, err)
80+
} else if pd != nil {
81+
d.api = pd.API
82+
}
83+
}
84+
85+
func (d *configurationProfileEmailDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
86+
var data models.ConfigurationProfileEmailDataSource
87+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
88+
if resp.Diagnostics.HasError() {
89+
return
90+
}
91+
92+
config, err := d.api.ConfigurationProfile.Read(ctx, api.ConfigurationProfileEmail)
93+
if err != nil {
94+
errors.AddDiagError(&resp.Diagnostics, err)
95+
return
96+
}
97+
98+
data.ID = types.StringValue(config.ID)
99+
data.Profile = types.StringValue(config.Profile)
100+
data.From = types.StringValue(config.Record.EmailConfiguration.FromEmail)
101+
102+
if smtp := config.Record.EmailConfiguration.SMTP; smtp != nil {
103+
smtpAttrs := map[string]attr.Value{
104+
"server": types.StringValue(smtp.Server),
105+
"port": types.StringValue(smtp.Port),
106+
"ssl": types.BoolValue(smtp.SSL != nil && *smtp.SSL),
107+
"username": func() types.String {
108+
if smtp.Username != nil {
109+
return types.StringValue(*smtp.Username)
110+
}
111+
return types.StringNull()
112+
}(),
113+
}
114+
115+
smtpObj, diags := types.ObjectValue(models.SMTP{}.AttributeTypes(), smtpAttrs)
116+
resp.Diagnostics.Append(diags...)
117+
if resp.Diagnostics.HasError() {
118+
return
119+
}
120+
data.SMTP = smtpObj
121+
} else {
122+
data.SMTP = types.ObjectNull(models.SMTP{}.AttributeTypes())
123+
}
124+
125+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
126+
}

0 commit comments

Comments
 (0)