Skip to content

Commit

Permalink
Finishes off template support for dests
Browse files Browse the repository at this point in the history
  • Loading branch information
tlm committed Oct 30, 2018
1 parent 840b885 commit d17f26c
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 102 deletions.
53 changes: 19 additions & 34 deletions cmd/config/dest.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,31 @@ import (
"github.com/tlmiller/disttrust/file"
)

func ToDest(id string, opts json.RawMessage) (dest.Dest, error) {
if id != "file" {
return nil, fmt.Errorf("unknown dest type '%s'", id)
}
uopts := map[string]string{}
err := json.Unmarshal(opts, &uopts)
if err != nil {
return nil, errors.Wrap(err, "parsing dest json")
}
fdest := dest.File{}
type Dest struct {
Dest string `json:"dest"`
DestOptions json.RawMessage `json:"destOpts"`
}

caFile, err := destBuilder(uopts["caFile"], uopts["caFileMode"],
uopts["caFileGid"], uopts["caFileUid"])
if err != nil {
return nil, errors.Wrap(err, "caFile")
}
fdest.CA = caFile
type DestMapper func(json.RawMessage) (dest.Dest, error)

cFile, err := destBuilder(uopts["certFile"], uopts["certFileMode"],
uopts["certFileGid"], uopts["certFileUid"])
if err != nil {
return nil, errors.Wrap(err, "certFile")
}
fdest.Certificate = cFile
var (
destMappings = make(map[string]DestMapper)
)

cbFile, err := destBuilder(uopts["certBundleFile"], uopts["certBundleFileMode"],
uopts["certBundleFileGid"], uopts["certBundleFileUid"])
if err != nil {
return nil, errors.Wrap(err, "certBundleFile")
func MapDest(id string, mapper DestMapper) error {
if _, exists := destMappings[id]; exists {
return fmt.Errorf("dest mapping already registered for id '%s'", id)
}
fdest.CertificateBundle = cbFile
destMappings[id] = mapper
return nil
}

pkfile, err := destBuilder(uopts["privKeyFile"], uopts["privKeyFileMode"],
uopts["privKeyFileGid"], uopts["privKeyFileUid"])
if err != nil {
return nil, errors.Wrap(err, "privKeyFile")
func ToDest(id string, opts json.RawMessage) (dest.Dest, error) {
mapper, exists := destMappings[id]
if !exists {
return nil, fmt.Errorf("dest mapper does not exist for id '%s'", id)
}
fdest.PrivateKey = pkfile

return &fdest, nil
return mapper(opts)
}

func destBuilder(path, mode, gid, uid string) (file.File, error) {
Expand Down
37 changes: 37 additions & 0 deletions cmd/config/dest_aggregate_mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package config

import (
"encoding/json"

"github.com/pkg/errors"

"github.com/tlmiller/disttrust/dest"
)

func destAggregateMapper(opts json.RawMessage) (dest.Dest, error) {
uopts := []Dest{}
err := json.Unmarshal(opts, &uopts)
if err != nil {
return nil, errors.Wrap(err, "parsing dest aggregate json")
}

dests := []dest.Dest{}
for _, rawDest := range uopts {
if rawDest.Dest == "" {
return nil, errors.New("aggregate dest missing 'dest' key")
}
dest, err := ToDest(rawDest.Dest, rawDest.DestOptions)
if err != nil {
return nil, errors.Wrap(err, "aggregate dest failed parsing")
}
dests = append(dests, dest)
}
return dest.NewAggregate(dests...), nil
}

func init() {
err := MapDest("aggregate", destAggregateMapper)
if err != nil {
panic(err)
}
}
59 changes: 59 additions & 0 deletions cmd/config/dest_file_mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package config

import (
"encoding/json"

"github.com/pkg/errors"

"github.com/tlmiller/disttrust/dest"
)

func destFileMapper(opts json.RawMessage) (dest.Dest, error) {
fileDests := []dest.Dest{}
uopts := map[string]string{}
err := json.Unmarshal(opts, &uopts)
if err != nil {
return nil, errors.Wrap(err, "parsing dest file json")
}

if uopts["caFile"] != "" {
caFile, err := destBuilder(uopts["caFile"], uopts["caFileMode"],
uopts["caFileGid"], uopts["caFileUid"])
if err != nil {
return nil, errors.Wrap(err, "caFile")
}
fileDests = append(fileDests, dest.NewTemplateFile(dest.CAFile, caFile))
}
if uopts["certFile"] != "" {
cFile, err := destBuilder(uopts["certFile"], uopts["certFileMode"],
uopts["certFileGid"], uopts["certFileUid"])
if err != nil {
return nil, errors.Wrap(err, "certFile")
}
fileDests = append(fileDests, dest.NewTemplateFile(dest.CertificateFile, cFile))
}
if uopts["certBundleFile"] != "" {
cbFile, err := destBuilder(uopts["certBundleFile"], uopts["certBundleFileMode"],
uopts["certBundleFileGid"], uopts["certBundleFileUid"])
if err != nil {
return nil, errors.Wrap(err, "certBundleFile")
}
fileDests = append(fileDests, dest.NewTemplateFile(dest.CertificateBundleFile, cbFile))
}
if uopts["privKeyFile"] != "" {
pkFile, err := destBuilder(uopts["privKeyFile"], uopts["privKeyFileMode"],
uopts["privKeyFileGid"], uopts["privKeyFileUid"])
if err != nil {
return nil, errors.Wrap(err, "privKeyFile")
}
fileDests = append(fileDests, dest.NewTemplateFile(dest.PrivateKeyFile, pkFile))
}
return dest.NewAggregate(fileDests...), nil
}

func init() {
err := MapDest("file", DestMapper(destFileMapper))
if err != nil {
panic(err)
}
}
37 changes: 37 additions & 0 deletions cmd/config/dest_template_file_mapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package config

import (
"encoding/json"

"github.com/pkg/errors"

"github.com/tlmiller/disttrust/dest"
)

func destTemplateFileMapper(opts json.RawMessage) (dest.Dest, error) {
uopts := map[string]string{}
err := json.Unmarshal(opts, &uopts)
if err != nil {
return nil, errors.Wrap(err, "parsing dest template json")
}

if uopts["source"] == "" {
return nil, errors.New("dest template does not have a source template path specificed")
}
if uopts["out"] == "" {
return nil, errors.New("dest template does not have an output path specificed")
}
outFile, err := destBuilder(uopts["out"], uopts["mode"], uopts["gid"],
uopts["uid"])
if err != nil {
return nil, errors.Wrap(err, "dest template output path")
}
return dest.NewTemplateFile(dest.TemplateFileLoader(uopts["source"]), outFile), nil
}

func init() {
err := MapDest("template", DestMapper(destTemplateFileMapper))
if err != nil {
panic(err)
}
}
25 changes: 25 additions & 0 deletions dest/aggregate_dest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dest

import (
"github.com/tlmiller/disttrust/provider"
)

type Aggregate struct {
Dests []Dest
}

func NewAggregate(dests ...Dest) *Aggregate {
return &Aggregate{
Dests: dests,
}
}

func (a *Aggregate) Send(res *provider.Response) error {
for _, dest := range a.Dests {
err := dest.Send(res)
if err != nil {
return err
}
}
return nil
}
48 changes: 48 additions & 0 deletions dest/aggregate_dest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dest

import (
"errors"
"testing"

"github.com/tlmiller/disttrust/provider"
)

type mockDest struct {
counter *int
fail bool
}

func (m *mockDest) Send(_ *provider.Response) error {
(*m.counter)++
if m.fail {
return errors.New("I was told to fail")
}
return nil
}

func TestAggregateCallsAllDests(t *testing.T) {
var counter int
agg := NewAggregate(&mockDest{&counter, false}, &mockDest{&counter, false},
&mockDest{&counter, false})
err := agg.Send(nil)
if err != nil {
t.Fatalf("unexpected error for aggregate send: %v", err)
}
if counter != 3 {
t.Fatalf("aggregate did not call all dests, expected 3 got %d", counter)
}
}

func TestAggregateCallDestFailure(t *testing.T) {
var counter int
agg := NewAggregate(&mockDest{&counter, false}, &mockDest{&counter, false},
&mockDest{&counter, true}, &mockDest{&counter, false},
&mockDest{&counter, false})
err := agg.Send(nil)
if err == nil {
t.Fatal("expected non nill err for aggregate failure send")
}
if counter != 3 {
t.Fatalf("aggregate did not call all dests, expected 3 got %d", counter)
}
}
76 changes: 8 additions & 68 deletions dest/file_dest.go
Original file line number Diff line number Diff line change
@@ -1,74 +1,14 @@
package dest

import (
"io/ioutil"
"os"
type FileDestType string

"github.com/pkg/errors"

"github.com/tlmiller/disttrust/file"
"github.com/tlmiller/disttrust/provider"
var (
CAFile FileDestType = "{{ .CA }}"
CertificateFile FileDestType = "{{ .Certificate }}"
CertificateBundleFile FileDestType = "{{ .Certificate }}\n{{ .CABundle }}"
PrivateKeyFile FileDestType = "{{ .PrivateKey }}"
)

type File struct {
CA file.File
Certificate file.File
CertificateBundle file.File
PrivateKey file.File
}

func (f *File) Send(res *provider.Response) error {

if res.CA != "" && f.CA.HasPath() {
err := ioutil.WriteFile(f.CA.Path, []byte(res.CA), f.CA.Mode)
if err != nil {
return errors.Wrap(err, "writing ca file")
}
err = f.CA.Chown()
if err != nil {
return errors.Wrap(err, "chown ca file")
}
}

if res.Certificate != "" && f.Certificate.HasPath() {
err := ioutil.WriteFile(f.Certificate.Path, []byte(res.Certificate),
f.Certificate.Mode)
if err != nil {
return errors.Wrap(err, "writing certificate file")
}
err = f.Certificate.Chown()
if err != nil {
return errors.Wrap(err, "chown certificate file")
}
}

if res.CABundle != "" && f.CertificateBundle.HasPath() {
s, err := os.OpenFile(f.CertificateBundle.Path,
os.O_WRONLY|os.O_TRUNC|os.O_CREATE, f.CertificateBundle.Mode)
defer s.Close()
if err != nil {
return errors.Wrap(err, "writing certificate bundle file")
}
_, err = s.WriteString(res.Certificate + "\n" + res.CABundle)
if err != nil {
return errors.Wrap(err, "writing certificate bundle file")
}
err = f.CertificateBundle.Chown()
if err != nil {
return errors.Wrap(err, "chown certificate bundle file")
}
}

if res.PrivateKey != "" && f.PrivateKey.HasPath() {
err := ioutil.WriteFile(f.PrivateKey.Path, []byte(res.PrivateKey),
f.PrivateKey.Mode)
if err != nil {
return errors.Wrap(err, "writing private key file")
}
err = f.PrivateKey.Chown()
if err != nil {
return errors.Wrap(err, "chown private key file")
}
}
return nil
func (f FileDestType) Load() (string, error) {
return string(f), nil
}
Loading

0 comments on commit d17f26c

Please sign in to comment.