Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 16 additions & 0 deletions action/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package action

import "context"

type Action interface {
// Schema should return the schema for this action.
Schema(context.Context, SchemaRequest, *SchemaResponse)

// Metadata should return the full name of the action, such as examplecloud_do_thing.
Metadata(context.Context, MetadataRequest, *MetadataResponse)

// TODO:Actions: Eventual landing place for all required methods to implement for an action
}
5 changes: 5 additions & 0 deletions action/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

// TODO:Actions: Eventual package docs for actions
package action
24 changes: 24 additions & 0 deletions action/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package action

// MetadataRequest represents a request for the Action to return metadata,
// such as its type name. An instance of this request struct is supplied as
// an argument to the Action type Metadata method.
type MetadataRequest struct {
// ProviderTypeName is the string returned from
// [provider.MetadataResponse.TypeName], if the Provider type implements
// the Metadata method. This string should prefix the Action type name
// with an underscore in the response.
ProviderTypeName string
}

// MetadataResponse represents a response to a MetadataRequest. An
// instance of this response struct is supplied as an argument to the
// Action type Metadata method.
type MetadataResponse struct {
// TypeName should be the full action type, including the provider
// type prefix and an underscore. For example, examplecloud_thing.
TypeName string
}
28 changes: 28 additions & 0 deletions action/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package action

import (
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
)

// SchemaRequest represents a request for the Action to return its schema.
// An instance of this request struct is supplied as an argument to the
// Action type Schema method.
type SchemaRequest struct{}

// SchemaResponse represents a response to a SchemaRequest. An instance of this
// response struct is supplied as an argument to the Action type Schema
// method.
type SchemaResponse struct {
// TODO:Actions: This will eventually be replaced by an interface defined in
// an "actions/schema" package. Schema implementations that will fulfill this
// interface will be unlinked, linked, or lifecycle. (also defined in the "actions/schema" package)
Schema fwschema.Schema

// Diagnostics report errors or warnings related to retrieving the action schema.
// An empty slice indicates success, with no warnings or errors generated.
Diagnostics diag.Diagnostics
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.23.7

require (
github.com/google/go-cmp v0.7.0
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1.0.20250709165734-a8477a15f806
github.com/hashicorp/terraform-plugin-log v0.9.0
)

Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0U
github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-go v0.28.1-0.20250616135123-a19df43120ea h1:U9EAAeQtszGlR7mDS7rY77B/a4/XiMDB8HfAtqLAuAQ=
github.com/hashicorp/terraform-plugin-go v0.28.1-0.20250616135123-a19df43120ea/go.mod h1:hL//wLEfYo0YVt0TC/VLzia/ADQQto3HEm4/jX2gkdY=
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1 h1:ZId6oWG8VTKhz207quE/Xh8a3HuoLtM/QkcSSypekIQ=
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1/go.mod h1:hL//wLEfYo0YVt0TC/VLzia/ADQQto3HEm4/jX2gkdY=
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1.0.20250709165734-a8477a15f806 h1:i3kA1sT/Fk8Ex+VVKdjf9sFOPwS7w3Q73pfbnxKwdjg=
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1.0.20250709165734-a8477a15f806/go.mod h1:hL//wLEfYo0YVt0TC/VLzia/ADQQto3HEm4/jX2gkdY=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-registry-address v0.3.0 h1:HMpK3nqaGFPS9VmgRXrJL/dzHNdheGVKk5k7VlFxzCo=
Expand Down
52 changes: 52 additions & 0 deletions internal/fromproto5/invokeaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto5

import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"

"github.com/hashicorp/terraform-plugin-framework/action"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
)

// InvokeActionRequest returns the *fwserver.InvokeActionRequest equivalent of a *tfprotov5.InvokeActionRequest.
func InvokeActionRequest(ctx context.Context, proto5 *tfprotov5.InvokeActionRequest, reqAction action.Action, actionSchema fwschema.Schema) (*fwserver.InvokeActionRequest, diag.Diagnostics) {
if proto5 == nil {
return nil, nil
}

var diags diag.Diagnostics

// Panic prevention here to simplify the calling implementations.
// This should not happen, but just in case.
if actionSchema == nil {
diags.AddError(
"Missing Action Schema",
"An unexpected error was encountered when handling the request. "+
"This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+
"Please report this to the provider developer:\n\n"+
"Missing schema.",
)

return nil, diags
}

fw := &fwserver.InvokeActionRequest{
ActionSchema: actionSchema,
}

config, configDiags := Config(ctx, proto5.Config, actionSchema)

diags.Append(configDiags...)

fw.Config = config

// TODO:Actions: Here we need to retrieve linked resource data

return fw, diags
}
6 changes: 6 additions & 0 deletions internal/fromproto5/invokeaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto5_test

// TODO:Actions: Add unit tests once this mapping logic is complete
52 changes: 52 additions & 0 deletions internal/fromproto5/planaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto5

import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov5"

"github.com/hashicorp/terraform-plugin-framework/action"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
)

