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  }