github.com/nycdavid/zeus@v0.0.0-20201208104106-9ba439429e03/go/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/json"
     6  	"io/ioutil"
     7  	"os"
     8  	"path"
     9  
    10  	"github.com/burke/zeus/go/filemonitor"
    11  	"github.com/burke/zeus/go/processtree"
    12  	"github.com/burke/zeus/go/zerror"
    13  )
    14  
    15  type config struct {
    16  	Command string
    17  	Plan    interface{}
    18  	Items   map[string]string
    19  }
    20  
    21  func BuildProcessTree(configFile string, monitor filemonitor.FileMonitor) *processtree.ProcessTree {
    22  	conf := parseConfig(configFile)
    23  	tree := &processtree.ProcessTree{}
    24  	tree.SlavesByName = make(map[string]*processtree.SlaveNode)
    25  	tree.StateChanged = make(chan bool, 16)
    26  
    27  	tree.ExecCommand = conf.Command
    28  
    29  	plan, ok := conf.Plan.(map[string]interface{})
    30  	if !ok {
    31  		zerror.ErrorConfigFileInvalidFormat()
    32  	}
    33  	iteratePlan(tree, plan, monitor, nil)
    34  
    35  	return tree
    36  }
    37  
    38  func iteratePlan(
    39  	tree *processtree.ProcessTree,
    40  	plan map[string]interface{},
    41  	monitor filemonitor.FileMonitor,
    42  	parent *processtree.SlaveNode,
    43  ) {
    44  	for name, v := range plan {
    45  		if subPlan, ok := v.(map[string]interface{}); ok {
    46  			newNode := tree.NewSlaveNode(name, parent, monitor)
    47  			if parent == nil {
    48  				tree.Root = newNode
    49  			} else {
    50  				parent.Slaves = append(parent.Slaves, newNode)
    51  			}
    52  			iteratePlan(tree, subPlan, monitor, newNode)
    53  		} else {
    54  			var newNode *processtree.CommandNode
    55  			if aliases, ok := v.([]interface{}); ok {
    56  				strs := make([]string, len(aliases))
    57  				for i, alias := range aliases {
    58  					strs[i] = alias.(string)
    59  				}
    60  				newNode = tree.NewCommandNode(name, strs, parent)
    61  			} else if v == nil {
    62  				newNode = tree.NewCommandNode(name, nil, parent)
    63  			} else {
    64  				zerror.ErrorConfigFileInvalidFormat()
    65  			}
    66  			parent.Commands = append(parent.Commands, newNode)
    67  		}
    68  	}
    69  }
    70  
    71  func defaultConfigPath() string {
    72  	binaryPath := os.Args[0]
    73  	gemDir := path.Dir(path.Dir(binaryPath))
    74  	jsonpath := path.Join(gemDir, "examples/zeus.json")
    75  	return jsonpath
    76  }
    77  
    78  func readConfigFileOrDefault(configFile string) ([]byte, error) {
    79  	contents, err := readFile(configFile)
    80  	if err != nil {
    81  		switch err.(type) {
    82  		case *os.PathError:
    83  			return readFile(defaultConfigPath())
    84  		default:
    85  			return contents, err
    86  		}
    87  	}
    88  	return contents, err
    89  }
    90  
    91  func parseConfig(configFile string) (c config) {
    92  	var conf config
    93  
    94  	contents, err := readConfigFileOrDefault(configFile)
    95  	if err != nil {
    96  		zerror.ErrorConfigFileInvalidJson()
    97  	}
    98  
    99  	json.Unmarshal(contents, &conf)
   100  	return conf
   101  }
   102  
   103  func readFile(path string) (contents []byte, err error) {
   104  	file, err := os.Open(path)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	reader := bufio.NewReader(file)
   109  
   110  	contents, err = ioutil.ReadAll(reader)
   111  	return
   112  }