Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Vertex AI Featurestores #4906

Merged
merged 8 commits into from
Jul 9, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions mmv1/api/async.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class OpAsync < Async
attr_reader :result
attr_reader :status
attr_reader :error
# If true, include project as an argument to OperationWaitTime.
upodroid marked this conversation as resolved.
Show resolved Hide resolved
# It is intended for resources that calculate project/region from a selflink field
attr_reader :include_project

# The list of methods where operations are used.
attr_reader :actions
Expand All @@ -78,6 +81,7 @@ def validate
check :status, type: Status, required: true
check :error, type: Error, required: true
check :actions, default: %w[create delete update], type: ::Array, item_type: ::String
check :include_project, type: :boolean, default: false
end

# The main implementation of Operation,
Expand Down
171 changes: 168 additions & 3 deletions mmv1/products/vertexai/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ objects:
name: 'createTime'
output: true
description: |
The timestamp of when the workflow was created in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
The timestamp of when the dataset was created in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
- !ruby/object:Api::Type::String
name: 'updateTime'
output: true
description: |
The timestamp of when the workflow was last updated in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
The timestamp of when the dataset was last updated in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
- !ruby/object:Api::Type::KeyValuePairs
name: 'labels'
description: |
Expand All @@ -102,4 +102,169 @@ objects:
required: true
input: true
description: |
Points to a YAML file stored on Google Cloud Storage describing additional information about the Dataset. The schema is defined as an OpenAPI 3.0.2 Schema Object. The schema files that can be used here are found in gs://google-cloud-aiplatform/schema/dataset/metadata/.
Points to a YAML file stored on Google Cloud Storage describing additional information about the Dataset. The schema is defined as an OpenAPI 3.0.2 Schema Object. The schema files that can be used here are found in gs://google-cloud-aiplatform/schema/dataset/metadata/.
# Vertex AI Featurestores
- !ruby/object:Api::Resource
name: Featurestore
base_url: projects/{{project}}/locations/{{region}}/featurestores
create_url: projects/{{project}}/locations/{{region}}/featurestores?featurestoreId={{name}}
self_link: 'projects/{{project}}/locations/{{region}}/featurestores/{{name}}'
min_version: beta
update_verb: :PATCH
update_mask: true
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Official Documentation':
'https://cloud.google.com/vertex-ai/docs'
api: 'https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.featurestores'
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::OpAsync::Result
path: 'response'
resource_inside_response: true
status: !ruby/object:Api::OpAsync::Status
path: 'done'
complete: True
allowed:
- True
- False
error: !ruby/object:Api::OpAsync::Error
path: 'error'
message: 'message'
description: |-
A collection of DataItems and Annotations on them.
parameters:
- !ruby/object:Api::Type::String
name: region
description: The region of the dataset. eg us-central1
url_param_only: true
input: true
properties:
- !ruby/object:Api::Type::String
name: 'name'
description: The name of the Featurestore. This value may be up to 60 characters, and valid characters are [a-z0-9_]. The first character cannot be a number.
input: true
url_param_only: true
pattern: projects/{{project}}/locations/{{region}}/featurestores/{{name}}
- !ruby/object:Api::Type::String
name: 'etag'
description: Used to perform consistent read-modify-write updates.
output: true
- !ruby/object:Api::Type::String
name: 'createTime'
output: true
description: |
The timestamp of when the featurestore was created in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
- !ruby/object:Api::Type::String
name: 'updateTime'
output: true
description: |
The timestamp of when the featurestore was last updated in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
- !ruby/object:Api::Type::KeyValuePairs
name: 'labels'
description: |
A set of key/value label pairs to assign to this Featurestore.
- !ruby/object:Api::Type::NestedObject
name: 'onlineServingConfig'
description: |
Config for online serving resources.
properties:
- !ruby/object:Api::Type::Integer
name: 'fixedNodeCount'
required: true
description: |
The number of nodes for each cluster. The number of nodes will not scale automatically but can be scaled manually by providing different values when updating.
# Vertex AI Featurestore Entity Type
- !ruby/object:Api::Resource
name: FeaturestoreEntitytype
base_url: '{{featurestore}}/entityTypes'
create_url: '{{featurestore}}/entityTypes?entityTypeId={{name}}'
self_link: '{{featurestore}}/entityTypes/{{name}}'
min_version: beta
update_verb: :PATCH
update_mask: true
references: !ruby/object:Api::Resource::ReferenceLinks
guides:
'Official Documentation':
'https://cloud.google.com/vertex-ai/docs'
api: 'https://cloud.google.com/vertex-ai/docs/reference/rest/v1beta1/projects.locations.featurestores.entityTypes'
async: !ruby/object:Api::OpAsync
operation: !ruby/object:Api::OpAsync::Operation
path: 'name'
base_url: '{{op_id}}'
wait_ms: 1000
result: !ruby/object:Api::OpAsync::Result
path: 'response'
resource_inside_response: true
status: !ruby/object:Api::OpAsync::Status
path: 'done'
complete: True
allowed:
- True
- False
error: !ruby/object:Api::OpAsync::Error
path: 'error'
message: 'message'
include_project: true
description: |-
An entity type is a type of object in a system that needs to be modeled and have stored information about. For example, driver is an entity type, and driver0 is an instance of an entity type driver.
parameters:
- !ruby/object:Api::Type::String
name: featurestore
description: The name of the Featurestore to use, in the format projects/{project}/locations/{location}/featurestores/{featurestore}.
url_param_only: true
input: true
required: true
properties:
- !ruby/object:Api::Type::String
name: 'name'
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.
input: true
url_param_only: true
pattern: '{featurestore}}/entityTypes/{{name}}'
- !ruby/object:Api::Type::String
name: 'etag'
description: Used to perform consistent read-modify-write updates.
output: true
- !ruby/object:Api::Type::String
name: 'createTime'
output: true
description: |
The timestamp of when the featurestore was created in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
- !ruby/object:Api::Type::String
name: 'updateTime'
output: true
description: |
The timestamp of when the featurestore was last updated in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits.
- !ruby/object:Api::Type::KeyValuePairs
name: 'labels'
description: |
A set of key/value label pairs to assign to this EntityType.
- !ruby/object:Api::Type::NestedObject
name: 'monitoringConfig'
description: |
The default monitoring configuration for all Features under this EntityType.

