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 }