Skip to content
This repository was archived by the owner on Aug 7, 2025. It is now read-only.

Commit 2a433a4

Browse files
committed
Implemented mixer reset command
It reverts the mix to a good state in case of a build failure or in case the user wants to roll back to a previous version. By default, the command will bring back the mix to the same state it have when it last build a successful mix. This value can be overridden if a `--to` flag is provided with a version number. The command will not be destructive unless a `--clean` flag is provided specified. If so, mixer will delete all files associated with versions that are bigger than the one provided. If not, only the values of the state files will change, but the files will be kept. Signed-off-by: Ashlesha Atrey <ashlesha.atrey@intel.com>
1 parent 4e76482 commit 2a433a4

5 files changed

Lines changed: 290 additions & 27 deletions

File tree

bat/tests/reset-command/Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.PHONY: check clean
2+
3+
check:
4+
bats ./run.bats
5+
6+
CLEANDIRS = ./update ./test-chroot ./logs ./.repos ./bundles ./update ./mix-bundles ./clr-bundles ./local-yum ./results ./repodata ./local-rpms ./upstream-bundles ./local-bundles
7+
CLEANFILES = ./*.log ./run.bats.trs ./yum.conf.in ./builder.conf ./mixer.state ./.{c,m}* *.pem .yum-mix.conf mixversion upstreamurl upstreamversion mixbundles
8+
clean:
9+
sudo rm -rf $(CLEANDIRS) $(CLEANFILES)
10+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
reset
2+
====================
3+
This test attempts to create multiple mixes of different upstream version
4+
in different format. It then tries to revert the mix to a previous stable
5+
version. If clean flag is set, mixer will delete all files associated with
6+
versions that are bigger than the one provided.
7+

bat/tests/reset-command/run.bats

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env bats
2+
3+
# shared test functions
4+
load ../../lib/mixerlib
5+
6+
setup() {
7+
global_setup
8+
}
9+
10+
@test "reset" {
11+
mixer-init-stripped-down 27310 10
12+
mixer build all --format 30 --native
13+
mixer versions update --upstream-version 30000
14+
mixer build upstream-format --new-format 28 --native
15+
sudo mixer versions update --upstream-version 30800
16+
mixer build upstream-format --new-format 20 --native
17+
#check LAST_VER and PREVIOUS_MIX_VERSION match
18+
test $(< update/image/LAST_VER) -eq 50
19+
test $(sed -n 's/[ ]*PREVIOUS_MIX_VERSION[ ="]*\([0-9]\+\)[ "]*/\1/p' mixer.state) -eq 50
20+
mixer reset --to 40
21+
#check LAST_VER and PREVIOUS_MIX_VERSION match
22+
test $(< update/image/LAST_VER) -eq 40
23+
test $(sed -n 's/[ ]*PREVIOUS_MIX_VERSION[ ="]*\([0-9]\+\)[ "]*/\1/p' mixer.state) -eq 40
24+
test -d "./update/www/50"
25+
test -d "./update/image/50"
26+
mixer reset --to 30 --clean
27+
#check LAST_VER and PREVIOUS_MIX_VERSION match
28+
test $(< update/image/LAST_VER) -eq 30
29+
test $(sed -n 's/[ ]*PREVIOUS_MIX_VERSION[ ="]*\([0-9]\+\)[ "]*/\1/p' mixer.state) -eq 30
30+
test ! -d "./update/www/40"
31+
test ! -d "./update/image/40"
32+
}
33+
# vi: ft=sh ts=8 sw=2 sts=2 et tw=80
34+

builder/builder.go

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -369,34 +369,9 @@ func (b *Builder) BuildUpdate(params UpdateParameters) error {
369369
return nil
370370
}
371371

372-
fmt.Printf("Setting latest version to %s\n", b.MixVer)
373-
latestVerFilePath := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "latest_version")
374-
err = ioutil.WriteFile(latestVerFilePath, []byte(b.MixVer), 0644)
375-
if err != nil {
376-
return errors.Wrapf(err, "couldn't update the latest_version file")
377-
}
378-
379-
// sign the latest_version file
380-
if !params.SkipSigning {
381-
fmt.Println("Signing latest_version file.")
382-
err = b.signFile(latestVerFilePath)
383-
if err != nil {
384-
return errors.Wrapf(err, "couldn't sign the latest_version file")
385-
}
386-
}
387-
err = ioutil.WriteFile(filepath.Join(formatDir, "latest"), []byte(b.MixVer), 0644)
372+
err = b.UpdateLatest(params.SkipSigning)
388373
if err != nil {
389-
return errors.Wrapf(err, "couldn't update the latest version")
390-
}
391-
392-
// sign the latest file in place based on the Mixed format
393-
// read from builder.conf.
394-
if !params.SkipSigning {
395-
fmt.Println("Signing latest file.")
396-
err = b.signFile(filepath.Join(formatDir, "latest"))
397-
if err != nil {
398-
return errors.Wrapf(err, "couldn't sign the latest file")
399-
}
374+
return err
400375
}
401376

