github.com/replicatedhq/ship@v0.55.0/pkg/lifecycle/render/dockerlayer/layer.go (about) 1 package dockerlayer 2 3 import ( 4 "context" 5 "path" 6 7 "github.com/go-kit/kit/log" 8 "github.com/go-kit/kit/log/level" 9 "github.com/mholt/archiver" 10 "github.com/pkg/errors" 11 "github.com/replicatedhq/libyaml" 12 "github.com/replicatedhq/ship/pkg/api" 13 "github.com/replicatedhq/ship/pkg/lifecycle/render/docker" 14 "github.com/replicatedhq/ship/pkg/lifecycle/render/root" 15 "github.com/replicatedhq/ship/pkg/util" 16 "github.com/spf13/afero" 17 "github.com/spf13/viper" 18 ) 19 20 // An unpacker 21 type Unpacker struct { 22 Logger log.Logger 23 FS afero.Afero 24 Viper *viper.Viper 25 DockerSaver docker.Renderer 26 Tar archiver.Archiver 27 } 28 29 func TarArchiver() archiver.Archiver { 30 return archiver.Tar 31 } 32 33 func NewUnpacker( 34 logger log.Logger, 35 dockerStep docker.Renderer, 36 fs afero.Afero, 37 viper *viper.Viper, 38 tar archiver.Archiver, 39 ) *Unpacker { 40 41 return &Unpacker{ 42 Logger: logger, 43 FS: fs, 44 Viper: viper, 45 DockerSaver: dockerStep, 46 Tar: tar, 47 } 48 } 49 50 func (u *Unpacker) Execute( 51 rootFs root.Fs, 52 asset api.DockerLayerAsset, 53 meta api.ReleaseMetadata, 54 doWithProgress func(ch chan interface{}, logger log.Logger) error, 55 templateContext map[string]interface{}, 56 configGroups []libyaml.ConfigGroup, 57 ) func(context.Context) error { 58 return func(ctx context.Context) error { 59 debug := level.Debug(log.With(u.Logger, "step.type", "render", "render.phase", "execute", "asset.type", "dockerlayer", "dest", asset.Dest, "description", asset.Description)) 60 61 if err := u.mkdirall(rootFs, "tmp")(); err != nil { 62 return errors.Wrap(err, "create root tmp path dir") 63 } 64 savePath, firstPassUnpackPath, basePath, layerPath, err := u.getPaths(asset, rootFs) 65 defer rootFs.RemoveAll("tmp") // nolint: errcheck 66 if err != nil { 67 return errors.Wrap(err, "resolve unpack paths") 68 } 69 70 err = util.IsLegalPath(basePath) 71 if err != nil { 72 return errors.Wrap(err, "write docker layer") 73 } 74 75 debug.Log( 76 "event", "execute", 77 "savePath", savePath, 78 "firstUnpack", firstPassUnpackPath, 79 "basePath", basePath, 80 "layerPath", layerPath, 81 ) 82 83 return errors.Wrap(u.chain( 84 u.save(ctx, rootFs, asset, meta, doWithProgress, savePath, templateContext, configGroups), 85 u.mkdirall(rootFs, basePath), 86 u.unpack(rootFs, savePath, firstPassUnpackPath), 87 u.unpack(rootFs, layerPath, basePath), 88 ), "execute chain") 89 } 90 } 91 92 func (u *Unpacker) getPaths(asset api.DockerLayerAsset, rootFs root.Fs) (string, string, string, string, error) { 93 fail := func(err error) (string, string, string, string, error) { return "", "", "", "", err } 94 95 saveDir, err := rootFs.TempDir("/tmp", "dockerlayer") 96 if err != nil { 97 return fail(errors.Wrap(err, "get image save tmpdir")) 98 } 99 100 savePath := path.Join(saveDir, "image.tar") 101 102 firstPassUnpackPath, err := rootFs.TempDir("/tmp", "dockerlayer") 103 if err != nil { 104 return fail(errors.Wrap(err, "get unpack tmpdir")) 105 } 106 107 basePath := asset.Dest //TODO enforce that this is a directory 108 layerPath := path.Join(firstPassUnpackPath, asset.Layer, "layer.tar") 109 return savePath, firstPassUnpackPath, basePath, layerPath, nil 110 } 111 112 func (u *Unpacker) save( 113 ctx context.Context, 114 rootFs root.Fs, 115 asset api.DockerLayerAsset, 116 meta api.ReleaseMetadata, 117 doWithProgress func(ch chan interface{}, logger log.Logger) error, 118 savePath string, 119 templateContext map[string]interface{}, 120 configGroups []libyaml.ConfigGroup, 121 ) func() error { 122 return func() error { 123 return errors.Wrapf( 124 u.DockerSaver.Execute( 125 rootFs, 126 asset.DockerAsset, 127 meta, 128 doWithProgress, 129 savePath, 130 templateContext, 131 configGroups, 132 )(ctx), 133 "save image to %s ", savePath) 134 } 135 } 136 137 func (u *Unpacker) unpack(rootFs root.Fs, src string, dest string) func() error { 138 return func() error { 139 rootPathedSrc := path.Join(rootFs.RootPath, src) 140 rootPathedDest := path.Join(rootFs.RootPath, dest) 141 return errors.Wrapf(u.Tar.Open(rootPathedSrc, rootPathedDest), "untar %s to %s", rootPathedSrc, rootPathedDest) 142 } 143 } 144 145 func (u *Unpacker) mkdirall(rootFs root.Fs, basePath string) func() error { 146 return func() error { 147 return errors.Wrapf(rootFs.MkdirAll(basePath, 0755), "mkdirall %s", basePath) 148 } 149 } 150 151 // this is here because it makes sense here, not trying to reinvent any wheels 152 func (u *Unpacker) chain(fs ...func() error) error { 153 for _, f := range fs { 154 if err := f(); err != nil { 155 return err 156 } 157 } 158 return nil 159 }