// PlanActionRequest returns the *fwserver.PlanActionRequest equivalent of a *tfprotov5.PlanActionRequest.
func PlanActionRequest(ctx context.Context, proto5 *tfprotov5.PlanActionRequest, reqAction action.Action, actionSchema fwschema.Schema) (*fwserver.PlanActionRequest, diag.Diagnostics) {
if proto5 == nil {
return nil, nil
}

var diags diag.Diagnostics

// Panic prevention here to simplify the calling implementations.
// This should not happen, but just in case.
if actionSchema == nil {
diags.AddError(
"Missing Action Schema",
"An unexpected error was encountered when handling the request. "+
"This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+
"Please report this to the provider developer:\n\n"+
"Missing schema.",
)

return nil, diags
}

fw := &fwserver.PlanActionRequest{
ActionSchema: actionSchema,
}

config, configDiags := Config(ctx, proto5.Config, actionSchema)

diags.Append(configDiags...)

fw.Config = config

// TODO:Actions: Here we need to retrieve client capabilities and linked resource data

return fw, diags
}
6 changes: 6 additions & 0 deletions internal/fromproto5/planaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto5_test

// TODO:Actions: Add unit tests once this mapping logic is complete
52 changes: 52 additions & 0 deletions internal/fromproto6/invokeaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto6

import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov6"

"github.com/hashicorp/terraform-plugin-framework/action"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
)

// InvokeActionRequest returns the *fwserver.InvokeActionRequest equivalent of a *tfprotov6.InvokeActionRequest.
func InvokeActionRequest(ctx context.Context, proto6 *tfprotov6.InvokeActionRequest, reqAction action.Action, actionSchema fwschema.Schema) (*fwserver.InvokeActionRequest, diag.Diagnostics) {
if proto6 == nil {
return nil, nil
}

var diags diag.Diagnostics

// Panic prevention here to simplify the calling implementations.
// This should not happen, but just in case.
if actionSchema == nil {
diags.AddError(
"Missing Action Schema",
"An unexpected error was encountered when handling the request. "+
"This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+
"Please report this to the provider developer:\n\n"+
"Missing schema.",
)

return nil, diags
}

fw := &fwserver.InvokeActionRequest{
ActionSchema: actionSchema,
}

config, configDiags := Config(ctx, proto6.Config, actionSchema)

diags.Append(configDiags...)

fw.Config = config

// TODO:Actions: Here we need to retrieve linked resource data

return fw, diags
}
6 changes: 6 additions & 0 deletions internal/fromproto6/invokeaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto6_test

// TODO:Actions: Add unit tests once this mapping logic is complete
52 changes: 52 additions & 0 deletions internal/fromproto6/planaction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto6

import (
"context"

"github.com/hashicorp/terraform-plugin-go/tfprotov6"

"github.com/hashicorp/terraform-plugin-framework/action"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwschema"
"github.com/hashicorp/terraform-plugin-framework/internal/fwserver"
)

// PlanActionRequest returns the *fwserver.PlanActionRequest equivalent of a *tfprotov6.PlanActionRequest.
func PlanActionRequest(ctx context.Context, proto6 *tfprotov6.PlanActionRequest, reqAction action.Action, actionSchema fwschema.Schema) (*fwserver.PlanActionRequest, diag.Diagnostics) {
if proto6 == nil {
return nil, nil
}

var diags diag.Diagnostics

// Panic prevention here to simplify the calling implementations.
// This should not happen, but just in case.
if actionSchema == nil {
diags.AddError(
"Missing Action Schema",
"An unexpected error was encountered when handling the request. "+
"This is always an issue in terraform-plugin-framework used to implement the provider and should be reported to the provider developers.\n\n"+
"Please report this to the provider developer:\n\n"+
"Missing schema.",
)

return nil, diags
}

fw := &fwserver.PlanActionRequest{
ActionSchema: actionSchema,
}

config, configDiags := Config(ctx, proto6.Config, actionSchema)

diags.Append(configDiags...)

fw.Config = config

// TODO:Actions: Here we need to retrieve client capabilities and linked resource data

return fw, diags
}
6 changes: 6 additions & 0 deletions internal/fromproto6/planaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package fromproto6_test

// TODO:Actions: Add unit tests once this mapping logic is complete
24 changes: 24 additions & 0 deletions internal/fwserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"sync"

"github.com/hashicorp/terraform-plugin-framework/action"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
Expand Down Expand Up @@ -40,6 +41,29 @@ type Server struct {
// to [ephemeral.ConfigureRequest.ProviderData].
EphemeralResourceConfigureData any

// actionSchemas is the cached Action Schemas for RPCs that need to
// convert configuration data from the protocol. If not found, it will be
// fetched from the Action.Schema() method.
actionSchemas map[string]fwschema.Schema

// actionSchemasMutex is a mutex to protect concurrent actionSchemas
// access from race conditions.
actionSchemasMutex sync.RWMutex

// actionFuncs is the cached Action functions for RPCs that need to
// access actions. If not found, it will be fetched from the
// Provider.Actions() method.
actionFuncs map[string]func() action.Action

// actionFuncsDiags is the cached Diagnostics obtained while populating
// actionFuncs. This is to ensure any warnings or errors are also
// returned appropriately when fetching actionFuncs.
actionFuncsDiags diag.Diagnostics

// actionFuncsMutex is a mutex to protect concurrent actionFuncs
// access from race conditions.
actionFuncsMutex sync.Mutex

// dataSourceSchemas is the cached DataSource Schemas for RPCs that need to
// convert configuration data from the protocol. If not found, it will be
// fetched from the DataSourceType.GetSchema() method.
Expand Down
Loading