llb: add readonly mounts support
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-18.09
parent
eac79f7c7e
commit
ff951eecd9
|
@ -33,7 +33,7 @@ func TestManager(t *testing.T) {
|
|||
active, err := cm.New(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
m, err := active.Mount(ctx)
|
||||
m, err := active.Mount(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(m)
|
||||
|
|
|
@ -30,7 +30,7 @@ type MutableRef interface {
|
|||
}
|
||||
|
||||
type Mountable interface {
|
||||
Mount(ctx context.Context) ([]mount.Mount, error)
|
||||
Mount(ctx context.Context, readonly bool) ([]mount.Mount, error)
|
||||
}
|
||||
|
||||
type cacheRecord struct {
|
||||
|
@ -101,7 +101,7 @@ func (cr *cacheRecord) Parent() ImmutableRef {
|
|||
return cr.parent.(*immutableRef).ref()
|
||||
}
|
||||
|
||||
func (cr *cacheRecord) Mount(ctx context.Context) ([]mount.Mount, error) {
|
||||
func (cr *cacheRecord) Mount(ctx context.Context, readonly bool) ([]mount.Mount, error) {
|
||||
cr.mu.Lock()
|
||||
defer cr.mu.Unlock()
|
||||
|
||||
|
@ -110,8 +110,20 @@ func (cr *cacheRecord) Mount(ctx context.Context) ([]mount.Mount, error) {
|
|||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to mount %s", cr.ID())
|
||||
}
|
||||
if readonly {
|
||||
m = setReadonly(m)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if cr.equalMutable != nil && readonly {
|
||||
m, err := cr.cm.Snapshotter.Mounts(ctx, cr.equalMutable.ID())
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to mount %s", cr.equalMutable.ID())
|
||||
}
|
||||
return setReadonly(m), nil
|
||||
}
|
||||
|
||||
if err := cr.finalize(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -268,3 +280,17 @@ func (sr *mutableRef) release(ctx context.Context) error {
|
|||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
func setReadonly(mounts []mount.Mount) []mount.Mount {
|
||||
for i, m := range mounts {
|
||||
opts := make([]string, 0, len(m.Options))
|
||||
for _, opt := range m.Options {
|
||||
if opt != "rw" {
|
||||
opts = append(opts, opt)
|
||||
}
|
||||
}
|
||||
opts = append(opts, "ro")
|
||||
mounts[i].Options = opts
|
||||
}
|
||||
return mounts
|
||||
}
|
||||
|
|
|
@ -167,8 +167,9 @@ func (eo *exec) marshalTo(list [][]byte, cache map[digest.Digest]struct{}) (dige
|
|||
}
|
||||
|
||||
pm := &pb.Mount{
|
||||
Input: int64(inputIndex),
|
||||
Dest: m.dest,
|
||||
Input: int64(inputIndex),
|
||||
Dest: m.dest,
|
||||
Readonly: m.readonly,
|
||||
}
|
||||
if m.hasOutput {
|
||||
pm.Output = outputIndex
|
||||
|
@ -186,7 +187,7 @@ func (eo *exec) marshalTo(list [][]byte, cache map[digest.Digest]struct{}) (dige
|
|||
type mount struct {
|
||||
execState *ExecState
|
||||
dest string
|
||||
// ro bool
|
||||
readonly bool
|
||||
// either parent or source has to be set
|
||||
parent *mount
|
||||
source *source
|
||||
|
|
|
@ -138,7 +138,7 @@ type ExecState struct {
|
|||
State
|
||||
}
|
||||
|
||||
func (s *ExecState) AddMount(dest string, mountState *State) *State {
|
||||
func (s *ExecState) AddMount(dest string, mountState *State, opts ...MountOption) *State {
|
||||
m := &mount{
|
||||
dest: dest,
|
||||
source: mountState.source,
|
||||
|
@ -146,6 +146,9 @@ func (s *ExecState) AddMount(dest string, mountState *State) *State {
|
|||
execState: s,
|
||||
hasOutput: true, // TODO: should be set only if something inherits
|
||||
}
|
||||
for _, opt := range opts {
|
||||
opt(m)
|
||||
}
|
||||
var newState State
|
||||
newState.meta = s.meta
|
||||
newState.metaNext = s.metaNext
|
||||
|
@ -182,9 +185,15 @@ func (s *ExecState) updateMeta(fn metaOption) *ExecState {
|
|||
|
||||
type RunOption func(es *ExecState) *ExecState
|
||||
|
||||
func AddMount(dest string, mountState *State) RunOption {
|
||||
type MountOption func(*mount)
|
||||
|
||||
func Readonly(m *mount) {
|
||||
m.readonly = true
|
||||
}
|
||||
|
||||
func AddMount(dest string, mountState *State, opts ...MountOption) RunOption {
|
||||
return func(es *ExecState) *ExecState {
|
||||
es.AddMount(dest, mountState)
|
||||
es.AddMount(dest, mountState, opts...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func TestControl(t *testing.T) {
|
|||
snap, err := src.Snapshot(ctx)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mounts, err := snap.Mount(ctx)
|
||||
mounts, err := snap.Mount(ctx, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(mounts)
|
||||
|
@ -127,7 +127,7 @@ func TestControl(t *testing.T) {
|
|||
rf, err := root.Commit(ctx)
|
||||
assert.NoError(t, err)
|
||||
|
||||
mounts, err = rf.Mount(ctx)
|
||||
mounts, err = rf.Mount(ctx, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
lm = snapshot.LocalMounter(mounts)
|
||||
|
|
|
@ -113,12 +113,12 @@ func (e *imageExporter) getBlobs(ctx context.Context, ref cache.ImmutableRef) ([
|
|||
var lower []mount.Mount
|
||||
if parent != nil {
|
||||
defer parent.Release(context.TODO())
|
||||
lower, err = parent.Mount(ctx)
|
||||
lower, err = parent.Mount(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
upper, err := ref.Mount(ctx)
|
||||
upper, err := ref.Mount(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ func (e *execOp) CacheKey(ctx context.Context, inputs []string) (string, int, er
|
|||
|
||||
func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, error) {
|
||||
var mounts []worker.Mount
|
||||
var outputs []cache.MutableRef
|
||||
var outputs []Reference
|
||||
var root cache.Mountable
|
||||
|
||||
defer func() {
|
||||
|
@ -77,17 +77,21 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
|
|||
mountable = ref
|
||||
}
|
||||
if m.Output != pb.SkipOutput {
|
||||
active, err := e.cm.New(ctx, ref) // TODO: should be method
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if m.Readonly && ref != nil {
|
||||
outputs = append(outputs, newSharedRef(ref).Clone())
|
||||
} else {
|
||||
active, err := e.cm.New(ctx, ref) // TODO: should be method
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputs = append(outputs, active)
|
||||
mountable = active
|
||||
}
|
||||
outputs = append(outputs, active)
|
||||
mountable = active
|
||||
}
|
||||
if m.Dest == pb.RootMount {
|
||||
root = mountable
|
||||
} else {
|
||||
mounts = append(mounts, worker.Mount{Src: mountable, Dest: m.Dest})
|
||||
mounts = append(mounts, worker.Mount{Src: mountable, Dest: m.Dest, Readonly: m.Readonly})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,11 +115,15 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
|
|||
|
||||
refs := []Reference{}
|
||||
for i, o := range outputs {
|
||||
ref, err := o.Commit(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error committing %s", o.ID())
|
||||
if mutable, ok := o.(cache.MutableRef); ok {
|
||||
ref, err := mutable.Commit(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error committing %s", mutable.ID())
|
||||
}
|
||||
refs = append(refs, ref)
|
||||
} else {
|
||||
refs = append(refs, o)
|
||||
}
|
||||
refs = append(refs, ref)
|
||||
outputs[i] = nil
|
||||
}
|
||||
return refs, nil
|
||||
|
|
|
@ -216,6 +216,7 @@ type Mount struct {
|
|||
Selector string `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"`
|
||||
Dest string `protobuf:"bytes,3,opt,name=dest,proto3" json:"dest,omitempty"`
|
||||
Output int64 `protobuf:"varint,4,opt,name=output,proto3" json:"output,omitempty"`
|
||||
Readonly bool `protobuf:"varint,5,opt,name=readonly,proto3" json:"readonly,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Mount) Reset() { *m = Mount{} }
|
||||
|
@ -513,6 +514,16 @@ func (m *Mount) MarshalTo(data []byte) (int, error) {
|
|||
i++
|
||||
i = encodeVarintOps(data, i, uint64(m.Output))
|
||||
}
|
||||
if m.Readonly {
|
||||
data[i] = 0x28
|
||||
i++
|
||||
if m.Readonly {
|
||||
data[i] = 1
|
||||
} else {
|
||||
data[i] = 0
|
||||
}
|
||||
i++
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
|
@ -759,6 +770,9 @@ func (m *Mount) Size() (n int) {
|
|||
if m.Output != 0 {
|
||||
n += 1 + sovOps(uint64(m.Output))
|
||||
}
|
||||
if m.Readonly {
|
||||
n += 2
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
@ -1473,6 +1487,26 @@ func (m *Mount) Unmarshal(data []byte) error {
|
|||
break
|
||||
}
|
||||
}
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Readonly", wireType)
|
||||
}
|
||||
var v int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowOps
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := data[iNdEx]
|
||||
iNdEx++
|
||||
v |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Readonly = bool(v != 0)
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipOps(data[iNdEx:])
|
||||
|
|
|
@ -34,6 +34,7 @@ message Mount {
|
|||
string selector = 2;
|
||||
string dest = 3;
|
||||
int64 output = 4;
|
||||
bool readonly = 5;
|
||||
}
|
||||
|
||||
message CopyOp {
|
||||
|
|
|
@ -95,7 +95,7 @@ func (gs *gitSource) mountRemote(ctx context.Context, remote string) (target str
|
|||
}
|
||||
}()
|
||||
|
||||
mount, err := remoteRef.Mount(ctx)
|
||||
mount, err := remoteRef.Mount(ctx, false)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context) (out cache.ImmutableRe
|
|||
}
|
||||
}()
|
||||
|
||||
mount, err := checkoutRef.Mount(ctx)
|
||||
mount, err := checkoutRef.Mount(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ func testRepeatedFetch(t *testing.T, keepGitDir bool) {
|
|||
require.NoError(t, err)
|
||||
defer ref1.Release(context.TODO())
|
||||
|
||||
mount, err := ref1.Mount(ctx)
|
||||
mount, err := ref1.Mount(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(mount)
|
||||
|
@ -102,7 +102,7 @@ func testRepeatedFetch(t *testing.T, keepGitDir bool) {
|
|||
require.NoError(t, err)
|
||||
defer ref3.Release(context.TODO())
|
||||
|
||||
mount, err = ref3.Mount(ctx)
|
||||
mount, err = ref3.Mount(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm = snapshot.LocalMounter(mount)
|
||||
|
@ -161,7 +161,7 @@ func testFetchBySHA(t *testing.T, keepGitDir bool) {
|
|||
require.NoError(t, err)
|
||||
defer ref1.Release(context.TODO())
|
||||
|
||||
mount, err := ref1.Mount(ctx)
|
||||
mount, err := ref1.Mount(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(mount)
|
||||
|
@ -234,7 +234,7 @@ func testMultipleRepos(t *testing.T, keepGitDir bool) {
|
|||
require.NoError(t, err)
|
||||
defer ref1.Release(context.TODO())
|
||||
|
||||
mount, err := ref1.Mount(ctx)
|
||||
mount, err := ref1.Mount(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm := snapshot.LocalMounter(mount)
|
||||
|
@ -246,7 +246,7 @@ func testMultipleRepos(t *testing.T, keepGitDir bool) {
|
|||
require.NoError(t, err)
|
||||
defer ref2.Release(context.TODO())
|
||||
|
||||
mount, err = ref2.Mount(ctx)
|
||||
mount, err = ref2.Mount(ctx, false)
|
||||
require.NoError(t, err)
|
||||
|
||||
lm = snapshot.LocalMounter(mount)
|
||||
|
|
|
@ -118,7 +118,7 @@ func (ls *localSourceHandler) Snapshot(ctx context.Context) (out cache.Immutable
|
|||
}
|
||||
}()
|
||||
|
||||
mount, err := mutable.Mount(ctx)
|
||||
mount, err := mutable.Mount(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func GenerateSpec(ctx context.Context, meta worker.Meta, mounts []worker.Mount)
|
|||
// TODO: User
|
||||
|
||||
for _, m := range mounts {
|
||||
mounts, err := m.Src.Mount(ctx)
|
||||
mounts, err := m.Src.Mount(ctx, m.Readonly)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to mount %s", m.Dest)
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ func New(root string) (worker.Worker, error) {
|
|||
}
|
||||
|
||||
func (w *runcworker) Exec(ctx context.Context, meta worker.Meta, root cache.Mountable, mounts []worker.Mount, stdout, stderr io.WriteCloser) error {
|
||||
rootMount, err := root.Mount(ctx)
|
||||
rootMount, err := root.Mount(ctx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ type Meta struct {
|
|||
type Mount struct {
|
||||
Src cache.Mountable
|
||||
Dest string
|
||||
ReadOnly bool
|
||||
Readonly bool
|
||||
}
|
||||
|
||||
type Worker interface {
|
||||
|
|
Loading…
Reference in New Issue