Skip to content

Commit

Permalink
Merge pull request #13 from threefoldtech/development_rollout_configs
Browse files Browse the repository at this point in the history
add rollout configs for version updates
  • Loading branch information
rawdaGastan authored Oct 31, 2024
2 parents 8430395 + 65ad5f6 commit 05f0360
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 17 deletions.
3 changes: 3 additions & 0 deletions pkg/environment/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type Config struct {
Users struct {
Authorized []string `json:"authorized"`
} `json:"users"`
RolloutUpgrade struct {
TestFarms []uint32 `json:"test_farms"`
} `json:"rollout_upgrade"`
}

// Merge, updates current config with cfg merging and override config
Expand Down
10 changes: 6 additions & 4 deletions pkg/upgrade/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

The upgrade module is responsible to keep a zos node always up to date.

It checks the hub for new releases of zos packages.
It checks the hub for new releases of zos packages. Also check version and `safe_to_upgrade` flag from the chain.

If a new release is available, it will then update the packages and restart the updated module with the new binaries if required.
If `safe_to_upgrade` is set to `false` and a new release is available then it will only update the [configured farms](https://github.com/threefoldtech/zos-config/blob/main/config.schema.json#L49)

If `safe_to_upgrade` is set to `true` and a new release is available, it will then update the packages and restart the updated module with the new binaries if required.

## Usage

Expand All @@ -27,14 +29,14 @@ Then run the upgrader `upgrader.Run(ctx)`

## How it works

The upgrader module has two running modes depeding on the booting method.
The upgrader module has two running modes depending on the booting method.

### Bootstrap Method

Running the upgrader on a node run with `bootstrap` will periodically check the hub for latest tag,
and if that tag differs from the current one, it updates the local packages to latest.

If the update failed, the upgrader would attempts to install the packages again every `10 secounds` until all packages are successfully updated to prevent partial updates.
If the update failed, the upgrader would attempts to install the packages again every `10 seconds` until all packages are successfully updated to prevent partial updates.

The upgrader runs periodically every hour to check for new updates.

Expand Down
62 changes: 61 additions & 1 deletion pkg/upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package upgrade

import (
"context"
"encoding/json"
"fmt"
"io"
"math/rand"
Expand All @@ -19,7 +20,9 @@ import (
"github.com/threefoldtech/0-fs/meta"
"github.com/threefoldtech/0-fs/rofs"
"github.com/threefoldtech/0-fs/storage"
substrate "github.com/threefoldtech/tfchain/clients/tfchain-client-go"
"github.com/threefoldtech/zos4/pkg/app"
"github.com/threefoldtech/zos4/pkg/environment"
"github.com/threefoldtech/zos4/pkg/upgrade/hub"
"github.com/threefoldtech/zos4/pkg/zinit"

Expand Down Expand Up @@ -48,6 +51,42 @@ const (
ZosPackage = "zos.flist"
)

type ChainVersion struct {
SafeToUpgrade bool `json:"safe_to_upgrade"`
Version string `json:"version"`
}

func getRolloutConfig(env environment.Environment) (ChainVersion, []uint32, error) {
config, err := environment.GetConfig()
if err != nil {
return ChainVersion{}, nil, errors.Wrap(err, "failed to get network config")
}

manager := substrate.NewManager(env.SubstrateURL...)

con, err := manager.Substrate()
if err != nil {
return ChainVersion{}, nil, err
}

v, err := con.GetZosVersion()
if err != nil {
return ChainVersion{}, nil, errors.Wrap(err, "failed to get zos version from chain")
}

var chainVersion ChainVersion
err = json.Unmarshal([]byte(v), &chainVersion)
if err != nil {
log.Debug().Err(err).Msg("failed to unmarshal chain version and safe to upgrade flag")
chainVersion = ChainVersion{
SafeToUpgrade: true,
Version: v,
}
}

return chainVersion, config.RolloutUpgrade.TestFarms, nil
}

// Upgrader is the component that is responsible
// to keep 0-OS up to date
type Upgrader struct {
Expand Down Expand Up @@ -131,7 +170,7 @@ func NewUpgrader(root string, opts ...UpgraderOption) (*Upgrader, error) {
return u, nil
}

// Run strats the upgrader module and run the update according to the detected boot method
// Run starts the upgrader module and run the update according to the detected boot method
func (u *Upgrader) Run(ctx context.Context) error {
method := u.boot.DetectBootMethod()
if method == BootMethodOther {
Expand Down Expand Up @@ -236,6 +275,27 @@ func (u *Upgrader) update() error {
return nil
}

env := environment.MustGet()
chainVer, testFarms, err := getRolloutConfig(env)
if err != nil {
return errors.Wrap(err, "failed to get rollout config and version")
}

remoteVer := remote.Target[strings.LastIndex(remote.Target, "/")+1:]

if env.RunningMode != environment.RunningDev && remoteVer != chainVer.Version {
// nothing to do! hub version is not the same as the chain
return nil
}

if !chainVer.SafeToUpgrade {
if !slices.Contains(testFarms, uint32(env.FarmID)) {
// nothing to do! waiting for the flag `safe to upgrade to be enabled after A/B testing`
// node is not a part of A/B testing
return nil
}
}

log.Info().Str("version", filepath.Base(remote.Target)).Msg("updating system...")
if err := u.updateTo(remote, &current); err != nil {
return errors.Wrapf(err, "failed to update to new tag '%s'", remote.Target)
Expand Down
31 changes: 19 additions & 12 deletions tools/zos-update-worker/internal/update_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,24 @@ func (w *Worker) updateZosVersion(network Network, manager client.Manager) error
}
defer con.Close()

currentZosVersions, err := con.GetZosVersion()
currentZosVersion, err := con.GetZosVersion()
if err != nil {
return err
}

type ZosVersions struct {
Zos string
ZosLight string
type ChainVersion struct {
SafeToUpgrade bool `json:"safe_to_upgrade"`
Version string `json:"version"`
}
versions := ZosVersions{}

err = json.Unmarshal([]byte(currentZosVersions), &versions)
var chainVersion ChainVersion
err = json.Unmarshal([]byte(currentZosVersion), &chainVersion)
if err != nil {
return err
log.Debug().Err(err).Msg("failed to unmarshal chain version")
chainVersion.Version = currentZosVersion
}
log.Debug().Msgf("getting substrate version %v for network %v", versions, network)

log.Debug().Msgf("getting substrate version %v for network %v", chainVersion.Version, network)

// now we need to find how dst is relative to src
path, err := filepath.Rel(w.dst, w.src)
Expand All @@ -128,16 +130,16 @@ func (w *Worker) updateZosVersion(network Network, manager client.Manager) error
}

//zos
zosCurrent := fmt.Sprintf("%v/.tag-%v", w.src, versions.Zos)
zosCurrent := fmt.Sprintf("%v/.tag-%v", w.src, chainVersion.Version)
zosLatest := fmt.Sprintf("%v/%v", w.dst, network)
// zos light
zosLightCurrent := fmt.Sprintf("%v/.tag-%v", w.src, versions.ZosLight)
zosLightCurrent := fmt.Sprintf("%v/.tag-%v", w.src, chainVersion.Version)
zosLightLatest := fmt.Sprintf("%v/%v-v4", w.dst, network)
// the link is like zosCurrent but it has the path relative from the symlink
// point of view (so relative to the symlink, how to reach zosCurrent)
// hence the link is instead used in all calls to symlink
zosLink := fmt.Sprintf("%v/.tag-%v", path, versions.Zos)
zosLightLink := fmt.Sprintf("%v/.tag-%v", path, versions.ZosLight)
zosLink := fmt.Sprintf("%v/.tag-%v", path, chainVersion.Version)
zosLightLink := fmt.Sprintf("%v/.tag-%v", path, chainVersion.Version)

// update links for both zos and zoslight
if err = w.updateLink(zosCurrent, zosLatest, zosLink); err != nil {
Expand All @@ -147,6 +149,11 @@ func (w *Worker) updateZosVersion(network Network, manager client.Manager) error
}

func (w *Worker) updateLink(current string, latest string, link string) error {
// check if current exists
if _, err := os.Lstat(current); err != nil {
return err
}

// check if symlink exists
dst, err := os.Readlink(latest)

Expand Down

0 comments on commit 05f0360

Please sign in to comment.