k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/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 v1 "k8s.io/api/core/v1" 29 "sigs.k8s.io/prow/pkg/config" 30 configflagutil "sigs.k8s.io/prow/pkg/flagutil/config" 31 ) 32 33 type options struct { 34 prowConfig configflagutil.ConfigOptions 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-gci-gke", 46 "k8s-jkns-pr-gke", 47 "k8s-jkns-pr-kubemark", 48 "k8s-jkns-pr-node-e2e", 49 "k8s-jkns-pr-gce-gpus", 50 // k8s-infra projects, can't be cleaned by k8s-prow serviceaccounts 51 "k8s-infra-e2e-scale-5k-project", 52 "k8s-infra-e2e-gpu-project", 53 } 54 ) 55 56 func (o *options) Validate() error { 57 if err := o.prowConfig.Validate(false); err != nil { 58 return err 59 } 60 61 if o.janitorPath == "" { 62 return errors.New("required flag --janitor-path was unset") 63 } 64 65 return nil 66 } 67 68 func gatherOptions() options { 69 o := options{} 70 o.prowConfig.AddFlags(flag.CommandLine) 71 flag.StringVar(&o.janitorPath, "janitor-path", "", "Path to gcp_janitor.py.") 72 flag.Parse() 73 return o 74 } 75 76 func containers(jb config.JobBase) []v1.Container { 77 var containers []v1.Container 78 if jb.Spec != nil { 79 containers = append(containers, jb.Spec.Containers...) 80 containers = append(containers, jb.Spec.InitContainers...) 81 } 82 return containers 83 } 84 85 func findProject(jb config.JobBase) (string, int) { 86 project := "" 87 ttl := defaultTTL 88 for _, container := range containers(jb) { 89 for _, arg := range container.Args { 90 if strings.HasPrefix(arg, "--gcp-project=") { 91 project = strings.TrimPrefix(arg, "--gcp-project=") 92 } 93 94 if arg == "--soak" { 95 ttl = soakTTL 96 } 97 } 98 } 99 100 return project, ttl 101 } 102 103 func clean(proj, janitorPath string, ttl int) error { 104 for _, bad := range blocked { 105 if bad == proj { 106 logrus.Infof("Will skip project %s", proj) 107 return nil 108 } 109 } 110 111 logrus.Infof("Will clean up %s with ttl %d h", proj, ttl) 112 113 cmd := exec.Command(janitorPath, fmt.Sprintf("--project=%s", proj), fmt.Sprintf("--hour=%d", ttl)) 114 b, err := cmd.CombinedOutput() 115 if err != nil { 116 logrus.WithError(err).Errorf("failed to clean up project %s, error info: %s", proj, string(b)) 117 } else { 118 logrus.Infof("successfully cleaned up project %s", proj) 119 } 120 121 return err 122 } 123 124 func main() { 125 o := gatherOptions() 126 if err := o.Validate(); err != nil { 127 logrus.Fatalf("Invalid options: %v", err) 128 } 129 130 agent, err := o.prowConfig.ConfigAgent() 131 if err != nil { 132 logrus.WithError(err).Fatal("Error loading config.") 133 } 134 conf := agent.Config() 135 136 failed := []string{} 137 138 var jobs []config.JobBase 139 140 for _, v := range conf.AllStaticPresubmits(nil) { 141 jobs = append(jobs, v.JobBase) 142 } 143 for _, v := range conf.AllStaticPostsubmits(nil) { 144 jobs = append(jobs, v.JobBase) 145 } 146 for _, v := range conf.AllPeriodics() { 147 jobs = append(jobs, v.JobBase) 148 } 149 150 for _, j := range jobs { 151 if project, ttl := findProject(j); project != "" { 152 if err := clean(project, o.janitorPath, ttl); err != nil { 153 logrus.WithError(err).Errorf("failed to clean %q", project) 154 failed = append(failed, project) 155 } 156 } 157 } 158 159 if len(failed) > 0 { 160 logrus.Fatalf("Failed clean %d projects: %v", len(failed), failed) 161 } 162 163 logrus.Info("Successfully cleaned up all projects!") 164 }