diff --git a/cli/cmd/root.go b/cli/cmd/root.go index 6773a9781..84f6dde3b 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -1,7 +1,6 @@ package cmd import ( - "errors" "fmt" "github.com/spf13/cobra" "github.com/up9inc/mizu/cli/fsUtils" @@ -19,8 +18,7 @@ Further info is available at https://github.com/up9inc/mizu`, } mizu.InitLogger() if err := mizu.InitConfig(cmd); err != nil { - mizu.Log.Errorf("Invalid config, Exit %s", err) - return errors.New(fmt.Sprintf("%v", err)) + mizu.Log.Fatal(err) } return nil diff --git a/cli/cmd/tap.go b/cli/cmd/tap.go index 3f4e56370..17dc116d1 100644 --- a/cli/cmd/tap.go +++ b/cli/cmd/tap.go @@ -63,7 +63,6 @@ func init() { tapCmd.Flags().StringArrayP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector") tapCmd.Flags().Bool(configStructs.AnalysisTapName, defaultTapConfig.Analysis, "Uploads traffic to UP9 for further analysis (Beta)") tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces") - tapCmd.Flags().StringP(configStructs.KubeConfigPathTapName, "k", defaultTapConfig.KubeConfigPath, "Path to kube-config file") tapCmd.Flags().StringArrayP(configStructs.PlainTextFilterRegexesTapName, "r", defaultTapConfig.PlainTextFilterRegexes, "List of regex expressions that are used to filter matching values from text/plain http bodies") tapCmd.Flags().Bool(configStructs.HideHealthChecksTapName, defaultTapConfig.HideHealthChecks, "hides requests with kube-probe or prometheus user-agent headers") tapCmd.Flags().Bool(configStructs.DisableRedactionTapName, defaultTapConfig.DisableRedaction, "Disables redaction of potentially sensitive request/response headers and body values") diff --git a/cli/cmd/tapRunner.go b/cli/cmd/tapRunner.go index 3bb0ca7fa..030740fce 100644 --- a/cli/cmd/tapRunner.go +++ b/cli/cmd/tapRunner.go @@ -6,6 +6,8 @@ import ( "encoding/json" "fmt" "github.com/up9inc/mizu/cli/fsUtils" + "github.com/up9inc/mizu/cli/goUtils" + "github.com/up9inc/mizu/cli/mizu/configStructs" "net/http" "net/url" "os" @@ -56,7 +58,7 @@ func RunMizuTap() { } } - kubernetesProvider, err := kubernetes.NewProvider(mizu.Config.Tap.KubeConfigPath) + kubernetesProvider, err := kubernetes.NewProvider(mizu.Config.KubeConfigPath) if err != nil { mizu.Log.Error(err) return @@ -101,8 +103,8 @@ func RunMizuTap() { return } - go createProxyToApiServerPod(ctx, kubernetesProvider, cancel) - go watchPodsForTapping(ctx, kubernetesProvider, targetNamespaces, cancel) + go goUtils.HandleExcWrapper(createProxyToApiServerPod, ctx, kubernetesProvider, cancel) + go goUtils.HandleExcWrapper(watchPodsForTapping, ctx, kubernetesProvider, targetNamespaces, cancel) //block until exit signal or error waitForFinish(ctx, cancel) @@ -399,13 +401,13 @@ func watchPodsForTapping(ctx context.Context, kubernetesProvider *kubernetes.Pro } case err := <-errorChan: - mizu.Log.Debugf("Watching pods loop, got error %v, stopping restart tappers debouncer", err) + mizu.Log.Debugf("Watching pods loop, got error %v, stopping `restart tappers debouncer`", err) restartTappersDebouncer.Cancel() // TODO: Does this also perform cleanup? cancel() case <-ctx.Done(): - mizu.Log.Debugf("Watching pods loop, context done, stopping restart tappers debouncer") + mizu.Log.Debugf("Watching pods loop, context done, stopping `restart tappers debouncer`") restartTappersDebouncer.Cancel() return } @@ -465,9 +467,10 @@ func createProxyToApiServerPod(ctx context.Context, kubernetesProvider *kubernet for { select { case <-ctx.Done(): + mizu.Log.Debugf("Watching API Server pod loop, ctx done") return case <-added: - mizu.Log.Debugf("Got agent pod added event") + mizu.Log.Debugf("Watching API Server pod loop, added") continue case <-removed: mizu.Log.Infof("%s removed", mizu.ApiServerPodName) @@ -475,16 +478,17 @@ func createProxyToApiServerPod(ctx context.Context, kubernetesProvider *kubernet return case modifiedPod := <-modified: if modifiedPod == nil { - mizu.Log.Debugf("Got agent pod modified event, status phase: %v", modifiedPod.Status.Phase) + mizu.Log.Debugf("Watching API Server pod loop, modifiedPod with nil") continue } - mizu.Log.Debugf("Got agent pod modified event, status phase: %v", modifiedPod.Status.Phase) + mizu.Log.Debugf("Watching API Server pod loop, modified: %v", modifiedPod.Status.Phase) if modifiedPod.Status.Phase == core.PodRunning && !isPodReady { isPodReady = true go func() { err := kubernetes.StartProxy(kubernetesProvider, mizu.Config.Tap.GuiPort, mizu.Config.MizuResourcesNamespace, mizu.ApiServerPodName) if err != nil { - mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error occured while running k8s proxy %v", errormessage.FormatError(err))) + mizu.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error occured while running k8s proxy %v\n"+ + "Try setting different port by using --%s", errormessage.FormatError(err), configStructs.GuiPortTapName)) cancel() } }() @@ -530,21 +534,15 @@ func requestForAnalysis() { } func createRBACIfNecessary(ctx context.Context, kubernetesProvider *kubernetes.Provider) (bool, error) { - mizuRBACExists, err := kubernetesProvider.DoesServiceAccountExist(ctx, mizu.Config.MizuResourcesNamespace, mizu.ServiceAccountName) - if err != nil { - return false, err - } - if !mizuRBACExists { - if !mizu.Config.IsNsRestrictedMode() { - err := kubernetesProvider.CreateMizuRBAC(ctx, mizu.Config.MizuResourcesNamespace, mizu.ServiceAccountName, mizu.ClusterRoleName, mizu.ClusterRoleBindingName, mizu.RBACVersion) - if err != nil { - return false, err - } - } else { - err := kubernetesProvider.CreateMizuRBACNamespaceRestricted(ctx, mizu.Config.MizuResourcesNamespace, mizu.ServiceAccountName, mizu.RoleName, mizu.RoleBindingName, mizu.RBACVersion) - if err != nil { - return false, err - } + if !mizu.Config.IsNsRestrictedMode() { + err := kubernetesProvider.CreateMizuRBAC(ctx, mizu.Config.MizuResourcesNamespace, mizu.ServiceAccountName, mizu.ClusterRoleName, mizu.ClusterRoleBindingName, mizu.RBACVersion) + if err != nil { + return false, err + } + } else { + err := kubernetesProvider.CreateMizuRBACNamespaceRestricted(ctx, mizu.Config.MizuResourcesNamespace, mizu.ServiceAccountName, mizu.RoleName, mizu.RoleBindingName, mizu.RBACVersion) + if err != nil { + return false, err } } return true, nil diff --git a/cli/cmd/viewRunner.go b/cli/cmd/viewRunner.go index f2aae65a7..587c7e384 100644 --- a/cli/cmd/viewRunner.go +++ b/cli/cmd/viewRunner.go @@ -38,6 +38,6 @@ func runMizuView() { mizu.Log.Infof("Mizu is available at http://%s\n", kubernetes.GetMizuApiServerProxiedHostAndPath(mizu.Config.View.GuiPort)) err = kubernetes.StartProxy(kubernetesProvider, mizu.Config.View.GuiPort, mizu.Config.MizuResourcesNamespace, mizu.ApiServerPodName) if err != nil { - mizu.Log.Infof("Error occured while running k8s proxy %v", err) + mizu.Log.Errorf("Error occurred while running k8s proxy %v", err) } } diff --git a/cli/fsUtils/mizuLogsUtils.go b/cli/fsUtils/mizuLogsUtils.go index a65058711..701c8b25f 100644 --- a/cli/fsUtils/mizuLogsUtils.go +++ b/cli/fsUtils/mizuLogsUtils.go @@ -18,7 +18,7 @@ func DumpLogs(provider *kubernetes.Provider, ctx context.Context, filePath strin } if len(pods) == 0 { - return fmt.Errorf("no pods found in namespace %s", mizu.Config.MizuResourcesNamespace) + return fmt.Errorf("no mizu pods found in namespace %s", mizu.Config.MizuResourcesNamespace) } newZipFile, err := os.Create(filePath) @@ -49,7 +49,7 @@ func DumpLogs(provider *kubernetes.Provider, ctx context.Context, filePath strin mizu.Log.Infof("Successfully added file %s", mizu.GetConfigFilePath()) } if err := AddFileToZip(zipWriter, mizu.GetLogFilePath()); err != nil { - mizu.Log.Errorf("Failed write file, %v", err) + mizu.Log.Debugf("Failed write file, %v", err) } else { mizu.Log.Infof("Successfully added file %s", mizu.GetLogFilePath()) } diff --git a/cli/goUtils/funcWrappers.go b/cli/goUtils/funcWrappers.go new file mode 100644 index 000000000..ad71b684b --- /dev/null +++ b/cli/goUtils/funcWrappers.go @@ -0,0 +1,25 @@ +package goUtils + +import ( + "github.com/up9inc/mizu/cli/mizu" + "reflect" + "runtime/debug" +) + +func HandleExcWrapper(fn interface{}, params ...interface{}) (result []reflect.Value) { + defer func() { + if panicMessage := recover(); panicMessage != nil { + stack := debug.Stack() + mizu.Log.Fatalf("Unhandled panic: %v\n stack: %s", panicMessage, stack) + } + }() + f := reflect.ValueOf(fn) + if f.Type().NumIn() != len(params) { + panic("incorrect number of parameters!") + } + inputs := make([]reflect.Value, len(params)) + for k, in := range params { + inputs[k] = reflect.ValueOf(in) + } + return f.Call(inputs) +} diff --git a/cli/kubernetes/provider.go b/cli/kubernetes/provider.go index 24f3e064a..fcbb78502 100644 --- a/cli/kubernetes/provider.go +++ b/cli/kubernetes/provider.go @@ -13,17 +13,14 @@ import ( "strconv" "github.com/up9inc/mizu/cli/mizu" - "io" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/homedir" - "github.com/up9inc/mizu/shared" + "io" core "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" resource "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/watch" applyconfapp "k8s.io/client-go/applyconfigurations/apps/v1" @@ -35,9 +32,11 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" _ "k8s.io/client-go/tools/portforward" watchtools "k8s.io/client-go/tools/watch" + "k8s.io/client-go/util/homedir" ) type Provider struct { @@ -358,15 +357,15 @@ func (provider *Provider) CreateMizuRBAC(ctx context.Context, namespace string, }, } _, err := provider.clientSet.CoreV1().ServiceAccounts(namespace).Create(ctx, serviceAccount, metav1.CreateOptions{}) - if err != nil { + if err != nil && !k8serrors.IsAlreadyExists(err) { return err } _, err = provider.clientSet.RbacV1().ClusterRoles().Create(ctx, clusterRole, metav1.CreateOptions{}) - if err != nil { + if err != nil && !k8serrors.IsAlreadyExists(err) { return err } _, err = provider.clientSet.RbacV1().ClusterRoleBindings().Create(ctx, clusterRoleBinding, metav1.CreateOptions{}) - if err != nil { + if err != nil && !k8serrors.IsAlreadyExists(err) { return err } return nil @@ -412,15 +411,15 @@ func (provider *Provider) CreateMizuRBACNamespaceRestricted(ctx context.Context, }, } _, err := provider.clientSet.CoreV1().ServiceAccounts(namespace).Create(ctx, serviceAccount, metav1.CreateOptions{}) - if err != nil { + if err != nil && !k8serrors.IsAlreadyExists(err) { return err } _, err = provider.clientSet.RbacV1().Roles(namespace).Create(ctx, role, metav1.CreateOptions{}) - if err != nil { + if err != nil && !k8serrors.IsAlreadyExists(err) { return err } _, err = provider.clientSet.RbacV1().RoleBindings(namespace).Create(ctx, roleBinding, metav1.CreateOptions{}) - if err != nil { + if err != nil && !k8serrors.IsAlreadyExists(err) { return err } return nil diff --git a/cli/mizu.go b/cli/mizu.go index e635ad429..6dc698567 100644 --- a/cli/mizu.go +++ b/cli/mizu.go @@ -2,8 +2,9 @@ package main import ( "github.com/up9inc/mizu/cli/cmd" + "github.com/up9inc/mizu/cli/goUtils" ) func main() { - cmd.Execute() + goUtils.HandleExcWrapper(cmd.Execute) } diff --git a/cli/mizu/config.go b/cli/mizu/config.go index a4dd222ca..2c2712af5 100644 --- a/cli/mizu/config.go +++ b/cli/mizu/config.go @@ -28,6 +28,7 @@ var allowedSetFlags = []string{ MizuResourcesNamespaceConfigName, TelemetryConfigName, DumpLogsConfigName, + KubeConfigPathName, configStructs.AnalysisDestinationTapName, configStructs.SleepIntervalSecTapName, } @@ -51,8 +52,8 @@ func InitConfig(cmd *cobra.Command) error { } if err := mergeConfigFile(); err != nil { - Log.Errorf("Could not load config file, error %v", err) - Log.Fatalf("You can regenerate the file using `mizu config -r` or just remove it %v", GetConfigFilePath()) + return fmt.Errorf("invalid config %w\n"+ + "you can regenerate the file using `mizu config -r` or just remove it %v", err, GetConfigFilePath()) } cmd.Flags().Visit(initFlag) diff --git a/cli/mizu/configStruct.go b/cli/mizu/configStruct.go index 6b45fc579..24ee0d49e 100644 --- a/cli/mizu/configStruct.go +++ b/cli/mizu/configStruct.go @@ -11,6 +11,7 @@ const ( MizuResourcesNamespaceConfigName = "mizu-resources-namespace" TelemetryConfigName = "telemetry" DumpLogsConfigName = "dump-logs" + KubeConfigPathName = "kube-config-path" ) type ConfigStruct struct { @@ -22,6 +23,7 @@ type ConfigStruct struct { MizuResourcesNamespace string `yaml:"mizu-resources-namespace" default:"mizu"` Telemetry bool `yaml:"telemetry" default:"true"` DumpLogs bool `yaml:"dump-logs" default:"false"` + KubeConfigPath string `yaml:"kube-config-path" default:""` } func (config *ConfigStruct) SetDefaults() { diff --git a/cli/mizu/configStructs/tapConfig.go b/cli/mizu/configStructs/tapConfig.go index 1f8923667..67582e467 100644 --- a/cli/mizu/configStructs/tapConfig.go +++ b/cli/mizu/configStructs/tapConfig.go @@ -16,7 +16,6 @@ const ( NamespacesTapName = "namespaces" AnalysisTapName = "analysis" AllNamespacesTapName = "all-namespaces" - KubeConfigPathTapName = "kube-config" PlainTextFilterRegexesTapName = "regex-masking" HideHealthChecksTapName = "hide-healthchecks" DisableRedactionTapName = "no-redact" @@ -34,7 +33,6 @@ type TapConfig struct { Namespaces []string `yaml:"namespaces"` Analysis bool `yaml:"analysis" default:"false"` AllNamespaces bool `yaml:"all-namespaces" default:"false"` - KubeConfigPath string `yaml:"kube-config"` PlainTextFilterRegexes []string `yaml:"regex-masking"` HideHealthChecks bool `yaml:"hide-healthchecks" default:"false"` DisableRedaction bool `yaml:"no-redact" default:"false"`