Skip to content

Commit dc6c135

Browse files
Release Qualifying Jobs Support (part 1) (#711)
* Initial commit rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED * Code review updates rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
1 parent 8aa1813 commit dc6c135

File tree

19 files changed

+2888
-79
lines changed

19 files changed

+2888
-79
lines changed

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ version=v${build_date}-${git_commit}
1414

1515
SOURCE_GIT_TAG=v1.0.0+$(shell git rev-parse --short=7 HEAD)
1616

17+
GOLINT=golangci-lint
18+
1719
GO_LD_EXTRAFLAGS=-X github.com/openshift/release-controller/vendor/k8s.io/client-go/pkg/version.gitCommit=$(shell git rev-parse HEAD) -X github.com/openshift/release-controller/vendor/k8s.io/client-go/pkg/version.gitVersion=${SOURCE_GIT_TAG} -X k8s.io/test-infra/prow/version.Name=release-controller -X k8s.io/test-infra/prow/version.Version=${version}
1820
GO_TEST_FLAGS=
1921
export CGO_ENABLED := 0
@@ -34,6 +36,15 @@ sonar-reports:
3436
golangci-lint run ./... --verbose --no-config --out-format checkstyle --issues-exit-code 0 > golangci-lint.out
3537
.PHONY: sonar-reports
3638

39+
lint:
40+
@echo "Running linter..."
41+
@if command -v $(GOLINT) >/dev/null 2>&1; then \
42+
$(GOLINT) run ./$(BINARY_PATH)/...; \
43+
else \
44+
echo "golangci-lint not installed. Install with: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest"; \
45+
fi
46+
.PHONY: lint
47+
3748
# Legacy targets
3849
image:
3950
imagebuilder -t openshift/release-controller:latest .

cmd/release-controller/config_validate.go

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,22 @@ import (
99
"time"
1010

1111
releasecontroller "github.com/openshift/release-controller/pkg/release-controller"
12-
12+
"github.com/openshift/release-controller/pkg/releasequalifiers"
1313
"gopkg.in/robfig/cron.v2"
14+
"gopkg.in/yaml.v2"
1415
utilerrors "k8s.io/apimachinery/pkg/util/errors"
1516
)
1617

17-
func validateConfigs(configDir string) error {
18+
func validateConfigs(options *options) error {
19+
errors := []error{}
20+
errors = append(errors, validateReleaseConfigs(options.validateConfigs))
21+
if len(options.ReleaseQualifiersConfigPath) > 0 {
22+
errors = append(errors, validateReleaseQualifiersConfig(options.ReleaseQualifiersConfigPath)...)
23+
}
24+
return utilerrors.NewAggregate(errors)
25+
}
26+
27+
func validateReleaseConfigs(configDir string) error {
1828
errors := []error{}
1929
releaseConfigs := []releasecontroller.ReleaseConfig{}
2030
err := filepath.Walk(configDir, func(path string, info os.FileInfo, err error) error {
@@ -37,8 +47,10 @@ func validateConfigs(configDir string) error {
3747
if err != nil {
3848
return fmt.Errorf("error encountered while trying to read config files: %w", err)
3949
}
50+
errors = append(errors, validateUpgradeJobs(releaseConfigs)...)
4051
errors = append(errors, verifyPeriodicFields(releaseConfigs)...)
4152
errors = append(errors, findDuplicatePeriodics(releaseConfigs)...)
53+
errors = append(errors, validateQualifiers(releaseConfigs)...)
4254
return utilerrors.NewAggregate(errors)
4355
}
4456

@@ -105,3 +117,46 @@ func findDuplicatePeriodics(releaseConfigs []releasecontroller.ReleaseConfig) []
105117
}
106118
return duplicates
107119
}
120+
121+
// validateQualifiers validates the contents of releasequalifiers.ReleaseQualifiers defined in releasecontroller.ReleaseConfig
122+
func validateQualifiers(releaseConfigs []releasecontroller.ReleaseConfig) []error {
123+
errors := []error{}
124+
for _, config := range releaseConfigs {
125+
for verificationName, verification := range config.Verify {
126+
for qualifierId, overrides := range verification.Qualifiers {
127+
if err := validateQualifier(qualifierId, overrides); err != nil {
128+
errors = append(errors, fmt.Errorf("unable to validate %q release qualifier %s: %v", verificationName, qualifierId, err))
129+
}
130+
}
131+
}
132+
}
133+
return errors
134+
}
135+
136+
// validateReleaseQualifiersConfig validates the contents of the file located at options.ReleaseQualifiersConfigPath
137+
func validateReleaseQualifiersConfig(configPath string) []error {
138+
errors := []error{}
139+
raw, err := os.ReadFile(configPath)
140+
if err != nil {
141+
return errors
142+
}
143+
config := releasecontroller.ReleaseQualifiersConfig{}
144+
dec := yaml.NewDecoder(bytes.NewReader(raw))
145+
dec.SetStrict(true)
146+
if err = dec.Decode(&config); err != nil {
147+
errors = append(errors, fmt.Errorf("failed to unmarshal release qualifier configuration file %s: %v", configPath, err))
148+
return errors
149+
}
150+
for qualifierId, overrides := range config.Qualifiers {
151+
errors = append(errors, validateQualifier(qualifierId, overrides))
152+
}
153+
return errors
154+
}
155+
156+
func validateQualifier(name releasequalifiers.QualifierId, qualifier releasequalifiers.ReleaseQualifier) error {
157+
err := qualifier.Validate()
158+
if err != nil {
159+
return fmt.Errorf("unable to validate qualifier %s: %v", name, err)
160+
}
161+
return nil
162+
}

cmd/release-controller/config_validate_test.go

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"testing"
55

66
releasecontroller "github.com/openshift/release-controller/pkg/release-controller"
7-
7+
"github.com/openshift/release-controller/pkg/releasequalifiers"
88
utilerrors "k8s.io/apimachinery/pkg/util/errors"
99
)
1010

@@ -356,3 +356,82 @@ func TestValidateUpgradeJobs(t *testing.T) {
356356
}
357357
}
358358
}
359+
360+
func TestValidateQualifiersConfiguration(t *testing.T) {
361+
testCases := []struct {
362+
name string
363+
configs []releasecontroller.ReleaseConfig
364+
expectedErr bool
365+
}{
366+
{
367+
name: "Good config with no qualifiers",
368+
configs: []releasecontroller.ReleaseConfig{{
369+
Name: "4.19.0-0.nightly",
370+
Verify: map[string]releasecontroller.ReleaseVerification{
371+
"osd-aws": {
372+
Optional: true,
373+
MaxRetries: 2,
374+
ProwJob: &releasecontroller.ProwJobVerification{
375+
Name: "periodic-ci-openshift-release-master-nightly-4.19-osd-aws",
376+
},
377+
},
378+
},
379+
},
380+
},
381+
expectedErr: false,
382+
},
383+
{
384+
name: "Good config with empty qualifier",
385+
configs: []releasecontroller.ReleaseConfig{{
386+
Name: "4.19.0-0.nightly",
387+
Verify: map[string]releasecontroller.ReleaseVerification{
388+
"osd-aws": {
389+
Optional: true,
390+
MaxRetries: 2,
391+
ProwJob: &releasecontroller.ProwJobVerification{
392+
Name: "periodic-ci-openshift-release-master-nightly-4.19-osd-aws",
393+
},
394+
Qualifiers: releasequalifiers.ReleaseQualifiers{
395+
"rosa": {},
396+
},
397+
},
398+
},
399+
},
400+
},
401+
expectedErr: false,
402+
},
403+
{
404+
name: "Good config with simple overrides",
405+
configs: []releasecontroller.ReleaseConfig{{
406+
Name: "4.19.0-0.nightly",
407+
Verify: map[string]releasecontroller.ReleaseVerification{
408+
"osd-aws": {
409+
Optional: true,
410+
MaxRetries: 2,
411+
ProwJob: &releasecontroller.ProwJobVerification{
412+
Name: "periodic-ci-openshift-release-master-nightly-4.19-osd-aws",
413+
},
414+
Qualifiers: releasequalifiers.ReleaseQualifiers{
415+
"hcm": {
416+
Enabled: releasequalifiers.BoolPtr(false),
417+
BadgeName: "HCM Updated",
418+
Description: "An updated description when displaying badge details",
419+
PayloadBadge: releasequalifiers.PayloadBadgeNo,
420+
},
421+
},
422+
},
423+
},
424+
}},
425+
expectedErr: false,
426+
},
427+
}
428+
for _, testCase := range testCases {
429+
errs := validateQualifiers(testCase.configs)
430+
if len(errs) > 0 && !testCase.expectedErr {
431+
t.Errorf("%s: got error when error was not expected: %v", testCase.name, errs)
432+
}
433+
if len(errs) == 0 && testCase.expectedErr {
434+
t.Errorf("%s: did not get error when error was expected", testCase.name)
435+
}
436+
}
437+
}

