diff --git a/cmd/external-app/wire_gen.go b/cmd/external-app/wire_gen.go index f79fb2449f..e30567cf81 100644 --- a/cmd/external-app/wire_gen.go +++ b/cmd/external-app/wire_gen.go @@ -234,15 +234,15 @@ func InitializeApp() (*App, error) { k8sClientServiceImpl := application.NewK8sClientServiceImpl(sugaredLogger, clusterRepositoryImpl) k8sResourceHistoryRepositoryImpl := repository5.NewK8sResourceHistoryRepositoryImpl(db, sugaredLogger) k8sResourceHistoryServiceImpl := kubernetesResourceAuditLogs.Newk8sResourceHistoryServiceImpl(k8sResourceHistoryRepositoryImpl, sugaredLogger, appRepositoryImpl, environmentRepositoryImpl) - terminalSessionHandlerImpl := terminal.NewTerminalSessionHandlerImpl(environmentServiceImpl, clusterServiceImpl, sugaredLogger, k8sUtil) ephemeralContainersRepositoryImpl := repository2.NewEphemeralContainersRepositoryImpl(db) ephemeralContainerServiceImpl := cluster.NewEphemeralContainerServiceImpl(ephemeralContainersRepositoryImpl, sugaredLogger) - k8sApplicationServiceImpl := k8s.NewK8sApplicationServiceImpl(sugaredLogger, clusterServiceImpl, pumpImpl, k8sClientServiceImpl, helmAppServiceImpl, k8sUtil, acdAuthConfig, k8sResourceHistoryServiceImpl, terminalSessionHandlerImpl, ephemeralContainerServiceImpl) + terminalSessionHandlerImpl := terminal.NewTerminalSessionHandlerImpl(environmentServiceImpl, clusterServiceImpl, sugaredLogger, k8sUtil, ephemeralContainerServiceImpl) + k8sApplicationServiceImpl := k8s.NewK8sApplicationServiceImpl(sugaredLogger, clusterServiceImpl, pumpImpl, k8sClientServiceImpl, helmAppServiceImpl, k8sUtil, acdAuthConfig, k8sResourceHistoryServiceImpl, terminalSessionHandlerImpl, ephemeralContainerServiceImpl, ephemeralContainersRepositoryImpl) environmentRestHandlerImpl := cluster2.NewEnvironmentRestHandlerImpl(environmentServiceImpl, k8sApplicationServiceImpl, sugaredLogger, userServiceImpl, validate, enforcerImpl, deleteServiceImpl) environmentRouterImpl := cluster2.NewEnvironmentRouterImpl(environmentRestHandlerImpl) ciPipelineRepositoryImpl := pipelineConfig.NewCiPipelineRepositoryImpl(db, sugaredLogger) enforcerUtilImpl := rbac.NewEnforcerUtilImpl(sugaredLogger, teamRepositoryImpl, appRepositoryImpl, environmentRepositoryImpl, pipelineRepositoryImpl, ciPipelineRepositoryImpl, clusterRepositoryImpl) - k8sApplicationRestHandlerImpl := k8s.NewK8sApplicationRestHandlerImpl(sugaredLogger, k8sApplicationServiceImpl, pumpImpl, terminalSessionHandlerImpl, enforcerImpl, enforcerUtilHelmImpl, enforcerUtilImpl, helmAppServiceImpl, userServiceImpl) + k8sApplicationRestHandlerImpl := k8s.NewK8sApplicationRestHandlerImpl(sugaredLogger, k8sApplicationServiceImpl, pumpImpl, terminalSessionHandlerImpl, enforcerImpl, enforcerUtilHelmImpl, enforcerUtilImpl, helmAppServiceImpl, userServiceImpl, validate) k8sApplicationRouterImpl := k8s.NewK8sApplicationRouterImpl(k8sApplicationRestHandlerImpl) chartRefRepositoryImpl := chartRepoRepository.NewChartRefRepositoryImpl(db) refChartDir := _wireRefChartDirValue diff --git a/internal/util/K8sUtil.go b/internal/util/K8sUtil.go index 5cbfdf3925..1966427d11 100644 --- a/internal/util/K8sUtil.go +++ b/internal/util/K8sUtil.go @@ -23,10 +23,11 @@ import ( error2 "errors" "flag" "fmt" + "github.com/caarlos0/env" + "github.com/devtron-labs/devtron/util" "net/http" "os/user" "path/filepath" - "strconv" "strings" "time" @@ -55,6 +56,7 @@ type K8sUtil struct { logger *zap.SugaredLogger runTimeConfig *client.RuntimeConfig kubeconfig *string + k8sUtilConfig *util.K8sUtilConfig } type ClusterConfig struct { @@ -84,7 +86,13 @@ func NewK8sUtil(logger *zap.SugaredLogger, runTimeConfig *client.RuntimeConfig) } flag.Parse() - return &K8sUtil{logger: logger, runTimeConfig: runTimeConfig, kubeconfig: kubeconfig} + + cfg := &util.K8sUtilConfig{} + err = env.Parse(cfg) + if err != nil { + logger.Infow("error occurred while parsing K8sUtilConfig,so setting K8sUtilConfig to default values", "err", err) + } + return &K8sUtil{logger: logger, runTimeConfig: runTimeConfig, kubeconfig: kubeconfig, k8sUtilConfig: cfg} } func (impl K8sUtil) GetRestConfigByCluster(configMap *ClusterConfig) (*rest.Config, error) { @@ -829,21 +837,19 @@ func (impl K8sUtil) GetKubeVersion() (*version.Info, error) { func (impl K8sUtil) K8sServerVersionCheckForEphemeralContainers(clientSet *kubernetes.Clientset) (bool, error) { k8sServerVersion, err := impl.GetK8sServerVersion(clientSet) - if err != nil { + if err != nil || k8sServerVersion == nil { impl.logger.Errorw("error occurred in getting k8sServerVersion", "err", err) return false, err } - majorVersion, minorVersion, err := impl.extractMajorAndMinorVersion(k8sServerVersion) - if err != nil { - impl.logger.Errorw("error occurred in extracting k8s Major and Minor server version values", "err", err, "k8sServerVersion", k8sServerVersion) - return false, err - } //ephemeral containers feature is introduced in version v1.23 of kubernetes, it is stable from version v1.25 //https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/ - if majorVersion < 1 || (majorVersion == 1 && minorVersion < 23) { - return false, nil + ephemeralRegex := impl.k8sUtilConfig.EphemeralServerVersionRegex + matched, err := util.MatchRegex(ephemeralRegex, k8sServerVersion.String()) + if err != nil { + impl.logger.Errorw("error in matching ephemeral containers support version regex with k8sServerVersion", "err", err, "EphemeralServerVersionRegex", ephemeralRegex) + return false, err } - return true, nil + return matched, nil } func (impl K8sUtil) GetK8sServerVersion(clientSet *kubernetes.Clientset) (*version.Info, error) { @@ -854,17 +860,3 @@ func (impl K8sUtil) GetK8sServerVersion(clientSet *kubernetes.Clientset) (*versi } return k8sServerVersion, nil } - -func (impl K8sUtil) extractMajorAndMinorVersion(k8sServerVersion *version.Info) (int, int, error) { - majorVersion, err := strconv.Atoi(k8sServerVersion.Major) - if err != nil { - impl.logger.Errorw("error occurred in converting k8sServerVersion.Major version value to integer", "err", err, "k8sServerVersion.Major", k8sServerVersion.Major) - return 0, 0, err - } - minorVersion, err := strconv.Atoi(k8sServerVersion.Minor) - if err != nil { - impl.logger.Errorw("error occurred in converting k8sServerVersion.Minor version value to integer", "err", err, "k8sServerVersion.Minor", k8sServerVersion.Minor) - return majorVersion, 0, err - } - return majorVersion, minorVersion, nil -} diff --git a/util/K8sUtil.go b/util/K8sUtil.go index 963c484e26..b2e8c1625a 100644 --- a/util/K8sUtil.go +++ b/util/K8sUtil.go @@ -5,9 +5,14 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/validation" + "regexp" "strings" ) +type K8sUtilConfig struct { + EphemeralServerVersionRegex string `env:"EPHEMERAL_SERVER_VERSION_REGEX" envDefault:"v[1-9]\\.\\b(2[3-9]|[3-9][0-9])\\b.*"` +} + func CheckIfValidLabel(labelKey string, labelValue string) error { labelKey = strings.TrimSpace(labelKey) labelValue = strings.TrimSpace(labelValue) @@ -70,3 +75,12 @@ func isExternalEphemeralContainer(cmds []string, name string) bool { } return isExternal } + +func MatchRegex(exp string, text string) (bool, error) { + rExp, err := regexp.Compile(exp) + if err != nil { + return false, err + } + matched := rExp.Match([]byte(text)) + return matched, nil +} diff --git a/util/K8sUtil_test.go b/util/K8sUtil_test.go new file mode 100644 index 0000000000..a47d4a17e1 --- /dev/null +++ b/util/K8sUtil_test.go @@ -0,0 +1,109 @@ +package util + +import ( + "fmt" + "github.com/caarlos0/env" + "testing" +) + +func TestMatchRegex(t *testing.T) { + cfg := &K8sUtilConfig{} + env.Parse(cfg) + ephemeralRegex := cfg.EphemeralServerVersionRegex + type args struct { + exp string + text string + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "Invalid regex", + args: args{ + exp: "**", + text: "v1.23+", + }, + want: false, + wantErr: true, + }, + { + name: "Valid regex,text not matching with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.03+", + }, + want: false, + wantErr: false, + }, + { + name: "Valid regex,text not matching with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.22+", + }, + want: false, + wantErr: false, + }, + { + name: "Valid regex, text not matching with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.3", + }, + want: false, + wantErr: false, + }, + { + name: "Valid regex, text match with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.23+", + }, + want: true, + wantErr: false, + }, + { + name: "Valid regex, text match with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.26.6", + }, + want: true, + wantErr: false, + }, + { + name: "Valid regex, text match with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.26", + }, + want: true, + wantErr: false, + }, + { + name: "Valid regex, text match with regex", + args: args{ + exp: ephemeralRegex, + text: "v1.30", + }, + want: true, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := MatchRegex(tt.args.exp, tt.args.text) + fmt.Println(err) + if (err != nil) != tt.wantErr { + t.Errorf("MatchRegex() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("MatchRegex() got = %v, want %v", got, tt.want) + } + }) + } +}