github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/install.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package containerd 18 19 import ( 20 "archive/tar" 21 "context" 22 "os" 23 "path/filepath" 24 "runtime" 25 "strings" 26 27 "github.com/containerd/containerd/archive" 28 "github.com/containerd/containerd/archive/compression" 29 "github.com/containerd/containerd/content" 30 "github.com/containerd/containerd/images" 31 "github.com/pkg/errors" 32 ) 33 34 // Install a binary image into the opt service 35 func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts) error { 36 var config InstallConfig 37 for _, o := range opts { 38 o(&config) 39 } 40 path, err := c.getInstallPath(ctx, config) 41 if err != nil { 42 return err 43 } 44 var ( 45 cs = image.ContentStore() 46 platform = c.platform 47 ) 48 manifest, err := images.Manifest(ctx, cs, image.Target(), platform) 49 if err != nil { 50 return err 51 } 52 53 var binDir, libDir string 54 if runtime.GOOS == "windows" { 55 binDir = "Files\\bin" 56 libDir = "Files\\lib" 57 } else { 58 binDir = "bin" 59 libDir = "lib" 60 } 61 for _, layer := range manifest.Layers { 62 ra, err := cs.ReaderAt(ctx, layer) 63 if err != nil { 64 return err 65 } 66 cr := content.NewReader(ra) 67 r, err := compression.DecompressStream(cr) 68 if err != nil { 69 return err 70 } 71 if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) { 72 d := filepath.Dir(hdr.Name) 73 result := d == binDir 74 75 if config.Libs { 76 result = result || d == libDir 77 } 78 79 if runtime.GOOS == "windows" { 80 hdr.Name = strings.Replace(hdr.Name, "Files", "", 1) 81 } 82 if result && !config.Replace { 83 if _, err := os.Lstat(filepath.Join(path, hdr.Name)); err == nil { 84 return false, errors.Errorf("cannot replace %s in %s", hdr.Name, path) 85 } 86 } 87 return result, nil 88 })); err != nil { 89 r.Close() 90 return err 91 } 92 r.Close() 93 } 94 return nil 95 } 96 97 func (c *Client) getInstallPath(ctx context.Context, config InstallConfig) (string, error) { 98 if config.Path != "" { 99 return config.Path, nil 100 } 101 filters := []string{"id==opt"} 102 resp, err := c.IntrospectionService().Plugins(ctx, filters) 103 if err != nil { 104 return "", err 105 } 106 if len(resp.Plugins) != 1 { 107 return "", errors.New("opt service not enabled") 108 } 109 path := resp.Plugins[0].Exports["path"] 110 if path == "" { 111 return "", errors.New("opt path not exported") 112 } 113 return path, nil 114 }