go.temporal.io/server@v1.23.0/common/rpc/rpc.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package rpc
    26  
    27  import (
    28  	"crypto/tls"
    29  	"net"
    30  	"sync"
    31  
    32  	"google.golang.org/grpc"
    33  	"google.golang.org/grpc/credentials"
    34  
    35  	"go.temporal.io/server/common"
    36  	"go.temporal.io/server/common/config"
    37  	"go.temporal.io/server/common/convert"
    38  	"go.temporal.io/server/common/log"
    39  	"go.temporal.io/server/common/log/tag"
    40  	"go.temporal.io/server/common/primitives"
    41  	"go.temporal.io/server/common/rpc/encryption"
    42  	"go.temporal.io/server/environment"
    43  )
    44  
    45  var _ common.RPCFactory = (*RPCFactory)(nil)
    46  
    47  // RPCFactory is an implementation of common.RPCFactory interface
    48  type RPCFactory struct {
    49  	config      *config.RPC
    50  	serviceName primitives.ServiceName
    51  	logger      log.Logger
    52  
    53  	frontendURL       string
    54  	frontendTLSConfig *tls.Config
    55  
    56  	initListener       sync.Once
    57  	grpcListener       net.Listener
    58  	tlsFactory         encryption.TLSConfigProvider
    59  	clientInterceptors []grpc.UnaryClientInterceptor
    60  }
    61  
    62  // NewFactory builds a new RPCFactory
    63  // conforming to the underlying configuration
    64  func NewFactory(
    65  	cfg *config.RPC,
    66  	sName primitives.ServiceName,
    67  	logger log.Logger,
    68  	tlsProvider encryption.TLSConfigProvider,
    69  	frontendURL string,
    70  	frontendTLSConfig *tls.Config,
    71  	clientInterceptors []grpc.UnaryClientInterceptor,
    72  ) *RPCFactory {
    73  	return &RPCFactory{
    74  		config:             cfg,
    75  		serviceName:        sName,
    76  		logger:             logger,
    77  		frontendURL:        frontendURL,
    78  		frontendTLSConfig:  frontendTLSConfig,
    79  		tlsFactory:         tlsProvider,
    80  		clientInterceptors: clientInterceptors,
    81  	}
    82  }
    83  
    84  func (d *RPCFactory) GetFrontendGRPCServerOptions() ([]grpc.ServerOption, error) {
    85  	var opts []grpc.ServerOption
    86  
    87  	if d.tlsFactory != nil {
    88  		serverConfig, err := d.tlsFactory.GetFrontendServerConfig()
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  		if serverConfig == nil {
    93  			return opts, nil
    94  		}
    95  		opts = append(opts, grpc.Creds(credentials.NewTLS(serverConfig)))
    96  	}
    97  
    98  	return opts, nil
    99  }
   100  
   101  func (d *RPCFactory) GetFrontendClientTlsConfig() (*tls.Config, error) {
   102  	if d.tlsFactory != nil {
   103  		return d.tlsFactory.GetFrontendClientConfig()
   104  	}
   105  
   106  	return nil, nil
   107  }
   108  
   109  func (d *RPCFactory) GetRemoteClusterClientConfig(hostname string) (*tls.Config, error) {
   110  	if d.tlsFactory != nil {
   111  		return d.tlsFactory.GetRemoteClusterClientConfig(hostname)
   112  	}
   113  
   114  	return nil, nil
   115  }
   116  
   117  func (d *RPCFactory) GetInternodeGRPCServerOptions() ([]grpc.ServerOption, error) {
   118  	var opts []grpc.ServerOption
   119  
   120  	if d.tlsFactory != nil {
   121  		serverConfig, err := d.tlsFactory.GetInternodeServerConfig()
   122  		if err != nil {
   123  			return nil, err
   124  		}
   125  		if serverConfig == nil {
   126  			return opts, nil
   127  		}
   128  		opts = append(opts, grpc.Creds(credentials.NewTLS(serverConfig)))
   129  	}
   130  
   131  	return opts, nil
   132  }
   133  
   134  func (d *RPCFactory) GetInternodeClientTlsConfig() (*tls.Config, error) {
   135  	if d.tlsFactory != nil {
   136  		return d.tlsFactory.GetInternodeClientConfig()
   137  	}
   138  
   139  	return nil, nil
   140  }
   141  
   142  // GetGRPCListener returns cached dispatcher for gRPC inbound or creates one
   143  func (d *RPCFactory) GetGRPCListener() net.Listener {
   144  	d.initListener.Do(func() {
   145  		hostAddress := net.JoinHostPort(getListenIP(d.config, d.logger).String(), convert.IntToString(d.config.GRPCPort))
   146  		var err error
   147  		d.grpcListener, err = net.Listen("tcp", hostAddress)
   148  
   149  		if err != nil {
   150  			d.logger.Fatal("Failed to start gRPC listener", tag.Error(err), tag.Service(d.serviceName), tag.Address(hostAddress))
   151  		}
   152  
   153  		d.logger.Info("Created gRPC listener", tag.Service(d.serviceName), tag.Address(hostAddress))
   154  	})
   155  
   156  	return d.grpcListener
   157  }
   158  
   159  func getListenIP(cfg *config.RPC, logger log.Logger) net.IP {
   160  	if cfg.BindOnLocalHost && len(cfg.BindOnIP) > 0 {
   161  		logger.Fatal("ListenIP failed, bindOnLocalHost and bindOnIP are mutually exclusive")
   162  		return nil
   163  	}
   164  
   165  	if cfg.BindOnLocalHost {
   166  		return net.ParseIP(environment.GetLocalhostIP())
   167  	}
   168  
   169  	if len(cfg.BindOnIP) > 0 {
   170  		ip := net.ParseIP(cfg.BindOnIP)
   171  		if ip != nil {
   172  			return ip
   173  		}
   174  		logger.Fatal("ListenIP failed, unable to parse bindOnIP value", tag.Address(cfg.BindOnIP))
   175  		return nil
   176  	}
   177  	ip, err := config.ListenIP()
   178  	if err != nil {
   179  		logger.Fatal("ListenIP failed", tag.Error(err))
   180  		return nil
   181  	}
   182  	return ip
   183  }
   184  
   185  // CreateRemoteFrontendGRPCConnection creates connection for gRPC calls
   186  func (d *RPCFactory) CreateRemoteFrontendGRPCConnection(rpcAddress string) *grpc.ClientConn {
   187  	var tlsClientConfig *tls.Config
   188  	var err error
   189  	if d.tlsFactory != nil {
   190  		hostname, _, err2 := net.SplitHostPort(rpcAddress)
   191  		if err2 != nil {
   192  			d.logger.Fatal("Invalid rpcAddress for remote cluster", tag.Error(err2))
   193  		}
   194  		tlsClientConfig, err = d.tlsFactory.GetRemoteClusterClientConfig(hostname)
   195  
   196  		if err != nil {
   197  			d.logger.Fatal("Failed to create tls config for gRPC connection", tag.Error(err))
   198  			return nil
   199  		}
   200  	}
   201  
   202  	return d.dial(rpcAddress, tlsClientConfig)
   203  }
   204  
   205  // CreateLocalFrontendGRPCConnection creates connection for internal frontend calls
   206  func (d *RPCFactory) CreateLocalFrontendGRPCConnection() *grpc.ClientConn {
   207  	return d.dial(d.frontendURL, d.frontendTLSConfig)
   208  }
   209  
   210  // CreateInternodeGRPCConnection creates connection for gRPC calls
   211  func (d *RPCFactory) CreateInternodeGRPCConnection(hostName string) *grpc.ClientConn {
   212  	var tlsClientConfig *tls.Config
   213  	var err error
   214  	if d.tlsFactory != nil {
   215  		tlsClientConfig, err = d.tlsFactory.GetInternodeClientConfig()
   216  		if err != nil {
   217  			d.logger.Fatal("Failed to create tls config for gRPC connection", tag.Error(err))
   218  			return nil
   219  		}
   220  	}
   221  
   222  	return d.dial(hostName, tlsClientConfig)
   223  }
   224  
   225  func (d *RPCFactory) dial(hostName string, tlsClientConfig *tls.Config) *grpc.ClientConn {
   226  	connection, err := Dial(hostName, tlsClientConfig, d.logger, d.clientInterceptors...)
   227  	if err != nil {
   228  		d.logger.Fatal("Failed to create gRPC connection", tag.Error(err))
   229  		return nil
   230  	}
   231  
   232  	return connection
   233  }
   234  
   235  func (d *RPCFactory) GetTLSConfigProvider() encryption.TLSConfigProvider {
   236  	return d.tlsFactory
   237  }