diff --git a/cmd/mixtool/server.go b/cmd/mixtool/server.go index 19da711..45f50a9 100644 --- a/cmd/mixtool/server.go +++ b/cmd/mixtool/server.go @@ -16,7 +16,6 @@ package main import ( "bufio" - "bytes" "context" "errors" "fmt" @@ -24,6 +23,7 @@ import ( "io/ioutil" "net/http" "os" + "path/filepath" "github.com/urfave/cli" ) @@ -99,39 +99,56 @@ type ruleProvisioner struct { // to existing, does not provision them. It returns whether Prometheus should // be reloaded and if an error has occurred. func (p *ruleProvisioner) provision(r io.Reader) (bool, error) { - b := bytes.NewBuffer(nil) - tr := io.TeeReader(r, b) + newData, err := ioutil.ReadAll(r) + if err != nil { + return false, fmt.Errorf("unable to read new rules: %w", err) + } - f, err := os.Open(p.ruleFile) - if err != nil && !os.IsNotExist(err) { - return false, fmt.Errorf("open rule file: %w", err) + tempfile, err := ioutil.TempFile(filepath.Dir(p.ruleFile), "temp-mixtool") + if err != nil { + return false, fmt.Errorf("unable to create temp file: %w", err) } - if os.IsNotExist(err) { - f, err = os.Create(p.ruleFile) - if err != nil { - return false, fmt.Errorf("create rule file: %w", err) - } + + n, err := tempfile.Write(newData) + if err != nil { + return false, fmt.Errorf("error when writing new rules: %w", err) } - equal, err := readersEqual(tr, f) + if n != len(newData) { + return false, fmt.Errorf("writing error, wrote %d bytes, expected %d", n, len(newData)) + } + + tempfile.Sync() + + ruleFileReader, err := os.OpenFile(p.ruleFile, os.O_RDWR, 0644) if err != nil { - return false, fmt.Errorf("compare existing rules with provisioned intention: %w", err) + return false, fmt.Errorf("unable to read existing rules: %w", err) } - if equal { - return false, nil + + newFileReader, err := os.OpenFile(tempfile.Name(), os.O_RDWR, 0644) + if err != nil { + return false, fmt.Errorf("unable to open new rules file: %w", err) } - if err := f.Truncate(0); err != nil { - return false, fmt.Errorf("truncate file: %w", err) + equal, err := readersEqual(newFileReader, ruleFileReader) + if err != nil { + return false, fmt.Errorf("error from readersEqual: %w", err) } - if _, err := io.Copy(f, b); err != nil { - return false, fmt.Errorf("provision rule to file: %w", err) + if equal { + return false, nil } + if err = os.Rename(tempfile.Name(), p.ruleFile); err != nil { + return false, fmt.Errorf("cannot rename rules file: %w", err) + } return true, nil } +type prometheusReloader struct { + prometheusReloadURL string +} + func readersEqual(r1, r2 io.Reader) (bool, error) { buf1 := bufio.NewReader(r1) buf2 := bufio.NewReader(r2) @@ -153,10 +170,6 @@ func readersEqual(r1, r2 io.Reader) (bool, error) { } } -type prometheusReloader struct { - prometheusReloadURL string -} - func (r *prometheusReloader) triggerReload(ctx context.Context) error { req, err := http.NewRequest("POST", r.prometheusReloadURL, nil) if err != nil { diff --git a/go.mod b/go.mod index c9dc2b0..70b8548 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect github.com/go-macaron/session v0.0.0-20170320172209-b8e286a0dba8 // indirect github.com/gobuffalo/packr v1.30.1 - github.com/gobuffalo/packr/v2 v2.8.0 + github.com/gobuffalo/packr/v2 v2.8.1 github.com/google/go-jsonnet v0.16.1-0.20200908152747-b70cbd441a39 github.com/gosimple/slug v1.2.0 // indirect github.com/grafana/grafana v5.2.4+incompatible diff --git a/go.sum b/go.sum index 7dcd3e0..4bff3c9 100644 --- a/go.sum +++ b/go.sum @@ -313,6 +313,8 @@ github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHx github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= github.com/gobuffalo/packr/v2 v2.8.0 h1:IULGd15bQL59ijXLxEvA5wlMxsmx/ZkQv9T282zNVIY= github.com/gobuffalo/packr/v2 v2.8.0/go.mod h1:PDk2k3vGevNE3SwVyVRgQCCXETC9SaONCNSXT1Q8M1g= +github.com/gobuffalo/packr/v2 v2.8.1 h1:tkQpju6i3EtMXJ9uoF5GT6kB+LMTimDWD8Xvbz6zDVA= +github.com/gobuffalo/packr/v2 v2.8.1/go.mod h1:c/PLlOuTU+p3SybaJATW3H6lX/iK7xEz5OeMf+NnJpg= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -491,6 +493,8 @@ github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0L github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/karrick/godirwalk v1.15.5 h1:ErdAEFW/cKxQ5+9Gm/hopxB8ki21/di+vyNb9mHnHrA= github.com/karrick/godirwalk v1.15.5/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/karrick/godirwalk v1.15.8 h1:7+rWAZPn9zuRxaIqqT8Ohs2Q2Ac0msBqwRdxNCr2VVs= +github.com/karrick/godirwalk v1.15.8/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=