Skip to content

Commit

Permalink
Fix log file mode, add octal number literal to TICKscript (influxdata…
Browse files Browse the repository at this point in the history
…#684)

* fix log file mode, add octal number literal to TICKscript

* Update CHANGELOG.md
  • Loading branch information
Nathaniel Cook authored Jun 28, 2016
1 parent e150515 commit df1832c
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 32 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
- [#656](https://github.com/influxdata/kapacitor/pull/656): Fix issues where an expression could not be passed as a function parameter in TICKscript.
- [#627](https://github.com/influxdata/kapacitor/issue/627): Fix where InfluxQL functions that returned a batch could drop tags.
- [#674](https://github.com/influxdata/kapacitor/issue/674): Fix panic with Join On and batches.
- [#665](https://github.com/influxdata/kapacitor/issue/665): BREAKING: Fix file mode not being correct for Alert.Log files.
Breaking change is that integers numbers prefixed with a 0 in TICKscript are interpreted as octal numbers.

## v1.0.0-beta2 [2016-06-17]

Expand Down
61 changes: 59 additions & 2 deletions integrations/streamer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/http/httptest"
"os"
"path"
"path/filepath"
"reflect"
"sync/atomic"
"testing"
Expand Down Expand Up @@ -3353,7 +3354,6 @@ stream
}

func TestStream_Alert(t *testing.T) {

requestCount := int32(0)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ad := kapacitor.AlertData{}
Expand Down Expand Up @@ -3415,7 +3415,6 @@ stream
.warn(lambda: "count" > warnThreshold)
.crit(lambda: "count" > critThreshold)
.post('` + ts.URL + `')
|log()
|httpOut('TestStream_Alert')
`

Expand Down Expand Up @@ -4348,6 +4347,64 @@ stream
t.Errorf("unexpected requestCount got %d exp 1", rc)
}
}
func TestStream_AlertLog(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "TestStream_AlertLog")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
normalPath := filepath.Join(tmpDir, "normal.log")
modePath := filepath.Join(tmpDir, "mode.log")
var script = fmt.Sprintf(`
stream
|from()
.measurement('cpu')
.where(lambda: "host" == 'serverA')
.groupBy('host')
|window()
.period(10s)
.every(10s)
|count('value')
|alert()
.id('kapacitor.{{ .Name }}.{{ index .Tags "host" }}')
.info(lambda: "count" > 6.0)
.warn(lambda: "count" > 7.0)
.crit(lambda: "count" > 8.0)
.log('%s')
.log('%s')
.mode(0644)
`, normalPath, modePath)

clock, et, replayErr, tm := testStreamer(t, "TestStream_Alert", script, nil)
defer tm.Close()

err = fastForwardTask(clock, et, replayErr, tm, 13*time.Second)
if err != nil {
t.Error(err)
}

normal, err := os.Open(normalPath)
if err != nil {
t.Fatalf("missing log file for alert %v", err)
}
defer normal.Close()
if stat, err := normal.Stat(); err != nil {
t.Fatal(err)
} else if exp, got := os.FileMode(0600), stat.Mode(); exp != got {
t.Errorf("unexpected normal file mode: got %v exp %v", got, exp)
}

mode, err := os.Open(modePath)
if err != nil {
t.Fatalf("missing log file for alert %v", err)
}
defer mode.Close()
if stat, err := mode.Stat(); err != nil {
t.Fatal(err)
} else if exp, got := os.FileMode(0644), stat.Mode(); exp != got {
t.Errorf("unexpected normal file mode: got %v exp %v", got, exp)
}
}

func TestStream_AlertSigma(t *testing.T) {
requestCount := int32(0)
Expand Down
19 changes: 19 additions & 0 deletions pipeline/alert.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package pipeline

import (
"fmt"
"os"
"reflect"
"time"

Expand Down Expand Up @@ -306,6 +308,15 @@ func newAlertNode(wants EdgeType) *AlertNode {
return a
}

func (n *AlertNode) validate() error {
for _, lh := range n.LogHandlers {
if err := lh.validate(); err != nil {
return err
}
}
return nil
}

//tick:ignore
func (n *AlertNode) ChainMethods() map[string]reflect.Value {
return map[string]reflect.Value{
Expand Down Expand Up @@ -539,9 +550,17 @@ type LogHandler struct {
FilePath string

// File's mode and permissions, default is 0600
// NOTE: The leading 0 is required to interpret the value as an octal integer.
Mode int64
}

func (h *LogHandler) validate() error {
if os.FileMode(h.Mode).Perm()&0200 == 0 {
return fmt.Errorf("invalid file mode %o, must be user writable", h.Mode)
}
return nil
}

// Send alert to VictorOps.
// To use VictorOps alerting you must first enable the 'Alert Ingestion API'
// in the 'Integrations' section of VictorOps.
Expand Down
54 changes: 40 additions & 14 deletions tick/ast/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ast

import (
"bytes"
"errors"
"fmt"
"regexp"
"strconv"
Expand Down Expand Up @@ -59,6 +60,11 @@ func (p position) String() string {
return fmt.Sprintf("%dl%dc%d", p.pos, p.line, p.char)
}

const (
octal = 8
decimal = 10
)

// numberNode holds a number: signed or unsigned integer or float.
// The value is parsed and stored under all the types that can represent the value.
// This simulates in a small amount of code the behavior of Go's ideal constants.
Expand All @@ -68,6 +74,7 @@ type NumberNode struct {
IsFloat bool // Number has a floating-point value.
Int64 int64 // The integer value.
Float64 float64 // The floating-point value.
Base int // The base of an integer value.
Comment *CommentNode
}

Expand All @@ -77,23 +84,37 @@ func newNumber(p position, text string, c *CommentNode) (*NumberNode, error) {
position: p,
Comment: c,
}
i, err := strconv.ParseInt(text, 10, 64)
if err == nil {
n.IsInt = true
n.Int64 = i
if n.Int64 < 0 {
panic("parser should not allow for negative number nodes")
}
} else {

if text == "" {
return nil, errors.New("invalid number literal, empty string")
}

if s := strings.IndexRune(text, '.'); s != -1 {
f, err := strconv.ParseFloat(text, 64)
if err == nil {
n.IsFloat = true
n.Float64 = f
if n.Float64 < 0 {
panic("parser should not allow for negative number nodes")
return nil, errors.New("parser should not allow for negative number nodes")
}
}
} else {
if text[0] == '0' && len(text) > 1 {
// We have an octal number
n.Base = octal
} else {
n.Base = decimal
}
i, err := strconv.ParseInt(text, n.Base, 64)
if err == nil {
n.IsInt = true
n.Int64 = i
}
if n.Int64 < 0 {
return nil, errors.New("parser should not allow for negative number nodes")
}
}

if !n.IsInt && !n.IsFloat {
return nil, fmt.Errorf("illegal number syntax: %q", text)
}
Expand All @@ -102,9 +123,9 @@ func newNumber(p position, text string, c *CommentNode) (*NumberNode, error) {

func (n *NumberNode) String() string {
if n.IsInt {
return fmt.Sprintf("NumberNode@%v{%di}%v", n.position, n.Int64, n.Comment)
return fmt.Sprintf("NumberNode@%v{%di,b%d}%v", n.position, n.Int64, n.Base, n.Comment)
}
return fmt.Sprintf("NumberNode@%v{%f}%v", n.position, n.Float64, n.Comment)
return fmt.Sprintf("NumberNode@%v{%f,b%d}%v", n.position, n.Float64, n.Base, n.Comment)
}

func (n *NumberNode) Format(buf *bytes.Buffer, indent string, onNewLine bool) {
Expand All @@ -114,7 +135,10 @@ func (n *NumberNode) Format(buf *bytes.Buffer, indent string, onNewLine bool) {
}
writeIndent(buf, indent, onNewLine)
if n.IsInt {
buf.WriteString(strconv.FormatInt(n.Int64, 10))
if n.Base == octal {
buf.WriteByte('0')
}
buf.WriteString(strconv.FormatInt(n.Int64, n.Base))
} else {
s := strconv.FormatFloat(n.Float64, 'f', -1, 64)
if strings.IndexRune(s, '.') == -1 {
Expand Down Expand Up @@ -143,6 +167,7 @@ func (n *NumberNode) Equal(o interface{}) bool {
type DurationNode struct {
position
Dur time.Duration //the duration
Literal string
Comment *CommentNode
}

Expand All @@ -151,6 +176,7 @@ func newDur(p position, text string, c *CommentNode) (*DurationNode, error) {
n := &DurationNode{
position: p,
Comment: c,
Literal: text,
}
d, err := influxql.ParseDuration(text)
if err != nil {
Expand All @@ -161,7 +187,7 @@ func newDur(p position, text string, c *CommentNode) (*DurationNode, error) {
}

func (n *DurationNode) String() string {
return fmt.Sprintf("DurationNode@%v{%v}%v", n.position, n.Dur, n.Comment)
return fmt.Sprintf("DurationNode@%v{%v,%q}%v", n.position, n.Dur, n.Literal, n.Comment)
}

func (n *DurationNode) Format(buf *bytes.Buffer, indent string, onNewLine bool) {
Expand All @@ -170,7 +196,7 @@ func (n *DurationNode) Format(buf *bytes.Buffer, indent string, onNewLine bool)
onNewLine = true
}
writeIndent(buf, indent, onNewLine)
buf.WriteString(influxql.FormatDuration(n.Dur))
buf.WriteString(n.Literal)
}
func (n *DurationNode) SetComment(c *CommentNode) {
n.Comment = c
Expand Down
Loading

0 comments on commit df1832c

Please sign in to comment.