402377
err = ioutil.WriteFile(filepath.Join(b.Config.Builder.ServerStateDir, "image", "LAST_VER"), []byte(b.MixVer), 0644)
@@ -762,3 +737,39 @@ func (b *Builder) BuildDeltaManifestsPreviousVersions(prev, to uint32) error {
762737

763738
return nil
764739
}
740+
741+
// UpdateLatest is use to update and sign the latest and latest_version file
742+
func (b *Builder) UpdateLatest(skipSigning bool) error {
743+
formatDir := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "format"+b.State.Mix.Format)
744+
fmt.Printf("Setting latest version to %s\n", b.MixVer)
745+
latestVerFilePath := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "latest_version")
746+
err := ioutil.WriteFile(latestVerFilePath, []byte(b.MixVer), 0644)
747+
if err != nil {
748+
return errors.Wrapf(err, "couldn't update the latest_version file")
749+
}
750+
751+
// sign the latest_version file
752+
if !skipSigning {
753+
fmt.Println("Signing latest_version file.")
754+
err = b.signFile(latestVerFilePath)
755+
if err != nil {
756+
return errors.Wrapf(err, "couldn't sign the latest_version file")
757+
}
758+
}
759+
err = ioutil.WriteFile(filepath.Join(formatDir, "latest"), []byte(b.MixVer), 0644)
760+
if err != nil {
761+
return errors.Wrapf(err, "couldn't update the latest version")
762+
}
763+
764+
// sign the latest file in place based on the Mixed format
765+
// read from builder.conf.
766+
if !skipSigning {
767+
fmt.Println("Signing latest file.")
768+
err = b.signFile(filepath.Join(formatDir, "latest"))
769+
if err != nil {
770+
return errors.Wrapf(err, "couldn't sign the latest file")
771+
}
772+
}
773+
return nil
774+
}
775+

