diff --git a/api/infraConfig/restHandler.go b/api/infraConfig/restHandler.go index d731297a33..bbcb3c48eb 100644 --- a/api/infraConfig/restHandler.go +++ b/api/infraConfig/restHandler.go @@ -98,7 +98,6 @@ func (handler *InfraConfigRestHandlerImpl) GetProfile(w http.ResponseWriter, r * Profile: *profile, } resp.ConfigurationUnits = handler.infraProfileService.GetConfigurationUnits() - //TODO: why below line ?? resp.DefaultConfigurations = defaultProfile.Configurations common.WriteJsonResp(w, nil, resp, http.StatusOK) } diff --git a/pkg/infraConfig/adapter/adapter.go b/pkg/infraConfig/adapter/adapter.go index e12c5cf84b..8faee3338a 100644 --- a/pkg/infraConfig/adapter/adapter.go +++ b/pkg/infraConfig/adapter/adapter.go @@ -15,7 +15,7 @@ import ( func ConvertToPlatformMap(infraProfileConfigurationEntities []*repository.InfraProfileConfigurationEntity, profileName string) (map[string][]*bean.ConfigurationBean, error) { // Validate input parameters - if infraProfileConfigurationEntities == nil { + if len(infraProfileConfigurationEntities) == 0 { return nil, fmt.Errorf("input infraProfileConfigurationEntities is empty") } if profileName == "" { @@ -23,11 +23,15 @@ func ConvertToPlatformMap(infraProfileConfigurationEntities []*repository.InfraP } platformMap := make(map[string][]*bean.ConfigurationBean) for _, infraProfileConfiguration := range infraProfileConfigurationEntities { - configurationBean, err := getConfigurationBean(infraProfileConfiguration, profileName) + if infraProfileConfiguration == nil { + return nil, fmt.Errorf("infraProfileConfiguration for profile %s is nil", profileName) + } + + configurationBean, err := GetConfigurationBean(infraProfileConfiguration, profileName) if err != nil { return nil, fmt.Errorf("failed to get configuration bean for profile from infraConfiguration '%s': %w", profileName, err) } - platform := infraProfileConfiguration.Platform + platform := infraProfileConfiguration.ProfilePlatformMapping.Platform if len(platform) == 0 { platform = bean.RUNNER_PLATFORM } @@ -72,25 +76,25 @@ func convertValueStringToInterface(configKey bean.ConfigKeyStr, valueString stri } } -func getConfigurationBean(infraProfileConfiguration *repository.InfraProfileConfigurationEntity, profileName string) (*bean.ConfigurationBean, error) { +func GetConfigurationBean(infraProfileConfiguration *repository.InfraProfileConfigurationEntity, profileName string) (*bean.ConfigurationBean, error) { valueString := infraProfileConfiguration.ValueString //handle old values if len(valueString) == 0 && infraProfileConfiguration.Unit > 0 { valueString = strconv.FormatFloat(infraProfileConfiguration.Value, 'f', -1, 64) } - valueInterface, err := convertValueStringToInterface(util.GetConfigKeyStr(infraProfileConfiguration.Key), valueString) + valueInterface, err := convertValueStringToInterface(utils.GetConfigKeyStr(infraProfileConfiguration.Key), valueString) if err != nil { return &bean.ConfigurationBean{}, err } return &bean.ConfigurationBean{ ConfigurationBeanAbstract: bean.ConfigurationBeanAbstract{ - Id: infraProfileConfiguration.Id, - Key: util.GetConfigKeyStr(infraProfileConfiguration.Key), - - Unit: util.GetUnitSuffixStr(infraProfileConfiguration.Key, infraProfileConfiguration.Unit), - ProfileId: infraProfileConfiguration.ProfileId, - Active: infraProfileConfiguration.Active, - ProfileName: profileName, + Id: infraProfileConfiguration.Id, + Key: utils.GetConfigKeyStr(infraProfileConfiguration.Key), + Unit: utils.GetUnitSuffixStr(infraProfileConfiguration.Key, infraProfileConfiguration.Unit), + Active: infraProfileConfiguration.Active, + ProfileId: infraProfileConfiguration.ProfilePlatformMapping.ProfileId, + ProfileName: profileName, + ProfilePlatformMappingId: infraProfileConfiguration.ProfilePlatformMapping.Id, }, Value: valueInterface, }, nil @@ -100,14 +104,19 @@ func getInfraProfileEntity(configurationBean *bean.ConfigurationBean, profileBea infraProfile := &repository.InfraProfileConfigurationEntity{ Id: configurationBean.Id, - Key: util.GetConfigKey(configurationBean.Key), + Key: utils.GetConfigKey(configurationBean.Key), ValueString: FormatTypedValueAsString(configurationBean.Key, configurationBean.Value), - Unit: util.GetUnitSuffix(configurationBean.Key, configurationBean.Unit), - ProfileId: profileBean.Id, - Platform: platform, + Unit: utils.GetUnitSuffix(configurationBean.Key, configurationBean.Unit), Active: configurationBean.Active, - AuditLog: sql.NewDefaultAuditLog(userId), + UniqueId: repository.GetUniqueId(profileBean.Id, platform), + ProfileId: profileBean.Id, // maintained for backward compatibility + ProfilePlatformMapping: &repository.ProfilePlatformMapping{ + ProfileId: profileBean.Id, + Platform: platform, + }, + AuditLog: sql.NewDefaultAuditLog(userId), } + setProfilePlatformMappingId(profileBean, infraProfile) if profileBean.Name == bean.GLOBAL_PROFILE_NAME { infraProfile.Active = true } @@ -166,18 +175,19 @@ func GetV0ProfileBean(profileBean *bean.ProfileBeanDto) *bean.ProfileBeanV0 { ciRunnerConfig := profileBean.Configurations[bean.RUNNER_PLATFORM] return &bean.ProfileBeanV0{ ProfileBeanAbstract: bean.ProfileBeanAbstract{ - Id: profileBean.Id, - Name: profileName, - Description: profileBean.Description, - Active: profileBean.Active, - Type: profileType, - AppCount: profileBean.AppCount, - CreatedBy: profileBean.CreatedBy, - CreatedOn: profileBean.CreatedOn, - UpdatedBy: profileBean.UpdatedBy, - UpdatedOn: profileBean.UpdatedOn, + Id: profileBean.Id, + Name: profileName, + Description: profileBean.Description, + BuildxDriverType: profileBean.BuildxDriverType, + Active: profileBean.Active, + Type: profileType, + AppCount: profileBean.AppCount, + CreatedBy: profileBean.CreatedBy, + CreatedOn: profileBean.CreatedOn, + UpdatedBy: profileBean.UpdatedBy, + UpdatedOn: profileBean.UpdatedOn, }, - Configurations: GetV0ConfigurationBeans(ciRunnerConfig, profileName), + Configurations: GetV0ConfigurationBeans(ciRunnerConfig), } } @@ -191,21 +201,22 @@ func GetV1ProfileBean(profileBean *bean.ProfileBeanV0) *bean.ProfileBeanDto { profileName = bean.GLOBAL_PROFILE_NAME } profileType := profileBean.Type - if profileType == bean.GLOBAL { - profileType = bean.DEFAULT + if profileType == bean.DEFAULT { + profileType = bean.GLOBAL } return &bean.ProfileBeanDto{ ProfileBeanAbstract: bean.ProfileBeanAbstract{ - Id: profileBean.Id, - Name: profileName, - Description: profileBean.Description, - Active: profileBean.Active, - Type: profileType, - AppCount: profileBean.AppCount, - CreatedBy: profileBean.CreatedBy, - CreatedOn: profileBean.CreatedOn, - UpdatedBy: profileBean.UpdatedBy, - UpdatedOn: profileBean.UpdatedOn, + Id: profileBean.Id, + Name: profileName, + Description: profileBean.Description, + Active: profileBean.Active, + Type: profileType, + AppCount: profileBean.AppCount, + CreatedBy: profileBean.CreatedBy, + CreatedOn: profileBean.CreatedOn, + UpdatedBy: profileBean.UpdatedBy, + UpdatedOn: profileBean.UpdatedOn, + BuildxDriverType: profileBean.BuildxDriverType, }, Configurations: map[string][]*bean.ConfigurationBean{bean.RUNNER_PLATFORM: GetV1ConfigurationBeans(profileBean.Configurations, profileName)}, } @@ -225,9 +236,9 @@ func GetV1ConfigurationBeans(configBeans []bean.ConfigurationBeanV0, profileName Id: configBean.Id, Key: configBean.Key, Unit: configBean.Unit, - ProfileName: profileName, - ProfileId: configBean.ProfileId, Active: configBean.Active, + ProfileId: configBean.ProfileId, + ProfileName: profileName, }, Value: valueString, } @@ -236,24 +247,34 @@ func GetV1ConfigurationBeans(configBeans []bean.ConfigurationBeanV0, profileName return resp } -func GetV0ConfigurationBeans(configBeans []*bean.ConfigurationBean, profileName string) []bean.ConfigurationBeanV0 { +func GetV0ConfigurationBeans(configBeans []*bean.ConfigurationBean) []bean.ConfigurationBeanV0 { if len(configBeans) == 0 { return []bean.ConfigurationBeanV0{} } resp := make([]bean.ConfigurationBeanV0, 0) for _, configBean := range configBeans { - valueFloat, _ := configBean.Value.(float64) - //valueFloat, _ := strconv.ParseFloat(configBean.Value, 64) + // Use the GetTypedValue function to decode the value + typedValue, _ := utils.GetTypedValue(configBean.Key, configBean.Value) + // Cast the returned value to float64 for supported keys + valueFloat, ok := typedValue.(float64) + if !ok { + //here skipping the value for the NodeSelectors and TolerationsKey + continue + } + profileName := configBean.ProfileName + if profileName == bean.GLOBAL_PROFILE_NAME { + profileName = bean.DEFAULT_PROFILE_NAME + } beanv0 := bean.ConfigurationBeanV0{ ConfigurationBeanAbstract: bean.ConfigurationBeanAbstract{ Id: configBean.Id, Key: configBean.Key, Unit: configBean.Unit, - ProfileName: profileName, - ProfileId: configBean.ProfileId, Active: configBean.Active, + ProfileId: configBean.ProfileId, + ProfileName: profileName, }, Value: valueFloat, } @@ -269,24 +290,26 @@ func ConvertToProfileBean(infraProfile *repository.InfraProfileEntity) bean.Prof } return bean.ProfileBeanDto{ ProfileBeanAbstract: bean.ProfileBeanAbstract{ - Id: infraProfile.Id, - Name: infraProfile.Name, - Type: profileType, - Description: infraProfile.Description, - Active: infraProfile.Active, - CreatedBy: infraProfile.CreatedBy, - CreatedOn: infraProfile.CreatedOn, - UpdatedBy: infraProfile.UpdatedBy, - UpdatedOn: infraProfile.UpdatedOn, + Id: infraProfile.Id, + Name: infraProfile.Name, + Type: profileType, + Description: infraProfile.Description, + BuildxDriverType: infraProfile.BuildxDriverType, + Active: infraProfile.Active, + CreatedBy: infraProfile.CreatedBy, + CreatedOn: infraProfile.CreatedOn, + UpdatedBy: infraProfile.UpdatedBy, + UpdatedOn: infraProfile.UpdatedOn, }, } } func ConvertToInfraProfileEntity(profileBean *bean.ProfileBeanDto) *repository.InfraProfileEntity { return &repository.InfraProfileEntity{ - Id: profileBean.Id, - Name: profileBean.Name, - Description: profileBean.Description, + Id: profileBean.Id, + Name: profileBean.Name, + Description: profileBean.Description, + BuildxDriverType: profileBean.BuildxDriverType, } } @@ -299,42 +322,25 @@ func LoadCiLimitCpu(infraConfig *bean.InfraConfig) (*repository.InfraProfileConf Key: bean.CPULimitKey, ValueString: strconv.FormatFloat(val, 'f', -1, 64), Unit: units.CPUUnitStr(suffix).GetCPUUnit(), - Platform: bean.RUNNER_PLATFORM, + ProfilePlatformMapping: &repository.ProfilePlatformMapping{ + Platform: bean.RUNNER_PLATFORM, + }, }, nil } -func LoadInfraConfigInEntities(infraConfig *bean.InfraConfig) ([]*repository.InfraProfileConfigurationEntity, error) { - cpuLimit, err := LoadCiLimitCpu(infraConfig) - if err != nil { - return nil, err - } - memLimit, err := LoadCiLimitMem(infraConfig) - if err != nil { - return nil, err - } - cpuReq, err := LoadCiReqCpu(infraConfig) - if err != nil { - return nil, err - } - memReq, err := LoadCiReqMem(infraConfig) - if err != nil { - return nil, err - } - timeout, err := LoadDefaultTimeout(infraConfig) +func LoadCiLimitMem(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { + val, suffix, err := units.ParseValAndUnit(infraConfig.CiLimitMem) if err != nil { return nil, err } - defaultConfigurations := []*repository.InfraProfileConfigurationEntity{cpuLimit, memLimit, cpuReq, memReq, timeout} - return defaultConfigurations, nil -} - -func LoadDefaultTimeout(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { return &repository.InfraProfileConfigurationEntity{ - Key: bean.TimeOutKey, - ValueString: strconv.FormatInt(infraConfig.CiDefaultTimeout, 10), - Unit: units.SecondStr.GetTimeUnit(), - Platform: bean.RUNNER_PLATFORM, + Key: bean.MemoryLimitKey, + ValueString: strconv.FormatFloat(val, 'f', -1, 64), + Unit: units.MemoryUnitStr(suffix).GetMemoryUnit(), + ProfilePlatformMapping: &repository.ProfilePlatformMapping{ + Platform: bean.RUNNER_PLATFORM, + }, }, nil } @@ -347,7 +353,9 @@ func LoadCiReqCpu(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfig Key: bean.CPURequestKey, ValueString: strconv.FormatFloat(val, 'f', -1, 64), Unit: units.CPUUnitStr(suffix).GetCPUUnit(), - Platform: bean.RUNNER_PLATFORM, + ProfilePlatformMapping: &repository.ProfilePlatformMapping{ + Platform: bean.RUNNER_PLATFORM, + }, }, nil } @@ -361,20 +369,53 @@ func LoadCiReqMem(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfig Key: bean.MemoryRequestKey, ValueString: strconv.FormatFloat(val, 'f', -1, 64), Unit: units.MemoryUnitStr(suffix).GetMemoryUnit(), - Platform: bean.RUNNER_PLATFORM, + ProfilePlatformMapping: &repository.ProfilePlatformMapping{ + Platform: bean.RUNNER_PLATFORM, + }, }, nil } -func LoadCiLimitMem(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { - val, suffix, err := units.ParseValAndUnit(infraConfig.CiLimitMem) +func LoadDefaultTimeout(infraConfig *bean.InfraConfig) (*repository.InfraProfileConfigurationEntity, error) { + return &repository.InfraProfileConfigurationEntity{ + Key: bean.TimeOutKey, + ValueString: strconv.FormatInt(infraConfig.CiDefaultTimeout, 10), + Unit: units.SecondStr.GetTimeUnit(), + ProfilePlatformMapping: &repository.ProfilePlatformMapping{ + Platform: bean.RUNNER_PLATFORM, + }, + }, nil +} +func LoadInfraConfigInEntities(infraConfig *bean.InfraConfig, nodeSelectorLabel []string, taintKey, taintValue string) ([]*repository.InfraProfileConfigurationEntity, error) { + cpuLimit, err := LoadCiLimitCpu(infraConfig) if err != nil { return nil, err } - return &repository.InfraProfileConfigurationEntity{ - Key: bean.MemoryLimitKey, - ValueString: strconv.FormatFloat(val, 'f', -1, 64), - Unit: units.MemoryUnitStr(suffix).GetMemoryUnit(), - Platform: bean.RUNNER_PLATFORM, - }, nil + memLimit, err := LoadCiLimitMem(infraConfig) + if err != nil { + return nil, err + } + cpuReq, err := LoadCiReqCpu(infraConfig) + if err != nil { + return nil, err + } + memReq, err := LoadCiReqMem(infraConfig) + if err != nil { + return nil, err + } + timeout, err := LoadDefaultTimeout(infraConfig) + if err != nil { + return nil, err + } + defaultConfigurations := []*repository.InfraProfileConfigurationEntity{cpuLimit, memLimit, cpuReq, memReq, timeout} + return defaultConfigurations, nil +} +func setProfilePlatformMappingId(defaultProfile *bean.ProfileBeanDto, infraConfiguration *repository.InfraProfileConfigurationEntity) { + runnerPlatformConfig := defaultProfile.Configurations[bean.RUNNER_PLATFORM] + for _, runnerConfig := range runnerPlatformConfig { + if runnerConfig.Key == utils.GetConfigKeyStr(infraConfiguration.Key) { + //setting hte ppm id and Profile Id + infraConfiguration.ProfilePlatformMappingId = runnerConfig.ProfilePlatformMappingId + } + } } diff --git a/pkg/infraConfig/bean/bean.go b/pkg/infraConfig/bean/bean.go index e65d02caae..476b4b3e7f 100644 --- a/pkg/infraConfig/bean/bean.go +++ b/pkg/infraConfig/bean/bean.go @@ -24,18 +24,50 @@ import ( // service layer structs type ProfileBeanAbstract struct { - Id int `json:"id"` - Name string `json:"name" validate:"required,min=1,max=50"` - Description string `json:"description" validate:"max=300"` - Active bool `json:"active"` - Type ProfileType `json:"type"` - AppCount int `json:"appCount"` - CreatedBy int32 `json:"createdBy"` - CreatedOn time.Time `json:"createdOn"` - UpdatedBy int32 `json:"updatedBy"` - UpdatedOn time.Time `json:"updatedOn"` + Id int `json:"id"` + Name string `json:"name" validate:"required,min=1,max=50"` + Description string `json:"description" validate:"max=350"` + BuildxDriverType BuildxDriver `json:"buildxDriverType" default:"kubernetes"` + Active bool `json:"active"` + Type ProfileType `json:"type"` + AppCount int `json:"appCount"` + CreatedBy int32 `json:"createdBy"` + CreatedOn time.Time `json:"createdOn"` + UpdatedBy int32 `json:"updatedBy"` + UpdatedOn time.Time `json:"updatedOn"` } +type BuildxDriver string + +func (b BuildxDriver) String() string { + return string(b) +} + +func (b BuildxDriver) IsKubernetes() bool { + return b == BuildxK8sDriver +} + +func (b BuildxDriver) IsDockerContainer() bool { + return b == BuildxDockerContainerDriver +} + +func (b BuildxDriver) IsPlatformSupported(platform string) bool { + return platform == RUNNER_PLATFORM +} + +func (b BuildxDriver) IsValid() bool { + return b.IsKubernetes() || b.IsDockerContainer() +} + +const ( + // BuildxK8sDriver is the default driver for buildx + BuildxK8sDriver BuildxDriver = "kubernetes" + // BuildxDockerContainerDriver is the driver for docker container + BuildxDockerContainerDriver BuildxDriver = "docker-container" +) + +const BuildxK8sDriverMigrated string = "build-infra-migrated" + type ProfileBeanDto struct { ProfileBeanAbstract Configurations map[string][]*ConfigurationBean `json:"configurations"` @@ -85,12 +117,13 @@ type Scope struct { } type ConfigurationBeanAbstract struct { - Id int `json:"id"` - Key ConfigKeyStr `json:"key"` - Unit string `json:"unit" validate:"required,gt=0"` - ProfileName string `json:"profileName"` - ProfileId int `json:"profileId"` - Active bool `json:"active"` + Id int `json:"id"` + Key ConfigKeyStr `json:"key"` + Unit string `json:"unit"` + ProfilePlatformMappingId int `json:"profilePlatformMappingId"` + Active bool `json:"active"` + ProfileName string `json:"profileName"` + ProfileId int `json:"profileId"` } // InfraConfig is used for read only purpose outside this package @@ -142,3 +175,9 @@ func (infraConfig InfraConfig) GetCiDefaultTimeout() int64 { func (infraConfig *InfraConfig) SetCiDefaultTimeout(timeout int64) { infraConfig.CiDefaultTimeout = timeout } + +type ProfileAndConfig struct { + GlobalProfile *ProfileBeanDto `json:"-"` + AppliedProfile *ProfileBeanDto `json:"-"` + Platforms []string `json:"-"` +} diff --git a/pkg/infraConfig/bean/constants.go b/pkg/infraConfig/bean/constants.go index 4f3adf1597..99b5227fa7 100644 --- a/pkg/infraConfig/bean/constants.go +++ b/pkg/infraConfig/bean/constants.go @@ -20,15 +20,17 @@ type ConfigKey int type ConfigKeyStr string type ProfileType string -const GLOBAL ProfileType = "GLOBAL" const NORMAL ProfileType = "NORMAL" const InvalidUnit = "invalid %s unit found in %s " const InvalidTypeValue = "invalid value found in %s with value %s " const GLOBAL_PROFILE_NAME = "global" + +// TODO Asutosh: Backward compatibility for default profile is compromised. revisit this. const DEFAULT_PROFILE_NAME = "default" const DEFAULT_PROFILE_EXISTS = "default profile exists" const NO_PROPERTIES_FOUND = "no properties found" const DEFAULT ProfileType = "DEFAULT" +const GLOBAL ProfileType = "GLOBAL" const InvalidProfileName = "profile name is invalid" const PayloadValidationError = "payload validation failed" const CPULimReqErrorCompErr = "cpu limit should not be less than cpu request" @@ -52,4 +54,7 @@ const TIME_OUT ConfigKeyStr = "timeout" // internal-platforms const RUNNER_PLATFORM = "runner" -const CI_RUNNER_PLATFORM = "ci-runner" +const QualifiedProfileMaxLength = 253 +const QualifiedDescriptionMaxLength = 350 +const QualifiedPlatformMaxLength = 50 +const ConfigurationMissingInGlobalPlatform = "configuration missing in the global Platform" diff --git a/pkg/infraConfig/repository/infraConfigRepository.go b/pkg/infraConfig/repository/infraConfigRepository.go index f42710ef21..1d32d6be1c 100644 --- a/pkg/infraConfig/repository/infraConfigRepository.go +++ b/pkg/infraConfig/repository/infraConfigRepository.go @@ -17,31 +17,22 @@ package repository import ( - "github.com/devtron-labs/devtron/pkg/infraConfig/bean" + "fmt" + infraBean "github.com/devtron-labs/devtron/pkg/infraConfig/bean" "github.com/devtron-labs/devtron/pkg/infraConfig/units" "github.com/devtron-labs/devtron/pkg/sql" "github.com/go-pg/pg" "github.com/pkg/errors" + "time" ) type InfraProfileEntity struct { - tableName struct{} `sql:"infra_profile" pg:",discard_unknown_columns"` - Id int `sql:"id"` - Name string `sql:"name"` - Description string `sql:"description"` - Active bool `sql:"active"` - sql.AuditLog -} -type InfraProfileConfigurationEntity struct { - tableName struct{} `sql:"infra_profile_configuration" pg:",discard_unknown_columns"` - Id int `sql:"id"` - Key bean.ConfigKey `sql:"key"` - Value float64 `sql:"value"` - ValueString string `sql:"value_string"` - Unit units.UnitSuffix `sql:"unit"` - ProfileId int `sql:"profile_id"` - Platform string `sql:"platform"` - Active bool `sql:"active"` + tableName struct{} `sql:"infra_profile" pg:",discard_unknown_columns"` + Id int `sql:"id"` + Name string `sql:"name"` + Description string `sql:"description"` + BuildxDriverType infraBean.BuildxDriver `sql:"buildx_driver_type,notnull"` + Active bool `sql:"active"` sql.AuditLog } @@ -51,15 +42,37 @@ type ProfilePlatformMapping struct { ProfileId int `sql:"profile_id"` Platform string `sql:"platform"` Active bool `sql:"active"` + UniqueId string `sql:"-"` + sql.AuditLog +} + +func GetUniqueId(profileId int, platform string) string { + return fmt.Sprintf("%d-%s", profileId, platform) +} + +type InfraProfileConfigurationEntity struct { + tableName struct{} `sql:"infra_profile_configuration" pg:",discard_unknown_columns"` + Id int `sql:"id,pk"` + Key infraBean.ConfigKey `sql:"key,notnull"` + Value float64 `sql:"value"` + ValueString string `sql:"value_string,notnull"` + Unit units.UnitSuffix `sql:"unit,notnull"` + ProfilePlatformMappingId int `sql:"profile_platform_mapping_id"` + Active bool `sql:"active,notnull"` + UniqueId string `sql:"-"` + // Deprecated; use ProfilePlatformMappingId + ProfileId int `sql:"profile_id"` + + ProfilePlatformMapping *ProfilePlatformMapping sql.AuditLog } type InfraConfigRepository interface { GetProfileByName(name string) (*InfraProfileEntity, error) GetConfigurationsByProfileName(profileName string) ([]*InfraProfileConfigurationEntity, error) - GetConfigurationsByProfileId(profileId int) ([]*InfraProfileConfigurationEntity, error) + GetConfigurationsByProfileIds(profileIds []int) ([]*InfraProfileConfigurationEntity, error) + GetPlatformsByProfileName(profileName string) ([]*ProfilePlatformMapping, error) - GetPlatformListByProfileName(profileName string) ([]string, error) CreatePlatformProfileMapping(tx *pg.Tx, platformMapping []*ProfilePlatformMapping) error CreateProfile(tx *pg.Tx, infraProfile *InfraProfileEntity) error @@ -99,68 +112,83 @@ func (impl *InfraConfigRepositoryImpl) GetProfileByName(name string) (*InfraProf } func (impl *InfraConfigRepositoryImpl) CreateConfigurations(tx *pg.Tx, configurations []*InfraProfileConfigurationEntity) error { + if len(configurations) == 0 { + return nil + } err := tx.Insert(&configurations) return err } func (impl *InfraConfigRepositoryImpl) UpdateConfigurations(tx *pg.Tx, configurations []*InfraProfileConfigurationEntity) error { - var err error - for _, configuration := range configurations { - _, err = tx.Model(configuration). - Set("value_string = ?", configuration.ValueString). - Set("unit = ?", configuration.Unit). - Set("updated_by = ?", configuration.UpdatedBy). - Set("updated_on = ?", configuration.UpdatedOn). - Where("id = ?", configuration.Id). - Update() - } + _, err := tx.Model(&configurations). + Column("value_string", "profile_platform_mapping_id", "unit", "active", "updated_by", "updated_on"). + Update() return err } func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileName(profileName string) ([]*InfraProfileConfigurationEntity, error) { var configurations []*InfraProfileConfigurationEntity err := impl.dbConnection.Model(&configurations). - Where("profile_id IN (SELECT id FROM infra_profile WHERE name = ? AND active = true)", profileName). - Where("active = ?", true). + Column("infra_profile_configuration_entity.*", "ProfilePlatformMapping"). + Join("INNER JOIN infra_profile"). + JoinOn("infra_profile_configuration_entity.profile_id = infra_profile.id"). + Where("infra_profile.name = ?", profileName). + Where("infra_profile.active = ?", true). + Where("infra_profile_configuration_entity.active = ?", true). Select() if errors.Is(err, pg.ErrNoRows) { - return nil, errors.New(bean.NO_PROPERTIES_FOUND) + return nil, errors.New(infraBean.NO_PROPERTIES_FOUND) } return configurations, err } -func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileId(profileId int) ([]*InfraProfileConfigurationEntity, error) { +func (impl *InfraConfigRepositoryImpl) GetConfigurationsByProfileIds(profileIds []int) ([]*InfraProfileConfigurationEntity, error) { var configurations []*InfraProfileConfigurationEntity err := impl.dbConnection.Model(&configurations). - Where("profile_id = ?", profileId). - Where("active = ?", true). + Column("infra_profile_configuration_entity.*", "ProfilePlatformMapping"). + Where("profile_platform_mapping.profile_id IN (?)", pg.In(profileIds)). + Where("profile_platform_mapping.active = ?", true). + Where("infra_profile_configuration_entity.active = ?", true). Select() if errors.Is(err, pg.ErrNoRows) { - return nil, errors.New(bean.NO_PROPERTIES_FOUND) + return nil, errors.New(infraBean.NO_PROPERTIES_FOUND) } return configurations, err } func (impl *InfraConfigRepositoryImpl) UpdateProfile(tx *pg.Tx, profileName string, profile *InfraProfileEntity) error { _, err := tx.Model(profile). - Set("description=?", profile.Description). - Set("updated_by=?", profile.UpdatedBy). - Set("updated_on=?", profile.UpdatedOn). + Set("name = ?", profile.Name). + Set("description = ?", profile.Description). + Set("buildx_driver_type = ?", profile.BuildxDriverType). + Set("updated_by = ?", profile.UpdatedBy). + Set("updated_on = ?", profile.UpdatedOn). Where("name = ?", profileName). Where("active = ?", true). Update() return err } -func (impl *InfraConfigRepositoryImpl) GetPlatformListByProfileName(profileName string) ([]string, error) { - var platforms []string - err := impl.dbConnection.Model(&ProfilePlatformMapping{}). - ColumnExpr("platform"). + +func (impl *InfraConfigRepositoryImpl) UpdateBuildxDriverTypeInAllProfiles(tx *pg.Tx, buildxDriverType infraBean.BuildxDriver) error { + _, err := tx.Model((*InfraProfileEntity)(nil)). + Set("buildx_driver_type = ?", buildxDriverType). + Set("updated_by = ?", 1). + Set("updated_on = ?", time.Now()). + Where("active = ?", true). + Update() + return err +} + +func (impl *InfraConfigRepositoryImpl) GetPlatformsByProfileName(profileName string) ([]*ProfilePlatformMapping, error) { + var profilePlatformMappings []*ProfilePlatformMapping + err := impl.dbConnection.Model(&profilePlatformMappings). + Column("profile_platform_mapping.*"). Join("INNER JOIN infra_profile ip ON profile_platform_mapping.profile_id = ip.id"). Where("ip.name = ?", profileName). Where("ip.active = ?", true). Where("profile_platform_mapping.active = ?", true). - Select(&platforms) - return platforms, err + Select() + return profilePlatformMappings, err } func (impl *InfraConfigRepositoryImpl) CreatePlatformProfileMapping(tx *pg.Tx, platformMapping []*ProfilePlatformMapping) error { err := tx.Insert(&platformMapping) diff --git a/pkg/infraConfig/service/configurationValidator.go b/pkg/infraConfig/service/configurationValidator.go index 15608cb016..2f088e28f3 100644 --- a/pkg/infraConfig/service/configurationValidator.go +++ b/pkg/infraConfig/service/configurationValidator.go @@ -9,7 +9,39 @@ import ( ) func (impl *InfraConfigServiceImpl) validateInfraConfig(profileBean *bean.ProfileBeanDto, defaultProfile *bean.ProfileBeanDto) error { + err := utils.ValidatePayloadConfig(profileBean) + if err != nil { + return err + } + if profileBean.Name == bean.GLOBAL_PROFILE_NAME || profileBean.Name == bean.DEFAULT_PROFILE_NAME { + for platform, configurations := range profileBean.Configurations { + // Create a copy of the defaultConfigKeysMap to track missing keys + missingKeysMap := utils.GetDefaultConfigKeysMap() + // Mark the keys that are present + for _, config := range configurations { + if _, exists := missingKeysMap[config.Key]; exists && config.Active { + missingKeysMap[config.Key] = false + } + } + // Check if any default keys are still true (missing) + var missingKeys []bean.ConfigKeyStr + for key, isMissing := range missingKeysMap { + if isMissing && platform != bean.RUNNER_PLATFORM && key != bean.TIME_OUT { + missingKeys = append(missingKeys, key) + } + if isMissing && platform == bean.RUNNER_PLATFORM { + missingKeys = append(missingKeys, key) + } + } + + if len(missingKeys) > 0 { + impl.logger.Errorw("Missing default configuration keys for platform", "platform", platform, "missingKeys", missingKeys, "profileName", profileBean.Name) + err = errors.New(bean.ConfigurationMissingInGlobalPlatform) + return err + } + } + } // currently validating cpu and memory limits and reqs only var ( cpuLimit *bean.ConfigurationBean @@ -38,7 +70,7 @@ func (impl *InfraConfigServiceImpl) validateInfraConfig(profileBean *bean.Profil } // validate cpu - err := impl.validateCPU(cpuLimit, cpuReq) + err = impl.validateCPU(cpuLimit, cpuReq) if err != nil { return err } @@ -67,7 +99,7 @@ func (impl *InfraConfigServiceImpl) validateCPU(cpuLimit, cpuReq *bean.Configura return errors.New(fmt.Sprintf(bean.InvalidUnit, cpuReq.Unit, cpuReq.Key)) } - cpuLimitInterfaceVal, err := util.GetTypedValue(cpuLimit.Key, cpuLimit.Value) + cpuLimitInterfaceVal, err := utils.GetTypedValue(cpuLimit.Key, cpuLimit.Value) if err != nil { return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuLimit.Key, cpuLimit.Value)) } @@ -76,7 +108,7 @@ func (impl *InfraConfigServiceImpl) validateCPU(cpuLimit, cpuReq *bean.Configura return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuLimit.Key, cpuLimit.Value)) } - cpuReqInterfaceVal, err := util.GetTypedValue(cpuReq.Key, cpuReq.Value) + cpuReqInterfaceVal, err := utils.GetTypedValue(cpuReq.Key, cpuReq.Value) if err != nil { return errors.New(fmt.Sprintf(bean.InvalidTypeValue, cpuReq.Key, cpuReq.Value)) } @@ -99,7 +131,7 @@ func (impl *InfraConfigServiceImpl) validateTimeOut(timeOut *bean.ConfigurationB if !ok { return errors.New(fmt.Sprintf(bean.InvalidUnit, timeOut.Unit, timeOut.Key)) } - timeout, err := util.GetTypedValue(timeOut.Key, timeOut.Value) + timeout, err := utils.GetTypedValue(timeOut.Key, timeOut.Value) if err != nil { return errors.New(fmt.Sprintf(bean.InvalidTypeValue, timeOut.Key, timeOut.Value)) } @@ -123,7 +155,7 @@ func (impl *InfraConfigServiceImpl) validateMEM(memLimit, memReq *bean.Configura } // Use getTypedValue to retrieve appropriate types - memLimitInterfaceVal, err := util.GetTypedValue(memLimit.Key, memLimit.Value) + memLimitInterfaceVal, err := utils.GetTypedValue(memLimit.Key, memLimit.Value) if err != nil { return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memLimit.Key, memLimit.Value)) } @@ -132,7 +164,7 @@ func (impl *InfraConfigServiceImpl) validateMEM(memLimit, memReq *bean.Configura return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memLimit.Key, memLimit.Value)) } - memReqInterfaceVal, err := util.GetTypedValue(memReq.Key, memReq.Value) + memReqInterfaceVal, err := utils.GetTypedValue(memReq.Key, memReq.Value) if err != nil { return errors.New(fmt.Sprintf(bean.InvalidTypeValue, memReq.Key, memReq.Value)) } diff --git a/pkg/infraConfig/service/infraConfigService.go b/pkg/infraConfig/service/infraConfigService.go index b01d374d51..146de29498 100644 --- a/pkg/infraConfig/service/infraConfigService.go +++ b/pkg/infraConfig/service/infraConfigService.go @@ -81,7 +81,7 @@ func (impl *InfraConfigServiceImpl) GetProfileByName(name string) (*bean.Profile } profileBean := adapter.ConvertToProfileBean(infraProfile) - infraConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileId(infraProfile.Id) + infraConfigurations, err := impl.infraProfileRepo.GetConfigurationsByProfileIds([]int{infraProfile.Id}) if err != nil { impl.logger.Errorw("error in fetching default configurations", "error", err) return nil, err @@ -105,6 +105,12 @@ func (impl *InfraConfigServiceImpl) GetProfileByName(name string) (*bean.Profile func (impl *InfraConfigServiceImpl) UpdateProfile(userId int32, profileName string, profileToUpdate *bean.ProfileBeanDto) error { // validation + + //here we are setting as it will get validate later.. //for maintaining the backward compatibility + if !profileToUpdate.BuildxDriverType.IsValid() && profileToUpdate.BuildxDriverType == "" { + profileToUpdate.BuildxDriverType = bean.BuildxK8sDriver + } + defaultProfile, err := impl.GetProfileByName(profileName) if err != nil { impl.logger.Errorw("error in fetching default profile", "profileName", profileName, "profileCreateRequest", profileToUpdate, "error", err) @@ -116,9 +122,11 @@ func (impl *InfraConfigServiceImpl) UpdateProfile(userId int32, profileName stri } // validations end + profileToUpdate.Id = defaultProfile.Id infraProfileEntity := adapter.ConvertToInfraProfileEntity(profileToUpdate) // user couldn't delete the profile, always set this to active infraProfileEntity.Active = true + //todo make it compatible with ent infraConfigurations := adapter.ConvertFromPlatformMap(profileToUpdate.Configurations, defaultProfile, userId) @@ -141,7 +149,6 @@ func (impl *InfraConfigServiceImpl) UpdateProfile(userId int32, profileName stri impl.logger.Errorw("error in updating profile", "error", "profileName", profileName, "profileCreateRequest", profileToUpdate, err) return err } - err = impl.infraProfileRepo.UpdateConfigurations(tx, infraConfigurations) if err != nil { impl.logger.Errorw("error in creating configurations", "error", "profileName", profileName, "profileCreateRequest", profileToUpdate, err) @@ -149,9 +156,10 @@ func (impl *InfraConfigServiceImpl) UpdateProfile(userId int32, profileName stri } err = impl.infraProfileRepo.CommitTx(tx) if err != nil { - impl.logger.Errorw("error in committing transaction to update profile", "profileName", profileName, "profileCreateRequest", profileToUpdate, "error", err) + impl.logger.Errorw("error in committing transaction to update profile", "profileCreateRequest", profileToUpdate, "error", err) + return err } - return err + return nil } // loadDefaultProfile loads default configurations from environment and save them in db. @@ -194,8 +202,8 @@ func (impl *InfraConfigServiceImpl) loadDefaultProfile() error { } profile = defaultProfile } - - defaultConfigurationsFromEnv, err := adapter.LoadInfraConfigInEntities(impl.infraConfig) + var nodeselector []string + defaultConfigurationsFromEnv, err := adapter.LoadInfraConfigInEntities(impl.infraConfig, nodeselector, "", "") if err != nil { impl.logger.Errorw("error in loading default configurations from environment", "error", err) return err @@ -214,42 +222,58 @@ func (impl *InfraConfigServiceImpl) loadDefaultProfile() error { creatableConfigurations := make([]*repository.InfraProfileConfigurationEntity, 0, len(defaultConfigurationsFromEnv)) creatableProfilePlatformMapping := make([]*repository.ProfilePlatformMapping, 0) - for _, configurationFromEnv := range defaultConfigurationsFromEnv { - if ok, exist := defaultConfigurationsFromDBMap[configurationFromEnv.Key]; !exist || !ok { - configurationFromEnv.ProfileId = profile.Id - configurationFromEnv.Active = true - configurationFromEnv.Platform = bean.RUNNER_PLATFORM - configurationFromEnv.AuditLog = sql.NewDefaultAuditLog(1) - creatableConfigurations = append(creatableConfigurations, configurationFromEnv) - } - } - _, err = impl.infraProfileRepo.GetPlatformListByProfileName(bean.GLOBAL_PROFILE_NAME) + platformsFromDb, err := impl.infraProfileRepo.GetPlatformsByProfileName(bean.GLOBAL_PROFILE_NAME) if err != nil && !errors.Is(err, pg.ErrNoRows) { impl.logger.Errorw("error in fetching platforms from db", "error", err) return err } - //creating default platform if not found in db - if errors.Is(err, pg.ErrNoRows) { - creatableProfilePlatformMapping = append(creatableProfilePlatformMapping, &repository.ProfilePlatformMapping{ + + runnerPlatFormMapping := &repository.ProfilePlatformMapping{} + //one platform is expected + if len(platformsFromDb) > 0 { + for _, platform := range platformsFromDb { + if platform.Platform == bean.RUNNER_PLATFORM { + runnerPlatFormMapping = platform + break + } + } + } else { + runnerPlatFormMapping = &repository.ProfilePlatformMapping{ Platform: bean.RUNNER_PLATFORM, ProfileId: profile.Id, Active: true, - }) + AuditLog: sql.NewDefaultAuditLog(1), + } } - if len(creatableConfigurations) > 0 { - err = impl.infraProfileRepo.CreateConfigurations(tx, creatableConfigurations) + //creating default platform if not found in db + if len(platformsFromDb) == 0 { + creatableProfilePlatformMapping = append(creatableProfilePlatformMapping, runnerPlatFormMapping) + } + if len(creatableProfilePlatformMapping) > 0 { + err = impl.infraProfileRepo.CreatePlatformProfileMapping(tx, creatableProfilePlatformMapping) if err != nil { - impl.logger.Errorw("error in saving default configurations", "configurations", creatableConfigurations, "error", err) + impl.logger.Errorw("error in saving default configurations", "error", err) return err } } - if len(creatableProfilePlatformMapping) > 0 { - err = impl.infraProfileRepo.CreatePlatformProfileMapping(tx, creatableProfilePlatformMapping) + for _, configurationFromEnv := range defaultConfigurationsFromEnv { + if ok, exist := defaultConfigurationsFromDBMap[configurationFromEnv.Key]; !exist || !ok { + configurationFromEnv.ProfileId = profile.Id + configurationFromEnv.Active = true + configurationFromEnv.ProfilePlatformMappingId = runnerPlatFormMapping.Id + configurationFromEnv.ProfilePlatformMapping.Platform = bean.RUNNER_PLATFORM + configurationFromEnv.AuditLog = sql.NewDefaultAuditLog(1) + creatableConfigurations = append(creatableConfigurations, configurationFromEnv) + } + } + + if len(creatableConfigurations) > 0 { + err = impl.infraProfileRepo.CreateConfigurations(tx, creatableConfigurations) if err != nil { - impl.logger.Errorw("error in saving default configurations", "error", err) + impl.logger.Errorw("error in saving default configurations", "configurations", creatableConfigurations, "error", err) return err } } @@ -346,12 +370,8 @@ func (impl *InfraConfigServiceImpl) GetConfigurationUnits() map[bean.ConfigKeySt } func (impl *InfraConfigServiceImpl) validate(profileToUpdate *bean.ProfileBeanDto, defaultProfile *bean.ProfileBeanDto) error { - err := util2.ValidatePayloadConfig(profileToUpdate) - if err != nil { - return err - } - err = impl.validateInfraConfig(profileToUpdate, defaultProfile) + err := impl.validateInfraConfig(profileToUpdate, defaultProfile) if err != nil { err = errors.Wrap(err, bean.PayloadValidationError) return err diff --git a/pkg/infraConfig/util/utils.go b/pkg/infraConfig/util/utils.go index 2e8e4ed9c3..2f02b2bb6c 100644 --- a/pkg/infraConfig/util/utils.go +++ b/pkg/infraConfig/util/utils.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package util +package utils import ( "errors" @@ -98,9 +98,17 @@ func ValidatePayloadConfig(profileToUpdate *bean.ProfileBeanDto) error { if len(profileToUpdate.Name) == 0 { return errors.New("profile name is required") } + err := validateProfileAttributes(profileToUpdate.ProfileBeanAbstract) + if err != nil { + return err + } defaultKeyMap := GetDefaultConfigKeysMap() - for _, config := range profileToUpdate.Configurations { - err := validateConfigItems(config, defaultKeyMap) + for platform, config := range profileToUpdate.Configurations { + err = validatePlatformName(platform, profileToUpdate.BuildxDriverType) + if err != nil { + return err + } + err = validateConfigItems(config, defaultKeyMap) if err != nil { return err } @@ -181,3 +189,32 @@ func IsValidProfileNameRequestedV0(profileName, payloadProfileName string) bool } return false } + +func validatePlatformName(platform string, buildxDriverType bean.BuildxDriver) error { + if len(platform) == 0 { + return errors.New("platform cannot be empty") + } + if len(platform) > bean.QualifiedPlatformMaxLength { + return errors.New("platform cannot be longer than 50 characters") + } + if !buildxDriverType.IsPlatformSupported(platform) { + return fmt.Errorf("invalid platform name: %q. not supported with driver type: %q", platform, buildxDriverType) + } + return nil +} + +func validateProfileAttributes(profileAbstract bean.ProfileBeanAbstract) error { + if len(profileAbstract.Name) > bean.QualifiedProfileMaxLength { + return errors.New("profile name is too long") + } + if len(profileAbstract.Name) == 0 { + return errors.New("profile name is empty") + } + if len(profileAbstract.Description) > bean.QualifiedDescriptionMaxLength { + return errors.New("profile description is too long") + } + if !profileAbstract.BuildxDriverType.IsValid() { + return fmt.Errorf("invalid buildx driver type: %q", profileAbstract.BuildxDriverType) + } + return nil +} diff --git a/pkg/pipeline/types/CiCdConfig.go b/pkg/pipeline/types/CiCdConfig.go index 7f77514977..eda3035e49 100644 --- a/pkg/pipeline/types/CiCdConfig.go +++ b/pkg/pipeline/types/CiCdConfig.go @@ -193,7 +193,9 @@ func GetCiConfig() (*CiConfig, error) { if err != nil { return nil, err } - ciConfig := CiConfig{ciCdConfig} + ciConfig := CiConfig{ + CiCdConfig: ciCdConfig, + } ciConfig.Type = CiConfigType return &ciConfig, nil } diff --git a/scripts/sql/31502601_build_infra_patch.down.sql b/scripts/sql/31502601_build_infra_patch.down.sql new file mode 100644 index 0000000000..4c7007e1d7 --- /dev/null +++ b/scripts/sql/31502601_build_infra_patch.down.sql @@ -0,0 +1,17 @@ +BEGIN; + + + + +ALTER TABLE public.infra_profile + DROP COLUMN IF EXISTS buildx_driver_type; + +ALTER TABLE public.infra_profile_configuration + DROP CONSTRAINT IF EXISTS fk_infra_profile_configuration_profile_platform_mapping_id; + +ALTER TABLE public.infra_profile_configuration + DROP COLUMN IF EXISTS profile_platform_mapping_id; + +DROP INDEX IF EXISTS unique_profile_platform_mapping; + +END; \ No newline at end of file diff --git a/scripts/sql/31502601_build_infra_patch.up.sql b/scripts/sql/31502601_build_infra_patch.up.sql new file mode 100644 index 0000000000..7c1f6986cb --- /dev/null +++ b/scripts/sql/31502601_build_infra_patch.up.sql @@ -0,0 +1,43 @@ +BEGIN; + +UPDATE "public"."infra_profile_configuration" +SET active='f' +WHERE platform = 'runner' + AND value_string= '[]' + AND active='t' + AND profile_id=( + SELECT infra_Profile.id + FROM infra_profile + WHERE name = 'global' + AND active='t' +) +; + +ALTER TABLE public.infra_profile_configuration + ALTER COLUMN platform DROP NOT NULL; + +ALTER TABLE public.infra_profile + ADD COLUMN IF NOT EXISTS buildx_driver_type VARCHAR(50) NOT NULL DEFAULT 'kubernetes'; + +ALTER TABLE public.infra_profile_configuration + ADD COLUMN IF NOT EXISTS profile_platform_mapping_id INTEGER; + +ALTER TABLE public.infra_profile_configuration + DROP CONSTRAINT IF EXISTS fk_infra_profile_configuration_profile_platform_mapping_id; + +ALTER TABLE public.infra_profile_configuration + ADD CONSTRAINT fk_infra_profile_configuration_profile_platform_mapping_id + FOREIGN KEY (profile_platform_mapping_id) REFERENCES profile_platform_mapping(id); + +CREATE UNIQUE INDEX IF NOT EXISTS unique_profile_platform_mapping ON public.profile_platform_mapping + (profile_id, platform) where active=true; + +UPDATE infra_profile_configuration + SET profile_platform_mapping_id = profile_platform_mapping.id + FROM profile_platform_mapping + WHERE infra_profile_configuration.profile_id = profile_platform_mapping.profile_id + AND infra_profile_configuration.platform = profile_platform_mapping.platform + AND profile_platform_mapping.active = 't' + AND infra_profile_configuration.active = 't'; + +END; \ No newline at end of file diff --git a/wire_gen.go b/wire_gen.go index 96a6f100a3..3726c97ffb 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -1,6 +1,6 @@ // Code generated by Wire. DO NOT EDIT. -//go:generate go run github.com/google/wire/cmd/wire +//go:generate go run -mod=mod github.com/google/wire/cmd/wire //go:build !wireinject // +build !wireinject