gateway.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. package gateway
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net"
  8. "os"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. "time"
  13. "github.com/docker/distribution/reference"
  14. apitypes "github.com/moby/buildkit/api/types"
  15. "github.com/moby/buildkit/cache"
  16. cacheutil "github.com/moby/buildkit/cache/util"
  17. "github.com/moby/buildkit/client"
  18. "github.com/moby/buildkit/client/llb"
  19. "github.com/moby/buildkit/executor"
  20. "github.com/moby/buildkit/exporter/containerimage/exptypes"
  21. "github.com/moby/buildkit/frontend"
  22. pb "github.com/moby/buildkit/frontend/gateway/pb"
  23. "github.com/moby/buildkit/identity"
  24. "github.com/moby/buildkit/session"
  25. "github.com/moby/buildkit/solver"
  26. opspb "github.com/moby/buildkit/solver/pb"
  27. "github.com/moby/buildkit/util/apicaps"
  28. "github.com/moby/buildkit/util/tracing"
  29. "github.com/moby/buildkit/worker"
  30. specs "github.com/opencontainers/image-spec/specs-go/v1"
  31. "github.com/pkg/errors"
  32. "github.com/sirupsen/logrus"
  33. "golang.org/x/net/http2"
  34. spb "google.golang.org/genproto/googleapis/rpc/status"
  35. "google.golang.org/grpc"
  36. "google.golang.org/grpc/health"
  37. "google.golang.org/grpc/health/grpc_health_v1"
  38. "google.golang.org/grpc/status"
  39. )
  40. const (
  41. keySource = "source"
  42. keyDevel = "gateway-devel"
  43. )
  44. func NewGatewayFrontend(w frontend.WorkerInfos) frontend.Frontend {
  45. return &gatewayFrontend{
  46. workers: w,
  47. }
  48. }
  49. type gatewayFrontend struct {
  50. workers frontend.WorkerInfos
  51. }
  52. func filterPrefix(opts map[string]string, pfx string) map[string]string {
  53. m := map[string]string{}
  54. for k, v := range opts {
  55. if strings.HasPrefix(k, pfx) {
  56. m[strings.TrimPrefix(k, pfx)] = v
  57. }
  58. }
  59. return m
  60. }
  61. func (gf *gatewayFrontend) Solve(ctx context.Context, llbBridge frontend.FrontendLLBBridge, opts map[string]string, inputs map[string]*opspb.Definition) (*frontend.Result, error) {
  62. source, ok := opts[keySource]
  63. if !ok {
  64. return nil, errors.Errorf("no source specified for gateway")
  65. }
  66. sid := session.FromContext(ctx)
  67. _, isDevel := opts[keyDevel]
  68. var img specs.Image
  69. var rootFS cache.ImmutableRef
  70. var readonly bool // TODO: try to switch to read-only by default.
  71. if isDevel {
  72. devRes, err := llbBridge.Solve(session.NewContext(ctx, "gateway:"+sid),
  73. frontend.SolveRequest{
  74. Frontend: source,
  75. FrontendOpt: filterPrefix(opts, "gateway-"),
  76. FrontendInputs: inputs,
  77. })
  78. if err != nil {
  79. return nil, err
  80. }
  81. defer func() {
  82. devRes.EachRef(func(ref solver.ResultProxy) error {
  83. return ref.Release(context.TODO())
  84. })
  85. }()
  86. if devRes.Ref == nil {
  87. return nil, errors.Errorf("development gateway didn't return default result")
  88. }
  89. res, err := devRes.Ref.Result(ctx)
  90. if err != nil {
  91. return nil, err
  92. }
  93. workerRef, ok := res.Sys().(*worker.WorkerRef)
  94. if !ok {
  95. return nil, errors.Errorf("invalid ref: %T", res.Sys())
  96. }
  97. rootFS = workerRef.ImmutableRef
  98. config, ok := devRes.Metadata[exptypes.ExporterImageConfigKey]
  99. if ok {
  100. if err := json.Unmarshal(config, &img); err != nil {
  101. return nil, err
  102. }
  103. }
  104. } else {
  105. sourceRef, err := reference.ParseNormalizedNamed(source)
  106. if err != nil {
  107. return nil, err
  108. }
  109. dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String(), llb.ResolveImageConfigOpt{})
  110. if err != nil {
  111. return nil, err
  112. }
  113. if err := json.Unmarshal(config, &img); err != nil {
  114. return nil, err
  115. }
  116. if dgst != "" {
  117. sourceRef, err = reference.WithDigest(sourceRef, dgst)
  118. if err != nil {
  119. return nil, err
  120. }
  121. }
  122. src := llb.Image(sourceRef.String(), &markTypeFrontend{})
  123. def, err := src.Marshal(ctx)
  124. if err != nil {
  125. return nil, err
  126. }
  127. res, err := llbBridge.Solve(ctx, frontend.SolveRequest{
  128. Definition: def.ToPB(),
  129. })
  130. if err != nil {
  131. return nil, err
  132. }
  133. defer func() {
  134. res.EachRef(func(ref solver.ResultProxy) error {
  135. return ref.Release(context.TODO())
  136. })
  137. }()
  138. if res.Ref == nil {
  139. return nil, errors.Errorf("gateway source didn't return default result")
  140. }
  141. r, err := res.Ref.Result(ctx)
  142. if err != nil {
  143. return nil, err
  144. }
  145. workerRef, ok := r.Sys().(*worker.WorkerRef)
  146. if !ok {
  147. return nil, errors.Errorf("invalid ref: %T", r.Sys())
  148. }
  149. rootFS = workerRef.ImmutableRef
  150. }
  151. lbf, ctx, err := newLLBBridgeForwarder(ctx, llbBridge, gf.workers, inputs)
  152. defer lbf.conn.Close()
  153. if err != nil {
  154. return nil, err
  155. }
  156. args := []string{"/run"}
  157. env := []string{}
  158. cwd := "/"
  159. if img.Config.Env != nil {
  160. env = img.Config.Env
  161. }
  162. if img.Config.Entrypoint != nil {
  163. args = img.Config.Entrypoint
  164. }
  165. if img.Config.WorkingDir != "" {
  166. cwd = img.Config.WorkingDir
  167. }
  168. i := 0
  169. for k, v := range opts {
  170. env = append(env, fmt.Sprintf("BUILDKIT_FRONTEND_OPT_%d", i)+"="+k+"="+v)
  171. i++
  172. }
  173. env = append(env, "BUILDKIT_SESSION_ID="+sid)
  174. dt, err := json.Marshal(gf.workers.WorkerInfos())
  175. if err != nil {
  176. return nil, errors.Wrap(err, "failed to marshal workers array")
  177. }
  178. env = append(env, "BUILDKIT_WORKERS="+string(dt))
  179. defer lbf.Discard()
  180. env = append(env, "BUILDKIT_EXPORTEDPRODUCT="+apicaps.ExportedProduct)
  181. meta := executor.Meta{
  182. Env: env,
  183. Args: args,
  184. Cwd: cwd,
  185. ReadonlyRootFS: readonly,
  186. }
  187. if v, ok := img.Config.Labels["moby.buildkit.frontend.network.none"]; ok {
  188. if ok, _ := strconv.ParseBool(v); ok {
  189. meta.NetMode = opspb.NetMode_NONE
  190. }
  191. }
  192. err = llbBridge.Exec(ctx, meta, rootFS, lbf.Stdin, lbf.Stdout, os.Stderr)
  193. if err != nil {
  194. if errors.Cause(err) == context.Canceled && lbf.isErrServerClosed {
  195. err = errors.Errorf("frontend grpc server closed unexpectedly")
  196. }
  197. // An existing error (set via Return rpc) takes
  198. // precedence over this error, which in turn takes
  199. // precedence over a success reported via Return.
  200. lbf.mu.Lock()
  201. if lbf.err == nil {
  202. lbf.result = nil
  203. lbf.err = err
  204. }
  205. lbf.mu.Unlock()
  206. }
  207. return lbf.Result()
  208. }
  209. func (lbf *llbBridgeForwarder) Discard() {
  210. lbf.mu.Lock()
  211. defer lbf.mu.Unlock()
  212. for id, r := range lbf.refs {
  213. if lbf.err == nil && lbf.result != nil {
  214. keep := false
  215. lbf.result.EachRef(func(r2 solver.ResultProxy) error {
  216. if r == r2 {
  217. keep = true
  218. }
  219. return nil
  220. })
  221. if keep {
  222. continue
  223. }
  224. }
  225. r.Release(context.TODO())
  226. delete(lbf.refs, id)
  227. }
  228. }
  229. func (lbf *llbBridgeForwarder) Done() <-chan struct{} {
  230. return lbf.doneCh
  231. }
  232. func (lbf *llbBridgeForwarder) setResult(r *frontend.Result, err error) (*pb.ReturnResponse, error) {
  233. lbf.mu.Lock()
  234. defer lbf.mu.Unlock()
  235. if (r == nil) == (err == nil) {
  236. return nil, errors.New("gateway return must be either result or err")
  237. }
  238. if lbf.result != nil || lbf.err != nil {
  239. return nil, errors.New("gateway result is already set")
  240. }
  241. lbf.result = r
  242. lbf.err = err
  243. close(lbf.doneCh)
  244. return &pb.ReturnResponse{}, nil
  245. }
  246. func (lbf *llbBridgeForwarder) Result() (*frontend.Result, error) {
  247. lbf.mu.Lock()
  248. defer lbf.mu.Unlock()
  249. if lbf.result == nil && lbf.err == nil {
  250. return nil, errors.New("no result for incomplete build")
  251. }
  252. if lbf.err != nil {
  253. return nil, lbf.err
  254. }
  255. return lbf.result, nil
  256. }
  257. func NewBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, workers frontend.WorkerInfos, inputs map[string]*opspb.Definition) *llbBridgeForwarder {
  258. lbf := &llbBridgeForwarder{
  259. callCtx: ctx,
  260. llbBridge: llbBridge,
  261. refs: map[string]solver.ResultProxy{},
  262. doneCh: make(chan struct{}),
  263. pipe: newPipe(),
  264. workers: workers,
  265. inputs: inputs,
  266. }
  267. return lbf
  268. }
  269. func newLLBBridgeForwarder(ctx context.Context, llbBridge frontend.FrontendLLBBridge, workers frontend.WorkerInfos, inputs map[string]*opspb.Definition) (*llbBridgeForwarder, context.Context, error) {
  270. ctx, cancel := context.WithCancel(ctx)
  271. lbf := NewBridgeForwarder(ctx, llbBridge, workers, inputs)
  272. server := grpc.NewServer()
  273. grpc_health_v1.RegisterHealthServer(server, health.NewServer())
  274. pb.RegisterLLBBridgeServer(server, lbf)
  275. go func() {
  276. serve(ctx, server, lbf.conn)
  277. select {
  278. case <-ctx.Done():
  279. default:
  280. lbf.isErrServerClosed = true
  281. }
  282. cancel()
  283. }()
  284. return lbf, ctx, nil
  285. }
  286. type pipe struct {
  287. Stdin io.ReadCloser
  288. Stdout io.WriteCloser
  289. conn net.Conn
  290. }
  291. func newPipe() *pipe {
  292. pr1, pw1, _ := os.Pipe()
  293. pr2, pw2, _ := os.Pipe()
  294. return &pipe{
  295. Stdin: pr1,
  296. Stdout: pw2,
  297. conn: &conn{
  298. Reader: pr2,
  299. Writer: pw1,
  300. Closer: pw2,
  301. },
  302. }
  303. }
  304. type conn struct {
  305. io.Reader
  306. io.Writer
  307. io.Closer
  308. }
  309. func (s *conn) LocalAddr() net.Addr {
  310. return dummyAddr{}
  311. }
  312. func (s *conn) RemoteAddr() net.Addr {
  313. return dummyAddr{}
  314. }
  315. func (s *conn) SetDeadline(t time.Time) error {
  316. return nil
  317. }
  318. func (s *conn) SetReadDeadline(t time.Time) error {
  319. return nil
  320. }
  321. func (s *conn) SetWriteDeadline(t time.Time) error {
  322. return nil
  323. }
  324. type dummyAddr struct {
  325. }
  326. func (d dummyAddr) Network() string {
  327. return "pipe"
  328. }
  329. func (d dummyAddr) String() string {
  330. return "localhost"
  331. }
  332. type LLBBridgeForwarder interface {
  333. pb.LLBBridgeServer
  334. Done() <-chan struct{}
  335. Result() (*frontend.Result, error)
  336. }
  337. type llbBridgeForwarder struct {
  338. mu sync.Mutex
  339. callCtx context.Context
  340. llbBridge frontend.FrontendLLBBridge
  341. refs map[string]solver.ResultProxy
  342. // lastRef solver.CachedResult
  343. // lastRefs map[string]solver.CachedResult
  344. // err error
  345. doneCh chan struct{} // closed when result or err become valid through a call to a Return
  346. result *frontend.Result
  347. err error
  348. exporterAttr map[string][]byte
  349. workers frontend.WorkerInfos
  350. inputs map[string]*opspb.Definition
  351. isErrServerClosed bool
  352. *pipe
  353. }
  354. func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.ResolveImageConfigRequest) (*pb.ResolveImageConfigResponse, error) {
  355. ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
  356. var platform *specs.Platform
  357. if p := req.Platform; p != nil {
  358. platform = &specs.Platform{
  359. OS: p.OS,
  360. Architecture: p.Architecture,
  361. Variant: p.Variant,
  362. OSVersion: p.OSVersion,
  363. OSFeatures: p.OSFeatures,
  364. }
  365. }
  366. dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref, llb.ResolveImageConfigOpt{
  367. Platform: platform,
  368. ResolveMode: req.ResolveMode,
  369. LogName: req.LogName,
  370. })
  371. if err != nil {
  372. return nil, err
  373. }
  374. return &pb.ResolveImageConfigResponse{
  375. Digest: dgst,
  376. Config: dt,
  377. }, nil
  378. }
  379. func translateLegacySolveRequest(req *pb.SolveRequest) error {
  380. // translates ImportCacheRefs to new CacheImports (v0.4.0)
  381. for _, legacyImportRef := range req.ImportCacheRefsDeprecated {
  382. im := &pb.CacheOptionsEntry{
  383. Type: "registry",
  384. Attrs: map[string]string{"ref": legacyImportRef},
  385. }
  386. // FIXME(AkihiroSuda): skip append if already exists
  387. req.CacheImports = append(req.CacheImports, im)
  388. }
  389. req.ImportCacheRefsDeprecated = nil
  390. return nil
  391. }
  392. func (lbf *llbBridgeForwarder) Solve(ctx context.Context, req *pb.SolveRequest) (*pb.SolveResponse, error) {
  393. if err := translateLegacySolveRequest(req); err != nil {
  394. return nil, err
  395. }
  396. var cacheImports []frontend.CacheOptionsEntry
  397. for _, e := range req.CacheImports {
  398. cacheImports = append(cacheImports, frontend.CacheOptionsEntry{
  399. Type: e.Type,
  400. Attrs: e.Attrs,
  401. })
  402. }
  403. ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
  404. res, err := lbf.llbBridge.Solve(ctx, frontend.SolveRequest{
  405. Definition: req.Definition,
  406. Frontend: req.Frontend,
  407. FrontendOpt: req.FrontendOpt,
  408. FrontendInputs: req.FrontendInputs,
  409. CacheImports: cacheImports,
  410. })
  411. if err != nil {
  412. return nil, err
  413. }
  414. if len(res.Refs) > 0 && !req.AllowResultReturn {
  415. // this should never happen because old client shouldn't make a map request
  416. return nil, errors.Errorf("solve did not return default result")
  417. }
  418. pbRes := &pb.Result{}
  419. var defaultID string
  420. lbf.mu.Lock()
  421. if res.Refs != nil {
  422. ids := make(map[string]string, len(res.Refs))
  423. defs := make(map[string]*opspb.Definition, len(res.Refs))
  424. for k, ref := range res.Refs {
  425. id := identity.NewID()
  426. if ref == nil {
  427. id = ""
  428. } else {
  429. lbf.refs[id] = ref
  430. }
  431. ids[k] = id
  432. defs[k] = ref.Definition()
  433. }
  434. if req.AllowResultArrayRef {
  435. refMap := make(map[string]*pb.Ref, len(res.Refs))
  436. for k, id := range ids {
  437. refMap[k] = &pb.Ref{Id: id, Def: defs[k]}
  438. }
  439. pbRes.Result = &pb.Result_Refs{Refs: &pb.RefMap{Refs: refMap}}
  440. } else {
  441. pbRes.Result = &pb.Result_RefsDeprecated{RefsDeprecated: &pb.RefMapDeprecated{Refs: ids}}
  442. }
  443. } else {
  444. ref := res.Ref
  445. id := identity.NewID()
  446. var def *opspb.Definition
  447. if ref == nil {
  448. id = ""
  449. } else {
  450. def = ref.Definition()
  451. lbf.refs[id] = ref
  452. }
  453. defaultID = id
  454. if req.AllowResultArrayRef {
  455. pbRes.Result = &pb.Result_Ref{Ref: &pb.Ref{Id: id, Def: def}}
  456. } else {
  457. pbRes.Result = &pb.Result_RefDeprecated{RefDeprecated: id}
  458. }
  459. }
  460. lbf.mu.Unlock()
  461. // compatibility mode for older clients
  462. if req.Final {
  463. exp := map[string][]byte{}
  464. if err := json.Unmarshal(req.ExporterAttr, &exp); err != nil {
  465. return nil, err
  466. }
  467. for k, v := range res.Metadata {
  468. exp[k] = v
  469. }
  470. lbf.mu.Lock()
  471. lbf.result = &frontend.Result{
  472. Ref: lbf.refs[defaultID],
  473. Metadata: exp,
  474. }
  475. lbf.mu.Unlock()
  476. }
  477. resp := &pb.SolveResponse{
  478. Result: pbRes,
  479. }
  480. if !req.AllowResultReturn {
  481. resp.Ref = defaultID
  482. }
  483. return resp, nil
  484. }
  485. func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileRequest) (*pb.ReadFileResponse, error) {
  486. ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
  487. lbf.mu.Lock()
  488. ref, ok := lbf.refs[req.Ref]
  489. lbf.mu.Unlock()
  490. if !ok {
  491. return nil, errors.Errorf("no such ref: %v", req.Ref)
  492. }
  493. if ref == nil {
  494. return nil, errors.Wrapf(os.ErrNotExist, "%s not found", req.FilePath)
  495. }
  496. r, err := ref.Result(ctx)
  497. if err != nil {
  498. return nil, err
  499. }
  500. workerRef, ok := r.Sys().(*worker.WorkerRef)
  501. if !ok {
  502. return nil, errors.Errorf("invalid ref: %T", r.Sys())
  503. }
  504. newReq := cacheutil.ReadRequest{
  505. Filename: req.FilePath,
  506. }
  507. if r := req.Range; r != nil {
  508. newReq.Range = &cacheutil.FileRange{
  509. Offset: int(r.Offset),
  510. Length: int(r.Length),
  511. }
  512. }
  513. dt, err := cacheutil.ReadFile(ctx, workerRef.ImmutableRef, newReq)
  514. if err != nil {
  515. return nil, err
  516. }
  517. return &pb.ReadFileResponse{Data: dt}, nil
  518. }
  519. func (lbf *llbBridgeForwarder) ReadDir(ctx context.Context, req *pb.ReadDirRequest) (*pb.ReadDirResponse, error) {
  520. ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
  521. lbf.mu.Lock()
  522. ref, ok := lbf.refs[req.Ref]
  523. lbf.mu.Unlock()
  524. if !ok {
  525. return nil, errors.Errorf("no such ref: %v", req.Ref)
  526. }
  527. if ref == nil {
  528. return nil, errors.Wrapf(os.ErrNotExist, "%s not found", req.DirPath)
  529. }
  530. r, err := ref.Result(ctx)
  531. if err != nil {
  532. return nil, err
  533. }
  534. workerRef, ok := r.Sys().(*worker.WorkerRef)
  535. if !ok {
  536. return nil, errors.Errorf("invalid ref: %T", r.Sys())
  537. }
  538. newReq := cacheutil.ReadDirRequest{
  539. Path: req.DirPath,
  540. IncludePattern: req.IncludePattern,
  541. }
  542. entries, err := cacheutil.ReadDir(ctx, workerRef.ImmutableRef, newReq)
  543. if err != nil {
  544. return nil, err
  545. }
  546. return &pb.ReadDirResponse{Entries: entries}, nil
  547. }
  548. func (lbf *llbBridgeForwarder) StatFile(ctx context.Context, req *pb.StatFileRequest) (*pb.StatFileResponse, error) {
  549. ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
  550. lbf.mu.Lock()
  551. ref, ok := lbf.refs[req.Ref]
  552. lbf.mu.Unlock()
  553. if !ok {
  554. return nil, errors.Errorf("no such ref: %v", req.Ref)
  555. }
  556. if ref == nil {
  557. return nil, errors.Wrapf(os.ErrNotExist, "%s not found", req.Path)
  558. }
  559. r, err := ref.Result(ctx)
  560. if err != nil {
  561. return nil, err
  562. }
  563. workerRef, ok := r.Sys().(*worker.WorkerRef)
  564. if !ok {
  565. return nil, errors.Errorf("invalid ref: %T", r.Sys())
  566. }
  567. st, err := cacheutil.StatFile(ctx, workerRef.ImmutableRef, req.Path)
  568. if err != nil {
  569. return nil, err
  570. }
  571. return &pb.StatFileResponse{Stat: st}, nil
  572. }
  573. func (lbf *llbBridgeForwarder) Ping(context.Context, *pb.PingRequest) (*pb.PongResponse, error) {
  574. workers := lbf.workers.WorkerInfos()
  575. pbWorkers := make([]*apitypes.WorkerRecord, 0, len(workers))
  576. for _, w := range workers {
  577. pbWorkers = append(pbWorkers, &apitypes.WorkerRecord{
  578. ID: w.ID,
  579. Labels: w.Labels,
  580. Platforms: opspb.PlatformsFromSpec(w.Platforms),
  581. })
  582. }
  583. return &pb.PongResponse{
  584. FrontendAPICaps: pb.Caps.All(),
  585. Workers: pbWorkers,
  586. LLBCaps: opspb.Caps.All(),
  587. }, nil
  588. }
  589. func (lbf *llbBridgeForwarder) Return(ctx context.Context, in *pb.ReturnRequest) (*pb.ReturnResponse, error) {
  590. if in.Error != nil {
  591. return lbf.setResult(nil, status.ErrorProto(&spb.Status{
  592. Code: in.Error.Code,
  593. Message: in.Error.Message,
  594. // Details: in.Error.Details,
  595. }))
  596. } else {
  597. r := &frontend.Result{
  598. Metadata: in.Result.Metadata,
  599. }
  600. switch res := in.Result.Result.(type) {
  601. case *pb.Result_RefDeprecated:
  602. ref, err := lbf.convertRef(res.RefDeprecated)
  603. if err != nil {
  604. return nil, err
  605. }
  606. r.Ref = ref
  607. case *pb.Result_RefsDeprecated:
  608. m := map[string]solver.ResultProxy{}
  609. for k, id := range res.RefsDeprecated.Refs {
  610. ref, err := lbf.convertRef(id)
  611. if err != nil {
  612. return nil, err
  613. }
  614. m[k] = ref
  615. }
  616. r.Refs = m
  617. case *pb.Result_Ref:
  618. ref, err := lbf.convertRef(res.Ref.Id)
  619. if err != nil {
  620. return nil, err
  621. }
  622. r.Ref = ref
  623. case *pb.Result_Refs:
  624. m := map[string]solver.ResultProxy{}
  625. for k, ref := range res.Refs.Refs {
  626. ref, err := lbf.convertRef(ref.Id)
  627. if err != nil {
  628. return nil, err
  629. }
  630. m[k] = ref
  631. }
  632. r.Refs = m
  633. }
  634. return lbf.setResult(r, nil)
  635. }
  636. }
  637. func (lbf *llbBridgeForwarder) Inputs(ctx context.Context, in *pb.InputsRequest) (*pb.InputsResponse, error) {
  638. return &pb.InputsResponse{
  639. Definitions: lbf.inputs,
  640. }, nil
  641. }
  642. func (lbf *llbBridgeForwarder) convertRef(id string) (solver.ResultProxy, error) {
  643. if id == "" {
  644. return nil, nil
  645. }
  646. lbf.mu.Lock()
  647. defer lbf.mu.Unlock()
  648. r, ok := lbf.refs[id]
  649. if !ok {
  650. return nil, errors.Errorf("return reference %s not found", id)
  651. }
  652. return r, nil
  653. }
  654. func serve(ctx context.Context, grpcServer *grpc.Server, conn net.Conn) {
  655. go func() {
  656. <-ctx.Done()
  657. conn.Close()
  658. }()
  659. logrus.Debugf("serving grpc connection")
  660. (&http2.Server{}).ServeConn(conn, &http2.ServeConnOpts{Handler: grpcServer})
  661. }
  662. type markTypeFrontend struct{}
  663. func (*markTypeFrontend) SetImageOption(ii *llb.ImageInfo) {
  664. ii.RecordType = string(client.UsageRecordTypeFrontend)
  665. }