Skip to content

Commit 247276e

Browse files
committed
Merge pull request #3947 from carmstrong/stateless-control-plane
feat(deisctl): support stateless control plane without Ceph
2 parents 3449a9d + 850aceb commit 247276e

8 files changed

Lines changed: 404 additions & 74 deletions

File tree

deisctl/cmd/cmd.go

Lines changed: 115 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import (
2222
const (
2323
// PlatformCommand is shorthand for "all the Deis components."
2424
PlatformCommand string = "platform"
25-
swarm string = "swarm"
25+
// StatelessPlatformCommand is shorthand for the components except store-*, database, and logger.
26+
StatelessPlatformCommand string = "stateless-platform"
27+
swarm string = "swarm"
2628
)
2729

2830
// ListUnits prints a list of installed units.
@@ -67,9 +69,10 @@ func Start(targets []string, b backend.Backend) error {
6769
// if target is platform, install all services
6870
if len(targets) == 1 {
6971
if targets[0] == PlatformCommand {
70-
return StartPlatform(b)
71-
}
72-
if targets[0] == swarm {
72+
return StartPlatform(b, false)
73+
} else if targets[0] == StatelessPlatformCommand {
74+
return StartPlatform(b, true)
75+
} else if targets[0] == swarm {
7376
return StartSwarm(b)
7477
}
7578
}
@@ -102,42 +105,57 @@ deisctl config platform set sshPrivateKey=<path-to-key>
102105
return nil
103106
}
104107

105-
func startDefaultServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
108+
func startDefaultServices(b backend.Backend, stateless bool, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
106109

107110
// create separate channels for background tasks
108111
_outchan := make(chan string)
109112
_errchan := make(chan error)
110113
var _wg sync.WaitGroup
111114

112115
// wait for groups to come up
113-
outchan <- fmt.Sprintf("Storage subsystem...")
114-
b.Start([]string{"store-monitor"}, wg, outchan, errchan)
115-
wg.Wait()
116-
b.Start([]string{"store-daemon"}, wg, outchan, errchan)
117-
wg.Wait()
118-
b.Start([]string{"store-metadata"}, wg, outchan, errchan)
119-
wg.Wait()
116+
if !stateless {
117+
outchan <- fmt.Sprintf("Storage subsystem...")
118+
b.Start([]string{"store-monitor"}, wg, outchan, errchan)
119+
wg.Wait()
120+
b.Start([]string{"store-daemon"}, wg, outchan, errchan)
121+
wg.Wait()
122+
b.Start([]string{"store-metadata"}, wg, outchan, errchan)
123+
wg.Wait()
120124

121-
// we start gateway first to give metadata time to come up for volume
122-
b.Start([]string{"store-gateway@*"}, wg, outchan, errchan)
123-
wg.Wait()
124-
b.Start([]string{"store-volume"}, wg, outchan, errchan)
125-
wg.Wait()
125+
// we start gateway first to give metadata time to come up for volume
126+
b.Start([]string{"store-gateway@*"}, wg, outchan, errchan)
127+
wg.Wait()
128+
b.Start([]string{"store-volume"}, wg, outchan, errchan)
129+
wg.Wait()
130+
}
126131

127132
// start logging subsystem first to collect logs from other components
128133
outchan <- fmt.Sprintf("Logging subsystem...")
129-
b.Start([]string{"logger"}, wg, outchan, errchan)
130-
wg.Wait()
134+
if !stateless {
135+
b.Start([]string{"logger"}, wg, outchan, errchan)
136+
wg.Wait()
137+
}
131138
b.Start([]string{"logspout"}, wg, outchan, errchan)
132139
wg.Wait()
133140

134-
b.Start([]string{
135-
"database", "registry@*", "controller", "builder",
136-
"publisher", "router@*"},
137-
&_wg, _outchan, _errchan)
141+
if stateless {
142+
b.Start([]string{
143+
"registry@*", "controller", "builder",
144+
"publisher", "router@*"},
145+
&_wg, _outchan, _errchan)
146+
} else {
147+
b.Start([]string{
148+
"database", "registry@*", "controller", "builder",
149+
"publisher", "router@*"},
150+
&_wg, _outchan, _errchan)
151+
}
138152

139153
outchan <- fmt.Sprintf("Control plane...")
140-
b.Start([]string{"database", "registry@*", "controller"}, wg, outchan, errchan)
154+
if stateless {
155+
b.Start([]string{"registry@*", "controller"}, wg, outchan, errchan)
156+
} else {
157+
b.Start([]string{"database", "registry@*", "controller"}, wg, outchan, errchan)
158+
}
141159
wg.Wait()
142160
b.Start([]string{"builder"}, wg, outchan, errchan)
143161
wg.Wait()
@@ -157,9 +175,10 @@ func Stop(targets []string, b backend.Backend) error {
157175
// if target is platform, stop all services
158176
if len(targets) == 1 {
159177
if targets[0] == PlatformCommand {
160-
return StopPlatform(b)
161-
}
162-
if targets[0] == swarm {
178+
return StopPlatform(b, false)
179+
} else if targets[0] == StatelessPlatformCommand {
180+
return StopPlatform(b, true)
181+
} else if targets[0] == swarm {
163182
return StopSwarm(b)
164183
}
165184
}
@@ -178,7 +197,7 @@ func Stop(targets []string, b backend.Backend) error {
178197
return nil
179198
}
180199

181-
func stopDefaultServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
200+
func stopDefaultServices(b backend.Backend, stateless bool, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
182201

183202
outchan <- fmt.Sprintf("Routing mesh...")
184203
b.Stop([]string{"router@*"}, wg, outchan, errchan)
@@ -189,22 +208,33 @@ func stopDefaultServices(b backend.Backend, wg *sync.WaitGroup, outchan chan str
189208
wg.Wait()
190209

191210
outchan <- fmt.Sprintf("Control plane...")
192-
b.Stop([]string{"controller", "builder", "database", "registry@*"}, wg, outchan, errchan)
211+
if stateless {
212+
b.Stop([]string{"controller", "builder", "registry@*"}, wg, outchan, errchan)
213+
} else {
214+
b.Stop([]string{"controller", "builder", "database", "registry@*"}, wg, outchan, errchan)
215+
}
193216
wg.Wait()
194217

195218
outchan <- fmt.Sprintf("Logging subsystem...")
196-
b.Stop([]string{"logger", "logspout"}, wg, outchan, errchan)
219+
if stateless {
220+
b.Stop([]string{"logspout"}, wg, outchan, errchan)
221+
} else {
222+
b.Stop([]string{"logger", "logspout"}, wg, outchan, errchan)
223+
}
197224
wg.Wait()
198225

199-
outchan <- fmt.Sprintf("Storage subsystem...")
200-
b.Stop([]string{"store-volume", "store-gateway@*"}, wg, outchan, errchan)
201-
wg.Wait()
202-
b.Stop([]string{"store-metadata"}, wg, outchan, errchan)
203-
wg.Wait()
204-
b.Stop([]string{"store-daemon"}, wg, outchan, errchan)
205-
wg.Wait()
206-
b.Stop([]string{"store-monitor"}, wg, outchan, errchan)
207-
wg.Wait()
226+
if !stateless {
227+
outchan <- fmt.Sprintf("Storage subsystem...")
228+
b.Stop([]string{"store-volume", "store-gateway@*"}, wg, outchan, errchan)
229+
wg.Wait()
230+
b.Stop([]string{"store-metadata"}, wg, outchan, errchan)
231+
wg.Wait()
232+
b.Stop([]string{"store-daemon"}, wg, outchan, errchan)
233+
wg.Wait()
234+
b.Stop([]string{"store-monitor"}, wg, outchan, errchan)
235+
wg.Wait()
236+
}
237+
208238
}
209239

210240
// Restart stops and then starts the specified components.
@@ -247,9 +277,10 @@ func Install(targets []string, b backend.Backend, checkKeys func() error) error
247277
// if target is platform, install all services
248278
if len(targets) == 1 {
249279
if targets[0] == PlatformCommand {
250-
return InstallPlatform(b, checkKeys)
251-
}
252-
if targets[0] == swarm {
280+
return InstallPlatform(b, checkKeys, false)
281+
} else if targets[0] == StatelessPlatformCommand {
282+
return InstallPlatform(b, checkKeys, true)
283+
} else if targets[0] == swarm {
253284
return InstallSwarm(b)
254285
}
255286
}
@@ -268,18 +299,28 @@ func Install(targets []string, b backend.Backend, checkKeys func() error) error
268299
return nil
269300
}
270301

271-
func installDefaultServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
302+
func installDefaultServices(b backend.Backend, stateless bool, wg *sync.WaitGroup, outchan chan string, errchan chan error) {
272303

273-
outchan <- fmt.Sprintf("Storage subsystem...")
274-
b.Create([]string{"store-daemon", "store-monitor", "store-metadata", "store-volume", "store-gateway@1"}, wg, outchan, errchan)
275-
wg.Wait()
304+
if !stateless {
305+
outchan <- fmt.Sprintf("Storage subsystem...")
306+
b.Create([]string{"store-daemon", "store-monitor", "store-metadata", "store-volume", "store-gateway@1"}, wg, outchan, errchan)
307+
wg.Wait()
308+
}
276309

277310
outchan <- fmt.Sprintf("Logging subsystem...")
278-
b.Create([]string{"logger", "logspout"}, wg, outchan, errchan)
311+
if stateless {
312+
b.Create([]string{"logspout"}, wg, outchan, errchan)
313+
} else {
314+
b.Create([]string{"logger", "logspout"}, wg, outchan, errchan)
315+
}
279316
wg.Wait()
280317

281318
outchan <- fmt.Sprintf("Control plane...")
282-
b.Create([]string{"database", "registry@1", "controller", "builder"}, wg, outchan, errchan)
319+
if stateless {
320+
b.Create([]string{"registry@1", "controller", "builder"}, wg, outchan, errchan)
321+
} else {
322+
b.Create([]string{"database", "registry@1", "controller", "builder"}, wg, outchan, errchan)
323+
}
283324
wg.Wait()
284325

285326
outchan <- fmt.Sprintf("Data plane...")
@@ -297,9 +338,10 @@ func installDefaultServices(b backend.Backend, wg *sync.WaitGroup, outchan chan
297338
func Uninstall(targets []string, b backend.Backend) error {
298339
if len(targets) == 1 {
299340
if targets[0] == PlatformCommand {
300-
return UninstallPlatform(b)
301-
}
302-
if targets[0] == swarm {
341+
return UninstallPlatform(b, false)
342+
} else if targets[0] == StatelessPlatformCommand {
343+
return UninstallPlatform(b, true)
344+
} else if targets[0] == swarm {
303345
return UnInstallSwarm(b)
304346
}
305347
}
@@ -319,7 +361,7 @@ func Uninstall(targets []string, b backend.Backend) error {
319361
return nil
320362
}
321363

322-
func uninstallAllServices(b backend.Backend, wg *sync.WaitGroup, outchan chan string, errchan chan error) error {
364+
func uninstallAllServices(b backend.Backend, stateless bool, wg *sync.WaitGroup, outchan chan string, errchan chan error) error {
323365

324366
outchan <- fmt.Sprintf("Routing mesh...")
325367
b.Destroy([]string{"router@*"}, wg, outchan, errchan)
@@ -330,22 +372,32 @@ func uninstallAllServices(b backend.Backend, wg *sync.WaitGroup, outchan chan st
330372
wg.Wait()
331373

332374
outchan <- fmt.Sprintf("Control plane...")
333-
b.Destroy([]string{"controller", "builder", "database", "registry@*"}, wg, outchan, errchan)
375+
if stateless {
376+
b.Destroy([]string{"controller", "builder", "registry@*"}, wg, outchan, errchan)
377+
} else {
378+
b.Destroy([]string{"controller", "builder", "database", "registry@*"}, wg, outchan, errchan)
379+
}
334380
wg.Wait()
335381

336382
outchan <- fmt.Sprintf("Logging subsystem...")
337-
b.Destroy([]string{"logger", "logspout"}, wg, outchan, errchan)
383+
if stateless {
384+
b.Destroy([]string{"logspout"}, wg, outchan, errchan)
385+
} else {
386+
b.Destroy([]string{"logger", "logspout"}, wg, outchan, errchan)
387+
}
338388
wg.Wait()
339389

340-
outchan <- fmt.Sprintf("Storage subsystem...")
341-
b.Destroy([]string{"store-volume", "store-gateway@*"}, wg, outchan, errchan)
342-
wg.Wait()
343-
b.Destroy([]string{"store-metadata"}, wg, outchan, errchan)
344-
wg.Wait()
345-
b.Destroy([]string{"store-daemon"}, wg, outchan, errchan)
346-
wg.Wait()
347-
b.Destroy([]string{"store-monitor"}, wg, outchan, errchan)
348-
wg.Wait()
390+
if !stateless {
391+
outchan <- fmt.Sprintf("Storage subsystem...")
392+
b.Destroy([]string{"store-volume", "store-gateway@*"}, wg, outchan, errchan)
393+
wg.Wait()
394+
b.Destroy([]string{"store-metadata"}, wg, outchan, errchan)
395+
wg.Wait()
396+
b.Destroy([]string{"store-daemon"}, wg, outchan, errchan)
397+
wg.Wait()
398+
b.Destroy([]string{"store-monitor"}, wg, outchan, errchan)
399+
wg.Wait()
400+
}
349401

350402
return nil
351403
}

deisctl/cmd/cmd_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,21 @@ func TestStartPlatform(t *testing.T) {
231231
}
232232
}
233233

234+
func TestStartStatelessPlatform(t *testing.T) {
235+
t.Parallel()
236+
237+
b := backendStub{}
238+
expected := []string{"logspout", "registry@*", "controller",
239+
"builder", "publisher", "router@*", "registry@*", "controller",
240+
"builder", "publisher", "router@*"}
241+
242+
Start([]string{"stateless-platform"}, &b)
243+
244+
if !reflect.DeepEqual(b.startedUnits, expected) {
245+
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.startedUnits))
246+
}
247+
}
248+
234249
func TestStartSwarm(t *testing.T) {
235250
t.Parallel()
236251

@@ -270,6 +285,19 @@ func TestStopPlatform(t *testing.T) {
270285
}
271286
}
272287

288+
func TestStopStatelessPlatform(t *testing.T) {
289+
t.Parallel()
290+
291+
b := backendStub{}
292+
expected := []string{"router@*", "publisher", "controller", "builder",
293+
"registry@*", "logspout"}
294+
Stop([]string{"stateless-platform"}, &b)
295+
296+
if !reflect.DeepEqual(b.stoppedUnits, expected) {
297+
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.stoppedUnits))
298+
}
299+
}
300+
273301
func TestStopSwarm(t *testing.T) {
274302
t.Parallel()
275303

@@ -394,6 +422,20 @@ func TestInstallPlatform(t *testing.T) {
394422
}
395423
}
396424

425+
func TestInstallStatelessPlatform(t *testing.T) {
426+
t.Parallel()
427+
428+
b := backendStub{}
429+
expected := []string{"logspout", "registry@1",
430+
"controller", "builder", "publisher", "router@1", "router@2", "router@3"}
431+
432+
Install([]string{"stateless-platform"}, &b, fakeCheckKeys)
433+
434+
if !reflect.DeepEqual(b.installedUnits, expected) {
435+
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.installedUnits))
436+
}
437+
}
438+
397439
func TestInstallSwarm(t *testing.T) {
398440
t.Parallel()
399441

@@ -435,6 +477,20 @@ func TestUninstallPlatform(t *testing.T) {
435477
}
436478
}
437479

480+
func TestUninstallStatelessPlatform(t *testing.T) {
481+
t.Parallel()
482+
483+
b := backendStub{}
484+
expected := []string{"router@*", "publisher", "controller", "builder",
485+
"registry@*", "logspout"}
486+
487+
Uninstall([]string{"stateless-platform"}, &b)
488+
489+
if !reflect.DeepEqual(b.uninstalledUnits, expected) {
490+
t.Error(fmt.Errorf("Expected %v, Got %v", expected, b.uninstalledUnits))
491+
}
492+
}
493+
438494
func TestUninstallSwarm(t *testing.T) {
439495
t.Parallel()
440496

0 commit comments

Comments
 (0)