|
4 | 4 | "encoding/json" |
5 | 5 | "fmt" |
6 | 6 | "log" |
| 7 | + "os" |
7 | 8 | "slices" |
8 | 9 | "strings" |
9 | 10 | "time" |
@@ -169,3 +170,218 @@ func CopySecret(secretName string, sourceNamespace string, destNamespace string) |
169 | 170 | cmd.MustSucceed("bash", "-c", fmt.Sprintf(`echo '%s' | kubectl apply -n %s -f -`, cmdOutput, destNamespace)) |
170 | 171 | log.Printf("Successfully copied secret %s from %s to %s", secretName, sourceNamespace, destNamespace) |
171 | 172 | } |
| 173 | + |
| 174 | +func FetchOlmSkipRange() (map[string]string, error) { |
| 175 | + 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() |
| 176 | + skipRanges := strings.Split(strings.TrimSpace(skipRangesJson), "\n") |
| 177 | + channelsJson := cmd.MustSucceed("bash", "-c", `oc get packagemanifests openshift-pipelines-operator-rh -n openshift-marketplace -o json | jq -r '.status.channels[].name'`).Stdout() |
| 178 | + channels := strings.Split(strings.TrimSpace(channelsJson), "\n") |
| 179 | + |
| 180 | + if len(channels) != len(skipRanges) { |
| 181 | + return nil, fmt.Errorf("mismatch between number of channels (%d) and skipRanges (%d)", len(channels), len(skipRanges)) |
| 182 | + } |
| 183 | + |
| 184 | + channelSkipRangeMap := make(map[string]string) |
| 185 | + for i, channel := range channels { |
| 186 | + if skipRanges[i] != "null" && skipRanges[i] != "" { |
| 187 | + channelSkipRangeMap[channel] = skipRanges[i] |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + if len(channelSkipRangeMap) == 0 { |
| 192 | + return nil, fmt.Errorf("no valid OLM Skip Ranges found") |
| 193 | + } |
| 194 | + return channelSkipRangeMap, nil |
| 195 | +} |
| 196 | + |
| 197 | +func GetOlmSkipRange(upgradeType, fieldName, fileName string) { |
| 198 | + skipRangeMap, err := FetchOlmSkipRange() |
| 199 | + if err != nil { |
| 200 | + log.Printf("Error fetching OLM Skip Range: %v", err) |
| 201 | + return |
| 202 | + } |
| 203 | + file, err := os.OpenFile(config.Path(fileName), os.O_RDWR, 0644) |
| 204 | + if err != nil { |
| 205 | + log.Printf("Error opening file %s: %v", fileName, err) |
| 206 | + return |
| 207 | + } |
| 208 | + defer file.Close() |
| 209 | + var existingData map[string]interface{} |
| 210 | + if err := json.NewDecoder(file).Decode(&existingData); err != nil { |
| 211 | + log.Printf("Error decoding existing data from file %s: %v", fileName, err) |
| 212 | + return |
| 213 | + } |
| 214 | + switch upgradeType { |
| 215 | + case "pre-upgrade": |
| 216 | + existingData["pre-upgrade-olm-skip-range"] = skipRangeMap |
| 217 | + log.Printf("Pre-upgrade OLM Skip Range is stored as: %+v", skipRangeMap) |
| 218 | + case "post-upgrade": |
| 219 | + existingData["post-upgrade-olm-skip-range"] = skipRangeMap |
| 220 | + log.Printf("Post-upgrade OLM Skip Range is stored as: %+v", skipRangeMap) |
| 221 | + } |
| 222 | + if _, err := file.Seek(0, 0); err != nil { |
| 223 | + log.Printf("Error seeking file %s: %v", fileName, err) |
| 224 | + return |
| 225 | + } |
| 226 | + encoder := json.NewEncoder(file) |
| 227 | + encoder.SetIndent("", " ") // Pretty-print the JSON output |
| 228 | + if err := encoder.Encode(existingData); err != nil { |
| 229 | + log.Printf("Error writing updated data to file %s: %v", fileName, err) |
| 230 | + return |
| 231 | + } |
| 232 | + log.Printf("OLM Skip Range for '%s' has been saved to file %s", fieldName, fileName) |
| 233 | +} |
| 234 | + |
| 235 | +func ValidateOlmSkipRange() { |
| 236 | + skipRangeMap, err := FetchOlmSkipRange() |
| 237 | + if err != nil { |
| 238 | + log.Printf("Error fetching OLM Skip Range: %v", err) |
| 239 | + return |
| 240 | + } |
| 241 | + |
| 242 | + ospVersion := os.Getenv("OSP_VERSION") |
| 243 | + log.Printf("Validating OSP_VERSION: %s", ospVersion) |
| 244 | + found := false |
| 245 | + |
| 246 | + if ospVersion == "5.0.5" { |
| 247 | + log.Printf("Detected nightly build (OSP_VERSION=5.0.5), validating only skipRange, not channel name") |
| 248 | + for channel, skipRange := range skipRangeMap { |
| 249 | + if channel == "latest" { |
| 250 | + log.Printf("Skipping 'latest' channel as requested") |
| 251 | + continue |
| 252 | + } |
| 253 | + skipRangeContainsVersion := strings.Contains(skipRange, ospVersion) |
| 254 | + log.Printf("Channel: %s, SkipRange: %s", channel, skipRange) |
| 255 | + log.Printf(" - SkipRange contains OSP_VERSION '%s': %v", ospVersion, skipRangeContainsVersion) |
| 256 | + |
| 257 | + if skipRangeContainsVersion { |
| 258 | + log.Printf("Success: OSP_VERSION '%s' found in skipRange for channel '%s': '%s'", ospVersion, channel, skipRange) |
| 259 | + found = true |
| 260 | + break |
| 261 | + } |
| 262 | + } |
| 263 | + } else { |
| 264 | + log.Printf("Regular release build, validating both channel name and skipRange") |
| 265 | + for channel, skipRange := range skipRangeMap { |
| 266 | + if channel == "latest" { |
| 267 | + log.Printf("Skipping 'latest' channel as requested") |
| 268 | + continue |
| 269 | + } |
| 270 | + channelContainsVersion := strings.Contains(channel, ospVersion) |
| 271 | + skipRangeContainsVersion := strings.Contains(skipRange, ospVersion) |
| 272 | + log.Printf("Channel: %s, SkipRange: %s", channel, skipRange) |
| 273 | + log.Printf(" - Channel contains OSP_VERSION '%s': %v", ospVersion, channelContainsVersion) |
| 274 | + log.Printf(" - SkipRange contains OSP_VERSION '%s': %v", ospVersion, skipRangeContainsVersion) |
| 275 | + if channelContainsVersion && skipRangeContainsVersion { |
| 276 | + log.Printf("Success: OSP_VERSION '%s' found in both channel '%s' and its skipRange '%s'", ospVersion, channel, skipRange) |
| 277 | + found = true |
| 278 | + break |
| 279 | + } |
| 280 | + } |
| 281 | + } |
| 282 | + |
| 283 | + if !found { |
| 284 | + log.Printf("Available channels and their skipRanges:") |
| 285 | + for channel, skipRange := range skipRangeMap { |
| 286 | + if channel != "latest" { |
| 287 | + log.Printf(" - Channel: %s, SkipRange: %s", channel, skipRange) |
| 288 | + } |
| 289 | + } |
| 290 | + |
| 291 | + if ospVersion == "5.0.5" { |
| 292 | + testsuit.T.Fail(fmt.Errorf("Error: OSP_VERSION '%s' not found in skipRange for any non-latest channel", ospVersion)) |
| 293 | + } else { |
| 294 | + testsuit.T.Fail(fmt.Errorf("Error: OSP_VERSION '%s' not found in both channel name and skipRange for any non-latest channel", ospVersion)) |
| 295 | + } |
| 296 | + } |
| 297 | +} |
| 298 | + |
| 299 | +func ValidateOlmSkipRangeDiff(fileName string, preUpgradeSkipRange string, postUpgradeSkipRange string) { |
| 300 | + file, err := os.Open(config.Path(fileName)) |
| 301 | + if err != nil { |
| 302 | + log.Printf("Error opening file %s: %v", fileName, err) |
| 303 | + testsuit.T.Fail(fmt.Errorf("Error opening file %s: %v", fileName, err)) |
| 304 | + return |
| 305 | + } |
| 306 | + defer file.Close() |
| 307 | + var skipRangeData map[string]interface{} |
| 308 | + decoder := json.NewDecoder(file) |
| 309 | + if err := decoder.Decode(&skipRangeData); err != nil { |
| 310 | + log.Printf("Error decoding JSON from file %s: %v", fileName, err) |
| 311 | + testsuit.T.Fail(fmt.Errorf("Error decoding JSON from file %s: %v", fileName, err)) |
| 312 | + return |
| 313 | + } |
| 314 | + preUpgradeData, preExists := skipRangeData[preUpgradeSkipRange] |
| 315 | + postUpgradeData, postExists := skipRangeData[postUpgradeSkipRange] |
| 316 | + if !preExists || !postExists { |
| 317 | + log.Printf("Error: One of the skip ranges is missing. Pre-Upgrade exists: %v, Post-Upgrade exists: %v", preExists, postExists) |
| 318 | + testsuit.T.Fail(fmt.Errorf("One of the skip ranges is missing. Pre-Upgrade exists: %v, Post-Upgrade exists: %v", preExists, postExists)) |
| 319 | + return |
| 320 | + } |
| 321 | + |
| 322 | + preUpgradeMap, ok1 := preUpgradeData.(map[string]interface{}) |
| 323 | + postUpgradeMap, ok2 := postUpgradeData.(map[string]interface{}) |
| 324 | + |
| 325 | + if !ok1 || !ok2 { |
| 326 | + log.Printf("Error: Skip range data is not in expected map format") |
| 327 | + testsuit.T.Fail(fmt.Errorf("Skip range data is not in expected map format")) |
| 328 | + return |
| 329 | + } |
| 330 | + |
| 331 | + log.Printf("Pre-Upgrade Skip Range: %+v", preUpgradeMap) |
| 332 | + log.Printf("Post-Upgrade Skip Range: %+v", postUpgradeMap) |
| 333 | + |
| 334 | + // Validate that all pre-upgrade channels (except 'latest') are preserved in post-upgrade |
| 335 | + // Ignore 'latest' channel in post-upgrade data completely |
| 336 | + validationErrors := []string{} |
| 337 | + |
| 338 | + log.Printf("Validating that all pre-upgrade channels are preserved in post-upgrade (ignoring 'latest' channel)") |
| 339 | + |
| 340 | + // Check each channel from pre-upgrade data |
| 341 | + for preChannel, preSkipRange := range preUpgradeMap { |
| 342 | + // Skip 'latest' channel from pre-upgrade validation |
| 343 | + if preChannel == "latest" { |
| 344 | + log.Printf("Skipping 'latest' channel from pre-upgrade data as requested") |
| 345 | + continue |
| 346 | + } |
| 347 | + |
| 348 | + // Check if this pre-upgrade channel exists in post-upgrade with same skipRange |
| 349 | + if postSkipRange, exists := postUpgradeMap[preChannel]; exists { |
| 350 | + if preSkipRange == postSkipRange { |
| 351 | + log.Printf("✅ Success: Channel '%s' preserved with skipRange: %v", preChannel, preSkipRange) |
| 352 | + } else { |
| 353 | + validationErrors = append(validationErrors, fmt.Sprintf("Channel '%s' skipRange changed from '%v' to '%v' (should remain unchanged)", preChannel, preSkipRange, postSkipRange)) |
| 354 | + } |
| 355 | + } else { |
| 356 | + validationErrors = append(validationErrors, fmt.Sprintf("Pre-upgrade channel '%s' is missing in post-upgrade data", preChannel)) |
| 357 | + } |
| 358 | + } |
| 359 | + |
| 360 | + // Log additional channels in post-upgrade (for information only, not validation errors) |
| 361 | + log.Printf("Additional channels found in post-upgrade data:") |
| 362 | + for postChannel, postSkipRange := range postUpgradeMap { |
| 363 | + // Skip channels that were in pre-upgrade (already validated above) |
| 364 | + if _, existedInPre := preUpgradeMap[postChannel]; existedInPre { |
| 365 | + continue |
| 366 | + } |
| 367 | + |
| 368 | + // Skip 'latest' channel as requested |
| 369 | + if postChannel == "latest" { |
| 370 | + log.Printf(" - Ignoring 'latest' channel in post-upgrade as requested") |
| 371 | + continue |
| 372 | + } |
| 373 | + |
| 374 | + log.Printf(" - New channel '%s' with skipRange: %v", postChannel, postSkipRange) |
| 375 | + } |
| 376 | + |
| 377 | + // Report results |
| 378 | + if len(validationErrors) > 0 { |
| 379 | + log.Printf("❌ OLM Skip Range validation failed with errors:") |
| 380 | + for _, err := range validationErrors { |
| 381 | + log.Printf(" - %s", err) |
| 382 | + } |
| 383 | + testsuit.T.Fail(fmt.Errorf("OLM Skip Range validation failed: %v", strings.Join(validationErrors, "; "))) |
| 384 | + } else { |
| 385 | + log.Printf("✅ Success: OLM Skip Range validation passed - all expected changes detected correctly") |
| 386 | + } |
| 387 | +} |
0 commit comments