2020-03-27 14:35:23 +00:00
|
|
|
package configuration
|
|
|
|
|
2020-05-27 22:57:42 +00:00
|
|
|
import (
|
2020-09-20 05:53:01 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
|
|
|
"syscall"
|
|
|
|
|
|
|
|
errors "git.sequentialread.com/forest/pkg-errors"
|
2020-05-27 22:57:42 +00:00
|
|
|
)
|
|
|
|
|
2020-03-27 14:35:23 +00:00
|
|
|
type Configuration struct {
|
2020-09-28 06:06:09 +00:00
|
|
|
Host HostConfiguration
|
|
|
|
ApplicationModules []string
|
|
|
|
Terraform TerraformConfiguration
|
|
|
|
ObjectStorage ObjectStorageConfiguration
|
|
|
|
Credentials []Credential
|
2020-03-27 14:35:23 +00:00
|
|
|
}
|
|
|
|
|
2020-03-30 20:26:26 +00:00
|
|
|
type HostConfiguration struct {
|
2020-09-20 05:53:01 +00:00
|
|
|
Name string
|
2020-03-30 20:26:26 +00:00
|
|
|
}
|
|
|
|
|
2020-04-01 22:12:08 +00:00
|
|
|
type TerraformConfiguration struct {
|
2020-09-20 05:53:01 +00:00
|
|
|
GlobalModules []string
|
|
|
|
LocalModules []string
|
|
|
|
Variables map[string]string
|
2020-04-01 22:12:08 +00:00
|
|
|
}
|
|
|
|
|
2020-03-29 19:51:07 +00:00
|
|
|
type ObjectStorageConfiguration struct {
|
2020-09-20 05:53:01 +00:00
|
|
|
Encryption string
|
|
|
|
Backends []ObjectStorageBackend
|
2020-03-27 14:35:23 +00:00
|
|
|
}
|
|
|
|
|
2020-03-29 19:51:07 +00:00
|
|
|
type ObjectStorageBackend struct {
|
2020-09-20 05:53:01 +00:00
|
|
|
Provider string
|
|
|
|
Region string
|
|
|
|
Name string
|
2020-03-27 14:35:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Credential struct {
|
2020-09-20 05:53:01 +00:00
|
|
|
Type string
|
|
|
|
SSID string
|
|
|
|
Username string
|
|
|
|
Password string
|
2020-03-27 14:35:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const GANDI = "Gandi"
|
|
|
|
const DIGITALOCEAN = "DigitalOcean"
|
2020-08-14 21:36:50 +00:00
|
|
|
const DIGITALOCEAN_API_URL = "https://api.digitalocean.com"
|
2020-08-17 23:59:16 +00:00
|
|
|
const GANDI_API_URL = "https://api.gandi.net"
|
2020-03-27 14:35:23 +00:00
|
|
|
const AMAZON_S3 = "AmazonS3"
|
|
|
|
const BACKBLAZE_B2 = "BackblazeB2"
|
|
|
|
const OBJECT_STORAGE_PASSPHRASE = "ObjectStoragePassphrase"
|
2020-10-01 20:51:46 +00:00
|
|
|
const APPLICATION_MODULES_PATH = "application-modules"
|
2020-08-14 21:36:50 +00:00
|
|
|
const GLOBAL_TERRAFORM_PROJECT = "terraform-global"
|
|
|
|
const LOCAL_TERRAFORM_PROJECT = "terraform-local"
|
|
|
|
const TERRAFORM_MODULES = "terraform-modules"
|
|
|
|
const ANSIBLE_ROLES = "ansible-roles"
|
2020-05-25 23:03:38 +00:00
|
|
|
const ANSIBLE_PLAYBOOK_FILE_NAME = "playbook.yml"
|
|
|
|
const TERRAFORM_PLAN_FILE_NAME = "terraform-plan-file"
|
2020-05-27 22:57:42 +00:00
|
|
|
const ANSIBLE_WRAPPER_PATH = "ansible-wrapper"
|
2020-10-21 18:36:28 +00:00
|
|
|
const DOCKER_SOCKET = "/var/run/docker.sock"
|
2020-11-04 07:24:31 +00:00
|
|
|
const THRESHOLD_SOCKET = "/var/run/servergarden/threshold/threshold.sock"
|
|
|
|
const CADDY_SOCKET = "/var/run/servergarden/caddy/caddy.sock"
|
|
|
|
const CADDY_DATA = "/var/lib/servergarden/caddy/data/"
|
2020-11-05 02:13:37 +00:00
|
|
|
const THRESHOLD_DATA = "/var/lib/servergarden/threshold/"
|
2020-06-07 21:13:32 +00:00
|
|
|
const TERRAFORM_APPLY_STATUS_UPDATE_INTERVAL_SECONDS = 5
|
2020-05-27 22:57:42 +00:00
|
|
|
|
|
|
|
func GET_ANSIBLE_WRAPPER_FILES() []string {
|
2020-09-20 05:53:01 +00:00
|
|
|
return []string{
|
|
|
|
"ansible-playbook-wrapper",
|
|
|
|
"callback_plugins",
|
|
|
|
"ansible.cfg",
|
|
|
|
}
|
2020-05-27 22:57:42 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 12:49:18 +00:00
|
|
|
const SSH_KEYS_PATH = "ssh"
|
|
|
|
const TERRAFORM_STATE_SERVER_PORT_NUMBER = 6471
|
2020-05-27 22:57:42 +00:00
|
|
|
|
|
|
|
func LoadConfiguration() (*Configuration, string, error) {
|
|
|
|
|
2020-09-20 05:53:01 +00:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
return nil, "", errors.New("windows operating system is not supported.")
|
|
|
|
}
|
|
|
|
|
|
|
|
workingDirectory, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", errors.Wrap(err, "can't os.Getwd()")
|
|
|
|
}
|
|
|
|
executableDirectory, err := getCurrentExecDir()
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", errors.Wrap(err, "can't getCurrentExecDir()")
|
|
|
|
}
|
|
|
|
|
|
|
|
configFileLocation1 := filepath.Join(executableDirectory, "config.json")
|
|
|
|
configFileLocation2 := filepath.Join(workingDirectory, "config.json")
|
|
|
|
|
|
|
|
configFileLocation := configFileLocation1
|
|
|
|
configFileStat, err := os.Stat(configFileLocation)
|
|
|
|
workingDirectoryToReturn := executableDirectory
|
|
|
|
if err != nil || !configFileStat.Mode().IsRegular() {
|
|
|
|
configFileLocation = configFileLocation2
|
|
|
|
configFileStat, err = os.Stat(configFileLocation)
|
|
|
|
workingDirectoryToReturn = workingDirectory
|
|
|
|
}
|
|
|
|
if err != nil || !configFileStat.Mode().IsRegular() {
|
|
|
|
return nil, workingDirectoryToReturn, fmt.Errorf("no config file. checked %s and %s", configFileLocation1, configFileLocation2)
|
|
|
|
}
|
|
|
|
|
|
|
|
// configFileUid, err := getUID(configFileStat)
|
|
|
|
// if err != nil {
|
|
|
|
// return nil, errors.Wrapf(err, "can't getUID() config file %s", configFileLocation)
|
|
|
|
// }
|
|
|
|
// if configFileUid != 0 {
|
|
|
|
// return nil, fmt.Errorf("can't start rootsystem: the config file %s is not owned by root.", configFileLocation)
|
|
|
|
// }
|
|
|
|
|
|
|
|
// ownerReadWriteOnlyPermissionsOctal := "600"
|
|
|
|
// configFilePermissionsOctal := fmt.Sprintf("%o", configFileStat.Mode().Perm())
|
|
|
|
// if configFilePermissionsOctal != ownerReadWriteOnlyPermissionsOctal {
|
|
|
|
// return nil, fmt.Errorf(
|
|
|
|
// "can't start rootsystem: the config file %s had permissions %s. expected %s. %s",
|
|
|
|
// configFileLocation,
|
|
|
|
// configFilePermissionsOctal,
|
|
|
|
// ownerReadWriteOnlyPermissionsOctal,
|
|
|
|
// "(config file should only be readable and writable by the owner, aka the root user)",
|
|
|
|
// )
|
|
|
|
// }
|
|
|
|
|
|
|
|
jsonBytes, err := ioutil.ReadFile(configFileLocation)
|
|
|
|
if err != nil {
|
|
|
|
return nil, workingDirectoryToReturn, errors.Wrap(err, "can't read config file")
|
|
|
|
}
|
|
|
|
|
|
|
|
var config Configuration
|
|
|
|
err = json.Unmarshal(jsonBytes, &config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, workingDirectoryToReturn, errors.Wrap(err, "can't json.Unmarshal config file")
|
|
|
|
}
|
|
|
|
|
|
|
|
return &config, workingDirectoryToReturn, nil
|
2020-05-27 22:57:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getUID(fileInfo os.FileInfo) (int, error) {
|
2020-09-20 05:53:01 +00:00
|
|
|
stat, ok := fileInfo.Sys().(*syscall.Stat_t)
|
|
|
|
if !ok {
|
|
|
|
return -1, fmt.Errorf("can't cast os.Stat(\"%s\").Sys() to *syscall.Stat_t")
|
|
|
|
}
|
2020-05-27 22:57:42 +00:00
|
|
|
|
2020-09-20 05:53:01 +00:00
|
|
|
return int(stat.Uid), nil
|
2020-05-27 22:57:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getCurrentExecDir() (dir string, err error) {
|
2020-09-20 05:53:01 +00:00
|
|
|
path, err := exec.LookPath(os.Args[0])
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("exec.LookPath(%s) returned %s\n", os.Args[0], err)
|
|
|
|
return "", err
|
|
|
|
}
|
2020-05-27 22:57:42 +00:00
|
|
|
|
2020-09-20 05:53:01 +00:00
|
|
|
absPath, err := filepath.Abs(path)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Printf("filepath.Abs(%s) returned %s\n", path, err)
|
|
|
|
return "", err
|
|
|
|
}
|
2020-05-27 22:57:42 +00:00
|
|
|
|
2020-09-20 05:53:01 +00:00
|
|
|
dir = filepath.Dir(absPath)
|
2020-05-27 22:57:42 +00:00
|
|
|
|
2020-09-20 05:53:01 +00:00
|
|
|
return dir, nil
|
2020-05-27 22:57:42 +00:00
|
|
|
}
|