Skip to content

Commit 823a57d

Browse files
committed
[SRVKP-7207] verify olmskiprange path
1 parent 48a1e56 commit 823a57d

File tree

6 files changed

+324
-2
lines changed

6 files changed

+324
-2
lines changed

pkg/oc/oc.go

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import (
44
"encoding/json"
55
"fmt"
66
"log"
7+
"os"
78
"slices"
89
"strings"
910
"time"
1011

12+
"regexp"
13+
1114
"github.com/getgauge-contrib/gauge-go/testsuit"
1215
"github.com/openshift-pipelines/release-tests/pkg/cmd"
1316
"github.com/openshift-pipelines/release-tests/pkg/config"
@@ -169,3 +172,276 @@ func CopySecret(secretName string, sourceNamespace string, destNamespace string)
169172
cmd.MustSucceed("bash", "-c", fmt.Sprintf(`echo '%s' | kubectl apply -n %s -f -`, cmdOutput, destNamespace))
170173
log.Printf("Successfully copied secret %s from %s to %s", secretName, sourceNamespace, destNamespace)
171174
}
175+
176+
func FetchOlmSkipRange() (map[string]string, error) {
177+
skipRangesJson := cmd.MustSucceed("bash", "-c", `oc get packagemanifests openshift-pipelines-operator-rh -n openshift-marketplace -o json | jq -r '.status.channels[].currentCSVDesc.annotations["olm.skipRange"]'`).Stdout()
178+
skipRanges := strings.Split(strings.TrimSpace(skipRangesJson), "\n")
179+
channelsJson := cmd.MustSucceed("bash", "-c", `oc get packagemanifests openshift-pipelines-operator-rh -n openshift-marketplace -o json | jq -r '.status.channels[].name'`).Stdout()
180+
channels := strings.Split(strings.TrimSpace(channelsJson), "\n")
181+
182+
if len(channels) != len(skipRanges) {
183+
return nil, fmt.Errorf("mismatch between number of channels (%d) and skipRanges (%d)", len(channels), len(skipRanges))
184+
}
185+
186+
channelSkipRangeMap := make(map[string]string)
187+
for i, channel := range channels {
188+
if skipRanges[i] != "null" && skipRanges[i] != "" {
189+
channelSkipRangeMap[channel] = skipRanges[i]
190+
}
191+
}
192+
193+
if len(channelSkipRangeMap) == 0 {
194+
return nil, fmt.Errorf("no valid OLM Skip Ranges found")
195+
}
196+
return channelSkipRangeMap, nil
197+
}
198+
199+
func GetOlmSkipRange(upgradeType, fieldName, fileName string) {
200+
skipRangeMap, err := FetchOlmSkipRange()
201+
if err != nil {
202+
log.Printf("Error fetching OLM Skip Range: %v", err)
203+
return
204+
}
205+
file, err := os.OpenFile(config.Path(fileName), os.O_RDWR, 0644)
206+
if err != nil {
207+
log.Printf("Error opening file %s: %v", fileName, err)
208+
return
209+
}
210+
defer file.Close()
211+
var existingData map[string]interface{}
212+
if err := json.NewDecoder(file).Decode(&existingData); err != nil {
213+
log.Printf("Error decoding existing data from file %s: %v", fileName, err)
214+
return
215+
}
216+
switch upgradeType {
217+
case "pre-upgrade":
218+
existingData["pre-upgrade-olm-skip-range"] = skipRangeMap
219+
log.Printf("Pre-upgrade OLM Skip Range is stored as: %+v", skipRangeMap)
220+
case "post-upgrade":
221+
existingData["post-upgrade-olm-skip-range"] = skipRangeMap
222+
log.Printf("Post-upgrade OLM Skip Range is stored as: %+v", skipRangeMap)
223+
}
224+
if _, err := file.Seek(0, 0); err != nil {
225+
log.Printf("Error seeking file %s: %v", fileName, err)
226+
return
227+
}
228+
encoder := json.NewEncoder(file)
229+
encoder.SetIndent("", " ") // Pretty-print the JSON output
230+
if err := encoder.Encode(existingData); err != nil {
231+
log.Printf("Error writing updated data to file %s: %v", fileName, err)
232+
return
233+
}
234+
log.Printf("OLM Skip Range for '%s' has been saved to file %s", fieldName, fileName)
235+
}
236+
237+
func ValidateOlmSkipRange() {
238+
skipRangeMap, err := FetchOlmSkipRange()
239+
if err != nil {
240+
log.Printf("Error fetching OLM Skip Range: %v", err)
241+
return
242+
}
243+
244+
ospVersion := os.Getenv("OSP_VERSION")
245+
log.Printf("Validating OSP_VERSION: %s", ospVersion)
246+
found := false
247+
248+
if ospVersion == "5.0.5" {
249+
log.Printf("Detected nightly build (OSP_VERSION=5.0.5), validating only skipRange, not channel name")
250+
for channel, skipRange := range skipRangeMap {
251+
if channel == "latest" {
252+
log.Printf("Skipping 'latest' channel as requested")
253+
continue
254+
}
255+
skipRangeContainsVersion := strings.Contains(skipRange, ospVersion)
256+
log.Printf("Channel: %s, SkipRange: %s", channel, skipRange)
257+
log.Printf(" - SkipRange contains OSP_VERSION '%s': %v", ospVersion, skipRangeContainsVersion)
258+
259+
if skipRangeContainsVersion {
260+
log.Printf("Success: OSP_VERSION '%s' found in skipRange for channel '%s': '%s'", ospVersion, channel, skipRange)
261+
found = true
262+
break
263+
}
264+
}
265+
} else {
266+
log.Printf("Regular release build, validating both channel name and skipRange")
267+
for channel, skipRange := range skipRangeMap {
268+
if channel == "latest" {
269+
log.Printf("Skipping 'latest' channel as requested")
270+
continue
271+
}
272+
channelContainsVersion := strings.Contains(channel, ospVersion)
273+
skipRangeContainsVersion := strings.Contains(skipRange, ospVersion)
274+
log.Printf("Channel: %s, SkipRange: %s", channel, skipRange)
275+
log.Printf(" - Channel contains OSP_VERSION '%s': %v", ospVersion, channelContainsVersion)
276+
log.Printf(" - SkipRange contains OSP_VERSION '%s': %v", ospVersion, skipRangeContainsVersion)
277+
if channelContainsVersion && skipRangeContainsVersion {
278+
log.Printf("Success: OSP_VERSION '%s' found in both channel '%s' and its skipRange '%s'", ospVersion, channel, skipRange)
279+
found = true
280+
break
281+
}
282+
}
283+
}
284+
285+
if !found {
286+
log.Printf("Available channels and their skipRanges:")
287+
for channel, skipRange := range skipRangeMap {
288+
if channel != "latest" {
289+
log.Printf(" - Channel: %s, SkipRange: %s", channel, skipRange)
290+
}
291+
}
292+
293+
if ospVersion == "5.0.5" {
294+
testsuit.T.Fail(fmt.Errorf("Error: OSP_VERSION '%s' not found in skipRange for any non-latest channel", ospVersion))
295+
} else {
296+
testsuit.T.Fail(fmt.Errorf("Error: OSP_VERSION '%s' not found in both channel name and skipRange for any non-latest channel", ospVersion))
297+
}
298+
}
299+
}
300+
301+
func isValidOspVersionPatchUpdate(preSkipRange, postSkipRange string) bool {
302+
ospVersion := os.Getenv("OSP_VERSION")
303+
304+
if !skipRangeContainsVersion(postSkipRange, ospVersion) {
305+
log.Printf("Post-upgrade skip range '%s' does not contain OSP_VERSION '%s'", postSkipRange, ospVersion)
306+
return false
307+
}
308+
309+
rangeRegex := regexp.MustCompile(`>=(\d+\.\d+\.\d+)\s*<(\d+\.\d+\.\d+)`)
310+
preMatches := rangeRegex.FindStringSubmatch(preSkipRange)
311+
postMatches := rangeRegex.FindStringSubmatch(postSkipRange)
312+
313+
preUpperBound := preMatches[2] // Upper bound from pre-upgrade
314+
postUpperBound := postMatches[2] // Upper bound from post-upgrade
315+
316+
versionRegex := regexp.MustCompile(`^(\d+)\.(\d+)\.(\d+)$`)
317+
preUpperMatches := versionRegex.FindStringSubmatch(preUpperBound)
318+
postUpperMatches := versionRegex.FindStringSubmatch(postUpperBound)
319+
320+
preUpperPatch := preUpperMatches[3]
321+
postUpperPatch := postUpperMatches[3]
322+
323+
var preUpperPatchInt, postUpperPatchInt int
324+
fmt.Sscanf(preUpperPatch, "%d", &preUpperPatchInt)
325+
fmt.Sscanf(postUpperPatch, "%d", &postUpperPatchInt)
326+
327+
if postUpperPatchInt <= preUpperPatchInt {
328+
log.Printf("Version did not increase: %s -> %s", preUpperBound, postUpperBound)
329+
return false
330+
}
331+
332+
log.Printf("Valid OSP version-based patch update detected: %s -> %s (OSP_VERSION: %s)",
333+
preUpperBound, postUpperBound, ospVersion)
334+
return true
335+
}
336+
337+
func skipRangeContainsVersion(skipRange, version string) bool {
338+
return strings.Contains(skipRange, version)
339+
}
340+
341+
func ValidateOlmSkipRangeDiff(fileName string, preUpgradeSkipRange string, postUpgradeSkipRange string) {
342+
file, err := os.Open(config.Path(fileName))
343+
if err != nil {
344+
log.Printf("Error opening file %s: %v", fileName, err)
345+
testsuit.T.Fail(fmt.Errorf("Error opening file %s: %v", fileName, err))
346+
return
347+
}
348+
defer file.Close()
349+
var skipRangeData map[string]interface{}
350+
decoder := json.NewDecoder(file)
351+
if err := decoder.Decode(&skipRangeData); err != nil {
352+
log.Printf("Error decoding JSON from file %s: %v", fileName, err)
353+
testsuit.T.Fail(fmt.Errorf("Error decoding JSON from file %s: %v", fileName, err))
354+
return
355+
}
356+
preUpgradeData, preExists := skipRangeData[preUpgradeSkipRange]
357+
postUpgradeData, postExists := skipRangeData[postUpgradeSkipRange]
358+
if !preExists || !postExists {
359+
log.Printf("Error: One of the skip ranges is missing. Pre-Upgrade exists: %v, Post-Upgrade exists: %v", preExists, postExists)
360+
testsuit.T.Fail(fmt.Errorf("One of the skip ranges is missing. Pre-Upgrade exists: %v, Post-Upgrade exists: %v", preExists, postExists))
361+
return
362+
}
363+
364+
preUpgradeMap, ok1 := preUpgradeData.(map[string]interface{})
365+
postUpgradeMap, ok2 := postUpgradeData.(map[string]interface{})
366+
367+
if !ok1 || !ok2 {
368+
log.Printf("Error: Skip range data is not in expected map format")
369+
testsuit.T.Fail(fmt.Errorf("Skip range data is not in expected map format"))
370+
return
371+
}
372+
373+
log.Printf("Pre-Upgrade Skip Range: %+v", preUpgradeMap)
374+
log.Printf("Post-Upgrade Skip Range: %+v", postUpgradeMap)
375+
376+
validationErrors := []string{}
377+
378+
log.Printf("Validating that all pre-upgrade channels are preserved in post-upgrade (ignoring 'latest' channel)")
379+
380+
// Check each channel from pre-upgrade data
381+
for preChannel, preSkipRange := range preUpgradeMap {
382+
// Skip 'latest' channel from pre-upgrade validation
383+
if preChannel == "latest" {
384+
log.Printf("Skipping 'latest' channel from pre-upgrade data as requested")
385+
continue
386+
}
387+
388+
if postSkipRange, exists := postUpgradeMap[preChannel]; exists {
389+
if preSkipRange == postSkipRange {
390+
log.Printf("✅ Success: Channel '%s' preserved with skipRange: %v", preChannel, preSkipRange)
391+
} else {
392+
// There's a skipRange mismatch - check if it's related to current OSP_VERSION
393+
preSkipRangeStr, ok1 := preSkipRange.(string)
394+
postSkipRangeStr, ok2 := postSkipRange.(string)
395+
396+
if ok1 && ok2 {
397+
ospVersion := os.Getenv("OSP_VERSION")
398+
399+
if ospVersion != "" && (strings.Contains(preSkipRangeStr, ospVersion) || strings.Contains(postSkipRangeStr, ospVersion)) {
400+
log.Printf("ℹ️ SkipRange mismatch involves current OSP_VERSION '%s', applying OSP_VERSION-based validation", ospVersion)
401+
402+
if isValidOspVersionPatchUpdate(preSkipRangeStr, postSkipRangeStr) {
403+
log.Printf("✅ Success: Channel '%s' updated with valid OSP_VERSION-based patch release: %v -> %v", preChannel, preSkipRange, postSkipRange)
404+
} else {
405+
validationErrors = append(validationErrors, fmt.Sprintf("Channel '%s' skipRange changed from '%v' to '%v' (not a valid OSP_VERSION-based patch update for OSP_VERSION '%s')", preChannel, preSkipRange, postSkipRange, ospVersion))
406+
}
407+
} else {
408+
if ospVersion == "" {
409+
log.Printf("ℹ️ OSP_VERSION not set, applying standard validation (no changes allowed)")
410+
} else {
411+
log.Printf("ℹ️ SkipRange mismatch does not involve current OSP_VERSION '%s', applying standard validation (no changes allowed)", ospVersion)
412+
}
413+
validationErrors = append(validationErrors, fmt.Sprintf("Channel '%s' skipRange changed from '%v' to '%v' (should remain unchanged)", preChannel, preSkipRange, postSkipRange))
414+
}
415+
} else {
416+
validationErrors = append(validationErrors, fmt.Sprintf("Channel '%s' skipRange changed from '%v' to '%v' (invalid format)", preChannel, preSkipRange, postSkipRange))
417+
}
418+
}
419+
} else {
420+
validationErrors = append(validationErrors, fmt.Sprintf("Pre-upgrade channel '%s' is missing in post-upgrade data", preChannel))
421+
}
422+
}
423+
424+
log.Printf("Additional channels found in post-upgrade data:")
425+
for postChannel, postSkipRange := range postUpgradeMap {
426+
if _, existedInPre := preUpgradeMap[postChannel]; existedInPre {
427+
continue
428+
}
429+
430+
if postChannel == "latest" {
431+
log.Printf(" - Ignoring 'latest' channel in post-upgrade as requested")
432+
continue
433+
}
434+
435+
log.Printf(" - New channel '%s' with skipRange: %v", postChannel, postSkipRange)
436+
}
437+
438+
if len(validationErrors) > 0 {
439+
log.Printf("❌ OLM Skip Range validation failed with errors:")
440+
for _, err := range validationErrors {
441+
log.Printf(" - %s", err)
442+
}
443+
testsuit.T.Fail(fmt.Errorf("OLM Skip Range validation failed: %v", strings.Join(validationErrors, "; ")))
444+
} else {
445+
log.Printf("✅ Success: OLM Skip Range validation passed - all expected changes detected correctly")
446+
}
447+
}

