server.garden privileged automation agent (mirror of https://git.sequentialread.com/forest/rootsystem)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

174 lines
4.9 KiB

package configuration
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"syscall"
errors "git.sequentialread.com/forest/pkg-errors"
)
type Configuration struct {
Host HostConfiguration
ApplicationModules []string
Terraform TerraformConfiguration
ObjectStorage ObjectStorageConfiguration
Credentials []Credential
}
type HostConfiguration struct {
Name string
}
type TerraformConfiguration struct {
GlobalModules []string
LocalModules []string
Variables map[string]string
}
type ObjectStorageConfiguration struct {
Encryption string
Backends []ObjectStorageBackend
}
type ObjectStorageBackend struct {
Provider string
Region string
Name string
}
type Credential struct {
Type string
SSID string
Username string
Password string
}
const GANDI = "Gandi"
const DIGITALOCEAN = "DigitalOcean"
const DIGITALOCEAN_API_URL = "https://api.digitalocean.com"
const GANDI_API_URL = "https://api.gandi.net"
const AMAZON_S3 = "AmazonS3"
const BACKBLAZE_B2 = "BackblazeB2"
const OBJECT_STORAGE_PASSPHRASE = "ObjectStoragePassphrase"
const APPLICATION_MODULES_PATH = "application-modules"
const GLOBAL_TERRAFORM_PROJECT = "terraform-global"
const LOCAL_TERRAFORM_PROJECT = "terraform-local"
const TERRAFORM_MODULES = "terraform-modules"
const ANSIBLE_ROLES = "ansible-roles"
const ANSIBLE_PLAYBOOK_FILE_NAME = "playbook.yml"
const TERRAFORM_PLAN_FILE_NAME = "terraform-plan-file"
const ANSIBLE_WRAPPER_PATH = "ansible-wrapper"
const DOCKER_SOCKET = "/var/run/docker.sock"
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/"
const THRESHOLD_DATA = "/var/lib/servergarden/threshold/"
const TERRAFORM_APPLY_STATUS_UPDATE_INTERVAL_SECONDS = 5
func GET_ANSIBLE_WRAPPER_FILES() []string {
return []string{
"ansible-playbook-wrapper",
"callback_plugins",
"ansible.cfg",
}
}
const SSH_KEYS_PATH = "ssh"
const TERRAFORM_STATE_SERVER_PORT_NUMBER = 6471
func LoadConfiguration() (*Configuration, string, error) {
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
}
func getUID(fileInfo os.FileInfo) (int, error) {
stat, ok := fileInfo.Sys().(*syscall.Stat_t)
if !ok {
return -1, fmt.Errorf("can't cast os.Stat(\"%s\").Sys() to *syscall.Stat_t")
}
return int(stat.Uid), nil
}
func getCurrentExecDir() (dir string, err error) {
path, err := exec.LookPath(os.Args[0])
if err != nil {
fmt.Printf("exec.LookPath(%s) returned %s\n", os.Args[0], err)
return "", err
}
absPath, err := filepath.Abs(path)
if err != nil {
fmt.Printf("filepath.Abs(%s) returned %s\n", path, err)
return "", err
}
dir = filepath.Dir(absPath)
return dir, nil
}