cmd/release-controller/controller.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -184,16 +184,16 @@ func NewController(
184184

185185
c := &Controller{
186186
eventRecorder: recorder,
187-
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "releases"),
188-
gcQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "gc"),
187+
queue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: "releases"}),
188+
gcQueue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: "gc"}),
189189

190190
// rate limit the audit queue severely
191-
auditQueue: workqueue.NewNamedRateLimitingQueue(workqueue.NewMaxOfRateLimiter(
191+
auditQueue: workqueue.NewRateLimitingQueueWithConfig(workqueue.NewMaxOfRateLimiter(
192192
workqueue.NewItemExponentialFailureRateLimiter(5*time.Second, 2*time.Hour),
193193
&workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Every(5), 2)},
194-
), "audit"),
194+
), workqueue.RateLimitingQueueConfig{Name: "audit"}),
195195

196-
jiraQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "jira"),
196+
jiraQueue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: "jira"}),
197197

198198
expectations: newExpectations(),
199199
expectationDelay: 2 * time.Second,
@@ -229,7 +229,7 @@ func NewController(
229229
releasePayloadClient: releasePayloadClient,
230230
releasePayloadLister: &releasecontroller.MultiReleasePayloadLister{Listers: make(map[string]v1alpha1.ReleasePayloadNamespaceLister)},
231231

232-
legacyResultsQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "legacyResults"),
232+
legacyResultsQueue: workqueue.NewRateLimitingQueueWithConfig(workqueue.DefaultControllerRateLimiter(), workqueue.RateLimitingQueueConfig{Name: "legacyResults"}),
233233

