github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/experiment/ci-janitor/main.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // ci-janitor cleans up dedicated projects in k8s prowjob configs 18 package main 19 20 import ( 21 "errors" 22 "flag" 23 "fmt" 24 "os/exec" 25 "strings" 26 27 "github.com/sirupsen/logrus" 28 "k8s.io/api/core/v1" 29 "k8s.io/test-infra/prow/config" 30 ) 31 32 type options struct { 33 configPath string 34 jobConfigPath string 35 janitorPath string 36 } 37 38 var ( 39 defaultTTL = 24 40 soakTTL = 24 * 10 41 blocked = []string{ 42 "kubernetes-scale", // Let it's up/down job handle the resources 43 "k8s-scale-testing", // As it can be running some manual experiments 44 // PR projects, migrate to boskos! 45 "k8s-jkns-pr-gce", 46 "k8s-jkns-pr-gce-bazel", 47 "k8s-jkns-pr-gce-etcd3", 48 "k8s-jkns-pr-gci-gce", 49 "k8s-jkns-pr-gci-gke", 50 "k8s-jkns-pr-gci-kubemark", 51 "k8s-jkns-pr-gke", 52 "k8s-jkns-pr-kubeadm", 53 "k8s-jkns-pr-kubemark", 54 "k8s-jkns-pr-node-e2e", 55 "k8s-jkns-pr-gce-gpus", 56 "k8s-gke-gpu-pr", 57 "k8s-presubmit-scale", 58 } 59 ) 60 61 func (o *options) Validate() error { 62 if o.configPath == "" { 63 return errors.New("required flag --config-path was unset") 64 } 65 66 if o.jobConfigPath == "" { 67 return errors.New("required flag --job-config-path was unset") 68 } 69 70 if o.janitorPath == "" { 71 return errors.New("required flag --janitor-path was unset") 72 } 73 74 return nil 75 } 76 77 func gatherOptions() options { 78 o := options{} 79 flag.StringVar(&o.configPath, "config-path", "", "Path to config.yaml.") 80 flag.StringVar(&o.jobConfigPath, "job-config-path", "", "Path to prow job configs.") 81 flag.StringVar(&o.janitorPath, "janitor-path", "", "Path to janitor.py.") 82 flag.Parse() 83 return o 84 } 85 86 func containers(jb config.JobBase) []v1.Container { 87 var containers []v1.Container 88 if jb.Spec != nil { 89 containers = append(containers, jb.Spec.Containers...) 90 containers = append(containers, jb.Spec.InitContainers...) 91 } 92 if jb.BuildSpec != nil { 93 containers = append(containers, jb.BuildSpec.Steps...) 94 if jb.BuildSpec.Source != nil && jb.BuildSpec.Source.Custom != nil { 95 containers = append(containers, *jb.BuildSpec.Source.Custom) 96 } 97 } 98 return containers 99 } 100 101 func findProject(jb config.JobBase) (string, int) { 102 project := "" 103 ttl := defaultTTL 104 for _, container := range containers(jb) { 105 for _, arg := range container.Args { 106 if strings.HasPrefix(arg, "--gcp-project=") { 107 project = strings.TrimPrefix(arg, "--gcp-project=") 108 } 109 110 if arg == "--soak" { 111 ttl = soakTTL 112 } 113 } 114 } 115 116 return project, ttl 117 } 118 119 func clean(proj, janitorPath string, ttl int) error { 120 for _, bad := range blocked { 121 if bad == proj { 122 logrus.Infof("Will skip project %s", proj) 123 return nil 124 } 125 } 126 127 logrus.Infof("Will clean up %s with ttl %d h", proj, ttl) 128 129 cmd := exec.Command(janitorPath, fmt.Sprintf("--project=%s", proj), fmt.Sprintf("--hour=%d", ttl)) 130 b, err := cmd.CombinedOutput() 131 if err != nil { 132 logrus.WithError(err).Errorf("failed to clean up project %s, error info: %s", proj, string(b)) 133 } else { 134 logrus.Infof("successfully cleaned up project %s", proj) 135 } 136 137 return err 138 } 139 140 func main() { 141 o := gatherOptions() 142 if err := o.Validate(); err != nil { 143 logrus.Fatalf("Invalid options: %v", err) 144 } 145 146 conf, err := config.Load(o.configPath, o.jobConfigPath) 147 if err != nil { 148 logrus.WithError(err).Fatal("Error loading config.") 149 } 150 151 failed := []string{} 152 153 var jobs []config.JobBase 154 155 for _, v := range conf.AllPresubmits(nil) { 156 jobs = append(jobs, v.JobBase) 157 } 158 for _, v := range conf.AllPostsubmits(nil) { 159 jobs = append(jobs, v.JobBase) 160 } 161 for _, v := range conf.AllPeriodics() { 162 jobs = append(jobs, v.JobBase) 163 } 164 165 for _, j := range jobs { 166 if project, ttl := findProject(j); project != "" { 167 if err := clean(project, o.janitorPath, ttl); err != nil { 168 logrus.WithError(err).Errorf("failed to clean %q", project) 169 failed = append(failed, project) 170 } 171 } 172 } 173 174 if len(failed) > 0 { 175 logrus.Fatalf("Failed clean %d projects: %v", len(failed), failed) 176 } 177 178 logrus.Info("Successfully cleaned up all projects!") 179 }