github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/rkt/prepare.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //+build linux
    16  
    17  package main
    18  
    19  import (
    20  	"os"
    21  
    22  	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
    23  	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/spf13/cobra"
    24  	"github.com/coreos/rkt/common"
    25  	"github.com/coreos/rkt/pkg/lock"
    26  	"github.com/coreos/rkt/pkg/uid"
    27  	"github.com/coreos/rkt/stage0"
    28  	"github.com/coreos/rkt/store"
    29  )
    30  
    31  var (
    32  	cmdPrepare = &cobra.Command{
    33  		Use:   "prepare [--volume=name,kind=host,...] [--mount volume=VOL,target=PATH] [--quiet] IMAGE [-- image-args...[---]]...",
    34  		Short: "Prepare to run image(s) in a pod in rkt",
    35  		Long: `IMAGE should be a string referencing an image; either a hash, local file on disk, or URL.
    36  They will be checked in that order and the first match will be used.
    37  
    38  An "--" may be used to inhibit rkt prepare's parsing of subsequent arguments,
    39  which will instead be appended to the preceding image app's exec arguments.
    40  End the image arguments with a lone "---" to resume argument parsing.`,
    41  		Run: runWrapper(runPrepare),
    42  	}
    43  	flagQuiet bool
    44  )
    45  
    46  func init() {
    47  	cmdRkt.AddCommand(cmdPrepare)
    48  
    49  	addStage1ImageFlag(cmdPrepare.Flags())
    50  	cmdPrepare.Flags().Var(&flagPorts, "port", "ports to expose on the host (needs contained networking with NAT)")
    51  	cmdPrepare.Flags().BoolVar(&flagQuiet, "quiet", false, "suppress superfluous output on stdout, print only the UUID on success")
    52  	cmdPrepare.Flags().BoolVar(&flagInheritEnv, "inherit-env", false, "inherit all environment variables not set by apps")
    53  	cmdPrepare.Flags().BoolVar(&flagNoOverlay, "no-overlay", false, "disable overlay filesystem")
    54  	cmdPrepare.Flags().BoolVar(&flagPrivateUsers, "private-users", false, "run within user namespaces (experimental).")
    55  	cmdPrepare.Flags().Var(&flagExplicitEnv, "set-env", "an environment variable to set for apps in the form name=value")
    56  	cmdPrepare.Flags().BoolVar(&flagStoreOnly, "store-only", false, "use only available images in the store (do not discover or download from remote URLs)")
    57  	cmdPrepare.Flags().BoolVar(&flagNoStore, "no-store", false, "fetch images ignoring the local store")
    58  	cmdPrepare.Flags().StringVar(&flagPodManifest, "pod-manifest", "", "the path to the pod manifest. If it's non-empty, then only '--quiet' and '--no-overlay' will have effects")
    59  	cmdPrepare.Flags().Var((*appsVolume)(&rktApps), "volume", "volumes to make available in the pod")
    60  
    61  	// per-app flags
    62  	cmdPrepare.Flags().Var((*appExec)(&rktApps), "exec", "override the exec command for the preceding image")
    63  	cmdPrepare.Flags().Var((*appMount)(&rktApps), "mount", "mount point binding a volume to a path within an app")
    64  
    65  	// Disable interspersed flags to stop parsing after the first non flag
    66  	// argument. This is need to permit to correctly handle
    67  	// multiple "IMAGE -- imageargs ---"  options
    68  	cmdPrepare.Flags().SetInterspersed(false)
    69  }
    70  
    71  func runPrepare(cmd *cobra.Command, args []string) (exit int) {
    72  	var err error
    73  	origStdout := os.Stdout
    74  	privateUsers := uid.NewBlankUidRange()
    75  	if flagQuiet {
    76  		if os.Stdout, err = os.Open("/dev/null"); err != nil {
    77  			stderr("prepare: unable to open /dev/null: %v", err)
    78  			return 1
    79  		}
    80  	}
    81  
    82  	if flagStoreOnly && flagNoStore {
    83  		stderr("both --store-only and --no-store specified")
    84  		return 1
    85  	}
    86  
    87  	if flagPrivateUsers {
    88  		if !common.SupportsUserNS() {
    89  			stderr("prepare: --private-users is not supported, kernel compiled without user namespace support")
    90  			return 1
    91  		}
    92  		privateUsers.SetRandomUidRange(uid.DefaultRangeCount)
    93  	}
    94  
    95  	if err = parseApps(&rktApps, args, cmd.Flags(), true); err != nil {
    96  		stderr("prepare: error parsing app image arguments: %v", err)
    97  		return 1
    98  	}
    99  
   100  	if len(flagPodManifest) > 0 && (len(flagPorts) > 0 || flagInheritEnv || !flagExplicitEnv.IsEmpty() || flagStoreOnly || flagNoStore) {
   101  		stderr("prepare: conflicting flags set with --pod-manifest (see --help)")
   102  		return 1
   103  	}
   104  
   105  	if rktApps.Count() < 1 && len(flagPodManifest) == 0 {
   106  		stderr("prepare: must provide at least one image or specify the pod manifest")
   107  		return 1
   108  	}
   109  
   110  	s, err := store.NewStore(globalFlags.Dir)
   111  	if err != nil {
   112  		stderr("prepare: cannot open store: %v", err)
   113  		return 1
   114  	}
   115  
   116  	config, err := getConfig()
   117  	if err != nil {
   118  		stderr("prepare: cannot get configuration: %v", err)
   119  		return 1
   120  	}
   121  	fn := &finder{
   122  		imageActionData: imageActionData{
   123  			s:                  s,
   124  			headers:            config.AuthPerHost,
   125  			dockerAuth:         config.DockerCredentialsPerRegistry,
   126  			insecureSkipVerify: globalFlags.InsecureSkipVerify,
   127  			debug:              globalFlags.Debug,
   128  		},
   129  		storeOnly: flagStoreOnly,
   130  		noStore:   flagNoStore,
   131  		withDeps:  false,
   132  	}
   133  
   134  	s1img, err := getStage1Hash(s, cmd)
   135  	if err != nil {
   136  		stderr("prepare: %v", err)
   137  		return 1
   138  	}
   139  
   140  	fn.ks = getKeystore()
   141  	fn.withDeps = true
   142  	if err := fn.findImages(&rktApps); err != nil {
   143  		stderr("prepare: %v", err)
   144  		return 1
   145  	}
   146  
   147  	p, err := newPod()
   148  	if err != nil {
   149  		stderr("prepare: error creating new pod: %v", err)
   150  		return 1
   151  	}
   152  
   153  	cfg := stage0.CommonConfig{
   154  		Store:       s,
   155  		Stage1Image: *s1img,
   156  		UUID:        p.uuid,
   157  		Debug:       globalFlags.Debug,
   158  	}
   159  
   160  	pcfg := stage0.PrepareConfig{
   161  		CommonConfig: cfg,
   162  		UseOverlay:   !flagNoOverlay && common.SupportsOverlay(),
   163  		PrivateUsers: privateUsers,
   164  	}
   165  
   166  	if len(flagPodManifest) > 0 {
   167  		pcfg.PodManifest = flagPodManifest
   168  	} else {
   169  		pcfg.Ports = []types.ExposedPort(flagPorts)
   170  		pcfg.InheritEnv = flagInheritEnv
   171  		pcfg.ExplicitEnv = flagExplicitEnv.Strings()
   172  		pcfg.Apps = &rktApps
   173  	}
   174  
   175  	if globalFlags.Debug {
   176  		stage0.InitDebug()
   177  	}
   178  
   179  	keyLock, err := lock.SharedKeyLock(lockDir(), common.PrepareLock)
   180  	if err != nil {
   181  		stderr("rkt: cannot get shared prepare lock: %v", err)
   182  		return 1
   183  	}
   184  	if err = stage0.Prepare(pcfg, p.path(), p.uuid); err != nil {
   185  		stderr("prepare: error setting up stage0: %v", err)
   186  		keyLock.Close()
   187  		return 1
   188  	}
   189  	keyLock.Close()
   190  
   191  	if err := p.sync(); err != nil {
   192  		stderr("prepare: error syncing pod data: %v", err)
   193  		return 1
   194  	}
   195  
   196  	if err := p.xToPrepared(); err != nil {
   197  		stderr("prepare: error transitioning to prepared: %v", err)
   198  		return 1
   199  	}
   200  
   201  	os.Stdout = origStdout // restore output in case of --quiet
   202  	stdout("%s", p.uuid.String())
   203  
   204  	return 0
   205  }