397
// will want to use Run instead, which also
398
// updates the config's raw state.
399
func run(newCfg *Config, start bool) (Context, error) {
400
+ ctx, err := provisionContext(newCfg, start)
401
+ if err != nil {
402
+ return ctx, err
403
+ }
404
+
405
+ if !start {
406
+ return ctx, nil
407
+ }
408
+
409
+ // Provision any admin routers which may need to access
410
+ // some of the other apps at runtime
411
+ err = ctx.cfg.Admin.provisionAdminRouters(ctx)
412
+ if err != nil {
413
+ return ctx, err
414
+ }
415
+
416
+ // Start
417
+ err = func() error {
418
+ started := make([]string, 0, len(ctx.cfg.apps))
419
+ for name, a := range ctx.cfg.apps {
420
+ err := a.Start()
421
+ if err != nil {
422
+ // an app failed to start, so we need to stop
423
+ // all other apps that were already started
424
+ for _, otherAppName := range started {
425
+ err2 := ctx.cfg.apps[otherAppName].Stop()
426
+ if err2 != nil {
427
+ err = fmt.Errorf("%v; additionally, aborting app %s: %v",
428
+ err, otherAppName, err2)
429
+ }
430
+ }
431
+ return fmt.Errorf("%s app module: start: %v", name, err)
432
+ }
433
+ started = append(started, name)
434
+ }
435
+ return nil
436
+ }()
437
+ if err != nil {
438
+ return ctx, err
439
+ }
440
+
441
+ // now that the user's config is running, finish setting up anything else,
442
+ // such as remote admin endpoint, config loader, etc.
443
+ return ctx, finishSettingUp(ctx, ctx.cfg)
444
+}
445
+
446
+// provisionContext creates a new context from the given configuration and provisions
447
+// storage and apps.
448
+// If `newCfg` is nil a new empty configuration will be created.
449
+// If `replaceAdminServer` is true any currently active admin server will be replaced
450
+// with a new admin server based on the provided configuration.
451
+func provisionContext(newCfg *Config, replaceAdminServer bool) (Context, error) {
452
// because we will need to roll back any state
453
// modifications if this function errors, we
454
// keep a single error value and scope all
496
}
497
498
// start the admin endpoint (and stop any prior one)
447
- if start {
499
+ if replaceAdminServer {
500
err = replaceLocalAdminServer(newCfg)
501
if err != nil {
502
return ctx, fmt.Errorf("starting caddy administration endpoint: %v", err)
543
}
544
return nil
545
}()
494
- if err != nil {
495
- return ctx, err
496
- }
497
-
498
- if !start {
499
- return ctx, nil
500
- }
501
-
502
- // Provision any admin routers which may need to access
503
- // some of the other apps at runtime
504
- err = newCfg.Admin.provisionAdminRouters(ctx)
505
- if err != nil {
506
- return ctx, err
507
- }
508
-
509
- // Start
510
- err = func() error {
511
- started := make([]string, 0, len(newCfg.apps))
512
- for name, a := range newCfg.apps {
513
- err := a.Start()
514
- if err != nil {
515
- // an app failed to start, so we need to stop
516
- // all other apps that were already started
517
- for _, otherAppName := range started {
518
- err2 := newCfg.apps[otherAppName].Stop()
519
- if err2 != nil {
520
- err = fmt.Errorf("%v; additionally, aborting app %s: %v",
521
- err, otherAppName, err2)
522
- }
523
- }
524
- return fmt.Errorf("%s app module: start: %v", name, err)
525
- }
526
- started = append(started, name)
527
- }
528
- return nil
529
- }()
530
- if err != nil {
531
- return ctx, err
532
- }
546
+ return ctx, err
547
+}
548
534
- // now that the user's config is running, finish setting up anything else,
535
- // such as remote admin endpoint, config loader, etc.
536
- return ctx, finishSettingUp(ctx, newCfg)
549
+// ProvisionContext creates a new context from the configuration and provisions storage
550
+// and app modules.
551
+// The function is intended for testing and advanced use cases only, typically `Run` should be
552
+// use to ensure a fully functional caddy instance.
553
+// EXPERIMENTAL: While this is public the interface and implementation details of this function may change.
554
+func ProvisionContext(newCfg *Config) (Context, error) {
555
+ return provisionContext(newCfg, false)
556
}
557
558
// finishSettingUp should be run after all apps have successfully started.