2018-11-27 17:39:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2019-02-25 13:44:22 +00:00
|
|
|
"github.com/AdguardTeam/golibs/log"
|
2019-01-25 13:01:27 +00:00
|
|
|
yaml "gopkg.in/yaml.v2"
|
2018-11-27 17:39:59 +00:00
|
|
|
)
|
|
|
|
|
2019-02-27 13:15:36 +00:00
|
|
|
const currentSchemaVersion = 3 // used for upgrading from old configs to new config
|
2018-12-05 17:29:00 +00:00
|
|
|
|
2018-11-27 17:39:59 +00:00
|
|
|
// Performs necessary upgrade operations if needed
|
|
|
|
func upgradeConfig() error {
|
|
|
|
// read a config file into an interface map, so we can manipulate values without losing any
|
2019-02-05 17:35:48 +00:00
|
|
|
configFile := config.getConfigFilename()
|
2018-11-27 17:39:59 +00:00
|
|
|
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
|
|
|
log.Printf("config file %s does not exist, nothing to upgrade", configFile)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
diskConfig := map[string]interface{}{}
|
|
|
|
body, err := ioutil.ReadFile(configFile)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Couldn't read config file '%s': %s", configFile, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = yaml.Unmarshal(body, &diskConfig)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Couldn't parse config file '%s': %s", configFile, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
schemaVersionInterface, ok := diskConfig["schema_version"]
|
2019-02-07 15:24:12 +00:00
|
|
|
log.Tracef("got schema version %v", schemaVersionInterface)
|
2018-11-27 17:39:59 +00:00
|
|
|
if !ok {
|
|
|
|
// no schema version, set it to 0
|
|
|
|
schemaVersionInterface = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
schemaVersion, ok := schemaVersionInterface.(int)
|
|
|
|
if !ok {
|
|
|
|
err = fmt.Errorf("configuration file contains non-integer schema_version, abort")
|
|
|
|
log.Println(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-11-27 17:51:12 +00:00
|
|
|
if schemaVersion == currentSchemaVersion {
|
2018-11-27 17:39:59 +00:00
|
|
|
// do nothing
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return upgradeConfigSchema(schemaVersion, &diskConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upgrade from oldVersion to newVersion
|
|
|
|
func upgradeConfigSchema(oldVersion int, diskConfig *map[string]interface{}) error {
|
|
|
|
switch oldVersion {
|
|
|
|
case 0:
|
2019-02-27 13:15:36 +00:00
|
|
|
err := upgradeSchema0to3(diskConfig)
|
2018-12-05 17:29:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case 1:
|
2019-02-27 13:15:36 +00:00
|
|
|
err := upgradeSchema1to3(diskConfig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
err := upgradeSchema2to3(diskConfig)
|
2018-11-27 17:39:59 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
err := fmt.Errorf("configuration file contains unknown schema_version, abort")
|
|
|
|
log.Println(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-02-05 17:35:48 +00:00
|
|
|
configFile := config.getConfigFilename()
|
2018-11-27 17:39:59 +00:00
|
|
|
body, err := yaml.Marshal(diskConfig)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Couldn't generate YAML file: %s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = safeWriteFile(configFile, body)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Couldn't save YAML config: %s", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-12-05 17:29:00 +00:00
|
|
|
// The first schema upgrade:
|
|
|
|
// No more "dnsfilter.txt", filters are now kept in data/filters/
|
2018-11-27 17:39:59 +00:00
|
|
|
func upgradeSchema0to1(diskConfig *map[string]interface{}) error {
|
2018-11-28 10:21:39 +00:00
|
|
|
log.Printf("%s(): called", _Func())
|
2018-11-27 17:39:59 +00:00
|
|
|
|
2019-02-10 17:47:43 +00:00
|
|
|
dnsFilterPath := filepath.Join(config.ourWorkingDir, "dnsfilter.txt")
|
2018-12-05 17:29:00 +00:00
|
|
|
if _, err := os.Stat(dnsFilterPath); !os.IsNotExist(err) {
|
2018-11-27 17:39:59 +00:00
|
|
|
log.Printf("Deleting %s as we don't need it anymore", dnsFilterPath)
|
|
|
|
err = os.Remove(dnsFilterPath)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Cannot remove %s due to %s", dnsFilterPath, err)
|
|
|
|
// not fatal, move on
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(*diskConfig)["schema_version"] = 1
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2018-12-05 17:29:00 +00:00
|
|
|
|
|
|
|
// Second schema upgrade:
|
|
|
|
// coredns is now dns in config
|
|
|
|
// delete 'Corefile', since we don't use that anymore
|
|
|
|
func upgradeSchema1to2(diskConfig *map[string]interface{}) error {
|
|
|
|
log.Printf("%s(): called", _Func())
|
|
|
|
|
2019-02-10 17:47:43 +00:00
|
|
|
coreFilePath := filepath.Join(config.ourWorkingDir, "Corefile")
|
2018-12-05 17:29:00 +00:00
|
|
|
if _, err := os.Stat(coreFilePath); !os.IsNotExist(err) {
|
|
|
|
log.Printf("Deleting %s as we don't need it anymore", coreFilePath)
|
|
|
|
err = os.Remove(coreFilePath)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Cannot remove %s due to %s", coreFilePath, err)
|
|
|
|
// not fatal, move on
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-05 21:29:38 +00:00
|
|
|
if _, ok := (*diskConfig)["dns"]; !ok {
|
|
|
|
(*diskConfig)["dns"] = (*diskConfig)["coredns"]
|
|
|
|
delete((*diskConfig), "coredns")
|
|
|
|
}
|
2018-12-05 17:29:00 +00:00
|
|
|
(*diskConfig)["schema_version"] = 2
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-27 13:15:36 +00:00
|
|
|
// Third schema upgrade:
|
|
|
|
// Bootstrap DNS becomes an array
|
|
|
|
func upgradeSchema2to3(diskConfig *map[string]interface{}) error {
|
|
|
|
log.Printf("%s(): called", _Func())
|
|
|
|
|
|
|
|
// Let's read dns configuration from diskConfig
|
|
|
|
dnsConfig, ok := (*diskConfig)["dns"]
|
|
|
|
if !ok {
|
2019-02-27 13:19:45 +00:00
|
|
|
return fmt.Errorf("no DNS configuration in config file")
|
2019-02-27 13:15:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Convert interface{} to map[string]interface{}
|
|
|
|
newDNSConfig := make(map[string]interface{})
|
|
|
|
|
|
|
|
switch v := dnsConfig.(type) {
|
|
|
|
case map[interface{}]interface{}:
|
|
|
|
for k, v := range v {
|
|
|
|
newDNSConfig[fmt.Sprint(k)] = v
|
|
|
|
}
|
|
|
|
default:
|
2019-02-27 13:19:45 +00:00
|
|
|
return fmt.Errorf("DNS configuration is not a map")
|
2019-02-27 13:15:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Replace bootstrap_dns value filed with new array contains old bootstrap_dns inside
|
|
|
|
if bootstrapDNS, ok := (newDNSConfig)["bootstrap_dns"]; ok {
|
|
|
|
newBootstrapConfig := []string{fmt.Sprint(bootstrapDNS)}
|
|
|
|
(newDNSConfig)["bootstrap_dns"] = newBootstrapConfig
|
|
|
|
(*diskConfig)["dns"] = newDNSConfig
|
|
|
|
} else {
|
2019-02-27 13:19:45 +00:00
|
|
|
return fmt.Errorf("no bootstrap DNS in DNS config")
|
2019-02-27 13:15:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bump schema version
|
|
|
|
(*diskConfig)["schema_version"] = 3
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// jump three schemas at once -- this time we just do it sequentially
|
|
|
|
func upgradeSchema0to3(diskConfig *map[string]interface{}) error {
|
2018-12-05 17:29:00 +00:00
|
|
|
err := upgradeSchema0to1(diskConfig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-02-27 13:15:36 +00:00
|
|
|
return upgradeSchema1to3(diskConfig)
|
|
|
|
}
|
|
|
|
|
|
|
|
// jump two schemas at once -- this time we just do it sequentially
|
|
|
|
func upgradeSchema1to3(diskConfig *map[string]interface{}) error {
|
|
|
|
err := upgradeSchema1to2(diskConfig)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return upgradeSchema2to3(diskConfig)
|
2018-12-05 17:29:00 +00:00
|
|
|
}
|