github.com/mfpierre/corectl@v0.5.6/load.go (about)

     1  // Copyright 2015 - António Meireles  <antonio.meireles@reformi.st>
     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  
    16  package main
    17  
    18  import (
    19  	"bytes"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"reflect"
    23  	"sort"
    24  	"strings"
    25  
    26  	"github.com/spf13/cobra"
    27  	"github.com/spf13/pflag"
    28  	"github.com/spf13/viper"
    29  )
    30  
    31  var (
    32  	loadFCmd = &cobra.Command{
    33  		Use:   "load path/to/yourProfile",
    34  		Short: "Loads CoreOS instances defined in an instrumentation file.",
    35  		Long: "Loads CoreOS instances defined in an instrumentation file " +
    36  			"(either in TOML, JSON or YAML format).\n" + "VMs are always launched " +
    37  			"by alphabetical order relative to their names.",
    38  		PreRunE: func(cmd *cobra.Command, args []string) (err error) {
    39  			if len(args) != 1 {
    40  				return fmt.Errorf("Incorrect usage: " +
    41  					"This command requires one argument (a file path)")
    42  			}
    43  			engine.rawArgs.BindPFlags(cmd.Flags())
    44  			return engine.allowedToRun()
    45  		},
    46  		RunE:    loadCommand,
    47  		Example: `  corectl load profiles/demo.toml`,
    48  	}
    49  )
    50  
    51  func loadCommand(cmd *cobra.Command, args []string) (err error) {
    52  	var (
    53  		vmDefs  = make(map[string]*viper.Viper)
    54  		ordered []string
    55  		f       []byte
    56  		def     = args[0]
    57  		setup   = viper.New()
    58  	)
    59  
    60  	if f, err = ioutil.ReadFile(def); err != nil {
    61  		return
    62  	}
    63  
    64  	if strings.HasSuffix(def, ".toml") {
    65  		setup.SetConfigType("toml")
    66  	} else if strings.HasSuffix(def, ".json") {
    67  		setup.SetConfigType("json")
    68  	} else if strings.HasSuffix(def, ".yaml") ||
    69  		strings.HasSuffix(def, ".yml") {
    70  		setup.SetConfigType("yaml")
    71  	} else {
    72  		return fmt.Errorf("%s unable to guess format via suffix", def)
    73  	}
    74  
    75  	if err = setup.ReadConfig(bytes.NewBuffer(f)); err != nil {
    76  		return
    77  	}
    78  
    79  	for name, def := range setup.AllSettings() {
    80  		if reflect.ValueOf(def).Kind() == reflect.Map {
    81  			lf := pflag.NewFlagSet(name, 0)
    82  			runFlagsDefaults(lf)
    83  			vmDefs[name] = viper.New()
    84  			vmDefs[name].BindPFlags(lf)
    85  
    86  			for x, xx := range setup.AllSettings() {
    87  				if reflect.ValueOf(x).Kind() != reflect.Map {
    88  					vmDefs[name].Set(x, xx)
    89  				}
    90  			}
    91  			for x, xx := range def.(map[string]interface{}) {
    92  				vmDefs[name].Set(x, xx)
    93  			}
    94  			vmDefs[name].Set("name", name)
    95  			vmDefs[name].Set("detached", true)
    96  		}
    97  	}
    98  	// (re)order alphabeticaly order to ensure cheap deterministic boot ordering
    99  	for name := range vmDefs {
   100  		ordered = append(ordered, name)
   101  	}
   102  	sort.Strings(ordered)
   103  	for slot, name := range ordered {
   104  		fmt.Println("> booting", name)
   105  		engine.VMs = append(engine.VMs, vmContext{})
   106  		if err = engine.boot(slot, vmDefs[name]); err != nil {
   107  			return
   108  		}
   109  	}
   110  	return
   111  }
   112  
   113  func init() {
   114  	RootCmd.AddCommand(loadFCmd)
   115  }