Skip to content

Commit 3bc1359

Browse files
committed
add proto files gen for stacks plugin, & regenerate protofiles
add tests update changelog
1 parent b129844 commit 3bc1359

19 files changed

+623
-157
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Experiments are only enabled in alpha releases of Terraform CLI. The following f
77

88
- The new command `terraform rpcapi` exposes some Terraform Core functionality through an RPC interface compatible with [`go-plugin`](https://github.com/hashicorp/go-plugin). The exact RPC API exposed here is currently subject to change at any time, because it's here primarily as a vehicle to support the [Terraform Stacks](https://www.hashicorp.com/blog/terraform-stacks-explained) private preview and so will be broken if necessary to respond to feedback from private preview participants, or possibly for other reasons. Do not use this mechanism yet outside of Terraform Stacks private preview.
99
- The experimental "deferred actions" feature, enabled by passing the `-allow-deferral` option to `terraform plan`, permits `count` and `for_each` arguments in `module`, `resource`, and `data` blocks to have unknown values and allows providers to react more flexibly to unknown values. This experiment is under active development, and so it's not yet useful to participate in this experiment
10+
- The new command `terraform stacks` exposes some [Terraform Stack](https://www.hashicorp.com/blog/terraform-stacks-explained) operations through the cli. The available subcommands depend on the stacks plugin implementation. Use `terraform stacks -help` to see available commands.
1011

1112
## Previous Releases
1213

internal/command/stacks.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ func (c *StacksCommand) realRun(args []string, stdout, stderr io.Writer) int {
131131
func (c *StacksCommand) discoverAndConfigure() tfdiags.Diagnostics {
132132
var diags tfdiags.Diagnostics
133133

134+
// using the current terraform path for the plugin binary path
134135
tfBinaryPath, err := os.Executable()
135136
if err != nil {
136137
return diags.Append(tfdiags.Sourceless(
@@ -219,7 +220,7 @@ func (c *StacksCommand) discoverAndConfigure() tfdiags.Diagnostics {
219220
}
220221
c.pluginService = pluginService
221222

222-
tfeService, err := cb.ServicesHost.ServiceURL(tfeServiceID)
223+
tfeService, err := cb.ServicesHost.ServiceURL(tfeStacksServiceID)
223224
if err != nil {
224225
return diags.Append(tfdiags.Sourceless(
225226
tfdiags.Error,
@@ -228,13 +229,21 @@ func (c *StacksCommand) discoverAndConfigure() tfdiags.Diagnostics {
228229
))
229230
}
230231

232+
// optional env values
233+
orgName := os.Getenv("TF_STACKS_ORGANIZATION_NAME")
234+
projectName := os.Getenv("TF_STACKS_PROJECT_NAME")
235+
stackName := os.Getenv("TF_STACKS_STACK_NAME")
236+
231237
// config to be passed to the plugin later.
232238
c.pluginConfig = StacksPluginConfig{
233239
Address: tfeService.String(),
234240
BasePath: tfeService.Path,
235241
DisplayHostname: displayHostname,
236242
Token: token,
237243
TerraformBinaryPath: tfBinaryPath,
244+
OrganizationName: orgName,
245+
ProjectName: projectName,
246+
StackName: stackName,
238247
}
239248

240249
return diags
@@ -334,6 +343,9 @@ type StacksPluginConfig struct {
334343
DisplayHostname string `md:"tfc-display-hostname"`
335344
Token string `md:"tfc-token"`
336345
TerraformBinaryPath string `md:"terraform-binary-path"`
346+
OrganizationName string `md:"tfc-organization"`
347+
ProjectName string `md:"tfc-project"`
348+
StackName string `md:"tfc-stack"`
337349
}
338350

339351
func (c StacksPluginConfig) ToMetadata() metadata.MD {
@@ -343,6 +355,9 @@ func (c StacksPluginConfig) ToMetadata() metadata.MD {
343355
"tfc-display-hostname", c.DisplayHostname,
344356
"tfc-token", c.Token,
345357
"terraform-binary-path", c.TerraformBinaryPath,
358+
"tfc-organization", c.OrganizationName,
359+
"tfc-project", c.ProjectName,
360+
"tfc-stack", c.StackName,
346361
)
347362
return md
348363
}

internal/command/stacks_test.go

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package command
5+
6+
import (
7+
"reflect"
8+
"testing"
9+
10+
"google.golang.org/grpc/metadata"
11+
)
12+
13+
func TestStacksPluginConfig_ToMetadata(t *testing.T) {
14+
expected := metadata.Pairs(
15+
"tfc-address", "https://app.staging.terraform.io",
16+
"tfc-base-path", "/api/v2/",
17+
"tfc-display-hostname", "app.staging.terraform.io",
18+
"tfc-token", "not-a-legit-token",
19+
"tfc-organization", "example-corp",
20+
"tfc-project", "example-project",
21+
"tfc-stack", "example-stack",
22+
"terraform-binary-path", "",
23+
)
24+
inputStruct := StacksPluginConfig{
25+
Address: "https://app.staging.terraform.io",
26+
BasePath: "/api/v2/",
27+
DisplayHostname: "app.staging.terraform.io",
28+
Token: "not-a-legit-token",
29+
OrganizationName: "example-corp",
30+
ProjectName: "example-project",
31+
StackName: "example-stack",
32+
TerraformBinaryPath: "",
33+
}
34+
result := inputStruct.ToMetadata()
35+
if !reflect.DeepEqual(expected, result) {
36+
t.Fatalf("Expected: %#v\nGot: %#v\n", expected, result)
37+
}
38+
}

internal/pluginshared/cloudclient.go

-6
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import (
1212
"github.com/hashicorp/terraform/internal/logging"
1313
)
1414

15-
// type CloudPluginClient struct {
16-
// BasePluginClient
17-
// }
18-
1915
// NewCloudPluginClient creates a new client for downloading and verifying
2016
// terraform-cloudplugin archives
2117
func NewCloudPluginClient(ctx context.Context, serviceURL *url.URL) (*BasePluginClient, error) {
@@ -34,7 +30,5 @@ func NewCloudPluginClient(ctx context.Context, serviceURL *url.URL) (*BasePlugin
3430
httpClient: retryableClient,
3531
pluginName: "cloudplugin",
3632
}
37-
38-
// return &CloudPluginClient{BasePluginClient: client}, nil
3933
return &client, nil
4034
}

internal/pluginshared/stacksclient.go

-6
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import (
1212
"github.com/hashicorp/terraform/internal/logging"
1313
)
1414

15-
// type StacksPluginClient struct {
16-
// BasePluginClient
17-
// }
18-
1915
// NewStacksPluginClient creates a new client for downloading and verifying
2016
// terraform-stacks plugin archives
2117
func NewStacksPluginClient(ctx context.Context, serviceURL *url.URL) (*BasePluginClient, error) {
@@ -34,7 +30,5 @@ func NewStacksPluginClient(ctx context.Context, serviceURL *url.URL) (*BasePlugi
3430
httpClient: retryableClient,
3531
pluginName: "stacksplugin",
3632
}
37-
38-
// return &StacksPluginClient{BasePluginClient: client}, nil
3933
return &client, nil
4034
}

internal/rpcapi/stacks_grpc_client.go

+30-7
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ import (
1212
"github.com/hashicorp/go-plugin"
1313
"github.com/hashicorp/terraform-svchost/disco"
1414
"github.com/hashicorp/terraform/internal/pluginshared"
15+
1516
"github.com/hashicorp/terraform/internal/rpcapi/dynrpcserver"
1617
"github.com/hashicorp/terraform/internal/rpcapi/terraform1/dependencies"
1718
"github.com/hashicorp/terraform/internal/rpcapi/terraform1/packages"
1819
"github.com/hashicorp/terraform/internal/rpcapi/terraform1/stacks"
1920
"github.com/hashicorp/terraform/internal/stacksplugin/stacksproto1"
20-
2121
"google.golang.org/grpc"
2222
)
2323

@@ -32,9 +32,15 @@ type GRPCStacksClient struct {
3232
// Proof that GRPCStacksClient fulfills the go-plugin interface
3333
var _ pluginshared.CustomPluginClient = GRPCStacksClient{}
3434

35-
// Execute sends the client Execute request and waits for the plugin to return
36-
// an exit code response before returning
37-
func (c GRPCStacksClient) Execute(args []string, stdout, stderr io.Writer) int {
35+
type brokerIDs struct {
36+
packagesBrokerID uint32
37+
dependenciesBrokerID uint32
38+
stacksBrokerID uint32
39+
}
40+
41+
// registerBrokers starts the GRPC servers for the dependencies, packages, and stacks
42+
// services and returns the broker IDs for each.
43+
func (c GRPCStacksClient) registerBrokers(stdout, stderr io.Writer) brokerIDs {
3844
handles := newHandleTable()
3945

4046
dependenciesServer := dynrpcserver.NewDependenciesStub()
@@ -75,10 +81,20 @@ func (c GRPCStacksClient) Execute(args []string, stdout, stderr io.Writer) int {
7581
stacksBrokerID := c.Broker.NextId()
7682
go c.Broker.AcceptAndServe(stacksBrokerID, stacksServerFunc)
7783

84+
return brokerIDs{
85+
dependenciesBrokerID: dependenciesBrokerID,
86+
packagesBrokerID: packagesBrokerID,
87+
stacksBrokerID: stacksBrokerID,
88+
}
89+
}
90+
91+
// Execute sends the client Execute request and waits for the plugin to return
92+
// an exit code response before returning
93+
func (c GRPCStacksClient) executeWithBrokers(brokerIDs brokerIDs, args []string, stdout, stderr io.Writer) int {
7894
client, err := c.Client.Execute(c.Context, &stacksproto1.CommandRequest{
79-
DependenciesServer: dependenciesBrokerID,
80-
PackagesServer: packagesBrokerID,
81-
StacksServer: stacksBrokerID,
95+
DependenciesServer: brokerIDs.dependenciesBrokerID,
96+
PackagesServer: brokerIDs.packagesBrokerID,
97+
StacksServer: brokerIDs.stacksBrokerID,
8298
Args: args,
8399
})
84100

@@ -132,3 +148,10 @@ func (c GRPCStacksClient) Execute(args []string, stdout, stderr io.Writer) int {
132148
fmt.Fprint(stderr, "stacksplugin exited without responding with an error code")
133149
return 1
134150
}
151+
152+
// Execute sends the client Execute request and waits for the plugin to return
153+
// an exit code response before returning
154+
func (c GRPCStacksClient) Execute(args []string, stdout, stderr io.Writer) int {
155+
brokerIDs := c.registerBrokers(stdout, stderr)
156+
return c.executeWithBrokers(brokerIDs, args, stdout, stderr)
157+
}

0 commit comments

Comments
 (0)