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 }