github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/scripts/juju-leasediff/main.go (about) 1 // Copyright 2021 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package main 5 6 import ( 7 "flag" 8 "fmt" 9 "log" 10 "os" 11 "strings" 12 13 "github.com/juju/collections/set" 14 "gopkg.in/yaml.v3" 15 ) 16 17 func main() { 18 flag.Parse() 19 20 files := flag.Args() 21 if len(files) == 0 { 22 log.Fatal("expected at least on file") 23 } 24 25 reports := make([]Controller, len(files)) 26 for i, file := range files { 27 f, err := os.Open(file) 28 if err != nil { 29 log.Fatal(err) 30 } 31 32 var report Controller 33 if err := yaml.NewDecoder(f).Decode(&report); err != nil { 34 log.Fatal(err) 35 } 36 37 reports[i] = report 38 } 39 40 // Process them to ensure that all leases are correctly held. 41 sets := make([]set.Strings, len(reports)) 42 for i, report := range reports { 43 set := set.NewStrings() 44 for k, v := range report.ControllerLeases { 45 set.Add(fmt.Sprintf("%s:%s", k, v.Holder)) 46 } 47 for k, v := range report.ModelLeases { 48 for app, lease := range v { 49 set.Add(fmt.Sprintf("%s:%s:%s", k, app, lease.Holder)) 50 } 51 } 52 sets[i] = set 53 } 54 55 for i := 1; i < len(sets); i++ { 56 a := sets[i-1] 57 b := sets[i] 58 59 x := a.Difference(b) 60 y := b.Difference(a) 61 62 if len(x) > 0 || len(y) > 0 { 63 fmt.Println("Difference located:") 64 fmt.Println(x) 65 fmt.Println(y) 66 return 67 } 68 69 for _, v0 := range a.SortedValues() { 70 parts := strings.Split(v0, ":") 71 if len(parts) == 2 { 72 l0 := reports[i-1].ControllerLeases[parts[0]] 73 l1 := reports[i].ControllerLeases[parts[0]] 74 if l0.LeaseExpires != l1.LeaseExpires { 75 fmt.Printf("Controller lease (%d - %d): %s:: %s - %s\n", i-1, i, parts[0], l0, l1) 76 } 77 } else if len(parts) == 3 { 78 l0 := reports[i-1].ModelLeases[parts[0]][parts[1]] 79 l1 := reports[i].ModelLeases[parts[0]][parts[1]] 80 if l0.LeaseExpires != l1.LeaseExpires { 81 fmt.Printf("Model lease (%d - %d): %s:: %s - %s\n", i-1, i, parts[0], l0, l1) 82 } 83 } 84 } 85 } 86 } 87 88 type Controller struct { 89 ControllerLeases map[string]Lease `yaml:"controller-leases"` 90 ModelLeases map[string]map[string]Lease `yaml:"model-leases"` 91 } 92 93 type Lease struct { 94 Holder string `yaml:"holder"` 95 LeaseExpires string `yaml:"lease-expires"` 96 }