Skip to content

Commit

Permalink
Implemented mixer reset command
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
ashleshaAtrey committed Sep 10, 2019
1 parent 4e76482 commit 6ac0537
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 27 deletions.
64 changes: 37 additions & 27 deletions builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,34 +369,9 @@ func (b *Builder) BuildUpdate(params UpdateParameters) error {
return nil
}

fmt.Printf("Setting latest version to %s\n", b.MixVer)
latestVerFilePath := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "latest_version")
err = ioutil.WriteFile(latestVerFilePath, []byte(b.MixVer), 0644)
if err != nil {
return errors.Wrapf(err, "couldn't update the latest_version file")
}

// sign the latest_version file
if !params.SkipSigning {
fmt.Println("Signing latest_version file.")
err = b.signFile(latestVerFilePath)
if err != nil {
return errors.Wrapf(err, "couldn't sign the latest_version file")
}
}
err = ioutil.WriteFile(filepath.Join(formatDir, "latest"), []byte(b.MixVer), 0644)
err = b.UpdateLatest(params.SkipSigning)
if err != nil {
return errors.Wrapf(err, "couldn't update the latest version")
}

// sign the latest file in place based on the Mixed format
// read from builder.conf.
if !params.SkipSigning {
fmt.Println("Signing latest file.")
err = b.signFile(filepath.Join(formatDir, "latest"))
if err != nil {
return errors.Wrapf(err, "couldn't sign the latest file")
}
return err
}

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

return nil
}

// UpdateLatest is use to update and sign the latest and latest_version file
func (b *Builder) UpdateLatest(skipSigning bool) error {
formatDir := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "format"+b.State.Mix.Format)
fmt.Printf("Setting latest version to %s\n", b.MixVer)
latestVerFilePath := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "latest_version")
err := ioutil.WriteFile(latestVerFilePath, []byte(b.MixVer), 0644)
if err != nil {
return errors.Wrapf(err, "couldn't update the latest_version file")
}

// sign the latest_version file
if !skipSigning {
fmt.Println("Signing latest_version file.")
err = b.signFile(latestVerFilePath)
if err != nil {
return errors.Wrapf(err, "couldn't sign the latest_version file")
}
}
err = ioutil.WriteFile(filepath.Join(formatDir, "latest"), []byte(b.MixVer), 0644)
if err != nil {
return errors.Wrapf(err, "couldn't update the latest version")
}

// sign the latest file in place based on the Mixed format
// read from builder.conf.
if !skipSigning {
fmt.Println("Signing latest file.")
err = b.signFile(filepath.Join(formatDir, "latest"))
if err != nil {
return errors.Wrapf(err, "couldn't sign the latest file")
}
}
return nil
}
202 changes: 202 additions & 0 deletions mixer/cmd/reset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
// Copyright © 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
"io/ioutil"
"log"
"os"
"path/filepath"
"strconv"
"strings"

"github.com/clearlinux/mixer-tools/builder"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

var resetCmd = &cobra.Command{
Use: "reset",
Short: "Revert the mix to a good state",
Long: `Revert 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`,
Run: runReset,
}

type resetFlags struct {
toVersion int32
clean bool
}

var resetCmdFlags resetFlags

func init() {
RootCmd.AddCommand(resetCmd)

resetCmd.Flags().Int32Var(&resetCmdFlags.toVersion, "to", -1, "Reset to a specific mix version, default = PREVIOUS_MIX_VERSION")
resetCmd.Flags().BoolVar(&resetCmdFlags.clean, "clean", false, "Deletes all files with versions bigger than the one provided")
}

