yuluo-yx commented on code in PR #19: URL: https://github.com/apache/hertzbeat-collector-go/pull/19#discussion_r2384211913
########## internal/util/param/param_replacer.go: ########## @@ -0,0 +1,391 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package param + +import ( + "encoding/json" + "fmt" + "os" + "strconv" + "strings" + + jobtypes "hertzbeat.apache.org/hertzbeat-collector-go/internal/collector/common/types/job" + loggertype "hertzbeat.apache.org/hertzbeat-collector-go/internal/collector/common/types/logger" + "hertzbeat.apache.org/hertzbeat-collector-go/internal/util/crypto" + "hertzbeat.apache.org/hertzbeat-collector-go/internal/util/logger" +) + +// Replacer is a standalone utility for parameter replacement +// This matches Java's parameter substitution mechanism where ^_^paramName^_^ gets replaced with actual values +type Replacer struct{} + +// NewReplacer creates a new parameter replacer +func NewReplacer() *Replacer { + return &Replacer{} +} + +// PreprocessJobPasswords decrypts passwords in job configmap once during job creation +// This permanently replaces encrypted passwords with decrypted ones in the job configmap +func (r *Replacer) PreprocessJobPasswords(job *jobtypes.Job) error { + if job == nil || job.Configmap == nil { + return nil + } + + log := logger.DefaultLogger(os.Stdout, loggertype.LogLevelDebug).WithName("password-preprocessor") + + // Decrypt passwords in configmap once and permanently replace them + for i := range job.Configmap { + config := &job.Configmap[i] // Get pointer to modify in place + if config.Type == 2 { // password type + if encryptedValue, ok := config.Value.(string); ok { + log.Sugar().Debugf("preprocessing encrypted password for key: %s", config.Key) + if decoded, err := r.decryptPassword(encryptedValue); err == nil { + log.Info("password preprocessing successful", "key", config.Key, "length", len(decoded)) + config.Value = decoded // Permanently replace encrypted value with decrypted value + config.Type = 1 // Change type to string since it's now decrypted + } else { + log.Error(err, "password preprocessing failed, keeping original value", "key", config.Key) + } + } + } + } + return nil +} + +// ReplaceJobParams replaces all parameter placeholders in job configuration +func (r *Replacer) ReplaceJobParams(job *jobtypes.Job) (*jobtypes.Job, error) { + if job == nil { + return nil, fmt.Errorf("job is nil") + } + + // Create parameter map from configmap (passwords should already be decrypted) + paramMap := r.createParamMapSimple(job.Configmap) + + // Clone the job to avoid modifying original + clonedJob := job.Clone() + if clonedJob == nil { + return nil, fmt.Errorf("failed to clone job") + } + + // Replace parameters in all metrics + for i := range clonedJob.Metrics { + if err := r.replaceMetricsParams(&clonedJob.Metrics[i], paramMap); err != nil { + return nil, fmt.Errorf("failed to replace params in metrics %s: %w", clonedJob.Metrics[i].Name, err) + } + } + + return clonedJob, nil +} + +// createParamMapSimple creates a parameter map from configmap entries +// Assumes passwords have already been decrypted by PreprocessJobPasswords +func (r *Replacer) createParamMapSimple(configmap []jobtypes.Configmap) map[string]string { + paramMap := make(map[string]string) + + for _, config := range configmap { + // Convert value to string, handle null values as empty strings + var strValue string + if config.Value == nil { + strValue = "" // null values become empty strings + } else { + switch config.Type { + case 0: // number + if numVal, ok := config.Value.(float64); ok { + strValue = strconv.FormatFloat(numVal, 'f', -1, 64) + } else if intVal, ok := config.Value.(int); ok { + strValue = strconv.Itoa(intVal) + } else { + strValue = fmt.Sprintf("%v", config.Value) + } + case 1, 2: // string or password (both are now plain strings after preprocessing) + strValue = fmt.Sprintf("%v", config.Value) + default: + strValue = fmt.Sprintf("%v", config.Value) + } + } + paramMap[config.Key] = strValue + } + + return paramMap +} + +// createParamMap creates a parameter map from configmap entries (legacy version with decryption) +// Deprecated: Use PreprocessJobPasswords + createParamMapSafe instead +func (r *Replacer) createParamMap(configmap []jobtypes.Configmap) map[string]string { + paramMap := make(map[string]string) + + for _, config := range configmap { + // Convert value to string based on type, handle null values as empty strings + var strValue string + if config.Value == nil { + strValue = "" // null values become empty strings + } else { + switch config.Type { + case 0: // number Review Comment: 可以抽成常亮放在 types 里面,0 1 2 不具有语义和可读性 ########## internal/util/param/param_replacer.go: ########## @@ -0,0 +1,391 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package param + +import ( + "encoding/json" + "fmt" + "os" + "strconv" + "strings" + + jobtypes "hertzbeat.apache.org/hertzbeat-collector-go/internal/collector/common/types/job" + loggertype "hertzbeat.apache.org/hertzbeat-collector-go/internal/collector/common/types/logger" + "hertzbeat.apache.org/hertzbeat-collector-go/internal/util/crypto" + "hertzbeat.apache.org/hertzbeat-collector-go/internal/util/logger" +) + +// Replacer is a standalone utility for parameter replacement +// This matches Java's parameter substitution mechanism where ^_^paramName^_^ gets replaced with actual values +type Replacer struct{} + +// NewReplacer creates a new parameter replacer +func NewReplacer() *Replacer { + return &Replacer{} +} + +// PreprocessJobPasswords decrypts passwords in job configmap once during job creation +// This permanently replaces encrypted passwords with decrypted ones in the job configmap +func (r *Replacer) PreprocessJobPasswords(job *jobtypes.Job) error { + if job == nil || job.Configmap == nil { + return nil + } + + log := logger.DefaultLogger(os.Stdout, loggertype.LogLevelDebug).WithName("password-preprocessor") + + // Decrypt passwords in configmap once and permanently replace them + for i := range job.Configmap { + config := &job.Configmap[i] // Get pointer to modify in place + if config.Type == 2 { // password type + if encryptedValue, ok := config.Value.(string); ok { + log.Sugar().Debugf("preprocessing encrypted password for key: %s", config.Key) + if decoded, err := r.decryptPassword(encryptedValue); err == nil { + log.Info("password preprocessing successful", "key", config.Key, "length", len(decoded)) + config.Value = decoded // Permanently replace encrypted value with decrypted value + config.Type = 1 // Change type to string since it's now decrypted + } else { + log.Error(err, "password preprocessing failed, keeping original value", "key", config.Key) + } + } + } + } + return nil +} + +// ReplaceJobParams replaces all parameter placeholders in job configuration +func (r *Replacer) ReplaceJobParams(job *jobtypes.Job) (*jobtypes.Job, error) { + if job == nil { + return nil, fmt.Errorf("job is nil") + } + + // Create parameter map from configmap (passwords should already be decrypted) + paramMap := r.createParamMapSimple(job.Configmap) + + // Clone the job to avoid modifying original + clonedJob := job.Clone() + if clonedJob == nil { + return nil, fmt.Errorf("failed to clone job") + } + + // Replace parameters in all metrics + for i := range clonedJob.Metrics { + if err := r.replaceMetricsParams(&clonedJob.Metrics[i], paramMap); err != nil { + return nil, fmt.Errorf("failed to replace params in metrics %s: %w", clonedJob.Metrics[i].Name, err) + } + } + + return clonedJob, nil +} + +// createParamMapSimple creates a parameter map from configmap entries +// Assumes passwords have already been decrypted by PreprocessJobPasswords +func (r *Replacer) createParamMapSimple(configmap []jobtypes.Configmap) map[string]string { + paramMap := make(map[string]string) + + for _, config := range configmap { + // Convert value to string, handle null values as empty strings + var strValue string + if config.Value == nil { + strValue = "" // null values become empty strings + } else { + switch config.Type { + case 0: // number + if numVal, ok := config.Value.(float64); ok { + strValue = strconv.FormatFloat(numVal, 'f', -1, 64) + } else if intVal, ok := config.Value.(int); ok { + strValue = strconv.Itoa(intVal) + } else { + strValue = fmt.Sprintf("%v", config.Value) + } + case 1, 2: // string or password (both are now plain strings after preprocessing) Review Comment: 同下 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
