Allow previous solve results to be used in new solves#1286
Allow previous solve results to be used in new solves#1286tonistiigi merged 5 commits intomoby:masterfrom
Conversation
|
Please sign your commits following these rules: $ git clone -b "llbstate-from-result" git@github.com:hinshun/buildkit.git somewhere
$ cd somewhere
$ git rebase -i HEAD~842354600464
editor opens
change each 'pick' to 'edit'
save the file and quit
$ git commit --amend -s --no-edit
$ git rebase --continue # and repeat the amend for each commit
$ git push -fAmending updates the existing PR. You DO NOT need to open a new one. |
747d269 to
72b42c8
Compare
72b42c8 to
7b346b6
Compare
7c4ba14 to
d1483f4
Compare
1ac2266 to
64064be
Compare
|
Currently, the Lines 72 to 74 in f7cf482 It's implemented this way because the helper function buildkit/client/llb/marshal.go Lines 61 to 67 in f7cf482 I can either duplicate this edge case in |
358e813 to
6e8c830
Compare
6e8c830 to
fa4ac7a
Compare
But don't call |
|
@tonistiigi You're right! That was dumb... 👍 |
|
@tonistiigi Could you give this another review? |
| {"local op", Local("name")}, | ||
| {"git op", Git("remote", "ref")}, | ||
| {"http op", HTTP("url")}, | ||
| {"file op", Scratch().File(Mkdir("foo", 0600).Mkfile("foo/bar", 0600, []byte("data")).Copy(Scratch(), "src", "dst"))}, |
There was a problem hiding this comment.
Could you add a test that sets a platform to the original state and then checks it after NewState(defOp)
There was a problem hiding this comment.
@tonistiigi Can you clarify what you mean by original state?
There was a problem hiding this comment.
The state that is marshaled and then passed to NewDefinitionOp
There was a problem hiding this comment.
This needs a specific call to state.Platform() to verify as the platform is stored in the state directly, not only in the proto where digest comparison is enough.
client/client_test.go
Outdated
|
|
||
| dockerfile := []byte(` | ||
| FROM scratch | ||
| COPY foo / |
There was a problem hiding this comment.
Add some renames to these copy operation to force a change in every step and avoid potential false positive. eg COPY foo foo2 llb.Copy(llb.NewState(ref), "foo2", "foo3")
client/client_test.go
Outdated
| require.Equal(t, dt, []byte("data")) | ||
| } | ||
|
|
||
| func testFrontendUseForwardedSolveResults(t *testing.T, sb integration.Sandbox) { |
There was a problem hiding this comment.
Maybe this test should be inside frontend/dockerfile pkg?
d3d4ec4 to
538946e
Compare
|
@hinshun needs rebase |
28641dd to
584fb0f
Compare
tonistiigi
left a comment
There was a problem hiding this comment.
I think we need a new cap for this, right? I assume NewState already errors on old daemons.
| return nil, errors.Errorf("reference ids and definitions mismatch length") | ||
| } | ||
|
|
||
| dop, err := llb.NewDefinitionOp(ref.Defs[0]) |
There was a problem hiding this comment.
Do this [0] selectors need to be protected to avoid panic (at least on old/misbehaving daemons)?
There was a problem hiding this comment.
I'll protect them. 👍
Signed-off-by: Edgar Lee <edgarl@netflix.com>
Signed-off-by: Edgar Lee <edgarl@netflix.com>
…ded solve test to dockerfile package Signed-off-by: Edgar Lee <edgarl@netflix.com>
Signed-off-by: Edgar Lee <edgarl@netflix.com>
@tonistiigi Thinking about how this will bubble up as an error. Instead of type Reference interface {
ToOutput() (llb.Output, error)
// ...
} |
|
@hinshun Maybe |
584fb0f to
503ae17
Compare
…ut to method ToOutput() Signed-off-by: Edgar Lee <edgarl@netflix.com>
503ae17 to
c83e8bf
Compare
|
@tonistiigi Do you think we can preserve context values in Example: fmt.Printf("env: %s\n", st.Env()) // => env: ["key=value"]
def, _ := st.Marshal()
res, _ := c.Solve(ctx, client.SolveRequest{Definition: def.ToPB()})
ref, _ := res.SingleRef()
st2, _ := ref.ToState()
fmt.Printf("env: %s\n", st2.Env()) // => env: ["key=value"] |
|
You can't get that information from the current proto. Not sure if it would make sense to add it. There is no magic inside |
|
Okay, I'll leave it out then. |
Depends on #1269
Fixes #751
Edit:
This PR introduces the ability to essentially marshal and unmarshal between
llb.Stateandpb.Definition. In addition, it also allows using previously solvedclient.Resultto be used as an input to a new build graph.For example, we can do some parallel solve requests, and then use their results in a new graph:
In order for previous solve results
(client.Result).SingleRefto be used as an argument forllb.NewState,client.Referencemust implementllb.Output. However, there is an import cycle related togw.ResolveImageConfigOptwhich I moved to thellbpackage. Let me know if you prefer this as a separate PR.client.Referenceimplementsllb.Outputwith the help of thepb.Definitionof the previous solve. When the new solve references anOpfrom a previous solve, it must still traverse the graph so the marshaled definitions responsible for the previous solve's result must be included in the new one. We implemented in a way such that users are not exposed to this detail.Questions
*llbBridgehandles a definition-based solve, it loads an edge from the definition:buildkit/solver/llbsolver/bridge.go
Lines 97 to 100 in 9257b28
Definitions end with an empty op (
(pb.Op).Op == nil) with a single input pointing to the lastOp. TheLoadfunction returns the edge referencing this lastOp:buildkit/solver/llbsolver/vertex.go
Line 228 in 9257b28
Which is eventually built by a
solver.Job:buildkit/solver/llbsolver/bridge.go
Lines 114 to 119 in 9257b28
The result that gets returned is the
llb.Vertexwe want to return, and we need it to also carry the full definition up to that vertex. It seems to only make sense to plumb the definition on the final result so I addedreq.Definitionto thefrontend.Result. Does this make sense? I'm not sure how this interplays with multi-result arrays.Todo