Skip to content

Commit 1c35008

Browse files
authored
SOT NOP upgrade sequence, allow explicit upgrade sequence with tags (#2431)
SOT NOP upgrade sequence, allow explicit upgrade sequence with tags
1 parent c8f04f9 commit 1c35008

5 files changed

Lines changed: 185 additions & 110 deletions

File tree

book/src/framework/compat.md

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,58 @@
11
# Compatibility Testing
22

3-
We have a simple tool to check compatibility for CL nodes. The example command will filter and sort the available tags, rollback and install the oldest version, and then begin performing automatic upgrades to verify that each subsequent version remains compatible with the previous one.
3+
## Prerequisites
4+
5+
Authorize in our SDLC ECR registry first. Get the creds and run
6+
```bash
7+
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <sdlc_ecr_registry>
8+
```
9+
10+
## Testing Upgrade Sequence
11+
12+
We have a simple tool to check compatibility for CL node clusters. The example command will filter and sort the available tags, rollback and install the oldest version, and then begin performing automatic upgrades to verify that each subsequent version remains compatible with the previous one.
13+
14+
`buildcmd`, `envcmd`, `testcmd` can be arbitrary bash commands.
415

516
```bash
617
ctf compat backward \
18+
--registry <sdlc_ecr_registry> \
19+
--buildcmd "just cli" \
20+
--envcmd "cl r" \
21+
--testcmd "cl test ocr2 TestSmoke/rounds" \
22+
--refs 2.32.0 \
23+
--refs 2.33.0 \
24+
--refs 2.34.0 \
25+
--refs 2.35.0 \
26+
--nodes 3
27+
```
28+
29+
Keep in mind that `refs` should be present in regsitry you are testing against, the first (oldest) `ref` should also have a valid end-to-end test that works.
30+
31+
In CI we detect SemVer tags automatically, whenever a new tag appears we select last 3, rollback to the oldest and perform upgrade process.
32+
33+
```bash
34+
ctf compat backward \
35+
--registry <sdlc_ecr_registry> \
736
--buildcmd "just cli" \
837
--envcmd "cl r" \
938
--testcmd "cl test ocr2 TestSmoke/rounds" \
10-
--include_tags +compat \
1139
--nodes 3 \
12-
--versions_back 3
40+
--versions-back 3
1341
```
1442

15-
Since some of our products have a different release and tagging strategies you should add `+compat` tags to all released versions and use this tool in CI to check compatibility on `+compat` tag.
43+
In case you have multiple DONs in your product and names of nodes are different please use `--node-name-template custom-cl-node-%d` option
1644

17-
Use `ctf compat restore` to rollback to current branch (default is `develop`)
45+
## Modelling Node Operators Cluster
46+
47+
It is possible to fetch versions node operators are currently running and model DON upgrade sequence locally. Logic is the same, get all the versions, rollback to the oldest one, setup product, verify, try to upgrade all the versions running the oldest test for each upgrade.
48+
49+
```bash
50+
ctf compat backward \
51+
--registry <sdlc_ecr_registry>\
52+
--buildcmd "just cli" \
53+
--envcmd "cl r" \
54+
--testcmd "cl test ocr2 TestSmoke/rounds" \
55+
--nop northwestnodes \
56+
--versions-back 3 \
57+
--nodes 3
58+
```

framework/.changeset/v0.14.6.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- NOPs from SOT upgrade sequence
2+
- Allow specify upgrade sequence explicitly

framework/cmd/main.go

Lines changed: 87 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"os/exec"
88
"path/filepath"
99
"runtime"
10-
"slices"
1110
"strings"
1211

1312
"github.com/pelletier/go-toml"
@@ -275,15 +274,15 @@ Be aware that any TODO requires your attention before your run the final test!
275274
},
276275
Usage: "Restores back to develop",
277276
Action: func(c *cli.Context) error {
278-
return framework.RestoreToBranch(c.String("base_branch"))
277+
return framework.CheckOut(c.String("base_branch"))
279278
},
280279
},
281280
{
282281
Name: "backward",
283282
Aliases: []string{"b"},
284283
Flags: []cli.Flag{
285284
&cli.IntFlag{
286-
Name: "versions_back",
285+
Name: "versions-back",
287286
Aliases: []string{"v"},
288287
Usage: "How many versions back to test",
289288
Value: 1,
@@ -300,6 +299,10 @@ Be aware that any TODO requires your attention before your run the final test!
300299
Usage: "Docker Image registry for Chainlink node",
301300
Value: "smartcontract/chainlink",
302301
},
302+
&cli.StringFlag{
303+
Name: "strip-image-suffix",
304+
Usage: "Stripts image suffix from ref to map it to registry images",
305+
},
303306
&cli.StringFlag{
304307
Name: "buildcmd",
305308
Aliases: []string{"b"},
@@ -316,41 +319,98 @@ Be aware that any TODO requires your attention before your run the final test!
316319
Aliases: []string{"t"},
317320
Usage: "Test verification command",
318321
},
322+
&cli.StringFlag{
323+
Name: "nop",
324+
Usage: "Find specific NOPs ref upgrade sequence",
325+
},
326+
&cli.StringFlag{
327+
Name: "node-name-template",
328+
Usage: "CL node Docker container name template",
329+
Value: "don-node%d",
330+
},
331+
&cli.StringFlag{
332+
Name: "sot-url",
333+
Usage: "RANE SOT snapshot API URL",
334+
Value: "https://rane-sot-app.main.prod.cldev.sh/v1/snapshot",
335+
},
336+
&cli.StringSliceFlag{
337+
Name: "refs",
338+
Usage: "Refs to test, can be tag or commit. The corresponding image with ref should be present in registry",
339+
},
319340
&cli.StringSliceFlag{
320-
Name: "include_tags",
321-
Usage: "Patterns to include specific tags (e.g., beta,rc,v0,v1)",
341+
Name: "include-refs",
342+
Usage: "Patterns to include specific refs (e.g., beta,rc,v0,v1), also used in CI to verify on test refs(tags)",
322343
},
323344
&cli.StringSliceFlag{
324-
Name: "exclude_tags",
325-
Usage: "Patterns to exclude specific tags (e.g., beta,rc,v0,v1)",
326-
Value: cli.NewStringSlice("beta", "rc", "v0", "ccip", "cre", "datastreams"),
345+
Name: "exclude-refs",
346+
Usage: "Patterns to exclude specific refs (e.g., beta,rc,v0,v1)",
327347
},
328348
},
329349
Usage: "Rollbacks N versions back, runs the test the upgrades CL nodes with new versions",
330350
Action: func(c *cli.Context) error {
331-
versionsBack := c.Int("versions_back")
351+
versionsBack := c.Int("versions-back")
332352
registry := c.String("registry")
333-
include := c.StringSlice("include_tags")
334-
exclude := c.StringSlice("exclude_tags")
353+
refs := c.StringSlice("refs")
354+
include := c.StringSlice("include-refs")
355+
exclude := c.StringSlice("exclude-refs")
335356

336357
buildcmd := c.String("buildcmd")
337358
envcmd := c.String("envcmd")
338359
testcmd := c.String("testcmd")
339360
nodes := c.Int("nodes")
361+
nodeNameTemplate := c.String("node-name-template")
362+
363+
nop := c.String("nop")
364+
sotURL := c.String("sot-url")
365+
340366
// test logic is:
341-
// - rollback to selected tag
367+
// - rollback to selected ref
342368
// - spin up the env and perform the initial smoke test
343369
// - upgrade N CL nodes with preversing DB volume (shared database)
344370
// - perform the test again
345371
// - repeat until all the new versions are validated
346-
tags, err := framework.RollbackToEarliestSemverTag(versionsBack, include, exclude)
347-
if err != nil {
348-
return err
372+
373+
// if no refs provided find refs (tags) sequence SemVer sequence for last N versions_back
374+
// else, use refs param slice
375+
//
376+
var err error
377+
if len(refs) == 0 && nop == "" {
378+
refs, err = framework.FindSemVerRefSequence(versionsBack, include, exclude)
379+
if err != nil {
380+
return err
381+
}
349382
}
350-
if envcmd == "" || testcmd == "" {
383+
if nop != "" {
384+
refs, err = framework.FindNOPRefs(sotURL, nop, exclude)
385+
if err != nil {
386+
return err
387+
}
388+
}
389+
framework.L.Info().
390+
Int("TotalSemVerRefs", len(refs)).
391+
Strs("SelectedRefs", refs).
392+
Str("EarliestRefs", refs[0]).
393+
Msg("Formed upgrade sequence")
394+
// if no commands just show the tags and return
395+
if buildcmd == "" || envcmd == "" || testcmd == "" {
351396
framework.L.Info().Msg("No envcmd or testcmd provided, skipping")
352397
return nil
353398
}
399+
// checkout the oldest ref
400+
if err := framework.CheckOut(refs[0]); err != nil {
401+
return err
402+
}
403+
404+
// this is a hack allowing us to match what we have in Git to registry or NOP version
405+
// it'd exist until we stabilize tagging strategy
406+
testImgSuffix := c.String("strip-image-suffix")
407+
for i := range refs {
408+
refs[i] = strings.ReplaceAll(refs[i], testImgSuffix, "")
409+
}
410+
411+
// setup the env and verify with test command
412+
framework.L.Info().Strs("Sequence", refs).Msg("Running upgrade sequence")
413+
os.Setenv("CHAINLINK_IMAGE", fmt.Sprintf("%s:%s", registry, refs[0]))
354414
if _, err := framework.ExecCmdWithContext(c.Context, buildcmd); err != nil {
355415
return err
356416
}
@@ -360,16 +420,18 @@ Be aware that any TODO requires your attention before your run the final test!
360420
if _, err := framework.ExecCmdWithContext(c.Context, testcmd); err != nil {
361421
return err
362422
}
363-
// reverse and skip current version
364-
slices.Reverse(tags)
365-
tags = tags[1:]
366-
for _, tag := range tags {
367-
tagToPull := strings.ReplaceAll(tag, "+compat", "")
423+
// start upgrading nodes and verifying with tests, all the versions except the oldest one
424+
for _, tag := range refs[1:] {
425+
framework.L.Info().
426+
Int("Nodes", nodes).
427+
Str("Version", tag).
428+
Msg("Upgrading nodes")
429+
img := fmt.Sprintf("%s:%s", registry, tag)
430+
if _, err := framework.ExecCmdWithContext(c.Context, fmt.Sprintf("docker pull %s", img)); err != nil {
431+
return fmt.Errorf("failed to pull image %s: %w", img, err)
432+
}
368433
for i := range nodes {
369-
if err := framework.UpgradeContainer(
370-
c.Context,
371-
fmt.Sprintf("don-node%d", i),
372-
fmt.Sprintf("%s:%s", registry, tagToPull)); err != nil {
434+
if err := framework.UpgradeContainer(c.Context, fmt.Sprintf(nodeNameTemplate, i), img); err != nil {
373435
return err
374436
}
375437
}

0 commit comments

Comments
 (0)