Skip to content

Commit 9d02521

Browse files
feat: add ttl fields for feature store and entitytype (#7164) (#5178)
* feat: add ttl fields for feature store and entitytype * add example * update example to use google-beta provider * try different resource IDs for tests * test: add min_version: beta to new test Signed-off-by: Modular Magician <[email protected]>
1 parent e188411 commit 9d02521

7 files changed

+180
-2
lines changed

.changelog/7164.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
```release-note:enhancement
2+
vertex_ai: added `online_storage_ttl_days` to `google_vertex_ai_featurestore` resource (beta)
3+
```
4+
```release-note:enhancement
5+
vertex_ai: added `offline_storage_ttl_days` to `google_vertex_ai_featurestore_entitytype` resource (beta)
6+
```

google-beta/resource_vertex_ai_featurestore.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ func resourceVertexAIFeaturestore() *schema.Resource {
106106
},
107107
},
108108
},
109+
"online_storage_ttl_days": {
110+
Type: schema.TypeInt,
111+
Optional: true,
112+
Description: `TTL in days for feature values that will be stored in online serving storage. The Feature Store online storage periodically removes obsolete feature values older than onlineStorageTtlDays since the feature generation time. Note that onlineStorageTtlDays should be less than or equal to offlineStorageTtlDays for each EntityType under a featurestore. If not set, default to 4000 days`,
113+
Default: 4000,
114+
},
109115
"region": {
110116
Type: schema.TypeString,
111117
Computed: true,
@@ -165,6 +171,12 @@ func resourceVertexAIFeaturestoreCreate(d *schema.ResourceData, meta interface{}
165171
} else if v, ok := d.GetOkExists("online_serving_config"); !isEmptyValue(reflect.ValueOf(onlineServingConfigProp)) && (ok || !reflect.DeepEqual(v, onlineServingConfigProp)) {
166172
obj["onlineServingConfig"] = onlineServingConfigProp
167173
}
174+
onlineStorageTtlDaysProp, err := expandVertexAIFeaturestoreOnlineStorageTtlDays(d.Get("online_storage_ttl_days"), d, config)
175+
if err != nil {
176+
return err
177+
} else if v, ok := d.GetOkExists("online_storage_ttl_days"); !isEmptyValue(reflect.ValueOf(onlineStorageTtlDaysProp)) && (ok || !reflect.DeepEqual(v, onlineStorageTtlDaysProp)) {
178+
obj["onlineStorageTtlDays"] = onlineStorageTtlDaysProp
179+
}
168180
encryptionSpecProp, err := expandVertexAIFeaturestoreEncryptionSpec(d.Get("encryption_spec"), d, config)
169181
if err != nil {
170182
return err
@@ -280,6 +292,9 @@ func resourceVertexAIFeaturestoreRead(d *schema.ResourceData, meta interface{})
280292
if err := d.Set("online_serving_config", flattenVertexAIFeaturestoreOnlineServingConfig(res["onlineServingConfig"], d, config)); err != nil {
281293
return fmt.Errorf("Error reading Featurestore: %s", err)
282294
}
295+
if err := d.Set("online_storage_ttl_days", flattenVertexAIFeaturestoreOnlineStorageTtlDays(res["onlineStorageTtlDays"], d, config)); err != nil {
296+
return fmt.Errorf("Error reading Featurestore: %s", err)
297+
}
283298
if err := d.Set("encryption_spec", flattenVertexAIFeaturestoreEncryptionSpec(res["encryptionSpec"], d, config)); err != nil {
284299
return fmt.Errorf("Error reading Featurestore: %s", err)
285300
}
@@ -315,6 +330,12 @@ func resourceVertexAIFeaturestoreUpdate(d *schema.ResourceData, meta interface{}
315330
} else if v, ok := d.GetOkExists("online_serving_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, onlineServingConfigProp)) {
316331
obj["onlineServingConfig"] = onlineServingConfigProp
317332
}
333+
onlineStorageTtlDaysProp, err := expandVertexAIFeaturestoreOnlineStorageTtlDays(d.Get("online_storage_ttl_days"), d, config)
334+
if err != nil {
335+
return err
336+
} else if v, ok := d.GetOkExists("online_storage_ttl_days"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, onlineStorageTtlDaysProp)) {
337+
obj["onlineStorageTtlDays"] = onlineStorageTtlDaysProp
338+
}
318339
encryptionSpecProp, err := expandVertexAIFeaturestoreEncryptionSpec(d.Get("encryption_spec"), d, config)
319340
if err != nil {
320341
return err
@@ -338,6 +359,10 @@ func resourceVertexAIFeaturestoreUpdate(d *schema.ResourceData, meta interface{}
338359
updateMask = append(updateMask, "onlineServingConfig")
339360
}
340361

362+
if d.HasChange("online_storage_ttl_days") {
363+
updateMask = append(updateMask, "onlineStorageTtlDays")
364+
}
365+
341366
if d.HasChange("encryption_spec") {
342367
updateMask = append(updateMask, "encryptionSpec")
343368
}
@@ -543,6 +568,23 @@ func flattenVertexAIFeaturestoreOnlineServingConfigScalingMaxNodeCount(v interfa
543568
return v // let terraform core handle it otherwise
544569
}
545570

571+
func flattenVertexAIFeaturestoreOnlineStorageTtlDays(v interface{}, d *schema.ResourceData, config *Config) interface{} {
572+
// Handles the string fixed64 format
573+
if strVal, ok := v.(string); ok {
574+
if intVal, err := stringToFixed64(strVal); err == nil {
575+
return intVal
576+
}
577+
}
578+
579+
// number values are represented as float64
580+
if floatVal, ok := v.(float64); ok {
581+
intVal := int(floatVal)
582+
return intVal
583+
}
584+
585+
return v // let terraform core handle it otherwise
586+
}
587+
546588
func flattenVertexAIFeaturestoreEncryptionSpec(v interface{}, d *schema.ResourceData, config *Config) interface{} {
547589
if v == nil {
548590
return nil
@@ -635,6 +677,10 @@ func expandVertexAIFeaturestoreOnlineServingConfigScalingMaxNodeCount(v interfac
635677
return v, nil
636678
}
637679

680+
func expandVertexAIFeaturestoreOnlineStorageTtlDays(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
681+
return v, nil
682+
}
683+
638684
func expandVertexAIFeaturestoreEncryptionSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
639685
l := v.([]interface{})
640686
if len(l) == 0 || l[0] == nil {

google-beta/resource_vertex_ai_featurestore_entitytype.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ If both FeaturestoreMonitoringConfig.SnapshotAnalysis.monitoring_interval_days a
172172
ForceNew: true,
173173
Description: `The name of the EntityType. This value may be up to 60 characters, and valid characters are [a-z0-9_]. The first character cannot be a number.`,
174174
},
175+
"offline_storage_ttl_days": {
176+
Type: schema.TypeInt,
177+
Optional: true,
178+
Description: `Config for data retention policy in offline storage. TTL in days for feature values that will be stored in offline storage. The Feature Store offline storage periodically removes obsolete feature values older than offlineStorageTtlDays since the feature generation time. If unset (or explicitly set to 0), default to 4000 days TTL.`,
179+
Default: 4000,
180+
},
175181
"create_time": {
176182
Type: schema.TypeString,
177183
Computed: true,
@@ -224,6 +230,12 @@ func resourceVertexAIFeaturestoreEntitytypeCreate(d *schema.ResourceData, meta i
224230
} else if v, ok := d.GetOkExists("monitoring_config"); !isEmptyValue(reflect.ValueOf(monitoringConfigProp)) && (ok || !reflect.DeepEqual(v, monitoringConfigProp)) {
225231
obj["monitoringConfig"] = monitoringConfigProp
226232
}
233+
offlineStorageTtlDaysProp, err := expandVertexAIFeaturestoreEntitytypeOfflineStorageTtlDays(d.Get("offline_storage_ttl_days"), d, config)
234+
if err != nil {
235+
return err
236+
} else if v, ok := d.GetOkExists("offline_storage_ttl_days"); !isEmptyValue(reflect.ValueOf(offlineStorageTtlDaysProp)) && (ok || !reflect.DeepEqual(v, offlineStorageTtlDaysProp)) {
237+
obj["offlineStorageTtlDays"] = offlineStorageTtlDaysProp
238+
}
227239

228240
obj, err = resourceVertexAIFeaturestoreEntitytypeEncoder(d, meta, obj)
229241
if err != nil {
@@ -328,6 +340,9 @@ func resourceVertexAIFeaturestoreEntitytypeRead(d *schema.ResourceData, meta int
328340
if err := d.Set("monitoring_config", flattenVertexAIFeaturestoreEntitytypeMonitoringConfig(res["monitoringConfig"], d, config)); err != nil {
329341
return fmt.Errorf("Error reading FeaturestoreEntitytype: %s", err)
330342
}
343+
if err := d.Set("offline_storage_ttl_days", flattenVertexAIFeaturestoreEntitytypeOfflineStorageTtlDays(res["offlineStorageTtlDays"], d, config)); err != nil {
344+
return fmt.Errorf("Error reading FeaturestoreEntitytype: %s", err)
345+
}
331346

332347
return nil
333348
}
@@ -360,6 +375,12 @@ func resourceVertexAIFeaturestoreEntitytypeUpdate(d *schema.ResourceData, meta i
360375
} else if v, ok := d.GetOkExists("monitoring_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, monitoringConfigProp)) {
361376
obj["monitoringConfig"] = monitoringConfigProp
362377
}
378+
offlineStorageTtlDaysProp, err := expandVertexAIFeaturestoreEntitytypeOfflineStorageTtlDays(d.Get("offline_storage_ttl_days"), d, config)
379+
if err != nil {
380+
return err
381+
} else if v, ok := d.GetOkExists("offline_storage_ttl_days"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, offlineStorageTtlDaysProp)) {
382+
obj["offlineStorageTtlDays"] = offlineStorageTtlDaysProp
383+
}
363384

364385
obj, err = resourceVertexAIFeaturestoreEntitytypeEncoder(d, meta, obj)
365386
if err != nil {
@@ -385,6 +406,10 @@ func resourceVertexAIFeaturestoreEntitytypeUpdate(d *schema.ResourceData, meta i
385406
if d.HasChange("monitoring_config") {
386407
updateMask = append(updateMask, "monitoringConfig")
387408
}
409+
410+
if d.HasChange("offline_storage_ttl_days") {
411+
updateMask = append(updateMask, "offlineStorageTtlDays")
412+
}
388413
// updateMask is a URL parameter but not present in the schema, so replaceVars
389414
// won't set it
390415
url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")})
@@ -635,6 +660,23 @@ func flattenVertexAIFeaturestoreEntitytypeMonitoringConfigCategoricalThresholdCo
635660
return v
636661
}
637662

663+
func flattenVertexAIFeaturestoreEntitytypeOfflineStorageTtlDays(v interface{}, d *schema.ResourceData, config *Config) interface{} {
664+
// Handles the string fixed64 format
665+
if strVal, ok := v.(string); ok {
666+
if intVal, err := stringToFixed64(strVal); err == nil {
667+
return intVal
668+
}
669+
}
670+
671+
// number values are represented as float64
672+
if floatVal, ok := v.(float64); ok {
673+
intVal := int(floatVal)
674+
return intVal
675+
}
676+
677+
return v // let terraform core handle it otherwise
678+
}
679+
638680
func expandVertexAIFeaturestoreEntitytypeDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
639681
return v, nil
640682
}
@@ -826,6 +868,10 @@ func expandVertexAIFeaturestoreEntitytypeMonitoringConfigCategoricalThresholdCon
826868
return v, nil
827869
}
828870

871+
func expandVertexAIFeaturestoreEntitytypeOfflineStorageTtlDays(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
872+
return v, nil
873+
}
874+
829875
func resourceVertexAIFeaturestoreEntitytypeEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
830876
if v, ok := d.GetOk("featurestore"); ok {
831877
re := regexp.MustCompile("projects/(.+)/locations/(.+)/featurestores/(.+)$")

google-beta/resource_vertex_ai_featurestore_entitytype_generated_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ resource "google_vertex_ai_featurestore_entitytype" "entity" {
161161
value = 0.3
162162
}
163163
}
164+
offline_storage_ttl_days = 30
164165
}
165166
`, context)
166167
}

google-beta/resource_vertex_ai_featurestore_generated_test.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,55 @@ resource "google_vertex_ai_featurestore" "featurestore" {
7070
`, context)
7171
}
7272

73+
func TestAccVertexAIFeaturestore_vertexAiFeaturestoreWithBetaFieldsExample(t *testing.T) {
74+
t.Parallel()
75+
76+
context := map[string]interface{}{
77+
"org_id": getTestOrgFromEnv(t),
78+
"billing_account": getTestBillingAccountFromEnv(t),
79+
"kms_key_name": BootstrapKMSKeyInLocation(t, "us-central1").CryptoKey.Name,
80+
"random_suffix": randString(t, 10),
81+
}
82+
83+
vcrTest(t, resource.TestCase{
84+
PreCheck: func() { testAccPreCheck(t) },
85+
Providers: testAccProvidersOiCS,
86+
CheckDestroy: testAccCheckVertexAIFeaturestoreDestroyProducer(t),
87+
Steps: []resource.TestStep{
88+
{
89+
Config: testAccVertexAIFeaturestore_vertexAiFeaturestoreWithBetaFieldsExample(context),
90+
},
91+
{
92+
ResourceName: "google_vertex_ai_featurestore.featurestore",
93+
ImportState: true,
94+
ImportStateVerify: true,
95+
ImportStateVerifyIgnore: []string{"name", "etag", "region", "force_destroy"},
96+
},
97+
},
98+
})
99+
}
100+
101+
func testAccVertexAIFeaturestore_vertexAiFeaturestoreWithBetaFieldsExample(context map[string]interface{}) string {
102+
return Nprintf(`
103+
resource "google_vertex_ai_featurestore" "featurestore" {
104+
provider = google-beta
105+
name = "terraform2%{random_suffix}"
106+
labels = {
107+
foo = "bar"
108+
}
109+
region = "us-central1"
110+
online_serving_config {
111+
fixed_node_count = 2
112+
}
113+
encryption_spec {
114+
kms_key_name = "%{kms_key_name}"
115+
}
116+
online_storage_ttl_days = 30
117+
force_destroy = true
118+
}
119+
`, context)
120+
}
121+
73122
func TestAccVertexAIFeaturestore_vertexAiFeaturestoreScalingExample(t *testing.T) {
74123
t.Parallel()
75124

@@ -101,7 +150,7 @@ func TestAccVertexAIFeaturestore_vertexAiFeaturestoreScalingExample(t *testing.T
101150
func testAccVertexAIFeaturestore_vertexAiFeaturestoreScalingExample(context map[string]interface{}) string {
102151
return Nprintf(`
103152
resource "google_vertex_ai_featurestore" "featurestore" {
104-
name = "terraform%{random_suffix}"
153+
name = "terraform3%{random_suffix}"
105154
labels = {
106155
foo = "bar"
107156
}

website/docs/r/vertex_ai_featurestore.html.markdown

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,33 @@ resource "google_vertex_ai_featurestore" "featurestore" {
4747
force_destroy = true
4848
}
4949
```
50+
## Example Usage - Vertex Ai Featurestore With Beta Fields
51+
52+
53+
```hcl
54+
resource "google_vertex_ai_featurestore" "featurestore" {
55+
provider = google-beta
56+
name = "terraform2"
57+
labels = {
58+
foo = "bar"
59+
}
60+
region = "us-central1"
61+
online_serving_config {
62+
fixed_node_count = 2
63+
}
64+
encryption_spec {
65+
kms_key_name = "kms-name"
66+
}
67+
online_storage_ttl_days = 30
68+
force_destroy = true
69+
}
70+
```
5071
## Example Usage - Vertex Ai Featurestore Scaling
5172

5273

5374
```hcl
5475
resource "google_vertex_ai_featurestore" "featurestore" {
55-
name = "terraform"
76+
name = "terraform3"
5677
labels = {
5778
foo = "bar"
5879
}
@@ -92,6 +113,10 @@ The following arguments are supported:
92113
Config for online serving resources.
93114
Structure is [documented below](#nested_online_serving_config).
94115

116+
* `online_storage_ttl_days` -
117+
(Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html))
118+
TTL in days for feature values that will be stored in online serving storage. The Feature Store online storage periodically removes obsolete feature values older than onlineStorageTtlDays since the feature generation time. Note that onlineStorageTtlDays should be less than or equal to offlineStorageTtlDays for each EntityType under a featurestore. If not set, default to 4000 days
119+
95120
* `encryption_spec` -
96121
(Optional)
97122
If set, both of the online and offline data storage will be secured by this key.

website/docs/r/vertex_ai_featurestore_entitytype.html.markdown

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ resource "google_vertex_ai_featurestore_entitytype" "entity" {
112112
value = 0.3
113113
}
114114
}
115+
offline_storage_ttl_days = 30
115116
}
116117
```
117118

@@ -146,6 +147,10 @@ The following arguments are supported:
146147
If this is populated with [FeaturestoreMonitoringConfig.monitoring_interval] specified, snapshot analysis monitoring is enabled. Otherwise, snapshot analysis monitoring is disabled.
147148
Structure is [documented below](#nested_monitoring_config).
148149

150+
* `offline_storage_ttl_days` -
151+
(Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html))
152+
Config for data retention policy in offline storage. TTL in days for feature values that will be stored in offline storage. The Feature Store offline storage periodically removes obsolete feature values older than offlineStorageTtlDays since the feature generation time. If unset (or explicitly set to 0), default to 4000 days TTL.
153+
149154

150155
<a name="nested_monitoring_config"></a>The `monitoring_config` block supports:
151156

0 commit comments

Comments
 (0)