Skip to content

Commit a3e38a1

Browse files
authored
🧹 change mondoo_gcs_bucket_export -> mondoo_export_gcs_bucket, deprecate old one (#299)
1 parent 354ed31 commit a3e38a1

File tree

5 files changed

+377
-45
lines changed

5 files changed

+377
-45
lines changed
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package provider
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/hashicorp/terraform-plugin-framework/resource"
11+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
12+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
13+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
14+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
15+
"github.com/hashicorp/terraform-plugin-framework/types"
16+
"github.com/hashicorp/terraform-plugin-log/tflog"
17+
mondoov1 "go.mondoo.com/mondoo-go"
18+
)
19+
20+
// Ensure provider defined types fully satisfy framework interfaces.
21+
var _ resource.Resource = &GcsBucketExportResource{}
22+
23+
func NewExportGSCBucketResource() resource.Resource {
24+
return &GcsBucketExportResource{}
25+
}
26+
27+
type GcsBucketExportResource struct {
28+
client *ExtendedGqlClient
29+
}
30+
31+
type GcsBucketExportResourceModel struct {
32+
// scope
33+
SpaceID types.String `tfsdk:"space_id"`
34+
35+
// integration details
36+
Mrn types.String `tfsdk:"mrn"`
37+
Name types.String `tfsdk:"name"`
38+
BucketName types.String `tfsdk:"bucket_name"`
39+
ExportFormat types.String `tfsdk:"export_format"`
40+
41+
// credentials
42+
Credential gcsBucketExportCredentialModel `tfsdk:"credentials"`
43+
}
44+
45+
type gcsBucketExportCredentialModel struct {
46+
PrivateKey types.String `tfsdk:"private_key"`
47+
}
48+
49+
func (r *GcsBucketExportResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
50+
resp.TypeName = req.ProviderTypeName + "_gcs_bucket_export"
51+
}
52+
53+
func (r *GcsBucketExportResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
54+
resp.Schema = schema.Schema{
55+
DeprecationMessage: "Use `mondoo_export_gcs_bucket` instead.",
56+
MarkdownDescription: `Export data to a Google Cloud Storage bucket.
57+
## Example Usage
58+
` + "```hcl" + `
59+
resource "mondoo_gcs_bucket_export" "test" {
60+
name = "bucket-export-integration"
61+
bucket_name = "my-bucket-name"
62+
space_id = "your-space-id"
63+
export_format = "jsonl"
64+
credentials = {
65+
private_key = base64decode(google_service_account_key.mondoo_integration.private_key)
66+
}
67+
}
68+
` + "```" + `
69+
`,
70+
Attributes: map[string]schema.Attribute{
71+
"space_id": schema.StringAttribute{
72+
MarkdownDescription: "Mondoo space identifier. If there is no space ID, the provider space is used.",
73+
Optional: true,
74+
Computed: true,
75+
PlanModifiers: []planmodifier.String{
76+
stringplanmodifier.UseStateForUnknown(),
77+
},
78+
},
79+
"mrn": schema.StringAttribute{
80+
MarkdownDescription: "Mondoo resource name (MRN) of the integration.",
81+
Computed: true,
82+
PlanModifiers: []planmodifier.String{
83+
stringplanmodifier.UseStateForUnknown(),
84+
},
85+
},
86+
"name": schema.StringAttribute{
87+
MarkdownDescription: "Name of the export integration.",
88+
Required: true,
89+
PlanModifiers: []planmodifier.String{
90+
stringplanmodifier.RequiresReplace(),
91+
},
92+
},
93+
94+
"bucket_name": schema.StringAttribute{
95+
MarkdownDescription: "Name of the Google Cloud Storage bucket to export data to.",
96+
Required: true,
97+
PlanModifiers: []planmodifier.String{
98+
stringplanmodifier.RequiresReplace(),
99+
},
100+
},
101+
"export_format": schema.StringAttribute{
102+
MarkdownDescription: "Format of the export (JSONL or CSV), defaults to JSONL.",
103+
Optional: true,
104+
Default: stringdefault.StaticString("jsonl"),
105+
Computed: true,
106+
PlanModifiers: []planmodifier.String{
107+
stringplanmodifier.RequiresReplace(),
108+
},
109+
},
110+
"credentials": schema.SingleNestedAttribute{
111+
MarkdownDescription: "Credentials for the Google Cloud Storage bucket.",
112+
Required: true,
113+
Attributes: map[string]schema.Attribute{
114+
"private_key": schema.StringAttribute{
115+
MarkdownDescription: "Private key for the service account in JSON format.",
116+
Required: true,
117+
Sensitive: true,
118+
},
119+
},
120+
},
121+
},
122+
}
123+
}
124+
125+
func (r *GcsBucketExportResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
126+
// Prevent panic if the provider has not been configured.
127+
if req.ProviderData == nil {
128+
return
129+
}
130+
131+
client, ok := req.ProviderData.(*ExtendedGqlClient)
132+
133+
if !ok {
134+
resp.Diagnostics.AddError(
135+
"Unexpected Resource Configure Type",
136+
fmt.Sprintf("Expected *http.Client. Got: %T. Please report this issue to the provider developers.", req.ProviderData),
137+
)
138+
139+
return
140+
}
141+
142+
r.client = client
143+
}
144+
145+
func (r *GcsBucketExportResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
146+
var data GcsBucketExportResourceModel
147+
148+
// Read the plan data into the model
149+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
150+
if resp.Diagnostics.HasError() {
151+
return
152+
}
153+
// Compute and validate the space
154+
space, err := r.client.ComputeSpace(data.SpaceID)
155+
if err != nil {
156+
resp.Diagnostics.AddError("Invalid Configuration", err.Error())
157+
return
158+
}
159+
ctx = tflog.SetField(ctx, "space_mrn", space.MRN())
160+
161+
// Create the export integration using the client
162+
integration, err := r.client.CreateIntegration(ctx,
163+
space.MRN(),
164+
data.Name.ValueString(),
165+
mondoov1.ClientIntegrationTypeGcsBucket,
166+
mondoov1.ClientIntegrationConfigurationInput{
167+
GcsBucketConfigurationOptions: &mondoov1.GcsBucketConfigurationOptionsInput{
168+
Output: mondoov1.BucketOutputTypeJsonl,
169+
Bucket: mondoov1.String(data.BucketName.ValueString()),
170+
ServiceAccount: mondoov1.String(data.Credential.PrivateKey.ValueString()),
171+
},
172+
})
173+
174+
if err != nil {
175+
resp.Diagnostics.AddError("Error creating GCS bucket export integration", err.Error())
176+
return
177+
}
178+
_, err = r.client.TriggerAction(ctx, string(integration.Mrn), mondoov1.ActionTypeRunExport)
179+
if err != nil {
180+
resp.Diagnostics.
181+
AddWarning("Client Error",
182+
fmt.Sprintf("Unable to trigger export for integration. Got error: %s", err),
183+
)
184+
return
185+
}
186+
187+
// Save space mrn into the Terraform state.
188+
data.Mrn = types.StringValue(string(integration.Mrn))
189+
data.Name = types.StringValue(string(integration.Name))
190+
data.SpaceID = types.StringValue(space.ID())
191+
192+
// Save data into Terraform state
193+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
194+
}
195+
196+
func (r *GcsBucketExportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
197+
var data GcsBucketExportResourceModel
198+
199+
// Read Terraform prior state data into the model
200+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
201+
202+
if resp.Diagnostics.HasError() {
203+
return
204+
}
205+
206+
// Read API call logic
207+
208+
// Save updated data into Terraform state
209+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
210+
}
211+
212+
func (r *GcsBucketExportResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
213+
var data GcsBucketExportResourceModel
214+
215+
// Read Terraform plan data into the model
216+
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
217+
if resp.Diagnostics.HasError() {
218+
return
219+
}
220+
221+
// Compute and validate the space
222+
space, err := r.client.ComputeSpace(data.SpaceID)
223+
if err != nil {
224+
resp.Diagnostics.AddError("Invalid Configuration", err.Error())
225+
return
226+
}
227+
ctx = tflog.SetField(ctx, "space_mrn", space.MRN())
228+
229+
// Do GraphQL request to API to update the resource.
230+
_, err = r.client.UpdateIntegration(ctx,
231+
data.Mrn.ValueString(),
232+
data.Name.ValueString(),
233+
mondoov1.ClientIntegrationTypeGcsBucket,
234+
mondoov1.ClientIntegrationConfigurationInput{
235+
GcsBucketConfigurationOptions: &mondoov1.GcsBucketConfigurationOptionsInput{
236+
Output: mondoov1.BucketOutputTypeJsonl,
237+
Bucket: mondoov1.String(data.BucketName.ValueString()),
238+
ServiceAccount: mondoov1.String(data.Credential.PrivateKey.ValueString()),
239+
},
240+
})
241+
242+
if err != nil {
243+
resp.Diagnostics.AddError("Error updating GCS bucket export integration", err.Error())
244+
return
245+
}
246+
247+
// Save updated data into Terraform state
248+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
249+
}
250+
251+
func (r *GcsBucketExportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
252+
var data GcsBucketExportResourceModel
253+
254+
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
255+
if resp.Diagnostics.HasError() {
256+
return
257+
}
258+
// Delete the integration using the client
259+
_, err := r.client.DeleteIntegration(ctx, data.Mrn.ValueString())
260+
if err != nil {
261+
resp.Diagnostics.AddError("Error deleting GCS bucket export integration", err.Error())
262+
return
263+
}
264+
}
265+
266+
func (r *GcsBucketExportResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
267+
integration, ok := r.client.ImportIntegration(ctx, req, resp)
268+
if !ok {
269+
return
270+
}
271+
272+
model := GcsBucketExportResourceModel{
273+
Mrn: types.StringValue(integration.Mrn),
274+
Name: types.StringValue(integration.Name),
275+
SpaceID: types.StringValue(integration.SpaceID()),
276+
BucketName: types.StringValue(integration.ConfigurationOptions.GcsBucketConfigurationOptions.Bucket),
277+
ExportFormat: types.StringValue(integration.ConfigurationOptions.GcsBucketConfigurationOptions.Output),
278+
279+
Credential: gcsBucketExportCredentialModel{
280+
PrivateKey: types.StringPointerValue(nil),
281+
},
282+
}
283+
284+
resp.State.Set(ctx, &model)
285+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package provider
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-testing/terraform"
12+
)
13+
14+
func TestAccExportResource(t *testing.T) {
15+
resource.Test(t, resource.TestCase{
16+
PreCheck: func() { testAccPreCheck(t) },
17+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
18+
Steps: []resource.TestStep{
19+
// Create and Read testing
20+
{
21+
Config: testGCSExportIntegration("bucket-export-integration", "my-bucket-name", accSpace.ID(), "CSV", "ServiceAccount_1"),
22+
Check: resource.ComposeAggregateTestCheckFunc(
23+
resource.TestCheckResourceAttr("mondoo_gcs_bucket_export.test", "name", "bucket-export-integration"),
24+
resource.TestCheckResourceAttr("mondoo_gcs_bucket_export.test", "bucket_name", "my-bucket-name"),
25+
resource.TestCheckResourceAttr("mondoo_gcs_bucket_export.test", "space_id", accSpace.ID()),
26+
),
27+
},
28+
// Update and Read testing
29+
{
30+
Config: testGCSExportIntegration("bucket-export-integration-updated", "my-bucket-name-updated", accSpace.ID(), "JSONL", "ServiceAccount_2"),
31+
Check: resource.ComposeAggregateTestCheckFunc(
32+
resource.TestCheckResourceAttr("mondoo_gcs_bucket_export.test", "name", "bucket-export-integration-updated"),
33+
resource.TestCheckResourceAttr("mondoo_gcs_bucket_export.test", "bucket_name", "my-bucket-name-updated"),
34+
resource.TestCheckResourceAttr("mondoo_gcs_bucket_export.test", "space_id", accSpace.ID()),
35+
),
36+
},
37+
// import testing
38+
{
39+
ResourceName: "mondoo_gcs_bucket_export.test",
40+
// setting the next two attributes allows the import to work in test, bc we use mrn instead of id
41+
ImportStateIdFunc: func(s *terraform.State) (string, error) {
42+
return s.RootModule().Resources["mondoo_gcs_bucket_export.test"].Primary.Attributes["mrn"], nil
43+
},
44+
ImportStateVerifyIdentifierAttribute: "mrn",
45+
ImportState: true,
46+
ImportStateVerify: true,
47+
ImportStateVerifyIgnore: []string{"credentials"},
48+
},
49+
},
50+
})
51+
}
52+
53+
func testGCSExportIntegration(name string, bucketName string, spaceId string, output string, serviceAccount string) string {
54+
return fmt.Sprintf(`
55+
resource "mondoo_gcs_bucket_export" "test" {
56+
name = "%s"
57+
bucket_name = "%s"
58+
space_id = "%s"
59+
export_format = "%s"
60+
credentials = {
61+
private_key = "%s"
62+
}
63+
}
64+
`, name, bucketName, spaceId, output, serviceAccount)
65+
}

0 commit comments

Comments
 (0)