Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Versioned visor configs. #364

Merged
merged 13 commits into from
May 21, 2020
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ install-generate: ## Installs required execs for go generate.
# git config --global url.git@github.com:.insteadOf https://github.com/
# Source: https://stackoverflow.com/questions/27500861/whats-the-proper-way-to-go-get-a-private-repository
# We are using 'go get' instead of 'go install' here, because we don't have a git tag in which 'readmegen' is already implemented.
${OPTS} go get -u github.com/SkycoinPro/skywire-services/cmd/readmegen@master
${OPTS} go get -u github.com/SkycoinPro/skywire-services/cmd/readmegen

generate: ## Generate mocks and config README's
go generate ./...
Expand Down
3 changes: 3 additions & 0 deletions ci_scripts/install-golangci-lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ if [[ "$VERSION" != "latest" ]]; then
VERSION="v$VERSION"
fi

if [[ -z "${GOBIN}" ]]; then export GOBIN=$HOME/go/bin; fi
echo "GOBIN=${GOBIN}"

# In alpine linux (as it does not come with curl by default)
wget -O - -q https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b "${GOBIN}" "${VERSION}"

Expand Down
2 changes: 1 addition & 1 deletion cmd/apps/skychat/static.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cmd/hypervisor/statik/statik.go

Large diffs are not rendered by default.

112 changes: 63 additions & 49 deletions cmd/skywire-cli/commands/visor/gen-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,90 +2,104 @@ package visor

import (
"encoding/json"
"fmt"
"io/ioutil"
"path"
"os"
"path/filepath"

"github.com/SkycoinProject/skycoin/src/util/logging"
evanlinjin marked this conversation as resolved.
Show resolved Hide resolved
"github.com/sirupsen/logrus"

"github.com/SkycoinProject/skywire-mainnet/pkg/visor/visorconfig"

"github.com/SkycoinProject/dmsg/cipher"
"github.com/spf13/cobra"

"github.com/SkycoinProject/skywire-mainnet/pkg/util/pathutil"
"github.com/SkycoinProject/skywire-mainnet/pkg/visor"
)

func init() {
RootCmd.AddCommand(genConfigCmd)
}

var (
sk cipher.SecKey
output string
replace bool
retainKeys bool
configLocType = pathutil.WorkingDirLoc
testenv bool
sk cipher.SecKey
output string
replace bool
testEnv bool
)

func init() {
genConfigCmd.Flags().VarP(&sk, "secret-key", "s", "if unspecified, a random key pair will be generated.")
genConfigCmd.Flags().StringVarP(&output, "output", "o", "", "path of output config file. Uses default of 'type' flag if unspecified.")
genConfigCmd.Flags().BoolVarP(&replace, "replace", "r", false, "whether to allow rewrite of a file that already exists.")
genConfigCmd.Flags().BoolVar(&retainKeys, "retain-keys", false, "retain current keys")
genConfigCmd.Flags().BoolVarP(&testenv, "testing-environment", "t", false, "whether to use production or test deployment service.")

// TODO(evanlinjin): Re-implement this at a later stage.
//genConfigCmd.Flags().VarP(&configLocType, "type", "m", fmt.Sprintf("config generation mode. Valid values: %v", pathutil.AllConfigLocationTypes()))
genConfigCmd.Flags().Var(&sk, "sk", "if unspecified, a random key pair will be generated.")
genConfigCmd.Flags().StringVarP(&output, "output", "o", "skywire-config.json", "path of output config file.")
genConfigCmd.Flags().BoolVarP(&replace, "replace", "r", false, "whether to allow rewrite of a file that already exists (this retains the keys).")
genConfigCmd.Flags().BoolVarP(&testEnv, "testenv", "t", false, "whether to use production or test deployment service.")
}

var genConfigCmd = &cobra.Command{
Use: "gen-config",
Short: "Generates a config file",
PreRun: func(_ *cobra.Command, _ []string) {
if output == "" {
output = pathutil.VisorDefaults().Get(configLocType)
logger.Infof("No 'output' set; using default path: %s", output)
}
var err error
if output, err = filepath.Abs(output); err != nil {
logger.WithError(err).Fatalln("invalid output provided")
logger.WithError(err).Fatal("Invalid output provided.")
}
},
Run: func(_ *cobra.Command, _ []string) {
var conf *visor.Config

// TODO(evanlinjin): Decide whether we still need this feature in the future.
// https://github.com/SkycoinProject/skywire-mainnet/pull/360#discussion_r425080223
switch configLocType {
case pathutil.WorkingDirLoc:
var err error
if conf, err = visor.DefaultConfig(nil, output, visor.NewKeyPair()); err != nil {
logger.WithError(err).Fatal("Failed to create default config.")
}
default:
logger.Fatalln("invalid config type:", configLocType)
mLog := logging.NewMasterLogger()
mLog.SetLevel(logrus.InfoLevel)

// Read in old config (if any) and obtain old secret key.
// Otherwise, we generate a new random secret key.
var sk cipher.SecKey
if oldConf, ok := readOldConfig(mLog, output, replace); !ok {
_, sk = cipher.GenerateKeyPair()
} else {
sk = oldConf.SK
}

// Determine config type to generate.
var genConf func(log *logging.MasterLogger, confPath string, sk *cipher.SecKey) (*visorconfig.V1, error)
if testEnv {
genConf = visorconfig.MakeTestConfig
} else {
genConf = visorconfig.MakeDefaultConfig
}
if replace && retainKeys && pathutil.Exists(output) {
if err := fillInOldKeys(output, conf); err != nil {
logger.WithError(err).Fatalln("Error retaining old keys")
}

// Generate config.
conf, err := genConf(mLog, output, &sk)
if err != nil {
logger.WithError(err).Fatal("Failed to create config.")
}
pathutil.WriteJSONConfig(conf, output, replace)

// Save config to file.
if err := conf.Flush(); err != nil {
logger.WithError(err).Fatal("Failed to flush config to file.")
}

// Print results.
j, err := json.MarshalIndent(conf, "", "\t")
if err != nil {
logger.WithError(err).Fatal("An unexpected error occurred. Please contact a developer.")
}
logger.Infof("Updated file '%s' to: %s", output, j)
},
}

func fillInOldKeys(confPath string, conf *visor.Config) error {
oldConfBytes, err := ioutil.ReadFile(path.Clean(confPath))
func readOldConfig(log *logging.MasterLogger, confPath string, replace bool) (*visorconfig.V1, bool) {
raw, err := ioutil.ReadFile(confPath) //nolint:gosec
if err != nil {
return fmt.Errorf("error reading old config file: %w", err)
if os.IsNotExist(err) {
return nil, false
}
logger.WithError(err).Fatal("Unexpected error occurred when attempting to read old config.")
}

var oldConf visor.Config
if err := json.Unmarshal(oldConfBytes, &oldConf); err != nil {
return fmt.Errorf("invalid old configuration file: %w", err)
if !replace {
logger.Fatal("Config file already exists. Specify the 'replace,r' flag to replace this.")
}

conf.KeyPair = oldConf.KeyPair
conf, err := visorconfig.Parse(log, confPath, raw)
if err != nil {
logger.WithError(err).Fatal("Failed to parse old config file.")
}

return nil
return conf, true
}
Loading