Skip to content

Commit 51fc4c1

Browse files
PSS: Implement ReadStateBytes + WriteStateBytes (#37440)
* Implement ReadStateBytes + WriteStateBytes * [WIP] - Testing ReadStateBytes and WriteStateBytes (#37464) * Fix nil pointer error * Add WIP test for ReadStateBytes * Move test mock to separate testing file * Update mock to send unexpected EOF when there's a problem returning data and it's not a true EOF * Add test case for when length != expected length * Add test for when trying to read state from a store type that doesn't exist * Change symbol names to lowercase * Add ability to force a diagnostic to be returned from `mockReadStateBytesClient`'s `Recv` method * Add test showing error diagnostics raised by the ReadStateBytes client are returned * Add missing header * Simplify mock by using an embedded type * Rename `mockOpts` to `mockReadStateBytesOpts` * Update existing tests to assert what arguments are passed to the RPC method call * Add mock WriteStateBytesClient which uses `go.uber.org/mock/gomock` to enable assertions about calls to Send * Add a test for WriteStateBytes that makes assertions about calls to the Send method * Update test case to explicitly test writing data smaller than the chunk size * Implement chunking in WriteStateBytes, add test case to assert expected chunking behaviour * Add generated mock for Provider_WriteStateBytesClient in protocol v6 * Update tests to use new `MockProvider_WriteStateBytesClient`, remove handwritten mock * Update code comments in test * Add tests for diagnostics and errors returned during WriteStateBytes * Add generated mock for Provider_ReadStateBytesClient in protocol v6, replace old mock * Add test case for grpc errors in ReadStateBytes, fix how error is returned * Typo in comment * Add missing warning test, rename some test cases * Update proto file definition of Read/WriteStateBytes RPCs (#37529) * Update Read/WriteStateBytes RPCs to match hashicorp/terraform-plugin-go#531 * Run `make protobuf` * Run `make generate` * Update use of `proto.ReadStateBytes_ResponseChunk` in tests * Fix how diagnostics are handled alongside EOF error, update ReadStateBytes test * More fixes - test setup was incorrect I think? I assume that a response would be returned full of zero-values when EOF is encountered. * WIP - avoid crash if chunk is nil * Sarah's updates to radek/pss-read-write (#37642) * Update code to not expect a chunk when EOF encountered * Return early if any grpc errors are encountered during ReadStateBytes * Close the stream with CloseSend once everything's read without error. Add test case about handling grpc errors from CloseSend. * Fix test case about warnings: We would expect to receive a chunk with data alongside the warning and have a normal closing of the stream after EOF * Add log line, remove unneeded type info * Implement configurable state chunk size * handle metadata in WriteStateBytes correctly * validate chunk sizes received from provider * ReadStateBytes: avoid early return on warnings --------- Co-authored-by: Sarah French <[email protected]>
1 parent a4cc769 commit 51fc4c1

File tree

18 files changed

+2840
-488
lines changed

18 files changed

+2840
-488
lines changed

docs/plugin-protocol/tfplugin6.proto

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,11 @@ service Provider {
390390
// ConfigureStateStore configures the state store, such as S3 connection in the context of already configured provider
391391
rpc ConfigureStateStore(ConfigureStateStore.Request) returns (ConfigureStateStore.Response);
392392

393+
// ReadStateBytes streams byte chunks of a given state file from a state store
394+
rpc ReadStateBytes(ReadStateBytes.Request) returns (stream ReadStateBytes.Response);
395+
// WriteStateBytes streams byte chunks of a given state file into a state store
396+
rpc WriteStateBytes(stream WriteStateBytes.RequestChunk) returns (WriteStateBytes.Response);
397+
393398
// GetStates returns a list of all states (i.e. CE workspaces) managed by a given state store
394399
rpc GetStates(GetStates.Request) returns (GetStates.Response);
395400
// DeleteState instructs a given state store to delete a specific state (i.e. a CE workspace)
@@ -896,7 +901,6 @@ message ValidateListResourceConfig {
896901
}
897902
}
898903

899-
900904
message ValidateStateStore {
901905
message Request {
902906
string type_name = 1;
@@ -911,12 +915,59 @@ message ConfigureStateStore {
911915
message Request {
912916
string type_name = 1;
913917
DynamicValue config = 2;
918+
StateStoreClientCapabilities capabilities = 3;
914919
}
915920
message Response {
916921
repeated Diagnostic diagnostics = 1;
922+
StateStoreServerCapabilities capabilities = 2;
917923
}
918924
}
919925

926+
message StateStoreClientCapabilities {
927+
int64 chunk_size = 1; // suggested chunk size by Core
928+
}
929+
930+
message StateStoreServerCapabilities {
931+
int64 chunk_size = 1; // chosen chunk size by plugin
932+
}
933+
934+
message ReadStateBytes {
935+
message Request {
936+
string type_name = 1;
937+
string state_id = 2;
938+
}
939+
message Response {
940+
bytes bytes = 1;
941+
int64 total_length = 2;
942+
StateRange range = 3;
943+
repeated Diagnostic diagnostics = 4;
944+
}
945+
}
946+
947+
message WriteStateBytes {
948+
message RequestChunk {
949+
// meta is sent with the first chunk only
950+
optional RequestChunkMeta meta = 1;
951+
952+
bytes bytes = 2;
953+
int64 total_length = 3;
954+
StateRange range = 4;
955+
}
956+
message Response {
957+
repeated Diagnostic diagnostics = 1;
958+
}
959+
}
960+
961+
message RequestChunkMeta {
962+
string type_name = 1;
963+
string state_id = 2;
964+
}
965+
966+
message StateRange {
967+
int64 start = 1;
968+
int64 end = 2;
969+
}
970+
920971
message GetStates {
921972
message Request {
922973
string type_name = 1;

internal/builtin/providers/terraform/provider.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,18 @@ func (p *Provider) ConfigureStateStore(req providers.ConfigureStateStoreRequest)
295295
return resp
296296
}
297297

298+
func (p *Provider) ReadStateBytes(req providers.ReadStateBytesRequest) providers.ReadStateBytesResponse {
299+
var resp providers.ReadStateBytesResponse
300+
resp.Diagnostics.Append(fmt.Errorf("unsupported state store type %q", req.TypeName))
301+
return resp
302+
}
303+
304+
func (p *Provider) WriteStateBytes(req providers.WriteStateBytesRequest) providers.WriteStateBytesResponse {
305+
var resp providers.WriteStateBytesResponse
306+
resp.Diagnostics.Append(fmt.Errorf("unsupported state store type %q", req.TypeName))
307+
return resp
308+
}
309+
298310
func (p *Provider) GetStates(req providers.GetStatesRequest) providers.GetStatesResponse {
299311
var resp providers.GetStatesResponse
300312
resp.Diagnostics.Append(fmt.Errorf("unsupported state store type %q", req.TypeName))

internal/grpcwrap/provider6.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,14 @@ func (p *provider6) ConfigureStateStore(ctx context.Context, req *tfplugin6.Conf
907907
panic("not implemented")
908908
}
909909

910+
func (p *provider6) ReadStateBytes(req *tfplugin6.ReadStateBytes_Request, srv tfplugin6.Provider_ReadStateBytesServer) error {
911+
panic("not implemented")
912+
}
913+
914+
func (p *provider6) WriteStateBytes(srv tfplugin6.Provider_WriteStateBytesServer) error {
915+
panic("not implemented")
916+
}
917+
910918
func (p *provider6) GetStates(ctx context.Context, req *tfplugin6.GetStates_Request) (*tfplugin6.GetStates_Response, error) {
911919
panic("not implemented")
912920
}

internal/plugin/grpc_provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,14 @@ func (p *GRPCProvider) ConfigureStateStore(r providers.ConfigureStateStoreReques
14441444
panic("not implemented")
14451445
}
14461446

1447+
func (p *GRPCProvider) ReadStateBytes(r providers.ReadStateBytesRequest) providers.ReadStateBytesResponse {
1448+
panic("not implemented")
1449+
}
1450+
1451+
func (p *GRPCProvider) WriteStateBytes(r providers.WriteStateBytesRequest) providers.WriteStateBytesResponse {
1452+
panic("not implemented")
1453+
}
1454+
14471455
func (p *GRPCProvider) GetStates(r providers.GetStatesRequest) providers.GetStatesResponse {
14481456
panic("not implemented")
14491457
}

0 commit comments

Comments
 (0)