Skip to content

Commit 7e2716a

Browse files
Adding KMS CMEK support for Dialogflow (#14206) (#23335)
[upstream:9ffb46b73330db0327937df09e14272ddc032f40] Signed-off-by: Modular Magician <[email protected]>
1 parent dd12aaa commit 7e2716a

7 files changed

+530
-2
lines changed

.changelog/14206.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-resource
2+
`google_dialogflow_encryption_spec`
3+
```

google/provider/provider_mmv1_resources.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,9 +542,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{
542542
}
543543

544544
// Resources
545-
// Generated resources: 620
545+
// Generated resources: 621
546546
// Generated IAM resources: 309
547-
// Total generated resources: 929
547+
// Total generated resources: 930
548548
var generatedResources = map[string]*schema.Resource{
549549
"google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(),
550550
"google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(),
@@ -987,6 +987,7 @@ var generatedResources = map[string]*schema.Resource{
987987
"google_developer_connect_connection": developerconnect.ResourceDeveloperConnectConnection(),
988988
"google_developer_connect_git_repository_link": developerconnect.ResourceDeveloperConnectGitRepositoryLink(),
989989
"google_dialogflow_agent": dialogflow.ResourceDialogflowAgent(),
990+
"google_dialogflow_encryption_spec": dialogflow.ResourceDialogflowEncryptionSpec(),
990991
"google_dialogflow_entity_type": dialogflow.ResourceDialogflowEntityType(),
991992
"google_dialogflow_fulfillment": dialogflow.ResourceDialogflowFulfillment(),
992993
"google_dialogflow_intent": dialogflow.ResourceDialogflowIntent(),
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
// ----------------------------------------------------------------------------
4+
//
5+
// *** AUTO GENERATED CODE *** Type: Handwritten ***
6+
//
7+
// ----------------------------------------------------------------------------
8+
//
9+
// This code is generated by Magic Modules using the following:
10+
//
11+
// Source file: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/third_party/terraform/services/dialogflow/dialogflow_operation.go
12+
//
13+
// DO NOT EDIT this file directly. Any changes made to this file will be
14+
// overwritten during the next generation cycle.
15+
//
16+
// ----------------------------------------------------------------------------
17+
package dialogflow
18+
19+
import (
20+
"encoding/json"
21+
"errors"
22+
"fmt"
23+
"regexp"
24+
"time"
25+
26+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
27+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
28+
)
29+
30+
type DialogflowOperationWaiter struct {
31+
Config *transport_tpg.Config
32+
UserAgent string
33+
Project string
34+
tpgresource.CommonOperationWaiter
35+
}
36+
37+
func (w *DialogflowOperationWaiter) QueryOp() (interface{}, error) {
38+
if w == nil {
39+
return nil, fmt.Errorf("Cannot query operation, it's unset or nil.")
40+
}
41+
// Returns the proper get.
42+
location := ""
43+
if parts := regexp.MustCompile(`locations\/([^\/]*)\/`).FindStringSubmatch(w.CommonOperationWaiter.Op.Name); parts != nil {
44+
location = parts[1]
45+
} else {
46+
return nil, fmt.Errorf(
47+
"Saw %s when the op name is expected to contains location %s",
48+
w.CommonOperationWaiter.Op.Name,
49+
"projects/{{project}}/locations/{{location}}/...",
50+
)
51+
}
52+
53+
url := fmt.Sprintf("https://%s-dialogflow.googleapis.com/v2/%s", location, w.CommonOperationWaiter.Op.Name)
54+
55+
return transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
56+
Config: w.Config,
57+
Method: "GET",
58+
Project: w.Project,
59+
RawURL: url,
60+
UserAgent: w.UserAgent,
61+
})
62+
}
63+
64+
func createDialogflowWaiter(config *transport_tpg.Config, op map[string]interface{}, project, activity, userAgent string) (*DialogflowOperationWaiter, error) {
65+
w := &DialogflowOperationWaiter{
66+
Config: config,
67+
UserAgent: userAgent,
68+
Project: project,
69+
}
70+
if err := w.CommonOperationWaiter.SetOp(op); err != nil {
71+
return nil, err
72+
}
73+
return w, nil
74+
}
75+
76+
// nolint: deadcode,unused
77+
func DialogflowOperationWaitTimeWithResponse(config *transport_tpg.Config, op map[string]interface{}, response *map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error {
78+
w, err := createDialogflowWaiter(config, op, project, activity, userAgent)
79+
if err != nil {
80+
return err
81+
}
82+
if err := tpgresource.OperationWait(w, activity, timeout, config.PollInterval); err != nil {
83+
return err
84+
}
85+
rawResponse := []byte(w.CommonOperationWaiter.Op.Response)
86+
if len(rawResponse) == 0 {
87+
return errors.New("`resource` not set in operation response")
88+
}
89+
return json.Unmarshal(rawResponse, response)
90+
}
91+
92+
func DialogflowOperationWaitTime(config *transport_tpg.Config, op map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error {
93+
if val, ok := op["name"]; !ok || val == "" {
94+
// This was a synchronous call - there is no operation to wait for.
95+
return nil
96+
}
97+
w, err := createDialogflowWaiter(config, op, project, activity, userAgent)
98+
if err != nil {
99+
// If w is nil, the op was synchronous.
100+
return err
101+
}
102+
return tpgresource.OperationWait(w, activity, timeout, config.PollInterval)
103+
}
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// ----------------------------------------------------------------------------
5+
//
6+
// *** AUTO GENERATED CODE *** Type: MMv1 ***
7+
//
8+
// ----------------------------------------------------------------------------
9+
//
10+
// This code is generated by Magic Modules using the following:
11+
//
12+
// Configuration: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/dialogflow/EncryptionSpec.yaml
13+
// Template: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/resource.go.tmpl
14+
//
15+
// DO NOT EDIT this file directly. Any changes made to this file will be
16+
// overwritten during the next generation cycle.
17+
//
18+
// ----------------------------------------------------------------------------
19+
20+
package dialogflow
21+
22+
import (
23+
"fmt"
24+
"log"
25+
"net/http"
26+
"reflect"
27+
"strings"
28+
"time"
29+
30+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
31+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
32+
33+
"github.com/hashicorp/terraform-provider-google/google/tpgresource"
34+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
35+
)
36+
37+
func ResourceDialogflowEncryptionSpec() *schema.Resource {
38+
return &schema.Resource{
39+
Create: resourceDialogflowEncryptionSpecCreate,
40+
Read: resourceDialogflowEncryptionSpecRead,
41+
Delete: resourceDialogflowEncryptionSpecDelete,
42+
43+
Timeouts: &schema.ResourceTimeout{
44+
Create: schema.DefaultTimeout(20 * time.Minute),
45+
Delete: schema.DefaultTimeout(20 * time.Minute),
46+
},
47+
48+
CustomizeDiff: customdiff.All(
49+
tpgresource.DefaultProviderProject,
50+
),
51+
52+
Schema: map[string]*schema.Schema{
53+
"encryption_spec": {
54+
Type: schema.TypeList,
55+
Required: true,
56+
ForceNew: true,
57+
Description: `A nested object resource.`,
58+
MaxItems: 1,
59+
Elem: &schema.Resource{
60+
Schema: map[string]*schema.Schema{
61+
"kms_key": {
62+
Type: schema.TypeString,
63+
Required: true,
64+
ForceNew: true,
65+
Description: `The name of customer-managed encryption key that is used to secure a resource and its sub-resources.
66+
If empty, the resource is secured by the default Google encryption key.
67+
Only the key in the same location as this resource is allowed to be used for encryption.
68+
Format: projects/{project}/locations/{location}/keyRings/{keyRing}/cryptoKeys/{key}`,
69+
},
70+
},
71+
},
72+
},
73+
"location": {
74+
Type: schema.TypeString,
75+
Required: true,
76+
ForceNew: true,
77+
Description: `The location in which the encryptionSpec is to be initialized.`,
78+
},
79+
"project": {
80+
Type: schema.TypeString,
81+
Optional: true,
82+
Computed: true,
83+
ForceNew: true,
84+
},
85+
},
86+
UseJSONNumber: true,
87+
}
88+
}
89+
90+
func resourceDialogflowEncryptionSpecCreate(d *schema.ResourceData, meta interface{}) error {
91+
config := meta.(*transport_tpg.Config)
92+
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
93+
if err != nil {
94+
return err
95+
}
96+
97+
obj := make(map[string]interface{})
98+
encryptionSpecProp, err := expandDialogflowEncryptionSpecEncryptionSpec(d.Get("encryption_spec"), d, config)
99+
if err != nil {
100+
return err
101+
} else if v, ok := d.GetOkExists("encryption_spec"); !tpgresource.IsEmptyValue(reflect.ValueOf(encryptionSpecProp)) && (ok || !reflect.DeepEqual(v, encryptionSpecProp)) {
102+
obj["encryptionSpec"] = encryptionSpecProp
103+
}
104+
locationProp, err := expandDialogflowEncryptionSpecLocation(d.Get("location"), d, config)
105+
if err != nil {
106+
return err
107+
} else if v, ok := d.GetOkExists("location"); !tpgresource.IsEmptyValue(reflect.ValueOf(locationProp)) && (ok || !reflect.DeepEqual(v, locationProp)) {
108+
obj["location"] = locationProp
109+
}
110+
111+
url, err := tpgresource.ReplaceVars(d, config, "{{DialogflowBasePath}}projects/{{project}}/locations/{{location}}/encryptionSpec:initialize")
112+
if err != nil {
113+
return err
114+
}
115+
116+
log.Printf("[DEBUG] Creating new EncryptionSpec: %#v", obj)
117+
billingProject := ""
118+
119+
project, err := tpgresource.GetProject(d, config)
120+
if err != nil {
121+
return fmt.Errorf("Error fetching project for EncryptionSpec: %s", err)
122+
}
123+
billingProject = project
124+
125+
// err == nil indicates that the billing_project value was found
126+
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
127+
billingProject = bp
128+
}
129+
130+
headers := make(http.Header)
131+
location := d.Get("location").(string)
132+
133+
// insert location into url for a different endpoint.
134+
if strings.HasPrefix(url, "https://dialogflow.googleapis.com/v2/") {
135+
url = strings.Replace(url, "https://dialogflow", fmt.Sprintf("https://%s-dialogflow", location), 1)
136+
}
137+
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
138+
Config: config,
139+
Method: "POST",
140+
Project: billingProject,
141+
RawURL: url,
142+
UserAgent: userAgent,
143+
Body: obj,
144+
Timeout: d.Timeout(schema.TimeoutCreate),
145+
Headers: headers,
146+
})
147+
if err != nil {
148+
return fmt.Errorf("Error creating EncryptionSpec: %s", err)
149+
}
150+
151+
// Store the ID now
152+
id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/encryptionSpec/{{name}}")
153+
if err != nil {
154+
return fmt.Errorf("Error constructing id: %s", err)
155+
}
156+
d.SetId(id)
157+
158+
err = DialogflowOperationWaitTime(
159+
config, res, project, "Creating EncryptionSpec", userAgent,
160+
d.Timeout(schema.TimeoutCreate))
161+
162+
if err != nil {
163+
// The resource didn't actually create
164+
d.SetId("")
165+
return fmt.Errorf("Error waiting to create EncryptionSpec: %s", err)
166+
}
167+
168+
log.Printf("[DEBUG] Finished creating EncryptionSpec %q: %#v", d.Id(), res)
169+
170+
return resourceDialogflowEncryptionSpecRead(d, meta)
171+
}
172+
173+
func resourceDialogflowEncryptionSpecRead(d *schema.ResourceData, meta interface{}) error {
174+
// This resource could not be read from the API.
175+
return nil
176+
}
177+
178+
func resourceDialogflowEncryptionSpecDelete(d *schema.ResourceData, meta interface{}) error {
179+
log.Printf("[WARNING] Dialogflow EncryptionSpec resources"+
180+
" cannot be deleted from Google Cloud. The resource %s will be removed from Terraform"+
181+
" state, but will still be present on Google Cloud.", d.Id())
182+
d.SetId("")
183+
184+
return nil
185+
}
186+
187+
func flattenDialogflowEncryptionSpecEncryptionSpec(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
188+
if v == nil {
189+
return nil
190+
}
191+
original := v.(map[string]interface{})
192+
if len(original) == 0 {
193+
return nil
194+
}
195+
transformed := make(map[string]interface{})
196+
transformed["kms_key"] =
197+
flattenDialogflowEncryptionSpecEncryptionSpecKmsKey(original["kmsKey"], d, config)
198+
return []interface{}{transformed}
199+
}
200+
func flattenDialogflowEncryptionSpecEncryptionSpecKmsKey(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
201+
return v
202+
}
203+
204+
func expandDialogflowEncryptionSpecEncryptionSpec(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
205+
l := v.([]interface{})
206+
if len(l) == 0 || l[0] == nil {
207+
return nil, nil
208+
}
209+
raw := l[0]
210+
original := raw.(map[string]interface{})
211+
transformed := make(map[string]interface{})
212+
213+
transformedKmsKey, err := expandDialogflowEncryptionSpecEncryptionSpecKmsKey(original["kms_key"], d, config)
214+
if err != nil {
215+
return nil, err
216+
} else if val := reflect.ValueOf(transformedKmsKey); val.IsValid() && !tpgresource.IsEmptyValue(val) {
217+
transformed["kmsKey"] = transformedKmsKey
218+
}
219+
220+
return transformed, nil
221+
}
222+
223+
func expandDialogflowEncryptionSpecEncryptionSpecKmsKey(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
224+
return v, nil
225+
}
226+
227+
func expandDialogflowEncryptionSpecLocation(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
228+
return v, nil
229+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
resource: 'google_dialogflow_encryption_spec'
2+
generation_type: 'mmv1'
3+
source_file: 'products/dialogflow/EncryptionSpec.yaml'
4+
api_service_name: 'dialogflow.googleapis.com'
5+
api_version: 'v2'
6+
api_resource_type_kind: 'EncryptionSpec'
7+
fields:
8+
- field: 'encryption_spec.kms_key'
9+
- field: 'location'
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
// ----------------------------------------------------------------------------
5+
//
6+
// *** AUTO GENERATED CODE *** Type: MMv1 ***
7+
//
8+
// ----------------------------------------------------------------------------
9+
//
10+
// This file is automatically generated by Magic Modules and manual
11+
// changes will be clobbered when the file is regenerated.
12+
//
13+
// Please read more about how to change this file in
14+
// .github/CONTRIBUTING.md.
15+
//
16+
// ----------------------------------------------------------------------------
17+
18+
package dialogflow_test

0 commit comments

Comments
 (0)