Skip to content
This repository has been archived by the owner on Sep 2, 2021. It is now read-only.

Commit

Permalink
Overhauling notification process (#6)
Browse files Browse the repository at this point in the history
* Overhauling notification process

* Fixing check/notify behaviour
  • Loading branch information
emcniece authored Mar 7, 2017
1 parent 282de11 commit db8124f
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 94 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ rancher-gen
secrets.txt
.DS_Store
go-rancher-gen
/docker-compose.yml
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
FROM alpine:edge
MAINTAINER <[email protected]>
MAINTAINER CausticLab

RUN apk add --no-cache ca-certificates

ENV RANCHER_GEN_RELEASE v0.4.3

ADD https://github.com/janeczku/go-rancher-gen/releases/download/${RANCHER_GEN_RELEASE}/rancher-gen-linux-amd64.tar.gz /tmp/rancher-gen.tar.gz
ADD https://github.com/causticlab/go-rancher-gen/releases/download/${RANCHER_GEN_RELEASE}/rancher-gen-linux-amd64.tar.gz /tmp/rancher-gen.tar.gz
RUN tar -zxvf /tmp/rancher-gen.tar.gz -C /usr/local/bin \
&& chmod +x /usr/local/bin/rancher-gen

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
PROJECT := rancher-gen
PLATFORM := linux
ARCH := amd64
DOCKER_IMAGE := janeczku/$(PROJECT)
DOCKER_IMAGE := causticlab/$(PROJECT)

VERSION := $(shell cat VERSION)
GITSHA := $(shell git rev-parse --short HEAD)
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.4.4
v0.5.0
2 changes: 2 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Template struct {
NotifyCmd string `toml:"notify-cmd"`
NotifyLbl string `toml:"notify-lbl"`
NotifyOutput bool `toml:"notify-output"`
Staging string ""
}

func initConfig() (*Config, error) {
Expand Down Expand Up @@ -85,6 +86,7 @@ func setTemplateFromFlags(conf *Config) {
NotifyCmd: notifyCmd,
NotifyLbl: notifyLbl,
NotifyOutput: notifyOutput,
Staging: "",
}
conf.Templates = []Template{tmpl}
}
Expand Down
200 changes: 110 additions & 90 deletions runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,94 +119,130 @@ func (r *runner) poll() error {
}

func (r *runner) processTemplate(funcs template.FuncMap, t Template) error {
log.Debugf("Processing template %s for destination %s", t.Source, t.Dest)
if _, err := os.Stat(t.Source); os.IsNotExist(err) {
log.Fatalf("Template '%s' is missing", t.Source)
}

tmplBytes, err := ioutil.ReadFile(t.Source)
if err != nil {
log.Fatalf("Could not read template '%s': %v", t.Source, err)
}
if (t.Source != "") && (t.Dest != "") {
log.Debugf("Processing template %s for destination %s", t.Source, t.Dest)
if _, err := os.Stat(t.Source); os.IsNotExist(err) {
log.Fatalf("Template '%s' is missing", t.Source)
}

name := filepath.Base(t.Source)
newTemplate, err := template.New(name).Funcs(funcs).Parse(string(tmplBytes))
if err != nil {
log.Fatalf("Could not parse template '%s': %v", t.Source, err)
}
tmplBytes, err := ioutil.ReadFile(t.Source)
if err != nil {
log.Fatalf("Could not read template '%s': %v", t.Source, err)
}

buf := new(bytes.Buffer)
if err := newTemplate.Execute(buf, nil); err != nil {
log.Fatalf("Could not render template: '%s': %v", t.Source, err)
}
name := filepath.Base(t.Source)
newTemplate, err := template.New(name).Funcs(funcs).Parse(string(tmplBytes))
if err != nil {
log.Fatalf("Could not parse template '%s': %v", t.Source, err)
}

content := buf.Bytes()
buf := new(bytes.Buffer)
if err := newTemplate.Execute(buf, nil); err != nil {
log.Fatalf("Could not render template: '%s': %v", t.Source, err)
}

if t.Dest == "" {
log.Debug("No destination specified. Printing to StdOut")
os.Stdout.Write(content)
return nil
}
content := buf.Bytes()

log.Debug("Checking whether content has changed")
same, err := sameContent(content, t.Dest)
if err != nil {
return fmt.Errorf("Could not compare content for %s: %v", t.Dest, err)
}
if t.Dest == "" {
log.Debug("No destination specified. Printing to StdOut")
os.Stdout.Write(content)
return nil
}

if same {
log.Debugf("Destination %s is up to date", t.Dest)
return nil
}
log.Debug("Checking whether content has changed")
same, err := sameContent(content, t.Dest)
if err != nil {
return fmt.Errorf("Could not compare content for %s: %v", t.Dest, err)
}

log.Debug("Creating staging file")
stagingFile, err := createStagingFile(content, t.Dest)
if err != nil {
return err
}
if same {
log.Debugf("Destination %s is up to date", t.Dest)
return nil
}

defer os.Remove(stagingFile)
log.Debug("Creating staging file")
stagingFile, err := createStagingFile(content, t.Dest)
t.Staging = stagingFile
if err != nil {
return err
}

if t.CheckCmd != "" {
if t.NotifyLbl != "" {
if err := r.execLabelGroup("check", t.CheckCmd, t.NotifyLbl, t.NotifyOutput, stagingFile); err != nil {
return fmt.Errorf("Notify Group command failed: %v", err)
}
log.Debugf("Writing destination")
if err := copyStagingToDestination(stagingFile, t.Dest); err != nil {
return fmt.Errorf("Could not write destination file %s: %v", t.Dest, err)
}

log.Info("Destination file has been updated: ", t.Dest)

defer os.Remove(stagingFile)

} else {
// No source or dest - just run check/notify commands
log.Debugf("No template - processing commands")
}

if t.NotifyLbl == "" {
// Basic check/notify command, no label group
r.runCheckNotify(t, "", "");
} else {
if err := check(t.CheckCmd, stagingFile); err != nil {
return fmt.Errorf("Check command failed: %v", err)
// Possible multi-container check/notify from label group
toNotify, _ := r.getLabelGroup(t.NotifyLbl)

for _, c := range toNotify {
log.Debugf("Parsing: %+v", c.Name)
parsedCheck, _ := parseCmdTemplate(c, t.CheckCmd)
parsedNotify, _ := parseCmdTemplate(c, t.NotifyCmd)

err := r.runCheckNotify(t, parsedCheck, parsedNotify);
if err != nil {
fmt.Errorf("Check notification failed for check: %v\nnotify: %v\nError: %v", parsedCheck, parsedNotify, err)
}
}
}

return nil
}

func (r *runner) runCheckNotify(t Template, parsedCheck string, parsedNotify string) error {
var err error

checkCmd := ""
if parsedCheck != "" {
checkCmd = parsedCheck
} else {
checkCmd = t.CheckCmd
}

log.Debugf("Writing destination")
if err = copyStagingToDestination(stagingFile, t.Dest); err != nil {
return fmt.Errorf("Could not write destination file %s: %v", t.Dest, err)
if checkCmd != "" {
command := strings.Replace(checkCmd, "{{staging}}", t.Staging, -1)
if err := check(command); err != nil {
return fmt.Errorf("Check command failed: %v", err)
}
}

log.Info("Destination file %s has been updated", t.Dest)
notifyCmd := ""
if parsedNotify != "" {
notifyCmd = parsedNotify
} else {
notifyCmd = t.NotifyCmd
}

if t.NotifyCmd != "" {
if t.NotifyLbl != "" {
if err := r.execLabelGroup("notify", t.NotifyCmd, t.NotifyLbl, t.NotifyOutput, ""); err != nil {
return fmt.Errorf("Notify Group command failed: %v", err)
}
} else {
if err := notify(t.NotifyCmd, t.NotifyOutput); err != nil {
return fmt.Errorf("Notify command failed: %v", err)
}
if notifyCmd != "" {
if err := notify(notifyCmd, t.NotifyOutput); err != nil {
return fmt.Errorf("Notify command failed: %v", err)
}
}

return nil
return err
}

func (r *runner) execLabelGroup(action string, command string, label string, verbose bool, filePath string) error {
func (r *runner) getLabelGroup(label string) ([]Container, error){
nLabelName, nLabelValue := "", ""
toNotify := []Container{} // may be more than just Containers in the future

if label == "" {
return fmt.Errorf("NotifyLabelGroup failed: no label specified")
return nil, fmt.Errorf("NotifyLabelGroup failed: no label specified")
}

split := strings.Split(label, ":")
Expand All @@ -224,7 +260,7 @@ func (r *runner) execLabelGroup(action string, command string, label string, ver
ctx, err := r.createContext()
if err != nil {
time.Sleep(time.Second * 2)
return fmt.Errorf("Failed to create context from Rancher Metadata: %v", err)
return nil, fmt.Errorf("Failed to create context from Rancher Metadata: %v", err)
}

// Search Services?
Expand All @@ -234,42 +270,24 @@ func (r *runner) execLabelGroup(action string, command string, label string, ver
for lbl, val := range c.Labels {
if lbl == nLabelName {
if (nLabelValue == "") || (val == nLabelValue) {
fmt.Printf("NOTIFY: %+v :: [%+v:%+v]\n", c.Name, lbl, val)
log.Debugf("NOTIFY: %+v :: [%+v:%+v]", c.Name, lbl, val)
toNotify = append(toNotify, c)
}
}
}
}

// Iterate matched containers & notify
for _, c := range toNotify {
pCommand, _ := parseCmdTemplate(c, command)

if action == "check" {
if err := check(pCommand, filePath); err != nil {
fmt.Errorf("Check command failed: %v", err)
}
} else if action == "notify"{
if err := notify(pCommand, verbose); err != nil {
fmt.Errorf("Notify command failed: %v", err)
}
}
}

return nil
return toNotify, err;
}

func parseCmdTemplate(c Container, command string) (string, error) {
ret := command
fmt.Printf("Parsing: %+v\n", c.Name)

reg, _ := regexp.Compile(`{{[\w\.]*}}`)
matches := reg.FindAll( []byte(ret), -1)

reg, _ := regexp.Compile(`{{[\w\.]*}}`)
matches := reg.FindAll( []byte(ret), -1)
cStruct := structs.New(c)

for _, match := range matches {
key := strings.Trim(string(match), "{}")
for _, match := range matches {
key := strings.Trim(string(match), "{}")
if strings.Index(key, ".") == 0{
key = strings.Replace(key, ".", "", 1)
}
Expand All @@ -287,7 +305,7 @@ func parseCmdTemplate(c Container, command string) (string, error) {
}
}
}
}
}

return ret, nil
}
Expand Down Expand Up @@ -441,17 +459,19 @@ func parseServicePorts(ports []string) []ServicePort {
return ret
}

func check(command, filePath string) error {
command = strings.Replace(command, "{{staging}}", filePath, -1)
func check(command string) error {
//command = strings.Replace(command, "{{staging}}", filePath, -1)
log.Debugf("Running check command '%s'", command)
cmd := exec.Command("/bin/sh", "-c", command)
out, err := cmd.CombinedOutput()

if err != nil {
log.Printf("Check failed, skipping notify-cmd");
logCmdOutput(command, out)
return err
}

log.Debugf("Check cmd output: %q", string(out))
//log.Debugf("Check cmd output: %q", string(out))
return nil
}

Expand Down

0 comments on commit db8124f

Please sign in to comment.