// Copyright IBM Corp. 2014, 2026 // SPDX-License-Identifier: BUSL-1.1 package rpcapi import ( "context" "sync" "github.com/hashicorp/terraform/internal/rpcapi/terraform1/setup" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) // setupServer is an implementation of the "Setup" service defined in our // terraform1 package. // // This service is here mainly to offer the "Handshake" function, which clients // must call to negotiate access to any other services. This is really just // an adapter around a handshake function implemented on [corePlugin]. type setupServer struct { setup.UnimplementedSetupServer // initOthers is the callback used to perform the capability negotiation // step and initialize all of the other API services based on what was // negotiated. initOthers func(context.Context, *setup.Handshake_Request, *stopper) (*setup.ServerCapabilities, error) // stopper is used to track and stop long-running operations when the Stop // RPC is called. stopper *stopper mu sync.Mutex } func newSetupServer(initOthers func(context.Context, *setup.Handshake_Request, *stopper) (*setup.ServerCapabilities, error)) setup.SetupServer { return &setupServer{ initOthers: initOthers, stopper: newStopper(), } } func (s *setupServer) Handshake(ctx context.Context, req *setup.Handshake_Request) (*setup.Handshake_Response, error) { s.mu.Lock() defer s.mu.Unlock() if s.initOthers == nil { return nil, status.Error(codes.FailedPrecondition, "handshake already completed") } var serverCaps *setup.ServerCapabilities var err error { ctx, span := tracer.Start(ctx, "initialize RPC services") serverCaps, err = s.initOthers(ctx, req, s.stopper) span.End() } s.initOthers = nil // cannot handshake again if err != nil { return nil, err } return &setup.Handshake_Response{ Capabilities: serverCaps, }, nil } func (s *setupServer) Stop(ctx context.Context, req *setup.Stop_Request) (*setup.Stop_Response, error) { s.mu.Lock() defer s.mu.Unlock() s.stopper.stop() return &setup.Stop_Response{}, nil }