specs/operator/post-upgrade.spec

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,15 @@ Importance: Critical
8383
Steps:
8484
* Switch to project "releasetest-upgrade-s2i"
8585
* Get tags of the imagestream "golang" from namespace "openshift" and store to variable "golang-tags"
86-
* Start and verify pipeline "s2i-go-pipeline" with param "VERSION" with values stored in variable "golang-tags" with workspace "name=source,claimName=shared-pvc"
86+
* Start and verify pipeline "s2i-go-pipeline" with param "VERSION" with values stored in variable "golang-tags" with workspace "name=source,claimName=shared-pvc"
87+
88+
## Validate olm skiprange post upgrade: PIPELINES-19-TC06
89+
Tags: post-upgrade, olm
90+
Component: Pipelines
91+
Level: Integration
92+
Type: Functional
93+
Importance: Critical
94+
95+
Steps:
96+
* Get olm-skip-range "post-upgrade" and save to field "post-upgrade-olm-skip-range" in file "testdata/olm/skiprange.json"
97+
* Validate the fields "pre-upgrade-olm-skip-range" and "post-upgrade-olm-skip-range" are same in file "testdata/olm/skiprange.json"

specs/operator/pre-upgrade.spec

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,14 @@ Steps:
126126
|S.NO|resource_dir |
127127
|----|------------------------------------------------------|
128128
|1 |testdata/ecosystem/pipelines/s2i-go.yaml|
129-
|2 |testdata/pvc/pvc.yaml |
129+
|2 |testdata/pvc/pvc.yaml |
130+
131+
## Validate olm skiprange pre upgrade: PIPELINES-18-TC06
132+
Tags: pre-upgrade, olm
133+
Component: Pipelines
134+
Level: Integration
135+
Type: Functional
136+
Importance: Critical
137+
138+
Steps:
139+
* Get olm-skip-range "pre-upgrade" and save to field "pre-upgrade-olm-skip-range" in file "testdata/olm/skiprange.json"

