github.com/pachyderm/pachyderm@v1.13.4/src/server/cmd/worker/main.go (about) 1 package main 2 3 import ( 4 "context" 5 "os" 6 "path" 7 "time" 8 9 "github.com/pachyderm/pachyderm/src/client" 10 debugclient "github.com/pachyderm/pachyderm/src/client/debug" 11 "github.com/pachyderm/pachyderm/src/client/pkg/errors" 12 "github.com/pachyderm/pachyderm/src/client/pkg/grpcutil" 13 "github.com/pachyderm/pachyderm/src/client/pkg/tracing" 14 "github.com/pachyderm/pachyderm/src/client/pps" 15 "github.com/pachyderm/pachyderm/src/client/version" 16 "github.com/pachyderm/pachyderm/src/client/version/versionpb" 17 "github.com/pachyderm/pachyderm/src/server/cmd/worker/assets" 18 debugserver "github.com/pachyderm/pachyderm/src/server/debug/server" 19 "github.com/pachyderm/pachyderm/src/server/pkg/cmdutil" 20 logutil "github.com/pachyderm/pachyderm/src/server/pkg/log" 21 "github.com/pachyderm/pachyderm/src/server/pkg/ppsutil" 22 "github.com/pachyderm/pachyderm/src/server/pkg/serviceenv" 23 "github.com/pachyderm/pachyderm/src/server/worker" 24 workerserver "github.com/pachyderm/pachyderm/src/server/worker/server" 25 "go.uber.org/automaxprocs/maxprocs" 26 27 etcd "github.com/coreos/etcd/clientv3" 28 log "github.com/sirupsen/logrus" 29 ) 30 31 func main() { 32 log.SetFormatter(logutil.FormatterFunc(logutil.Pretty)) 33 maxprocs.Set(maxprocs.Logger(log.Printf)) 34 35 // Copy certs embedded via go-bindata to /etc/ssl/certs. Because the 36 // container running this app is user-specified, we don't otherwise have 37 // control over the certs that are available. 38 // 39 // If an error occurs, don't hard-fail, but do record if any certs are 40 // known to be missing so we can inform the user. 41 if err := assets.RestoreAssets("/", "etc/ssl/certs"); err != nil { 42 log.Warnf("failed to inject TLS certs: %v", err) 43 } 44 45 // append pachyderm bins to path to allow use of pachctl 46 os.Setenv("PATH", os.Getenv("PATH")+":/pach-bin") 47 48 cmdutil.Main(do, &serviceenv.WorkerFullConfiguration{}) 49 } 50 51 // getPipelineInfo gets the PipelineInfo proto describing the pipeline that this 52 // worker is part of. 53 // getPipelineInfo has the side effect of adding auth to the passed pachClient 54 // which is necessary to get the PipelineInfo from pfs. 55 func getPipelineInfo(pachClient *client.APIClient, env *serviceenv.ServiceEnv) (*pps.PipelineInfo, error) { 56 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 57 defer cancel() 58 resp, err := env.GetEtcdClient().Get(ctx, path.Join(env.PPSEtcdPrefix, "pipelines", env.PPSPipelineName)) 59 if err != nil { 60 return nil, err 61 } 62 if len(resp.Kvs) != 1 { 63 return nil, errors.Errorf("expected to find 1 pipeline (%s), got %d: %v", env.PPSPipelineName, len(resp.Kvs), resp) 64 } 65 var pipelinePtr pps.EtcdPipelineInfo 66 if err := pipelinePtr.Unmarshal(resp.Kvs[0].Value); err != nil { 67 return nil, err 68 } 69 pachClient.SetAuthToken(pipelinePtr.AuthToken) 70 // Notice we use the SpecCommitID from our env, not from etcd. This is 71 // because the value in etcd might get updated while the worker pod is 72 // being created and we don't want to run the transform of one version of 73 // the pipeline in the image of a different verison. 74 pipelinePtr.SpecCommit.ID = env.PPSSpecCommitID 75 return ppsutil.GetPipelineInfo(pachClient, env.PPSPipelineName, &pipelinePtr) 76 } 77 78 func do(config interface{}) error { 79 // must run InstallJaegerTracer before InitWithKube/pach client initialization 80 tracing.InstallJaegerTracerFromEnv() 81 env := serviceenv.InitServiceEnv(serviceenv.NewConfiguration(config)) 82 83 // Construct a client that connects to the sidecar. 84 pachClient := env.GetPachClient(context.Background()) 85 pipelineInfo, err := getPipelineInfo(pachClient, env) // get pipeline creds for pachClient 86 if err != nil { 87 return errors.Wrapf(err, "error getting pipelineInfo") 88 } 89 90 // Construct worker API server. 91 workerRcName := ppsutil.PipelineRcName(pipelineInfo.Pipeline.Name, pipelineInfo.Version) 92 workerInstance, err := worker.NewWorker(pachClient, env.GetEtcdClient(), env.PPSEtcdPrefix, pipelineInfo, env.PodName, env.Namespace, env.CacheRoot, "/") 93 if err != nil { 94 return err 95 } 96 97 // Start worker api server 98 server, err := grpcutil.NewServer(context.Background(), false) 99 if err != nil { 100 return err 101 } 102 103 workerserver.RegisterWorkerServer(server.Server, workerInstance.APIServer) 104 versionpb.RegisterAPIServer(server.Server, version.NewAPIServer(version.Version, version.APIServerOptions{})) 105 debugclient.RegisterDebugServer(server.Server, debugserver.NewDebugServer(env, env.PodName, pachClient)) 106 107 // Put our IP address into etcd, so pachd can discover us 108 key := path.Join(env.PPSEtcdPrefix, workerserver.WorkerEtcdPrefix, workerRcName, env.PPSWorkerIP) 109 110 // Prepare to write "key" into etcd by creating lease -- if worker dies, our 111 // IP will be removed from etcd 112 ctx, cancel := context.WithTimeout(pachClient.Ctx(), 10*time.Second) 113 defer cancel() 114 115 resp, err := env.GetEtcdClient().Grant(ctx, 10 /* seconds */) 116 if err != nil { 117 return errors.Wrapf(err, "error granting lease") 118 } 119 120 // keepalive forever 121 if _, err := env.GetEtcdClient().KeepAlive(context.Background(), resp.ID); err != nil { 122 return errors.Wrapf(err, "error with KeepAlive") 123 } 124 125 // Actually write "key" into etcd 126 ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) // new ctx 127 defer cancel() 128 if _, err := env.GetEtcdClient().Put(ctx, key, "", etcd.WithLease(resp.ID)); err != nil { 129 return errors.Wrapf(err, "error putting IP address") 130 } 131 132 // If server ever exits, return error 133 if _, err := server.ListenTCP("", env.PPSWorkerPort); err != nil { 134 return err 135 } 136 return server.Wait() 137 }