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  }