mixer/cmd/reset.go

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// Copyright © 2018 Intel Corporation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
"io/ioutil"
19+
"log"
20+
"os"
21+
"path/filepath"
22+
"strconv"
23+
"strings"
24+
25+
"github.com/clearlinux/mixer-tools/builder"
26+
"github.com/pkg/errors"
27+
"github.com/spf13/cobra"
28+
)
29+
30+
var resetCmd = &cobra.Command{
31+
Use: "reset",
32+
Short: "Revert the mix to a good state",
33+
Long: `Revert the mix to a good state in case of a build
34+
failure or in case the user wants to roll back to a previous
35+
version`,
36+
Run: runReset,
37+
}
38+
39+
type resetFlags struct {
40+
toVersion int32
41+
clean bool
42+
}
43+
44+
var resetCmdFlags resetFlags
45+
46+
func init() {
47+
RootCmd.AddCommand(resetCmd)
48+
49+
resetCmd.Flags().Int32Var(&resetCmdFlags.toVersion, "to", -1, "Reset to a specific mix version, default = PREVIOUS_MIX_VERSION")
50+
resetCmd.Flags().BoolVar(&resetCmdFlags.clean, "clean", false, "Deletes all files with versions bigger than the one provided")
51+
}
52+
53+
func runReset(cmd *cobra.Command, args []string) {
54+
b, err := builder.NewFromConfig(configFile)
55+
if err != nil {
56+
fail(err)
57+
}
58+
59+
// assuming mixer.state file has the correct info
60+
stateMixPreviousMixVersionUint32, err := parseUint32(b.State.Mix.PreviousMixVer)
61+
if err != nil {
62+
fail(err)
63+
}
64+
65+
// if toVersion provided by the user, replace the default previous version
66+
if resetCmdFlags.toVersion >= 0 {
67+
b.State.Mix.PreviousMixVer = strconv.Itoa(int(resetCmdFlags.toVersion))
68+
stateMixPreviousMixVersionUint32 = uint32(resetCmdFlags.toVersion)
69+
}
70+
71+
// Make sure FORMAT in mixer.state has the same value as update/www/<previousMixVer>/format
72+
var format []byte
73+
filename := filepath.Join(b.Config.Builder.ServerStateDir, "www", b.State.Mix.PreviousMixVer, "format")
74+
if format, err = ioutil.ReadFile(filename); err != nil {
75+
fail(err)
76+
} else {
77+
if strings.TrimSpace(string(format)) != b.State.Mix.Format {
78+
b.State.Mix.Format = strings.TrimSpace(string(format))
79+
}
80+
}
81+
82+
// Change upstreamVersion file content to the previous version
83+
var lastStableMixUpstreamVersion []byte
84+
filename = filepath.Join(b.Config.Builder.ServerStateDir, "www", b.State.Mix.PreviousMixVer, "upstreamver")
85+
if lastStableMixUpstreamVersion, err = ioutil.ReadFile(filename); err != nil {
86+
fail(err)
87+
} else {
88+
if strings.TrimSpace(string(lastStableMixUpstreamVersion)) != b.UpstreamVer {
89+
// Set the upstream version to the previous format's latest version
90+
b.UpstreamVer = strings.TrimSpace(string(lastStableMixUpstreamVersion))
91+
b.UpstreamVerUint32, err = parseUint32(b.UpstreamVer)
92+
if err != nil {
93+
fail(errors.Wrapf(err, "Couldn't parse upstream version"))
94+
}
95+
vFile := filepath.Join(b.Config.Builder.VersionPath, b.UpstreamVerFile)
96+
if err = ioutil.WriteFile(vFile, []byte(b.UpstreamVer), 0644); err != nil {
97+
fail(err)
98+
}
99+
}
100+
}
101+
102+
// Change mixVersion to point to the last good build
103+
if err := ioutil.WriteFile(filepath.Join(b.Config.Builder.VersionPath, b.MixVerFile), []byte(b.State.Mix.PreviousMixVer), 0644); err != nil {
104+
fail(err)
105+
}
106+
b.MixVer = b.State.Mix.PreviousMixVer
107+
b.MixVerUint32, err = parseUint32(b.MixVer)
108+
if err != nil {
109+
fail(errors.Wrapf(err, "Couldn't parse mixer version"))
110+
}
111+
112+
// Make sure update/image/LAST_VER points to the last good build
113+
if err = ioutil.WriteFile(filepath.Join(b.Config.Builder.ServerStateDir, "image", "LAST_VER"), []byte(b.State.Mix.PreviousMixVer), 0644); err != nil {
114+
failf("Couldn't update LAST_VER file: %s", err)
115+
}
116+
117+
// update the state.mix file
118+
err = b.State.Save()
119+
if err != nil {
120+
failf("Couldn't update mixer.state file: %s", err)
121+
}
122+
123+
// update www/version/latest_version file and check if sig file exists, if it does, regenerate the signature
124+
// update www/version/formatXX/latest file and update the content, if signature exits , regenerate the signature
125+
var skipSign bool
126+
latestVerSigFilePath := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "latest_version.sig")
127+
if _, err = ioutil.ReadFile(latestVerSigFilePath); err != nil {
128+
skipSign = true
129+
}
130+
err = b.UpdateLatest(skipSign)
131+
if err != nil {
132+
fail(err)
133+
}
134+
135+
// if clean flag set
136+
if resetCmdFlags.clean {
137+
// Remove any folder inside update/image for versions above prevMixVer
138+
files, err := ioutil.ReadDir(b.Config.Builder.ServerStateDir + "/image")
139+
if err != nil {
140+
log.Fatal(err)
141+
}
142+
143+
for _, f := range files {
144+
dirNameInt, err := parseUint32(f.Name())
145+
if err != nil {
146+
continue
147+
}
148+
if dirNameInt > stateMixPreviousMixVersionUint32 {
149+
err := os.RemoveAll(b.Config.Builder.ServerStateDir + "/image/" + f.Name())
150+
if err != nil {
151+
continue
152+
}
153+
}
154+
}
155+
156+
// Remove any folder inside update/www for versions above prevMixVer
157+
files, err = ioutil.ReadDir(b.Config.Builder.ServerStateDir + "/www")
158+
if err != nil {
159+
log.Fatal(err)
160+
}
161+
162+
for _, f := range files {
163+
dirNameInt, err := parseUint32(f.Name())
164+
if err != nil {
165+
continue
166+
}
167+
if dirNameInt > stateMixPreviousMixVersionUint32 {
168+
err := os.RemoveAll(b.Config.Builder.ServerStateDir + "/www/" + f.Name())
169+
if err != nil {
170+
continue
171+
}
172+
}
173+
}
174+
175+
// Remove any folder inside update/www/version/ for version above prevStableVersion
176+
files, err = ioutil.ReadDir(b.Config.Builder.ServerStateDir + "/www/version")
177+
if err != nil {
178+
log.Fatal(err)
179+
}
180+
// iterate over all the formats folder
181+
for _, f := range files {
182+
// read the latest file and extract the version
183+
var version []byte
184+
if version, err = ioutil.ReadFile(b.Config.Builder.ServerStateDir + "/www/version/" + f.Name() + "/latest"); err != nil {
185+
continue
186+
}
187+
versionInt, err := parseUint32(strings.TrimSpace(string(version)))
188+
if err != nil {
189+
continue
190+
}
191+
// if version > previousMixVersion
192+
if versionInt > stateMixPreviousMixVersionUint32 {
193+
err := os.RemoveAll(b.Config.Builder.ServerStateDir + "/www/version/" + f.Name())
194+
if err != nil {
195+
continue
196+
}
197+
}
198+
}
199+
}
200+
}
201+

0 commit comments

Comments
 (0)