1
0
mirror of https://github.com/minio/mc.git synced 2025-11-10 13:42:32 +03:00
Files
mc/cmd/config-migrate.go

485 lines
15 KiB
Go

/*
* MinIO Client (C) 2015 MinIO, Inc.
*
* 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 (
"fmt"
"strings"
"github.com/minio/mc/pkg/console"
"github.com/minio/mc/pkg/probe"
"github.com/minio/minio/pkg/quick"
)
// migrate config files from the any older version to the latest.
func migrateConfig() {
// Migrate config V1 to V101
migrateConfigV1ToV101()
// Migrate config V101 to V2
migrateConfigV101ToV2()
// Migrate config V2 to V3
migrateConfigV2ToV3()
// Migrate config V3 to V4
migrateConfigV3ToV4()
// Migrate config V4 to V5
migrateConfigV4ToV5()
// Migrate config V5 to V6
migrateConfigV5ToV6()
// Migrate config V6 to V7
migrateConfigV6ToV7()
// Migrate config V7 to V8
migrateConfigV7ToV8()
// Migrate config V8 to V9
migrateConfigV8ToV9()
}
// Migrate from config version 1.0 to 1.0.1. Populate example entries and save it back.
func migrateConfigV1ToV101() {
if !isMcConfigExists() {
return
}
mcCfgV1, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV1())
fatalIf(probe.NewError(e), "Unable to load config version `1`.")
// If loaded config version does not match 1.0.0, we do nothing.
if mcCfgV1.Version() != "1.0.0" {
return
}
// 1.0.1 is compatible to 1.0.0. We are just adding new entries.
cfgV101 := newConfigV101()
// Copy aliases.
for k, v := range mcCfgV1.Data().(*configV1).Aliases {
cfgV101.Aliases[k] = v
}
// Copy hosts.
for k, hostCfgV1 := range mcCfgV1.Data().(*configV1).Hosts {
cfgV101.Hosts[k] = hostConfigV101{
AccessKeyID: hostCfgV1.AccessKeyID,
SecretAccessKey: hostCfgV1.SecretAccessKey,
}
}
// Example localhost entry.
if _, ok := cfgV101.Hosts["localhost:*"]; !ok {
cfgV101.Hosts["localhost:*"] = hostConfigV101{}
}
// Example loopback IP entry.
if _, ok := cfgV101.Hosts["127.0.0.1:*"]; !ok {
cfgV101.Hosts["127.0.0.1:*"] = hostConfigV101{}
}
// Example AWS entry.
// Look for glob string (not glob match). We used to support glob based key matching earlier.
if _, ok := cfgV101.Hosts["*.s3*.amazonaws.com"]; !ok {
cfgV101.Hosts["*.s3*.amazonaws.com"] = hostConfigV101{
AccessKeyID: "YOUR-ACCESS-KEY-ID-HERE",
SecretAccessKey: "YOUR-SECRET-ACCESS-KEY-HERE",
}
}
// Save the new config back to the disk.
mcCfgV101, e := quick.NewConfig(cfgV101, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `1.0.1`.")
e = mcCfgV101.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `1.0.1`.")
console.Infof("Successfully migrated %s from version `1.0.0` to version `1.0.1`.\n", mustGetMcConfigPath())
}
// Migrate from config `1.0.1` to `2`. Drop semantic versioning and move to integer versioning. No other changes.
func migrateConfigV101ToV2() {
if !isMcConfigExists() {
return
}
mcCfgV101, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV101())
fatalIf(probe.NewError(e), "Unable to load config version `1.0.1`.")
// update to newer version
if mcCfgV101.Version() != "1.0.1" {
return
}
cfgV2 := newConfigV2()
// Copy aliases.
for k, v := range mcCfgV101.Data().(*configV101).Aliases {
cfgV2.Aliases[k] = v
}
// Copy hosts.
for k, hostCfgV101 := range mcCfgV101.Data().(*configV101).Hosts {
cfgV2.Hosts[k] = hostConfigV2{
AccessKeyID: hostCfgV101.AccessKeyID,
SecretAccessKey: hostCfgV101.SecretAccessKey,
}
}
mcCfgV2, e := quick.NewConfig(cfgV2, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `2`.")
e = mcCfgV2.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `2`.")
console.Infof("Successfully migrated %s from version `1.0.1` to version `2`.\n", mustGetMcConfigPath())
}
// Migrate from config `2` to `3`. Use `-` separated names for
// hostConfig using struct json tags.
func migrateConfigV2ToV3() {
if !isMcConfigExists() {
return
}
mcCfgV2, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV2())
fatalIf(probe.NewError(e), "Unable to load mc config V2.")
// update to newer version
if mcCfgV2.Version() != "2" {
return
}
cfgV3 := newConfigV3()
// Copy aliases.
for k, v := range mcCfgV2.Data().(*configV2).Aliases {
cfgV3.Aliases[k] = v
}
// Copy hosts.
for k, hostCfgV2 := range mcCfgV2.Data().(*configV2).Hosts {
// New hostConfV3 uses struct json tags.
cfgV3.Hosts[k] = hostConfigV3{
AccessKeyID: hostCfgV2.AccessKeyID,
SecretAccessKey: hostCfgV2.SecretAccessKey,
}
}
mcNewCfgV3, e := quick.NewConfig(cfgV3, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `3`.")
e = mcNewCfgV3.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `3`.")
console.Infof("Successfully migrated %s from version `2` to version `3`.\n", mustGetMcConfigPath())
}
// Migrate from config version `3` to `4`. Introduce API Signature
// field in host config. Also Use JavaScript notation for field names.
func migrateConfigV3ToV4() {
if !isMcConfigExists() {
return
}
mcCfgV3, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV3())
fatalIf(probe.NewError(e), "Unable to load mc config V2.")
// update to newer version
if mcCfgV3.Version() != "3" {
return
}
cfgV4 := newConfigV4()
for k, v := range mcCfgV3.Data().(*configV3).Aliases {
cfgV4.Aliases[k] = v
}
// New hostConfig has API signature. All older entries were V4
// only. So it is safe to assume V4 as default for all older
// entries.
// HostConfigV4 als uses JavaScript naming notation for struct JSON tags.
for host, hostCfgV3 := range mcCfgV3.Data().(*configV3).Hosts {
cfgV4.Hosts[host] = hostConfigV4{
AccessKeyID: hostCfgV3.AccessKeyID,
SecretAccessKey: hostCfgV3.SecretAccessKey,
Signature: "v4",
}
}
mcNewCfgV4, e := quick.NewConfig(cfgV4, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `4`.")
e = mcNewCfgV4.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `4`.")
console.Infof("Successfully migrated %s from version `3` to version `4`.\n", mustGetMcConfigPath())
}
// Migrate config version `4` to `5`. Rename hostConfigV4.Signature -> hostConfigV5.API.
func migrateConfigV4ToV5() {
if !isMcConfigExists() {
return
}
mcCfgV4, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV4())
fatalIf(probe.NewError(e), "Unable to load mc config V4.")
// update to newer version
if mcCfgV4.Version() != "4" {
return
}
cfgV5 := newConfigV5()
for k, v := range mcCfgV4.Data().(*configV4).Aliases {
cfgV5.Aliases[k] = v
}
for host, hostCfgV4 := range mcCfgV4.Data().(*configV4).Hosts {
cfgV5.Hosts[host] = hostConfigV5{
AccessKeyID: hostCfgV4.AccessKeyID,
SecretAccessKey: hostCfgV4.SecretAccessKey,
API: "v4", // Rename from .Signature to .API
}
}
mcNewCfgV5, e := quick.NewConfig(cfgV5, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `5`.")
e = mcNewCfgV5.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `5`.")
console.Infof("Successfully migrated %s from version `4` to version `5`.\n", mustGetMcConfigPath())
}
// Migrate config version `5` to `6`. Add google cloud storage servers
// to host config. Also remove "." from s3 aws glob rule.
func migrateConfigV5ToV6() {
if !isMcConfigExists() {
return
}
mcCfgV5, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV5())
fatalIf(probe.NewError(e), "Unable to load mc config V5.")
// update to newer version
if mcCfgV5.Version() != "5" {
return
}
cfgV6 := newConfigV6()
// Add new Google Cloud Storage alias.
cfgV6.Aliases["gcs"] = "https://storage.googleapis.com"
for k, v := range mcCfgV5.Data().(*configV5).Aliases {
cfgV6.Aliases[k] = v
}
// Add defaults.
cfgV6.Hosts["*s3*amazonaws.com"] = hostConfigV6{
AccessKeyID: "YOUR-ACCESS-KEY-ID-HERE",
SecretAccessKey: "YOUR-SECRET-ACCESS-KEY-HERE",
API: "S3v4",
}
cfgV6.Hosts["*storage.googleapis.com"] = hostConfigV6{
AccessKeyID: "YOUR-ACCESS-KEY-ID-HERE",
SecretAccessKey: "YOUR-SECRET-ACCESS-KEY-HERE",
API: "S3v2",
}
for host, hostCfgV5 := range mcCfgV5.Data().(*configV5).Hosts {
// Find any matching s3 entry and copy keys from it to newer generalized glob entry.
if strings.Contains(host, "s3") {
if (hostCfgV5.AccessKeyID == "YOUR-ACCESS-KEY-ID-HERE") ||
(hostCfgV5.SecretAccessKey == "YOUR-SECRET-ACCESS-KEY-HERE") ||
hostCfgV5.AccessKeyID == "" ||
hostCfgV5.SecretAccessKey == "" {
continue // Skip defaults.
}
// Now we have real keys set by the user. Copy
// them over to newer glob rule.
// Original host entry has "." in the glob rule.
host = "*s3*amazonaws.com" // Use this glob entry.
}
cfgV6.Hosts[host] = hostConfigV6{
AccessKeyID: hostCfgV5.AccessKeyID,
SecretAccessKey: hostCfgV5.SecretAccessKey,
API: hostCfgV5.API,
}
}
mcNewCfgV6, e := quick.NewConfig(cfgV6, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `6`.")
e = mcNewCfgV6.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `6`.")
console.Infof("Successfully migrated %s from version `5` to version `6`.\n", mustGetMcConfigPath())
}
// Migrate config version `6` to `7'. Remove alias map and introduce
// named Host config. Also no more glob match for host config entries.
func migrateConfigV6ToV7() {
if !isMcConfigExists() {
return
}
mcCfgV6, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV6())
fatalIf(probe.NewError(e), "Unable to load mc config V6.")
if mcCfgV6.Version() != "6" {
return
}
cfgV7 := newConfigV7()
aliasIndex := 0
// old Aliases.
oldAliases := mcCfgV6.Data().(*configV6).Aliases
// We dropped alias support in v7. We only need to migrate host configs.
for host, hostCfgV6 := range mcCfgV6.Data().(*configV6).Hosts {
// Look through old aliases, if found any matching save those entries.
for aliasName, aliasedHost := range oldAliases {
if aliasedHost == host {
cfgV7.Hosts[aliasName] = hostConfigV7{
URL: host,
AccessKey: hostCfgV6.AccessKeyID,
SecretKey: hostCfgV6.SecretAccessKey,
API: hostCfgV6.API,
}
continue
}
}
if hostCfgV6.AccessKeyID == "YOUR-ACCESS-KEY-ID-HERE" ||
hostCfgV6.SecretAccessKey == "YOUR-SECRET-ACCESS-KEY-HERE" ||
hostCfgV6.AccessKeyID == "" ||
hostCfgV6.SecretAccessKey == "" {
// Ignore default entries. configV7.loadDefaults() will re-insert them back.
} else if host == "https://s3.amazonaws.com" {
// Only one entry can exist for "s3" domain.
cfgV7.Hosts["s3"] = hostConfigV7{
URL: host,
AccessKey: hostCfgV6.AccessKeyID,
SecretKey: hostCfgV6.SecretAccessKey,
API: hostCfgV6.API,
}
} else if host == "https://storage.googleapis.com" {
// Only one entry can exist for "gcs" domain.
cfgV7.Hosts["gcs"] = hostConfigV7{
URL: host,
AccessKey: hostCfgV6.AccessKeyID,
SecretKey: hostCfgV6.SecretAccessKey,
API: hostCfgV6.API,
}
} else {
// Assign a generic "cloud1", cloud2..." key
// for all other entries that has valid keys set.
alias := fmt.Sprintf("cloud%d", aliasIndex)
aliasIndex++
cfgV7.Hosts[alias] = hostConfigV7{
URL: host,
AccessKey: hostCfgV6.AccessKeyID,
SecretKey: hostCfgV6.SecretAccessKey,
API: hostCfgV6.API,
}
}
}
// Load default settings.
cfgV7.loadDefaults()
mcNewCfgV7, e := quick.NewConfig(cfgV7, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `7`.")
e = mcNewCfgV7.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `7`.")
console.Infof("Successfully migrated %s from version `6` to version `7`.\n", mustGetMcConfigPath())
}
// Migrate config version `7` to `8'. Remove hosts
// 'play.min.io:9002' and 'dl.min.io:9000'.
func migrateConfigV7ToV8() {
if !isMcConfigExists() {
return
}
mcCfgV7, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV7())
fatalIf(probe.NewError(e), "Unable to load mc config V7.")
if mcCfgV7.Version() != "7" {
return
}
cfgV8 := newConfigV8()
// We dropped alias support in v7. We only need to migrate host configs.
for host, hostCfgV7 := range mcCfgV7.Data().(*configV7).Hosts {
// Ignore 'player', 'play' and 'dl' aliases.
if host == "player" || host == "dl" || host == "play" {
continue
}
hostCfgV8 := hostConfigV8{}
hostCfgV8.URL = hostCfgV7.URL
hostCfgV8.AccessKey = hostCfgV7.AccessKey
hostCfgV8.SecretKey = hostCfgV7.SecretKey
hostCfgV8.API = hostCfgV7.API
cfgV8.Hosts[host] = hostCfgV8
}
// Load default settings.
cfgV8.loadDefaults()
mcNewCfgV8, e := quick.NewConfig(cfgV8, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `8`.")
e = mcNewCfgV8.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `8`.")
console.Infof("Successfully migrated %s from version `7` to version `8`.\n", mustGetMcConfigPath())
}
// Migrate config version `8` to `9'. Add optional field virtual
func migrateConfigV8ToV9() {
if !isMcConfigExists() {
return
}
mcCfgV8, e := quick.LoadConfig(mustGetMcConfigPath(), nil, newConfigV8())
fatalIf(probe.NewError(e), "Unable to load mc config V8.")
if mcCfgV8.Version() != "8" {
return
}
cfgV9 := newConfigV9()
isEmpty := true
// We dropped alias support in v8. We only need to migrate host configs.
for host, hostCfgV8 := range mcCfgV8.Data().(*configV8).Hosts {
// Ignore 'player', 'play' and 'dl' aliases.
if host == "player" || host == "dl" || host == "play" {
continue
}
isEmpty = false
hostCfgV9 := hostConfigV9{}
hostCfgV9.URL = hostCfgV8.URL
hostCfgV9.AccessKey = hostCfgV8.AccessKey
hostCfgV9.SecretKey = hostCfgV8.SecretKey
hostCfgV9.API = hostCfgV8.API
hostCfgV9.Lookup = "auto"
cfgV9.Hosts[host] = hostCfgV9
}
if isEmpty {
// Load default settings.
cfgV9.loadDefaults()
}
mcNewCfgV9, e := quick.NewConfig(cfgV9, nil)
fatalIf(probe.NewError(e), "Unable to initialize quick config for config version `9`.")
e = mcNewCfgV9.Save(mustGetMcConfigPath())
fatalIf(probe.NewError(e), "Unable to save config version `9`.")
console.Infof("Successfully migrated %s from version `8` to version `9`.\n", mustGetMcConfigPath())
}