specs/versions.spec

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,12 @@ Steps:
3030
* Check "tkn-pac" version
3131
* Check "opc" client version
3232
* Check "opc" server version
33+
34+
## Check OperatorVersion in OlmSkipRange : PIPELINES-22-TC03
35+
Tags: e2e, sanity, olm
36+
Component: Operator
37+
Level: Integration
38+
Type: Functional
39+
Importance: High
40+
Steps:
41+
* Validate OperatorVersion in OlmSkipRange

steps/olm/operator.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,15 @@ var _ = gauge.Step("Store Cosign public key in file", func() {
196196
var _ = gauge.Step("Verify <binary> version from the pipelinerun logs", func(binary string) {
197197
pipelines.CheckLogVersion(store.Clients(), binary, store.Namespace())
198198
})
199+
200+
var _ = gauge.Step("Get olm-skip-range <upgradeType> and save to field <fieldName> in file <fileName>", func(upgradeType string, fieldName string, filename string) {
201+
oc.GetOlmSkipRange(upgradeType, fieldName, filename)
202+
})
203+
204+
var _ = gauge.Step("Validate the fields <preUpgradeSkipRange> and <postUpgradeSkipRange> are same in file <fileName>", func(preUpgradeSkipRange string, postUpgradeSkipRange string, fileName string) {
205+
oc.ValidateOlmSkipRangeDiff(fileName, preUpgradeSkipRange, postUpgradeSkipRange)
206+
})
207+
208+
var _ = gauge.Step("Validate OperatorVersion in OlmSkipRange", func() {
209+
oc.ValidateOlmSkipRange()
210+
})

testdata/olm/skiprange.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"post-upgrade-olm-skip-range": {},
3+
"pre-upgrade-olm-skip-range": {}
4+
}

0 commit comments

Comments
 (0)