Skip to content

Commit

Permalink
refactor: plumb a single context throughout the code
Browse files Browse the repository at this point in the history
This patch is an effort to improve the context propagation in decK, down
to every single operation.
In order to do that, a single root context is now being created in the
main function, and all contexts should be derived from it.
  • Loading branch information
hbagdi committed May 3, 2021
1 parent 2a4ce4e commit 9733315
Show file tree
Hide file tree
Showing 14 changed files with 57 additions and 52 deletions.
32 changes: 13 additions & 19 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,12 @@ const (
)

var (
stopChannel chan struct{}
dumpConfig dump.Config
assumeYes bool
dumpConfig dump.Config
assumeYes bool
)

// SetStopCh sets the stop channel for long running commands.
// This is useful for cases when a process needs to be cancelled gracefully
// before it can complete to finish. Example: SIGINT
func SetStopCh(stopCh chan struct{}) {
stopChannel = stopCh
}

// workspaceExists checks if workspace exists in Kong.
func workspaceExists(config utils.KongClientConfig) (bool, error) {
func workspaceExists(ctx context.Context, config utils.KongClientConfig) (bool, error) {
if config.Workspace == "" {
// default workspace always exists
return true, nil
Expand All @@ -54,7 +46,7 @@ func workspaceExists(config utils.KongClientConfig) (bool, error) {
return false, err
}

_, _, err = wsClient.Routes.List(context.TODO(), nil)
_, _, err = wsClient.Routes.List(ctx, nil)
switch {
case kong.IsNotFoundErr(err):
return false, nil
Expand All @@ -65,7 +57,8 @@ func workspaceExists(config utils.KongClientConfig) (bool, error) {
}
}

func syncMain(filenames []string, dry bool, parallelism, delay int, workspace string) error {
func syncMain(ctx context.Context, filenames []string, dry bool, parallelism,
delay int, workspace string) error {

// read target file
targetContent, err := file.GetContentFromFiles(filenames)
Expand All @@ -89,12 +82,12 @@ func syncMain(filenames []string, dry bool, parallelism, delay int, workspace st
}

// load Kong version after workspace
kongVersion, err := kongVersion(wsConfig)
kongVersion, err := kongVersion(ctx, wsConfig)
if err != nil {
return errors.Wrap(err, "reading Kong version")
}

workspaceExists, err := workspaceExists(wsConfig)
workspaceExists, err := workspaceExists(ctx, wsConfig)
if err != nil {
return err
}
Expand All @@ -111,7 +104,7 @@ func syncMain(filenames []string, dry bool, parallelism, delay int, workspace st
// read the current state
var currentState *state.KongState
if workspaceExists {
rawState, err := dump.Get(wsClient, dumpConfig)
rawState, err := dump.Get(ctx, wsClient, dumpConfig)
if err != nil {
return err
}
Expand Down Expand Up @@ -157,7 +150,7 @@ func syncMain(filenames []string, dry bool, parallelism, delay int, workspace st

s, _ := diff.NewSyncer(currentState, targetState)
s.StageDelaySec = delay
stats, errs := solver.Solve(stopChannel, s, wsClient, nil, parallelism, dry)
stats, errs := solver.Solve(ctx, s, wsClient, nil, parallelism, dry)
printFn := color.New(color.FgGreen, color.Bold).PrintfFunc()
printFn("Summary:\n")
printFn(" Created: %v\n", stats.CreateOps)
Expand All @@ -173,7 +166,8 @@ func syncMain(filenames []string, dry bool, parallelism, delay int, workspace st
return nil
}

func kongVersion(config utils.KongClientConfig) (semver.Version, error) {
func kongVersion(ctx context.Context,
config utils.KongClientConfig) (semver.Version, error) {

var version string

Expand All @@ -185,7 +179,7 @@ func kongVersion(config utils.KongClientConfig) (semver.Version, error) {
if err != nil {
return semver.Version{}, err
}
root, err := client.Root(nil)
root, err := client.Root(ctx)
if err != nil {
if workspace == "" {
return semver.Version{}, err
Expand Down
4 changes: 2 additions & 2 deletions cmd/common_konnect.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func syncKonnect(ctx context.Context,
}

s, _ := diff.NewSyncer(currentState, targetState)
stats, errs := solver.Solve(stopChannel, s, kongClient, konnectClient, parallelism, dry)
stats, errs := solver.Solve(ctx, s, kongClient, konnectClient, parallelism, dry)
printFn := color.New(color.FgGreen, color.Bold).PrintfFunc()
printFn("Summary:\n")
printFn(" Created: %v\n", stats.CreateOps)
Expand Down Expand Up @@ -142,7 +142,7 @@ func getKonnectState(ctx context.Context,
group.Go(func() error {
var err error
// get export of Kong resources
kongState, err = dump.Get(kongClient, dump.Config{
kongState, err = dump.Get(ctx, kongClient, dump.Config{
SkipConsumers: skipConsumers,
})
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion cmd/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ that will be created or updated or deleted.
`,
Args: validateNoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return syncMain(diffCmdKongStateFile, true, diffCmdParallelism, 0, diffWorkspace)
return syncMain(cmd.Context(), diffCmdKongStateFile, true,
diffCmdParallelism, 0, diffWorkspace)
},
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(diffCmdKongStateFile) == 0 {
Expand Down
9 changes: 5 additions & 4 deletions cmd/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The file can then be read using the Sync o Diff command to again
configure Kong.`,
Args: validateNoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

wsClient, err := utils.GetKongClient(rootConfig)
if err != nil {
Expand All @@ -61,7 +62,7 @@ configure Kong.`,
if dumpCmdKongStateFile != "kong" {
return errors.New("output-file cannot be specified with --all-workspace flag")
}
workspaces, err := listWorkspaces(cmd.Context(), wsClient)
workspaces, err := listWorkspaces(ctx, wsClient)
if err != nil {
return err
}
Expand All @@ -72,7 +73,7 @@ configure Kong.`,
return err
}

rawState, err := dump.Get(wsClient, dumpConfig)
rawState, err := dump.Get(ctx, wsClient, dumpConfig)
if err != nil {
return errors.Wrap(err, "reading configuration from Kong")
}
Expand Down Expand Up @@ -105,7 +106,7 @@ configure Kong.`,
if dumpWorkspace != "" {
wsConfig := rootConfig.ForWorkspace(dumpWorkspace)

exists, err := workspaceExists(wsConfig)
exists, err := workspaceExists(ctx, wsConfig)
if err != nil {
return err
}
Expand All @@ -119,7 +120,7 @@ configure Kong.`,
}
}

rawState, err := dump.Get(wsClient, dumpConfig)
rawState, err := dump.Get(ctx, wsClient, dumpConfig)
if err != nil {
return errors.Wrap(err, "reading configuration from Kong")
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ var pingCmd = &cobra.Command{
can connect to Kong's Admin API or not.`,
Args: validateNoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

wsConfig := rootConfig.ForWorkspace(pingWorkspace)
version, err := kongVersion(wsConfig)
version, err := kongVersion(ctx, wsConfig)
if err != nil {
return errors.Wrap(err, "reading Kong version")
}
Expand Down
14 changes: 8 additions & 6 deletions cmd/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Use this command with extreme care as it is equivalent to running
By default, this command will ask for a confirmation prompt.`,
Args: validateNoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()

if !resetCmdForce {
ok, err := utils.Confirm("This will delete all configuration from Kong's database." +
"\n> Are you sure? ")
Expand All @@ -43,11 +45,11 @@ By default, this command will ask for a confirmation prompt.`,
}
// Kong OSS or default workspace
if !resetAllWorkspaces && resetWorkspace == "" {
state, err := dump.Get(rootClient, dumpConfig)
state, err := dump.Get(ctx, rootClient, dumpConfig)
if err != nil {
return err
}
err = reset.Reset(state, rootClient)
err = reset.Reset(ctx, state, rootClient)
if err != nil {
return err
}
Expand All @@ -61,13 +63,13 @@ By default, this command will ask for a confirmation prompt.`,
// Kong Enterprise
var workspaces []string
if resetAllWorkspaces {
workspaces, err = listWorkspaces(cmd.Context(), rootClient)
workspaces, err = listWorkspaces(ctx, rootClient)
if err != nil {
return err
}
}
if resetWorkspace != "" {
exists, err := workspaceExists(rootConfig.ForWorkspace(resetWorkspace))
exists, err := workspaceExists(ctx, rootConfig.ForWorkspace(resetWorkspace))
if err != nil {
return err
}
Expand All @@ -83,11 +85,11 @@ By default, this command will ask for a confirmation prompt.`,
if err != nil {
return err
}
state, err := dump.Get(wsClient, dumpConfig)
state, err := dump.Get(ctx, wsClient, dumpConfig)
if err != nil {
return err
}
err = reset.Reset(state, wsClient)
err = reset.Reset(ctx, state, wsClient)
if err != nil {
return err
}
Expand Down
7 changes: 4 additions & 3 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"fmt"
"io/ioutil"
"net/url"
Expand Down Expand Up @@ -39,10 +40,10 @@ It can be used to export, import or sync entities to Kong.`,
}

// Execute adds all child commands to the root command and sets
// sflags appropriately.
// flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
func Execute(ctx context.Context) {
err := rootCmd.ExecuteContext(ctx)
if err != nil {
// do not print error because cobra already prints it
os.Exit(1)
Expand Down
3 changes: 2 additions & 1 deletion cmd/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ var syncCmd = &cobra.Command{
to get Kong's state in sync with the input state.`,
Args: validateNoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return syncMain(syncCmdKongStateFile, false, syncCmdParallelism, syncCmdDBUpdateDelay, syncWorkspace)
return syncMain(cmd.Context(), syncCmdKongStateFile, false,
syncCmdParallelism, syncCmdDBUpdateDelay, syncWorkspace)
},
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(syncCmdKongStateFile) == 0 {
Expand Down
5 changes: 3 additions & 2 deletions diff/diff.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package diff

import (
"context"
"net/http"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -366,7 +367,7 @@ func (sc *Syncer) wait() {
}

// Run starts a diff and invokes d for every diff.
func (sc *Syncer) Run(done <-chan struct{}, parallelism int, d Do) []error {
func (sc *Syncer) Run(ctx context.Context, parallelism int, d Do) []error {
if parallelism < 1 {
return append([]error{}, errors.New("parallelism can not be negative"))
}
Expand Down Expand Up @@ -410,7 +411,7 @@ func (sc *Syncer) Run(done <-chan struct{}, parallelism int, d Do) []error {

var errs []error
select {
case <-done:
case <-ctx.Done():
case err, ok := <-sc.errChan:
if ok && err != nil {
if err != errEnqueueFailed {
Expand Down
4 changes: 2 additions & 2 deletions dump/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ func getEnterpriseRBACConfiguration(ctx context.Context, group *errgroup.Group,

// Get queries all the entities using client and returns
// all the entities in KongRawState.
func Get(client *kong.Client, config Config) (*utils.KongRawState, error) {
func Get(ctx context.Context, client *kong.Client, config Config) (*utils.KongRawState, error) {

var state utils.KongRawState

if err := validateConfig(config); err != nil {
return nil, err
}

group, ctx := errgroup.WithContext(context.Background())
group, ctx := errgroup.WithContext(ctx)

// dump only rbac resources
if config.RBACResourcesOnly {
Expand Down
2 changes: 1 addition & 1 deletion dump/dump_konnect.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func GetFromKonnect(ctx context.Context, konnectClient *konnect.Client,
var servicePackages []*konnect.ServicePackage
var relations []*konnect.ControlPlaneServiceRelation

group, ctx := errgroup.WithContext(context.Background())
group, ctx := errgroup.WithContext(ctx)
// group1 fetches service packages and their versions
group.Go(func() error {
var err error
Expand Down
13 changes: 7 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"context"
"fmt"
"math/rand"
"os"
Expand All @@ -11,22 +12,22 @@ import (
"github.com/kong/deck/cmd"
)

func registerSignalHandler() {
func registerSignalHandler() context.Context {
ctx, cancel := context.WithCancel(context.Background())
sigs := make(chan os.Signal, 1)
done := make(chan struct{})
cmd.SetStopCh(done)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

go func() {
sig := <-sigs
fmt.Println("received", sig, ", terminating...")
close(done)
cancel()
}()
return ctx
}

func main() {
registerSignalHandler()
cmd.Execute()
ctx := registerSignalHandler()
cmd.Execute(ctx)
}

func init() {
Expand Down
4 changes: 2 additions & 2 deletions reset/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import (
)

// Reset deletes all entities in Kong.
func Reset(state *utils.KongRawState, client *kong.Client) error {
func Reset(ctx context.Context, state *utils.KongRawState, client *kong.Client) error {
if state == nil {
return errors.New("state cannot be empty")
}

group, ctx := errgroup.WithContext(context.Background())
group, ctx := errgroup.WithContext(ctx)

group.Go(func() error {
// Delete routes before services
Expand Down
6 changes: 4 additions & 2 deletions solver/solver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package solver

import (
"context"

"github.com/kong/deck/crud"
"github.com/kong/deck/diff"
"github.com/kong/deck/konnect"
Expand All @@ -18,7 +20,7 @@ type Stats struct {
}

// Solve generates a diff and walks the graph.
func Solve(doneCh chan struct{}, syncer *diff.Syncer,
func Solve(ctx context.Context, syncer *diff.Syncer,
client *kong.Client, konnectClient *konnect.Client,
parallelism int, dry bool) (Stats, []error) {

Expand All @@ -36,7 +38,7 @@ func Solve(doneCh chan struct{}, syncer *diff.Syncer,
}
}

errs := syncer.Run(doneCh, parallelism, func(e diff.Event) (crud.Arg, error) {
errs := syncer.Run(ctx, parallelism, func(e diff.Event) (crud.Arg, error) {
var err error
var result crud.Arg

Expand Down

0 comments on commit 9733315

Please sign in to comment.