If this is populated with [FeaturestoreMonitoringConfig.monitoring_interval] specified, snapshot analysis monitoring is enabled. Otherwise, snapshot analysis monitoring is disabled.
properties:
- !ruby/object:Api::Type::NestedObject
name: 'snapshotAnalysis'
description: |
Configuration of how features in Featurestore are monitored.
properties:
- !ruby/object:Api::Type::Boolean
name: 'disabled'
default_value: false
description: |
The monitoring schedule for snapshot analysis. For EntityType-level config: unset / disabled = true indicates disabled by default for Features under it; otherwise by default enable snapshot analysis monitoring with monitoringInterval for Features under it.
- !ruby/object:Api::Type::String
name: 'monitoringInterval'
description: |
Configuration of the snapshot analysis based monitoring pipeline running interval. The value is rolled up to full day.

A duration in seconds with up to nine fractional digits, terminated by 's'. Example: "3.5s".


51 changes: 50 additions & 1 deletion mmv1/products/vertexai/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,56 @@ overrides: !ruby/object:Overrides::ResourceOverrides
default_from_api: true
region: !ruby/object:Overrides::Terraform::PropertyOverride
default_from_api: true

Featurestore: !ruby/object:Overrides::Terraform::ResourceOverride
autogen_async: false
skip_sweeper: true
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 6
update_minutes: 6
delete_minutes: 10
examples:
- !ruby/object:Provider::Terraform::Examples
name: "vertex_ai_featurestore"
primary_resource_id: "dataset"
vars:
name: "terraform"
properties:
region: !ruby/object:Overrides::Terraform::PropertyOverride
default_from_api: true
etag: !ruby/object:Overrides::Terraform::PropertyOverride
ignore_read: true
name: !ruby/object:Overrides::Terraform::PropertyOverride
custom_flatten: templates/terraform/custom_flatten/name_from_self_link.erb
custom_code: !ruby/object:Provider::Terraform::CustomCode
pre_delete: templates/terraform/pre_delete/vertex_ai_force_delete.go.erb
virtual_fields:
- !ruby/object:Api::Type::Boolean
name: 'force_destroy'
description: 'If set to true, any EntityTypes and Features for this Featurestore will also be deleted'
default_value: false
FeaturestoreEntitytype: !ruby/object:Overrides::Terraform::ResourceOverride
import_format: ["{{featurestore}}/entityTypes/{{name}}"]
autogen_async: false
skip_sweeper: true
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 6
update_minutes: 6
delete_minutes: 10
examples:
- !ruby/object:Provider::Terraform::Examples
name: "vertex_ai_featurestore_entitytype"
primary_resource_id: "entity"
vars:
name: "terraform"
properties:
etag: !ruby/object:Overrides::Terraform::PropertyOverride
ignore_read: true
name: !ruby/object:Overrides::Terraform::PropertyOverride
custom_flatten: templates/terraform/custom_flatten/name_from_self_link.erb
custom_code: !ruby/object:Provider::Terraform::CustomCode
pre_create: templates/terraform/constants/vertex_ai_featurestore_entitytype.go.erb
pre_update: templates/terraform/constants/vertex_ai_featurestore_entitytype.go.erb
pre_delete: templates/terraform/constants/vertex_ai_featurestore_entitytype.go.erb
# This is for copying files over
files: !ruby/object:Provider::Config::Files
# These files have templating (ERB) code that will be run.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
if v, ok := d.GetOk("featurestore"); ok {
re := regexp.MustCompile("projects/([a-zA-Z0-9-]*)/(?:locations|regions)/([a-zA-Z0-9-]*)")
switch {
case re.MatchString(v.(string)):
if res := re.FindStringSubmatch(v.(string)); len(res) == 3 && res[1] != "" {
project = res[1]
}
}
}
11 changes: 11 additions & 0 deletions mmv1/templates/terraform/examples/vertex_ai_featurestore.tf.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
resource "google_vertex_ai_featurestore" "featurestore" {
provider = google-beta
name = "<%= ctx[:vars]['name'] %>"
labels = {
foo = "bar"
}
region = "us-central1"
online_serving_config {
fixed_node_count = 2
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
resource "google_vertex_ai_featurestore" "featurestore" {
provider = google-beta
name = "<%= ctx[:vars]['name'] %>"
labels = {
foo = "bar"
}
region = "us-central1"
online_serving_config {
fixed_node_count = 2
}
}

resource "google_vertex_ai_featurestore_entitytype" "featurestore" {
provider = google-beta
name = "<%= ctx[:vars]['name'] %>"
labels = {
foo = "bar"
}
featurestore = google_vertex_ai_featurestore.featurestore.id
monitoring_config {
snapshot_analysis {
disabled = false
monitoring_interval = "86400s"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

if v, ok := d.GetOk("force_destroy"); ok {
url, err = addQueryParams(url, map[string]string{"force": v.(string)})
if err != nil {
return err
}
}
16 changes: 11 additions & 5 deletions mmv1/templates/terraform/resource.erb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ import (
timeouts ||= Api::Timeouts.new
-%>

<% if object.async&.is_a? Api::OpAsync -%>
<% if object.async.include_project -%>
var project string
<% end -%>
<% end -%>

func resource<%= resource_name -%>() *schema.Resource {
return &schema.Resource{
Create: resource<%= resource_name -%>Create,
Expand Down Expand Up @@ -261,7 +267,7 @@ func resource<%= resource_name -%>Create(d *schema.ResourceData, meta interface{
// identity fields and d.Id() before read
var opRes map[string]interface{}
err = <%= client_name_camel -%>OperationWaitTimeWithResponse(
config, res, &opRes, <% if has_project -%> project, <% end -%> "Creating <%= object.name -%>", userAgent,
config, res, &opRes, <% if has_project || object.async.include_project -%> project, <% end -%> "Creating <%= object.name -%>", userAgent,
d.Timeout(schema.TimeoutCreate))
if err != nil {
<% if object.custom_code.post_create_failure -%>
Expand Down Expand Up @@ -311,7 +317,7 @@ func resource<%= resource_name -%>Create(d *schema.ResourceData, meta interface{

<% else -%>
err = <%= client_name_camel -%>OperationWaitTime(
config, res, <% if has_project -%> project, <% end -%> "Creating <%= object.name -%>", userAgent,
config, res, <% if has_project || object.async.include_project -%> project, <% end -%> "Creating <%= object.name -%>", userAgent,
d.Timeout(schema.TimeoutCreate))

if err != nil {
Expand Down Expand Up @@ -660,7 +666,7 @@ if len(updateMask) > 0 {
<% if object.async&.allow?('update') -%>
<% if object.async.is_a? Api::OpAsync -%>
err = <%= client_name_camel -%>OperationWaitTime(
config, res, <% if has_project -%> project, <% end -%> "Updating <%= object.name -%>", userAgent,
config, res, <% if has_project || object.async.include_project -%> project, <% end -%> "Updating <%= object.name -%>", userAgent,
d.Timeout(schema.TimeoutUpdate))

if err != nil {
Expand Down Expand Up @@ -792,7 +798,7 @@ if <%= props.map { |prop| "d.HasChange(\"#{prop.name.underscore}\")" }.join ' ||
<% if object.async&.allow?('update') -%>
<% if object.async.is_a? Api::OpAsync-%>
err = <%= client_name_camel -%>OperationWaitTime(
config, res, <% if has_project -%> project, <% end -%> "Updating <%= object.name -%>", userAgent,
config, res, <% if has_project || object.async.include_project -%> project, <% end -%> "Updating <%= object.name -%>", userAgent,
d.Timeout(schema.TimeoutUpdate))
if err != nil {
return err
Expand Down Expand Up @@ -909,7 +915,7 @@ func resource<%= resource_name -%>Delete(d *schema.ResourceData, meta interface{
}
<% else -%>
err = <%= client_name_camel -%>OperationWaitTime(
config, res, <% if has_project -%> project, <% end -%> "Deleting <%= object.name -%>", userAgent,
config, res, <% if has_project || object.async.include_project-%> project, <% end -%> "Deleting <%= object.name -%>", userAgent,
d.Timeout(schema.TimeoutDelete))

if err != nil {
Expand Down