github.com/abayer/test-infra@v0.0.5/boskos/janitor/janitor.go (about)

     1  /*
     2  Copyright 2017 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  package main
    18  
    19  import (
    20  	"flag"
    21  	"fmt"
    22  	"os/exec"
    23  	"time"
    24  
    25  	"github.com/sirupsen/logrus"
    26  	"k8s.io/test-infra/boskos/client"
    27  	"k8s.io/test-infra/boskos/common"
    28  )
    29  
    30  var (
    31  	bufferSize     = 1 // Maximum holding resources
    32  	serviceAccount = flag.String("service-account", "", "Path to projects service account")
    33  	rTypes         common.CommaSeparatedStrings
    34  	poolSize       int
    35  	janitorPath    = flag.String("janitor-path", "/bin/janitor.py", "Path to janitor binary path")
    36  	boskosURL      = flag.String("boskos-url", "http://boskos", "Boskos URL")
    37  )
    38  
    39  func init() {
    40  	flag.Var(&rTypes, "resource-type", "comma-separated list of resources need to be cleaned up")
    41  	flag.IntVar(&poolSize, "pool-size", 20, "number of concurrent janitor goroutine")
    42  }
    43  
    44  func main() {
    45  	// Activate service account
    46  	flag.Parse()
    47  
    48  	logrus.SetFormatter(&logrus.JSONFormatter{})
    49  	boskos := client.NewClient("Janitor", *boskosURL)
    50  	logrus.Info("Initialized boskos client!")
    51  
    52  	if *serviceAccount == "" {
    53  		logrus.Fatal("--service-account cannot be empty!")
    54  	}
    55  
    56  	if len(rTypes) == 0 {
    57  		logrus.Fatal("--resource-type must not be empty!")
    58  	}
    59  
    60  	cmd := exec.Command("gcloud", "auth", "activate-service-account", "--key-file="+*serviceAccount)
    61  	if b, err := cmd.CombinedOutput(); err != nil {
    62  		logrus.WithError(err).Fatalf("fail to activate service account from %s :%s", *serviceAccount, string(b))
    63  	}
    64  
    65  	buffer := setup(boskos, poolSize, bufferSize, janitorClean)
    66  
    67  	for {
    68  		run(boskos, buffer, rTypes)
    69  		time.Sleep(time.Minute)
    70  	}
    71  }
    72  
    73  type clean func(string) error
    74  
    75  // Clean by janitor script
    76  func janitorClean(proj string) error {
    77  	cmd := exec.Command(*janitorPath, fmt.Sprintf("--project=%s", proj), "--hour=0")
    78  	b, err := cmd.CombinedOutput()
    79  	if err != nil {
    80  		logrus.WithError(err).Errorf("failed to clean up project %s, error info: %s", proj, string(b))
    81  	} else {
    82  		logrus.Infof("successfully cleaned up project %s", proj)
    83  	}
    84  	return err
    85  }
    86  
    87  type boskosClient interface {
    88  	Acquire(rtype string, state string, dest string) (*common.Resource, error)
    89  	ReleaseOne(name string, dest string) error
    90  }
    91  
    92  func setup(c boskosClient, janitorCount int, bufferSize int, cleanFunc clean) chan string {
    93  	buffer := make(chan string, 1)
    94  	for i := 0; i < janitorCount; i++ {
    95  		go janitor(c, buffer, cleanFunc)
    96  	}
    97  	return buffer
    98  }
    99  
   100  func run(c boskosClient, buffer chan string, rtypes []string) int {
   101  	totalAcquire := 0
   102  	res := make(map[string]int)
   103  	for _, s := range rtypes {
   104  		res[s] = 0
   105  	}
   106  
   107  	for {
   108  		for r := range res {
   109  			if projRes, err := c.Acquire(r, common.Dirty, common.Cleaning); err != nil {
   110  				logrus.WithError(err).Error("boskos acquire failed!")
   111  				totalAcquire += res[r]
   112  				delete(res, r)
   113  			} else if projRes == nil {
   114  				// To Sen: I don t understand why this would happen
   115  				logrus.Warning("received nil resource")
   116  				totalAcquire += res[r]
   117  				delete(res, r)
   118  			} else {
   119  				logrus.Infof("Acquired resources %s of type %s", projRes.Name, projRes.Type)
   120  				buffer <- projRes.Name // will block until buffer has a free slot
   121  				res[r]++
   122  			}
   123  		}
   124  
   125  		if len(res) == 0 {
   126  			break
   127  		}
   128  	}
   129  
   130  	return totalAcquire
   131  }
   132  
   133  // async janitor goroutine
   134  func janitor(c boskosClient, buffer chan string, fn clean) {
   135  	for {
   136  		proj := <-buffer
   137  
   138  		dest := common.Free
   139  		if err := fn(proj); err != nil {
   140  			logrus.WithError(err).Error("janitor.py failed!")
   141  			dest = common.Dirty
   142  		}
   143  
   144  		if err := c.ReleaseOne(proj, dest); err != nil {
   145  			logrus.WithError(err).Error("boskos release failed!")
   146  		}
   147  	}
   148  }