Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:zvelo/envetcd into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
jbriggs-zvelo committed Jul 1, 2015
2 parents 08ea8c3 + 4b28e50 commit 380e387
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 72 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/.coveralls-stamp
/release/
/profile.out
/cmd/envetcd/envetcd
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ release-linux-amd64: $(EXECUTABLE) $(EXECUTABLE)-linux-amd64
@mkdir -p release
@tar czf release/$(EXECUTABLE)-$(VERSION)-linux-amd64.tgz $(EXECUTABLE)-$(VERSION)-linux-amd64
@rm -rf $(EXECUTABLE)-$(VERSION)-linux-amd64
@cp $(EXECUTABLE)-linux-amd64 release/

release-darwin-amd64: $(EXECUTABLE) $(EXECUTABLE)-darwin-amd64
$(eval VERSION=$(shell ./$(EXECUTABLE) -v | awk '{print $$3}'))
Expand All @@ -79,6 +80,7 @@ release-darwin-amd64: $(EXECUTABLE) $(EXECUTABLE)-darwin-amd64
@mkdir -p release
@tar czf release/$(EXECUTABLE)-$(VERSION)-darwin-amd64.tgz $(EXECUTABLE)-$(VERSION)-darwin-amd64
@rm -rf $(EXECUTABLE)-$(VERSION)-darwin-amd64
@cp $(EXECUTABLE)-darwin-amd64 release/

clean:
@rm -rf \
Expand Down
23 changes: 0 additions & 23 deletions cmd/envetcd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/codegangsta/cli"
"github.com/zvelo/envetcd"
"github.com/zvelo/zvelo-services/util"
)

// Exit codes are int values that represent an exit code for a particular error.
Expand All @@ -24,28 +23,6 @@ const (
exitCodeEnvEtcdError
)

func setup(c *cli.Context) error {
util.InitLogger(c.GlobalString("log-level"))

config = configT{
EnvEtcd: &envetcd.Config{
Etcd: util.NewEtcdConfig(c),
Hostname: c.GlobalString("hostname"),
System: c.GlobalString("system"),
Service: c.GlobalString("service"),
Prefix: c.GlobalString("prefix"),
Sanitize: !c.GlobalBool("no-sanitize"),
Upcase: !c.GlobalBool("no-upcase"),
UseDefaultGateway: c.GlobalBool("use-default-gateway"),
},
Output: c.String("output"),
WriteEnv: c.GlobalString("write-env"),
CleanEnv: c.GlobalBool("clean-env"),
}

return nil
}

