Skip to content

Commit

Permalink
feat(parser) add flag to log diff on failure (#991)
Browse files Browse the repository at this point in the history
  • Loading branch information
Travis Raines authored Feb 12, 2021
1 parent 90f818d commit a44d8b0
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 0 deletions.
31 changes: 31 additions & 0 deletions cli/ingress-controller/flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"testing"
"time"

"github.com/kong/kubernetes-ingress-controller/pkg/util"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -440,3 +441,33 @@ func TestEnvironmentCertificates(t *testing.T) {
assert.Equal(expected.AdmissionWebhookKey, conf.AdmissionWebhookKey)
assert.Equal(expected.KongAdminCACert, conf.KongAdminCACert)
}

func TestDumpConfig(t *testing.T) {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()

tests := []struct {
value string
expectedMode util.ConfigDumpMode
errors bool
}{
{"", util.ConfigDumpModeOff, false},
{"enabled", util.ConfigDumpModeEnabled, false},
{"sensitive", util.ConfigDumpModeSensitive, false},
{"garbagedjgnkdgd", util.ConfigDumpModeOff, true},
}

for _, test := range tests {
resetForTesting(func() { t.Fatal("bad parse") })
assert := assert.New(t)
os.Setenv("CONTROLLER_DUMP_CONFIG", test.value)
conf, err := parseFlags()
if test.errors {
assert.NotNil(err, "error not emitted when expected parsing dump config")
} else {
assert.Nil(err, "unexpected error parsing dump config")
}
assert.Equal(test.expectedMode, conf.DumpConfig)
os.Unsetenv("CONTROLLER_DUMP_CONFIG")
}
}
16 changes: 16 additions & 0 deletions cli/ingress-controller/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package main

import (
"flag"
"fmt"
"os"
"strings"
"time"
Expand All @@ -28,6 +29,7 @@ import (
apiv1 "k8s.io/api/core/v1"

"github.com/kong/kubernetes-ingress-controller/pkg/annotations"
"github.com/kong/kubernetes-ingress-controller/pkg/util"
)

const (
Expand Down Expand Up @@ -80,6 +82,9 @@ type cliConfig struct {
LogLevel string
LogFormat string

// Diagnostics
DumpConfig util.ConfigDumpMode

// k8s connection details
APIServerHost string
KubeConfigFilePath string
Expand Down Expand Up @@ -199,6 +204,11 @@ trace, debug, info, warn, error, fatal and panic.`)
`Format of logs of the controller. Allowed values are
text and json.`)

// Diagnostics
flags.String("dump-config", "",
`Dump generated configuration to a temporary directory when set to "enabled".
When set to "sensitive", dumps will include certificate+key pairs and credentials.`)

// k8s connection details
flags.String("apiserver-host", "",
`The address of the Kubernetes Apiserver to connect to in the format of
Expand Down Expand Up @@ -311,6 +321,12 @@ func parseFlags() (cliConfig, error) {
config.LogLevel = viper.GetString("log-level")
config.LogFormat = viper.GetString("log-format")

// Diagnostics
var err error
if config.DumpConfig, err = util.ParseConfigDumpMode(viper.GetString("dump-config")); err != nil {
return cliConfig{}, fmt.Errorf("could not parse --dump-config: %w", err)
}

// k8s connection details
config.APIServerHost = viper.GetString("apiserver-host")
config.KubeConfigFilePath = viper.GetString("kubeconfig")
Expand Down
11 changes: 11 additions & 0 deletions cli/ingress-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ func controllerConfigFromCLIConfig(cliConfig cliConfig) controller.Configuration
UpdateStatus: cliConfig.UpdateStatus,
UpdateStatusOnShutdown: cliConfig.UpdateStatusOnShutdown,
ElectionID: cliConfig.ElectionID,

DumpConfig: cliConfig.DumpConfig,
}
}

Expand Down Expand Up @@ -340,6 +342,14 @@ func main() {
)
}

if cliConfig.DumpConfig != util.ConfigDumpModeOff {
controllerConfig.DumpDir, err = ioutil.TempDir("", "controller")
if err != nil {
log.Fatalf("failed to create a dump directory: %v", err)
}
log.Infof("config dumps will be created in: %v", controllerConfig.DumpDir)
}

var synced []cache.InformerSynced
updateChannel := channels.NewRingChannel(1024)
reh := controller.ResourceEventHandler{
Expand Down Expand Up @@ -454,6 +464,7 @@ func main() {

store := store.New(cacheStores, cliConfig.IngressClass, cliConfig.ProcessClasslessIngressV1Beta1,
cliConfig.ProcessClasslessIngressV1, cliConfig.ProcessClasslessKongConsumer, log.WithField("component", "store"))

kong, err := controller.NewKongController(ctx, &controllerConfig, updateChannel,
store)
if err != nil {
Expand Down
5 changes: 5 additions & 0 deletions internal/ingress/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ type Configuration struct {
EnableKnativeIngressSupport bool

Logger logrus.FieldLogger

// DumpConfig writes generated config to a temp directory for manual inspection and debugging.
DumpConfig util.ConfigDumpMode
// DumpDir specifies the target directory for dumps enabled by `DumpConfig`.
DumpDir string
}

// sync collects all the pieces required to assemble the configuration file and
Expand Down
27 changes: 27 additions & 0 deletions internal/ingress/controller/kong.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ package controller

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"

"github.com/kong/deck/file"
"github.com/kong/kubernetes-ingress-controller/pkg/deckgen"
"github.com/kong/kubernetes-ingress-controller/pkg/kongstate"
"github.com/kong/kubernetes-ingress-controller/pkg/sendconfig"
Expand Down Expand Up @@ -53,10 +57,33 @@ func (n *KongController) OnUpdate(ctx context.Context, state *kongstate.KongStat
n.runningConfigHash,
)

if n.cfg.DumpConfig != util.ConfigDumpModeOff {
if n.cfg.DumpConfig == util.ConfigDumpModeEnabled {
targetContent = deckgen.ToDeckContent(ctx, n.Logger, state.SanitizedCopy(), &n.PluginSchemaStore,
n.getIngressControllerTags())
}
dumpErr := dumpConfig(err != nil, n.cfg.DumpDir, targetContent)
if dumpErr != nil {
n.Logger.WithError(err).Warn("failed to dump configuration")
}
}

n.runningConfigHash = newSHA
return err
}

func dumpConfig(failed bool, dumpDir string, targetContent *file.Content) error {
target, err := json.Marshal(targetContent)
if err != nil {
return err
}
filename := "last_good.json"
if failed {
filename = "last_bad.json"
}
return ioutil.WriteFile(filepath.Join(dumpDir, filename), target, 0600)
}

func (n *KongController) fetchCustomEntities() ([]byte, error) {
ns, name, err := util.ParseNameNS(n.cfg.KongCustomEntitiesSecret)
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions pkg/util/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ limitations under the License.

package util

import (
"fmt"
)

// Endpoint describes a kubernetes endpoint, same as a target in Kong.
type Endpoint struct {
// Address IP address of the endpoint
Expand All @@ -29,3 +33,24 @@ type RawSSLCert struct {
Cert []byte
Key []byte
}

type ConfigDumpMode int

const (
ConfigDumpModeOff ConfigDumpMode = iota
ConfigDumpModeEnabled ConfigDumpMode = iota
ConfigDumpModeSensitive ConfigDumpMode = iota
)

func ParseConfigDumpMode(in string) (ConfigDumpMode, error) {
switch in {
case "enabled":
return ConfigDumpModeEnabled, nil
case "sensitive":
return ConfigDumpModeSensitive, nil
case "":
return ConfigDumpModeOff, nil
default:
return ConfigDumpModeOff, fmt.Errorf("unrecognized config dump mode: %s", in)
}
}

0 comments on commit a44d8b0

Please sign in to comment.