Various fixes

This PR:
* Uses Go 1.8 executable lookup
* Stores any err message from stats init method
* Allows overriding of Cpu Compute for hosts where it can't be detected
This commit is contained in:
Alex Dadgar 2017-03-14 12:56:31 -07:00
parent 55f9d1ee84
commit a1a7941dec
11 changed files with 74 additions and 19 deletions

View File

@ -87,6 +87,10 @@ type Config struct {
// be determined dynamically.
NetworkSpeed int
// CpuCompute is the default total CPU compute if they can not be determined
// dynamically. It should be given as Cores * MHz (2 Cores * 2 Ghz = 4000)
CpuCompute int
// MaxKillTimeout allows capping the user-specifiable KillTimeout. If the
// task's KillTimeout is greater than the MaxKillTimeout, MaxKillTimeout is
// used.
@ -242,6 +246,29 @@ func (c *Config) ReadBoolDefault(id string, defaultValue bool) bool {
return val
}
// ReadInt parses the specified option as a int.
func (c *Config) ReadInt(id string) (int, error) {
val, ok := c.Options[id]
if !ok {
return 0, fmt.Errorf("Specified config is missing from options")
}
ival, err := strconv.Atoi(val)
if err != nil {
return 0, fmt.Errorf("Failed to parse %s as int: %s", val, err)
}
return ival, nil
}
// ReadIntDefault tries to parse the specified option as a int. If there is
// an error in parsing, the default option is returned.
func (c *Config) ReadIntDefault(id string, defaultValue int) int {
val, err := c.ReadInt(id)
if err != nil {
return defaultValue
}
return val
}
// ReadDuration parses the specified option as a duration.
func (c *Config) ReadDuration(id string) (time.Duration, error) {
val, ok := c.Options[id]

View File

@ -207,8 +207,7 @@ type UniversalExecutor struct {
// NewExecutor returns an Executor
func NewExecutor(logger *log.Logger) Executor {
if err := shelpers.Init(); err != nil {
logger.Printf("[FATAL] executor: unable to initialize stats: %v", err)
return nil
logger.Printf("[ERR] executor: unable to initialize stats: %v", err)
}
exec := &UniversalExecutor{

View File

@ -22,8 +22,29 @@ func NewCPUFingerprint(logger *log.Logger) Fingerprint {
}
func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bool, error) {
setResources := func(totalCompute int) {
if node.Resources == nil {
node.Resources = &structs.Resources{}
}
node.Resources.CPU = totalCompute
}
if err := stats.Init(); err != nil {
return false, fmt.Errorf("Unable to obtain CPU information: %v", err)
err := fmt.Errorf("Unable to obtain CPU information: %v", err)
if cfg.CpuCompute != 0 {
f.logger.Printf("[DEBUG] fingerprint.cpu: %v. Using specified cpu compute %d", err, cfg.CpuCompute)
setResources(cfg.CpuCompute)
return true, nil
}
f.logger.Printf("[ERR] fingerprint.cpu: %v", err)
f.logger.Printf("[INFO] fingerprint.cpu: cpu compute may be set manually"+
" using the client config option %q on machines where cpu information"+
" can not be automatically detected.", "cpu_compute")
return false, err
}
modelName := stats.CPUModelName()
@ -40,13 +61,9 @@ func (f *CPUFingerprint) Fingerprint(cfg *config.Config, node *structs.Node) (bo
f.logger.Printf("[DEBUG] fingerprint.cpu: core count: %d", numCores)
tt := stats.TotalTicksAvailable()
node.Attributes["cpu.totalcompute"] = fmt.Sprintf("%.0f", tt)
if node.Resources == nil {
node.Resources = &structs.Resources{}
}
node.Resources.CPU = int(tt)
setResources(int(tt))
return true, nil
}

View File

@ -259,6 +259,9 @@ func (a *Agent) clientConfig() (*clientconfig.Config, error) {
if a.config.Client.NetworkSpeed != 0 {
conf.NetworkSpeed = a.config.Client.NetworkSpeed
}
if a.config.Client.CpuCompute != 0 {
conf.CpuCompute = a.config.Client.CpuCompute
}
if a.config.Client.MaxKillTimeout != "" {
dur, err := time.ParseDuration(a.config.Client.MaxKillTimeout)
if err != nil {

View File

@ -39,6 +39,7 @@ client {
}
network_interface = "eth0"
network_speed = 100
cpu_compute = 4444
reserved {
cpu = 10
memory = 10

View File

@ -182,6 +182,9 @@ type ClientConfig struct {
// speed.
NetworkSpeed int `mapstructure:"network_speed"`
// CpuCompute is used to override any detected or default total CPU compute.
CpuCompute int `mapstructure:"cpu_compute"`
// MaxKillTimeout allows capping the user-specifiable KillTimeout.
MaxKillTimeout string `mapstructure:"max_kill_timeout"`
@ -916,6 +919,9 @@ func (a *ClientConfig) Merge(b *ClientConfig) *ClientConfig {
if b.NetworkSpeed != 0 {
result.NetworkSpeed = b.NetworkSpeed
}
if b.CpuCompute != 0 {
result.CpuCompute = b.CpuCompute
}
if b.MaxKillTimeout != "" {
result.MaxKillTimeout = b.MaxKillTimeout
}

View File

@ -336,6 +336,7 @@ func parseClient(result **ClientConfig, list *ast.ObjectList) error {
"chroot_env",
"network_interface",
"network_speed",
"cpu_compute",
"max_kill_timeout",
"client_max_port",
"client_min_port",

View File

@ -59,6 +59,7 @@ func TestConfig_Parse(t *testing.T) {
},
NetworkInterface: "eth0",
NetworkSpeed: 100,
CpuCompute: 4444,
MaxKillTimeout: "10s",
ClientMinPort: 1000,
ClientMaxPort: 2000,

View File

@ -76,6 +76,7 @@ func TestConfig_Merge(t *testing.T) {
"foo": "bar",
},
NetworkSpeed: 100,
CpuCompute: 100,
MaxKillTimeout: "20s",
ClientMaxPort: 19996,
Reserved: &Resources{
@ -202,6 +203,7 @@ func TestConfig_Merge(t *testing.T) {
ClientMaxPort: 20000,
ClientMinPort: 22000,
NetworkSpeed: 105,
CpuCompute: 105,
MaxKillTimeout: "50s",
Reserved: &Resources{
CPU: 15,

View File

@ -6,8 +6,6 @@ import (
"os/exec"
"path/filepath"
"runtime"
"github.com/kardianos/osext"
)
// Checks the current executable, then $GOPATH/bin, and finally the CWD, in that
@ -19,12 +17,12 @@ func NomadExecutable() (string, error) {
}
// Check the current executable.
bin, err := osext.Executable()
bin, err := os.Executable()
if err != nil {
return "", fmt.Errorf("Failed to determine the nomad executable: %v", err)
}
if filepath.Base(bin) == nomadExe {
if _, err := os.Stat(bin); err == nil {
return bin, nil
}

View File

@ -14,20 +14,20 @@ var (
cpuNumCores int
cpuTotalTicks float64
initErr error
onceLer sync.Once
)
func Init() error {
var err error
onceLer.Do(func() {
if cpuNumCores, err = cpu.Counts(true); err != nil {
err = fmt.Errorf("Unable to determine the number of CPU cores available: %v", err)
if cpuNumCores, initErr = cpu.Counts(true); initErr != nil {
initErr = fmt.Errorf("Unable to determine the number of CPU cores available: %v", initErr)
return
}
var cpuInfo []cpu.InfoStat
if cpuInfo, err = cpu.Info(); err != nil {
err = fmt.Errorf("Unable to obtain CPU information: %v", err)
if cpuInfo, initErr = cpu.Info(); initErr != nil {
initErr = fmt.Errorf("Unable to obtain CPU information: %v", initErr)
return
}
@ -42,7 +42,7 @@ func Init() error {
cpuMhzPerCore = math.Floor(cpuMhzPerCore)
cpuTotalTicks = math.Floor(float64(cpuNumCores) * cpuMhzPerCore)
})
return err
return initErr
}
// CPUModelName returns the number of CPU cores available