github.com/containerd/nerdctl@v1.7.7/pkg/snapshotterutil/sociutil.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 snapshotterutil 18 19 import ( 20 "bufio" 21 "os" 22 "os/exec" 23 "strconv" 24 "strings" 25 26 "github.com/containerd/log" 27 "github.com/containerd/nerdctl/pkg/api/types" 28 ) 29 30 // CreateSoci creates a SOCI index(`rawRef`) 31 func CreateSoci(rawRef string, gOpts types.GlobalCommandOptions, allPlatform bool, platforms []string, sOpts types.SociOptions) error { 32 sociExecutable, err := exec.LookPath("soci") 33 if err != nil { 34 log.L.WithError(err).Error("soci executable not found in path $PATH") 35 log.L.Info("you might consider installing soci from: https://github.com/awslabs/soci-snapshotter/blob/main/docs/install.md") 36 return err 37 } 38 39 sociCmd := exec.Command(sociExecutable) 40 sociCmd.Env = os.Environ() 41 42 // #region for global flags. 43 if gOpts.Address != "" { 44 sociCmd.Args = append(sociCmd.Args, "--address", gOpts.Address) 45 } 46 if gOpts.Namespace != "" { 47 sociCmd.Args = append(sociCmd.Args, "--namespace", gOpts.Namespace) 48 } 49 // #endregion 50 51 // Global flags have to be put before subcommand before soci upgrades to urfave v3. 52 // https://github.com/urfave/cli/issues/1113 53 sociCmd.Args = append(sociCmd.Args, "create") 54 55 if allPlatform { 56 sociCmd.Args = append(sociCmd.Args, "--all-platforms", strconv.FormatBool(allPlatform)) 57 } 58 if len(platforms) > 0 { 59 sociCmd.Args = append(sociCmd.Args, "--platform") 60 sociCmd.Args = append(sociCmd.Args, strings.Join(platforms, ",")) 61 } 62 if sOpts.SpanSize != -1 { 63 sociCmd.Args = append(sociCmd.Args, "--span-size", strconv.FormatInt(sOpts.SpanSize, 10)) 64 } 65 if sOpts.MinLayerSize != -1 { 66 sociCmd.Args = append(sociCmd.Args, "--min-layer-size", strconv.FormatInt(sOpts.MinLayerSize, 10)) 67 } 68 // --timeout, --debug, --content-store 69 sociCmd.Args = append(sociCmd.Args, rawRef) 70 71 log.L.Debugf("running %s %v", sociExecutable, sociCmd.Args) 72 73 err = processSociIO(sociCmd) 74 if err != nil { 75 return err 76 } 77 78 return sociCmd.Wait() 79 } 80 81 // PushSoci pushes a SOCI index(`rawRef`) 82 // `hostsDirs` are used to resolve image `rawRef` 83 func PushSoci(rawRef string, gOpts types.GlobalCommandOptions, allPlatform bool, platforms []string) error { 84 log.L.Debugf("pushing SOCI index: %s", rawRef) 85 86 sociExecutable, err := exec.LookPath("soci") 87 if err != nil { 88 log.L.WithError(err).Error("soci executable not found in path $PATH") 89 log.L.Info("you might consider installing soci from: https://github.com/awslabs/soci-snapshotter/blob/main/docs/install.md") 90 return err 91 } 92 93 sociCmd := exec.Command(sociExecutable) 94 sociCmd.Env = os.Environ() 95 96 // #region for global flags. 97 if gOpts.Address != "" { 98 sociCmd.Args = append(sociCmd.Args, "--address", gOpts.Address) 99 } 100 if gOpts.Namespace != "" { 101 sociCmd.Args = append(sociCmd.Args, "--namespace", gOpts.Namespace) 102 } 103 // #endregion 104 105 // Global flags have to be put before subcommand before soci upgrades to urfave v3. 106 // https://github.com/urfave/cli/issues/1113 107 sociCmd.Args = append(sociCmd.Args, "push") 108 109 if allPlatform { 110 sociCmd.Args = append(sociCmd.Args, "--all-platforms", strconv.FormatBool(allPlatform)) 111 } 112 if len(platforms) > 0 { 113 sociCmd.Args = append(sociCmd.Args, "--platform") 114 sociCmd.Args = append(sociCmd.Args, strings.Join(platforms, ",")) 115 } 116 if gOpts.InsecureRegistry { 117 sociCmd.Args = append(sociCmd.Args, "--skip-verify") 118 sociCmd.Args = append(sociCmd.Args, "--plain-http") 119 } 120 if len(gOpts.HostsDir) > 0 { 121 sociCmd.Args = append(sociCmd.Args, "--hosts-dir") 122 sociCmd.Args = append(sociCmd.Args, strings.Join(gOpts.HostsDir, ",")) 123 } 124 sociCmd.Args = append(sociCmd.Args, rawRef) 125 126 log.L.Debugf("running %s %v", sociExecutable, sociCmd.Args) 127 128 err = processSociIO(sociCmd) 129 if err != nil { 130 return err 131 } 132 return sociCmd.Wait() 133 } 134 135 func processSociIO(sociCmd *exec.Cmd) error { 136 stdout, err := sociCmd.StdoutPipe() 137 if err != nil { 138 log.L.Warn("soci: " + err.Error()) 139 } 140 stderr, err := sociCmd.StderrPipe() 141 if err != nil { 142 log.L.Warn("soci: " + err.Error()) 143 } 144 if err := sociCmd.Start(); err != nil { 145 // only return err if it's critical (soci command failed to start.) 146 return err 147 } 148 149 scanner := bufio.NewScanner(stdout) 150 for scanner.Scan() { 151 log.L.Info("soci: " + scanner.Text()) 152 } 153 if err := scanner.Err(); err != nil { 154 log.L.Warn("soci: " + err.Error()) 155 } 156 157 errScanner := bufio.NewScanner(stderr) 158 for errScanner.Scan() { 159 log.L.Info("soci: " + errScanner.Text()) 160 } 161 if err := errScanner.Err(); err != nil { 162 log.L.Warn("soci: " + err.Error()) 163 } 164 165 return nil 166 }