Skip to content

Commit

Permalink
feat(cmd/influxd): add --overwrite-existing-v2 flag to influxd upgrade (
Browse files Browse the repository at this point in the history
  • Loading branch information
danxmoran authored Jan 15, 2021
1 parent c797cc1 commit fdc0fdb
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 37 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Replacement `tsi1` indexes will be automatically generated on startup for shards

### Features

1. [19811](https://github.com/influxdata/influxdb/pull/19811): Add Geo graph type to be able to store in Dashboard cells
1. [19811](https://github.com/influxdata/influxdb/pull/19811): Add Geo graph type to be able to store in Dashboard cells.
1. [20473](https://github.com/influxdata/influxdb/pull/20473): Add `--overwrite-existing-v2` flag to `influxd upgrade` to overwrite existing files at output paths (instead of aborting).

### Bug Fixes

Expand Down
119 changes: 87 additions & 32 deletions cmd/influxd/upgrade/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,16 @@ type optionsV2 struct {
enginePath string
cqPath string
configPath string
userName string
password string
orgName string
bucket string
orgID influxdb.ID
userID influxdb.ID
token string
retention string
rmConflicts bool

userName string
password string
orgName string
bucket string
orgID influxdb.ID
userID influxdb.ID
token string
retention string
}

type options struct {
Expand Down Expand Up @@ -264,6 +266,12 @@ func NewCommand(v *viper.Viper) *cobra.Command {
Desc: "skip the confirmation prompt",
Short: 'f',
},
{
DestP: &options.target.rmConflicts,
Flag: "overwrite-existing-v2",
Default: false,
Desc: "if files are present at an output path, overwrite them instead of aborting the upgrade process",
},
}

cli.BindOptions(v, cmd, opts)
Expand Down Expand Up @@ -373,8 +381,14 @@ func runUpgradeE(cmd *cobra.Command, options *options, verbose bool) error {
options.source.dbURL = (&configV1{}).dbURL()
}

err = validatePaths(&options.source, &options.target)
if err != nil {
if err := options.source.validatePaths(); err != nil {
return err
}
checkV2paths := options.target.validatePaths
if options.target.rmConflicts {
checkV2paths = options.target.clearPaths
}
if err := checkV2paths(); err != nil {
return err
}

Expand Down Expand Up @@ -478,54 +492,95 @@ func runUpgradeE(cmd *cobra.Command, options *options, verbose bool) error {
return nil
}

// validatePaths ensures that all filesystem paths provided as input
// are usable by the upgrade command
func validatePaths(sourceOpts *optionsV1, targetOpts *optionsV2) error {
if sourceOpts.dbDir != "" {
fi, err := os.Stat(sourceOpts.dbDir)
// validatePaths ensures that all paths pointing to V1 inputs are usable by the upgrade command.
func (o *optionsV1) validatePaths() error {
if o.dbDir != "" {
fi, err := os.Stat(o.dbDir)
if err != nil {
return fmt.Errorf("1.x DB dir '%s' does not exist", sourceOpts.dbDir)
return fmt.Errorf("1.x DB dir '%s' does not exist", o.dbDir)
}
if !fi.IsDir() {
return fmt.Errorf("1.x DB dir '%s' is not a directory", sourceOpts.dbDir)
return fmt.Errorf("1.x DB dir '%s' is not a directory", o.dbDir)
}
}

metaDb := filepath.Join(sourceOpts.metaDir, "meta.db")
metaDb := filepath.Join(o.metaDir, "meta.db")
_, err := os.Stat(metaDb)
if err != nil {
return fmt.Errorf("1.x meta.db '%s' does not exist", metaDb)
}

if targetOpts.configPath != "" {
if _, err := os.Stat(targetOpts.configPath); err == nil {
return fmt.Errorf("file present at target path for upgraded 2.x config file '%s'", targetOpts.configPath)
return nil
}

// validatePaths ensures that none of the paths pointing to V2 outputs refer to existing files.
func (o *optionsV2) validatePaths() error {
if o.configPath != "" {
if _, err := os.Stat(o.configPath); err == nil {
return fmt.Errorf("file present at target path for upgraded 2.x config file %q", o.configPath)
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking for existing file at %q: %w", o.configPath, err)
}
}

if _, err = os.Stat(targetOpts.boltPath); err == nil {
return fmt.Errorf("file present at target path for upgraded 2.x bolt DB: '%s'", targetOpts.boltPath)
if _, err := os.Stat(o.boltPath); err == nil {
return fmt.Errorf("file present at target path for upgraded 2.x bolt DB: %q", o.boltPath)
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking for existing file at %q: %w", o.boltPath, err)
}

if fi, err := os.Stat(targetOpts.enginePath); err == nil {
if fi, err := os.Stat(o.enginePath); err == nil {
if !fi.IsDir() {
return fmt.Errorf("upgraded 2.x engine path '%s' is not a directory", targetOpts.enginePath)
return fmt.Errorf("upgraded 2.x engine path %q is not a directory", o.enginePath)
}
entries, err := ioutil.ReadDir(targetOpts.enginePath)
entries, err := ioutil.ReadDir(o.enginePath)
if err != nil {
return err
return fmt.Errorf("error checking contents of existing engine directory %q: %w", o.enginePath, err)
}
if len(entries) > 0 {
return fmt.Errorf("upgraded 2.x engine directory '%s' must be empty", targetOpts.enginePath)
return fmt.Errorf("upgraded 2.x engine directory %q must be empty", o.enginePath)
}
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking for existing file at %q: %w", o.enginePath, err)
}

if _, err := os.Stat(o.cliConfigsPath); err == nil {
return fmt.Errorf("file present at target path for 2.x CLI configs %q", o.cliConfigsPath)
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking for existing file at %q: %w", o.cliConfigsPath, err)
}

if _, err := os.Stat(o.cqPath); err == nil {
return fmt.Errorf("file present at target path for exported continuous queries %q", o.cqPath)
} else if !os.IsNotExist(err) {
return fmt.Errorf("error checking for existing file at %q: %w", o.cqPath, err)
}

return nil
}

// clearPaths deletes any files already present at the specified V2 output paths.
func (o *optionsV2) clearPaths() error {
if o.configPath != "" {
if err := os.RemoveAll(o.configPath); err != nil {
return fmt.Errorf("couldn't delete existing file at %q: %w", o.configPath, err)
}
}

if err := os.RemoveAll(o.boltPath); err != nil {
return fmt.Errorf("couldn't delete existing file at %q: %w", o.boltPath, err)
}

if err := os.RemoveAll(o.enginePath); err != nil {
return fmt.Errorf("couldn't delete existing file at %q: %w", o.enginePath, err)
}

if _, err = os.Stat(targetOpts.cliConfigsPath); err == nil {
return fmt.Errorf("file present at target path for 2.x CLI configs '%s'", targetOpts.cliConfigsPath)
if err := os.RemoveAll(o.cliConfigsPath); err != nil {
return fmt.Errorf("couldn't delete existing file at %q: %w", o.cliConfigsPath, err)
}

if _, err = os.Stat(targetOpts.cqPath); err == nil {
return fmt.Errorf("file present at target path for exported continuous queries '%s'", targetOpts.cqPath)
if err := os.RemoveAll(o.cqPath); err != nil {
return fmt.Errorf("couldn't delete existing file at %q: %w", o.cqPath, err)
}

return nil
Expand Down
51 changes: 47 additions & 4 deletions cmd/influxd/upgrade/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,24 @@ func TestPathValidations(t *testing.T) {
enginePath: enginePath,
}

err = validatePaths(sourceOpts, targetOpts)
err = sourceOpts.validatePaths()
require.NotNil(t, err, "Must fail")
assert.Contains(t, err.Error(), "1.x DB dir")

err = os.MkdirAll(filepath.Join(v1Dir, "meta"), 0777)
require.Nil(t, err)

err = validatePaths(sourceOpts, targetOpts)
err = sourceOpts.validatePaths()
require.NotNil(t, err, "Must fail")
assert.Contains(t, err.Error(), "1.x meta.db")

err = ioutil.WriteFile(filepath.Join(v1Dir, "meta", "meta.db"), []byte{1}, 0777)
require.Nil(t, err)

err = validatePaths(sourceOpts, targetOpts)
err = sourceOpts.validatePaths()
require.Nil(t, err)

err = targetOpts.validatePaths()
require.NotNil(t, err, "Must fail")
assert.Contains(t, err.Error(), "2.x engine")

Expand All @@ -65,11 +68,51 @@ func TestPathValidations(t *testing.T) {
err = ioutil.WriteFile(configsPath, []byte{1}, 0777)
require.Nil(t, err)

err = validatePaths(sourceOpts, targetOpts)
err = targetOpts.validatePaths()
require.NotNil(t, err, "Must fail")
assert.Contains(t, err.Error(), "2.x CLI configs")
}

func TestClearTargetPaths(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "")
require.NoError(t, err)

defer os.RemoveAll(tmpdir)

v2Dir := filepath.Join(tmpdir, "v2db")
boltPath := filepath.Join(v2Dir, bolt.DefaultFilename)
configsPath := filepath.Join(v2Dir, "configs")
enginePath := filepath.Join(v2Dir, "engine")
cqPath := filepath.Join(v2Dir, "cqs")
configPath := filepath.Join(v2Dir, "config")

err = os.MkdirAll(filepath.Join(enginePath, "db"), 0777)
require.NoError(t, err)
err = ioutil.WriteFile(boltPath, []byte{1}, 0777)
require.NoError(t, err)
err = ioutil.WriteFile(configsPath, []byte{1}, 0777)
require.NoError(t, err)
err = ioutil.WriteFile(cqPath, []byte{1}, 0777)
require.NoError(t, err)
err = ioutil.WriteFile(configPath, []byte{1}, 0777)
require.NoError(t, err)

targetOpts := &optionsV2{
boltPath: boltPath,
cliConfigsPath: configsPath,
enginePath: enginePath,
configPath: configPath,
cqPath: cqPath,
}

err = targetOpts.validatePaths()
require.Error(t, err)
err = targetOpts.clearPaths()
require.NoError(t, err)
err = targetOpts.validatePaths()
require.NoError(t, err)
}

func TestDbURL(t *testing.T) {

type testCase struct {
Expand Down

0 comments on commit fdc0fdb

Please sign in to comment.