234234
manifestListMode: manifestListMode,
235235
}

cmd/release-controller/main.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@ import (
1111
"strings"
1212
"time"
1313

14-
"golang.org/x/text/cases"
15-
"golang.org/x/text/language"
16-
17-
releasepayloadinformers "github.com/openshift/release-controller/pkg/client/informers/externalversions"
18-
1914
releasepayloadclient "github.com/openshift/release-controller/pkg/client/clientset/versioned"
15+
releasepayloadinformers "github.com/openshift/release-controller/pkg/client/informers/externalversions"
2016
"github.com/openshift/release-controller/pkg/jira"
17+
"golang.org/x/text/cases"
18+
"golang.org/x/text/language"
2119

2220
releasecontroller "github.com/openshift/release-controller/pkg/release-controller"
2321

@@ -112,6 +110,8 @@ type options struct {
112110

113111
ProcessLegacyResults bool
114112
ManifestListMode bool
113+
114+
ReleaseQualifiersConfigPath string
115115
}
116116

117117
// Add metrics for jira verifier errors
@@ -221,6 +221,8 @@ func main() {
221221
flagset.BoolVar(&opt.ProcessLegacyResults, "process-legacy-results", opt.ProcessLegacyResults, "enable the migration of imagestream based results to ReleasePayloads")
222222
flagset.BoolVar(&opt.ManifestListMode, "manifest-list-mode", opt.ManifestListMode, "enable manifest list support for oc operations")
223223

224+
flagset.StringVar(&opt.ReleaseQualifiersConfigPath, "release-qualifiers-config-path", "", "Path to release qualifiers config file")
225+
224226
goFlagSet := flag.NewFlagSet("prowflags", flag.ContinueOnError)
225227
opt.github.AddFlags(goFlagSet)
226228
opt.jira.AddFlags(goFlagSet)
@@ -241,7 +243,7 @@ func (o *options) Run() error {
241243
// report liveness on default prow health port 8081
242244
health := pjutil.NewHealthOnPort(flagutil.DefaultHealthPort)
243245
if o.validateConfigs != "" {
244-
return validateConfigs(o.validateConfigs)
246+
return validateConfigs(o)
245247
}
246248
tagParts := strings.Split(o.ToolsImageStreamTag, ":")
247249
if len(tagParts) != 2 || len(tagParts[1]) == 0 {

cmd/release-controller/sync_release_payload.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,36 +69,37 @@ func newReleasePayload(release *releasecontroller.Release, name, jobNamespace, p
6969
sort.Strings(sortedKeys)
7070

7171
for _, verifyName := range sortedKeys {
72-
definition := verificationJobs[verifyName]
73-
if definition.Disabled {
72+
verificationJobDefinition := verificationJobs[verifyName]
73+
if verificationJobDefinition.Disabled {
7474
continue
7575
}
76+
7677
ciConfig := v1alpha1.CIConfiguration{
7778
CIConfigurationName: verifyName,
78-
CIConfigurationJobName: definition.ProwJob.Name,
79-
MaxRetries: definition.MaxRetries,
79+
CIConfigurationJobName: verificationJobDefinition.ProwJob.Name,
80+
MaxRetries: verificationJobDefinition.MaxRetries,
8081
}
8182

8283
switch {
83-
case definition.AggregatedProwJob != nil:
84+
case verificationJobDefinition.AggregatedProwJob != nil:
8485
// Every Aggregated Job will contain a Blocking "Aggregator" job and an Informing "Analysis" job
8586
// Adding the Blocking Job
8687
blockingJobName := defaultAggregateProwJobName
87-
if definition.AggregatedProwJob.ProwJob != nil && len(definition.AggregatedProwJob.ProwJob.Name) > 0 {
88-
blockingJobName = definition.AggregatedProwJob.ProwJob.Name
88+
if verificationJobDefinition.AggregatedProwJob.ProwJob != nil && len(verificationJobDefinition.AggregatedProwJob.ProwJob.Name) > 0 {
89+
blockingJobName = verificationJobDefinition.AggregatedProwJob.ProwJob.Name
8990
}
9091
ciConfig.CIConfigurationJobName = fmt.Sprintf("%s-%s", verifyName, blockingJobName)
9192
payload.Spec.PayloadVerificationConfig.BlockingJobs = append(payload.Spec.PayloadVerificationConfig.BlockingJobs, ciConfig)
9293

9394
// Adding the Informing Job
9495
informingJob := v1alpha1.CIConfiguration{
9596
CIConfigurationName: verifyName,
96-
CIConfigurationJobName: definition.ProwJob.Name,
97-
AnalysisJobCount: definition.AggregatedProwJob.AnalysisJobCount,
97+
CIConfigurationJobName: verificationJobDefinition.ProwJob.Name,
98+
AnalysisJobCount: verificationJobDefinition.AggregatedProwJob.AnalysisJobCount,
9899
}
99100
payload.Spec.PayloadVerificationConfig.InformingJobs = append(payload.Spec.PayloadVerificationConfig.InformingJobs, informingJob)
100101
default:
101-
if definition.Optional {
102+
if verificationJobDefinition.Optional {
102103
payload.Spec.PayloadVerificationConfig.InformingJobs = append(payload.Spec.PayloadVerificationConfig.InformingJobs, ciConfig)
103104
} else {
104105
payload.Spec.PayloadVerificationConfig.BlockingJobs = append(payload.Spec.PayloadVerificationConfig.BlockingJobs, ciConfig)

cmd/release-controller/sync_release_payload_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ var (
2323

2424
func TestNewReleasePayload(t *testing.T) {
2525
testCases := []struct {
26-
name string
27-
release *releasecontroller.Release
28-
payloadName string
29-
jobNamespace string
30-
prowNamespace string
31-
verificationJobs map[string]releasecontroller.ReleaseVerification
32-
upgradeJobs map[string]releasecontroller.UpgradeVerification
33-
dataSource v1alpha1.PayloadVerificationDataSource
34-
expected *v1alpha1.ReleasePayload
26+
name string
27+
release *releasecontroller.Release
28+
payloadName string
29+
jobNamespace string
30+
prowNamespace string
31+
verificationJobs map[string]releasecontroller.ReleaseVerification
32+
upgradeJobs map[string]releasecontroller.UpgradeVerification
33+
dataSource v1alpha1.PayloadVerificationDataSource
34+
expected *v1alpha1.ReleasePayload
3535
}{
3636
{
3737
name: "DisabledJob",

0 commit comments

Comments
 (0)