mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-17 04:03:07 -06:00
0b1dbf31a3
Currently Terraform is leaking goroutines and with that memory. I know strictly speaking this maybe isn’t a real concern for Terraform as it’s mostly used as a short running command line executable. But there are a few of us out there that are using Terraform in some long running processes and then this starts to become a problem. Next to that it’s of course good programming practise to clean up resources when they're not needed anymore. So even for the standard command line use case, this seems an improvement in resource management. Personally I see no downsides as the primary connection to the plugin is kept alive (the plugin is not killed) and only unused connections that will never be used again are closed to free up any related goroutines and memory.
135 lines
2.9 KiB
Go
135 lines
2.9 KiB
Go
package rpc
|
|
|
|
import (
|
|
"net/rpc"
|
|
|
|
"github.com/hashicorp/terraform/terraform"
|
|
)
|
|
|
|
// ResourceProvisioner is an implementation of terraform.ResourceProvisioner
|
|
// that communicates over RPC.
|
|
type ResourceProvisioner struct {
|
|
Broker *muxBroker
|
|
Client *rpc.Client
|
|
Name string
|
|
}
|
|
|
|
func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, []error) {
|
|
var resp ResourceProvisionerValidateResponse
|
|
args := ResourceProvisionerValidateArgs{
|
|
Config: c,
|
|
}
|
|
|
|
err := p.Client.Call(p.Name+".Validate", &args, &resp)
|
|
if err != nil {
|
|
return nil, []error{err}
|
|
}
|
|
|
|
var errs []error
|
|
if len(resp.Errors) > 0 {
|
|
errs = make([]error, len(resp.Errors))
|
|
for i, err := range resp.Errors {
|
|
errs[i] = err
|
|
}
|
|
}
|
|
|
|
return resp.Warnings, errs
|
|
}
|
|
|
|
func (p *ResourceProvisioner) Apply(
|
|
output terraform.UIOutput,
|
|
s *terraform.InstanceState,
|
|
c *terraform.ResourceConfig) error {
|
|
id := p.Broker.NextId()
|
|
go acceptAndServe(p.Broker, id, "UIOutput", &UIOutputServer{
|
|
UIOutput: output,
|
|
})
|
|
|
|
var resp ResourceProvisionerApplyResponse
|
|
args := &ResourceProvisionerApplyArgs{
|
|
OutputId: id,
|
|
State: s,
|
|
Config: c,
|
|
}
|
|
|
|
err := p.Client.Call(p.Name+".Apply", args, &resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (p *ResourceProvisioner) Close() error {
|
|
return p.Client.Close()
|
|
}
|
|
|
|
type ResourceProvisionerValidateArgs struct {
|
|
Config *terraform.ResourceConfig
|
|
}
|
|
|
|
type ResourceProvisionerValidateResponse struct {
|
|
Warnings []string
|
|
Errors []*BasicError
|
|
}
|
|
|
|
type ResourceProvisionerApplyArgs struct {
|
|
OutputId uint32
|
|
State *terraform.InstanceState
|
|
Config *terraform.ResourceConfig
|
|
}
|
|
|
|
type ResourceProvisionerApplyResponse struct {
|
|
Error *BasicError
|
|
}
|
|
|
|
// ResourceProvisionerServer is a net/rpc compatible structure for serving
|
|
// a ResourceProvisioner. This should not be used directly.
|
|
type ResourceProvisionerServer struct {
|
|
Broker *muxBroker
|
|
Provisioner terraform.ResourceProvisioner
|
|
}
|
|
|
|
func (s *ResourceProvisionerServer) Apply(
|
|
args *ResourceProvisionerApplyArgs,
|
|
result *ResourceProvisionerApplyResponse) error {
|
|
conn, err := s.Broker.Dial(args.OutputId)
|
|
if err != nil {
|
|
*result = ResourceProvisionerApplyResponse{
|
|
Error: NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
client := rpc.NewClient(conn)
|
|
defer client.Close()
|
|
|
|
output := &UIOutput{
|
|
Client: client,
|
|
Name: "UIOutput",
|
|
}
|
|
|
|
err = s.Provisioner.Apply(output, args.State, args.Config)
|
|
*result = ResourceProvisionerApplyResponse{
|
|
Error: NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProvisionerServer) Validate(
|
|
args *ResourceProvisionerValidateArgs,
|
|
reply *ResourceProvisionerValidateResponse) error {
|
|
warns, errs := s.Provisioner.Validate(args.Config)
|
|
berrs := make([]*BasicError, len(errs))
|
|
for i, err := range errs {
|
|
berrs[i] = NewBasicError(err)
|
|
}
|
|
*reply = ResourceProvisionerValidateResponse{
|
|
Warnings: warns,
|
|
Errors: berrs,
|
|
}
|
|
return nil
|
|
}
|