2017-01-20 16:59:14 +01:00
|
|
|
/*
|
|
|
|
*
|
2017-08-11 19:19:46 +02:00
|
|
|
* Copyright 2014 gRPC authors.
|
2017-01-20 16:59:14 +01:00
|
|
|
*
|
2017-08-11 19:19:46 +02:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2017-01-20 16:59:14 +01:00
|
|
|
*
|
2017-08-11 19:19:46 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2017-01-20 16:59:14 +01:00
|
|
|
*
|
2017-08-11 19:19:46 +02:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
2017-01-20 16:59:14 +01:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
package grpc
|
|
|
|
|
|
|
|
import (
|
2019-02-20 19:51:33 +01:00
|
|
|
"context"
|
2017-01-20 16:59:14 +01:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2018-09-24 18:30:39 +02:00
|
|
|
"math"
|
2017-01-20 16:59:14 +01:00
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
"reflect"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
2019-02-20 19:51:33 +01:00
|
|
|
"sync/atomic"
|
2017-01-20 16:59:14 +01:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"golang.org/x/net/trace"
|
2018-09-24 18:30:39 +02:00
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/credentials"
|
2018-09-24 18:30:39 +02:00
|
|
|
"google.golang.org/grpc/encoding"
|
|
|
|
"google.golang.org/grpc/encoding/proto"
|
2017-01-20 16:59:14 +01:00
|
|
|
"google.golang.org/grpc/grpclog"
|
2019-02-20 19:51:33 +01:00
|
|
|
"google.golang.org/grpc/internal/binarylog"
|
2018-09-24 18:30:39 +02:00
|
|
|
"google.golang.org/grpc/internal/channelz"
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
"google.golang.org/grpc/internal/grpcsync"
|
2018-09-24 18:30:39 +02:00
|
|
|
"google.golang.org/grpc/internal/transport"
|
2017-08-11 19:19:46 +02:00
|
|
|
"google.golang.org/grpc/keepalive"
|
2017-01-20 16:59:14 +01:00
|
|
|
"google.golang.org/grpc/metadata"
|
2019-02-20 19:51:33 +01:00
|
|
|
"google.golang.org/grpc/peer"
|
2017-01-20 16:59:14 +01:00
|
|
|
"google.golang.org/grpc/stats"
|
2017-08-11 19:19:46 +02:00
|
|
|
"google.golang.org/grpc/status"
|
2017-01-20 16:59:14 +01:00
|
|
|
"google.golang.org/grpc/tap"
|
|
|
|
)
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
const (
|
|
|
|
defaultServerMaxReceiveMessageSize = 1024 * 1024 * 4
|
2018-09-24 18:30:39 +02:00
|
|
|
defaultServerMaxSendMessageSize = math.MaxInt32
|
2017-08-11 19:19:46 +02:00
|
|
|
)
|
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
var statusOK = status.New(codes.OK, "")
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
type methodHandler func(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor UnaryServerInterceptor) (interface{}, error)
|
|
|
|
|
|
|
|
// MethodDesc represents an RPC service's method specification.
|
|
|
|
type MethodDesc struct {
|
|
|
|
MethodName string
|
|
|
|
Handler methodHandler
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServiceDesc represents an RPC service's specification.
|
|
|
|
type ServiceDesc struct {
|
|
|
|
ServiceName string
|
|
|
|
// The pointer to the service interface. Used to check whether the user
|
|
|
|
// provided implementation satisfies the interface requirements.
|
|
|
|
HandlerType interface{}
|
|
|
|
Methods []MethodDesc
|
|
|
|
Streams []StreamDesc
|
|
|
|
Metadata interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// service consists of the information of the server serving this service and
|
|
|
|
// the methods in this service.
|
|
|
|
type service struct {
|
|
|
|
server interface{} // the server for service methods
|
|
|
|
md map[string]*MethodDesc
|
|
|
|
sd map[string]*StreamDesc
|
|
|
|
mdata interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Server is a gRPC server to serve RPC requests.
|
|
|
|
type Server struct {
|
2019-09-09 14:04:58 +02:00
|
|
|
opts serverOptions
|
2017-01-20 16:59:14 +01:00
|
|
|
|
|
|
|
mu sync.Mutex // guards following
|
|
|
|
lis map[net.Listener]bool
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
conns map[transport.ServerTransport]bool
|
2017-08-11 19:19:46 +02:00
|
|
|
serve bool
|
2017-01-20 16:59:14 +01:00
|
|
|
drain bool
|
2018-09-24 18:30:39 +02:00
|
|
|
cv *sync.Cond // signaled when connections close for GracefulStop
|
2017-01-20 16:59:14 +01:00
|
|
|
m map[string]*service // service name -> service info
|
|
|
|
events trace.EventLog
|
2018-09-24 18:30:39 +02:00
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
quit *grpcsync.Event
|
|
|
|
done *grpcsync.Event
|
2018-09-24 18:30:39 +02:00
|
|
|
channelzRemoveOnce sync.Once
|
|
|
|
serveWG sync.WaitGroup // counts active Serve goroutines for GracefulStop
|
|
|
|
|
2019-02-20 19:51:33 +01:00
|
|
|
channelzID int64 // channelz unique identification number
|
|
|
|
czData *channelzData
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2019-09-09 14:04:58 +02:00
|
|
|
type serverOptions struct {
|
2017-08-11 19:19:46 +02:00
|
|
|
creds credentials.TransportCredentials
|
2018-09-24 18:30:39 +02:00
|
|
|
codec baseCodec
|
2017-08-11 19:19:46 +02:00
|
|
|
cp Compressor
|
|
|
|
dc Decompressor
|
|
|
|
unaryInt UnaryServerInterceptor
|
|
|
|
streamInt StreamServerInterceptor
|
|
|
|
inTapHandle tap.ServerInHandle
|
|
|
|
statsHandler stats.Handler
|
|
|
|
maxConcurrentStreams uint32
|
|
|
|
maxReceiveMessageSize int
|
|
|
|
maxSendMessageSize int
|
|
|
|
unknownStreamDesc *StreamDesc
|
|
|
|
keepaliveParams keepalive.ServerParameters
|
|
|
|
keepalivePolicy keepalive.EnforcementPolicy
|
|
|
|
initialWindowSize int32
|
|
|
|
initialConnWindowSize int32
|
2018-09-24 18:30:39 +02:00
|
|
|
writeBufferSize int
|
|
|
|
readBufferSize int
|
|
|
|
connectionTimeout time.Duration
|
|
|
|
maxHeaderListSize *uint32
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
headerTableSize *uint32
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
2019-09-09 14:04:58 +02:00
|
|
|
var defaultServerOptions = serverOptions{
|
2017-08-11 19:19:46 +02:00
|
|
|
maxReceiveMessageSize: defaultServerMaxReceiveMessageSize,
|
|
|
|
maxSendMessageSize: defaultServerMaxSendMessageSize,
|
2018-09-24 18:30:39 +02:00
|
|
|
connectionTimeout: 120 * time.Second,
|
|
|
|
writeBufferSize: defaultWriteBufSize,
|
|
|
|
readBufferSize: defaultReadBufSize,
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// A ServerOption sets options such as credentials, codec and keepalive parameters, etc.
|
2019-09-09 14:04:58 +02:00
|
|
|
type ServerOption interface {
|
|
|
|
apply(*serverOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
// EmptyServerOption does not alter the server configuration. It can be embedded
|
|
|
|
// in another structure to build custom server options.
|
|
|
|
//
|
|
|
|
// This API is EXPERIMENTAL.
|
|
|
|
type EmptyServerOption struct{}
|
|
|
|
|
|
|
|
func (EmptyServerOption) apply(*serverOptions) {}
|
|
|
|
|
|
|
|
// funcServerOption wraps a function that modifies serverOptions into an
|
|
|
|
// implementation of the ServerOption interface.
|
|
|
|
type funcServerOption struct {
|
|
|
|
f func(*serverOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fdo *funcServerOption) apply(do *serverOptions) {
|
|
|
|
fdo.f(do)
|
|
|
|
}
|
|
|
|
|
|
|
|
func newFuncServerOption(f func(*serverOptions)) *funcServerOption {
|
|
|
|
return &funcServerOption{
|
|
|
|
f: f,
|
|
|
|
}
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// WriteBufferSize determines how much data can be batched before doing a write on the wire.
|
|
|
|
// The corresponding memory allocation for this buffer will be twice the size to keep syscalls low.
|
|
|
|
// The default value for this buffer is 32KB.
|
|
|
|
// Zero will disable the write buffer such that each write will be on underlying connection.
|
|
|
|
// Note: A Send call may not directly translate to a write.
|
|
|
|
func WriteBufferSize(s int) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2018-09-24 18:30:39 +02:00
|
|
|
o.writeBufferSize = s
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most
|
|
|
|
// for one read syscall.
|
|
|
|
// The default value for this buffer is 32KB.
|
|
|
|
// Zero will disable read buffer for a connection so data framer can access the underlying
|
|
|
|
// conn directly.
|
|
|
|
func ReadBufferSize(s int) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2018-09-24 18:30:39 +02:00
|
|
|
o.readBufferSize = s
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// InitialWindowSize returns a ServerOption that sets window size for stream.
|
|
|
|
// The lower bound for window size is 64K and any value smaller than that will be ignored.
|
|
|
|
func InitialWindowSize(s int32) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.initialWindowSize = s
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// InitialConnWindowSize returns a ServerOption that sets window size for a connection.
|
|
|
|
// The lower bound for window size is 64K and any value smaller than that will be ignored.
|
|
|
|
func InitialConnWindowSize(s int32) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.initialConnWindowSize = s
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// KeepaliveParams returns a ServerOption that sets keepalive and max-age parameters for the server.
|
|
|
|
func KeepaliveParams(kp keepalive.ServerParameters) ServerOption {
|
2019-07-30 00:19:40 +02:00
|
|
|
if kp.Time > 0 && kp.Time < time.Second {
|
|
|
|
grpclog.Warning("Adjusting keepalive ping interval to minimum period of 1s")
|
|
|
|
kp.Time = time.Second
|
|
|
|
}
|
|
|
|
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.keepaliveParams = kp
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// KeepaliveEnforcementPolicy returns a ServerOption that sets keepalive enforcement policy for the server.
|
|
|
|
func KeepaliveEnforcementPolicy(kep keepalive.EnforcementPolicy) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.keepalivePolicy = kep
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
// CustomCodec returns a ServerOption that sets a codec for message marshaling and unmarshaling.
|
2018-09-24 18:30:39 +02:00
|
|
|
//
|
|
|
|
// This will override any lookups by content-subtype for Codecs registered with RegisterCodec.
|
2017-01-20 16:59:14 +01:00
|
|
|
func CustomCodec(codec Codec) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
o.codec = codec
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// RPCCompressor returns a ServerOption that sets a compressor for outbound
|
|
|
|
// messages. For backward compatibility, all outbound messages will be sent
|
|
|
|
// using this compressor, regardless of incoming message compression. By
|
|
|
|
// default, server messages will be sent using the same compressor with which
|
|
|
|
// request messages were sent.
|
|
|
|
//
|
|
|
|
// Deprecated: use encoding.RegisterCompressor instead.
|
2017-01-20 16:59:14 +01:00
|
|
|
func RPCCompressor(cp Compressor) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
o.cp = cp
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// RPCDecompressor returns a ServerOption that sets a decompressor for inbound
|
|
|
|
// messages. It has higher priority than decompressors registered via
|
|
|
|
// encoding.RegisterCompressor.
|
|
|
|
//
|
|
|
|
// Deprecated: use encoding.RegisterCompressor instead.
|
2017-01-20 16:59:14 +01:00
|
|
|
func RPCDecompressor(dc Decompressor) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
o.dc = dc
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// MaxMsgSize returns a ServerOption to set the max message size in bytes the server can receive.
|
2018-09-24 18:30:39 +02:00
|
|
|
// If this is not set, gRPC uses the default limit.
|
|
|
|
//
|
|
|
|
// Deprecated: use MaxRecvMsgSize instead.
|
2017-01-20 16:59:14 +01:00
|
|
|
func MaxMsgSize(m int) ServerOption {
|
2017-08-11 19:19:46 +02:00
|
|
|
return MaxRecvMsgSize(m)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaxRecvMsgSize returns a ServerOption to set the max message size in bytes the server can receive.
|
|
|
|
// If this is not set, gRPC uses the default 4MB.
|
|
|
|
func MaxRecvMsgSize(m int) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.maxReceiveMessageSize = m
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// MaxSendMsgSize returns a ServerOption to set the max message size in bytes the server can send.
|
2019-07-30 00:19:40 +02:00
|
|
|
// If this is not set, gRPC uses the default `math.MaxInt32`.
|
2017-08-11 19:19:46 +02:00
|
|
|
func MaxSendMsgSize(m int) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.maxSendMessageSize = m
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// MaxConcurrentStreams returns a ServerOption that will apply a limit on the number
|
|
|
|
// of concurrent streams to each ServerTransport.
|
|
|
|
func MaxConcurrentStreams(n uint32) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
o.maxConcurrentStreams = n
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Creds returns a ServerOption that sets credentials for server connections.
|
|
|
|
func Creds(c credentials.TransportCredentials) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
o.creds = c
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnaryInterceptor returns a ServerOption that sets the UnaryServerInterceptor for the
|
|
|
|
// server. Only one unary interceptor can be installed. The construction of multiple
|
|
|
|
// interceptors (e.g., chaining) can be implemented at the caller.
|
|
|
|
func UnaryInterceptor(i UnaryServerInterceptor) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
if o.unaryInt != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
panic("The unary server interceptor was already set and may not be reset.")
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
o.unaryInt = i
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// StreamInterceptor returns a ServerOption that sets the StreamServerInterceptor for the
|
|
|
|
// server. Only one stream interceptor can be installed.
|
|
|
|
func StreamInterceptor(i StreamServerInterceptor) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
if o.streamInt != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
panic("The stream server interceptor was already set and may not be reset.")
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
o.streamInt = i
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// InTapHandle returns a ServerOption that sets the tap handle for all the server
|
|
|
|
// transport to be created. Only one can be installed.
|
|
|
|
func InTapHandle(h tap.ServerInHandle) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
if o.inTapHandle != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
panic("The tap handle was already set and may not be reset.")
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
o.inTapHandle = h
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// StatsHandler returns a ServerOption that sets the stats handler for the server.
|
|
|
|
func StatsHandler(h stats.Handler) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-01-20 16:59:14 +01:00
|
|
|
o.statsHandler = h
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// UnknownServiceHandler returns a ServerOption that allows for adding a custom
|
|
|
|
// unknown service handler. The provided method is a bidi-streaming RPC service
|
|
|
|
// handler that will be invoked instead of returning the "unimplemented" gRPC
|
|
|
|
// error whenever a request is received for an unregistered service or method.
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
// The handling function and stream interceptor (if set) have full access to
|
|
|
|
// the ServerStream, including its Context.
|
2017-08-11 19:19:46 +02:00
|
|
|
func UnknownServiceHandler(streamHandler StreamHandler) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2017-08-11 19:19:46 +02:00
|
|
|
o.unknownStreamDesc = &StreamDesc{
|
|
|
|
StreamName: "unknown_service_handler",
|
|
|
|
Handler: streamHandler,
|
|
|
|
// We need to assume that the users of the streamHandler will want to use both.
|
|
|
|
ClientStreams: true,
|
|
|
|
ServerStreams: true,
|
|
|
|
}
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// ConnectionTimeout returns a ServerOption that sets the timeout for
|
|
|
|
// connection establishment (up to and including HTTP/2 handshaking) for all
|
|
|
|
// new connections. If this is not set, the default is 120 seconds. A zero or
|
|
|
|
// negative value will result in an immediate timeout.
|
|
|
|
//
|
|
|
|
// This API is EXPERIMENTAL.
|
|
|
|
func ConnectionTimeout(d time.Duration) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2018-09-24 18:30:39 +02:00
|
|
|
o.connectionTimeout = d
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// MaxHeaderListSize returns a ServerOption that sets the max (uncompressed) size
|
|
|
|
// of header list that the server is prepared to accept.
|
|
|
|
func MaxHeaderListSize(s uint32) ServerOption {
|
2019-09-09 14:04:58 +02:00
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
2018-09-24 18:30:39 +02:00
|
|
|
o.maxHeaderListSize = &s
|
2019-09-09 14:04:58 +02:00
|
|
|
})
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
// HeaderTableSize returns a ServerOption that sets the size of dynamic
|
|
|
|
// header table for stream.
|
|
|
|
//
|
|
|
|
// This API is EXPERIMENTAL.
|
|
|
|
func HeaderTableSize(s uint32) ServerOption {
|
|
|
|
return newFuncServerOption(func(o *serverOptions) {
|
|
|
|
o.headerTableSize = &s
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
// NewServer creates a gRPC server which has no service registered and has not
|
|
|
|
// started to accept requests yet.
|
|
|
|
func NewServer(opt ...ServerOption) *Server {
|
2017-08-11 19:19:46 +02:00
|
|
|
opts := defaultServerOptions
|
2017-01-20 16:59:14 +01:00
|
|
|
for _, o := range opt {
|
2019-09-09 14:04:58 +02:00
|
|
|
o.apply(&opts)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
s := &Server{
|
2019-02-20 19:51:33 +01:00
|
|
|
lis: make(map[net.Listener]bool),
|
|
|
|
opts: opts,
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
conns: make(map[transport.ServerTransport]bool),
|
2019-02-20 19:51:33 +01:00
|
|
|
m: make(map[string]*service),
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
quit: grpcsync.NewEvent(),
|
|
|
|
done: grpcsync.NewEvent(),
|
2019-02-20 19:51:33 +01:00
|
|
|
czData: new(channelzData),
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
s.cv = sync.NewCond(&s.mu)
|
|
|
|
if EnableTracing {
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
|
|
s.events = trace.NewEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line))
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
if channelz.IsOn() {
|
2019-02-20 19:51:33 +01:00
|
|
|
s.channelzID = channelz.RegisterServer(&channelzServer{s}, "")
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
// printf records an event in s's event log, unless s has been stopped.
|
|
|
|
// REQUIRES s.mu is held.
|
|
|
|
func (s *Server) printf(format string, a ...interface{}) {
|
|
|
|
if s.events != nil {
|
|
|
|
s.events.Printf(format, a...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// errorf records an error in s's event log, unless s has been stopped.
|
|
|
|
// REQUIRES s.mu is held.
|
|
|
|
func (s *Server) errorf(format string, a ...interface{}) {
|
|
|
|
if s.events != nil {
|
|
|
|
s.events.Errorf(format, a...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// RegisterService registers a service and its implementation to the gRPC
|
|
|
|
// server. It is called from the IDL generated code. This must be called before
|
2017-01-20 16:59:14 +01:00
|
|
|
// invoking Serve.
|
|
|
|
func (s *Server) RegisterService(sd *ServiceDesc, ss interface{}) {
|
|
|
|
ht := reflect.TypeOf(sd.HandlerType).Elem()
|
|
|
|
st := reflect.TypeOf(ss)
|
|
|
|
if !st.Implements(ht) {
|
|
|
|
grpclog.Fatalf("grpc: Server.RegisterService found the handler of type %v that does not satisfy %v", st, ht)
|
|
|
|
}
|
|
|
|
s.register(sd, ss)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) register(sd *ServiceDesc, ss interface{}) {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
s.printf("RegisterService(%q)", sd.ServiceName)
|
2017-08-11 19:19:46 +02:00
|
|
|
if s.serve {
|
|
|
|
grpclog.Fatalf("grpc: Server.RegisterService after Server.Serve for %q", sd.ServiceName)
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
if _, ok := s.m[sd.ServiceName]; ok {
|
|
|
|
grpclog.Fatalf("grpc: Server.RegisterService found duplicate service registration for %q", sd.ServiceName)
|
|
|
|
}
|
|
|
|
srv := &service{
|
|
|
|
server: ss,
|
|
|
|
md: make(map[string]*MethodDesc),
|
|
|
|
sd: make(map[string]*StreamDesc),
|
|
|
|
mdata: sd.Metadata,
|
|
|
|
}
|
|
|
|
for i := range sd.Methods {
|
|
|
|
d := &sd.Methods[i]
|
|
|
|
srv.md[d.MethodName] = d
|
|
|
|
}
|
|
|
|
for i := range sd.Streams {
|
|
|
|
d := &sd.Streams[i]
|
|
|
|
srv.sd[d.StreamName] = d
|
|
|
|
}
|
|
|
|
s.m[sd.ServiceName] = srv
|
|
|
|
}
|
|
|
|
|
|
|
|
// MethodInfo contains the information of an RPC including its method name and type.
|
|
|
|
type MethodInfo struct {
|
|
|
|
// Name is the method name only, without the service name or package name.
|
|
|
|
Name string
|
|
|
|
// IsClientStream indicates whether the RPC is a client streaming RPC.
|
|
|
|
IsClientStream bool
|
|
|
|
// IsServerStream indicates whether the RPC is a server streaming RPC.
|
|
|
|
IsServerStream bool
|
|
|
|
}
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// ServiceInfo contains unary RPC method info, streaming RPC method info and metadata for a service.
|
2017-01-20 16:59:14 +01:00
|
|
|
type ServiceInfo struct {
|
|
|
|
Methods []MethodInfo
|
|
|
|
// Metadata is the metadata specified in ServiceDesc when registering service.
|
|
|
|
Metadata interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetServiceInfo returns a map from service names to ServiceInfo.
|
|
|
|
// Service names include the package names, in the form of <package>.<service>.
|
|
|
|
func (s *Server) GetServiceInfo() map[string]ServiceInfo {
|
|
|
|
ret := make(map[string]ServiceInfo)
|
|
|
|
for n, srv := range s.m {
|
|
|
|
methods := make([]MethodInfo, 0, len(srv.md)+len(srv.sd))
|
|
|
|
for m := range srv.md {
|
|
|
|
methods = append(methods, MethodInfo{
|
|
|
|
Name: m,
|
|
|
|
IsClientStream: false,
|
|
|
|
IsServerStream: false,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for m, d := range srv.sd {
|
|
|
|
methods = append(methods, MethodInfo{
|
|
|
|
Name: m,
|
|
|
|
IsClientStream: d.ClientStreams,
|
|
|
|
IsServerStream: d.ServerStreams,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
ret[n] = ServiceInfo{
|
|
|
|
Methods: methods,
|
|
|
|
Metadata: srv.mdata,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// ErrServerStopped indicates that the operation is now illegal because of
|
|
|
|
// the server being stopped.
|
|
|
|
var ErrServerStopped = errors.New("grpc: the server has been stopped")
|
2017-01-20 16:59:14 +01:00
|
|
|
|
|
|
|
func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
|
|
|
|
if s.opts.creds == nil {
|
|
|
|
return rawConn, nil, nil
|
|
|
|
}
|
|
|
|
return s.opts.creds.ServerHandshake(rawConn)
|
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
type listenSocket struct {
|
|
|
|
net.Listener
|
|
|
|
channelzID int64
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *listenSocket) ChannelzMetric() *channelz.SocketInternalMetric {
|
|
|
|
return &channelz.SocketInternalMetric{
|
|
|
|
SocketOptions: channelz.GetSocketOption(l.Listener),
|
|
|
|
LocalAddr: l.Listener.Addr(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *listenSocket) Close() error {
|
|
|
|
err := l.Listener.Close()
|
|
|
|
if channelz.IsOn() {
|
|
|
|
channelz.RemoveEntry(l.channelzID)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
// Serve accepts incoming connections on the listener lis, creating a new
|
|
|
|
// ServerTransport and service goroutine for each. The service goroutines
|
|
|
|
// read gRPC requests and then call the registered handlers to reply to them.
|
|
|
|
// Serve returns when lis.Accept fails with fatal errors. lis will be closed when
|
|
|
|
// this method returns.
|
2018-09-24 18:30:39 +02:00
|
|
|
// Serve will return a non-nil error unless Stop or GracefulStop is called.
|
2017-01-20 16:59:14 +01:00
|
|
|
func (s *Server) Serve(lis net.Listener) error {
|
|
|
|
s.mu.Lock()
|
|
|
|
s.printf("serving")
|
2017-08-11 19:19:46 +02:00
|
|
|
s.serve = true
|
2017-01-20 16:59:14 +01:00
|
|
|
if s.lis == nil {
|
2018-09-24 18:30:39 +02:00
|
|
|
// Serve called after Stop or GracefulStop.
|
2017-01-20 16:59:14 +01:00
|
|
|
s.mu.Unlock()
|
|
|
|
lis.Close()
|
|
|
|
return ErrServerStopped
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
s.serveWG.Add(1)
|
|
|
|
defer func() {
|
|
|
|
s.serveWG.Done()
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if s.quit.HasFired() {
|
|
|
|
// Stop or GracefulStop called; block until done and return nil.
|
|
|
|
<-s.done.Done()
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
ls := &listenSocket{Listener: lis}
|
|
|
|
s.lis[ls] = true
|
|
|
|
|
|
|
|
if channelz.IsOn() {
|
2019-02-20 19:51:33 +01:00
|
|
|
ls.channelzID = channelz.RegisterListenSocket(ls, s.channelzID, lis.Addr().String())
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
s.mu.Unlock()
|
2018-09-24 18:30:39 +02:00
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
defer func() {
|
|
|
|
s.mu.Lock()
|
2018-09-24 18:30:39 +02:00
|
|
|
if s.lis != nil && s.lis[ls] {
|
|
|
|
ls.Close()
|
|
|
|
delete(s.lis, ls)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
s.mu.Unlock()
|
|
|
|
}()
|
|
|
|
|
|
|
|
var tempDelay time.Duration // how long to sleep on accept failure
|
|
|
|
|
|
|
|
for {
|
|
|
|
rawConn, err := lis.Accept()
|
|
|
|
if err != nil {
|
|
|
|
if ne, ok := err.(interface {
|
|
|
|
Temporary() bool
|
|
|
|
}); ok && ne.Temporary() {
|
|
|
|
if tempDelay == 0 {
|
|
|
|
tempDelay = 5 * time.Millisecond
|
|
|
|
} else {
|
|
|
|
tempDelay *= 2
|
|
|
|
}
|
|
|
|
if max := 1 * time.Second; tempDelay > max {
|
|
|
|
tempDelay = max
|
|
|
|
}
|
|
|
|
s.mu.Lock()
|
|
|
|
s.printf("Accept error: %v; retrying in %v", err, tempDelay)
|
|
|
|
s.mu.Unlock()
|
2017-08-11 19:19:46 +02:00
|
|
|
timer := time.NewTimer(tempDelay)
|
2017-01-20 16:59:14 +01:00
|
|
|
select {
|
2017-08-11 19:19:46 +02:00
|
|
|
case <-timer.C:
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
case <-s.quit.Done():
|
2018-09-24 18:30:39 +02:00
|
|
|
timer.Stop()
|
|
|
|
return nil
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
s.mu.Lock()
|
|
|
|
s.printf("done serving; Accept = %v", err)
|
|
|
|
s.mu.Unlock()
|
2018-09-24 18:30:39 +02:00
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if s.quit.HasFired() {
|
2018-09-24 18:30:39 +02:00
|
|
|
return nil
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
tempDelay = 0
|
2018-09-24 18:30:39 +02:00
|
|
|
// Start a new goroutine to deal with rawConn so we don't stall this Accept
|
|
|
|
// loop goroutine.
|
|
|
|
//
|
|
|
|
// Make sure we account for the goroutine so GracefulStop doesn't nil out
|
|
|
|
// s.conns before this conn can be added.
|
|
|
|
s.serveWG.Add(1)
|
|
|
|
go func() {
|
|
|
|
s.handleRawConn(rawConn)
|
|
|
|
s.serveWG.Done()
|
|
|
|
}()
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// handleRawConn forks a goroutine to handle a just-accepted connection that
|
|
|
|
// has not had any I/O performed on it yet.
|
2017-01-20 16:59:14 +01:00
|
|
|
func (s *Server) handleRawConn(rawConn net.Conn) {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if s.quit.HasFired() {
|
|
|
|
rawConn.Close()
|
|
|
|
return
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
rawConn.SetDeadline(time.Now().Add(s.opts.connectionTimeout))
|
2017-01-20 16:59:14 +01:00
|
|
|
conn, authInfo, err := s.useTransportAuthenticator(rawConn)
|
|
|
|
if err != nil {
|
2019-09-09 14:04:58 +02:00
|
|
|
// ErrConnDispatched means that the connection was dispatched away from
|
|
|
|
// gRPC; those connections should be left open.
|
2017-01-20 16:59:14 +01:00
|
|
|
if err != credentials.ErrConnDispatched {
|
2019-09-09 14:04:58 +02:00
|
|
|
s.mu.Lock()
|
|
|
|
s.errorf("ServerHandshake(%q) failed: %v", rawConn.RemoteAddr(), err)
|
|
|
|
s.mu.Unlock()
|
|
|
|
grpclog.Warningf("grpc: Server.Serve failed to complete security handshake from %q: %v", rawConn.RemoteAddr(), err)
|
2017-01-20 16:59:14 +01:00
|
|
|
rawConn.Close()
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
rawConn.SetDeadline(time.Time{})
|
2017-01-20 16:59:14 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-20 19:51:33 +01:00
|
|
|
// Finish handshaking (HTTP2)
|
|
|
|
st := s.newHTTP2Transport(conn, authInfo)
|
|
|
|
if st == nil {
|
|
|
|
return
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
rawConn.SetDeadline(time.Time{})
|
2019-02-20 19:51:33 +01:00
|
|
|
if !s.addConn(st) {
|
2018-09-24 18:30:39 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
go func() {
|
2019-02-20 19:51:33 +01:00
|
|
|
s.serveStreams(st)
|
|
|
|
s.removeConn(st)
|
2018-09-24 18:30:39 +02:00
|
|
|
}()
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// newHTTP2Transport sets up a http/2 transport (using the
|
|
|
|
// gRPC http2 server transport in transport/http2_server.go).
|
|
|
|
func (s *Server) newHTTP2Transport(c net.Conn, authInfo credentials.AuthInfo) transport.ServerTransport {
|
2017-01-20 16:59:14 +01:00
|
|
|
config := &transport.ServerConfig{
|
2017-08-11 19:19:46 +02:00
|
|
|
MaxStreams: s.opts.maxConcurrentStreams,
|
|
|
|
AuthInfo: authInfo,
|
|
|
|
InTapHandle: s.opts.inTapHandle,
|
|
|
|
StatsHandler: s.opts.statsHandler,
|
|
|
|
KeepaliveParams: s.opts.keepaliveParams,
|
|
|
|
KeepalivePolicy: s.opts.keepalivePolicy,
|
|
|
|
InitialWindowSize: s.opts.initialWindowSize,
|
|
|
|
InitialConnWindowSize: s.opts.initialConnWindowSize,
|
2018-09-24 18:30:39 +02:00
|
|
|
WriteBufferSize: s.opts.writeBufferSize,
|
|
|
|
ReadBufferSize: s.opts.readBufferSize,
|
|
|
|
ChannelzParentID: s.channelzID,
|
|
|
|
MaxHeaderListSize: s.opts.maxHeaderListSize,
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
HeaderTableSize: s.opts.headerTableSize,
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
st, err := transport.NewServerTransport("http2", c, config)
|
|
|
|
if err != nil {
|
|
|
|
s.mu.Lock()
|
|
|
|
s.errorf("NewServerTransport(%q) failed: %v", c.RemoteAddr(), err)
|
|
|
|
s.mu.Unlock()
|
|
|
|
c.Close()
|
2017-08-11 19:19:46 +02:00
|
|
|
grpclog.Warningln("grpc: Server.Serve failed to create ServerTransport: ", err)
|
2018-09-24 18:30:39 +02:00
|
|
|
return nil
|
2018-08-27 20:26:52 +02:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
return st
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) serveStreams(st transport.ServerTransport) {
|
|
|
|
defer st.Close()
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
st.HandleStreams(func(stream *transport.Stream) {
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
s.handleStream(st, stream, s.traceInfo(st, stream))
|
|
|
|
}()
|
|
|
|
}, func(ctx context.Context, method string) context.Context {
|
|
|
|
if !EnableTracing {
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
tr := trace.New("grpc.Recv."+methodFamily(method), method)
|
|
|
|
return trace.NewContext(ctx, tr)
|
|
|
|
})
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ http.Handler = (*Server)(nil)
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// ServeHTTP implements the Go standard library's http.Handler
|
|
|
|
// interface by responding to the gRPC request r, by looking up
|
|
|
|
// the requested gRPC method in the gRPC server s.
|
|
|
|
//
|
|
|
|
// The provided HTTP request must have arrived on an HTTP/2
|
|
|
|
// connection. When using the Go standard library's server,
|
|
|
|
// practically this means that the Request must also have arrived
|
|
|
|
// over TLS.
|
|
|
|
//
|
|
|
|
// To share one port (such as 443 for https) between gRPC and an
|
|
|
|
// existing http.Handler, use a root http.Handler such as:
|
|
|
|
//
|
|
|
|
// if r.ProtoMajor == 2 && strings.HasPrefix(
|
|
|
|
// r.Header.Get("Content-Type"), "application/grpc") {
|
|
|
|
// grpcServer.ServeHTTP(w, r)
|
|
|
|
// } else {
|
|
|
|
// yourMux.ServeHTTP(w, r)
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// Note that ServeHTTP uses Go's HTTP/2 server implementation which is totally
|
|
|
|
// separate from grpc-go's HTTP/2 server. Performance and features may vary
|
|
|
|
// between the two paths. ServeHTTP does not support some gRPC features
|
|
|
|
// available through grpc-go's HTTP/2 server, and it is currently EXPERIMENTAL
|
|
|
|
// and subject to change.
|
2017-01-20 16:59:14 +01:00
|
|
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
2018-09-24 18:30:39 +02:00
|
|
|
st, err := transport.NewServerHandlerTransport(w, r, s.opts.statsHandler)
|
2017-01-20 16:59:14 +01:00
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !s.addConn(st) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer s.removeConn(st)
|
|
|
|
s.serveStreams(st)
|
|
|
|
}
|
|
|
|
|
|
|
|
// traceInfo returns a traceInfo and associates it with stream, if tracing is enabled.
|
|
|
|
// If tracing is not enabled, it returns nil.
|
|
|
|
func (s *Server) traceInfo(st transport.ServerTransport, stream *transport.Stream) (trInfo *traceInfo) {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if !EnableTracing {
|
|
|
|
return nil
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
tr, ok := trace.FromContext(stream.Context())
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
trInfo = &traceInfo{
|
|
|
|
tr: tr,
|
2019-09-09 14:04:58 +02:00
|
|
|
firstLine: firstLine{
|
|
|
|
client: false,
|
|
|
|
remoteAddr: st.RemoteAddr(),
|
|
|
|
},
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
if dl, ok := stream.Context().Deadline(); ok {
|
2019-07-30 00:19:40 +02:00
|
|
|
trInfo.firstLine.deadline = time.Until(dl)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
return trInfo
|
|
|
|
}
|
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
func (s *Server) addConn(st transport.ServerTransport) bool {
|
2017-01-20 16:59:14 +01:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
2018-09-24 18:30:39 +02:00
|
|
|
if s.conns == nil {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
st.Close()
|
2017-01-20 16:59:14 +01:00
|
|
|
return false
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
if s.drain {
|
|
|
|
// Transport added after we drained our existing conns: drain it
|
|
|
|
// immediately.
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
st.Drain()
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
s.conns[st] = true
|
2017-01-20 16:59:14 +01:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
func (s *Server) removeConn(st transport.ServerTransport) {
|
2017-01-20 16:59:14 +01:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
if s.conns != nil {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
delete(s.conns, st)
|
2017-01-20 16:59:14 +01:00
|
|
|
s.cv.Broadcast()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-20 19:51:33 +01:00
|
|
|
func (s *Server) channelzMetric() *channelz.ServerInternalMetric {
|
2018-09-24 18:30:39 +02:00
|
|
|
return &channelz.ServerInternalMetric{
|
2019-02-20 19:51:33 +01:00
|
|
|
CallsStarted: atomic.LoadInt64(&s.czData.callsStarted),
|
|
|
|
CallsSucceeded: atomic.LoadInt64(&s.czData.callsSucceeded),
|
|
|
|
CallsFailed: atomic.LoadInt64(&s.czData.callsFailed),
|
|
|
|
LastCallStartedTimestamp: time.Unix(0, atomic.LoadInt64(&s.czData.lastCallStartedTime)),
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) incrCallsStarted() {
|
2019-02-20 19:51:33 +01:00
|
|
|
atomic.AddInt64(&s.czData.callsStarted, 1)
|
|
|
|
atomic.StoreInt64(&s.czData.lastCallStartedTime, time.Now().UnixNano())
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) incrCallsSucceeded() {
|
2019-02-20 19:51:33 +01:00
|
|
|
atomic.AddInt64(&s.czData.callsSucceeded, 1)
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) incrCallsFailed() {
|
2019-02-20 19:51:33 +01:00
|
|
|
atomic.AddInt64(&s.czData.callsFailed, 1)
|
2018-09-24 18:30:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) sendResponse(t transport.ServerTransport, stream *transport.Stream, msg interface{}, cp Compressor, opts *transport.Options, comp encoding.Compressor) error {
|
|
|
|
data, err := encode(s.getCodec(stream.ContentSubtype()), msg)
|
2018-07-26 22:32:32 +02:00
|
|
|
if err != nil {
|
2018-08-27 20:26:52 +02:00
|
|
|
grpclog.Errorln("grpc: server failed to encode response: ", err)
|
2018-07-26 22:32:32 +02:00
|
|
|
return err
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
compData, err := compress(data, cp, comp)
|
|
|
|
if err != nil {
|
|
|
|
grpclog.Errorln("grpc: server failed to compress response: ", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
hdr, payload := msgHeader(data, compData)
|
|
|
|
// TODO(dfawley): should we be checking len(data) instead?
|
|
|
|
if len(payload) > s.opts.maxSendMessageSize {
|
|
|
|
return status.Errorf(codes.ResourceExhausted, "grpc: trying to send message larger than max (%d vs. %d)", len(payload), s.opts.maxSendMessageSize)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
err = t.Write(stream, hdr, payload, opts)
|
|
|
|
if err == nil && s.opts.statsHandler != nil {
|
|
|
|
s.opts.statsHandler.HandleRPC(stream.Context(), outPayload(false, msg, data, payload, time.Now()))
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) processUnaryRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, md *MethodDesc, trInfo *traceInfo) (err error) {
|
|
|
|
sh := s.opts.statsHandler
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if sh != nil || trInfo != nil || channelz.IsOn() {
|
|
|
|
if channelz.IsOn() {
|
|
|
|
s.incrCallsStarted()
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
var statsBegin *stats.Begin
|
|
|
|
if sh != nil {
|
|
|
|
beginTime := time.Now()
|
|
|
|
statsBegin = &stats.Begin{
|
2018-09-24 18:30:39 +02:00
|
|
|
BeginTime: beginTime,
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
sh.HandleRPC(stream.Context(), statsBegin)
|
|
|
|
}
|
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(&trInfo.firstLine, false)
|
|
|
|
}
|
|
|
|
// The deferred error handling for tracing, stats handler and channelz are
|
|
|
|
// combined into one function to reduce stack usage -- a defer takes ~56-64
|
|
|
|
// bytes on the stack, so overflowing the stack will require a stack
|
|
|
|
// re-allocation, which is expensive.
|
|
|
|
//
|
|
|
|
// To maintain behavior similar to separate deferred statements, statements
|
|
|
|
// should be executed in the reverse order. That is, tracing first, stats
|
|
|
|
// handler second, and channelz last. Note that panics *within* defers will
|
|
|
|
// lead to different behavior, but that's an acceptable compromise; that
|
|
|
|
// would be undefined behavior territory anyway.
|
2017-01-20 16:59:14 +01:00
|
|
|
defer func() {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if trInfo != nil {
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
|
|
|
|
trInfo.tr.SetError()
|
|
|
|
}
|
|
|
|
trInfo.tr.Finish()
|
|
|
|
}
|
|
|
|
|
|
|
|
if sh != nil {
|
|
|
|
end := &stats.End{
|
|
|
|
BeginTime: statsBegin.BeginTime,
|
|
|
|
EndTime: time.Now(),
|
|
|
|
}
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
end.Error = toRPCErr(err)
|
|
|
|
}
|
|
|
|
sh.HandleRPC(stream.Context(), end)
|
|
|
|
}
|
|
|
|
|
|
|
|
if channelz.IsOn() {
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
s.incrCallsFailed()
|
|
|
|
} else {
|
|
|
|
s.incrCallsSucceeded()
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
2019-02-20 19:51:33 +01:00
|
|
|
binlog := binarylog.GetMethodLogger(stream.Method())
|
|
|
|
if binlog != nil {
|
|
|
|
ctx := stream.Context()
|
|
|
|
md, _ := metadata.FromIncomingContext(ctx)
|
|
|
|
logEntry := &binarylog.ClientHeader{
|
|
|
|
Header: md,
|
|
|
|
MethodName: stream.Method(),
|
|
|
|
PeerAddr: nil,
|
|
|
|
}
|
|
|
|
if deadline, ok := ctx.Deadline(); ok {
|
2019-07-30 00:19:40 +02:00
|
|
|
logEntry.Timeout = time.Until(deadline)
|
2019-02-20 19:51:33 +01:00
|
|
|
if logEntry.Timeout < 0 {
|
|
|
|
logEntry.Timeout = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if a := md[":authority"]; len(a) > 0 {
|
|
|
|
logEntry.Authority = a[0]
|
|
|
|
}
|
|
|
|
if peer, ok := peer.FromContext(ctx); ok {
|
|
|
|
logEntry.PeerAddr = peer.Addr
|
|
|
|
}
|
|
|
|
binlog.Log(logEntry)
|
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// comp and cp are used for compression. decomp and dc are used for
|
|
|
|
// decompression. If comp and decomp are both set, they are the same;
|
|
|
|
// however they are kept separate to ensure that at most one of the
|
|
|
|
// compressor/decompressor variable pairs are set for use later.
|
|
|
|
var comp, decomp encoding.Compressor
|
|
|
|
var cp Compressor
|
|
|
|
var dc Decompressor
|
|
|
|
|
|
|
|
// If dc is set and matches the stream's compression, use it. Otherwise, try
|
|
|
|
// to find a matching registered compressor for decomp.
|
|
|
|
if rc := stream.RecvCompress(); s.opts.dc != nil && s.opts.dc.Type() == rc {
|
|
|
|
dc = s.opts.dc
|
|
|
|
} else if rc != "" && rc != encoding.Identity {
|
|
|
|
decomp = encoding.GetCompressor(rc)
|
|
|
|
if decomp == nil {
|
|
|
|
st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc)
|
|
|
|
t.WriteStatus(stream, st)
|
|
|
|
return st.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If cp is set, use it. Otherwise, attempt to compress the response using
|
|
|
|
// the incoming message compression method.
|
|
|
|
//
|
|
|
|
// NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686.
|
2017-01-20 16:59:14 +01:00
|
|
|
if s.opts.cp != nil {
|
2018-09-24 18:30:39 +02:00
|
|
|
cp = s.opts.cp
|
|
|
|
stream.SetSendCompress(cp.Type())
|
|
|
|
} else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity {
|
|
|
|
// Legacy compressor not specified; attempt to respond with same encoding.
|
|
|
|
comp = encoding.GetCompressor(rc)
|
|
|
|
if comp != nil {
|
|
|
|
stream.SetSendCompress(rc)
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
2019-02-20 19:51:33 +01:00
|
|
|
var payInfo *payloadInfo
|
|
|
|
if sh != nil || binlog != nil {
|
|
|
|
payInfo = &payloadInfo{}
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
d, err := recvAndDecompress(&parser{r: stream}, stream, dc, s.opts.maxReceiveMessageSize, payInfo, decomp)
|
2017-08-11 19:19:46 +02:00
|
|
|
if err != nil {
|
|
|
|
if st, ok := status.FromError(err); ok {
|
|
|
|
if e := t.WriteStatus(stream, st); e != nil {
|
|
|
|
grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status %v", e)
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
return err
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
if channelz.IsOn() {
|
|
|
|
t.IncrMsgRecv()
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
df := func(v interface{}) error {
|
2019-02-20 19:51:33 +01:00
|
|
|
if err := s.getCodec(stream.ContentSubtype()).Unmarshal(d, v); err != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
return status.Errorf(codes.Internal, "grpc: error unmarshalling request: %v", err)
|
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
if sh != nil {
|
|
|
|
sh.HandleRPC(stream.Context(), &stats.InPayload{
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
RecvTime: time.Now(),
|
|
|
|
Payload: v,
|
|
|
|
WireLength: payInfo.wireLength,
|
|
|
|
Data: d,
|
|
|
|
Length: len(d),
|
2019-02-20 19:51:33 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
if binlog != nil {
|
|
|
|
binlog.Log(&binarylog.ClientMessage{
|
|
|
|
Message: d,
|
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
if trInfo != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
trInfo.tr.LazyLog(&payload{sent: false, msg: v}, true)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
return nil
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
ctx := NewContextWithServerTransportStream(stream.Context(), stream)
|
|
|
|
reply, appErr := md.Handler(srv.server, ctx, df, s.opts.unaryInt)
|
2017-08-11 19:19:46 +02:00
|
|
|
if appErr != nil {
|
|
|
|
appStatus, ok := status.FromError(appErr)
|
|
|
|
if !ok {
|
|
|
|
// Convert appErr if it is not a grpc status error.
|
2018-09-24 18:30:39 +02:00
|
|
|
appErr = status.Error(codes.Unknown, appErr.Error())
|
2017-08-11 19:19:46 +02:00
|
|
|
appStatus, _ = status.FromError(appErr)
|
|
|
|
}
|
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(stringer(appStatus.Message()), true)
|
|
|
|
trInfo.tr.SetError()
|
|
|
|
}
|
|
|
|
if e := t.WriteStatus(stream, appStatus); e != nil {
|
|
|
|
grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status: %v", e)
|
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
if binlog != nil {
|
|
|
|
if h, _ := stream.Header(); h.Len() > 0 {
|
|
|
|
// Only log serverHeader if there was header. Otherwise it can
|
|
|
|
// be trailer only.
|
|
|
|
binlog.Log(&binarylog.ServerHeader{
|
|
|
|
Header: h,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
binlog.Log(&binarylog.ServerTrailer{
|
|
|
|
Trailer: stream.Trailer(),
|
|
|
|
Err: appErr,
|
|
|
|
})
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
return appErr
|
|
|
|
}
|
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(stringer("OK"), false)
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
opts := &transport.Options{Last: true}
|
|
|
|
|
|
|
|
if err := s.sendResponse(t, stream, reply, cp, opts, comp); err != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
if err == io.EOF {
|
|
|
|
// The entire stream is done (for unary RPC only).
|
|
|
|
return err
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
if s, ok := status.FromError(err); ok {
|
|
|
|
if e := t.WriteStatus(stream, s); e != nil {
|
|
|
|
grpclog.Warningf("grpc: Server.processUnaryRPC failed to write status: %v", e)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch st := err.(type) {
|
2017-01-20 16:59:14 +01:00
|
|
|
case transport.ConnectionError:
|
|
|
|
// Nothing to do here.
|
|
|
|
default:
|
2017-08-11 19:19:46 +02:00
|
|
|
panic(fmt.Sprintf("grpc: Unexpected error (%T) from sendResponse: %v", st, st))
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
if binlog != nil {
|
|
|
|
h, _ := stream.Header()
|
|
|
|
binlog.Log(&binarylog.ServerHeader{
|
|
|
|
Header: h,
|
|
|
|
})
|
|
|
|
binlog.Log(&binarylog.ServerTrailer{
|
|
|
|
Trailer: stream.Trailer(),
|
|
|
|
Err: appErr,
|
|
|
|
})
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
return err
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
if binlog != nil {
|
|
|
|
h, _ := stream.Header()
|
|
|
|
binlog.Log(&binarylog.ServerHeader{
|
|
|
|
Header: h,
|
|
|
|
})
|
|
|
|
binlog.Log(&binarylog.ServerMessage{
|
|
|
|
Message: reply,
|
|
|
|
})
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
if channelz.IsOn() {
|
|
|
|
t.IncrMsgSent()
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(&payload{sent: true, msg: reply}, true)
|
|
|
|
}
|
|
|
|
// TODO: Should we be logging if writing status failed here, like above?
|
|
|
|
// Should the logging be in WriteStatus? Should we ignore the WriteStatus
|
|
|
|
// error or allow the stats handler to see it?
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
err = t.WriteStatus(stream, statusOK)
|
2019-02-20 19:51:33 +01:00
|
|
|
if binlog != nil {
|
|
|
|
binlog.Log(&binarylog.ServerTrailer{
|
|
|
|
Trailer: stream.Trailer(),
|
|
|
|
Err: appErr,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return err
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) processStreamingRPC(t transport.ServerTransport, stream *transport.Stream, srv *service, sd *StreamDesc, trInfo *traceInfo) (err error) {
|
2018-09-24 18:30:39 +02:00
|
|
|
if channelz.IsOn() {
|
|
|
|
s.incrCallsStarted()
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
sh := s.opts.statsHandler
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
var statsBegin *stats.Begin
|
2017-01-20 16:59:14 +01:00
|
|
|
if sh != nil {
|
2018-09-24 18:30:39 +02:00
|
|
|
beginTime := time.Now()
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
statsBegin = &stats.Begin{
|
2018-09-24 18:30:39 +02:00
|
|
|
BeginTime: beginTime,
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
sh.HandleRPC(stream.Context(), statsBegin)
|
2017-08-11 19:19:46 +02:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
ctx := NewContextWithServerTransportStream(stream.Context(), stream)
|
2017-01-20 16:59:14 +01:00
|
|
|
ss := &serverStream{
|
2019-02-20 19:51:33 +01:00
|
|
|
ctx: ctx,
|
|
|
|
t: t,
|
|
|
|
s: stream,
|
|
|
|
p: &parser{r: stream},
|
|
|
|
codec: s.getCodec(stream.ContentSubtype()),
|
2017-08-11 19:19:46 +02:00
|
|
|
maxReceiveMessageSize: s.opts.maxReceiveMessageSize,
|
|
|
|
maxSendMessageSize: s.opts.maxSendMessageSize,
|
|
|
|
trInfo: trInfo,
|
|
|
|
statsHandler: sh,
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
if sh != nil || trInfo != nil || channelz.IsOn() {
|
|
|
|
// See comment in processUnaryRPC on defers.
|
|
|
|
defer func() {
|
|
|
|
if trInfo != nil {
|
|
|
|
ss.mu.Lock()
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
ss.trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
|
|
|
|
ss.trInfo.tr.SetError()
|
|
|
|
}
|
|
|
|
ss.trInfo.tr.Finish()
|
|
|
|
ss.trInfo.tr = nil
|
|
|
|
ss.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
|
|
|
if sh != nil {
|
|
|
|
end := &stats.End{
|
|
|
|
BeginTime: statsBegin.BeginTime,
|
|
|
|
EndTime: time.Now(),
|
|
|
|
}
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
end.Error = toRPCErr(err)
|
|
|
|
}
|
|
|
|
sh.HandleRPC(stream.Context(), end)
|
|
|
|
}
|
|
|
|
|
|
|
|
if channelz.IsOn() {
|
|
|
|
if err != nil && err != io.EOF {
|
|
|
|
s.incrCallsFailed()
|
|
|
|
} else {
|
|
|
|
s.incrCallsSucceeded()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2019-02-20 19:51:33 +01:00
|
|
|
ss.binlog = binarylog.GetMethodLogger(stream.Method())
|
|
|
|
if ss.binlog != nil {
|
|
|
|
md, _ := metadata.FromIncomingContext(ctx)
|
|
|
|
logEntry := &binarylog.ClientHeader{
|
|
|
|
Header: md,
|
|
|
|
MethodName: stream.Method(),
|
|
|
|
PeerAddr: nil,
|
|
|
|
}
|
|
|
|
if deadline, ok := ctx.Deadline(); ok {
|
2019-07-30 00:19:40 +02:00
|
|
|
logEntry.Timeout = time.Until(deadline)
|
2019-02-20 19:51:33 +01:00
|
|
|
if logEntry.Timeout < 0 {
|
|
|
|
logEntry.Timeout = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if a := md[":authority"]; len(a) > 0 {
|
|
|
|
logEntry.Authority = a[0]
|
|
|
|
}
|
|
|
|
if peer, ok := peer.FromContext(ss.Context()); ok {
|
|
|
|
logEntry.PeerAddr = peer.Addr
|
|
|
|
}
|
|
|
|
ss.binlog.Log(logEntry)
|
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// If dc is set and matches the stream's compression, use it. Otherwise, try
|
|
|
|
// to find a matching registered compressor for decomp.
|
|
|
|
if rc := stream.RecvCompress(); s.opts.dc != nil && s.opts.dc.Type() == rc {
|
|
|
|
ss.dc = s.opts.dc
|
|
|
|
} else if rc != "" && rc != encoding.Identity {
|
|
|
|
ss.decomp = encoding.GetCompressor(rc)
|
|
|
|
if ss.decomp == nil {
|
|
|
|
st := status.Newf(codes.Unimplemented, "grpc: Decompressor is not installed for grpc-encoding %q", rc)
|
|
|
|
t.WriteStatus(ss.s, st)
|
|
|
|
return st.Err()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If cp is set, use it. Otherwise, attempt to compress the response using
|
|
|
|
// the incoming message compression method.
|
|
|
|
//
|
|
|
|
// NOTE: this needs to be ahead of all handling, https://github.com/grpc/grpc-go/issues/686.
|
|
|
|
if s.opts.cp != nil {
|
|
|
|
ss.cp = s.opts.cp
|
|
|
|
stream.SetSendCompress(s.opts.cp.Type())
|
|
|
|
} else if rc := stream.RecvCompress(); rc != "" && rc != encoding.Identity {
|
|
|
|
// Legacy compressor not specified; attempt to respond with same encoding.
|
|
|
|
ss.comp = encoding.GetCompressor(rc)
|
|
|
|
if ss.comp != nil {
|
|
|
|
stream.SetSendCompress(rc)
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(&trInfo.firstLine, false)
|
|
|
|
}
|
|
|
|
var appErr error
|
2017-08-11 19:19:46 +02:00
|
|
|
var server interface{}
|
|
|
|
if srv != nil {
|
|
|
|
server = srv.server
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
if s.opts.streamInt == nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
appErr = sd.Handler(server, ss)
|
2017-01-20 16:59:14 +01:00
|
|
|
} else {
|
|
|
|
info := &StreamServerInfo{
|
|
|
|
FullMethod: stream.Method(),
|
|
|
|
IsClientStream: sd.ClientStreams,
|
|
|
|
IsServerStream: sd.ServerStreams,
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
appErr = s.opts.streamInt(server, ss, info, sd.Handler)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
if appErr != nil {
|
2017-08-11 19:19:46 +02:00
|
|
|
appStatus, ok := status.FromError(appErr)
|
|
|
|
if !ok {
|
2018-09-24 18:30:39 +02:00
|
|
|
appStatus = status.New(codes.Unknown, appErr.Error())
|
2017-08-11 19:19:46 +02:00
|
|
|
appErr = appStatus.Err()
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
if trInfo != nil {
|
|
|
|
ss.mu.Lock()
|
|
|
|
ss.trInfo.tr.LazyLog(stringer(appStatus.Message()), true)
|
|
|
|
ss.trInfo.tr.SetError()
|
|
|
|
ss.mu.Unlock()
|
|
|
|
}
|
|
|
|
t.WriteStatus(ss.s, appStatus)
|
2019-02-20 19:51:33 +01:00
|
|
|
if ss.binlog != nil {
|
|
|
|
ss.binlog.Log(&binarylog.ServerTrailer{
|
|
|
|
Trailer: ss.s.Trailer(),
|
|
|
|
Err: appErr,
|
|
|
|
})
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
// TODO: Should we log an error from WriteStatus here and below?
|
|
|
|
return appErr
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
if trInfo != nil {
|
|
|
|
ss.mu.Lock()
|
2017-08-11 19:19:46 +02:00
|
|
|
ss.trInfo.tr.LazyLog(stringer("OK"), false)
|
2017-01-20 16:59:14 +01:00
|
|
|
ss.mu.Unlock()
|
|
|
|
}
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
err = t.WriteStatus(ss.s, statusOK)
|
2019-02-20 19:51:33 +01:00
|
|
|
if ss.binlog != nil {
|
|
|
|
ss.binlog.Log(&binarylog.ServerTrailer{
|
|
|
|
Trailer: ss.s.Trailer(),
|
|
|
|
Err: appErr,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return err
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) handleStream(t transport.ServerTransport, stream *transport.Stream, trInfo *traceInfo) {
|
|
|
|
sm := stream.Method()
|
|
|
|
if sm != "" && sm[0] == '/' {
|
|
|
|
sm = sm[1:]
|
|
|
|
}
|
|
|
|
pos := strings.LastIndex(sm, "/")
|
|
|
|
if pos == -1 {
|
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(&fmtStringer{"Malformed method name %q", []interface{}{sm}}, true)
|
|
|
|
trInfo.tr.SetError()
|
|
|
|
}
|
|
|
|
errDesc := fmt.Sprintf("malformed method name: %q", stream.Method())
|
2017-08-11 19:19:46 +02:00
|
|
|
if err := t.WriteStatus(stream, status.New(codes.ResourceExhausted, errDesc)); err != nil {
|
2017-01-20 16:59:14 +01:00
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
|
|
|
|
trInfo.tr.SetError()
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
grpclog.Warningf("grpc: Server.handleStream failed to write status: %v", err)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.Finish()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
service := sm[:pos]
|
|
|
|
method := sm[pos+1:]
|
2019-02-20 19:51:33 +01:00
|
|
|
|
2019-09-09 14:04:58 +02:00
|
|
|
srv, knownService := s.m[service]
|
|
|
|
if knownService {
|
2019-02-20 19:51:33 +01:00
|
|
|
if md, ok := srv.md[method]; ok {
|
|
|
|
s.processUnaryRPC(t, stream, srv, md, trInfo)
|
2017-08-11 19:19:46 +02:00
|
|
|
return
|
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
if sd, ok := srv.sd[method]; ok {
|
|
|
|
s.processStreamingRPC(t, stream, srv, sd, trInfo)
|
|
|
|
return
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
// Unknown service, or known server unknown method.
|
|
|
|
if unknownDesc := s.opts.unknownStreamDesc; unknownDesc != nil {
|
|
|
|
s.processStreamingRPC(t, stream, nil, unknownDesc, trInfo)
|
2017-01-20 16:59:14 +01:00
|
|
|
return
|
|
|
|
}
|
2019-09-09 14:04:58 +02:00
|
|
|
var errDesc string
|
|
|
|
if !knownService {
|
|
|
|
errDesc = fmt.Sprintf("unknown service %v", service)
|
|
|
|
} else {
|
|
|
|
errDesc = fmt.Sprintf("unknown method %v for service %v", method, service)
|
|
|
|
}
|
2017-01-20 16:59:14 +01:00
|
|
|
if trInfo != nil {
|
2019-09-09 14:04:58 +02:00
|
|
|
trInfo.tr.LazyPrintf("%s", errDesc)
|
2017-01-20 16:59:14 +01:00
|
|
|
trInfo.tr.SetError()
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
if err := t.WriteStatus(stream, status.New(codes.Unimplemented, errDesc)); err != nil {
|
2017-01-20 16:59:14 +01:00
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.LazyLog(&fmtStringer{"%v", []interface{}{err}}, true)
|
|
|
|
trInfo.tr.SetError()
|
|
|
|
}
|
2017-08-11 19:19:46 +02:00
|
|
|
grpclog.Warningf("grpc: Server.handleStream failed to write status: %v", err)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
if trInfo != nil {
|
|
|
|
trInfo.tr.Finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// The key to save ServerTransportStream in the context.
|
|
|
|
type streamKey struct{}
|
|
|
|
|
|
|
|
// NewContextWithServerTransportStream creates a new context from ctx and
|
|
|
|
// attaches stream to it.
|
|
|
|
//
|
|
|
|
// This API is EXPERIMENTAL.
|
|
|
|
func NewContextWithServerTransportStream(ctx context.Context, stream ServerTransportStream) context.Context {
|
|
|
|
return context.WithValue(ctx, streamKey{}, stream)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServerTransportStream is a minimal interface that a transport stream must
|
|
|
|
// implement. This can be used to mock an actual transport stream for tests of
|
|
|
|
// handler code that use, for example, grpc.SetHeader (which requires some
|
|
|
|
// stream to be in context).
|
|
|
|
//
|
|
|
|
// See also NewContextWithServerTransportStream.
|
|
|
|
//
|
|
|
|
// This API is EXPERIMENTAL.
|
|
|
|
type ServerTransportStream interface {
|
|
|
|
Method() string
|
|
|
|
SetHeader(md metadata.MD) error
|
|
|
|
SendHeader(md metadata.MD) error
|
|
|
|
SetTrailer(md metadata.MD) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// ServerTransportStreamFromContext returns the ServerTransportStream saved in
|
|
|
|
// ctx. Returns nil if the given context has no stream associated with it
|
|
|
|
// (which implies it is not an RPC invocation context).
|
|
|
|
//
|
|
|
|
// This API is EXPERIMENTAL.
|
|
|
|
func ServerTransportStreamFromContext(ctx context.Context) ServerTransportStream {
|
|
|
|
s, _ := ctx.Value(streamKey{}).(ServerTransportStream)
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
// Stop stops the gRPC server. It immediately closes all open
|
|
|
|
// connections and listeners.
|
|
|
|
// It cancels all active RPCs on the server side and the corresponding
|
|
|
|
// pending RPCs on the client side will get notified by connection
|
|
|
|
// errors.
|
|
|
|
func (s *Server) Stop() {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
s.quit.Fire()
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
defer func() {
|
|
|
|
s.serveWG.Wait()
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
s.done.Fire()
|
2018-09-24 18:30:39 +02:00
|
|
|
}()
|
|
|
|
|
|
|
|
s.channelzRemoveOnce.Do(func() {
|
|
|
|
if channelz.IsOn() {
|
|
|
|
channelz.RemoveEntry(s.channelzID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
s.mu.Lock()
|
|
|
|
listeners := s.lis
|
|
|
|
s.lis = nil
|
|
|
|
st := s.conns
|
|
|
|
s.conns = nil
|
|
|
|
// interrupt GracefulStop if Stop and GracefulStop are called concurrently.
|
|
|
|
s.cv.Broadcast()
|
|
|
|
s.mu.Unlock()
|
|
|
|
|
|
|
|
for lis := range listeners {
|
|
|
|
lis.Close()
|
|
|
|
}
|
|
|
|
for c := range st {
|
|
|
|
c.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
s.mu.Lock()
|
|
|
|
if s.events != nil {
|
|
|
|
s.events.Finish()
|
|
|
|
s.events = nil
|
|
|
|
}
|
|
|
|
s.mu.Unlock()
|
|
|
|
}
|
|
|
|
|
2017-08-11 19:19:46 +02:00
|
|
|
// GracefulStop stops the gRPC server gracefully. It stops the server from
|
|
|
|
// accepting new connections and RPCs and blocks until all the pending RPCs are
|
|
|
|
// finished.
|
2017-01-20 16:59:14 +01:00
|
|
|
func (s *Server) GracefulStop() {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
s.quit.Fire()
|
|
|
|
defer s.done.Fire()
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
s.channelzRemoveOnce.Do(func() {
|
|
|
|
if channelz.IsOn() {
|
|
|
|
channelz.RemoveEntry(s.channelzID)
|
|
|
|
}
|
|
|
|
})
|
2017-01-20 16:59:14 +01:00
|
|
|
s.mu.Lock()
|
|
|
|
if s.conns == nil {
|
2018-09-24 18:30:39 +02:00
|
|
|
s.mu.Unlock()
|
2017-01-20 16:59:14 +01:00
|
|
|
return
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
for lis := range s.lis {
|
|
|
|
lis.Close()
|
|
|
|
}
|
|
|
|
s.lis = nil
|
|
|
|
if !s.drain {
|
command: Unmanaged providers
This adds supports for "unmanaged" providers, or providers with process
lifecycles not controlled by Terraform. These providers are assumed to
be started before Terraform is launched, and are assumed to shut
themselves down after Terraform has finished running.
To do this, we must update the go-plugin dependency to v1.3.0, which
added support for the "test mode" plugin serving that powers all this.
As a side-effect of not needing to manage the process lifecycle anymore,
Terraform also no longer needs to worry about the provider's binary, as
it won't be used for anything anymore. Because of this, we can disable
the init behavior that concerns itself with downloading that provider's
binary, checking its version, and otherwise managing the binary.
This is all managed on a per-provider basis, so managed providers that
Terraform downloads, starts, and stops can be used in the same commands
as unmanaged providers. The TF_REATTACH_PROVIDERS environment variable
is added, and is a JSON encoding of the provider's address to the
information we need to connect to it.
This change enables two benefits: first, delve and other debuggers can
now be attached to provider server processes, and Terraform can connect.
This allows for attaching debuggers to provider processes, which before
was difficult to impossible. Second, it allows the SDK test framework to
host the provider in the same process as the test driver, while running
a production Terraform binary against the provider. This allows for Go's
built-in race detector and test coverage tooling to work as expected in
provider tests.
Unmanaged providers are expected to work in the exact same way as
managed providers, with one caveat: Terraform kills provider processes
and restarts them once per graph walk, meaning multiple times during
most Terraform CLI commands. As unmanaged providers can't be killed by
Terraform, and have no visibility into graph walks, unmanaged providers
are likely to have differences in how their global mutable state behaves
when compared to managed providers. Namely, unmanaged providers are
likely to retain global state when managed providers would have reset
it. Developers relying on global state should be aware of this.
2020-05-27 02:48:57 +02:00
|
|
|
for st := range s.conns {
|
|
|
|
st.Drain()
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
s.drain = true
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
// Wait for serving threads to be ready to exit. Only then can we be sure no
|
|
|
|
// new conns will be created.
|
|
|
|
s.mu.Unlock()
|
|
|
|
s.serveWG.Wait()
|
|
|
|
s.mu.Lock()
|
|
|
|
|
2017-01-20 16:59:14 +01:00
|
|
|
for len(s.conns) != 0 {
|
|
|
|
s.cv.Wait()
|
|
|
|
}
|
|
|
|
s.conns = nil
|
|
|
|
if s.events != nil {
|
|
|
|
s.events.Finish()
|
|
|
|
s.events = nil
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
s.mu.Unlock()
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
2018-09-24 18:30:39 +02:00
|
|
|
// contentSubtype must be lowercase
|
|
|
|
// cannot return nil
|
|
|
|
func (s *Server) getCodec(contentSubtype string) baseCodec {
|
|
|
|
if s.opts.codec != nil {
|
|
|
|
return s.opts.codec
|
2018-07-26 22:32:32 +02:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
if contentSubtype == "" {
|
|
|
|
return encoding.GetCodec(proto.Name)
|
|
|
|
}
|
|
|
|
codec := encoding.GetCodec(contentSubtype)
|
|
|
|
if codec == nil {
|
|
|
|
return encoding.GetCodec(proto.Name)
|
|
|
|
}
|
|
|
|
return codec
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetHeader sets the header metadata.
|
|
|
|
// When called multiple times, all the provided metadata will be merged.
|
|
|
|
// All the metadata will be sent out when one of the following happens:
|
|
|
|
// - grpc.SendHeader() is called;
|
|
|
|
// - The first response is sent out;
|
|
|
|
// - An RPC status is sent out (error or success).
|
|
|
|
func SetHeader(ctx context.Context, md metadata.MD) error {
|
|
|
|
if md.Len() == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
stream := ServerTransportStreamFromContext(ctx)
|
|
|
|
if stream == nil {
|
|
|
|
return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
return stream.SetHeader(md)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendHeader sends header metadata. It may be called at most once.
|
|
|
|
// The provided md and headers set by SetHeader() will be sent.
|
|
|
|
func SendHeader(ctx context.Context, md metadata.MD) error {
|
2018-09-24 18:30:39 +02:00
|
|
|
stream := ServerTransportStreamFromContext(ctx)
|
|
|
|
if stream == nil {
|
|
|
|
return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
if err := stream.SendHeader(md); err != nil {
|
2017-01-20 16:59:14 +01:00
|
|
|
return toRPCErr(err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetTrailer sets the trailer metadata that will be sent when an RPC returns.
|
|
|
|
// When called more than once, all the provided metadata will be merged.
|
|
|
|
func SetTrailer(ctx context.Context, md metadata.MD) error {
|
|
|
|
if md.Len() == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
stream := ServerTransportStreamFromContext(ctx)
|
|
|
|
if stream == nil {
|
|
|
|
return status.Errorf(codes.Internal, "grpc: failed to fetch the stream from the context %v", ctx)
|
2017-01-20 16:59:14 +01:00
|
|
|
}
|
|
|
|
return stream.SetTrailer(md)
|
|
|
|
}
|
2018-09-24 18:30:39 +02:00
|
|
|
|
|
|
|
// Method returns the method string for the server context. The returned
|
|
|
|
// string is in the format of "/service/method".
|
|
|
|
func Method(ctx context.Context) (string, bool) {
|
|
|
|
s := ServerTransportStreamFromContext(ctx)
|
|
|
|
if s == nil {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
return s.Method(), true
|
|
|
|
}
|
2019-02-20 19:51:33 +01:00
|
|
|
|
|
|
|
type channelzServer struct {
|
|
|
|
s *Server
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *channelzServer) ChannelzMetric() *channelz.ServerInternalMetric {
|
|
|
|
return c.s.channelzMetric()
|
|
|
|
}
|