diff --git a/go.sum b/go.sum index cd0381cfe..02cfa4dd1 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,6 @@ github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8Wlg github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= -github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= -github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -179,6 +177,7 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= @@ -269,9 +268,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= @@ -296,8 +292,6 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -337,9 +331,6 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/template/funcs.go b/template/funcs.go index 09db41976..4c20c4b4e 100644 --- a/template/funcs.go +++ b/template/funcs.go @@ -27,14 +27,15 @@ import ( "github.com/BurntSushi/toml" spewLib "github.com/davecgh/go-spew/spew" - dep "github.com/hashicorp/consul-template/dependency" "github.com/hashicorp/consul/api" socktmpl "github.com/hashicorp/go-sockaddr/template" "github.com/imdario/mergo" "github.com/pkg/errors" "golang.org/x/text/cases" "golang.org/x/text/language" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" + + dep "github.com/hashicorp/consul-template/dependency" ) // now is function that represents the current time in UTC. This is here @@ -764,6 +765,35 @@ func byKey(pairs []*dep.KeyPair) (map[string]map[string]*dep.KeyPair, error) { return m, nil } +// byPort is a template func that takes the provided services and +// produces a map based on Service Port. +// +// The map key is an integer representing the service port. The map value is a +// slice of Services which have the port assigned. +func byPort(in interface{}) (map[int][]interface{}, error) { + m := make(map[int][]interface{}) + + switch typed := in.(type) { + case nil: + case []*dep.CatalogService: + for _, s := range typed { + m[s.ServicePort] = append(m[s.ServicePort], s) + } + case []*dep.HealthService: + for _, s := range typed { + m[s.Port] = append(m[s.Port], s) + } + case []*dep.NomadService: + for _, s := range typed { + m[s.Port] = append(m[s.Port], s) + } + default: + return nil, fmt.Errorf("byPort: wrong argument type %T", in) + } + + return m, nil +} + // byTag is a template func that takes the provided services and // produces a map based on Service tags. // diff --git a/template/funcs_test.go b/template/funcs_test.go index 20a47869c..a7bd1d59e 100644 --- a/template/funcs_test.go +++ b/template/funcs_test.go @@ -10,6 +10,9 @@ import ( "runtime" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + dep "github.com/hashicorp/consul-template/dependency" ) @@ -203,6 +206,97 @@ func Test_byMeta(t *testing.T) { } } +func Test_byPort(t *testing.T) { + tests := []struct { + name string + services interface{} + wantGroupIDs map[int][]string + wantErr error + }{ + { + name: "HealthService", + services: []*dep.HealthService{ + {Port: 8080, ID: "svcA"}, + {Port: 8080, ID: "svcB"}, + {Port: 9090, ID: "svcC"}, + }, + wantGroupIDs: map[int][]string{ + 8080: {"svcA", "svcB"}, + 9090: {"svcC"}, + }, + wantErr: nil, + }, + { + name: "CatalogService", + services: []*dep.CatalogService{ + {ServicePort: 8080, ID: "svcA"}, + {ServicePort: 8080, ID: "svcB"}, + {ServicePort: 9090, ID: "svcC"}, + }, + wantGroupIDs: map[int][]string{ + 8080: {"svcA", "svcB"}, + 9090: {"svcC"}, + }, + wantErr: nil, + }, + { + name: "NomadService", + services: []*dep.NomadService{ + {Port: 8080, ID: "svcA"}, + {Port: 8080, ID: "svcB"}, + {Port: 9090, ID: "svcC"}, + }, + wantGroupIDs: map[int][]string{ + 8080: {"svcA", "svcB"}, + 9090: {"svcC"}, + }, + wantErr: nil, + }, + { + name: "empty", + services: []*dep.HealthService{}, + wantGroupIDs: map[int][]string{}, + wantErr: nil, + }, + { + name: "unsupported type", + services: []*dep.CatalogSnippet{ + {Name: "svcA"}, + }, + wantGroupIDs: map[int][]string{}, + wantErr: fmt.Errorf("byPort: wrong argument type []*dependency.CatalogSnippet"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotGroups, err := byPort(tt.services) + if tt.wantErr == nil { + require.NoError(t, err) + } else { + assert.EqualError(t, err, tt.wantErr.Error()) + } + + gotGroupIDs := make(map[int][]string) + for port, services := range gotGroups { + for _, service := range services { + switch tService := service.(type) { + case *dep.HealthService: + gotGroupIDs[port] = append(gotGroupIDs[port], tService.ID) + case *dep.CatalogService: + gotGroupIDs[port] = append(gotGroupIDs[port], tService.ID) + case *dep.NomadService: + gotGroupIDs[port] = append(gotGroupIDs[port], tService.ID) + } + } + } + + if !reflect.DeepEqual(gotGroupIDs, tt.wantGroupIDs) { + t.Errorf("byTag() = %v, want %v", gotGroupIDs, tt.wantGroupIDs) + } + }) + } +} + func Test_sha256Hex(t *testing.T) { type args struct { item string diff --git a/template/template.go b/template/template.go index 28b5265d1..8e7f42ed2 100644 --- a/template/template.go +++ b/template/template.go @@ -12,10 +12,11 @@ import ( "text/template" "github.com/Masterminds/sprig/v3" - "github.com/hashicorp/consul-template/config" - dep "github.com/hashicorp/consul-template/dependency" "github.com/pkg/errors" "golang.org/x/exp/maps" + + "github.com/hashicorp/consul-template/config" + dep "github.com/hashicorp/consul-template/dependency" ) var ( @@ -366,6 +367,7 @@ func funcMap(i *funcMapInput) template.FuncMap { "base64URLDecode": base64URLDecode, "base64URLEncode": base64URLEncode, "byKey": byKey, + "byPort": byPort, "byTag": byTag, "contains": contains, "containsAll": containsSomeFunc(true, true),