// Run accepts a slice of arguments and returns an int representing the exit
// status from the command.
func run(c *cli.Context) {
Expand Down
43 changes: 35 additions & 8 deletions cmd/envetcd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

const (
name = "envetcd"
version = "0.2.2"
version = "0.3.6"
)

type configT struct {
Expand All @@ -21,8 +21,9 @@ type configT struct {
}

var (
app = cli.NewApp()
config configT
app = cli.NewApp()
config configT
templates = cli.StringSlice{}
)

func init() {
Expand Down Expand Up @@ -67,6 +68,15 @@ func init() {
EnvVar: "ENVETCD_OUTPUT",
Usage: "write stdout from the command to this file",
},
cli.StringSliceFlag{
Name: "templates, t",
EnvVar: "ENVETCD_TEMPLATES",
Usage: "replace values in this template file using those pulled from etcd," +
"filename should end in '.tmpl'," +
"the substituted file will be written without the '.tmpl' suffix," +
"may be supplied multiple times",
Value: &templates,
},
cli.BoolFlag{
Name: "clean-env, c",
EnvVar: "ENVETCD_CLEAN_ENV",
Expand All @@ -82,16 +92,33 @@ func init() {
EnvVar: "ENVETCD_NO_UPCASE",
Usage: "don't convert all environment keys to uppercase",
},
cli.BoolFlag{
Name: "use-default-gateway, d",
EnvVar: "ENVETCD_USE_DEFAULT_GATEWAY",
Usage: "expose the default gateway as $ENVETCD_DEFAULT_GATEWAY",
},
}...)
app.Before = setup
app.Action = run
}

func setup(c *cli.Context) error {
util.InitLogger(c.GlobalString("log-level"))

config = configT{
EnvEtcd: &envetcd.Config{
Etcd: util.NewEtcdConfig(c),
Hostname: c.GlobalString("hostname"),
System: c.GlobalString("system"),
Service: c.GlobalString("service"),
Prefix: c.GlobalString("prefix"),
Sanitize: !c.GlobalBool("no-sanitize"),
Upcase: !c.GlobalBool("no-upcase"),
TemplateFiles: c.StringSlice("templates"),
},
Output: c.String("output"),
WriteEnv: c.GlobalString("write-env"),
CleanEnv: c.GlobalBool("clean-env"),
}

return nil
}

func main() {
app.Run(os.Args)
}
166 changes: 125 additions & 41 deletions envetcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"log"
"net"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
Expand All @@ -24,14 +25,15 @@ var invalidRegexp = regexp.MustCompile(`[^a-zA-Z0-9_]`)

// Config contains all of the parameters needed to run GetKeyPairs
type Config struct {
Etcd *util.EtcdConfig
Etcd *util.EtcdConfig
Sanitize bool
Upcase bool
UseDefaultGateway bool
Prefix string
System string
Service string
Hostname string
TemplateFiles []string
}

var (
Expand All @@ -57,16 +59,66 @@ func init() {
}
}

func getEnvSlice(key string) []string {
ret := []string{}

vals := os.Getenv(key)
if len(vals) == 0 {
return ret
}

for _, val := range strings.Split(vals, ",") {
val = strings.TrimSpace(val)
if len(val) > 0 {
ret = append(ret, val)
}
}

return ret
}

func getEnvBool(key string, dflt bool) bool {
val := os.Getenv(key)
if len(val) == 0 {
return dflt
}

ret, err := strconv.ParseBool(val)
if err != nil {
log.Printf("[WARN] error parsing environment bool ($%s): %s", key, err)
return dflt
}

return ret
}

func getEnvDefault(key, dflt string) string {
ret := os.Getenv(key)
if len(ret) == 0 {
return dflt
}
return ret
}

func initLogger() {
logLevel := "WARN"
if val := os.Getenv("LOG_LEVEL"); len(val) > 0 {
logLevel = val
}

util.InitLogger(logLevel)
}

// Set modifies the current environment with variables retrieved from etcd. Set
// will not overwrite existing variables.
// On linux systems, the default gateway will be automatically used as the etcd
// endpoint.
// If $ETCD_ENDPOINT is set, it will override the default gateway.
// $ETCD_ENDPOINT should look like "http://127.0.0.1:4001".
// If $ETCD_PEERS is set, it will override the default gateway.
// $ETCD_PEERS should look like "http://127.0.0.1:4001".
// service should be set by the application calling Set and not derived from
// an environment variable.
// Set will also use some other environment variables if they exist.
// $ETCD_PREFIX defaults to "/config"
// $ENVETCD_PREFIX defaults to "/config"
// $HOSTNAME will be honored if it is set.
// An error is returned only if there was an actual error. Inability to
// determine the etcd endpoint as tolerated and not considered an error. In this
Expand All @@ -79,64 +131,49 @@ func Set(service string) error {
return nil
}
setRun = true
logLevel := os.Getenv("LOG_LEVEL")
if logLevel == "" {
logLevel = "WARN"
}
util.InitLogger(logLevel)
initLogger()

etcdEndpoint := os.Getenv("ETCD_ENDPOINT")
useDefaultGateway := getEnvBool("ETCD_USE_DEFAULT_GATEWAY", true)

useSync := true
if len(os.Getenv("ETCD_NO_SYNC")) > 0 {
useSync = false
}
useDefaultGateway := true
if len(os.Getenv("ENVETCD_USE_DEFAULT_GATEWAY")) > 0 {
if val, err := strconv.ParseBool(os.Getenv("ENVETCD_USE_DEFAULT_GATEWAY")); err != nil {
log.Printf("[INFO] envetcd.Set could not parse $ENVETCD_USE_DEFAULT_GATEWAY, defaulting to true: %v\n", err)
} else {
useDefaultGateway = val
}
}
peers := getEnvSlice("ETCD_PEERS")

if gatewayIP != nil && useDefaultGateway && len(etcdEndpoint) == 0 {
etcdEndpoint = fmt.Sprintf("http://%s:4001", gatewayIP.String())
if gatewayIP != nil && useDefaultGateway && len(peers) == 0 {
peers = []string{fmt.Sprintf("http://%s:4001", gatewayIP.String())}
} else {
useDefaultGateway = false
}

if len(etcdEndpoint) == 0 {
if len(peers) == 0 {
log.Println("[INFO] envetcd.Set returned after it could not determine the etcd endpoint")
return nil
}

config := &Config{
Etcd: &util.EtcdConfig{
Peers: []string{etcdEndpoint},
Sync: useSync,
Peers: peers,
Sync: !getEnvBool("ETCD_NO_SYNC", false),
UseDefaultGateway: useDefaultGateway,
},
Sanitize: true,
Upcase: true,
UseDefaultGateway: useDefaultGateway,
Prefix: os.Getenv("ETCD_PREFIX"),
Service: service,
Hostname: os.Getenv("HOSTNAME"),
Sanitize: true,
Upcase: true,
Prefix: getEnvDefault("ENVETCD_PREFIX", "/config"),
Service: service,
Hostname: os.Getenv("HOSTNAME"),
TemplateFiles: getEnvSlice("ENVETCD_TEMPLATES"),
}

if len(config.Etcd.Peers[0]) == 0 {
config.Etcd.Peers[0] = "http://127.0.0.1:4001"
}

if len(config.Prefix) == 0 {
config.Prefix = "/config"
}

keyPairs, err := GetKeyPairs(config)
if err != nil {
return err
}

log.Printf("[DEBUG] envetcd: %v => %v\n", "ETCD_ENDPOINT", etcdEndpoint)
keyPairs["ETCD_ENDPOINT"] = etcdEndpoint
etcdPeers := strings.Join(peers, ", ")
log.Printf("[DEBUG] envetcd: %v => %v\n", "ETCD_PEERS", etcdPeers)
keyPairs["ETCD_PEERS"] = etcdPeers

for key, value := range keyPairs {
if len(os.Getenv(key)) == 0 {
Expand All @@ -147,6 +184,51 @@ func Set(service string) error {
return nil
}

func processTemplates(keyPairs KeyPairs, tplFiles []string) {
const ext = ".tmpl"

data := map[string]interface{}{}
arrays := map[string][]string{}
for key, value := range keyPairs {
data[key] = value
arrays[key] = []string{}
for _, val := range strings.Split(value, ",") {
val = strings.TrimSpace(val)
if len(val) > 0 {
arrays[key] = append(arrays[key], val)
}
}
}
data["ARRAY"] = arrays

for _, tplFile := range tplFiles {
if filepath.Ext(tplFile) != ext {
tplFile += ext
}

tpl, err := template.ParseFiles(tplFile)
if err != nil {
log.Printf("[WARN] error parsing template (%s): %s", tplFile, err)
continue
}

fName := tplFile[0 : len(tplFile)-len(ext)]
f, err := os.Create(fName)
if err != nil {
log.Printf("[WARN] error creating file (%s): %s", fName, err)
continue
}
defer f.Close()

if err := tpl.Execute(f, data); err != nil {
log.Printf("[WARN] error writing file (%s): %s", fName, err)
continue
}

log.Printf("[INFO] wrote file %s", fName)
}
}

// GetKeyPairs takes a given config and client, and returns all key pairs
func GetKeyPairs(config *Config) (KeyPairs, error) {
const noSort = false
Expand Down Expand Up @@ -205,8 +287,8 @@ func GetKeyPairs(config *Config) (KeyPairs, error) {
keyPairs["ENVETCD_HOSTNAME"] = config.Hostname
}

if config.UseDefaultGateway && gatewayIP != nil {
keyPairs["ENVETCD_DEFAULT_GATEWAY"] = gatewayIP.String()
if config.Etcd.UseDefaultGateway && len(config.Etcd.Peers) == 1 {
keyPairs["ENVETCD_DEFAULT_GATEWAY"] = config.Etcd.Peers[0]
}

var keys []string
Expand All @@ -223,6 +305,8 @@ func GetKeyPairs(config *Config) (KeyPairs, error) {
log.Printf("[DEBUG] envetcd: %v => %v\n", key, keyPairs[key])
}

processTemplates(keyPairs, config.TemplateFiles)

return keyPairs, nil
}

Expand Down

0 comments on commit 380e387

Please sign in to comment.