Skip to content

Commit 27dafc8

Browse files
feat: Scoped variables primitive handling (#4033)
* adding system variables in get scoped data * system variables * bug fixes * minor fix * image tag variable exposed * refactoring * refactoring * fix escaping $ * wf resolver to type string * fixing logic * addressed comments and cleaned up code * cleaning up * parser to return if scoped variables disabled --------- Co-authored-by: Kripansh <[email protected]>
1 parent 9890774 commit 27dafc8

File tree

11 files changed

+214
-34
lines changed

11 files changed

+214
-34
lines changed

api/bean/ValuesOverrideRequest.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ type ValuesOverrideRequest struct {
7272
AppName string `json:"-"`
7373
PipelineName string `json:"-"`
7474
DeploymentAppType string `json:"-"`
75+
ImageTag string `json:"-"`
7576
}
7677

7778
type BulkCdDeployEvent struct {

pkg/app/AppService.go

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,13 +1256,8 @@ func (impl *AppServiceImpl) GetDeploymentStrategyByTriggerType(overrideRequest *
12561256

12571257
func (impl *AppServiceImpl) GetEnvOverrideByTriggerType(overrideRequest *bean.ValuesOverrideRequest, triggeredAt time.Time, ctx context.Context) (*chartConfig.EnvConfigOverride, error) {
12581258

1259-
//VARIABLE different cases for variable resolution
1260-
scope := resourceQualifiers.Scope{
1261-
AppId: overrideRequest.AppId,
1262-
EnvId: overrideRequest.EnvId,
1263-
ClusterId: overrideRequest.ClusterId,
1264-
}
12651259
envOverride := &chartConfig.EnvConfigOverride{}
1260+
12661261
var err error
12671262
if overrideRequest.DeploymentWithConfig == bean.DEPLOYMENT_CONFIG_TYPE_SPECIFIC_TRIGGER {
12681263
_, span := otel.Tracer("orchestrator").Start(ctx, "deploymentTemplateHistoryRepository.GetHistoryByPipelineIdAndWfrId")
@@ -1375,7 +1370,30 @@ func (impl *AppServiceImpl) GetEnvOverrideByTriggerType(overrideRequest *bean.Va
13751370
envOverride.Chart = chart
13761371
}
13771372

1373+
_, span = otel.Tracer("orchestrator").Start(ctx, "envRepository.FindById")
1374+
env, err := impl.envRepository.FindById(envOverride.TargetEnvironment)
1375+
span.End()
1376+
if err != nil {
1377+
impl.logger.Errorw("unable to find env", "err", err)
1378+
return nil, err
1379+
}
1380+
envOverride.Environment = env
1381+
1382+
//VARIABLE different cases for variable resolution
1383+
scope := resourceQualifiers.Scope{
1384+
AppId: overrideRequest.AppId,
1385+
EnvId: overrideRequest.EnvId,
1386+
ClusterId: overrideRequest.ClusterId,
1387+
SystemMetadata: &resourceQualifiers.SystemMetadata{
1388+
EnvironmentName: env.Name,
1389+
ClusterName: env.Cluster.ClusterName,
1390+
Namespace: env.Namespace,
1391+
ImageTag: overrideRequest.ImageTag,
1392+
},
1393+
}
1394+
13781395
if envOverride.IsOverride {
1396+
13791397
resolvedTemplate, variableMap, err := impl.extractVariablesAndResolveTemplate(scope, envOverride.EnvOverrideValues, repository6.Entity{
13801398
EntityType: repository6.EntityTypeDeploymentTemplateEnvLevel,
13811399
EntityId: envOverride.Id,
@@ -1397,15 +1415,7 @@ func (impl *AppServiceImpl) GetEnvOverrideByTriggerType(overrideRequest *bean.Va
13971415
envOverride.VariableSnapshot = variableMap
13981416
}
13991417
}
1400-
_, span := otel.Tracer("orchestrator").Start(ctx, "envRepository.FindById")
1401-
env, err := impl.envRepository.FindById(envOverride.TargetEnvironment)
1402-
span.End()
1403-
if err != nil {
1404-
impl.logger.Errorw("unable to find env", "err", err)
1405-
return nil, err
1406-
}
1407-
envOverride.Environment = env
1408-
//VARIABLE_RESOLVE
1418+
14091419
return envOverride, nil
14101420
}
14111421

@@ -1490,6 +1500,14 @@ func (impl *AppServiceImpl) GetValuesOverrideForTrigger(overrideRequest *bean.Va
14901500
return valuesOverrideResponse, err
14911501
}
14921502

1503+
_, span := otel.Tracer("orchestrator").Start(ctx, "ciArtifactRepository.Get")
1504+
artifact, err := impl.ciArtifactRepository.Get(overrideRequest.CiArtifactId)
1505+
span.End()
1506+
if err != nil {
1507+
return valuesOverrideResponse, err
1508+
}
1509+
overrideRequest.ImageTag = artifact.Image
1510+
14931511
envOverride, err := impl.GetEnvOverrideByTriggerType(overrideRequest, triggeredAt, ctx)
14941512
if err != nil {
14951513
impl.logger.Errorw("error in getting env override by trigger type", "err", err)
@@ -1505,12 +1523,6 @@ func (impl *AppServiceImpl) GetValuesOverrideForTrigger(overrideRequest *bean.Va
15051523
impl.logger.Errorw("error in getting strategy by trigger type", "err", err)
15061524
return valuesOverrideResponse, err
15071525
}
1508-
_, span := otel.Tracer("orchestrator").Start(ctx, "ciArtifactRepository.Get")
1509-
artifact, err := impl.ciArtifactRepository.Get(overrideRequest.CiArtifactId)
1510-
span.End()
1511-
if err != nil {
1512-
return valuesOverrideResponse, err
1513-
}
15141526
_, span = otel.Tracer("orchestrator").Start(ctx, "getDbMigrationOverride")
15151527
//FIXME: how to determine rollback
15161528
//we can't depend on ciArtifact ID because CI pipeline can be manually triggered in any order regardless of sourcecode status

pkg/pipeline/CiService.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ func (impl *CiServiceImpl) TriggerCiPipeline(trigger Trigger) (int, error) {
166166
//This will be populated for jobs running in selected environment
167167
scope.EnvId = env.Id
168168
scope.ClusterId = env.ClusterId
169+
170+
scope.SystemMetadata = &resourceQualifiers.SystemMetadata{
171+
EnvironmentName: env.Name,
172+
ClusterName: env.Cluster.ClusterName,
173+
Namespace: env.Namespace,
174+
}
169175
}
170176
if ciWorkflowConfig.Namespace == "" {
171177
ciWorkflowConfig.Namespace = impl.config.GetDefaultNamespace()

pkg/pipeline/WorkflowDagExecutor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,12 @@ func (impl *WorkflowDagExecutorImpl) buildWFRequest(runner *pipelineConfig.CdWor
902902
AppId: cdPipeline.App.Id,
903903
EnvId: env.Id,
904904
ClusterId: env.ClusterId,
905+
SystemMetadata: &resourceQualifiers.SystemMetadata{
906+
EnvironmentName: env.Name,
907+
ClusterName: env.Cluster.ClusterName,
908+
Namespace: env.Namespace,
909+
ImageTag: artifact.Image,
910+
},
905911
}
906912
var variableSnapshot map[string]string
907913
if runner.WorkflowType == bean.CD_WORKFLOW_TYPE_PRE {

pkg/resourceQualifiers/bean.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,29 @@ type Scope struct {
44
AppId int `json:"appId"`
55
EnvId int `json:"envId"`
66
ClusterId int `json:"clusterId"`
7+
8+
SystemMetadata *SystemMetadata `json:"-"`
9+
}
10+
11+
type SystemMetadata struct {
12+
EnvironmentName string
13+
ClusterName string
14+
Namespace string
15+
ImageTag string
16+
}
17+
18+
func (metadata *SystemMetadata) GetDataFromSystemVariable(variable SystemVariableName) string {
19+
switch variable {
20+
case DevtronNamespace:
21+
return metadata.Namespace
22+
case DevtronClusterName:
23+
return metadata.ClusterName
24+
case DevtronEnvName:
25+
return metadata.EnvironmentName
26+
case DevtronImageTag:
27+
return metadata.ImageTag
28+
}
29+
return ""
730
}
831

932
type Qualifier int
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package resourceQualifiers
2+
3+
type SystemVariableName string
4+
5+
const (
6+
DevtronNamespace SystemVariableName = "DEVTRON_NAMESPACE"
7+
DevtronClusterName SystemVariableName = "DEVTRON_CLUSTER_NAME"
8+
DevtronEnvName SystemVariableName = "DEVTRON_ENV_NAME"
9+
DevtronImageTag SystemVariableName = "DEVTRON_IMAGE_TAG"
10+
)
11+
12+
var SystemVariables = []SystemVariableName{DevtronNamespace, DevtronClusterName, DevtronEnvName, DevtronImageTag}

pkg/variables/ScopedVariableService.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func NewScopedVariableServiceImpl(logger *zap.SugaredLogger, scopedVariableRepos
5353
type VariableConfig struct {
5454
VariableNameRegex string `env:"SCOPED_VARIABLE_NAME_REGEX" envDefault:"^[a-zA-Z][a-zA-Z0-9_-]{0,62}[a-zA-Z0-9]$"`
5555
VariableCacheEnabled bool `env:"VARIABLE_CACHE_ENABLED" envDefault:"true"`
56+
SystemVariablePrefix string `env:"SYSTEM_VAR_PREFIX" envDefault:"DEVTRON_"`
5657
}
5758

5859
func loadVariableCache(cfg *VariableConfig, service *ScopedVariableServiceImpl) {
@@ -318,12 +319,18 @@ func (impl *ScopedVariableServiceImpl) selectScopeForCompoundQualifier(scopes []
318319

319320
func (impl *ScopedVariableServiceImpl) GetScopedVariables(scope resourceQualifiers.Scope, varNames []string, maskSensitiveData bool) (scopedVariableDataObj []*models.ScopedVariableData, err error) {
320321

322+
//populating system variables from system metadata
323+
if scope.SystemMetadata != nil {
324+
systemVariableData := impl.getSystemVariablesData(scope.SystemMetadata, varNames)
325+
scopedVariableDataObj = append(scopedVariableDataObj, systemVariableData...)
326+
}
327+
321328
// getting all variables from cache
322329
allVariableDefinitions := impl.VariableCache.GetData()
323330

324331
// cache is loaded and no active variables exist. Returns empty
325332
if allVariableDefinitions != nil && len(allVariableDefinitions) == 0 {
326-
return nil, nil
333+
return scopedVariableDataObj, nil
327334
}
328335

329336
// Need to get from repo for isSensitive even if cache is loaded since cache only contains metadata
@@ -332,7 +339,7 @@ func (impl *ScopedVariableServiceImpl) GetScopedVariables(scope resourceQualifie
332339

333340
//Cache was not loaded and no active variables found
334341
if len(allVariableDefinitions) == 0 {
335-
return nil, nil
342+
return scopedVariableDataObj, nil
336343
}
337344
}
338345

@@ -354,7 +361,7 @@ func (impl *ScopedVariableServiceImpl) GetScopedVariables(scope resourceQualifie
354361

355362
// This to prevent corner case where no variables were found for the provided names
356363
if len(varNames) > 0 && len(variableIds) == 0 {
357-
return make([]*models.ScopedVariableData, 0), nil
364+
return scopedVariableDataObj, nil
358365
}
359366

360367
varScope, err := impl.qualifierMappingService.GetQualifierMappings(resourceQualifiers.Variable, &scope, variableIds)
@@ -424,6 +431,20 @@ func (impl *ScopedVariableServiceImpl) GetScopedVariables(scope resourceQualifie
424431
}
425432

426433
return scopedVariableDataObj, err
434+
435+
}
436+
437+
func (impl *ScopedVariableServiceImpl) getSystemVariablesData(metadata *resourceQualifiers.SystemMetadata, varNames []string) []*models.ScopedVariableData {
438+
systemVariables := make([]*models.ScopedVariableData, 0)
439+
for _, variable := range resourceQualifiers.SystemVariables {
440+
if len(metadata.GetDataFromSystemVariable(variable)) > 0 && slices.Contains(varNames, string(variable)) {
441+
systemVariables = append(systemVariables, &models.ScopedVariableData{
442+
VariableName: string(variable),
443+
VariableValue: &models.VariableValue{Value: metadata.GetDataFromSystemVariable(variable)},
444+
})
445+
}
446+
}
447+
return systemVariables
427448
}
428449

429450
func (impl *ScopedVariableServiceImpl) GetJsonForVariables() (*models.Payload, error) {

pkg/variables/ScopedVariableValidator.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/devtron-labs/devtron/pkg/variables/utils"
88
"golang.org/x/exp/slices"
99
"regexp"
10+
"strings"
1011
)
1112

1213
func (impl *ScopedVariableServiceImpl) isValidPayload(payload models.Payload) (error, bool) {
@@ -15,6 +16,11 @@ func (impl *ScopedVariableServiceImpl) isValidPayload(payload models.Payload) (e
1516
if slices.Contains(variableNamesList, variable.Definition.VarName) {
1617
return models.ValidationError{Err: fmt.Errorf("duplicate variable name %s", variable.Definition.VarName)}, false
1718
}
19+
20+
if strings.HasPrefix(variable.Definition.VarName, impl.VariableNameConfig.SystemVariablePrefix) {
21+
return models.ValidationError{Err: fmt.Errorf("%s is not allowed (Prefix %s is reserved for system variables)", variable.Definition.VarName, impl.VariableNameConfig.SystemVariablePrefix)}, false
22+
}
23+
1824
regex := impl.VariableNameConfig.VariableNameRegex
1925

2026
regexExpression := regexp.MustCompile(regex)

0 commit comments

Comments
 (0)