func runReset(cmd *cobra.Command, args []string) {
b, err := builder.NewFromConfig(configFile)
if err != nil {
fail(err)
}

// assuming mixer.state file has the correct info
stateMixPreviousMixVersionUint32, err := parseUint32(b.State.Mix.PreviousMixVer)
if err != nil {
fail(err)
}

// if toVersion provided by the user, replace the default previous version
if resetCmdFlags.toVersion >= 0 && uint32(resetCmdFlags.toVersion) < stateMixPreviousMixVersionUint32 {
b.State.Mix.PreviousMixVer = strconv.Itoa(int(resetCmdFlags.toVersion))
stateMixPreviousMixVersionUint32 = uint32(resetCmdFlags.toVersion)
}

// Make sure FORMAT in mixer.state has the same value as update/www/<previousMixVer>/format
var format []byte
filename := filepath.Join(b.Config.Builder.ServerStateDir, "www", b.State.Mix.PreviousMixVer, "format")
if format, err = ioutil.ReadFile(filename); err != nil {
fail(err)
} else {
if strings.TrimSpace(string(format)) != b.State.Mix.Format {
b.State.Mix.Format = strings.TrimSpace(string(format))
}
}

stateMixPreviousMixFormatUint32, err := parseUint32(b.State.Mix.Format)
if err != nil {
fail(err)
}
// Change upstreamVersion file content to the previous version
var lastStableMixUpstreamVersion []byte
filename = filepath.Join(b.Config.Builder.ServerStateDir, "www", b.State.Mix.PreviousMixVer, "upstreamver")
if lastStableMixUpstreamVersion, err = ioutil.ReadFile(filename); err != nil {
fail(err)
} else {
if strings.TrimSpace(string(lastStableMixUpstreamVersion)) != b.UpstreamVer {
// Set the upstream version to the previous format's latest version
b.UpstreamVer = strings.TrimSpace(string(lastStableMixUpstreamVersion))
b.UpstreamVerUint32, err = parseUint32(b.UpstreamVer)
if err != nil {
fail(errors.Wrapf(err, "Couldn't parse upstream version"))
}
vFile := filepath.Join(b.Config.Builder.VersionPath, b.UpstreamVerFile)
if err = ioutil.WriteFile(vFile, []byte(b.UpstreamVer), 0644); err != nil {
fail(err)
}
}
}

// Change mixVersion to point to the last good build
if err := ioutil.WriteFile(filepath.Join(b.Config.Builder.VersionPath, b.MixVerFile), []byte(b.State.Mix.PreviousMixVer), 0644); err != nil {
fail(err)
}
b.MixVer = b.State.Mix.PreviousMixVer
b.MixVerUint32, err = parseUint32(b.MixVer)
if err != nil {
fail(errors.Wrapf(err, "Couldn't parse mixer version"))
}

// Make sure update/image/LAST_VER points to the last good build
if err = ioutil.WriteFile(filepath.Join(b.Config.Builder.ServerStateDir, "image", "LAST_VER"), []byte(b.State.Mix.PreviousMixVer), 0644); err != nil {
failf("Couldn't update LAST_VER file: %s", err)
}

// update the state.mix file
err = b.State.Save()
if err != nil {
failf("Couldn't update mixer.state file: %s", err)
}

// update www/version/latest_version file and check if sig file exists, if it does, regenerate the signature
// update www/version/formatXX/latest file and update the content, if signature exits , regenerate the signature
var skipSign bool
latestVerSigFilePath := filepath.Join(b.Config.Builder.ServerStateDir, "www", "version", "latest_version.sig")
if format, err = ioutil.ReadFile(latestVerSigFilePath); err != nil {
skipSign = true
}
err = b.UpdateLatest(skipSign)
if err != nil {
fail(err)
}

// if clean flag set
if resetCmdFlags.clean {
// Remove any folder inside update/image for versions above prevMixVer
files, err := ioutil.ReadDir(b.Config.Builder.ServerStateDir + "/image")
if err != nil {
log.Fatal(err)
}

for _, f := range files {
dirNameInt, err := parseUint32(f.Name())
if err != nil {
continue
}
if dirNameInt > stateMixPreviousMixVersionUint32 {
err := os.RemoveAll(b.Config.Builder.ServerStateDir + "/image/" + f.Name())
if err != nil {
continue
}
}
}

// Remove any folder inside update/www for versions above prevMixVer
files, err = ioutil.ReadDir(b.Config.Builder.ServerStateDir + "/www")
if err != nil {
log.Fatal(err)
}

for _, f := range files {
dirNameInt, err := parseUint32(f.Name())
if err != nil {
continue
}
if dirNameInt > stateMixPreviousMixVersionUint32 {
err := os.RemoveAll(b.Config.Builder.ServerStateDir + "/www/" + f.Name())
if err != nil {
continue
}
}
}

// Remove any folder inside update/www/version for formats above prevStableFormats
files, err = ioutil.ReadDir(b.Config.Builder.ServerStateDir + "/www/version")
if err != nil {
log.Fatal(err)
}

for _, f := range files {
dirName := strings.SplitAfter(f.Name(), "format")
if len(dirName) == 2 {
dirNameInt, err := parseUint32(dirName[1])
if err != nil {
continue
}

if dirNameInt > stateMixPreviousMixFormatUint32 {
err := os.RemoveAll(b.Config.Builder.ServerStateDir + "/www/version/" + f.Name())
if err != nil {
continue
}
}
}
}
}
}

0 comments on commit 6ac0537

Please sign in to comment.