github.com/apptainer/singularity@v3.1.1+incompatible/internal/app/singularity/oci_create_linux.go (about)

     1  // Copyright (c) 2018-2019, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package singularity
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"github.com/opencontainers/runtime-tools/generate"
    16  	"github.com/sylabs/singularity/internal/pkg/buildcfg"
    17  	"github.com/sylabs/singularity/internal/pkg/runtime/engines/config"
    18  	"github.com/sylabs/singularity/internal/pkg/runtime/engines/oci"
    19  	"github.com/sylabs/singularity/internal/pkg/sylog"
    20  	"github.com/sylabs/singularity/internal/pkg/util/exec"
    21  )
    22  
    23  // OciCreate creates a container from an OCI bundle
    24  func OciCreate(containerID string, args *OciArgs) error {
    25  	starter := buildcfg.LIBEXECDIR + "/singularity/bin/starter"
    26  
    27  	_, err := getState(containerID)
    28  	if err == nil {
    29  		return fmt.Errorf("%s already exists", containerID)
    30  	}
    31  
    32  	os.Clearenv()
    33  
    34  	absBundle, err := filepath.Abs(args.BundlePath)
    35  	if err != nil {
    36  		return fmt.Errorf("failed to determine bundle absolute path: %s", err)
    37  	}
    38  
    39  	if err := os.Chdir(absBundle); err != nil {
    40  		return fmt.Errorf("failed to change directory to %s: %s", absBundle, err)
    41  	}
    42  
    43  	engineConfig := oci.NewConfig()
    44  	generator := generate.Generator{Config: &engineConfig.OciConfig.Spec}
    45  	engineConfig.SetBundlePath(absBundle)
    46  	engineConfig.SetLogPath(args.LogPath)
    47  	engineConfig.SetLogFormat(args.LogFormat)
    48  	engineConfig.SetPidFile(args.PidFile)
    49  
    50  	// load config.json from bundle path
    51  	configJSON := filepath.Join(absBundle, "config.json")
    52  	fb, err := os.Open(configJSON)
    53  	if err != nil {
    54  		return fmt.Errorf("OCI specification file %q is missing or cannot be read", configJSON)
    55  	}
    56  
    57  	data, err := ioutil.ReadAll(fb)
    58  	if err != nil {
    59  		return fmt.Errorf("failed to read OCI specification file %s: %s", configJSON, err)
    60  	}
    61  
    62  	fb.Close()
    63  
    64  	if err := json.Unmarshal(data, generator.Config); err != nil {
    65  		return fmt.Errorf("failed to parse OCI specification file %s: %s", configJSON, err)
    66  	}
    67  
    68  	Env := []string{sylog.GetEnvVar()}
    69  
    70  	engineConfig.EmptyProcess = args.EmptyProcess
    71  	engineConfig.SyncSocket = args.SyncSocketPath
    72  
    73  	commonConfig := &config.Common{
    74  		ContainerID:  containerID,
    75  		EngineName:   oci.Name,
    76  		EngineConfig: engineConfig,
    77  	}
    78  
    79  	configData, err := json.Marshal(commonConfig)
    80  	if err != nil {
    81  		sylog.Fatalf("%s", err)
    82  	}
    83  
    84  	procName := fmt.Sprintf("Singularity OCI %s", containerID)
    85  	cmd, err := exec.PipeCommand(starter, []string{procName}, Env, configData)
    86  	cmd.Stdout = os.Stdout
    87  	cmd.Stderr = os.Stderr
    88  	cmd.Stdin = os.Stdin
    89  
    90  	return cmd.Run()
    91  }