243 lines
5.4 KiB
Go
243 lines
5.4 KiB
Go
package agent
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/hcl"
|
|
hclobj "github.com/hashicorp/hcl/hcl"
|
|
)
|
|
|
|
// Config is the configuration for the Nomad agent.
|
|
type Config struct {
|
|
// Region is the region this agent is in. Defaults to region1.
|
|
Region string `hcl:"region"`
|
|
|
|
// DataDir is the directory to store our state in
|
|
DataDir string `hcl:"data_dir"`
|
|
|
|
// LogLevel is the level of the logs to putout
|
|
LogLevel string `hcl:"log_level"`
|
|
|
|
// HttpAddr is used to control the address and port we bind to.
|
|
// If not specified, 127.0.0.1:4646 is used.
|
|
HttpAddr string `hcl:"http_addr"`
|
|
|
|
// Client has our client related settings
|
|
Client *ClientConfig `hcl:"client"`
|
|
|
|
// Server has our server related settings
|
|
Server *ServerConfig `hcl:"server"`
|
|
|
|
Telemetry *Telemetry `hcl:"telemetry"`
|
|
|
|
LeaveOnInt bool
|
|
LeaveOnTerm bool
|
|
EnableSyslog bool
|
|
SyslogFacility string
|
|
|
|
DisableUpdateCheck bool
|
|
DisableAnonymousSignature bool
|
|
|
|
Revision string
|
|
Version string
|
|
VersionPrerelease string
|
|
}
|
|
|
|
type ClientConfig struct {
|
|
// Enabled controls if we are a client
|
|
Enabled bool `hcl:"enabled"`
|
|
|
|
// Datacenter is the datacenter this agent is in. Defaults to dc1
|
|
Datacenter string `hcl:"datacenter"`
|
|
|
|
// Name is the name we register as. Defaults to hostname.
|
|
Name string `hcl:"name"`
|
|
|
|
// NodeID is the unique node identifier to use. A UUID is used
|
|
// if not provided, and stored in the data directory
|
|
NodeID string `hcl:"node_id"`
|
|
}
|
|
|
|
type ServerConfig struct {
|
|
// Enabled controls if we are a server
|
|
Enabled bool `hcl:"enabled"`
|
|
|
|
// Bootstrap is used to bring up the first Consul server, and
|
|
// permits that node to elect itself leader
|
|
Bootstrap bool `hcl:"bootstrap"`
|
|
|
|
// BootstrapExpect tries to automatically bootstrap the Consul cluster,
|
|
// by witholding peers until enough servers join.
|
|
BootstrapExpect int `hcl:"bootstrap_expect"`
|
|
|
|
// AdvertiseAddr is the address we use for advertising our Serf,
|
|
// and Consul RPC IP. If not specified, bind address is used.
|
|
AdvertiseAddr string `mapstructure:"advertise_addr"`
|
|
|
|
// BindAddr is used to control the address we bind to.
|
|
// If not specified, the first private IP we find is used.
|
|
// This controls the address we use for cluster facing
|
|
// services (Gossip, Server RPC)
|
|
BindAddr string `hcl:"bind_addr"`
|
|
}
|
|
|
|
// Telemetry is the telemetry configuration for the server
|
|
type Telemetry struct {
|
|
StatsiteAddr string `hcl:"statsite_address"`
|
|
StatsdAddr string `hcl:"statsd_address"`
|
|
DisableHostname bool `hcl:"disable_hostname"`
|
|
}
|
|
|
|
// DevConfig is a Config that is used for dev mode of Nomad.
|
|
func DevConfig() *Config {
|
|
return &Config{
|
|
LogLevel: "DEBUG",
|
|
}
|
|
}
|
|
|
|
// DefaultConfig is a the baseline configuration for Nomad
|
|
func DefaultConfig() *Config {
|
|
return &Config{
|
|
LogLevel: "INFO",
|
|
}
|
|
}
|
|
|
|
// Merge merges two configurations.
|
|
func (c *Config) Merge(c2 *Config) *Config {
|
|
result := new(Config)
|
|
|
|
result.Telemetry = c.Telemetry
|
|
if c2.Telemetry != nil {
|
|
result.Telemetry = c2.Telemetry
|
|
}
|
|
return result
|
|
}
|
|
|
|
// LoadConfig loads the configuration at the given path, regardless if
|
|
// its a file or directory.
|
|
func LoadConfig(path string) (*Config, error) {
|
|
fi, err := os.Stat(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if fi.IsDir() {
|
|
return LoadConfigDir(path)
|
|
} else {
|
|
return LoadConfigFile(path)
|
|
}
|
|
}
|
|
|
|
// LoadConfigFile loads the configuration from the given file.
|
|
func LoadConfigFile(path string) (*Config, error) {
|
|
// Read the file
|
|
d, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Parse!
|
|
obj, err := hcl.Parse(string(d))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Start building the result
|
|
var result Config
|
|
if err := hcl.DecodeObject(&result, obj); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &result, nil
|
|
}
|
|
|
|
func getString(o *hclobj.Object) string {
|
|
if o == nil || o.Type != hclobj.ValueTypeString {
|
|
return ""
|
|
}
|
|
|
|
return o.Value.(string)
|
|
}
|
|
|
|
// LoadConfigDir loads all the configurations in the given directory
|
|
// in alphabetical order.
|
|
func LoadConfigDir(dir string) (*Config, error) {
|
|
f, err := os.Open(dir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
fi, err := f.Stat()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !fi.IsDir() {
|
|
return nil, fmt.Errorf(
|
|
"configuration path must be a directory: %s",
|
|
dir)
|
|
}
|
|
|
|
var files []string
|
|
err = nil
|
|
for err != io.EOF {
|
|
var fis []os.FileInfo
|
|
fis, err = f.Readdir(128)
|
|
if err != nil && err != io.EOF {
|
|
return nil, err
|
|
}
|
|
|
|
for _, fi := range fis {
|
|
// Ignore directories
|
|
if fi.IsDir() {
|
|
continue
|
|
}
|
|
|
|
// Only care about files that are valid to load.
|
|
name := fi.Name()
|
|
skip := true
|
|
if strings.HasSuffix(name, ".hcl") {
|
|
skip = false
|
|
} else if strings.HasSuffix(name, ".json") {
|
|
skip = false
|
|
}
|
|
if skip || isTemporaryFile(name) {
|
|
continue
|
|
}
|
|
|
|
path := filepath.Join(dir, name)
|
|
files = append(files, path)
|
|
}
|
|
}
|
|
|
|
var result *Config
|
|
for _, f := range files {
|
|
config, err := LoadConfigFile(f)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error loading %s: %s", f, err)
|
|
}
|
|
|
|
if result == nil {
|
|
result = config
|
|
} else {
|
|
result = result.Merge(config)
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// isTemporaryFile returns true or false depending on whether the
|
|
// provided file name is a temporary file for the following editors:
|
|
// emacs or vim.
|
|
func isTemporaryFile(name string) bool {
|
|
return strings.HasSuffix(name, "~") || // vim
|
|
strings.HasPrefix(name, ".#") || // emacs
|
|
(strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#")) // emacs
|
|
}
|