github.com/coreos/mantle@v0.13.0/cmd/kola/kola.go (about)

     1  // Copyright 2015 CoreOS, Inc.
     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  package main
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"os"
    21  	"path/filepath"
    22  	"sort"
    23  	"text/tabwriter"
    24  
    25  	"github.com/coreos/pkg/capnslog"
    26  	"github.com/spf13/cobra"
    27  
    28  	"github.com/coreos/mantle/cli"
    29  	"github.com/coreos/mantle/kola"
    30  	"github.com/coreos/mantle/kola/register"
    31  
    32  	// register OS test suite
    33  	_ "github.com/coreos/mantle/kola/registry"
    34  )
    35  
    36  var (
    37  	plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "kola")
    38  
    39  	root = &cobra.Command{
    40  		Use:   "kola [command]",
    41  		Short: "The CoreOS Superdeep Borehole",
    42  		// http://en.wikipedia.org/wiki/Kola_Superdeep_Borehole
    43  	}
    44  
    45  	cmdRun = &cobra.Command{
    46  		Use:   "run [glob pattern]",
    47  		Short: "Run kola tests by category",
    48  		Long: `Run all kola tests (default) or related groups.
    49  
    50  If the glob pattern is exactly equal to the name of a single test, any
    51  restrictions on the versions of Container Linux supported by that test
    52  will be ignored.
    53  `,
    54  		Run:    runRun,
    55  		PreRun: preRun,
    56  	}
    57  
    58  	cmdList = &cobra.Command{
    59  		Use:   "list",
    60  		Short: "List kola test names",
    61  		Run:   runList,
    62  	}
    63  
    64  	listJSON bool
    65  )
    66  
    67  func init() {
    68  	root.AddCommand(cmdRun)
    69  	root.AddCommand(cmdList)
    70  
    71  	cmdList.Flags().BoolVar(&listJSON, "json", false, "format output in JSON")
    72  }
    73  
    74  func main() {
    75  	cli.Execute(root)
    76  }
    77  
    78  func preRun(cmd *cobra.Command, args []string) {
    79  	err := syncOptions()
    80  	if err != nil {
    81  		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
    82  		os.Exit(3)
    83  	}
    84  
    85  	// Packet uses storage, and storage talks too much.
    86  	if !plog.LevelAt(capnslog.INFO) {
    87  		mantleLogger := capnslog.MustRepoLogger("github.com/coreos/mantle")
    88  		mantleLogger.SetLogLevel(map[string]capnslog.LogLevel{
    89  			"storage": capnslog.WARNING,
    90  		})
    91  	}
    92  }
    93  
    94  func runRun(cmd *cobra.Command, args []string) {
    95  	if len(args) > 1 {
    96  		fmt.Fprintf(os.Stderr, "Extra arguments specified. Usage: 'kola run [glob pattern]'\n")
    97  		os.Exit(2)
    98  	}
    99  	var pattern string
   100  	if len(args) == 1 {
   101  		pattern = args[0]
   102  	} else {
   103  		pattern = "*" // run all tests by default
   104  	}
   105  
   106  	var err error
   107  	outputDir, err = kola.SetupOutputDir(outputDir, kolaPlatform)
   108  	if err != nil {
   109  		fmt.Fprintf(os.Stderr, "%v\n", err)
   110  		os.Exit(1)
   111  	}
   112  
   113  	runErr := kola.RunTests(pattern, kolaPlatform, outputDir)
   114  
   115  	// needs to be after RunTests() because harness empties the directory
   116  	if err := writeProps(); err != nil {
   117  		fmt.Fprintf(os.Stderr, "%v\n", err)
   118  		os.Exit(1)
   119  	}
   120  
   121  	if runErr != nil {
   122  		fmt.Fprintf(os.Stderr, "%v\n", runErr)
   123  		os.Exit(1)
   124  	}
   125  }
   126  
   127  func writeProps() error {
   128  	f, err := os.OpenFile(filepath.Join(outputDir, "properties.json"), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
   129  	if err != nil {
   130  		return err
   131  	}
   132  	defer f.Close()
   133  
   134  	enc := json.NewEncoder(f)
   135  	enc.SetIndent("", "    ")
   136  
   137  	type AWS struct {
   138  		Region       string `json:"region"`
   139  		AMI          string `json:"ami"`
   140  		InstanceType string `json:"type"`
   141  	}
   142  	type Azure struct {
   143  		DiskURI   string `json:"diskUri"`
   144  		Publisher string `json:"publisher"`
   145  		Offer     string `json:"offer"`
   146  		Sku       string `json:"sku"`
   147  		Version   string `json:"version"`
   148  		Location  string `json:"location"`
   149  		Size      string `json:"size"`
   150  	}
   151  	type DO struct {
   152  		Region string `json:"region"`
   153  		Size   string `json:"size"`
   154  		Image  string `json:"image"`
   155  	}
   156  	type ESX struct {
   157  		Server     string `json:"server"`
   158  		BaseVMName string `json:"base_vm_name"`
   159  	}
   160  	type GCE struct {
   161  		Image       string `json:"image"`
   162  		MachineType string `json:"type"`
   163  	}
   164  	type OpenStack struct {
   165  		Region string `json:"region"`
   166  		Image  string `json:"image"`
   167  		Flavor string `json:"flavor"`
   168  	}
   169  	type Packet struct {
   170  		Facility              string `json:"facility"`
   171  		Plan                  string `json:"plan"`
   172  		InstallerImageBaseURL string `json:"installer"`
   173  		ImageURL              string `json:"image"`
   174  	}
   175  	type QEMU struct {
   176  		Image   string `json:"image"`
   177  		Mangled bool   `json:"mangled"`
   178  	}
   179  	return enc.Encode(&struct {
   180  		Cmdline         []string  `json:"cmdline"`
   181  		Platform        string    `json:"platform"`
   182  		Distro          string    `json:"distro"`
   183  		IgnitionVersion string    `json:"ignitionversion"`
   184  		Board           string    `json:"board"`
   185  		OSContainer     string    `json:"oscontainer"`
   186  		AWS             AWS       `json:"aws"`
   187  		Azure           Azure     `json:"azure"`
   188  		DO              DO        `json:"do"`
   189  		ESX             ESX       `json:"esx"`
   190  		GCE             GCE       `json:"gce"`
   191  		OpenStack       OpenStack `json:"openstack"`
   192  		Packet          Packet    `json:"packet"`
   193  		QEMU            QEMU      `json:"qemu"`
   194  	}{
   195  		Cmdline:         os.Args,
   196  		Platform:        kolaPlatform,
   197  		Distro:          kola.Options.Distribution,
   198  		IgnitionVersion: kola.Options.IgnitionVersion,
   199  		Board:           kola.QEMUOptions.Board,
   200  		OSContainer:     kola.Options.OSContainer,
   201  		AWS: AWS{
   202  			Region:       kola.AWSOptions.Region,
   203  			AMI:          kola.AWSOptions.AMI,
   204  			InstanceType: kola.AWSOptions.InstanceType,
   205  		},
   206  		Azure: Azure{
   207  			DiskURI:   kola.AzureOptions.DiskURI,
   208  			Publisher: kola.AzureOptions.Publisher,
   209  			Offer:     kola.AzureOptions.Offer,
   210  			Sku:       kola.AzureOptions.Sku,
   211  			Version:   kola.AzureOptions.Version,
   212  			Location:  kola.AzureOptions.Location,
   213  			Size:      kola.AzureOptions.Size,
   214  		},
   215  		DO: DO{
   216  			Region: kola.DOOptions.Region,
   217  			Size:   kola.DOOptions.Size,
   218  			Image:  kola.DOOptions.Image,
   219  		},
   220  		ESX: ESX{
   221  			Server:     kola.ESXOptions.Server,
   222  			BaseVMName: kola.ESXOptions.BaseVMName,
   223  		},
   224  		GCE: GCE{
   225  			Image:       kola.GCEOptions.Image,
   226  			MachineType: kola.GCEOptions.MachineType,
   227  		},
   228  		OpenStack: OpenStack{
   229  			Region: kola.OpenStackOptions.Region,
   230  			Image:  kola.OpenStackOptions.Image,
   231  			Flavor: kola.OpenStackOptions.Flavor,
   232  		},
   233  		Packet: Packet{
   234  			Facility:              kola.PacketOptions.Facility,
   235  			Plan:                  kola.PacketOptions.Plan,
   236  			InstallerImageBaseURL: kola.PacketOptions.InstallerImageBaseURL,
   237  			ImageURL:              kola.PacketOptions.ImageURL,
   238  		},
   239  		QEMU: QEMU{
   240  			Image:   kola.QEMUOptions.DiskImage,
   241  			Mangled: !kola.QEMUOptions.UseVanillaImage,
   242  		},
   243  	})
   244  }
   245  
   246  func runList(cmd *cobra.Command, args []string) {
   247  	var testlist []*item
   248  	for name, test := range register.Tests {
   249  		item := &item{
   250  			name,
   251  			test.Platforms,
   252  			test.ExcludePlatforms,
   253  			test.Architectures,
   254  			test.Distros,
   255  			test.ExcludeDistros}
   256  		item.updateValues()
   257  		testlist = append(testlist, item)
   258  	}
   259  
   260  	sort.Slice(testlist, func(i, j int) bool {
   261  		return testlist[i].Name < testlist[j].Name
   262  	})
   263  
   264  	if !listJSON {
   265  		var w = tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
   266  
   267  		fmt.Fprintln(w, "Test Name\tPlatforms\tArchitectures\tDistributions")
   268  		fmt.Fprintln(w, "\t")
   269  		for _, item := range testlist {
   270  			fmt.Fprintf(w, "%v\n", item)
   271  		}
   272  		w.Flush()
   273  	} else {
   274  		out, err := json.MarshalIndent(testlist, "", "\t")
   275  		if err != nil {
   276  			fmt.Fprintf(os.Stderr, "marshalling test list: %v\n", err)
   277  			os.Exit(1)
   278  		}
   279  		fmt.Println(string(out))
   280  	}
   281  }
   282  
   283  type item struct {
   284  	Name             string
   285  	Platforms        []string
   286  	ExcludePlatforms []string `json:"-"`
   287  	Architectures    []string
   288  	Distros          []string
   289  	ExcludeDistros   []string `json:"-"`
   290  }
   291  
   292  func (i *item) updateValues() {
   293  	buildItems := func(include, exclude, all []string) []string {
   294  		if len(include) == 0 && len(exclude) == 0 {
   295  			if listJSON {
   296  				return all
   297  			} else {
   298  				return []string{"all"}
   299  			}
   300  		}
   301  		var retItems []string
   302  		if len(exclude) > 0 {
   303  			excludeMap := map[string]struct{}{}
   304  			for _, item := range exclude {
   305  				excludeMap[item] = struct{}{}
   306  			}
   307  			if len(include) == 0 {
   308  				retItems = all
   309  			} else {
   310  				retItems = include
   311  			}
   312  			items := []string{}
   313  			for _, item := range retItems {
   314  				if _, ok := excludeMap[item]; !ok {
   315  					items = append(items, item)
   316  				}
   317  			}
   318  			retItems = items
   319  		} else {
   320  			retItems = include
   321  		}
   322  		return retItems
   323  	}
   324  	i.Platforms = buildItems(i.Platforms, i.ExcludePlatforms, kolaPlatforms)
   325  	i.Architectures = buildItems(i.Architectures, nil, kolaArchitectures)
   326  	i.Distros = buildItems(i.Distros, i.ExcludeDistros, kolaDistros)
   327  }
   328  
   329  func (i item) String() string {
   330  	return fmt.Sprintf("%v\t%v\t%v\t%v", i.Name, i.Platforms, i.Architectures, i.Distros)
   331  }