github.com/pachyderm/pachyderm@v1.13.4/src/server/cmd/pachd/main.go (about)

     1  package main
     2  
     3  import (
     4  	gotls "crypto/tls"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"os"
     9  	"path"
    10  	"runtime/debug"
    11  	"runtime/pprof"
    12  	"strconv"
    13  
    14  	adminclient "github.com/pachyderm/pachyderm/src/client/admin"
    15  	authclient "github.com/pachyderm/pachyderm/src/client/auth"
    16  	debugclient "github.com/pachyderm/pachyderm/src/client/debug"
    17  	eprsclient "github.com/pachyderm/pachyderm/src/client/enterprise"
    18  	healthclient "github.com/pachyderm/pachyderm/src/client/health"
    19  	pfsclient "github.com/pachyderm/pachyderm/src/client/pfs"
    20  	"github.com/pachyderm/pachyderm/src/client/pkg/discovery"
    21  	"github.com/pachyderm/pachyderm/src/client/pkg/errors"
    22  	"github.com/pachyderm/pachyderm/src/client/pkg/grpcutil"
    23  	"github.com/pachyderm/pachyderm/src/client/pkg/shard"
    24  	"github.com/pachyderm/pachyderm/src/client/pkg/tracing"
    25  	ppsclient "github.com/pachyderm/pachyderm/src/client/pps"
    26  	transactionclient "github.com/pachyderm/pachyderm/src/client/transaction"
    27  	"github.com/pachyderm/pachyderm/src/client/version"
    28  	"github.com/pachyderm/pachyderm/src/client/version/versionpb"
    29  	adminserver "github.com/pachyderm/pachyderm/src/server/admin/server"
    30  	auth_iface "github.com/pachyderm/pachyderm/src/server/auth"
    31  	authserver "github.com/pachyderm/pachyderm/src/server/auth/server"
    32  	debugserver "github.com/pachyderm/pachyderm/src/server/debug/server"
    33  	eprsserver "github.com/pachyderm/pachyderm/src/server/enterprise/server"
    34  	"github.com/pachyderm/pachyderm/src/server/health"
    35  	pach_http "github.com/pachyderm/pachyderm/src/server/http"
    36  	pfs_iface "github.com/pachyderm/pachyderm/src/server/pfs"
    37  	"github.com/pachyderm/pachyderm/src/server/pfs/s3"
    38  	pfs_server "github.com/pachyderm/pachyderm/src/server/pfs/server"
    39  	cache_pb "github.com/pachyderm/pachyderm/src/server/pkg/cache/groupcachepb"
    40  	cache_server "github.com/pachyderm/pachyderm/src/server/pkg/cache/server"
    41  	"github.com/pachyderm/pachyderm/src/server/pkg/cmdutil"
    42  	col "github.com/pachyderm/pachyderm/src/server/pkg/collection"
    43  	"github.com/pachyderm/pachyderm/src/server/pkg/deploy/assets"
    44  	"github.com/pachyderm/pachyderm/src/server/pkg/hashtree"
    45  	logutil "github.com/pachyderm/pachyderm/src/server/pkg/log"
    46  	"github.com/pachyderm/pachyderm/src/server/pkg/metrics"
    47  	"github.com/pachyderm/pachyderm/src/server/pkg/netutil"
    48  	"github.com/pachyderm/pachyderm/src/server/pkg/serviceenv"
    49  	txnenv "github.com/pachyderm/pachyderm/src/server/pkg/transactionenv"
    50  	"github.com/pachyderm/pachyderm/src/server/pkg/uuid"
    51  	pps_iface "github.com/pachyderm/pachyderm/src/server/pps"
    52  	pps_server "github.com/pachyderm/pachyderm/src/server/pps/server"
    53  	"github.com/pachyderm/pachyderm/src/server/pps/server/githook"
    54  	txnserver "github.com/pachyderm/pachyderm/src/server/transaction/server"
    55  	"go.uber.org/automaxprocs/maxprocs"
    56  
    57  	etcd "github.com/coreos/etcd/clientv3"
    58  	units "github.com/docker/go-units"
    59  	"github.com/pachyderm/pachyderm/src/client/pkg/tls"
    60  	"github.com/prometheus/client_golang/prometheus/promhttp"
    61  	log "github.com/sirupsen/logrus"
    62  	flag "github.com/spf13/pflag"
    63  	"golang.org/x/net/context"
    64  	"google.golang.org/grpc"
    65  )
    66  
    67  const (
    68  	defaultTreeCacheSize = 8
    69  )
    70  
    71  var mode string
    72  var readiness bool
    73  
    74  func init() {
    75  	flag.StringVar(&mode, "mode", "full", "Pachd currently supports two modes: full and sidecar.  The former includes everything you need in a full pachd node.  The latter runs only PFS, the Auth service, and a stripped-down version of PPS.")
    76  	flag.BoolVar(&readiness, "readiness", false, "Run readiness check.")
    77  	flag.Parse()
    78  }
    79  
    80  func main() {
    81  	log.SetFormatter(logutil.FormatterFunc(logutil.Pretty))
    82  	maxprocs.Set(maxprocs.Logger(log.Printf))
    83  
    84  	switch {
    85  	case readiness:
    86  		cmdutil.Main(doReadinessCheck, &serviceenv.PachdFullConfiguration{})
    87  	case mode == "full":
    88  		cmdutil.Main(doFullMode, &serviceenv.PachdFullConfiguration{})
    89  	case mode == "sidecar":
    90  		cmdutil.Main(doSidecarMode, &serviceenv.PachdFullConfiguration{})
    91  	default:
    92  		fmt.Printf("unrecognized mode: %s\n", mode)
    93  	}
    94  }
    95  
    96  func doReadinessCheck(config interface{}) error {
    97  	env := serviceenv.InitPachOnlyEnv(serviceenv.NewConfiguration(config))
    98  	return env.GetPachClient(context.Background()).Health()
    99  }
   100  
   101  func doSidecarMode(config interface{}) (retErr error) {
   102  	defer func() {
   103  		if retErr != nil {
   104  			pprof.Lookup("goroutine").WriteTo(os.Stderr, 2)
   105  		}
   106  	}()
   107  	switch logLevel := os.Getenv("LOG_LEVEL"); logLevel {
   108  	case "debug":
   109  		log.SetLevel(log.DebugLevel)
   110  	case "error":
   111  		log.SetLevel(log.ErrorLevel)
   112  	case "info", "":
   113  		log.SetLevel(log.InfoLevel)
   114  	default:
   115  		log.Errorf("Unrecognized log level %s, falling back to default of \"info\"", logLevel)
   116  		log.SetLevel(log.InfoLevel)
   117  	}
   118  	// must run InstallJaegerTracer before InitWithKube (otherwise InitWithKube
   119  	// may create a pach client before tracing is active, not install the Jaeger
   120  	// gRPC interceptor in the client, and not propagate traces)
   121  	if endpoint := tracing.InstallJaegerTracerFromEnv(); endpoint != "" {
   122  		log.Printf("connecting to Jaeger at %q", endpoint)
   123  	} else {
   124  		log.Printf("no Jaeger collector found (JAEGER_COLLECTOR_SERVICE_HOST not set)")
   125  	}
   126  	env := serviceenv.InitWithKube(serviceenv.NewConfiguration(config))
   127  	debug.SetGCPercent(env.GCPercent)
   128  	if env.EtcdPrefix == "" {
   129  		env.EtcdPrefix = col.DefaultPrefix
   130  	}
   131  	clusterID, err := getClusterID(env.GetEtcdClient())
   132  	if err != nil {
   133  		return errors.Wrapf(err, "getClusterID")
   134  	}
   135  	var reporter *metrics.Reporter
   136  	if env.Metrics {
   137  		reporter = metrics.NewReporter(clusterID, env)
   138  	}
   139  	pfsCacheSize, err := strconv.Atoi(env.PFSCacheSize)
   140  	if err != nil {
   141  		return errors.Wrapf(err, "atoi")
   142  	}
   143  	if pfsCacheSize == 0 {
   144  		pfsCacheSize = defaultTreeCacheSize
   145  	}
   146  	treeCache, err := hashtree.NewCache(pfsCacheSize)
   147  	if err != nil {
   148  		return errors.Wrapf(err, "lru.New")
   149  	}
   150  	server, err := grpcutil.NewServer(context.Background(), false)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	txnEnv := &txnenv.TransactionEnv{}
   155  	var blockAPIServer pfs_server.BlockAPIServer
   156  	if !env.StorageV2 {
   157  		blockCacheBytes, err := units.RAMInBytes(env.BlockCacheBytes)
   158  		if err != nil {
   159  			return errors.Wrapf(err, "units.RAMInBytes")
   160  		}
   161  		if err := logGRPCServerSetup("Block API", func() error {
   162  			var err error
   163  			blockAPIServer, err = pfs_server.NewBlockAPIServer(env.StorageRoot, blockCacheBytes, env.StorageBackend, net.JoinHostPort(env.EtcdHost, env.EtcdPort), false)
   164  			if err != nil {
   165  				return err
   166  			}
   167  			pfsclient.RegisterObjectAPIServer(server.Server, blockAPIServer)
   168  			return nil
   169  		}); err != nil {
   170  			return err
   171  		}
   172  	}
   173  	memoryRequestBytes, err := units.RAMInBytes(env.MemoryRequest)
   174  	if err != nil {
   175  		return err
   176  	}
   177  	var pfsAPIServer pfs_iface.APIServer
   178  	if err := logGRPCServerSetup("PFS API", func() error {
   179  		pfsAPIServer, err = pfs_server.NewAPIServer(
   180  			env,
   181  			txnEnv,
   182  			path.Join(env.EtcdPrefix, env.PFSEtcdPrefix),
   183  			treeCache,
   184  			env.StorageRoot,
   185  			memoryRequestBytes,
   186  			blockAPIServer,
   187  		)
   188  		if err != nil {
   189  			return err
   190  		}
   191  		pfsclient.RegisterAPIServer(server.Server, pfsAPIServer)
   192  		env.SetPfsServer(pfsAPIServer)
   193  		return nil
   194  	}); err != nil {
   195  		return err
   196  	}
   197  	var ppsAPIServer pps_iface.APIServer
   198  	if err := logGRPCServerSetup("PPS API", func() error {
   199  		ppsAPIServer, err = pps_server.NewSidecarAPIServer(
   200  			env,
   201  			txnEnv,
   202  			path.Join(env.EtcdPrefix, env.PPSEtcdPrefix),
   203  			env.Namespace,
   204  			env.IAMRole,
   205  			reporter,
   206  			env.PPSWorkerPort,
   207  			env.HTTPPort,
   208  			env.PeerPort,
   209  		)
   210  		if err != nil {
   211  			return err
   212  		}
   213  		ppsclient.RegisterAPIServer(server.Server, ppsAPIServer)
   214  		env.SetPpsServer(ppsAPIServer)
   215  		return nil
   216  	}); err != nil {
   217  		return err
   218  	}
   219  	var authAPIServer auth_iface.APIServer
   220  	if err := logGRPCServerSetup("Auth API", func() error {
   221  		authAPIServer, err = authserver.NewAuthServer(
   222  			env,
   223  			txnEnv,
   224  			path.Join(env.EtcdPrefix, env.AuthEtcdPrefix),
   225  			false,
   226  			false,
   227  		)
   228  		if err != nil {
   229  			return err
   230  		}
   231  		authclient.RegisterAPIServer(server.Server, authAPIServer)
   232  		env.SetAuthServer(authAPIServer)
   233  		return nil
   234  	}); err != nil {
   235  		return err
   236  	}
   237  	var transactionAPIServer txnserver.APIServer
   238  	if err := logGRPCServerSetup("Transaction API", func() error {
   239  		transactionAPIServer, err = txnserver.NewAPIServer(
   240  			env,
   241  			txnEnv,
   242  			path.Join(env.EtcdPrefix, env.PFSEtcdPrefix),
   243  		)
   244  		if err != nil {
   245  			return err
   246  		}
   247  		transactionclient.RegisterAPIServer(server.Server, transactionAPIServer)
   248  		return nil
   249  	}); err != nil {
   250  		return err
   251  	}
   252  	if err := logGRPCServerSetup("Enterprise API", func() error {
   253  		enterpriseAPIServer, err := eprsserver.NewEnterpriseServer(
   254  			env, path.Join(env.EtcdPrefix, env.EnterpriseEtcdPrefix))
   255  		if err != nil {
   256  			return err
   257  		}
   258  		eprsclient.RegisterAPIServer(server.Server, enterpriseAPIServer)
   259  		env.SetEnterpriseServer(enterpriseAPIServer)
   260  		return nil
   261  	}); err != nil {
   262  		return err
   263  	}
   264  	if err := logGRPCServerSetup("Health", func() error {
   265  		healthclient.RegisterHealthServer(server.Server, health.NewHealthServer())
   266  		return nil
   267  	}); err != nil {
   268  		return err
   269  	}
   270  	if err := logGRPCServerSetup("Debug", func() error {
   271  		debugclient.RegisterDebugServer(server.Server, debugserver.NewDebugServer(
   272  			env,
   273  			env.PachdPodName,
   274  			nil,
   275  		))
   276  		return nil
   277  	}); err != nil {
   278  		return err
   279  	}
   280  	txnEnv.Initialize(env, transactionAPIServer, authAPIServer, pfsAPIServer, ppsAPIServer)
   281  	// The sidecar only needs to serve traffic on the peer port, as it only serves
   282  	// traffic from the user container (the worker binary and occasionally user
   283  	// pipelines)
   284  	if _, err := server.ListenTCP("", env.PeerPort); err != nil {
   285  		return err
   286  	}
   287  	return server.Wait()
   288  }
   289  
   290  func doFullMode(config interface{}) (retErr error) {
   291  	defer func() {
   292  		if retErr != nil {
   293  			pprof.Lookup("goroutine").WriteTo(os.Stderr, 2)
   294  		}
   295  	}()
   296  	switch logLevel := os.Getenv("LOG_LEVEL"); logLevel {
   297  	case "debug":
   298  		log.SetLevel(log.DebugLevel)
   299  	case "error":
   300  		log.SetLevel(log.ErrorLevel)
   301  	case "info", "":
   302  		log.SetLevel(log.InfoLevel)
   303  	default:
   304  		log.Errorf("Unrecognized log level %s, falling back to default of \"info\"", logLevel)
   305  		log.SetLevel(log.InfoLevel)
   306  	}
   307  	// must run InstallJaegerTracer before InitWithKube/pach client initialization
   308  	if endpoint := tracing.InstallJaegerTracerFromEnv(); endpoint != "" {
   309  		log.Printf("connecting to Jaeger at %q", endpoint)
   310  	} else {
   311  		log.Printf("no Jaeger collector found (JAEGER_COLLECTOR_SERVICE_HOST not set)")
   312  	}
   313  	env := serviceenv.InitWithKube(serviceenv.NewConfiguration(config))
   314  	debug.SetGCPercent(env.GCPercent)
   315  	if env.EtcdPrefix == "" {
   316  		env.EtcdPrefix = col.DefaultPrefix
   317  	}
   318  	clusterID, err := getClusterID(env.GetEtcdClient())
   319  	if err != nil {
   320  		return errors.Wrapf(err, "getClusterID")
   321  	}
   322  	var reporter *metrics.Reporter
   323  	if env.Metrics {
   324  		reporter = metrics.NewReporter(clusterID, env)
   325  	}
   326  	// (bryce) Do we have to use etcd client v2 here for sharder? Might want to re-visit this later.
   327  	etcdAddress := fmt.Sprintf("http://%s", net.JoinHostPort(env.EtcdHost, env.EtcdPort))
   328  	etcdClientV2 := getEtcdClient(etcdAddress)
   329  	ip, err := netutil.ExternalIP()
   330  	if err != nil {
   331  		return errors.Wrapf(err, "error getting pachd external ip")
   332  	}
   333  	address := net.JoinHostPort(ip, fmt.Sprintf("%d", env.PeerPort))
   334  	sharder := shard.NewSharder(
   335  		etcdClientV2,
   336  		env.NumShards,
   337  		env.Namespace,
   338  	)
   339  	go func() {
   340  		if err := sharder.AssignRoles(address); err != nil {
   341  			log.Printf("error from sharder.AssignRoles: %s", grpcutil.ScrubGRPC(err))
   342  		}
   343  	}()
   344  	router := shard.NewRouter(
   345  		sharder,
   346  		grpcutil.NewDialer(
   347  			grpc.WithInsecure(),
   348  		),
   349  		address,
   350  	)
   351  	pfsCacheSize, err := strconv.Atoi(env.PFSCacheSize)
   352  	if err != nil {
   353  		return errors.Wrapf(err, "atoi")
   354  	}
   355  	if pfsCacheSize == 0 {
   356  		pfsCacheSize = defaultTreeCacheSize
   357  	}
   358  	treeCache, err := hashtree.NewCache(pfsCacheSize)
   359  	if err != nil {
   360  		return errors.Wrapf(err, "lru.New")
   361  	}
   362  	kubeNamespace := env.Namespace
   363  	requireNoncriticalServers := !env.RequireCriticalServersOnly
   364  	// Setup internal block gRPC server first so we can reference it from both the external and internal PFS gRPC servers.
   365  	internalServer, err := grpcutil.NewServer(context.Background(), false)
   366  	if err != nil {
   367  		return err
   368  	}
   369  	var blockAPIServer pfs_server.BlockAPIServer
   370  	if !env.StorageV2 {
   371  		blockCacheBytes, err := units.RAMInBytes(env.BlockCacheBytes)
   372  		if err != nil {
   373  			return errors.Wrapf(err, "units.RAMInBytes")
   374  		}
   375  		if err := logGRPCServerSetup("Block API", func() error {
   376  			var err error
   377  			blockAPIServer, err = pfs_server.NewBlockAPIServer(
   378  				env.StorageRoot, blockCacheBytes, env.StorageBackend, etcdAddress, false)
   379  			if err != nil {
   380  				return err
   381  			}
   382  			pfsclient.RegisterObjectAPIServer(internalServer.Server, blockAPIServer)
   383  			return nil
   384  		}); err != nil {
   385  			return err
   386  		}
   387  	}
   388  	// Setup External Pachd GRPC Server.
   389  	externalServer, err := grpcutil.NewServer(context.Background(), true)
   390  	if err != nil {
   391  		return err
   392  	}
   393  	if err := logGRPCServerSetup("External Pachd", func() error {
   394  		txnEnv := &txnenv.TransactionEnv{}
   395  		memoryRequestBytes, err := units.RAMInBytes(env.MemoryRequest)
   396  		if err != nil {
   397  			return err
   398  		}
   399  		var pfsAPIServer pfs_iface.APIServer
   400  		if err := logGRPCServerSetup("PFS API", func() error {
   401  			pfsAPIServer, err = pfs_server.NewAPIServer(env, txnEnv, path.Join(env.EtcdPrefix, env.PFSEtcdPrefix), treeCache, env.StorageRoot, memoryRequestBytes, blockAPIServer)
   402  			if err != nil {
   403  				return err
   404  			}
   405  			pfsclient.RegisterAPIServer(externalServer.Server, pfsAPIServer)
   406  			return nil
   407  		}); err != nil {
   408  			return err
   409  		}
   410  		var ppsAPIServer pps_iface.APIServer
   411  		if err := logGRPCServerSetup("PPS API", func() error {
   412  			ppsAPIServer, err = pps_server.NewAPIServer(
   413  				env,
   414  				txnEnv,
   415  				path.Join(env.EtcdPrefix, env.PPSEtcdPrefix),
   416  				kubeNamespace,
   417  				env.WorkerImage,
   418  				env.WorkerSidecarImage,
   419  				env.WorkerImagePullPolicy,
   420  				env.StorageRoot,
   421  				env.StorageBackend,
   422  				env.StorageHostPath,
   423  				env.CacheRoot,
   424  				env.IAMRole,
   425  				env.ImagePullSecret,
   426  				env.NoExposeDockerSocket,
   427  				reporter,
   428  				env.WorkerUsesRoot,
   429  				env.PPSWorkerPort,
   430  				env.Port,
   431  				env.HTTPPort,
   432  				env.PeerPort,
   433  				env.GCPercent,
   434  			)
   435  			if err != nil {
   436  				return err
   437  			}
   438  			ppsclient.RegisterAPIServer(externalServer.Server, ppsAPIServer)
   439  			return nil
   440  		}); err != nil {
   441  			return err
   442  		}
   443  		if !env.StorageV2 {
   444  			if env.ExposeObjectAPI {
   445  				if err := logGRPCServerSetup("Block API", func() error {
   446  					// Generally the object API should not be exposed publicly, but
   447  					// TestGarbageCollection uses it and it may help with debugging
   448  					blockAPIServer, err := pfs_server.NewBlockAPIServer(
   449  						env.StorageRoot,
   450  						0 /* = blockCacheBytes (disable cache) */, env.StorageBackend,
   451  						etcdAddress,
   452  						true /* duplicate */)
   453  					if err != nil {
   454  						return err
   455  					}
   456  					pfsclient.RegisterObjectAPIServer(externalServer.Server, blockAPIServer)
   457  					return nil
   458  				}); err != nil {
   459  					return err
   460  				}
   461  			}
   462  		}
   463  		var authAPIServer auth_iface.APIServer
   464  		if err := logGRPCServerSetup("Auth API", func() error {
   465  			authAPIServer, err = authserver.NewAuthServer(
   466  				env, txnEnv, path.Join(env.EtcdPrefix, env.AuthEtcdPrefix), true, requireNoncriticalServers)
   467  			if err != nil {
   468  				return err
   469  			}
   470  			authclient.RegisterAPIServer(externalServer.Server, authAPIServer)
   471  			return nil
   472  		}); err != nil {
   473  			return err
   474  		}
   475  		var transactionAPIServer txnserver.APIServer
   476  		if err := logGRPCServerSetup("Transaction API", func() error {
   477  			transactionAPIServer, err = txnserver.NewAPIServer(
   478  				env,
   479  				txnEnv,
   480  				path.Join(env.EtcdPrefix, env.PFSEtcdPrefix),
   481  			)
   482  			if err != nil {
   483  				return err
   484  			}
   485  			transactionclient.RegisterAPIServer(externalServer.Server, transactionAPIServer)
   486  			return nil
   487  		}); err != nil {
   488  			return err
   489  		}
   490  		if err := logGRPCServerSetup("Enterprise API", func() error {
   491  			enterpriseAPIServer, err := eprsserver.NewEnterpriseServer(
   492  				env, path.Join(env.EtcdPrefix, env.EnterpriseEtcdPrefix))
   493  			if err != nil {
   494  				return err
   495  			}
   496  			eprsclient.RegisterAPIServer(externalServer.Server, enterpriseAPIServer)
   497  			return nil
   498  		}); err != nil {
   499  			return err
   500  		}
   501  		if err := logGRPCServerSetup("Admin API", func() error {
   502  			adminclient.RegisterAPIServer(externalServer.Server, adminserver.NewAPIServer(address, env.StorageRoot, &adminclient.ClusterInfo{
   503  				ID:           clusterID,
   504  				DeploymentID: env.DeploymentID,
   505  			}))
   506  			return nil
   507  		}); err != nil {
   508  			return err
   509  		}
   510  		healthServer := health.NewHealthServer()
   511  		if err := logGRPCServerSetup("Health", func() error {
   512  			healthclient.RegisterHealthServer(externalServer.Server, healthServer)
   513  			return nil
   514  		}); err != nil {
   515  			return err
   516  		}
   517  		if err := logGRPCServerSetup("Version API", func() error {
   518  			versionpb.RegisterAPIServer(externalServer.Server, version.NewAPIServer(version.Version, version.APIServerOptions{}))
   519  			return nil
   520  		}); err != nil {
   521  			return err
   522  		}
   523  		if err := logGRPCServerSetup("Debug", func() error {
   524  			debugclient.RegisterDebugServer(externalServer.Server, debugserver.NewDebugServer(
   525  				env,
   526  				env.PachdPodName,
   527  				nil,
   528  			))
   529  			return nil
   530  		}); err != nil {
   531  			return err
   532  		}
   533  		txnEnv.Initialize(env, transactionAPIServer, authAPIServer, pfsAPIServer, ppsAPIServer)
   534  		if _, err := externalServer.ListenTCP("", env.Port); err != nil {
   535  			return err
   536  		}
   537  		healthServer.Ready()
   538  		return nil
   539  	}); err != nil {
   540  		return err
   541  	}
   542  	// Setup Internal Pachd GRPC Server.
   543  	if err := logGRPCServerSetup("Internal Pachd", func() error {
   544  		txnEnv := &txnenv.TransactionEnv{}
   545  		cacheServer := cache_server.NewCacheServer(router, env.NumShards)
   546  		go func() {
   547  			if err := sharder.RegisterFrontends(address, []shard.Frontend{cacheServer}); err != nil {
   548  				log.Printf("error from sharder.RegisterFrontend %s", grpcutil.ScrubGRPC(err))
   549  			}
   550  		}()
   551  		go func() {
   552  			if err := sharder.Register(address, []shard.Server{cacheServer}); err != nil {
   553  				log.Printf("error from sharder.Register %s", grpcutil.ScrubGRPC(err))
   554  			}
   555  		}()
   556  		cache_pb.RegisterGroupCacheServer(internalServer.Server, cacheServer)
   557  		memoryRequestBytes, err := units.RAMInBytes(env.MemoryRequest)
   558  		if err != nil {
   559  			return err
   560  		}
   561  		var pfsAPIServer pfs_iface.APIServer
   562  		if err := logGRPCServerSetup("PFS API", func() error {
   563  			pfsAPIServer, err = pfs_server.NewAPIServer(
   564  				env,
   565  				txnEnv,
   566  				path.Join(env.EtcdPrefix, env.PFSEtcdPrefix),
   567  				treeCache,
   568  				env.StorageRoot,
   569  				memoryRequestBytes,
   570  				blockAPIServer,
   571  			)
   572  			if err != nil {
   573  				return err
   574  			}
   575  			pfsclient.RegisterAPIServer(internalServer.Server, pfsAPIServer)
   576  			env.SetPfsServer(pfsAPIServer)
   577  			return nil
   578  		}); err != nil {
   579  			return err
   580  		}
   581  		var ppsAPIServer pps_iface.APIServer
   582  		if err := logGRPCServerSetup("PPS API", func() error {
   583  			ppsAPIServer, err = pps_server.NewAPIServer(
   584  				env,
   585  				txnEnv,
   586  				path.Join(env.EtcdPrefix, env.PPSEtcdPrefix),
   587  				kubeNamespace,
   588  				env.WorkerImage,
   589  				env.WorkerSidecarImage,
   590  				env.WorkerImagePullPolicy,
   591  				env.StorageRoot,
   592  				env.StorageBackend,
   593  				env.StorageHostPath,
   594  				env.CacheRoot,
   595  				env.IAMRole,
   596  				env.ImagePullSecret,
   597  				env.NoExposeDockerSocket,
   598  				reporter,
   599  				env.WorkerUsesRoot,
   600  				env.PPSWorkerPort,
   601  				env.Port,
   602  				env.HTTPPort,
   603  				env.PeerPort,
   604  				env.GCPercent,
   605  			)
   606  			if err != nil {
   607  				return err
   608  			}
   609  			ppsclient.RegisterAPIServer(internalServer.Server, ppsAPIServer)
   610  			env.SetPpsServer(ppsAPIServer)
   611  			return nil
   612  		}); err != nil {
   613  			return err
   614  		}
   615  		var authAPIServer auth_iface.APIServer
   616  		if err := logGRPCServerSetup("Auth API", func() error {
   617  			authAPIServer, err = authserver.NewAuthServer(
   618  				env,
   619  				txnEnv,
   620  				path.Join(env.EtcdPrefix, env.AuthEtcdPrefix),
   621  				false,
   622  				requireNoncriticalServers,
   623  			)
   624  			if err != nil {
   625  				return err
   626  			}
   627  			authclient.RegisterAPIServer(internalServer.Server, authAPIServer)
   628  			env.SetAuthServer(authAPIServer)
   629  			return nil
   630  		}); err != nil {
   631  			return err
   632  		}
   633  		var transactionAPIServer txnserver.APIServer
   634  		if err := logGRPCServerSetup("Transaction API", func() error {
   635  			transactionAPIServer, err = txnserver.NewAPIServer(
   636  				env,
   637  				txnEnv,
   638  				path.Join(env.EtcdPrefix, env.PFSEtcdPrefix),
   639  			)
   640  			if err != nil {
   641  				return err
   642  			}
   643  			transactionclient.RegisterAPIServer(internalServer.Server, transactionAPIServer)
   644  			return nil
   645  		}); err != nil {
   646  			return err
   647  		}
   648  		if err := logGRPCServerSetup("Enterprise API", func() error {
   649  			enterpriseAPIServer, err := eprsserver.NewEnterpriseServer(
   650  				env, path.Join(env.EtcdPrefix, env.EnterpriseEtcdPrefix))
   651  			if err != nil {
   652  				return err
   653  			}
   654  			eprsclient.RegisterAPIServer(internalServer.Server, enterpriseAPIServer)
   655  			env.SetEnterpriseServer(enterpriseAPIServer)
   656  			return nil
   657  		}); err != nil {
   658  			return err
   659  		}
   660  		healthServer := health.NewHealthServer()
   661  		if err := logGRPCServerSetup("Health", func() error {
   662  			healthclient.RegisterHealthServer(internalServer.Server, healthServer)
   663  			return nil
   664  		}); err != nil {
   665  			return err
   666  		}
   667  		if err := logGRPCServerSetup("Version API", func() error {
   668  			versionpb.RegisterAPIServer(internalServer.Server, version.NewAPIServer(version.Version, version.APIServerOptions{}))
   669  			return nil
   670  		}); err != nil {
   671  			return err
   672  		}
   673  		if err := logGRPCServerSetup("Admin API", func() error {
   674  			adminclient.RegisterAPIServer(internalServer.Server, adminserver.NewAPIServer(address, env.StorageRoot, &adminclient.ClusterInfo{
   675  				ID:           clusterID,
   676  				DeploymentID: env.DeploymentID,
   677  			}))
   678  			return nil
   679  		}); err != nil {
   680  			return err
   681  		}
   682  		txnEnv.Initialize(env, transactionAPIServer, authAPIServer, pfsAPIServer, ppsAPIServer)
   683  		if _, err := internalServer.ListenTCP("", env.PeerPort); err != nil {
   684  			return err
   685  		}
   686  		healthServer.Ready()
   687  		return nil
   688  	}); err != nil {
   689  		return err
   690  	}
   691  	// Create the goroutines for the servers.
   692  	// Any server error is considered critical and will cause Pachd to exit.
   693  	// The first server that errors will have its error message logged.
   694  	errChan := make(chan error, 1)
   695  	go waitForError("External Pachd GRPC Server", errChan, true, func() error {
   696  		return externalServer.Wait()
   697  	})
   698  	go waitForError("Internal Pachd GRPC Server", errChan, true, func() error {
   699  		return internalServer.Wait()
   700  	})
   701  	go waitForError("HTTP Server", errChan, requireNoncriticalServers, func() error {
   702  		httpServer, err := pach_http.NewHTTPServer(address)
   703  		if err != nil {
   704  			return err
   705  		}
   706  		server := http.Server{
   707  			Addr:    fmt.Sprintf(":%v", env.HTTPPort),
   708  			Handler: httpServer,
   709  		}
   710  
   711  		certPath, keyPath, err := tls.GetCertPaths()
   712  		if err != nil {
   713  			log.Warnf("pfs-over-HTTP - TLS disabled: %v", err)
   714  			return server.ListenAndServe()
   715  		}
   716  
   717  		cLoader := tls.NewCertLoader(certPath, keyPath, tls.CertCheckFrequency)
   718  		err = cLoader.LoadAndStart()
   719  		if err != nil {
   720  			return errors.Wrapf(err, "couldn't load TLS cert for pfs-over-http: %v", err)
   721  		}
   722  
   723  		server.TLSConfig = &gotls.Config{GetCertificate: cLoader.GetCertificate}
   724  
   725  		return server.ListenAndServeTLS(certPath, keyPath)
   726  	})
   727  	go waitForError("Githook Server", errChan, requireNoncriticalServers, func() error {
   728  		return githook.RunGitHookServer(address, etcdAddress, path.Join(env.EtcdPrefix, env.PPSEtcdPrefix))
   729  	})
   730  	go waitForError("S3 Server", errChan, requireNoncriticalServers, func() error {
   731  		server, err := s3.Server(env, s3.NewMasterDriver())
   732  		if err != nil {
   733  			return err
   734  		}
   735  		certPath, keyPath, err := tls.GetCertPaths()
   736  		if err != nil {
   737  			log.Warnf("s3gateway TLS disabled: %v", err)
   738  			return server.ListenAndServe()
   739  		}
   740  		cLoader := tls.NewCertLoader(certPath, keyPath, tls.CertCheckFrequency)
   741  		// Read TLS cert and key
   742  		err = cLoader.LoadAndStart()
   743  		if err != nil {
   744  			return errors.Wrapf(err, "couldn't load TLS cert for s3gateway: %v", err)
   745  		}
   746  		server.TLSConfig = &gotls.Config{GetCertificate: cLoader.GetCertificate}
   747  		return server.ListenAndServeTLS(certPath, keyPath)
   748  	})
   749  	go waitForError("Prometheus Server", errChan, requireNoncriticalServers, func() error {
   750  		http.Handle("/metrics", promhttp.Handler())
   751  		return http.ListenAndServe(fmt.Sprintf(":%v", assets.PrometheusPort), nil)
   752  	})
   753  	return <-errChan
   754  }
   755  
   756  func getEtcdClient(etcdAddress string) discovery.Client {
   757  	return discovery.NewEtcdClient(etcdAddress)
   758  }
   759  
   760  const clusterIDKey = "cluster-id"
   761  
   762  func getClusterID(client *etcd.Client) (string, error) {
   763  	resp, err := client.Get(context.Background(),
   764  		clusterIDKey)
   765  
   766  	// if it's a key not found error then we create the key
   767  	if resp.Count == 0 {
   768  		// This might error if it races with another pachd trying to set the
   769  		// cluster id so we ignore the error.
   770  		client.Put(context.Background(), clusterIDKey, uuid.NewWithoutDashes())
   771  	} else if err != nil {
   772  		return "", err
   773  	} else {
   774  		// We expect there to only be one value for this key
   775  		id := string(resp.Kvs[0].Value)
   776  		return id, nil
   777  	}
   778  
   779  	return getClusterID(client)
   780  }
   781  
   782  func logGRPCServerSetup(name string, f func() error) (retErr error) {
   783  	log.Printf("started setting up %v GRPC Server", name)
   784  	defer func() {
   785  		if retErr != nil {
   786  			retErr = errors.Wrapf(retErr, "error setting up %v GRPC Server", name)
   787  		} else {
   788  			log.Printf("finished setting up %v GRPC Server", name)
   789  		}
   790  	}()
   791  	return f()
   792  }
   793  
   794  func waitForError(name string, errChan chan error, required bool, f func() error) {
   795  	if err := f(); !errors.Is(err, http.ErrServerClosed) {
   796  		if !required {
   797  			log.Errorf("error setting up and/or running %v: %v", name, err)
   798  		} else {
   799  			errChan <- errors.Wrapf(err, "error setting up and/or running %v (use --require-critical-servers-only deploy flag to ignore errors from noncritical servers)", name)
   800  		}
   801  	}
   802  }