github.com/greenboxal/deis@v1.12.1/deisctl/cmd/upgrade.go (about)

     1  package cmd
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"sync"
     8  
     9  	"github.com/deis/deis/deisctl/backend"
    10  	"github.com/deis/deis/deisctl/config"
    11  	"github.com/deis/deis/deisctl/config/model"
    12  )
    13  
    14  // UpgradePrep stops and uninstalls all components except router and publisher
    15  func UpgradePrep(stateless bool, b backend.Backend) error {
    16  	var wg sync.WaitGroup
    17  
    18  	b.Stop([]string{"database", "registry@*", "controller", "builder", "logger", "logspout"}, &wg, Stdout, Stderr)
    19  	wg.Wait()
    20  	b.Destroy([]string{"database", "registry@*", "controller", "builder", "logger", "logspout"}, &wg, Stdout, Stderr)
    21  	wg.Wait()
    22  
    23  	if !stateless {
    24  		b.Stop([]string{"store-volume", "store-gateway@*"}, &wg, Stdout, Stderr)
    25  		wg.Wait()
    26  		b.Destroy([]string{"store-volume", "store-gateway@*"}, &wg, Stdout, Stderr)
    27  		wg.Wait()
    28  
    29  		b.Stop([]string{"store-metadata"}, &wg, Stdout, Stderr)
    30  		wg.Wait()
    31  		b.Destroy([]string{"store-metadata"}, &wg, Stdout, Stderr)
    32  		wg.Wait()
    33  
    34  		b.Stop([]string{"store-daemon"}, &wg, Stdout, Stderr)
    35  		wg.Wait()
    36  		b.Destroy([]string{"store-daemon"}, &wg, Stdout, Stderr)
    37  		wg.Wait()
    38  
    39  		b.Stop([]string{"store-monitor"}, &wg, Stdout, Stderr)
    40  		wg.Wait()
    41  		b.Destroy([]string{"store-monitor"}, &wg, Stdout, Stderr)
    42  		wg.Wait()
    43  	}
    44  
    45  	fmt.Fprintln(Stdout, "The platform has been stopped, but applications are still serving traffic as normal.")
    46  	fmt.Fprintln(Stdout, "Your cluster is now ready for upgrade. Install a new deisctl version and run `deisctl upgrade-takeover`.")
    47  	fmt.Fprintln(Stdout, "For more details, see: http://docs.deis.io/en/latest/managing_deis/upgrading-deis/#graceful-upgrade")
    48  	return nil
    49  }
    50  
    51  func listPublishedServices(cb config.Backend) ([]*model.ConfigNode, error) {
    52  	nodes, err := cb.GetRecursive("deis/services")
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	return nodes, nil
    58  }
    59  
    60  func republishServices(ttl uint64, nodes []*model.ConfigNode, cb config.Backend) error {
    61  	for _, node := range nodes {
    62  		_, err := cb.SetWithTTL(node.Key, node.Value, ttl)
    63  		if err != nil {
    64  			return err
    65  		}
    66  	}
    67  
    68  	return nil
    69  }
    70  
    71  // UpgradeTakeover gracefully starts a platform stopped with UpgradePrep
    72  func UpgradeTakeover(stateless bool, b backend.Backend, cb config.Backend) error {
    73  	if err := doUpgradeTakeOver(stateless, b, cb); err != nil {
    74  		return err
    75  	}
    76  
    77  	return nil
    78  }
    79  
    80  func doUpgradeTakeOver(stateless bool, b backend.Backend, cb config.Backend) error {
    81  	var wg sync.WaitGroup
    82  
    83  	nodes, err := listPublishedServices(cb)
    84  	if err != nil {
    85  		return err
    86  	}
    87  
    88  	b.Stop([]string{"publisher"}, &wg, Stdout, Stderr)
    89  	wg.Wait()
    90  	b.Destroy([]string{"publisher"}, &wg, Stdout, Stderr)
    91  	wg.Wait()
    92  
    93  	if err := republishServices(1800, nodes, cb); err != nil {
    94  		return err
    95  	}
    96  
    97  	b.RollingRestart("router", &wg, Stdout, Stderr)
    98  	wg.Wait()
    99  	b.Create([]string{"publisher"}, &wg, Stdout, Stderr)
   100  	wg.Wait()
   101  	b.Start([]string{"publisher"}, &wg, Stdout, Stderr)
   102  	wg.Wait()
   103  
   104  	installUpgradeServices(b, stateless, &wg, Stdout, Stderr)
   105  	wg.Wait()
   106  
   107  	startUpgradeServices(b, stateless, &wg, Stdout, Stderr)
   108  	wg.Wait()
   109  	return nil
   110  }
   111  
   112  func installUpgradeServices(b backend.Backend, stateless bool, wg *sync.WaitGroup, out, err io.Writer) {
   113  	if !stateless {
   114  		fmt.Fprintln(out, "Storage subsystem...")
   115  		b.Create([]string{"store-daemon", "store-monitor", "store-metadata", "store-volume", "store-gateway@1"}, wg, out, err)
   116  		wg.Wait()
   117  	}
   118  
   119  	fmt.Fprintln(out, "Logging subsystem...")
   120  	if stateless {
   121  		b.Create([]string{"logspout"}, wg, out, err)
   122  	} else {
   123  		b.Create([]string{"logger", "logspout"}, wg, out, err)
   124  	}
   125  	wg.Wait()
   126  
   127  	fmt.Fprintln(out, "Control plane...")
   128  	if stateless {
   129  		b.Create([]string{"registry@1", "controller", "builder"}, wg, out, err)
   130  	} else {
   131  		b.Create([]string{"database", "registry@1", "controller", "builder"}, wg, out, err)
   132  	}
   133  	wg.Wait()
   134  
   135  	fmt.Fprintln(out, "Data plane...")
   136  	b.Create([]string{"publisher"}, wg, out, err)
   137  	wg.Wait()
   138  }
   139  
   140  func startUpgradeServices(b backend.Backend, stateless bool, wg *sync.WaitGroup, out, err io.Writer) {
   141  
   142  	// Wait for groups to come up.
   143  	// If we're running in stateless mode, we start only a subset of services.
   144  	if !stateless {
   145  		fmt.Fprintln(out, "Storage subsystem...")
   146  		b.Start([]string{"store-monitor"}, wg, out, err)
   147  		wg.Wait()
   148  		b.Start([]string{"store-daemon"}, wg, out, err)
   149  		wg.Wait()
   150  		b.Start([]string{"store-metadata"}, wg, out, err)
   151  		wg.Wait()
   152  
   153  		// we start gateway first to give metadata time to come up for volume
   154  		b.Start([]string{"store-gateway@*"}, wg, out, err)
   155  		wg.Wait()
   156  		b.Start([]string{"store-volume"}, wg, out, err)
   157  		wg.Wait()
   158  	}
   159  
   160  	// start logging subsystem first to collect logs from other components
   161  	fmt.Fprintln(out, "Logging subsystem...")
   162  	if !stateless {
   163  		b.Start([]string{"logger"}, wg, out, err)
   164  		wg.Wait()
   165  	}
   166  	b.Start([]string{"logspout"}, wg, out, err)
   167  	wg.Wait()
   168  
   169  	// Start these in parallel. This section can probably be removed now.
   170  	var bgwg sync.WaitGroup
   171  	var trash bytes.Buffer
   172  	batch := []string{
   173  		"database", "registry@*", "controller", "builder",
   174  		"publisher",
   175  	}
   176  	if stateless {
   177  		batch = []string{"registry@*", "controller", "builder", "publisher", "router@*"}
   178  	}
   179  	b.Start(batch, &bgwg, &trash, &trash)
   180  
   181  	fmt.Fprintln(Stdout, "Control plane...")
   182  	batch = []string{"database", "registry@*", "controller"}
   183  	if stateless {
   184  		batch = []string{"registry@*", "controller"}
   185  	}
   186  	b.Start(batch, wg, out, err)
   187  	wg.Wait()
   188  
   189  	b.Start([]string{"builder"}, wg, out, err)
   190  	wg.Wait()
   191  
   192  	fmt.Fprintln(out, "Data plane...")
   193  	b.Start([]string{"publisher"}, wg, out, err)
   194  	wg.Wait()
   195  }