github.com/demonoid81/containerd@v1.3.4/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 introspectionapi "github.com/containerd/containerd/api/services/introspection/v1" 28 "github.com/containerd/containerd/archive" 29 "github.com/containerd/containerd/archive/compression" 30 "github.com/containerd/containerd/content" 31 "github.com/containerd/containerd/images" 32 "github.com/pkg/errors" 33 ) 34 35 // Install a binary image into the opt service 36 func (c *Client) Install(ctx context.Context, image Image, opts ...InstallOpts) error { 37 var config InstallConfig 38 for _, o := range opts { 39 o(&config) 40 } 41 path, err := c.getInstallPath(ctx, config) 42 if err != nil { 43 return err 44 } 45 var ( 46 cs = image.ContentStore() 47 platform = c.platform 48 ) 49 manifest, err := images.Manifest(ctx, cs, image.Target(), platform) 50 if err != nil { 51 return err 52 } 53 54 var binDir, libDir string 55 if runtime.GOOS == "windows" { 56 binDir = "Files\\bin" 57 libDir = "Files\\lib" 58 } else { 59 binDir = "bin" 60 libDir = "lib" 61 } 62 for _, layer := range manifest.Layers { 63 ra, err := cs.ReaderAt(ctx, layer) 64 if err != nil { 65 return err 66 } 67 cr := content.NewReader(ra) 68 r, err := compression.DecompressStream(cr) 69 if err != nil { 70 return err 71 } 72 if _, err := archive.Apply(ctx, path, r, archive.WithFilter(func(hdr *tar.Header) (bool, error) { 73 d := filepath.Dir(hdr.Name) 74 result := d == binDir 75 76 if config.Libs { 77 result = result || d == libDir 78 } 79 80 if runtime.GOOS == "windows" { 81 hdr.Name = strings.Replace(hdr.Name, "Files", "", 1) 82 } 83 if result && !config.Replace { 84 if _, err := os.Lstat(filepath.Join(path, hdr.Name)); err == nil { 85 return false, errors.Errorf("cannot replace %s in %s", hdr.Name, path) 86 } 87 } 88 return result, nil 89 })); err != nil { 90 r.Close() 91 return err 92 } 93 r.Close() 94 } 95 return nil 96 } 97 98 func (c *Client) getInstallPath(ctx context.Context, config InstallConfig) (string, error) { 99 if config.Path != "" { 100 return config.Path, nil 101 } 102 resp, err := c.IntrospectionService().Plugins(ctx, &introspectionapi.PluginsRequest{ 103 Filters: []string{ 104 "id==opt", 105 }, 106 }) 107 if err != nil { 108 return "", err 109 } 110 if len(resp.Plugins) != 1 { 111 return "", errors.New("opt service not enabled") 112 } 113 path := resp.Plugins[0].Exports["path"] 114 if path == "" { 115 return "", errors.New("opt path not exported") 116 } 117 return path, nil 118 }