2023-03-28 18:39:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2014-01-06 21:21:48 +00:00
|
|
|
package agent
|
|
|
|
|
|
|
|
import (
|
2016-12-13 06:09:35 +00:00
|
|
|
"bytes"
|
2020-01-28 23:50:41 +00:00
|
|
|
"context"
|
2018-04-30 21:23:49 +00:00
|
|
|
"crypto/tls"
|
2018-03-21 17:55:39 +00:00
|
|
|
"crypto/x509"
|
2018-09-27 13:33:12 +00:00
|
|
|
"encoding/json"
|
2014-01-06 21:21:48 +00:00
|
|
|
"fmt"
|
2016-11-16 21:45:26 +00:00
|
|
|
"io"
|
2014-01-06 21:21:48 +00:00
|
|
|
"net/http"
|
2015-01-15 09:17:35 +00:00
|
|
|
"net/http/httptest"
|
2019-04-16 16:00:15 +00:00
|
|
|
"net/url"
|
2020-05-20 10:38:29 +00:00
|
|
|
"os"
|
2019-09-26 16:54:14 +00:00
|
|
|
"strconv"
|
2016-03-03 01:08:06 +00:00
|
|
|
"strings"
|
2014-01-06 21:21:48 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
2015-05-11 23:48:10 +00:00
|
|
|
|
2021-07-15 23:04:24 +00:00
|
|
|
"github.com/armon/go-metrics"
|
2023-05-30 22:25:48 +00:00
|
|
|
|
2023-02-06 17:14:35 +00:00
|
|
|
"github.com/hashicorp/consul/api"
|
2023-05-30 22:25:48 +00:00
|
|
|
"github.com/hashicorp/consul/version"
|
|
|
|
|
2021-07-15 23:04:24 +00:00
|
|
|
"github.com/hashicorp/go-hclog"
|
2020-11-30 17:53:46 +00:00
|
|
|
"github.com/hashicorp/go-uuid"
|
|
|
|
"github.com/hashicorp/serf/serf"
|
2021-07-26 21:12:29 +00:00
|
|
|
"github.com/mitchellh/hashstructure"
|
2020-11-30 17:53:46 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"golang.org/x/time/rate"
|
|
|
|
|
2017-08-23 14:52:48 +00:00
|
|
|
"github.com/hashicorp/consul/acl"
|
2022-06-17 09:24:43 +00:00
|
|
|
"github.com/hashicorp/consul/acl/resolver"
|
2017-09-25 18:40:42 +00:00
|
|
|
"github.com/hashicorp/consul/agent/config"
|
2018-03-21 17:20:35 +00:00
|
|
|
"github.com/hashicorp/consul/agent/connect"
|
2021-02-08 19:18:51 +00:00
|
|
|
"github.com/hashicorp/consul/agent/connect/ca"
|
2020-09-16 17:29:59 +00:00
|
|
|
"github.com/hashicorp/consul/agent/consul"
|
2018-10-17 20:20:35 +00:00
|
|
|
"github.com/hashicorp/consul/agent/debug"
|
2018-09-27 13:33:12 +00:00
|
|
|
"github.com/hashicorp/consul/agent/local"
|
2017-07-06 10:34:00 +00:00
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2019-10-04 18:37:34 +00:00
|
|
|
"github.com/hashicorp/consul/agent/token"
|
2019-02-27 19:28:31 +00:00
|
|
|
tokenStore "github.com/hashicorp/consul/agent/token"
|
2023-02-06 17:14:35 +00:00
|
|
|
"github.com/hashicorp/consul/envoyextensions/xdscommon"
|
2022-05-19 20:03:46 +00:00
|
|
|
"github.com/hashicorp/consul/lib"
|
2019-12-06 19:01:34 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
2019-03-27 12:54:56 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
2019-04-16 16:00:15 +00:00
|
|
|
"github.com/hashicorp/consul/testrpc"
|
2016-06-07 20:24:51 +00:00
|
|
|
"github.com/hashicorp/consul/types"
|
2014-01-06 21:21:48 +00:00
|
|
|
)
|
|
|
|
|
2021-07-20 21:52:34 +00:00
|
|
|
func createACLTokenWithAgentReadPolicy(t *testing.T, srv *HTTPHandlers) string {
|
|
|
|
policyReq := &structs.ACLPolicy{
|
|
|
|
Name: "agent-read",
|
|
|
|
Rules: `agent_prefix "" { policy = "read" }`,
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
2021-07-20 21:52:34 +00:00
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/acl/policy", jsonReader(policyReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2016-12-14 17:33:57 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2021-07-20 21:52:34 +00:00
|
|
|
|
|
|
|
tokenReq := &structs.ACLToken{
|
|
|
|
Description: "agent-read-token-for-test",
|
|
|
|
Policies: []structs.ACLTokenPolicyLink{{Name: "agent-read"}},
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
2021-07-20 21:52:34 +00:00
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/acl/token", jsonReader(tokenReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-07-20 21:52:34 +00:00
|
|
|
resp = httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
svcToken := &structs.ACLToken{}
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
err := dec.Decode(svcToken)
|
2021-07-20 21:52:34 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
return svcToken.SecretID
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_Services(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2014-01-21 01:06:44 +00:00
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-21 01:06:44 +00:00
|
|
|
srv1 := &structs.NodeService{
|
|
|
|
ID: "mysql",
|
|
|
|
Service: "mysql",
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2018-05-12 10:27:44 +00:00
|
|
|
Meta: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
Port: 5000,
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
require.NoError(t, a.State.AddServiceWithChecks(srv1, nil, "", false))
|
2018-04-20 13:24:24 +00:00
|
|
|
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
2021-11-03 15:12:36 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := decoder.Decode(&val)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Lenf(t, val, 1, "bad services: %v", val)
|
2018-04-20 13:24:24 +00:00
|
|
|
assert.Equal(t, 5000, val["mysql"].Port)
|
2018-05-12 10:27:44 +00:00
|
|
|
assert.Equal(t, srv1.Meta, val["mysql"].Meta)
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
|
|
|
|
2019-04-16 16:00:15 +00:00
|
|
|
func TestAgent_ServicesFiltered(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-04-16 16:00:15 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2019-04-16 16:00:15 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
srv1 := &structs.NodeService{
|
|
|
|
ID: "mysql",
|
|
|
|
Service: "mysql",
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2019-04-16 16:00:15 +00:00
|
|
|
Meta: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
Port: 5000,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
require.NoError(t, a.State.AddServiceWithChecks(srv1, nil, "", false))
|
2019-04-16 16:00:15 +00:00
|
|
|
|
|
|
|
// Add another service
|
|
|
|
srv2 := &structs.NodeService{
|
|
|
|
ID: "redis",
|
|
|
|
Service: "redis",
|
|
|
|
Tags: []string{"kv"},
|
|
|
|
Meta: map[string]string{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
Port: 1234,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
require.NoError(t, a.State.AddServiceWithChecks(srv2, nil, "", false))
|
2019-04-16 16:00:15 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services?filter="+url.QueryEscape("foo in Meta"), nil)
|
2021-11-03 15:12:36 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := decoder.Decode(&val)
|
2019-04-16 16:00:15 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, val, 2)
|
|
|
|
|
|
|
|
req, _ = http.NewRequest("GET", "/v1/agent/services?filter="+url.QueryEscape("kv in Tags"), nil)
|
2021-11-03 15:12:36 +00:00
|
|
|
resp = httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
decoder = json.NewDecoder(resp.Body)
|
|
|
|
val = make(map[string]*api.AgentService)
|
|
|
|
err = decoder.Decode(&val)
|
2019-04-16 16:00:15 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, val, 1)
|
|
|
|
}
|
|
|
|
|
2018-03-12 20:05:06 +00:00
|
|
|
// This tests that the agent services endpoint (/v1/agent/services) returns
|
|
|
|
// Connect proxies.
|
2018-04-20 13:24:24 +00:00
|
|
|
func TestAgent_Services_ExternalConnectProxy(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-08 18:54:05 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-08 18:54:05 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-08 18:54:05 +00:00
|
|
|
srv1 := &structs.NodeService{
|
2018-09-12 16:07:47 +00:00
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
ID: "db-proxy",
|
|
|
|
Service: "db-proxy",
|
|
|
|
Port: 5000,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "db",
|
2023-03-22 18:56:18 +00:00
|
|
|
Upstreams: structs.TestUpstreams(t, false),
|
2018-09-12 16:07:47 +00:00
|
|
|
},
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddServiceWithChecks(srv1, nil, "", false)
|
2018-03-08 18:54:05 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
2021-11-03 15:12:36 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := decoder.Decode(&val)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Len(t, val, 1)
|
2018-03-11 16:31:31 +00:00
|
|
|
actual := val["db-proxy"]
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, api.ServiceKindConnectProxy, actual.Kind)
|
|
|
|
assert.Equal(t, srv1.Proxy.ToAPI(), actual.Proxy)
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
|
|
|
|
2018-09-27 13:33:12 +00:00
|
|
|
// Thie tests that a sidecar-registered service is returned as expected.
|
|
|
|
func TestAgent_Services_Sidecar(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-09-27 13:33:12 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-09-27 13:33:12 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
srv1 := &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
ID: "db-sidecar-proxy",
|
|
|
|
Service: "db-sidecar-proxy",
|
|
|
|
Port: 5000,
|
|
|
|
// Set this internal state that we expect sidecar registrations to have.
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "db",
|
2023-03-22 18:56:18 +00:00
|
|
|
Upstreams: structs.TestUpstreams(t, false),
|
2021-04-12 15:35:14 +00:00
|
|
|
Mode: structs.ProxyModeTransparent,
|
|
|
|
TransparentProxy: structs.TransparentProxyConfig{
|
|
|
|
OutboundListenerPort: 10101,
|
|
|
|
},
|
2018-09-27 13:33:12 +00:00
|
|
|
},
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddServiceWithChecks(srv1, nil, "", false)
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
2021-11-03 15:12:36 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := decoder.Decode(&val)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
2021-11-03 15:12:36 +00:00
|
|
|
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Len(t, val, 1)
|
2018-09-27 13:33:12 +00:00
|
|
|
actual := val["db-sidecar-proxy"]
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NotNil(t, actual)
|
|
|
|
assert.Equal(t, api.ServiceKindConnectProxy, actual.Kind)
|
|
|
|
assert.Equal(t, srv1.Proxy.ToAPI(), actual.Proxy)
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
// Sanity check that LocalRegisteredAsSidecar is not in the output (assuming
|
2018-11-02 17:00:39 +00:00
|
|
|
// JSON encoding). Right now this is not the case because the services
|
2018-09-27 13:33:12 +00:00
|
|
|
// endpoint happens to use the api struct which doesn't include that field,
|
|
|
|
// but this test serves as a regression test incase we change the endpoint to
|
|
|
|
// return the internal struct later and accidentally expose some "internal"
|
|
|
|
// state.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.NotContains(t, resp.Body.String(), "LocallyRegisteredAsSidecar")
|
|
|
|
assert.NotContains(t, resp.Body.String(), "locally_registered_as_sidecar")
|
2018-09-27 13:33:12 +00:00
|
|
|
}
|
|
|
|
|
2020-03-26 16:20:56 +00:00
|
|
|
// This tests that a mesh gateway service is returned as expected.
|
2019-06-18 00:52:01 +00:00
|
|
|
func TestAgent_Services_MeshGateway(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-06-18 00:52:01 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2019-06-18 00:52:01 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
srv1 := &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindMeshGateway,
|
|
|
|
ID: "mg-dc1-01",
|
|
|
|
Service: "mg-dc1",
|
|
|
|
Port: 8443,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddServiceWithChecks(srv1, nil, "", false)
|
2019-06-18 00:52:01 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := dec.Decode(&val)
|
2019-06-18 00:52:01 +00:00
|
|
|
require.NoError(t, err)
|
2021-12-07 14:44:03 +00:00
|
|
|
|
2019-06-18 00:52:01 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
actual := val["mg-dc1-01"]
|
|
|
|
require.NotNil(t, actual)
|
|
|
|
require.Equal(t, api.ServiceKindMeshGateway, actual.Kind)
|
2021-12-07 14:44:03 +00:00
|
|
|
// Proxy.ToAPI() creates an empty Upstream list instead of keeping nil so do the same with actual.
|
|
|
|
if actual.Proxy.Upstreams == nil {
|
|
|
|
actual.Proxy.Upstreams = make([]api.Upstream, 0)
|
|
|
|
}
|
2019-06-18 00:52:01 +00:00
|
|
|
require.Equal(t, srv1.Proxy.ToAPI(), actual.Proxy)
|
|
|
|
}
|
|
|
|
|
2020-03-26 16:20:56 +00:00
|
|
|
// This tests that a terminating gateway service is returned as expected.
|
|
|
|
func TestAgent_Services_TerminatingGateway(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-03-26 16:20:56 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2020-03-26 16:20:56 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
srv1 := &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindTerminatingGateway,
|
|
|
|
ID: "tg-dc1-01",
|
|
|
|
Service: "tg-dc1",
|
|
|
|
Port: 8443,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
require.NoError(t, a.State.AddServiceWithChecks(srv1, nil, "", false))
|
2020-03-26 16:20:56 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := dec.Decode(&val)
|
2020-03-26 16:20:56 +00:00
|
|
|
require.NoError(t, err)
|
2021-12-07 14:44:03 +00:00
|
|
|
|
2020-03-26 16:20:56 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
actual := val["tg-dc1-01"]
|
|
|
|
require.NotNil(t, actual)
|
|
|
|
require.Equal(t, api.ServiceKindTerminatingGateway, actual.Kind)
|
2021-12-07 14:44:03 +00:00
|
|
|
// Proxy.ToAPI() creates an empty Upstream list instead of keeping nil so do the same with actual.
|
|
|
|
if actual.Proxy.Upstreams == nil {
|
|
|
|
actual.Proxy.Upstreams = make([]api.Upstream, 0)
|
|
|
|
}
|
2020-03-26 16:20:56 +00:00
|
|
|
require.Equal(t, srv1.Proxy.ToAPI(), actual.Proxy)
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_Services_ACLFilter(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2021-12-03 20:36:28 +00:00
|
|
|
|
|
|
|
services := []*structs.NodeService{
|
|
|
|
{
|
|
|
|
ID: "web",
|
|
|
|
Service: "web",
|
|
|
|
Port: 5000,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: "api",
|
|
|
|
Service: "api",
|
|
|
|
Port: 6000,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, s := range services {
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddServiceWithChecks(s, nil, "", false)
|
2017-07-14 05:33:47 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2021-12-07 14:44:03 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := dec.Decode(&val)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
if len(val) != 0 {
|
|
|
|
t.Fatalf("bad: %v", val)
|
|
|
|
}
|
|
|
|
require.Len(t, val, 0)
|
|
|
|
require.Empty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2021-12-03 20:36:28 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("limited token", func(t *testing.T) {
|
|
|
|
|
|
|
|
token := testCreateToken(t, a, `
|
|
|
|
service "web" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req := httptest.NewRequest("GET", "/v1/agent/services", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
require.NotEmpty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[string]*api.AgentService
|
|
|
|
err := dec.Decode(&val)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
require.Len(t, val, 2)
|
|
|
|
require.Empty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2018-09-27 14:00:51 +00:00
|
|
|
func TestAgent_Service(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-09-27 14:00:51 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig()+`
|
2018-09-27 14:00:51 +00:00
|
|
|
services {
|
|
|
|
name = "web"
|
|
|
|
port = 8181
|
2019-08-10 13:15:19 +00:00
|
|
|
tagged_addresses {
|
|
|
|
wan {
|
|
|
|
address = "198.18.0.1"
|
|
|
|
port = 1818
|
|
|
|
}
|
|
|
|
}
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
proxy := structs.TestConnectProxyConfig(t)
|
|
|
|
proxy.DestinationServiceID = "web1"
|
|
|
|
|
|
|
|
// Define a valid local sidecar proxy service
|
|
|
|
sidecarProxy := &structs.ServiceDefinition{
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
Name: "web-sidecar-proxy",
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TCP: "127.0.0.1:8000",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
},
|
|
|
|
Port: 8000,
|
|
|
|
Proxy: &proxy,
|
2018-10-04 13:08:12 +00:00
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
2021-07-22 18:20:45 +00:00
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Define an updated version. Be careful to copy it.
|
|
|
|
updatedProxy := *sidecarProxy
|
|
|
|
updatedProxy.Port = 9999
|
|
|
|
|
|
|
|
// Mangle the proxy config/upstreams into the expected for with defaults and
|
|
|
|
// API struct types.
|
|
|
|
expectProxy := proxy
|
|
|
|
expectProxy.Upstreams =
|
2021-07-26 21:12:29 +00:00
|
|
|
structs.TestAddDefaultsToUpstreams(t, sidecarProxy.Proxy.Upstreams, *structs.DefaultEnterpriseMetaInDefaultPartition())
|
2018-09-27 14:00:51 +00:00
|
|
|
|
|
|
|
expectedResponse := &api.AgentService{
|
2021-07-26 21:12:29 +00:00
|
|
|
Kind: api.ServiceKindConnectProxy,
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "web-sidecar-proxy",
|
|
|
|
Port: 8000,
|
|
|
|
Proxy: expectProxy.ToAPI(),
|
2018-10-04 13:08:12 +00:00
|
|
|
Weights: api.AgentWeights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
2020-11-19 21:27:31 +00:00
|
|
|
Meta: map[string]string{},
|
|
|
|
Tags: []string{},
|
|
|
|
Datacenter: "dc1",
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
2021-07-22 18:20:45 +00:00
|
|
|
fillAgentServiceEnterpriseMeta(expectedResponse, structs.DefaultEnterpriseMetaInDefaultPartition())
|
2021-07-26 21:12:29 +00:00
|
|
|
hash1, err := hashstructure.Hash(expectedResponse, nil)
|
2021-07-27 21:09:59 +00:00
|
|
|
require.NoError(t, err, "failed to generate hash")
|
2021-07-26 21:12:29 +00:00
|
|
|
expectedResponse.ContentHash = fmt.Sprintf("%x", hash1)
|
2018-09-27 14:00:51 +00:00
|
|
|
|
|
|
|
// Copy and modify
|
|
|
|
updatedResponse := *expectedResponse
|
|
|
|
updatedResponse.Port = 9999
|
2021-07-27 21:09:59 +00:00
|
|
|
updatedResponse.ContentHash = "" // clear field before hashing
|
2021-07-26 21:12:29 +00:00
|
|
|
hash2, err := hashstructure.Hash(updatedResponse, nil)
|
2021-07-27 21:09:59 +00:00
|
|
|
require.NoError(t, err, "failed to generate hash")
|
2021-07-26 21:12:29 +00:00
|
|
|
updatedResponse.ContentHash = fmt.Sprintf("%x", hash2)
|
2018-09-27 14:00:51 +00:00
|
|
|
|
2018-10-04 13:08:12 +00:00
|
|
|
// Simple response for non-proxy service registered in TestAgent config
|
2018-09-27 14:00:51 +00:00
|
|
|
expectWebResponse := &api.AgentService{
|
2021-07-27 21:09:59 +00:00
|
|
|
ID: "web",
|
|
|
|
Service: "web",
|
|
|
|
Port: 8181,
|
2018-10-04 13:08:12 +00:00
|
|
|
Weights: api.AgentWeights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
2019-08-10 13:15:19 +00:00
|
|
|
TaggedAddresses: map[string]api.ServiceAddress{
|
2020-06-16 17:19:31 +00:00
|
|
|
"wan": {
|
2019-08-10 13:15:19 +00:00
|
|
|
Address: "198.18.0.1",
|
|
|
|
Port: 1818,
|
|
|
|
},
|
|
|
|
},
|
2020-11-19 21:27:31 +00:00
|
|
|
Meta: map[string]string{},
|
|
|
|
Tags: []string{},
|
|
|
|
Datacenter: "dc1",
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
2021-07-22 18:20:45 +00:00
|
|
|
fillAgentServiceEnterpriseMeta(expectWebResponse, structs.DefaultEnterpriseMetaInDefaultPartition())
|
2021-07-27 21:09:59 +00:00
|
|
|
hash3, err := hashstructure.Hash(expectWebResponse, nil)
|
|
|
|
require.NoError(t, err, "failed to generate hash")
|
|
|
|
expectWebResponse.ContentHash = fmt.Sprintf("%x", hash3)
|
2018-09-27 14:00:51 +00:00
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
2023-02-06 15:35:52 +00:00
|
|
|
policies string
|
2018-09-27 14:00:51 +00:00
|
|
|
url string
|
|
|
|
updateFunc func()
|
|
|
|
wantWait time.Duration
|
|
|
|
wantCode int
|
|
|
|
wantErr string
|
|
|
|
wantResp *api.AgentService
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "simple fetch - proxy",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy",
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectedResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "simple fetch - non-proxy",
|
|
|
|
url: "/v1/agent/service/web",
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectWebResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "blocking fetch timeout, no change",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy?hash=" + expectedResponse.ContentHash + "&wait=100ms",
|
|
|
|
wantWait: 100 * time.Millisecond,
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectedResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "blocking fetch old hash should return immediately",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy?hash=123456789abcd&wait=10m",
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectedResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "blocking fetch returns change",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy?hash=" + expectedResponse.ContentHash,
|
|
|
|
updateFunc: func() {
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Re-register with new proxy config, make sure we copy the struct so we
|
|
|
|
// don't alter it and affect later test cases.
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(updatedProxy))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-09-27 14:00:51 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2018-09-27 14:00:51 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "body: %s", resp.Body.String())
|
|
|
|
},
|
|
|
|
wantWait: 100 * time.Millisecond,
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: &updatedResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// This test exercises a case that caused a busy loop to eat CPU for the
|
|
|
|
// entire duration of the blocking query. If a service gets re-registered
|
|
|
|
// wth same proxy config then the old proxy config chan is closed causing
|
|
|
|
// blocked watchset.Watch to return false indicating a change. But since
|
|
|
|
// the hash is the same when the blocking fn is re-called we should just
|
|
|
|
// keep blocking on the next iteration. The bug hit was that the WatchSet
|
|
|
|
// ws was not being reset in the loop and so when you try to `Watch` it
|
|
|
|
// the second time it just returns immediately making the blocking loop
|
|
|
|
// into a busy-poll!
|
|
|
|
//
|
|
|
|
// This test though doesn't catch that because busy poll still has the
|
2019-03-06 17:13:28 +00:00
|
|
|
// correct external behavior. I don't want to instrument the loop to
|
2018-09-27 14:00:51 +00:00
|
|
|
// assert it's not executing too fast here as I can't think of a clean way
|
|
|
|
// and the issue is fixed now so this test doesn't actually catch the
|
2019-03-06 17:13:28 +00:00
|
|
|
// error, but does provide an easy way to verify the behavior by hand:
|
2018-09-27 14:00:51 +00:00
|
|
|
// 1. Make this test fail e.g. change wantErr to true
|
|
|
|
// 2. Add a log.Println or similar into the blocking loop/function
|
|
|
|
// 3. See whether it's called just once or many times in a tight loop.
|
|
|
|
name: "blocking fetch interrupted with no change (same hash)",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy?wait=200ms&hash=" + expectedResponse.ContentHash,
|
|
|
|
updateFunc: func() {
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Re-register with _same_ proxy config
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(sidecarProxy))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-09-27 14:00:51 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2018-09-27 14:00:51 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "body: %s", resp.Body.String())
|
|
|
|
},
|
|
|
|
wantWait: 200 * time.Millisecond,
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectedResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// When we reload config, the agent pauses Anti-entropy, then clears all
|
|
|
|
// services (which causes their watch chans to be closed) before loading
|
|
|
|
// state from config/snapshot again). If we do that naively then we don't
|
|
|
|
// just get a spurios wakeup on the watch if the service didn't change,
|
|
|
|
// but we get it wakeup and then race with the reload and probably see no
|
2020-01-27 13:00:33 +00:00
|
|
|
// services and return a 404 error which is gross. This test exercises
|
2018-09-27 14:00:51 +00:00
|
|
|
// that - even though the registrations were from API not config, they are
|
|
|
|
// persisted and cleared/reloaded from snapshot which has same effect.
|
|
|
|
//
|
|
|
|
// The fix for this test is to allow the same mechanism that pauses
|
|
|
|
// Anti-entropy during reload to also pause the hash blocking loop so we
|
|
|
|
// don't resume until the state is reloaded and we get a chance to see if
|
|
|
|
// it actually changed or not.
|
|
|
|
name: "blocking fetch interrupted by reload shouldn't 404 - no change",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy?wait=200ms&hash=" + expectedResponse.ContentHash,
|
|
|
|
updateFunc: func() {
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Reload
|
2020-06-10 20:47:35 +00:00
|
|
|
require.NoError(t, a.reloadConfigInternal(a.Config))
|
2018-09-27 14:00:51 +00:00
|
|
|
},
|
|
|
|
// Should eventually timeout since there is no actual change
|
|
|
|
wantWait: 200 * time.Millisecond,
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectedResponse,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
// As above but test actually altering the service with the config reload.
|
|
|
|
// This simulates the API registration being overridden by a different one
|
|
|
|
// on disk during reload.
|
|
|
|
name: "blocking fetch interrupted by reload shouldn't 404 - changes",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy?wait=10m&hash=" + expectedResponse.ContentHash,
|
|
|
|
updateFunc: func() {
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Reload
|
|
|
|
newConfig := *a.Config
|
|
|
|
newConfig.Services = append(newConfig.Services, &updatedProxy)
|
2020-06-10 20:47:35 +00:00
|
|
|
require.NoError(t, a.reloadConfigInternal(&newConfig))
|
2018-09-27 14:00:51 +00:00
|
|
|
},
|
|
|
|
wantWait: 100 * time.Millisecond,
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: &updatedResponse,
|
|
|
|
},
|
|
|
|
{
|
2022-01-05 17:11:03 +00:00
|
|
|
name: "err: non-existent proxy",
|
|
|
|
url: "/v1/agent/service/nope",
|
2022-01-05 20:18:08 +00:00
|
|
|
wantErr: fmt.Sprintf("unknown service ID: %s", structs.NewServiceID("nope", nil)),
|
2018-09-27 14:00:51 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "err: bad ACL for service",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy",
|
|
|
|
// Limited token doesn't grant read to the service
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2018-09-27 14:00:51 +00:00
|
|
|
key "" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Note that because we return ErrPermissionDenied and handle writing
|
|
|
|
// status at a higher level helper this actually gets a 200 in this test
|
|
|
|
// case so just assert that it was an error.
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "good ACL for service",
|
|
|
|
url: "/v1/agent/service/web-sidecar-proxy",
|
|
|
|
// Limited token doesn't grant read to the service
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2018-09-27 14:00:51 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantCode: 200,
|
|
|
|
wantResp: expectedResponse,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
// Register the basic service to ensure it's in a known state to start.
|
|
|
|
{
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(sidecarProxy))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-09-27 14:00:51 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "body: %s", resp.Body.String())
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", tt.url, nil)
|
|
|
|
|
|
|
|
// Inject the root token for tests that don't care about ACL
|
2021-08-20 16:57:45 +00:00
|
|
|
token := "root"
|
2023-02-06 15:35:52 +00:00
|
|
|
if tt.policies != "" {
|
2018-09-27 14:00:51 +00:00
|
|
|
// Create new token and use that.
|
2023-02-06 15:35:52 +00:00
|
|
|
token = testCreateToken(t, a, tt.policies)
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
req.Header.Set("X-Consul-Token", token)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
if tt.updateFunc != nil {
|
|
|
|
go tt.updateFunc()
|
|
|
|
}
|
|
|
|
start := time.Now()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2019-07-20 13:37:19 +00:00
|
|
|
elapsed := time.Since(start)
|
2018-09-27 14:00:51 +00:00
|
|
|
|
|
|
|
if tt.wantErr != "" {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Contains(t, strings.ToLower(resp.Body.String()), strings.ToLower(tt.wantErr))
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
if tt.wantCode != 0 {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, tt.wantCode, resp.Code, "body: %s", resp.Body.String())
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
if tt.wantWait != 0 {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, elapsed >= tt.wantWait, "should have waited at least %s, "+
|
2018-09-27 14:00:51 +00:00
|
|
|
"took %s", tt.wantWait, elapsed)
|
|
|
|
}
|
|
|
|
|
|
|
|
if tt.wantResp != nil {
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := &api.AgentService{}
|
|
|
|
err := dec.Decode(&val)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
2021-12-07 14:44:03 +00:00
|
|
|
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, tt.wantResp, val)
|
|
|
|
assert.Equal(t, tt.wantResp.ContentHash, resp.Header().Get("X-Consul-ContentHash"))
|
2018-09-27 14:00:51 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Checks(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2014-01-21 01:06:44 +00:00
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-21 01:06:44 +00:00
|
|
|
chk1 := &structs.HealthCheck{
|
2021-08-03 22:26:49 +00:00
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql",
|
|
|
|
Name: "mysql",
|
|
|
|
Interval: "30s",
|
|
|
|
Timeout: "5s",
|
|
|
|
Status: api.HealthPassing,
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddCheck(chk1, "", false)
|
2014-01-21 01:06:44 +00:00
|
|
|
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/checks", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[types.CheckID]*structs.HealthCheck
|
|
|
|
err := dec.Decode(&val)
|
2014-01-21 01:06:44 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
|
2014-01-21 01:06:44 +00:00
|
|
|
if len(val) != 1 {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad checks: %v", val)
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
2017-04-19 23:00:11 +00:00
|
|
|
if val["mysql"].Status != api.HealthPassing {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad check: %v", val)
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
2021-08-03 22:26:49 +00:00
|
|
|
if val["mysql"].Node != chk1.Node {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad check: %v", val)
|
2021-08-03 22:26:49 +00:00
|
|
|
}
|
|
|
|
if val["mysql"].Interval != chk1.Interval {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad check: %v", val)
|
2021-08-03 22:26:49 +00:00
|
|
|
}
|
|
|
|
if val["mysql"].Timeout != chk1.Timeout {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad check: %v", val)
|
2021-08-03 22:26:49 +00:00
|
|
|
}
|
2014-01-21 01:06:44 +00:00
|
|
|
}
|
|
|
|
|
2019-04-16 16:00:15 +00:00
|
|
|
func TestAgent_ChecksWithFilter(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-04-16 16:00:15 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2019-04-16 16:00:15 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
chk1 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql",
|
|
|
|
Name: "mysql",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddCheck(chk1, "", false)
|
2019-04-16 16:00:15 +00:00
|
|
|
|
|
|
|
chk2 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "redis",
|
|
|
|
Name: "redis",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddCheck(chk2, "", false)
|
2019-04-16 16:00:15 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/checks?filter="+url.QueryEscape("Name == `redis`"), nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[types.CheckID]*structs.HealthCheck
|
|
|
|
err := dec.Decode(&val)
|
2019-04-16 16:00:15 +00:00
|
|
|
require.NoError(t, err)
|
2021-12-07 14:44:03 +00:00
|
|
|
|
2019-04-16 16:00:15 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
_, ok := val["redis"]
|
|
|
|
require.True(t, ok)
|
|
|
|
}
|
|
|
|
|
2019-01-07 14:39:23 +00:00
|
|
|
func TestAgent_HealthServiceByID(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2019-01-07 14:39:23 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
service := &structs.NodeService{
|
|
|
|
ID: "mysql",
|
|
|
|
Service: "mysql",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
|
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: service,
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
|
|
|
}
|
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "mysql2",
|
|
|
|
Service: "mysql2",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "mysql3",
|
|
|
|
Service: "mysql3",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk1 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql",
|
|
|
|
Name: "mysql",
|
|
|
|
ServiceID: "mysql",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err := a.State.AddCheck(chk1, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk2 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql",
|
|
|
|
Name: "mysql",
|
|
|
|
ServiceID: "mysql",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk2, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk3 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql2",
|
|
|
|
Name: "mysql2",
|
|
|
|
ServiceID: "mysql2",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk3, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk4 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql2",
|
|
|
|
Name: "mysql2",
|
|
|
|
ServiceID: "mysql2",
|
|
|
|
Status: api.HealthWarning,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk4, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk5 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql3",
|
|
|
|
Name: "mysql3",
|
|
|
|
ServiceID: "mysql3",
|
|
|
|
Status: api.HealthMaint,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk5, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk6 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql3",
|
|
|
|
Name: "mysql3",
|
|
|
|
ServiceID: "mysql3",
|
|
|
|
Status: api.HealthCritical,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk6, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
eval := func(t *testing.T, url string, expectedCode int, expected string) {
|
|
|
|
t.Helper()
|
|
|
|
t.Run("format=text", func(t *testing.T) {
|
|
|
|
t.Helper()
|
|
|
|
req, _ := http.NewRequest("GET", url+"?format=text", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
body := resp.Body.String()
|
|
|
|
if got, want := resp.Code, expectedCode; got != want {
|
|
|
|
t.Fatalf("returned bad status: expected %d, but had: %d", expectedCode, resp.Code)
|
2019-01-07 14:39:23 +00:00
|
|
|
}
|
|
|
|
if got, want := body, expected; got != want {
|
|
|
|
t.Fatalf("got body %q want %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("format=json", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if got, want := resp.Code, expectedCode; got != want {
|
|
|
|
t.Fatalf("returned bad status: expected %d, but had: %d", expectedCode, resp.Code)
|
2019-01-07 14:39:23 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
data := &api.AgentServiceChecksInfo{}
|
|
|
|
if err := dec.Decode(data); err != nil {
|
|
|
|
t.Fatalf("Cannot convert result from JSON: %v", err)
|
2019-01-07 14:39:23 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if resp.Code != http.StatusNotFound {
|
2019-01-07 14:39:23 +00:00
|
|
|
if data != nil && data.AggregatedStatus != expected {
|
|
|
|
t.Fatalf("got body %v want %v", data, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("passing checks", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/id/mysql", http.StatusOK, "passing")
|
|
|
|
})
|
|
|
|
t.Run("warning checks", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/id/mysql2", http.StatusTooManyRequests, "warning")
|
|
|
|
})
|
|
|
|
t.Run("critical checks", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/id/mysql3", http.StatusServiceUnavailable, "critical")
|
|
|
|
})
|
|
|
|
t.Run("unknown serviceid", func(t *testing.T) {
|
2019-12-10 02:26:41 +00:00
|
|
|
eval(t, "/v1/agent/health/service/id/mysql1", http.StatusNotFound, fmt.Sprintf("ServiceId %s not found", structs.ServiceIDString("mysql1", nil)))
|
2019-01-07 14:39:23 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
nodeCheck := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "diskCheck",
|
|
|
|
Name: "diskCheck",
|
|
|
|
Status: api.HealthCritical,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(nodeCheck, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
t.Run("critical check on node", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/id/mysql", http.StatusServiceUnavailable, "critical")
|
|
|
|
})
|
|
|
|
|
2019-12-10 02:26:41 +00:00
|
|
|
err = a.State.RemoveCheck(nodeCheck.CompoundCheckID())
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
nodeCheck = &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "_node_maintenance",
|
|
|
|
Name: "_node_maintenance",
|
|
|
|
Status: api.HealthMaint,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(nodeCheck, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
t.Run("maintenance check on node", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/id/mysql", http.StatusServiceUnavailable, "maintenance")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_HealthServiceByName(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2019-01-07 14:39:23 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
service := &structs.NodeService{
|
|
|
|
ID: "mysql1",
|
|
|
|
Service: "mysql-pool-r",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: service,
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
|
|
|
}
|
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "mysql2",
|
|
|
|
Service: "mysql-pool-r",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "mysql3",
|
|
|
|
Service: "mysql-pool-rw",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "mysql4",
|
|
|
|
Service: "mysql-pool-rw",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "httpd1",
|
|
|
|
Service: "httpd",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2019-01-07 14:39:23 +00:00
|
|
|
ID: "httpd2",
|
|
|
|
Service: "httpd",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if err := a.AddService(serviceReq); err != nil {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk1 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql1",
|
|
|
|
Name: "mysql1",
|
|
|
|
ServiceID: "mysql1",
|
|
|
|
ServiceName: "mysql-pool-r",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err := a.State.AddCheck(chk1, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk2 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql1",
|
|
|
|
Name: "mysql1",
|
|
|
|
ServiceID: "mysql1",
|
|
|
|
ServiceName: "mysql-pool-r",
|
|
|
|
Status: api.HealthWarning,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk2, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk3 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql2",
|
|
|
|
Name: "mysql2",
|
|
|
|
ServiceID: "mysql2",
|
|
|
|
ServiceName: "mysql-pool-r",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk3, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk4 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql2",
|
|
|
|
Name: "mysql2",
|
|
|
|
ServiceID: "mysql2",
|
|
|
|
ServiceName: "mysql-pool-r",
|
|
|
|
Status: api.HealthCritical,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk4, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk5 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql3",
|
|
|
|
Name: "mysql3",
|
|
|
|
ServiceID: "mysql3",
|
|
|
|
ServiceName: "mysql-pool-rw",
|
|
|
|
Status: api.HealthWarning,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk5, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk6 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "mysql4",
|
|
|
|
Name: "mysql4",
|
|
|
|
ServiceID: "mysql4",
|
|
|
|
ServiceName: "mysql-pool-rw",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk6, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk7 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "httpd1",
|
|
|
|
Name: "httpd1",
|
|
|
|
ServiceID: "httpd1",
|
|
|
|
ServiceName: "httpd",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk7, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
chk8 := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "httpd2",
|
|
|
|
Name: "httpd2",
|
|
|
|
ServiceID: "httpd2",
|
|
|
|
ServiceName: "httpd",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(chk8, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
eval := func(t *testing.T, url string, expectedCode int, expected string) {
|
|
|
|
t.Helper()
|
|
|
|
t.Run("format=text", func(t *testing.T) {
|
|
|
|
t.Helper()
|
|
|
|
req, _ := http.NewRequest("GET", url+"?format=text", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if got, want := resp.Code, expectedCode; got != want {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("returned bad status: %d. Body: %q", resp.Code, resp.Body.String())
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if got, want := resp.Body.String(), expected; got != want {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("got body %q want %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("format=json", func(t *testing.T) {
|
|
|
|
t.Helper()
|
|
|
|
req, _ := http.NewRequest("GET", url, nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
data := make([]*api.AgentServiceChecksInfo, 0)
|
|
|
|
if err := dec.Decode(&data); err != nil {
|
|
|
|
t.Fatalf("Cannot convert result from JSON: %v", err)
|
2019-01-07 14:39:23 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if got, want := resp.Code, expectedCode; got != want {
|
2019-01-07 14:39:23 +00:00
|
|
|
t.Fatalf("returned bad code: %d. Body: %#v", resp.Code, data)
|
|
|
|
}
|
|
|
|
if resp.Code != http.StatusNotFound {
|
2021-12-07 14:44:03 +00:00
|
|
|
matched := false
|
|
|
|
for _, d := range data {
|
|
|
|
if d.AggregatedStatus == expected {
|
|
|
|
matched = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !matched {
|
|
|
|
t.Fatalf("got wrong status, wanted %#v", expected)
|
2019-01-07 14:39:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("passing checks", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/name/httpd", http.StatusOK, "passing")
|
|
|
|
})
|
|
|
|
t.Run("warning checks", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/name/mysql-pool-rw", http.StatusTooManyRequests, "warning")
|
|
|
|
})
|
|
|
|
t.Run("critical checks", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/name/mysql-pool-r", http.StatusServiceUnavailable, "critical")
|
|
|
|
})
|
|
|
|
t.Run("unknown serviceName", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/name/test", http.StatusNotFound, "ServiceName test Not Found")
|
|
|
|
})
|
|
|
|
nodeCheck := &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "diskCheck",
|
|
|
|
Name: "diskCheck",
|
|
|
|
Status: api.HealthCritical,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(nodeCheck, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
t.Run("critical check on node", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/name/mysql-pool-r", http.StatusServiceUnavailable, "critical")
|
|
|
|
})
|
|
|
|
|
2019-12-10 02:26:41 +00:00
|
|
|
err = a.State.RemoveCheck(nodeCheck.CompoundCheckID())
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
nodeCheck = &structs.HealthCheck{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "_node_maintenance",
|
|
|
|
Name: "_node_maintenance",
|
|
|
|
Status: api.HealthMaint,
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
err = a.State.AddCheck(nodeCheck, "", false)
|
2019-01-07 14:39:23 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
t.Run("maintenance check on node", func(t *testing.T) {
|
|
|
|
eval(t, "/v1/agent/health/service/name/mysql-pool-r", http.StatusServiceUnavailable, "maintenance")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-01-31 14:57:38 +00:00
|
|
|
func TestAgent_HealthServicesACLEnforcement(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-01-31 14:57:38 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfigWithParams(nil))
|
2020-01-31 14:57:38 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
service := &structs.NodeService{
|
|
|
|
ID: "mysql1",
|
|
|
|
Service: "mysql",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: service,
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
|
|
|
}
|
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2020-01-31 14:57:38 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq.Service = &structs.NodeService{
|
2020-01-31 14:57:38 +00:00
|
|
|
ID: "foo1",
|
|
|
|
Service: "foo",
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2020-01-31 14:57:38 +00:00
|
|
|
|
|
|
|
// no token
|
|
|
|
t.Run("no-token-health-by-id", func(t *testing.T) {
|
|
|
|
req, err := http.NewRequest("GET", "/v1/agent/health/service/id/mysql1", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2020-01-31 14:57:38 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no-token-health-by-name", func(t *testing.T) {
|
|
|
|
req, err := http.NewRequest("GET", "/v1/agent/health/service/name/mysql", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2020-01-31 14:57:38 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("root-token-health-by-id", func(t *testing.T) {
|
|
|
|
req, err := http.NewRequest("GET", "/v1/agent/health/service/id/foo1", nil)
|
|
|
|
require.NoError(t, err)
|
2021-12-07 12:48:50 +00:00
|
|
|
req.Header.Add("X-Consul-Token", TestDefaultInitialManagementToken)
|
2020-01-31 14:57:38 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2020-01-31 14:57:38 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("root-token-health-by-name", func(t *testing.T) {
|
|
|
|
req, err := http.NewRequest("GET", "/v1/agent/health/service/name/foo", nil)
|
|
|
|
require.NoError(t, err)
|
2021-12-07 12:48:50 +00:00
|
|
|
req.Header.Add("X-Consul-Token", TestDefaultInitialManagementToken)
|
2020-01-31 14:57:38 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2020-01-31 14:57:38 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_Checks_ACLFilter(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2021-12-03 20:36:28 +00:00
|
|
|
|
|
|
|
checks := structs.HealthChecks{
|
|
|
|
{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "web",
|
|
|
|
ServiceName: "web",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Node: a.Config.NodeName,
|
|
|
|
CheckID: "api",
|
|
|
|
ServiceName: "api",
|
|
|
|
Status: api.HealthPassing,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, c := range checks {
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddCheck(c, "", false)
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2021-12-07 14:44:03 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/checks", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make(map[types.CheckID]*structs.HealthCheck)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
require.Len(t, val, 0)
|
|
|
|
require.Empty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2021-12-03 20:36:28 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("limited token", func(t *testing.T) {
|
|
|
|
|
|
|
|
token := testCreateToken(t, a, fmt.Sprintf(`
|
|
|
|
service "web" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
node "%s" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
`, a.Config.NodeName))
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req := httptest.NewRequest("GET", "/v1/agent/checks", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
var val map[types.CheckID]*structs.HealthCheck
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
require.NotEmpty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/checks", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make(map[types.CheckID]*structs.HealthCheck)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
require.Len(t, val, 2)
|
|
|
|
require.Empty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Self(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2014-05-25 23:59:48 +00:00
|
|
|
|
2020-08-26 15:04:11 +00:00
|
|
|
cases := map[string]struct {
|
|
|
|
hcl string
|
|
|
|
expectXDS bool
|
2022-08-19 17:07:22 +00:00
|
|
|
grpcTLS bool
|
2020-08-26 15:04:11 +00:00
|
|
|
}{
|
2022-08-19 17:07:22 +00:00
|
|
|
"no grpc": {
|
2020-08-26 15:04:11 +00:00
|
|
|
hcl: `
|
|
|
|
node_meta {
|
|
|
|
somekey = "somevalue"
|
|
|
|
}
|
2022-08-19 17:07:22 +00:00
|
|
|
ports = {
|
|
|
|
grpc = -1
|
2022-09-29 03:27:11 +00:00
|
|
|
grpc_tls = -1
|
|
|
|
}`,
|
2022-08-19 17:07:22 +00:00
|
|
|
expectXDS: false,
|
|
|
|
grpcTLS: false,
|
2020-08-26 15:04:11 +00:00
|
|
|
},
|
2022-08-19 17:07:22 +00:00
|
|
|
"plaintext grpc": {
|
2020-08-26 15:04:11 +00:00
|
|
|
hcl: `
|
|
|
|
node_meta {
|
|
|
|
somekey = "somevalue"
|
|
|
|
}
|
2022-09-29 03:27:11 +00:00
|
|
|
ports = {
|
|
|
|
grpc_tls = -1
|
|
|
|
}`,
|
2022-08-19 17:07:22 +00:00
|
|
|
expectXDS: true,
|
|
|
|
grpcTLS: false,
|
|
|
|
},
|
|
|
|
"tls grpc": {
|
|
|
|
hcl: `
|
|
|
|
node_meta {
|
|
|
|
somekey = "somevalue"
|
2022-09-29 03:27:11 +00:00
|
|
|
}`,
|
2022-08-19 17:07:22 +00:00
|
|
|
expectXDS: true,
|
|
|
|
grpcTLS: true,
|
2020-08-26 15:04:11 +00:00
|
|
|
},
|
2014-05-25 23:59:48 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 15:04:11 +00:00
|
|
|
for name, tc := range cases {
|
|
|
|
tc := tc
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2022-08-19 17:07:22 +00:00
|
|
|
a := StartTestAgent(t, TestAgent{
|
|
|
|
HCL: tc.hcl,
|
|
|
|
UseGRPCTLS: tc.grpcTLS,
|
|
|
|
})
|
2020-08-26 15:04:11 +00:00
|
|
|
defer a.Shutdown()
|
2014-05-27 22:09:28 +00:00
|
|
|
|
2020-08-26 15:04:11 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := &Self{}
|
|
|
|
require.NoError(t, dec.Decode(val))
|
2015-07-30 19:02:37 +00:00
|
|
|
|
2020-08-26 15:04:11 +00:00
|
|
|
require.Equal(t, a.Config.SerfPortLAN, int(val.Member.Port))
|
2021-12-07 14:44:03 +00:00
|
|
|
require.Equal(t, a.Config.SerfPortLAN, int(val.DebugConfig["SerfPortLAN"].(float64)))
|
2020-08-26 15:04:11 +00:00
|
|
|
|
|
|
|
cs, err := a.GetLANCoordinate()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, cs[a.config.SegmentName], val.Coord)
|
|
|
|
|
Backport of Displays Consul version of each nodes in UI nodes section into release/1.16.x (#18113)
## Backport
This PR is auto-generated from #17754 to be assessed for backporting due
to the inclusion of the label backport/1.16.
:rotating_light:
>**Warning** automatic cherry-pick of commits failed. If the first
commit failed,
you will see a blank no-op commit below. If at least one commit
succeeded, you
will see the cherry-picked commits up to, _not including_, the commit
where
the merge conflict occurred.
The person who merged in the original PR is:
@WenInCode
This person should manually cherry-pick the original PR into a new
backport PR,
and close this one when the manual backport PR is merged in.
> merge conflict error: unable to process merge commit:
"1c757b8a2c1160ad53421b7b8bd7f74b205c4b89", automatic backport requires
rebase workflow
The below text is copied from the body of the original PR.
---
fixes #17097 Consul version of each nodes in UI nodes section
@jkirschner-hashicorp @huikang @team @Maintainers
Updated consul version in the request to register consul.
Added this as Node MetaData.
Fetching this new metadata in UI
<img width="1512" alt="Screenshot 2023-06-15 at 4 21 33 PM"
src="https://github.com/hashicorp/consul/assets/3139634/94f7cf6b-701f-4230-b9f7-d8c4342d0737">
Also made this backward compatible and tested.
Backward compatible in this context means - If consul binary with above
PR changes is deployed to one of node, and if UI is run from this node,
then the version of not only current (upgraded) node is displayed in UI
, but also of older nodes given that they are consul servers only.
For older (non-server or client) nodes the version is not added in
NodeMeta Data and hence the version will not be displayed for them.
If a old node is consul server, the version will be displayed. As the
endpoint - "v1/internal/ui/nodes?dc=dc1" was already returning version
in service meta. This is made use of in current UI changes.
<img width="1480" alt="Screenshot 2023-06-16 at 6 58 32 PM"
src="https://github.com/hashicorp/consul/assets/3139634/257942f4-fbed-437d-a492-37849d2bec4c">
---
<details>
<summary> Overview of commits </summary>
- 931fdfc7ecdc26bb7cc20b698c5e14c1b65fcc6e -
b3e2ec1ccaca3832a088ffcac54257fa6653c6c1 -
8d0e9a54907039c09330c6cd7b9e761566af6856 -
04e5d88cca37821f6667be381c16aaa5958b5c92 -
28286a2e98f8cd66ef8593c2e2893b4db6080417 -
43e50ad38207952a9c4d04d45d08b6b8f71b31fe -
0cf1b7077cdf255596254d9dc1624a269c42b94d -
27f34ce1c2973591f75b1e38a81ccbe7cee6cee3 -
2ac76d62b8cbae76b1a903021aebb9b865e29d6e -
3d618df9ef1d10dd5056c8b1ed865839c553a0e0 -
1c757b8a2c1160ad53421b7b8bd7f74b205c4b89 -
23ce82b4cee8f74dd634dbe145313e9a56c0077d -
4dc1c9b4c5aafdb8883ef977dfa9b39da138b6cb -
85a12a92528bfa267a039a9bb258170be914abf7 -
25d30a3fa980d130a30d445d26d47ef2356cb553 -
7f1d6192dce3352e92307175848b89f91e728c24 -
5174cbff84b0795d4cb36eb8980d0d5336091ac9
</details>
---------
Co-authored-by: Vijay Srinivas <vijayraghav22@gmail.com>
Co-authored-by: John Murret <john.murret@hashicorp.com>
Co-authored-by: Jared Kirschner <85913323+jkirschner-hashicorp@users.noreply.github.com>
2023-07-17 17:27:50 +00:00
|
|
|
delete(val.Meta, structs.MetaSegmentKey) // Added later, not in config.
|
|
|
|
delete(val.Meta, structs.MetaConsulVersion) // Added later, not in config.
|
2020-08-26 15:04:11 +00:00
|
|
|
require.Equal(t, a.config.NodeMeta, val.Meta)
|
|
|
|
|
|
|
|
if tc.expectXDS {
|
|
|
|
require.NotNil(t, val.XDS, "xds component missing when gRPC is enabled")
|
|
|
|
require.Equal(t,
|
2023-02-06 17:14:35 +00:00
|
|
|
map[string][]string{"envoy": xdscommon.EnvoyVersions},
|
2020-08-26 15:04:11 +00:00
|
|
|
val.XDS.SupportedProxies,
|
|
|
|
)
|
2022-09-01 17:32:11 +00:00
|
|
|
require.Equal(t, a.Config.GRPCTLSPort, val.XDS.Ports.TLS)
|
|
|
|
require.Equal(t, a.Config.GRPCPort, val.XDS.Ports.Plaintext)
|
2022-08-19 17:07:22 +00:00
|
|
|
if tc.grpcTLS {
|
|
|
|
require.Equal(t, a.Config.GRPCTLSPort, val.XDS.Port)
|
|
|
|
} else {
|
|
|
|
require.Equal(t, a.Config.GRPCPort, val.XDS.Port)
|
|
|
|
}
|
2020-08-26 15:04:11 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
require.Nil(t, val.XDS, "xds component should be missing when gRPC is disabled")
|
|
|
|
}
|
|
|
|
})
|
2016-12-13 06:09:35 +00:00
|
|
|
}
|
2014-05-25 23:59:48 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Self_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2022-01-20 12:47:50 +00:00
|
|
|
t.Run("agent recovery token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "towel")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("read-only token", func(t *testing.T) {
|
2021-07-20 21:52:34 +00:00
|
|
|
ro := createACLTokenWithAgentReadPolicy(t, a.srv)
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", ro)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 20:05:38 +00:00
|
|
|
func TestAgent_Metrics_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-08-08 20:05:38 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-08-08 20:05:38 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2017-08-08 20:05:38 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/metrics", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-08-08 20:05:38 +00:00
|
|
|
})
|
|
|
|
|
2022-01-20 12:47:50 +00:00
|
|
|
t.Run("agent recovery token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/metrics", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "towel")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-08-08 20:05:38 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("read-only token", func(t *testing.T) {
|
2021-07-20 21:52:34 +00:00
|
|
|
ro := createACLTokenWithAgentReadPolicy(t, a.srv)
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/metrics", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", ro)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-08-08 20:05:38 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-15 23:04:24 +00:00
|
|
|
func TestHTTPHandlers_AgentMetricsStream_ACLDeny(t *testing.T) {
|
|
|
|
bd := BaseDeps{}
|
|
|
|
bd.Tokens = new(tokenStore.Store)
|
|
|
|
sink := metrics.NewInmemSink(30*time.Millisecond, time.Second)
|
2022-05-19 20:03:46 +00:00
|
|
|
bd.MetricsConfig = &lib.MetricsConfig{
|
|
|
|
Handler: sink,
|
|
|
|
}
|
2021-07-15 23:04:24 +00:00
|
|
|
d := fakeResolveTokenDelegate{authorizer: acl.DenyAll()}
|
|
|
|
agent := &Agent{
|
|
|
|
baseDeps: bd,
|
|
|
|
delegate: d,
|
|
|
|
tokens: bd.Tokens,
|
|
|
|
config: &config.RuntimeConfig{NodeName: "the-node"},
|
|
|
|
logger: hclog.NewInterceptLogger(nil),
|
|
|
|
}
|
|
|
|
h := HTTPHandlers{agent: agent, denylist: NewDenylist(nil)}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil)
|
|
|
|
require.NoError(t, err)
|
2023-06-30 13:10:20 +00:00
|
|
|
handle := h.handler()
|
2021-07-15 23:04:24 +00:00
|
|
|
handle.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
|
|
|
require.Contains(t, resp.Body.String(), "Permission denied")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestHTTPHandlers_AgentMetricsStream(t *testing.T) {
|
|
|
|
bd := BaseDeps{}
|
|
|
|
bd.Tokens = new(tokenStore.Store)
|
|
|
|
sink := metrics.NewInmemSink(20*time.Millisecond, time.Second)
|
2022-05-19 20:03:46 +00:00
|
|
|
bd.MetricsConfig = &lib.MetricsConfig{
|
|
|
|
Handler: sink,
|
|
|
|
}
|
2021-07-30 17:16:38 +00:00
|
|
|
d := fakeResolveTokenDelegate{authorizer: acl.ManageAll()}
|
2021-07-15 23:04:24 +00:00
|
|
|
agent := &Agent{
|
|
|
|
baseDeps: bd,
|
|
|
|
delegate: d,
|
|
|
|
tokens: bd.Tokens,
|
|
|
|
config: &config.RuntimeConfig{NodeName: "the-node"},
|
|
|
|
logger: hclog.NewInterceptLogger(nil),
|
|
|
|
}
|
|
|
|
h := HTTPHandlers{agent: agent, denylist: NewDenylist(nil)}
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Millisecond)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
// produce some metrics
|
|
|
|
go func() {
|
|
|
|
for ctx.Err() == nil {
|
|
|
|
sink.SetGauge([]string{"the-key"}, 12)
|
|
|
|
time.Sleep(5 * time.Millisecond)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "/v1/agent/metrics/stream", nil)
|
|
|
|
require.NoError(t, err)
|
2023-06-30 13:10:20 +00:00
|
|
|
handle := h.handler()
|
2021-07-15 23:04:24 +00:00
|
|
|
handle.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
decoder := json.NewDecoder(resp.Body)
|
|
|
|
var summary metrics.MetricsSummary
|
|
|
|
err = decoder.Decode(&summary)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
expected := []metrics.GaugeValue{
|
|
|
|
{Name: "the-key", Value: 12, DisplayLabels: map[string]string{}},
|
|
|
|
}
|
|
|
|
require.Equal(t, expected, summary.Gauges)
|
|
|
|
|
|
|
|
// There should be at least two intervals worth of metrics
|
|
|
|
err = decoder.Decode(&summary)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expected, summary.Gauges)
|
|
|
|
}
|
|
|
|
|
|
|
|
type fakeResolveTokenDelegate struct {
|
|
|
|
delegate
|
|
|
|
authorizer acl.Authorizer
|
|
|
|
}
|
|
|
|
|
2022-06-17 09:24:43 +00:00
|
|
|
func (f fakeResolveTokenDelegate) ResolveTokenAndDefaultMeta(_ string, _ *acl.EnterpriseMeta, _ *acl.AuthorizerContext) (resolver.Result, error) {
|
|
|
|
return resolver.Result{Authorizer: f.authorizer}, nil
|
2021-07-15 23:04:24 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Reload(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
dc1 := "dc1"
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2017-09-25 18:40:42 +00:00
|
|
|
services = [
|
|
|
|
{
|
|
|
|
name = "redis"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
watches = [
|
|
|
|
{
|
2018-08-06 23:46:09 +00:00
|
|
|
datacenter = "`+dc1+`"
|
2017-09-25 18:40:42 +00:00
|
|
|
type = "key"
|
|
|
|
key = "test"
|
|
|
|
handler = "true"
|
|
|
|
}
|
|
|
|
]
|
2018-04-08 10:57:01 +00:00
|
|
|
limits = {
|
|
|
|
rpc_rate=1
|
|
|
|
rpc_max_burst=100
|
|
|
|
}
|
2017-09-25 18:40:42 +00:00
|
|
|
`)
|
2017-06-03 19:22:47 +00:00
|
|
|
defer a.Shutdown()
|
2016-11-30 18:29:42 +00:00
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, dc1)
|
2019-12-10 02:26:41 +00:00
|
|
|
if a.State.Service(structs.NewServiceID("redis", nil)) == nil {
|
2017-08-28 12:17:13 +00:00
|
|
|
t.Fatal("missing redis service")
|
2016-11-30 18:29:42 +00:00
|
|
|
}
|
|
|
|
|
2020-08-10 16:46:28 +00:00
|
|
|
cfg2 := TestConfig(testutil.Logger(t), config.FileSource{
|
2017-09-25 18:40:42 +00:00
|
|
|
Name: "reload",
|
|
|
|
Format: "hcl",
|
|
|
|
Data: `
|
|
|
|
data_dir = "` + a.Config.DataDir + `"
|
|
|
|
node_id = "` + string(a.Config.NodeID) + `"
|
|
|
|
node_name = "` + a.Config.NodeName + `"
|
|
|
|
|
|
|
|
services = [
|
|
|
|
{
|
|
|
|
name = "redis-reloaded"
|
|
|
|
}
|
|
|
|
]
|
2018-04-08 10:57:01 +00:00
|
|
|
limits = {
|
|
|
|
rpc_rate=2
|
|
|
|
rpc_max_burst=200
|
|
|
|
}
|
2017-09-25 18:40:42 +00:00
|
|
|
`,
|
|
|
|
})
|
2016-11-30 18:29:42 +00:00
|
|
|
|
2020-09-16 17:29:59 +00:00
|
|
|
shim := &delegateConfigReloadShim{delegate: a.delegate}
|
2022-05-25 19:33:00 +00:00
|
|
|
// NOTE: this may require refactoring to remove a potential test race
|
2020-09-16 17:29:59 +00:00
|
|
|
a.delegate = shim
|
2020-06-10 20:47:35 +00:00
|
|
|
if err := a.reloadConfigInternal(cfg2); err != nil {
|
2017-06-03 19:22:47 +00:00
|
|
|
t.Fatalf("got error %v want nil", err)
|
2016-11-30 18:29:42 +00:00
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
if a.State.Service(structs.NewServiceID("redis-reloaded", nil)) == nil {
|
2017-08-28 12:17:13 +00:00
|
|
|
t.Fatal("missing redis-reloaded service")
|
2016-11-30 18:29:42 +00:00
|
|
|
}
|
2017-06-24 19:52:41 +00:00
|
|
|
|
2020-09-16 17:29:59 +00:00
|
|
|
require.Equal(t, rate.Limit(2), shim.newCfg.RPCRateLimit)
|
|
|
|
require.Equal(t, 200, shim.newCfg.RPCMaxBurst)
|
2018-04-08 10:57:01 +00:00
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
for _, wp := range a.watchPlans {
|
2017-06-24 19:52:41 +00:00
|
|
|
if !wp.IsStopped() {
|
|
|
|
t.Fatalf("Reloading configs should stop watch plans of the previous configuration")
|
|
|
|
}
|
|
|
|
}
|
2016-11-30 18:29:42 +00:00
|
|
|
}
|
|
|
|
|
2020-09-16 17:29:59 +00:00
|
|
|
type delegateConfigReloadShim struct {
|
|
|
|
delegate
|
|
|
|
newCfg consul.ReloadableConfig
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *delegateConfigReloadShim) ReloadConfig(cfg consul.ReloadableConfig) error {
|
|
|
|
s.newCfg = cfg
|
|
|
|
return s.delegate.ReloadConfig(cfg)
|
|
|
|
}
|
|
|
|
|
2020-05-20 10:38:29 +00:00
|
|
|
// TestAgent_ReloadDoesNotTriggerWatch Ensure watches not triggered after reload
|
|
|
|
// see https://github.com/hashicorp/consul/issues/7446
|
|
|
|
func TestAgent_ReloadDoesNotTriggerWatch(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-05-20 10:38:29 +00:00
|
|
|
dc1 := "dc1"
|
2022-11-10 16:26:01 +00:00
|
|
|
tmpFileRaw, err := os.CreateTemp("", "rexec")
|
2020-05-20 10:38:29 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
tmpFile := tmpFileRaw.Name()
|
|
|
|
defer os.Remove(tmpFile)
|
|
|
|
handlerShell := fmt.Sprintf("(cat ; echo CONSUL_INDEX $CONSUL_INDEX) | tee '%s.atomic' ; mv '%s.atomic' '%s'", tmpFile, tmpFile, tmpFile)
|
|
|
|
|
|
|
|
a := NewTestAgent(t, `
|
|
|
|
services = [
|
|
|
|
{
|
|
|
|
name = "redis"
|
|
|
|
checks = [
|
|
|
|
{
|
|
|
|
id = "red-is-dead"
|
|
|
|
ttl = "30s"
|
|
|
|
notes = "initial check"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
watches = [
|
|
|
|
{
|
|
|
|
datacenter = "`+dc1+`"
|
|
|
|
type = "service"
|
|
|
|
service = "redis"
|
|
|
|
args = ["bash", "-c", "`+handlerShell+`"]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
`)
|
|
|
|
checkID := structs.NewCheckID("red-is-dead", nil)
|
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, dc1)
|
|
|
|
require.NoError(t, a.updateTTLCheck(checkID, api.HealthPassing, "testing-agent-reload-001"))
|
|
|
|
|
|
|
|
checkStr := func(r *retry.R, evaluator func(string) error) {
|
|
|
|
t.Helper()
|
|
|
|
contentsStr := ""
|
|
|
|
// Wait for watch to be populated
|
|
|
|
for i := 1; i < 7; i++ {
|
2022-11-10 16:26:01 +00:00
|
|
|
contents, err := os.ReadFile(tmpFile)
|
2020-05-20 10:38:29 +00:00
|
|
|
if err != nil {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("should be able to read file, but had: %#v", err)
|
2020-05-20 10:38:29 +00:00
|
|
|
}
|
|
|
|
contentsStr = string(contents)
|
|
|
|
if contentsStr != "" {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
time.Sleep(time.Duration(i) * time.Second)
|
|
|
|
testutil.Logger(t).Info("Watch not yet populated, retrying")
|
|
|
|
}
|
|
|
|
if err := evaluator(contentsStr); err != nil {
|
|
|
|
r.Errorf("ERROR: Test failing: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ensureNothingCritical := func(r *retry.R, mustContain string) {
|
|
|
|
t.Helper()
|
|
|
|
eval := func(contentsStr string) error {
|
|
|
|
if strings.Contains(contentsStr, "critical") {
|
|
|
|
return fmt.Errorf("MUST NOT contain critical:= %s", contentsStr)
|
|
|
|
}
|
|
|
|
if !strings.Contains(contentsStr, mustContain) {
|
|
|
|
return fmt.Errorf("MUST contain '%s' := %s", mustContain, contentsStr)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
checkStr(r, eval)
|
|
|
|
}
|
|
|
|
|
|
|
|
retriesWithDelay := func() *retry.Counter {
|
|
|
|
return &retry.Counter{Count: 10, Wait: 1 * time.Second}
|
|
|
|
}
|
|
|
|
|
|
|
|
retry.RunWith(retriesWithDelay(), t, func(r *retry.R) {
|
|
|
|
testutil.Logger(t).Info("Consul is now ready")
|
|
|
|
// it should contain the output
|
|
|
|
checkStr(r, func(contentStr string) error {
|
|
|
|
if contentStr == "[]" {
|
|
|
|
return fmt.Errorf("Consul is still starting up")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
retry.RunWith(retriesWithDelay(), t, func(r *retry.R) {
|
|
|
|
ensureNothingCritical(r, "testing-agent-reload-001")
|
|
|
|
})
|
|
|
|
|
|
|
|
// Let's take almost the same config
|
2020-08-10 16:46:28 +00:00
|
|
|
cfg2 := TestConfig(testutil.Logger(t), config.FileSource{
|
2020-05-20 10:38:29 +00:00
|
|
|
Name: "reload",
|
|
|
|
Format: "hcl",
|
|
|
|
Data: `
|
|
|
|
data_dir = "` + a.Config.DataDir + `"
|
|
|
|
node_id = "` + string(a.Config.NodeID) + `"
|
|
|
|
node_name = "` + a.Config.NodeName + `"
|
|
|
|
|
|
|
|
services = [
|
|
|
|
{
|
|
|
|
name = "redis"
|
|
|
|
checks = [
|
|
|
|
{
|
|
|
|
id = "red-is-dead"
|
|
|
|
ttl = "30s"
|
|
|
|
notes = "initial check"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
watches = [
|
|
|
|
{
|
|
|
|
datacenter = "` + dc1 + `"
|
|
|
|
type = "service"
|
|
|
|
service = "redis"
|
|
|
|
args = ["bash", "-c", "` + handlerShell + `"]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
justOnce := func() *retry.Counter {
|
|
|
|
return &retry.Counter{Count: 1, Wait: 25 * time.Millisecond}
|
|
|
|
}
|
|
|
|
|
|
|
|
retry.RunWith(justOnce(), t, func(r *retry.R) {
|
|
|
|
// We check that reload does not go to critical
|
|
|
|
ensureNothingCritical(r, "red-is-dead")
|
|
|
|
|
2020-06-10 20:47:35 +00:00
|
|
|
if err := a.reloadConfigInternal(cfg2); err != nil {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("got error %v want nil", err)
|
2020-05-20 10:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We check that reload does not go to critical
|
|
|
|
ensureNothingCritical(r, "red-is-dead")
|
|
|
|
ensureNothingCritical(r, "testing-agent-reload-001")
|
|
|
|
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NoError(r, a.updateTTLCheck(checkID, api.HealthPassing, "testing-agent-reload-002"))
|
2020-05-20 10:38:29 +00:00
|
|
|
|
|
|
|
ensureNothingCritical(r, "red-is-dead")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Reload_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/reload", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("read-only token", func(t *testing.T) {
|
2021-07-20 21:52:34 +00:00
|
|
|
ro := createACLTokenWithAgentReadPolicy(t, a.srv)
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/reload", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", ro)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
|
|
|
// This proves we call the ACL function, and we've got the other reload
|
|
|
|
// test to prove we do the reload, which should be sufficient.
|
|
|
|
// The reload logic is a little complex to set up so isn't worth
|
|
|
|
// repeating again here.
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_Members(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2014-01-06 21:21:48 +00:00
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/members", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make([]serf.Member, 0)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
2014-01-06 21:21:48 +00:00
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
|
2014-01-06 21:21:48 +00:00
|
|
|
if len(val) == 0 {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad members: %v", val)
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
if int(val[0].Port) != a.Config.SerfPortLAN {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("not lan: %v", val)
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Members_WAN(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2014-01-06 21:21:48 +00:00
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/members?wan=true", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make([]serf.Member, 0)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
2014-01-06 21:21:48 +00:00
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
|
2014-01-06 21:21:48 +00:00
|
|
|
if len(val) == 0 {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("bad members: %v", val)
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
if int(val[0].Port) != a.Config.SerfPortWAN {
|
2021-12-07 14:44:03 +00:00
|
|
|
t.Fatalf("not wan: %v", val)
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_Members_ACLFilter(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2021-12-03 20:36:28 +00:00
|
|
|
|
|
|
|
// Start 2 agents and join them together.
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2021-12-03 20:36:28 +00:00
|
|
|
b := NewTestAgent(t, TestACLConfig())
|
|
|
|
defer b.Shutdown()
|
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2021-12-03 20:36:28 +00:00
|
|
|
testrpc.WaitForLeader(t, b.RPC, "dc1")
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
joinPath := fmt.Sprintf("/v1/agent/join/127.0.0.1:%d", b.Config.SerfPortLAN)
|
|
|
|
req := httptest.NewRequest("PUT", joinPath, nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2023-01-24 16:21:41 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-07 14:44:03 +00:00
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2021-12-07 14:44:03 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/members", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make([]serf.Member, 0)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
require.Len(t, val, 0)
|
|
|
|
require.Empty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2021-12-03 20:36:28 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("limited token", func(t *testing.T) {
|
|
|
|
|
|
|
|
token := testCreateToken(t, a, fmt.Sprintf(`
|
|
|
|
node "%s" {
|
|
|
|
policy = "read"
|
|
|
|
}
|
|
|
|
`, b.Config.NodeName))
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req := httptest.NewRequest("GET", "/v1/agent/members", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make([]serf.Member, 0)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
require.NotEmpty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/members", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-03 20:36:28 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make([]serf.Member, 0)
|
|
|
|
if err := dec.Decode(&val); err != nil {
|
|
|
|
t.Fatalf("Err: %v", err)
|
|
|
|
}
|
|
|
|
require.Len(t, val, 2)
|
|
|
|
require.Empty(t, resp.Header().Get("X-Consul-Results-Filtered-By-ACLs"))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Join(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a1 := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a1.Shutdown()
|
2020-03-31 19:59:56 +00:00
|
|
|
a2 := NewTestAgent(t, "")
|
2014-01-06 21:21:48 +00:00
|
|
|
defer a2.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc1")
|
2014-01-06 21:21:48 +00:00
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortLAN)
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/join/%s", addr), nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
2014-01-06 21:21:48 +00:00
|
|
|
|
2021-10-26 20:08:55 +00:00
|
|
|
if len(a1.LANMembersInAgentPartition()) != 2 {
|
2014-01-06 21:21:48 +00:00
|
|
|
t.Fatalf("should have 2 members")
|
|
|
|
}
|
2016-10-25 20:46:54 +00:00
|
|
|
|
2017-05-04 22:52:53 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2021-10-26 20:08:55 +00:00
|
|
|
if got, want := len(a2.LANMembersInAgentPartition()), 2; got != want {
|
2017-04-29 16:34:02 +00:00
|
|
|
r.Fatalf("got %d LAN members want %d", got, want)
|
|
|
|
}
|
|
|
|
})
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Join_WAN(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a1 := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a1.Shutdown()
|
2020-03-31 19:59:56 +00:00
|
|
|
a2 := NewTestAgent(t, "")
|
2014-01-06 21:21:48 +00:00
|
|
|
defer a2.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc1")
|
2014-01-06 21:21:48 +00:00
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortWAN)
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/join/%s?wan=true", addr), nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
2014-01-06 21:21:48 +00:00
|
|
|
|
2017-05-21 07:11:09 +00:00
|
|
|
if len(a1.WANMembers()) != 2 {
|
2016-10-25 20:46:54 +00:00
|
|
|
t.Fatalf("should have 2 members")
|
|
|
|
}
|
|
|
|
|
2017-05-04 22:52:53 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2017-04-29 16:34:02 +00:00
|
|
|
if got, want := len(a2.WANMembers()), 2; got != want {
|
|
|
|
r.Fatalf("got %d WAN members want %d", got, want)
|
|
|
|
}
|
|
|
|
})
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Join_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a1 := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a1.Shutdown()
|
2020-03-31 19:59:56 +00:00
|
|
|
a2 := NewTestAgent(t, "")
|
2016-12-14 17:33:57 +00:00
|
|
|
defer a2.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc1")
|
2017-05-21 07:11:09 +00:00
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortLAN)
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/join/%s", addr), nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2022-01-20 12:47:50 +00:00
|
|
|
t.Run("agent recovery token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/join/%s", addr), nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "towel")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("read-only token", func(t *testing.T) {
|
2021-07-20 21:52:34 +00:00
|
|
|
ro := createACLTokenWithAgentReadPolicy(t, a1.srv)
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/join/%s", addr), nil)
|
|
|
|
req.Header.Add("X-Consul-Token", ro)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2017-06-21 04:43:55 +00:00
|
|
|
type mockNotifier struct{ s string }
|
|
|
|
|
|
|
|
func (n *mockNotifier) Notify(state string) error {
|
|
|
|
n.s = state
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_JoinLANNotify(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-06-21 04:43:55 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a1 := NewTestAgent(t, "")
|
2017-06-21 04:43:55 +00:00
|
|
|
defer a1.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
2017-06-21 04:43:55 +00:00
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a2 := NewTestAgent(t, `
|
2017-09-25 18:40:42 +00:00
|
|
|
server = false
|
|
|
|
bootstrap = false
|
|
|
|
`)
|
2017-06-21 04:43:55 +00:00
|
|
|
defer a2.Shutdown()
|
|
|
|
|
|
|
|
notif := &mockNotifier{}
|
|
|
|
a1.joinLANNotifier = notif
|
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortLAN)
|
2021-10-26 20:08:55 +00:00
|
|
|
_, err := a1.JoinLAN([]string{addr}, nil)
|
2017-06-21 04:43:55 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := notif.s, "READY=1"; got != want {
|
|
|
|
t.Fatalf("got joinLAN notification %q want %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Leave(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a1 := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a1.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
2016-11-30 18:29:42 +00:00
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a2 := NewTestAgent(t, `
|
2017-09-25 18:40:42 +00:00
|
|
|
server = false
|
|
|
|
bootstrap = false
|
|
|
|
`)
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a2.Shutdown()
|
2016-11-30 18:29:42 +00:00
|
|
|
|
|
|
|
// Join first
|
2017-09-25 18:40:42 +00:00
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortLAN)
|
2021-10-26 20:08:55 +00:00
|
|
|
_, err := a1.JoinLAN([]string{addr}, nil)
|
2016-11-30 18:29:42 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Graceful leave now
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/leave", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a2.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
2017-05-04 22:52:53 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2021-10-26 20:08:55 +00:00
|
|
|
m := a1.LANMembersInAgentPartition()
|
2017-04-29 16:34:02 +00:00
|
|
|
if got, want := m[1].Status, serf.StatusLeft; got != want {
|
|
|
|
r.Fatalf("got status %q want %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
2016-11-30 18:29:42 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Leave_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-10 07:08:39 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/leave", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("read-only token", func(t *testing.T) {
|
2021-07-20 21:52:34 +00:00
|
|
|
ro := createACLTokenWithAgentReadPolicy(t, a.srv)
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/leave", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", ro)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2017-05-10 07:08:39 +00:00
|
|
|
|
|
|
|
// this sub-test will change the state so that there is no leader.
|
|
|
|
// it must therefore be the last one in this list.
|
2022-01-20 12:47:50 +00:00
|
|
|
t.Run("agent recovery token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/leave", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "towel")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-10 07:08:39 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_ForceLeave(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a1 := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a1.Shutdown()
|
2020-03-31 19:59:56 +00:00
|
|
|
a2 := NewTestAgent(t, "")
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc1")
|
2014-01-06 21:21:48 +00:00
|
|
|
|
|
|
|
// Join first
|
2017-09-25 18:40:42 +00:00
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortLAN)
|
2021-10-26 20:08:55 +00:00
|
|
|
_, err := a1.JoinLAN([]string{addr}, nil)
|
2014-01-06 21:21:48 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-09-25 18:40:42 +00:00
|
|
|
// this test probably needs work
|
2014-01-06 21:21:48 +00:00
|
|
|
a2.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
// Wait for agent being marked as failed, so we wait for full shutdown of Agent
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
2021-10-26 20:08:55 +00:00
|
|
|
m := a1.LANMembersInAgentPartition()
|
2018-08-06 23:46:09 +00:00
|
|
|
if got, want := m[1].Status, serf.StatusFailed; got != want {
|
|
|
|
r.Fatalf("got status %q want %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
2014-01-06 21:21:48 +00:00
|
|
|
|
|
|
|
// Force leave now
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/force-leave/%s", a2.Config.NodeName), nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
2017-05-04 22:52:53 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2021-10-26 20:08:55 +00:00
|
|
|
m := a1.LANMembersInAgentPartition()
|
2017-04-29 16:34:02 +00:00
|
|
|
if got, want := m[1].Status, serf.StatusLeft; got != want {
|
|
|
|
r.Fatalf("got status %q want %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
2014-01-06 21:21:48 +00:00
|
|
|
}
|
2014-01-30 23:51:15 +00:00
|
|
|
|
2020-03-03 13:18:19 +00:00
|
|
|
func TestOpenMetricsMimeTypeHeaders(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
assert.False(t, acceptsOpenMetricsMimeType(""))
|
|
|
|
assert.False(t, acceptsOpenMetricsMimeType(";;;"))
|
|
|
|
assert.False(t, acceptsOpenMetricsMimeType(",,,"))
|
|
|
|
assert.False(t, acceptsOpenMetricsMimeType("text/plain"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("text/plain;version=0.4.0,"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("text/plain;version=0.4.0;q=1,*/*;q=0.1"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("text/plain ; version=0.4.0"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("*/*, application/openmetrics-text ;"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("*/*, application/openmetrics-text ;q=1"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("application/openmetrics-text, text/plain;version=0.4.0"))
|
|
|
|
assert.True(t, acceptsOpenMetricsMimeType("application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1"))
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_ForceLeave_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2019-12-02 19:06:15 +00:00
|
|
|
uri := fmt.Sprintf("/v1/agent/force-leave/%s", a.Config.NodeName)
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2019-12-02 19:06:15 +00:00
|
|
|
req, _ := http.NewRequest("PUT", uri, nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2022-01-20 12:47:50 +00:00
|
|
|
t.Run("agent recovery token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", uri, nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "towel")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("read-only token", func(t *testing.T) {
|
2021-07-20 21:52:34 +00:00
|
|
|
ro := createACLTokenWithAgentReadPolicy(t, a.srv)
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", uri, nil)
|
|
|
|
req.Header.Add("X-Consul-Token", ro)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2020-01-14 22:40:34 +00:00
|
|
|
|
|
|
|
t.Run("operator write token", func(t *testing.T) {
|
|
|
|
// Create an ACL with operator read permissions.
|
2021-08-20 16:57:45 +00:00
|
|
|
rules := `
|
2020-01-14 22:40:34 +00:00
|
|
|
operator = "write"
|
|
|
|
`
|
|
|
|
opToken := testCreateToken(t, a, rules)
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", uri, nil)
|
|
|
|
req.Header.Add("X-Consul-Token", opToken)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2020-01-14 22:40:34 +00:00
|
|
|
})
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2019-10-04 21:10:02 +00:00
|
|
|
func TestAgent_ForceLeavePrune(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-10-04 21:10:02 +00:00
|
|
|
t.Parallel()
|
2020-03-31 20:24:39 +00:00
|
|
|
a1 := StartTestAgent(t, TestAgent{Name: "Agent1"})
|
2019-10-04 21:10:02 +00:00
|
|
|
defer a1.Shutdown()
|
2020-03-31 20:24:39 +00:00
|
|
|
a2 := StartTestAgent(t, TestAgent{Name: "Agent2"})
|
2019-10-04 21:10:02 +00:00
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc1")
|
|
|
|
|
|
|
|
// Join first
|
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a2.Config.SerfPortLAN)
|
2021-10-26 20:08:55 +00:00
|
|
|
_, err := a1.JoinLAN([]string{addr}, nil)
|
2019-10-04 21:10:02 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// this test probably needs work
|
|
|
|
a2.Shutdown()
|
|
|
|
// Wait for agent being marked as failed, so we wait for full shutdown of Agent
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
2021-10-26 20:08:55 +00:00
|
|
|
m := a1.LANMembersInAgentPartition()
|
2019-10-04 21:10:02 +00:00
|
|
|
for _, member := range m {
|
|
|
|
if member.Name == a2.Config.NodeName {
|
|
|
|
if member.Status != serf.StatusFailed {
|
|
|
|
r.Fatalf("got status %q want %q", member.Status, serf.StatusFailed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Force leave now
|
|
|
|
req, _ := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/force-leave/%s?prune=true", a2.Config.NodeName), nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-10-04 21:10:02 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2021-10-26 20:08:55 +00:00
|
|
|
m := len(a1.LANMembersInAgentPartition())
|
2019-10-04 21:10:02 +00:00
|
|
|
if m != 1 {
|
|
|
|
r.Fatalf("want one member, got %v", m)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-12-02 23:15:10 +00:00
|
|
|
func TestAgent_ForceLeavePrune_WAN(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
a1 := StartTestAgent(t, TestAgent{Name: "dc1", HCL: `
|
|
|
|
datacenter = "dc1"
|
|
|
|
primary_datacenter = "dc1"
|
|
|
|
gossip_wan {
|
|
|
|
probe_interval = "50ms"
|
|
|
|
suspicion_mult = 2
|
|
|
|
}
|
|
|
|
`})
|
|
|
|
defer a1.Shutdown()
|
|
|
|
|
|
|
|
a2 := StartTestAgent(t, TestAgent{Name: "dc2", HCL: `
|
|
|
|
datacenter = "dc2"
|
|
|
|
primary_datacenter = "dc1"
|
|
|
|
`})
|
|
|
|
defer a2.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc2")
|
|
|
|
|
|
|
|
// Wait for the WAN join.
|
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN)
|
|
|
|
_, err := a2.JoinWAN([]string{addr})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc2")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc1")
|
|
|
|
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
require.Len(r, a1.WANMembers(), 2)
|
|
|
|
require.Len(r, a2.WANMembers(), 2)
|
|
|
|
})
|
|
|
|
|
|
|
|
wanNodeName_a2 := a2.Config.NodeName + ".dc2"
|
|
|
|
|
|
|
|
// Shutdown and wait for agent being marked as failed, so we wait for full
|
|
|
|
// shutdown of Agent.
|
|
|
|
require.NoError(t, a2.Shutdown())
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
m := a1.WANMembers()
|
|
|
|
for _, member := range m {
|
|
|
|
if member.Name == wanNodeName_a2 {
|
|
|
|
if member.Status != serf.StatusFailed {
|
|
|
|
r.Fatalf("got status %q want %q", member.Status, serf.StatusFailed)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// Force leave now
|
|
|
|
req, err := http.NewRequest("PUT", fmt.Sprintf("/v1/agent/force-leave/%s?prune=1&wan=1", wanNodeName_a2), nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a1.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code, resp.Body.String())
|
|
|
|
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
require.Len(r, a1.WANMembers(), 1)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_RegisterCheck(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-30 23:51:15 +00:00
|
|
|
|
2017-06-15 16:46:06 +00:00
|
|
|
args := &structs.CheckDefinition{
|
2014-01-30 23:51:15 +00:00
|
|
|
Name: "test",
|
2017-05-15 19:49:13 +00:00
|
|
|
TTL: 15 * time.Second,
|
2014-01-30 23:51:15 +00:00
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2014-01-30 23:51:15 +00:00
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
checkID := structs.NewCheckID("test", nil)
|
|
|
|
if existing := a.State.Check(checkID); existing == nil {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("missing test check")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:11:09 +00:00
|
|
|
if _, ok := a.checkTTLs[checkID]; !ok {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("missing test check ttl")
|
|
|
|
}
|
2015-04-28 20:06:02 +00:00
|
|
|
|
|
|
|
// Ensure the token was configured
|
2017-08-28 12:17:13 +00:00
|
|
|
if token := a.State.CheckToken(checkID); token == "" {
|
2015-04-28 20:06:02 +00:00
|
|
|
t.Fatalf("missing token")
|
|
|
|
}
|
2015-05-11 23:48:10 +00:00
|
|
|
|
2015-04-12 00:53:48 +00:00
|
|
|
// By default, checks start in critical state.
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(checkID)
|
2017-04-19 23:00:11 +00:00
|
|
|
if state.Status != api.HealthCritical {
|
2015-04-12 00:53:48 +00:00
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
func TestAgent_RegisterCheck_UDP(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
a := NewTestAgent(t, "")
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.CheckDefinition{
|
|
|
|
UDP: "1.1.1.1",
|
|
|
|
Name: "test",
|
|
|
|
Interval: 10 * time.Second,
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2022-06-06 19:13:19 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
|
|
|
checkID := structs.NewCheckID("test", nil)
|
|
|
|
if existing := a.State.Check(checkID); existing == nil {
|
|
|
|
t.Fatalf("missing test check")
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := a.checkUDPs[checkID]; !ok {
|
|
|
|
t.Fatalf("missing test check udp")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the token was configured
|
|
|
|
if token := a.State.CheckToken(checkID); token == "" {
|
|
|
|
t.Fatalf("missing token")
|
|
|
|
}
|
|
|
|
|
|
|
|
// By default, checks start in critical state.
|
|
|
|
state := a.State.Check(checkID)
|
|
|
|
if state.Status != api.HealthCritical {
|
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-18 18:28:39 +00:00
|
|
|
// This verifies all the forms of the new args-style check that we need to
|
|
|
|
// support as a result of https://github.com/hashicorp/consul/issues/3587.
|
|
|
|
func TestAgent_RegisterCheck_Scripts(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-10-18 18:28:39 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2017-10-18 18:28:39 +00:00
|
|
|
enable_script_checks = true
|
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2017-10-18 18:28:39 +00:00
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
check map[string]interface{}
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"== Consul 1.0.0",
|
|
|
|
map[string]interface{}{
|
|
|
|
"Name": "test",
|
|
|
|
"Interval": "2s",
|
|
|
|
"ScriptArgs": []string{"true"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"> Consul 1.0.0 (fixup)",
|
|
|
|
map[string]interface{}{
|
|
|
|
"Name": "test",
|
|
|
|
"Interval": "2s",
|
|
|
|
"script_args": []string{"true"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"> Consul 1.0.0",
|
|
|
|
map[string]interface{}{
|
|
|
|
"Name": "test",
|
|
|
|
"Interval": "2s",
|
|
|
|
"Args": []string{"true"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name+" as node check", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(tt.check))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2017-10-18 18:28:39 +00:00
|
|
|
if resp.Code != http.StatusOK {
|
|
|
|
t.Fatalf("bad: %d", resp.Code)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run(tt.name+" as top-level service check", func(t *testing.T) {
|
|
|
|
args := map[string]interface{}{
|
|
|
|
"Name": "a",
|
|
|
|
"Port": 1234,
|
|
|
|
"Check": tt.check,
|
|
|
|
}
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2017-10-18 18:28:39 +00:00
|
|
|
if resp.Code != http.StatusOK {
|
|
|
|
t.Fatalf("bad: %d", resp.Code)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run(tt.name+" as slice-based service check", func(t *testing.T) {
|
|
|
|
args := map[string]interface{}{
|
|
|
|
"Name": "a",
|
|
|
|
"Port": 1234,
|
|
|
|
"Checks": []map[string]interface{}{tt.check},
|
|
|
|
}
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2017-10-18 18:28:39 +00:00
|
|
|
if resp.Code != http.StatusOK {
|
|
|
|
t.Fatalf("bad: %d", resp.Code)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-11 12:22:11 +00:00
|
|
|
func TestAgent_RegisterCheckScriptsExecDisable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-10-11 12:22:11 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-10-11 12:22:11 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.CheckDefinition{
|
|
|
|
Name: "test",
|
|
|
|
ScriptArgs: []string{"true"},
|
|
|
|
Interval: time.Second,
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2018-10-11 12:22:11 +00:00
|
|
|
res := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(res, req)
|
|
|
|
if http.StatusInternalServerError != res.Code {
|
|
|
|
t.Fatalf("expected 500 code error but got %v", res.Code)
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if !strings.Contains(res.Body.String(), "Scripts are disabled on this agent") {
|
|
|
|
t.Fatalf("expected script disabled error, got: %s", res.Body.String())
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
checkID := structs.NewCheckID("test", nil)
|
|
|
|
require.Nil(t, a.State.Check(checkID), "check registered with exec disabled")
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_RegisterCheckScriptsExecRemoteDisable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-10-11 12:22:11 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2018-10-11 12:22:11 +00:00
|
|
|
enable_local_script_checks = true
|
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.CheckDefinition{
|
|
|
|
Name: "test",
|
|
|
|
ScriptArgs: []string{"true"},
|
|
|
|
Interval: time.Second,
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2018-10-11 12:22:11 +00:00
|
|
|
res := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(res, req)
|
|
|
|
if http.StatusInternalServerError != res.Code {
|
|
|
|
t.Fatalf("expected 500 code error but got %v", res.Code)
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if !strings.Contains(res.Body.String(), "Scripts are disabled on this agent") {
|
|
|
|
t.Fatalf("expected script disabled error, got: %s", res.Body.String())
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
checkID := structs.NewCheckID("test", nil)
|
|
|
|
require.Nil(t, a.State.Check(checkID), "check registered with exec disabled")
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_RegisterCheck_Passing(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-04-12 00:53:48 +00:00
|
|
|
|
2017-06-15 16:46:06 +00:00
|
|
|
args := &structs.CheckDefinition{
|
2017-05-15 19:49:13 +00:00
|
|
|
Name: "test",
|
|
|
|
TTL: 15 * time.Second,
|
2017-04-19 23:00:11 +00:00
|
|
|
Status: api.HealthPassing,
|
2015-04-12 00:53:48 +00:00
|
|
|
}
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusOK != resp.Code {
|
|
|
|
t.Fatalf("expcted 200 but got %v", resp.Code)
|
2015-04-12 00:53:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
checkID := structs.NewCheckID("test", nil)
|
|
|
|
if existing := a.State.Check(checkID); existing == nil {
|
2015-04-12 00:53:48 +00:00
|
|
|
t.Fatalf("missing test check")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:11:09 +00:00
|
|
|
if _, ok := a.checkTTLs[checkID]; !ok {
|
2015-04-12 00:53:48 +00:00
|
|
|
t.Fatalf("missing test check ttl")
|
|
|
|
}
|
|
|
|
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(checkID)
|
2017-04-19 23:00:11 +00:00
|
|
|
if state.Status != api.HealthPassing {
|
2015-04-12 00:53:48 +00:00
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_RegisterCheck_BadStatus(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-04-12 00:53:48 +00:00
|
|
|
|
2017-06-15 16:46:06 +00:00
|
|
|
args := &structs.CheckDefinition{
|
2017-05-15 19:49:13 +00:00
|
|
|
Name: "test",
|
|
|
|
TTL: 15 * time.Second,
|
2015-04-12 00:53:48 +00:00
|
|
|
Status: "fluffy",
|
|
|
|
}
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(args))
|
2015-04-12 00:53:48 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-11-19 16:50:44 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-07 14:44:03 +00:00
|
|
|
if resp.Code != http.StatusBadRequest {
|
|
|
|
t.Fatalf("accepted bad status")
|
|
|
|
}
|
2014-01-30 23:51:15 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_RegisterCheck_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfigNew())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2019-04-30 23:00:57 +00:00
|
|
|
nodeCheck := &structs.CheckDefinition{
|
2016-12-14 22:16:46 +00:00
|
|
|
Name: "test",
|
2017-05-15 19:49:13 +00:00
|
|
|
TTL: 15 * time.Second,
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
2017-05-09 16:58:12 +00:00
|
|
|
|
2019-04-30 23:00:57 +00:00
|
|
|
svc := &structs.ServiceDefinition{
|
|
|
|
ID: "foo:1234",
|
|
|
|
Name: "foo",
|
|
|
|
Port: 1234,
|
|
|
|
}
|
|
|
|
|
|
|
|
svcCheck := &structs.CheckDefinition{
|
|
|
|
Name: "test2",
|
|
|
|
ServiceID: "foo:1234",
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure the service is ready for registering a check for it.
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(svc))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-04-30 23:00:57 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-04-30 23:00:57 +00:00
|
|
|
|
|
|
|
// create a policy that has write on service foo
|
|
|
|
policyReq := &structs.ACLPolicy{
|
|
|
|
Name: "write-foo",
|
|
|
|
Rules: `service "foo" { policy = "write"}`,
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/acl/policy", jsonReader(policyReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-04-30 23:00:57 +00:00
|
|
|
resp = httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-04-30 23:00:57 +00:00
|
|
|
|
|
|
|
// create a policy that has write on the node name of the agent
|
|
|
|
policyReq = &structs.ACLPolicy{
|
|
|
|
Name: "write-node",
|
|
|
|
Rules: fmt.Sprintf(`node "%s" { policy = "write" }`, a.config.NodeName),
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/acl/policy", jsonReader(policyReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-04-30 23:00:57 +00:00
|
|
|
resp = httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-04-30 23:00:57 +00:00
|
|
|
|
|
|
|
// create a token using the write-foo policy
|
|
|
|
tokenReq := &structs.ACLToken{
|
|
|
|
Description: "write-foo",
|
|
|
|
Policies: []structs.ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-04-30 23:00:57 +00:00
|
|
|
Name: "write-foo",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/acl/token", jsonReader(tokenReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-04-30 23:00:57 +00:00
|
|
|
resp = httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
svcToken := &structs.ACLToken{}
|
|
|
|
if err := dec.Decode(svcToken); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2019-04-30 23:00:57 +00:00
|
|
|
require.NotNil(t, svcToken)
|
|
|
|
|
|
|
|
// create a token using the write-node policy
|
|
|
|
tokenReq = &structs.ACLToken{
|
|
|
|
Description: "write-node",
|
|
|
|
Policies: []structs.ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-04-30 23:00:57 +00:00
|
|
|
Name: "write-node",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/acl/token", jsonReader(tokenReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-04-30 23:00:57 +00:00
|
|
|
resp = httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
dec = json.NewDecoder(resp.Body)
|
|
|
|
nodeToken := &structs.ACLToken{}
|
|
|
|
if err := dec.Decode(nodeToken); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2019-04-30 23:00:57 +00:00
|
|
|
require.NotNil(t, nodeToken)
|
|
|
|
|
|
|
|
t.Run("no token - node check", func(t *testing.T) {
|
2019-09-26 02:55:52 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(nodeCheck))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusForbidden, resp.Code)
|
2019-09-26 02:55:52 +00:00
|
|
|
})
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2019-04-30 23:00:57 +00:00
|
|
|
t.Run("svc token - node check", func(t *testing.T) {
|
2019-09-26 02:55:52 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(nodeCheck))
|
|
|
|
req.Header.Add("X-Consul-Token", svcToken.SecretID)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusForbidden, resp.Code)
|
2019-09-26 02:55:52 +00:00
|
|
|
})
|
2019-04-30 23:00:57 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("node token - node check", func(t *testing.T) {
|
2019-09-26 02:55:52 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(nodeCheck))
|
|
|
|
req.Header.Add("X-Consul-Token", nodeToken.SecretID)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusOK, resp.Code)
|
2019-09-26 02:55:52 +00:00
|
|
|
})
|
2019-04-30 23:00:57 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("no token - svc check", func(t *testing.T) {
|
2019-09-26 02:55:52 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(svcCheck))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusForbidden, resp.Code)
|
2019-09-26 02:55:52 +00:00
|
|
|
})
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2019-04-30 23:00:57 +00:00
|
|
|
|
|
|
|
t.Run("node token - svc check", func(t *testing.T) {
|
2019-09-26 02:55:52 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(svcCheck))
|
|
|
|
req.Header.Add("X-Consul-Token", nodeToken.SecretID)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusForbidden, resp.Code)
|
2019-09-26 02:55:52 +00:00
|
|
|
})
|
2019-04-30 23:00:57 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("svc token - svc check", func(t *testing.T) {
|
2019-09-26 02:55:52 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(svcCheck))
|
|
|
|
req.Header.Add("X-Consul-Token", svcToken.SecretID)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusOK, resp.Code)
|
2019-09-26 02:55:52 +00:00
|
|
|
})
|
2019-04-30 23:00:57 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_DeregisterCheck(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-30 23:51:15 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, nil, false, "", ConfigSourceLocal); err != nil {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2022-01-06 20:38:37 +00:00
|
|
|
t.Run("remove registered check", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/deregister/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("remove non-existent check", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/deregister/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusNotFound, resp.Code)
|
|
|
|
})
|
2014-01-30 23:51:15 +00:00
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
requireCheckMissing(t, a, "test")
|
2014-01-30 23:51:15 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_DeregisterCheckACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2019-12-10 02:26:41 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1", testrpc.WithToken("root"))
|
2016-12-14 22:16:46 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, nil, false, "", ConfigSourceLocal); err != nil {
|
2016-12-14 22:16:46 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/deregister/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/deregister/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2022-01-06 20:38:37 +00:00
|
|
|
|
|
|
|
t.Run("non-existent check without token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/deregister/_nope_", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusNotFound, resp.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("non-existent check with token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/deregister/_nope_", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2022-01-06 20:38:37 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusNotFound, resp.Code)
|
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_PassCheck(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-30 23:51:15 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/pass/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
if http.StatusOK != resp.Code {
|
|
|
|
t.Fatalf("expected 200 by got %v", resp.Code)
|
2014-01-30 23:51:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(structs.NewCheckID("test", nil))
|
2017-04-19 23:00:11 +00:00
|
|
|
if state.Status != api.HealthPassing {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_PassCheck_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2016-12-14 22:16:46 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/pass/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/pass/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_WarnCheck(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-30 23:51:15 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/warn/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
if http.StatusOK != resp.Code {
|
|
|
|
t.Fatalf("expected 200 by got %v", resp.Code)
|
2014-01-30 23:51:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(structs.NewCheckID("test", nil))
|
2017-04-19 23:00:11 +00:00
|
|
|
if state.Status != api.HealthWarning {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_WarnCheck_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2016-12-14 22:16:46 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/warn/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/warn/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_FailCheck(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2014-01-30 23:51:15 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/fail/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
if http.StatusOK != resp.Code {
|
|
|
|
t.Fatalf("expected 200 by got %v", resp.Code)
|
2014-01-30 23:51:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(structs.NewCheckID("test", nil))
|
2017-04-19 23:00:11 +00:00
|
|
|
if state.Status != api.HealthCritical {
|
2014-01-30 23:51:15 +00:00
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
}
|
2014-01-30 23:56:03 +00:00
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_FailCheck_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2016-12-14 22:16:46 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/fail/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/fail/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_UpdateCheck(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2019-06-26 15:43:25 +00:00
|
|
|
maxChecksSize := 256
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, fmt.Sprintf("check_output_max_size=%d", maxChecksSize))
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2016-03-03 01:08:06 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2016-03-03 01:08:06 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cases := []checkUpdate{
|
2020-06-16 17:19:31 +00:00
|
|
|
{api.HealthPassing, "hello-passing"},
|
|
|
|
{api.HealthCritical, "hello-critical"},
|
|
|
|
{api.HealthWarning, "hello-warning"},
|
2016-03-03 01:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run(c.Status, func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/update/test", jsonReader(c))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != http.StatusOK {
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
|
|
|
}
|
2016-03-03 01:08:06 +00:00
|
|
|
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(structs.NewCheckID("test", nil))
|
2017-05-09 17:46:11 +00:00
|
|
|
if state.Status != c.Status || state.Output != c.Output {
|
|
|
|
t.Fatalf("bad: %v", state)
|
|
|
|
}
|
|
|
|
})
|
2016-03-03 01:08:06 +00:00
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("log output limit", func(t *testing.T) {
|
2017-05-09 16:58:12 +00:00
|
|
|
args := checkUpdate{
|
2017-04-19 23:00:11 +00:00
|
|
|
Status: api.HealthPassing,
|
2019-06-26 15:43:25 +00:00
|
|
|
Output: strings.Repeat("-= bad -=", 5*maxChecksSize),
|
2016-03-03 01:08:06 +00:00
|
|
|
}
|
2017-05-09 16:58:12 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/update/test", jsonReader(args))
|
2016-03-03 01:08:06 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != http.StatusOK {
|
2016-03-03 01:08:06 +00:00
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since we append some notes about truncating, we just do a
|
|
|
|
// rough check that the output buffer was cut down so this test
|
|
|
|
// isn't super brittle.
|
2019-12-10 02:26:41 +00:00
|
|
|
state := a.State.Check(structs.NewCheckID("test", nil))
|
2019-06-26 15:43:25 +00:00
|
|
|
if state.Status != api.HealthPassing || len(state.Output) > 2*maxChecksSize {
|
|
|
|
t.Fatalf("bad: %v, (len:=%d)", state, len(state.Output))
|
2016-03-03 01:08:06 +00:00
|
|
|
}
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-03-03 01:08:06 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("bogus status", func(t *testing.T) {
|
2017-05-09 16:58:12 +00:00
|
|
|
args := checkUpdate{Status: "itscomplicated"}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/update/test", jsonReader(args))
|
2016-03-03 01:08:06 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != http.StatusBadRequest {
|
2016-03-03 01:08:06 +00:00
|
|
|
t.Fatalf("expected 400, got %d", resp.Code)
|
|
|
|
}
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-03-03 01:08:06 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_UpdateCheck_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
|
|
|
chk := &structs.HealthCheck{Name: "test", CheckID: "test"}
|
2017-06-15 16:46:06 +00:00
|
|
|
chkType := &structs.CheckType{TTL: 15 * time.Second}
|
2018-10-11 12:22:11 +00:00
|
|
|
if err := a.AddCheck(chk, chkType, false, "", ConfigSourceLocal); err != nil {
|
2016-12-14 22:16:46 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
|
|
|
args := checkUpdate{api.HealthPassing, "hello-passing"}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/update/test", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
|
|
|
args := checkUpdate{api.HealthPassing, "hello-passing"}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/check/update/test", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_RegisterService(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-30 23:56:03 +00:00
|
|
|
|
2017-06-15 16:46:06 +00:00
|
|
|
args := &structs.ServiceDefinition{
|
2014-01-30 23:56:03 +00:00
|
|
|
Name: "test",
|
2018-04-21 15:34:29 +00:00
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2014-01-30 23:56:03 +00:00
|
|
|
Port: 8000,
|
2017-06-15 16:46:06 +00:00
|
|
|
Check: structs.CheckType{
|
2014-01-30 23:56:03 +00:00
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
2017-06-15 16:46:06 +00:00
|
|
|
Checks: []*structs.CheckType{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2015-01-14 03:08:30 +00:00
|
|
|
TTL: 20 * time.Second,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2015-01-14 03:08:30 +00:00
|
|
|
TTL: 30 * time.Second,
|
|
|
|
},
|
2022-06-06 19:13:19 +00:00
|
|
|
{
|
|
|
|
UDP: "1.1.1.1",
|
|
|
|
Interval: 5 * time.Second,
|
|
|
|
},
|
2015-01-14 03:08:30 +00:00
|
|
|
},
|
2018-09-07 14:30:47 +00:00
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusOK != resp.Code {
|
|
|
|
t.Fatalf("expected 200 but got %v", resp.Code)
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 16:56:00 +00:00
|
|
|
// Ensure the service
|
2019-12-10 02:26:41 +00:00
|
|
|
sid := structs.NewServiceID("test", nil)
|
|
|
|
svc := a.State.Service(sid)
|
|
|
|
if svc == nil {
|
2014-01-30 23:56:03 +00:00
|
|
|
t.Fatalf("missing test service")
|
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
if val := svc.Meta["hello"]; val != "world" {
|
|
|
|
t.Fatalf("Missing meta: %v", svc.Meta)
|
2018-04-21 15:34:29 +00:00
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
if val := svc.Weights.Passing; val != 100 {
|
2018-09-07 14:30:47 +00:00
|
|
|
t.Fatalf("Expected 100 for Weights.Passing, got: %v", val)
|
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
if val := svc.Weights.Warning; val != 3 {
|
2018-09-07 14:30:47 +00:00
|
|
|
t.Fatalf("Expected 3 for Weights.Warning, got: %v", val)
|
|
|
|
}
|
2014-01-30 23:56:03 +00:00
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2021-07-22 18:20:45 +00:00
|
|
|
checks := a.State.Checks(structs.WildcardEnterpriseMetaInDefaultPartition())
|
2022-06-06 19:13:19 +00:00
|
|
|
if len(checks) != 4 {
|
2015-01-14 03:08:30 +00:00
|
|
|
t.Fatalf("bad: %v", checks)
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
2019-10-17 18:33:11 +00:00
|
|
|
for _, c := range checks {
|
2022-06-06 19:13:19 +00:00
|
|
|
if c.Type != "ttl" && c.Type != "udp" {
|
|
|
|
t.Fatalf("expected ttl or udp check type, got %s", c.Type)
|
2019-10-17 18:33:11 +00:00
|
|
|
}
|
|
|
|
}
|
2014-01-30 23:56:03 +00:00
|
|
|
|
2017-05-21 07:11:09 +00:00
|
|
|
if len(a.checkTTLs) != 3 {
|
|
|
|
t.Fatalf("missing test check ttls: %v", a.checkTTLs)
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
2015-04-28 20:06:02 +00:00
|
|
|
|
|
|
|
// Ensure the token was configured
|
2019-12-10 02:26:41 +00:00
|
|
|
if token := a.State.ServiceToken(sid); token == "" {
|
2015-04-28 20:06:02 +00:00
|
|
|
t.Fatalf("missing token")
|
|
|
|
}
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 15:38:29 +00:00
|
|
|
func TestAgent_RegisterService_ReRegister(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_ReRegister(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ReRegister(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_ReRegister(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2019-09-02 15:38:29 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2019-09-02 15:38:29 +00:00
|
|
|
Port: 8000,
|
|
|
|
Checks: []*structs.CheckType{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-09-02 15:38:29 +00:00
|
|
|
CheckID: types.CheckID("check_1"),
|
|
|
|
TTL: 20 * time.Second,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-09-02 15:38:29 +00:00
|
|
|
CheckID: types.CheckID("check_2"),
|
|
|
|
TTL: 30 * time.Second,
|
|
|
|
},
|
2022-06-06 19:13:19 +00:00
|
|
|
{
|
|
|
|
CheckID: types.CheckID("check_3"),
|
|
|
|
UDP: "1.1.1.1",
|
|
|
|
Interval: 5 * time.Second,
|
|
|
|
},
|
2019-09-02 15:38:29 +00:00
|
|
|
},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-09-02 15:38:29 +00:00
|
|
|
|
|
|
|
args = &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2019-09-02 15:38:29 +00:00
|
|
|
Port: 8000,
|
|
|
|
Checks: []*structs.CheckType{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-09-02 15:38:29 +00:00
|
|
|
CheckID: types.CheckID("check_1"),
|
|
|
|
TTL: 20 * time.Second,
|
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-09-02 15:38:29 +00:00
|
|
|
CheckID: types.CheckID("check_3"),
|
|
|
|
TTL: 30 * time.Second,
|
|
|
|
},
|
2022-06-06 19:13:19 +00:00
|
|
|
{
|
|
|
|
CheckID: types.CheckID("check_3"),
|
|
|
|
UDP: "1.1.1.1",
|
|
|
|
Interval: 5 * time.Second,
|
|
|
|
},
|
2019-09-02 15:38:29 +00:00
|
|
|
},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ = http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp = httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-09-02 15:38:29 +00:00
|
|
|
|
2021-07-22 18:20:45 +00:00
|
|
|
checks := a.State.Checks(structs.DefaultEnterpriseMetaInDefaultPartition())
|
2019-09-02 15:38:29 +00:00
|
|
|
require.Equal(t, 3, len(checks))
|
|
|
|
|
|
|
|
checkIDs := []string{}
|
|
|
|
for id := range checks {
|
2019-12-10 02:26:41 +00:00
|
|
|
checkIDs = append(checkIDs, string(id.ID))
|
2019-09-02 15:38:29 +00:00
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
require.ElementsMatch(t, []string{"check_1", "check_2", "check_3"}, checkIDs)
|
2019-09-02 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_RegisterService_ReRegister_ReplaceExistingChecks(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_ReRegister_ReplaceExistingChecks(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ReRegister_ReplaceExistingChecks(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_ReRegister_ReplaceExistingChecks(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2019-09-02 15:38:29 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2019-09-02 15:38:29 +00:00
|
|
|
Port: 8000,
|
|
|
|
Checks: []*structs.CheckType{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-11-14 15:59:06 +00:00
|
|
|
// explicitly not setting the check id to let it be auto-generated
|
2019-11-15 15:33:21 +00:00
|
|
|
// we want to ensure that we are testing out the cases with autogenerated names/ids
|
2019-11-14 15:59:06 +00:00
|
|
|
TTL: 20 * time.Second,
|
2019-09-02 15:38:29 +00:00
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-09-02 15:38:29 +00:00
|
|
|
CheckID: types.CheckID("check_2"),
|
|
|
|
TTL: 30 * time.Second,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register?replace-existing-checks", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-09-02 15:38:29 +00:00
|
|
|
|
|
|
|
args = &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2019-09-02 15:38:29 +00:00
|
|
|
Port: 8000,
|
|
|
|
Checks: []*structs.CheckType{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-11-14 15:59:06 +00:00
|
|
|
TTL: 20 * time.Second,
|
2019-09-02 15:38:29 +00:00
|
|
|
},
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-09-02 15:38:29 +00:00
|
|
|
CheckID: types.CheckID("check_3"),
|
|
|
|
TTL: 30 * time.Second,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ = http.NewRequest("PUT", "/v1/agent/service/register?replace-existing-checks", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp = httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-09-02 15:38:29 +00:00
|
|
|
|
2021-07-22 18:20:45 +00:00
|
|
|
checks := a.State.Checks(structs.DefaultEnterpriseMetaInDefaultPartition())
|
2019-12-10 02:26:41 +00:00
|
|
|
require.Len(t, checks, 2)
|
2019-09-02 15:38:29 +00:00
|
|
|
|
|
|
|
checkIDs := []string{}
|
|
|
|
for id := range checks {
|
2019-12-10 02:26:41 +00:00
|
|
|
checkIDs = append(checkIDs, string(id.ID))
|
2019-09-02 15:38:29 +00:00
|
|
|
}
|
2019-11-14 15:59:06 +00:00
|
|
|
require.ElementsMatch(t, []string{"service:test:1", "check_3"}, checkIDs)
|
2019-09-02 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
2017-10-10 23:40:59 +00:00
|
|
|
func TestAgent_RegisterService_TranslateKeys(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-02-19 21:04:23 +00:00
|
|
|
testAgent_RegisterService_TranslateKeys(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-02-19 21:04:23 +00:00
|
|
|
testAgent_RegisterService_TranslateKeys(t, "enable_central_service_config = true")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_TranslateKeys(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
2019-06-04 14:02:38 +00:00
|
|
|
tests := []struct {
|
|
|
|
ip string
|
|
|
|
expectedTCPCheckStart string
|
|
|
|
}{
|
|
|
|
{"127.0.0.1", "127.0.0.1:"}, // private network address
|
|
|
|
{"::1", "[::1]:"}, // shared address space
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.ip, func(t *testing.T) {
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2019-08-09 19:19:30 +00:00
|
|
|
connect {}
|
2019-09-24 15:04:48 +00:00
|
|
|
`+extraHCL)
|
2019-06-04 14:02:38 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2017-10-10 23:40:59 +00:00
|
|
|
|
2019-06-04 14:02:38 +00:00
|
|
|
json := `
|
2018-09-12 16:07:47 +00:00
|
|
|
{
|
2018-10-17 20:20:35 +00:00
|
|
|
"name":"test",
|
|
|
|
"port":8000,
|
|
|
|
"enable_tag_override": true,
|
2019-06-17 14:51:50 +00:00
|
|
|
"tagged_addresses": {
|
|
|
|
"lan": {
|
|
|
|
"address": "1.2.3.4",
|
|
|
|
"port": 5353
|
|
|
|
},
|
|
|
|
"wan": {
|
|
|
|
"address": "2.3.4.5",
|
|
|
|
"port": 53
|
|
|
|
}
|
|
|
|
},
|
2018-09-12 16:07:47 +00:00
|
|
|
"meta": {
|
2018-09-27 13:33:12 +00:00
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "meta is 'opaque' so should not get translated"
|
2018-09-12 16:07:47 +00:00
|
|
|
},
|
2018-09-27 13:33:12 +00:00
|
|
|
"kind": "connect-proxy",` +
|
2019-06-04 14:02:38 +00:00
|
|
|
// Note the uppercase P is important here - it ensures translation works
|
|
|
|
// correctly in case-insensitive way. Without it this test can pass even
|
|
|
|
// when translation is broken for other valid inputs.
|
|
|
|
`"Proxy": {
|
2018-09-12 16:07:47 +00:00
|
|
|
"destination_service_name": "web",
|
|
|
|
"destination_service_id": "web",
|
|
|
|
"local_service_port": 1234,
|
2019-06-04 14:02:38 +00:00
|
|
|
"local_service_address": "` + tt.ip + `",
|
2018-09-27 13:33:12 +00:00
|
|
|
"config": {
|
|
|
|
"destination_type": "proxy.config is 'opaque' so should not get translated"
|
|
|
|
},
|
2018-09-12 16:07:47 +00:00
|
|
|
"upstreams": [
|
|
|
|
{
|
|
|
|
"destination_type": "service",
|
|
|
|
"destination_namespace": "default",
|
2021-08-20 16:57:45 +00:00
|
|
|
"destination_partition": "default",
|
2018-09-12 16:07:47 +00:00
|
|
|
"destination_name": "db",
|
2019-06-04 14:02:38 +00:00
|
|
|
"local_bind_address": "` + tt.ip + `",
|
2018-09-27 13:33:12 +00:00
|
|
|
"local_bind_port": 1234,
|
|
|
|
"config": {
|
|
|
|
"destination_type": "proxy.upstreams.config is 'opaque' so should not get translated"
|
|
|
|
}
|
2018-09-12 16:07:47 +00:00
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
"connect": {
|
2018-09-27 13:33:12 +00:00
|
|
|
"sidecar_service": {
|
2018-10-17 20:20:35 +00:00
|
|
|
"name":"test-proxy",
|
|
|
|
"port":8001,
|
|
|
|
"enable_tag_override": true,
|
2018-09-27 13:33:12 +00:00
|
|
|
"meta": {
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "sidecar_service.meta is 'opaque' so should not get translated"
|
|
|
|
},
|
|
|
|
"kind": "connect-proxy",
|
|
|
|
"proxy": {
|
|
|
|
"destination_service_name": "test",
|
|
|
|
"destination_service_id": "test",
|
|
|
|
"local_service_port": 4321,
|
2019-06-04 14:02:38 +00:00
|
|
|
"local_service_address": "` + tt.ip + `",
|
2018-09-27 13:33:12 +00:00
|
|
|
"upstreams": [
|
|
|
|
{
|
|
|
|
"destination_type": "service",
|
|
|
|
"destination_namespace": "default",
|
2021-08-20 16:57:45 +00:00
|
|
|
"destination_partition": "default",
|
2018-09-27 13:33:12 +00:00
|
|
|
"destination_name": "db",
|
2019-06-04 14:02:38 +00:00
|
|
|
"local_bind_address": "` + tt.ip + `",
|
2018-09-27 13:33:12 +00:00
|
|
|
"local_bind_port": 1234,
|
|
|
|
"config": {
|
|
|
|
"destination_type": "sidecar_service.proxy.upstreams.config is 'opaque' so should not get translated"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
2018-09-12 16:07:47 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
"weights":{
|
|
|
|
"passing": 16
|
|
|
|
}
|
|
|
|
}`
|
2019-06-04 14:02:38 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", strings.NewReader(json))
|
|
|
|
|
|
|
|
rr := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(rr, req)
|
2019-06-04 14:02:38 +00:00
|
|
|
require.Equal(t, 200, rr.Code, "body: %s", rr.Body)
|
|
|
|
|
|
|
|
svc := &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
2019-06-17 14:51:50 +00:00
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{
|
|
|
|
"lan": {
|
|
|
|
Address: "1.2.3.4",
|
|
|
|
Port: 5353,
|
|
|
|
},
|
|
|
|
"wan": {
|
|
|
|
Address: "2.3.4.5",
|
|
|
|
Port: 53,
|
|
|
|
},
|
|
|
|
},
|
2019-06-04 14:02:38 +00:00
|
|
|
Meta: map[string]string{
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "meta is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
Port: 8000,
|
|
|
|
EnableTagOverride: true,
|
|
|
|
Weights: &structs.Weights{Passing: 16, Warning: 0},
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "web",
|
|
|
|
DestinationServiceID: "web",
|
|
|
|
LocalServiceAddress: tt.ip,
|
|
|
|
LocalServicePort: 1234,
|
2018-09-27 13:33:12 +00:00
|
|
|
Config: map[string]interface{}{
|
2019-06-04 14:02:38 +00:00
|
|
|
"destination_type": "proxy.config is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
Upstreams: structs.Upstreams{
|
|
|
|
{
|
|
|
|
DestinationType: structs.UpstreamDestTypeService,
|
|
|
|
DestinationName: "db",
|
|
|
|
DestinationNamespace: "default",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2019-06-04 14:02:38 +00:00
|
|
|
LocalBindAddress: tt.ip,
|
|
|
|
LocalBindPort: 1234,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"destination_type": "proxy.upstreams.config is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
},
|
2018-09-27 13:33:12 +00:00
|
|
|
},
|
2018-09-12 16:07:47 +00:00
|
|
|
},
|
2019-06-04 14:02:38 +00:00
|
|
|
Connect: structs.ServiceConnect{
|
|
|
|
// The sidecar service is nilled since it is only config sugar and
|
|
|
|
// shouldn't be represented in state. We assert that the translations
|
|
|
|
// there worked by inspecting the registered sidecar below.
|
|
|
|
SidecarService: nil,
|
2018-09-27 13:33:12 +00:00
|
|
|
},
|
2021-07-22 18:20:45 +00:00
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
2019-06-04 14:02:38 +00:00
|
|
|
}
|
2018-09-27 14:00:51 +00:00
|
|
|
|
2019-12-10 02:26:41 +00:00
|
|
|
got := a.State.Service(structs.NewServiceID("test", nil))
|
2019-06-04 14:02:38 +00:00
|
|
|
require.Equal(t, svc, got)
|
2018-09-27 14:00:51 +00:00
|
|
|
|
2019-06-04 14:02:38 +00:00
|
|
|
sidecarSvc := &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
ID: "test-sidecar-proxy",
|
|
|
|
Service: "test-proxy",
|
|
|
|
Meta: map[string]string{
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "sidecar_service.meta is 'opaque' so should not get translated",
|
|
|
|
},
|
2020-02-19 21:04:23 +00:00
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
2019-06-04 14:02:38 +00:00
|
|
|
Port: 8001,
|
|
|
|
EnableTagOverride: true,
|
|
|
|
Weights: &structs.Weights{Passing: 1, Warning: 1},
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "test",
|
|
|
|
DestinationServiceID: "test",
|
|
|
|
LocalServiceAddress: tt.ip,
|
|
|
|
LocalServicePort: 4321,
|
|
|
|
Upstreams: structs.Upstreams{
|
|
|
|
{
|
|
|
|
DestinationType: structs.UpstreamDestTypeService,
|
|
|
|
DestinationName: "db",
|
|
|
|
DestinationNamespace: "default",
|
2021-08-20 16:57:45 +00:00
|
|
|
DestinationPartition: "default",
|
2019-06-04 14:02:38 +00:00
|
|
|
LocalBindAddress: tt.ip,
|
|
|
|
LocalBindPort: 1234,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"destination_type": "sidecar_service.proxy.upstreams.config is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
},
|
2018-09-12 16:07:47 +00:00
|
|
|
},
|
|
|
|
},
|
2021-07-22 18:20:45 +00:00
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
2019-06-04 14:02:38 +00:00
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
gotSidecar := a.State.Service(structs.NewServiceID("test-sidecar-proxy", nil))
|
2019-06-04 14:02:38 +00:00
|
|
|
hasNoCorrectTCPCheck := true
|
|
|
|
for _, v := range a.checkTCPs {
|
|
|
|
if strings.HasPrefix(v.TCP, tt.expectedTCPCheckStart) {
|
|
|
|
hasNoCorrectTCPCheck = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
fmt.Println("TCP Check:= ", v)
|
|
|
|
}
|
|
|
|
if hasNoCorrectTCPCheck {
|
2022-09-01 21:03:35 +00:00
|
|
|
t.Fatalf("Did not find the expected TCP Healthcheck '%s' in %#v ", tt.expectedTCPCheckStart, a.checkTCPs)
|
2019-06-04 14:02:38 +00:00
|
|
|
}
|
|
|
|
require.Equal(t, sidecarSvc, gotSidecar)
|
|
|
|
})
|
2017-10-10 23:40:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
func TestAgent_RegisterService_TranslateKeys_UDP(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-06-06 19:13:19 +00:00
|
|
|
testAgent_RegisterService_TranslateKeys(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-06-06 19:13:19 +00:00
|
|
|
testAgent_RegisterService_TranslateKeys(t, "enable_central_service_config = true")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
func testAgent_RegisterService_TranslateKeys_UDP(t *testing.T, extraHCL string) {
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Helper()
|
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
tests := []struct {
|
|
|
|
ip string
|
|
|
|
expectedUDPCheckStart string
|
|
|
|
}{
|
|
|
|
{"127.0.0.1", "127.0.0.1:"}, // private network address
|
|
|
|
{"::1", "[::1]:"}, // shared address space
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.ip, func(t *testing.T) {
|
|
|
|
a := NewTestAgent(t, `
|
|
|
|
connect {}
|
|
|
|
`+extraHCL)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
json := `
|
|
|
|
{
|
|
|
|
"name":"test",
|
|
|
|
"port":8000,
|
|
|
|
"enable_tag_override": true,
|
|
|
|
"tagged_addresses": {
|
|
|
|
"lan": {
|
|
|
|
"address": "1.2.3.4",
|
|
|
|
"port": 5353
|
2016-12-14 22:16:46 +00:00
|
|
|
},
|
2022-06-06 19:13:19 +00:00
|
|
|
"wan": {
|
|
|
|
"address": "2.3.4.5",
|
|
|
|
"port": 53
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"meta": {
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "meta is 'opaque' so should not get translated"
|
|
|
|
},
|
|
|
|
"kind": "connect-proxy",` +
|
|
|
|
// Note the uppercase P is important here - it ensures translation works
|
|
|
|
// correctly in case-insensitive way. Without it this test can pass even
|
|
|
|
// when translation is broken for other valid inputs.
|
|
|
|
`"Proxy": {
|
|
|
|
"destination_service_name": "web",
|
|
|
|
"destination_service_id": "web",
|
|
|
|
"local_service_port": 1234,
|
|
|
|
"local_service_address": "` + tt.ip + `",
|
|
|
|
"config": {
|
|
|
|
"destination_type": "proxy.config is 'opaque' so should not get translated"
|
2016-12-14 22:16:46 +00:00
|
|
|
},
|
2022-06-06 19:13:19 +00:00
|
|
|
"upstreams": [
|
|
|
|
{
|
|
|
|
"destination_type": "service",
|
|
|
|
"destination_namespace": "default",
|
|
|
|
"destination_partition": "default",
|
|
|
|
"destination_name": "db",
|
|
|
|
"local_bind_address": "` + tt.ip + `",
|
|
|
|
"local_bind_port": 1234,
|
|
|
|
"config": {
|
|
|
|
"destination_type": "proxy.upstreams.config is 'opaque' so should not get translated"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
2016-12-14 22:16:46 +00:00
|
|
|
},
|
2022-06-06 19:13:19 +00:00
|
|
|
"connect": {
|
|
|
|
"sidecar_service": {
|
|
|
|
"name":"test-proxy",
|
|
|
|
"port":8001,
|
|
|
|
"enable_tag_override": true,
|
|
|
|
"meta": {
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "sidecar_service.meta is 'opaque' so should not get translated"
|
|
|
|
},
|
|
|
|
"kind": "connect-proxy",
|
|
|
|
"proxy": {
|
|
|
|
"destination_service_name": "test",
|
|
|
|
"destination_service_id": "test",
|
|
|
|
"local_service_port": 4321,
|
|
|
|
"local_service_address": "` + tt.ip + `",
|
|
|
|
"upstreams": [
|
|
|
|
{
|
|
|
|
"destination_type": "service",
|
|
|
|
"destination_namespace": "default",
|
|
|
|
"destination_partition": "default",
|
|
|
|
"destination_name": "db",
|
|
|
|
"local_bind_address": "` + tt.ip + `",
|
|
|
|
"local_bind_port": 1234,
|
|
|
|
"config": {
|
|
|
|
"destination_type": "sidecar_service.proxy.upstreams.config is 'opaque' so should not get translated"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"weights":{
|
|
|
|
"passing": 16
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", strings.NewReader(json))
|
2020-12-07 18:42:55 +00:00
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
rr := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(rr, req)
|
|
|
|
require.Equal(t, 200, rr.Code, "body: %s", rr.Body)
|
2019-09-24 15:04:48 +00:00
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
svc := &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{
|
|
|
|
"lan": {
|
|
|
|
Address: "1.2.3.4",
|
|
|
|
Port: 5353,
|
|
|
|
},
|
|
|
|
"wan": {
|
|
|
|
Address: "2.3.4.5",
|
|
|
|
Port: 53,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Meta: map[string]string{
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "meta is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
Port: 8000,
|
|
|
|
EnableTagOverride: true,
|
|
|
|
Weights: &structs.Weights{Passing: 16, Warning: 0},
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "web",
|
|
|
|
DestinationServiceID: "web",
|
|
|
|
LocalServiceAddress: tt.ip,
|
|
|
|
LocalServicePort: 1234,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"destination_type": "proxy.config is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
Upstreams: structs.Upstreams{
|
|
|
|
{
|
|
|
|
DestinationType: structs.UpstreamDestTypeService,
|
|
|
|
DestinationName: "db",
|
|
|
|
DestinationNamespace: "default",
|
|
|
|
DestinationPartition: "default",
|
|
|
|
LocalBindAddress: tt.ip,
|
|
|
|
LocalBindPort: 1234,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"destination_type": "proxy.upstreams.config is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Connect: structs.ServiceConnect{
|
|
|
|
// The sidecar service is nilled since it is only config sugar and
|
|
|
|
// shouldn't be represented in state. We assert that the translations
|
|
|
|
// there worked by inspecting the registered sidecar below.
|
|
|
|
SidecarService: nil,
|
|
|
|
},
|
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
|
|
|
}
|
2019-09-24 15:04:48 +00:00
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
got := a.State.Service(structs.NewServiceID("test", nil))
|
|
|
|
require.Equal(t, svc, got)
|
2017-05-08 16:34:45 +00:00
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
sidecarSvc := &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
ID: "test-sidecar-proxy",
|
|
|
|
Service: "test-proxy",
|
|
|
|
Meta: map[string]string{
|
|
|
|
"some": "meta",
|
|
|
|
"enable_tag_override": "sidecar_service.meta is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
|
|
|
Port: 8001,
|
|
|
|
EnableTagOverride: true,
|
|
|
|
Weights: &structs.Weights{Passing: 1, Warning: 1},
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "test",
|
|
|
|
DestinationServiceID: "test",
|
|
|
|
LocalServiceAddress: tt.ip,
|
|
|
|
LocalServicePort: 4321,
|
|
|
|
Upstreams: structs.Upstreams{
|
|
|
|
{
|
|
|
|
DestinationType: structs.UpstreamDestTypeService,
|
|
|
|
DestinationName: "db",
|
|
|
|
DestinationNamespace: "default",
|
|
|
|
DestinationPartition: "default",
|
|
|
|
LocalBindAddress: tt.ip,
|
|
|
|
LocalBindPort: 1234,
|
|
|
|
Config: map[string]interface{}{
|
|
|
|
"destination_type": "sidecar_service.proxy.upstreams.config is 'opaque' so should not get translated",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
|
|
|
}
|
|
|
|
gotSidecar := a.State.Service(structs.NewServiceID("test-sidecar-proxy", nil))
|
|
|
|
hasNoCorrectUDPCheck := true
|
|
|
|
for _, v := range a.checkUDPs {
|
|
|
|
if strings.HasPrefix(v.UDP, tt.expectedUDPCheckStart) {
|
|
|
|
hasNoCorrectUDPCheck = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
fmt.Println("UDP Check:= ", v)
|
|
|
|
}
|
|
|
|
if hasNoCorrectUDPCheck {
|
|
|
|
t.Fatalf("Did not find the expected UDP Healtcheck '%s' in %#v ", tt.expectedUDPCheckStart, a.checkUDPs)
|
|
|
|
}
|
|
|
|
require.Equal(t, sidecarSvc, gotSidecar)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_RegisterService_ACLDeny(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ACLDeny(t, "enable_central_service_config = false")
|
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ACLDeny(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_ACLDeny(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
a := NewTestAgent(t, TestACLConfig()+" "+extraHCL)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Tags: []string{"primary"},
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
Checks: []*structs.CheckType{
|
|
|
|
{
|
|
|
|
TTL: 20 * time.Second,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
TTL: 30 * time.Second,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("no token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2022-06-06 19:13:19 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_RegisterService_InvalidAddress(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_InvalidAddress(t, "enable_central_service_config = false")
|
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_InvalidAddress(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_InvalidAddress(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
a := NewTestAgent(t, extraHCL)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
for _, addr := range []string{"0.0.0.0", "::", "[::]"} {
|
|
|
|
t.Run("addr "+addr, func(t *testing.T) {
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Address: addr,
|
|
|
|
Port: 8000,
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2022-06-06 19:13:19 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if got, want := resp.Code, 400; got != want {
|
2017-05-09 07:29:13 +00:00
|
|
|
t.Fatalf("got code %d want %d", got, want)
|
|
|
|
}
|
|
|
|
})
|
2017-05-08 16:34:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-17 12:29:02 +00:00
|
|
|
// This tests local agent service registration of a unmanaged connect proxy.
|
|
|
|
// This verifies that it is put in the local state store properly for syncing
|
2019-08-09 19:19:30 +00:00
|
|
|
// later.
|
2018-04-17 12:29:02 +00:00
|
|
|
func TestAgent_RegisterService_UnmanagedConnectProxy(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_UnmanagedConnectProxy(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_UnmanagedConnectProxy(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_UnmanagedConnectProxy(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
2018-03-10 01:16:12 +00:00
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2018-03-10 01:16:12 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-10 01:16:12 +00:00
|
|
|
|
2018-09-12 16:07:47 +00:00
|
|
|
// Register a proxy. Note that the destination doesn't exist here on this
|
|
|
|
// agent or in the catalog at all. This is intended and part of the design.
|
|
|
|
args := &api.AgentServiceRegistration{
|
|
|
|
Kind: api.ServiceKindConnectProxy,
|
|
|
|
Name: "connect-proxy",
|
|
|
|
Port: 8000,
|
|
|
|
Proxy: &api.AgentServiceConnectProxyConfig{
|
|
|
|
DestinationServiceName: "web",
|
|
|
|
Upstreams: []api.Upstream{
|
|
|
|
{
|
|
|
|
// No type to force default
|
|
|
|
DestinationName: "db",
|
|
|
|
LocalBindPort: 1234,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
DestinationType: "prepared_query",
|
|
|
|
DestinationName: "geo-cache",
|
|
|
|
LocalBindPort: 1235,
|
|
|
|
},
|
|
|
|
},
|
2021-04-13 22:08:41 +00:00
|
|
|
Mode: api.ProxyModeTransparent,
|
|
|
|
TransparentProxy: &api.TransparentProxyConfig{
|
|
|
|
OutboundListenerPort: 808,
|
|
|
|
},
|
2018-03-10 01:16:12 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2018-03-10 01:16:12 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2018-03-10 01:16:12 +00:00
|
|
|
|
2018-03-12 17:13:44 +00:00
|
|
|
// Ensure the service
|
2019-12-10 02:26:41 +00:00
|
|
|
sid := structs.NewServiceID("connect-proxy", nil)
|
|
|
|
svc := a.State.Service(sid)
|
|
|
|
require.NotNil(t, svc, "has service")
|
|
|
|
require.Equal(t, structs.ServiceKindConnectProxy, svc.Kind)
|
2021-07-26 21:12:29 +00:00
|
|
|
|
|
|
|
// Registration sets default types and namespaces
|
|
|
|
for i := range args.Proxy.Upstreams {
|
|
|
|
if args.Proxy.Upstreams[i].DestinationType == "" {
|
|
|
|
args.Proxy.Upstreams[i].DestinationType = api.UpstreamDestTypeService
|
|
|
|
}
|
|
|
|
if args.Proxy.Upstreams[i].DestinationNamespace == "" {
|
|
|
|
args.Proxy.Upstreams[i].DestinationNamespace =
|
|
|
|
structs.DefaultEnterpriseMetaInDefaultPartition().NamespaceOrEmpty()
|
|
|
|
}
|
2021-08-20 16:57:45 +00:00
|
|
|
if args.Proxy.Upstreams[i].DestinationPartition == "" {
|
|
|
|
args.Proxy.Upstreams[i].DestinationPartition =
|
|
|
|
structs.DefaultEnterpriseMetaInDefaultPartition().PartitionOrEmpty()
|
|
|
|
}
|
2021-07-26 21:12:29 +00:00
|
|
|
}
|
|
|
|
|
2019-12-10 02:26:41 +00:00
|
|
|
require.Equal(t, args.Proxy, svc.Proxy.ToAPI())
|
2018-03-10 01:16:12 +00:00
|
|
|
|
|
|
|
// Ensure the token was configured
|
2019-12-10 02:26:41 +00:00
|
|
|
require.Equal(t, "abc123", a.State.ServiceToken(structs.NewServiceID("connect-proxy", nil)))
|
2018-03-10 01:16:12 +00:00
|
|
|
}
|
|
|
|
|
2018-09-27 13:33:12 +00:00
|
|
|
func testDefaultSidecar(svc string, port int, fns ...func(*structs.NodeService)) *structs.NodeService {
|
|
|
|
ns := &structs.NodeService{
|
2020-01-17 14:54:17 +00:00
|
|
|
ID: svc + "-sidecar-proxy",
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
Service: svc + "-sidecar-proxy",
|
|
|
|
Port: 2222,
|
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
2019-01-08 10:13:49 +00:00
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
2018-09-27 13:33:12 +00:00
|
|
|
// Note that LocallyRegisteredAsSidecar should be true on the internal
|
|
|
|
// NodeService, but that we never want to see it in the HTTP response as
|
|
|
|
// it's internal only state. This is being compared directly to local state
|
|
|
|
// so should be present here.
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: svc,
|
|
|
|
DestinationServiceID: svc,
|
|
|
|
LocalServiceAddress: "127.0.0.1",
|
|
|
|
LocalServicePort: port,
|
|
|
|
},
|
2021-07-22 18:20:45 +00:00
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
2018-09-27 13:33:12 +00:00
|
|
|
}
|
|
|
|
for _, fn := range fns {
|
|
|
|
fn(ns)
|
|
|
|
}
|
|
|
|
return ns
|
|
|
|
}
|
|
|
|
|
2019-02-20 16:23:38 +00:00
|
|
|
// testCreateToken creates a Policy for the provided rules and a Token linked to that Policy.
|
2018-09-27 14:00:51 +00:00
|
|
|
func testCreateToken(t *testing.T, a *TestAgent, rules string) string {
|
2019-02-20 16:23:38 +00:00
|
|
|
policyName, err := uuid.GenerateUUID() // we just need a unique name for the test and UUIDs are definitely unique
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
policyID := testCreatePolicy(t, a, policyName, rules)
|
|
|
|
|
2018-09-27 14:00:51 +00:00
|
|
|
args := map[string]interface{}{
|
2019-12-06 16:14:56 +00:00
|
|
|
"Description": "User Token",
|
2019-02-20 16:23:38 +00:00
|
|
|
"Policies": []map[string]interface{}{
|
2020-06-16 17:19:31 +00:00
|
|
|
{
|
2019-02-20 16:23:38 +00:00
|
|
|
"ID": policyID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"Local": false,
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/acl/token", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-02-20 16:23:38 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
aclResp := &structs.ACLToken{}
|
|
|
|
if err := dec.Decode(aclResp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2019-02-20 16:23:38 +00:00
|
|
|
return aclResp.SecretID
|
|
|
|
}
|
|
|
|
|
|
|
|
func testCreatePolicy(t *testing.T, a *TestAgent, name, rules string) string {
|
|
|
|
args := map[string]interface{}{
|
|
|
|
"Name": name,
|
2018-09-27 14:00:51 +00:00
|
|
|
"Rules": rules,
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/acl/policy", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-09-27 14:00:51 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
aclResp := &structs.ACLPolicy{}
|
|
|
|
if err := dec.Decode(aclResp); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2018-09-27 14:00:51 +00:00
|
|
|
return aclResp.ID
|
|
|
|
}
|
|
|
|
|
2018-09-27 13:33:12 +00:00
|
|
|
// This tests local agent service registration with a sidecar service. Note we
|
|
|
|
// only test simple defaults for the sidecar here since the actual logic for
|
|
|
|
// handling sidecar defaults and port assignment is tested thoroughly in
|
|
|
|
// TestAgent_sidecarServiceFromNodeService. Note it also tests Deregister
|
|
|
|
// explicitly too since setup is identical.
|
|
|
|
func TestAgent_RegisterServiceDeregisterService_Sidecar(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterServiceDeregisterService_Sidecar(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterServiceDeregisterService_Sidecar(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterServiceDeregisterService_Sidecar(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
preRegister, preRegister2 *structs.NodeService
|
|
|
|
// Use raw JSON payloads rather than encoding to avoid subtleties with some
|
|
|
|
// internal representations and different ways they encode and decode. We
|
|
|
|
// rely on the payload being Unmarshalable to structs.ServiceDefinition
|
|
|
|
// directly.
|
|
|
|
json string
|
|
|
|
enableACL bool
|
2023-02-06 15:35:52 +00:00
|
|
|
policies string
|
2018-09-27 13:33:12 +00:00
|
|
|
wantNS *structs.NodeService
|
|
|
|
wantErr string
|
|
|
|
wantSidecarIDLeftAfterDereg bool
|
|
|
|
assertStateFn func(t *testing.T, state *local.State)
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "sanity check no sidecar case",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "default sidecar",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: testDefaultSidecar("web", 1111),
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK defaults",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2019-02-20 16:23:38 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
2018-09-27 13:33:12 +00:00
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: testDefaultSidecar("web", 1111),
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL denied",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
2023-02-06 15:35:52 +00:00
|
|
|
enableACL: true,
|
2023-09-18 23:10:50 +00:00
|
|
|
policies: ``, // No policies means no valid token
|
2023-02-06 15:35:52 +00:00
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
2018-09-27 13:33:12 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service but not for sidecar",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
|
|
|
// This will become more common/reasonable when ACLs support exact match.
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2018-09-27 13:33:12 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "deny"
|
|
|
|
}
|
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
2019-02-20 16:23:38 +00:00
|
|
|
name: "ACL OK for service and sidecar but not sidecar's overridden destination",
|
2018-09-27 13:33:12 +00:00
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"proxy": {
|
|
|
|
"DestinationServiceName": "foo"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2019-02-20 16:23:38 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
2018-09-27 13:33:12 +00:00
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service but not for overridden sidecar",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"name": "foo-sidecar-proxy"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2019-02-20 16:23:38 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
2018-09-27 13:33:12 +00:00
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service but and overridden for sidecar",
|
|
|
|
// This test ensures that if the sidecar embeds it's own token with
|
2019-03-06 17:13:28 +00:00
|
|
|
// different privs from the main request token it will be honored for the
|
2018-09-27 13:33:12 +00:00
|
|
|
// sidecar registration. We use the test root token since that should have
|
|
|
|
// permission.
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"name": "foo",
|
|
|
|
"token": "root"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2019-02-20 16:23:38 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
2018-09-27 13:33:12 +00:00
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: testDefaultSidecar("web", 1111, func(ns *structs.NodeService) {
|
|
|
|
ns.Service = "foo"
|
|
|
|
}),
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid check definition in sidecar",
|
|
|
|
// Note no interval in the TCP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"check": {
|
|
|
|
"TCP": "foo"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "invalid check in sidecar_service",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid checks definitions in sidecar",
|
|
|
|
// Note no interval in the TCP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"checks": [{
|
|
|
|
"TCP": "foo"
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "invalid check in sidecar_service",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid check status in sidecar",
|
|
|
|
// Note no interval in the TCP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"check": {
|
|
|
|
"TCP": "foo",
|
|
|
|
"Interval": 10,
|
|
|
|
"Status": "unsupported-status"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Status for checks must 'passing', 'warning', 'critical'",
|
|
|
|
},
|
|
|
|
{
|
2019-02-20 16:23:38 +00:00
|
|
|
name: "invalid checks status in sidecar",
|
2018-09-27 13:33:12 +00:00
|
|
|
// Note no interval in the TCP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"checks": [{
|
|
|
|
"TCP": "foo",
|
|
|
|
"Interval": 10,
|
|
|
|
"Status": "unsupported-status"
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Status for checks must 'passing', 'warning', 'critical'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "another service registered with same ID as a sidecar should not be deregistered",
|
|
|
|
// Add another service with the same ID that a sidecar for web would have
|
|
|
|
preRegister: &structs.NodeService{
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "fake-sidecar",
|
|
|
|
Port: 9999,
|
|
|
|
},
|
|
|
|
// Register web with NO SIDECAR
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Note here that although the registration here didn't register it, we
|
|
|
|
// should still see the NodeService we pre-registered here.
|
|
|
|
wantNS: &structs.NodeService{
|
2020-01-17 14:54:17 +00:00
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "fake-sidecar",
|
|
|
|
Port: 9999,
|
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
2019-01-08 10:13:49 +00:00
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
2021-07-22 18:20:45 +00:00
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
2018-09-27 13:33:12 +00:00
|
|
|
},
|
|
|
|
// After we deregister the web service above, the fake sidecar with
|
|
|
|
// clashing ID SHOULD NOT have been removed since it wasn't part of the
|
|
|
|
// original registration.
|
|
|
|
wantSidecarIDLeftAfterDereg: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "updates to sidecar should work",
|
|
|
|
// Add a valid sidecar already registered
|
|
|
|
preRegister: &structs.NodeService{
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "web-sidecar-proxy",
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Port: 9999,
|
|
|
|
},
|
|
|
|
// Register web with Sidecar on different port
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"Port": 6666
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Note here that although the registration here didn't register it, we
|
|
|
|
// should still see the NodeService we pre-registered here.
|
|
|
|
wantNS: &structs.NodeService{
|
|
|
|
Kind: "connect-proxy",
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "web-sidecar-proxy",
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Port: 6666,
|
2020-01-17 14:54:17 +00:00
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
2019-01-08 10:13:49 +00:00
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
2018-09-27 13:33:12 +00:00
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "web",
|
|
|
|
DestinationServiceID: "web",
|
|
|
|
LocalServiceAddress: "127.0.0.1",
|
|
|
|
LocalServicePort: 1111,
|
|
|
|
},
|
2021-07-22 18:20:45 +00:00
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
2018-09-27 13:33:12 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "update that removes sidecar should NOT deregister it",
|
|
|
|
// Add web with a valid sidecar already registered
|
|
|
|
preRegister: &structs.NodeService{
|
|
|
|
ID: "web",
|
|
|
|
Service: "web",
|
|
|
|
Port: 1111,
|
|
|
|
},
|
|
|
|
preRegister2: testDefaultSidecar("web", 1111),
|
|
|
|
// Register (update) web and remove sidecar (and port for sanity check)
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 2222
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Sidecar should still be there such that API can update registration
|
|
|
|
// without accidentally removing a sidecar. This is equivalent to embedded
|
|
|
|
// checks which are not removed by just not being included in an update.
|
|
|
|
// We will document that sidecar registrations via API must be explicitiy
|
|
|
|
// deregistered.
|
|
|
|
wantNS: testDefaultSidecar("web", 1111),
|
|
|
|
// Sanity check the rest of the update happened though.
|
|
|
|
assertStateFn: func(t *testing.T, state *local.State) {
|
2019-12-10 02:26:41 +00:00
|
|
|
svc := state.Service(structs.NewServiceID("web", nil))
|
|
|
|
require.NotNil(t, svc)
|
2018-09-27 13:33:12 +00:00
|
|
|
require.Equal(t, 2222, svc.Port)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
// Constrain auto ports to 1 available to make it deterministic
|
2018-10-17 20:20:35 +00:00
|
|
|
hcl := `ports {
|
2018-09-27 13:33:12 +00:00
|
|
|
sidecar_min_port = 2222
|
|
|
|
sidecar_max_port = 2222
|
|
|
|
}
|
|
|
|
`
|
|
|
|
if tt.enableACL {
|
|
|
|
hcl = hcl + TestACLConfig()
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, hcl+" "+extraHCL)
|
2018-09-27 13:33:12 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
if tt.preRegister != nil {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, a.addServiceFromSource(tt.preRegister, nil, false, "", ConfigSourceLocal))
|
2018-09-27 13:33:12 +00:00
|
|
|
}
|
|
|
|
if tt.preRegister2 != nil {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, a.addServiceFromSource(tt.preRegister2, nil, false, "", ConfigSourceLocal))
|
2018-09-27 13:33:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create an ACL token with require policy
|
|
|
|
var token string
|
2023-02-06 15:35:52 +00:00
|
|
|
if tt.enableACL && tt.policies != "" {
|
|
|
|
token = testCreateToken(t, a, tt.policies)
|
2018-09-27 13:33:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
br := bytes.NewBufferString(tt.json)
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", br)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2018-09-27 13:33:12 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2018-09-27 13:33:12 +00:00
|
|
|
if tt.wantErr != "" {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Contains(t, strings.ToLower(resp.Body.String()), strings.ToLower(tt.wantErr))
|
2018-09-27 13:33:12 +00:00
|
|
|
return
|
|
|
|
}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "request failed with body: %s",
|
2018-09-27 13:33:12 +00:00
|
|
|
resp.Body.String())
|
|
|
|
|
|
|
|
// Sanity the target service registration
|
2021-08-19 20:09:42 +00:00
|
|
|
svcs := a.State.AllServices()
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
// Parse the expected definition into a ServiceDefinition
|
|
|
|
var sd structs.ServiceDefinition
|
2021-12-07 14:44:03 +00:00
|
|
|
err := json.Unmarshal([]byte(tt.json), &sd)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, sd.Name)
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
svcID := sd.ID
|
|
|
|
if svcID == "" {
|
|
|
|
svcID = sd.Name
|
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
sid := structs.NewServiceID(svcID, nil)
|
|
|
|
svc, ok := svcs[sid]
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.True(t, ok, "has service "+sid.String())
|
|
|
|
assert.Equal(t, sd.Name, svc.Service)
|
|
|
|
assert.Equal(t, sd.Port, svc.Port)
|
2018-09-27 13:33:12 +00:00
|
|
|
// Ensure that the actual registered service _doesn't_ still have it's
|
|
|
|
// sidecar info since it's duplicate and we don't want that synced up to
|
2019-03-06 17:13:28 +00:00
|
|
|
// the catalog or included in responses particularly - it's just
|
2018-09-27 13:33:12 +00:00
|
|
|
// registration syntax sugar.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Nil(t, svc.Connect.SidecarService)
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
if tt.wantNS == nil {
|
|
|
|
// Sanity check that there was no service registered, we rely on there
|
|
|
|
// being no services at start of test so we can just use the count.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Len(t, svcs, 1, "should be no sidecar registered")
|
2018-09-27 13:33:12 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure sidecar
|
2019-12-10 02:26:41 +00:00
|
|
|
svc, ok = svcs[structs.NewServiceID(tt.wantNS.ID, nil)]
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.True(t, ok, "no sidecar registered at "+tt.wantNS.ID)
|
|
|
|
assert.Equal(t, tt.wantNS, svc)
|
2018-09-27 13:33:12 +00:00
|
|
|
|
|
|
|
if tt.assertStateFn != nil {
|
|
|
|
tt.assertStateFn(t, a.State)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now verify deregistration also removes sidecar (if there was one and it
|
|
|
|
// was added via sidecar not just coincidental ID clash)
|
|
|
|
{
|
|
|
|
req := httptest.NewRequest("PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
"/v1/agent/service/deregister/"+svcID, nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2018-09-27 13:33:12 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2018-09-27 13:33:12 +00:00
|
|
|
|
2021-08-19 20:09:42 +00:00
|
|
|
svcs := a.State.AllServices()
|
2020-05-14 18:41:20 +00:00
|
|
|
_, ok = svcs[structs.NewServiceID(tt.wantNS.ID, nil)]
|
2018-09-27 13:33:12 +00:00
|
|
|
if tt.wantSidecarIDLeftAfterDereg {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.True(t, ok, "removed non-sidecar service at "+tt.wantNS.ID)
|
2018-09-27 13:33:12 +00:00
|
|
|
} else {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.False(t, ok, "sidecar not deregistered with service "+svcID)
|
2018-09-27 13:33:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-06 19:13:19 +00:00
|
|
|
// This tests local agent service registration with a sidecar service. Note we
|
|
|
|
// only test simple defaults for the sidecar here since the actual logic for
|
|
|
|
// handling sidecar defaults and port assignment is tested thoroughly in
|
|
|
|
// TestAgent_sidecarServiceFromNodeService. Note it also tests Deregister
|
|
|
|
// explicitly too since setup is identical.
|
|
|
|
func TestAgent_RegisterServiceDeregisterService_Sidecar_UDP(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterServiceDeregisterService_Sidecar_UDP(t, "enable_central_service_config = false")
|
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterServiceDeregisterService_Sidecar_UDP(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterServiceDeregisterService_Sidecar_UDP(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
preRegister, preRegister2 *structs.NodeService
|
|
|
|
// Use raw JSON payloads rather than encoding to avoid subtleties with some
|
|
|
|
// internal representations and different ways they encode and decode. We
|
|
|
|
// rely on the payload being Unmarshalable to structs.ServiceDefinition
|
|
|
|
// directly.
|
|
|
|
json string
|
|
|
|
enableACL bool
|
2023-02-06 15:35:52 +00:00
|
|
|
policies string
|
2022-06-06 19:13:19 +00:00
|
|
|
wantNS *structs.NodeService
|
|
|
|
wantErr string
|
|
|
|
wantSidecarIDLeftAfterDereg bool
|
|
|
|
assertStateFn func(t *testing.T, state *local.State)
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "sanity check no sidecar case",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "default sidecar",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: testDefaultSidecar("web", 1111),
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK defaults",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2022-06-06 19:13:19 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: testDefaultSidecar("web", 1111),
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL denied",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
2023-02-06 15:35:52 +00:00
|
|
|
enableACL: true,
|
|
|
|
policies: ``, // No policies means no valid token
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
2022-06-06 19:13:19 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service but not for sidecar",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
|
|
|
// This will become more common/reasonable when ACLs support exact match.
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2022-06-06 19:13:19 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "deny"
|
|
|
|
}
|
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service and sidecar but not sidecar's overridden destination",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"proxy": {
|
|
|
|
"DestinationServiceName": "foo"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2022-06-06 19:13:19 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service but not for overridden sidecar",
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"name": "foo-sidecar-proxy"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2022-06-06 19:13:19 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Permission denied",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "ACL OK for service but and overridden for sidecar",
|
|
|
|
// This test ensures that if the sidecar embeds it's own token with
|
|
|
|
// different privs from the main request token it will be honored for the
|
|
|
|
// sidecar registration. We use the test root token since that should have
|
|
|
|
// permission.
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"name": "foo",
|
|
|
|
"token": "root"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
enableACL: true,
|
2023-02-06 15:35:52 +00:00
|
|
|
policies: `
|
2022-06-06 19:13:19 +00:00
|
|
|
service "web-sidecar-proxy" {
|
|
|
|
policy = "write"
|
|
|
|
}
|
|
|
|
service "web" {
|
|
|
|
policy = "write"
|
|
|
|
}`,
|
|
|
|
wantNS: testDefaultSidecar("web", 1111, func(ns *structs.NodeService) {
|
|
|
|
ns.Service = "foo"
|
|
|
|
}),
|
|
|
|
wantErr: "",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid check definition in sidecar",
|
|
|
|
// Note no interval in the UDP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"check": {
|
|
|
|
"UDP": "foo"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "invalid check in sidecar_service",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid checks definitions in sidecar",
|
|
|
|
// Note no interval in the UDP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"checks": [{
|
|
|
|
"UDP": "foo"
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "invalid check in sidecar_service",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid check status in sidecar",
|
|
|
|
// Note no interval in the UDP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"check": {
|
|
|
|
"UDP": "foo",
|
|
|
|
"Interval": 10,
|
|
|
|
"Status": "unsupported-status"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Status for checks must 'passing', 'warning', 'critical'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid checks status in sidecar",
|
|
|
|
// Note no interval in the UDP check should fail validation
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"checks": [{
|
|
|
|
"UDP": "foo",
|
|
|
|
"Interval": 10,
|
|
|
|
"Status": "unsupported-status"
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
wantNS: nil,
|
|
|
|
wantErr: "Status for checks must 'passing', 'warning', 'critical'",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "another service registered with same ID as a sidecar should not be deregistered",
|
|
|
|
// Add another service with the same ID that a sidecar for web would have
|
|
|
|
preRegister: &structs.NodeService{
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "fake-sidecar",
|
|
|
|
Port: 9999,
|
|
|
|
},
|
|
|
|
// Register web with NO SIDECAR
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Note here that although the registration here didn't register it, we
|
|
|
|
// should still see the NodeService we pre-registered here.
|
|
|
|
wantNS: &structs.NodeService{
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "fake-sidecar",
|
|
|
|
Port: 9999,
|
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
|
|
|
},
|
|
|
|
// After we deregister the web service above, the fake sidecar with
|
|
|
|
// clashing ID SHOULD NOT have been removed since it wasn't part of the
|
|
|
|
// original registration.
|
|
|
|
wantSidecarIDLeftAfterDereg: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "updates to sidecar should work",
|
|
|
|
// Add a valid sidecar already registered
|
|
|
|
preRegister: &structs.NodeService{
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "web-sidecar-proxy",
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Port: 9999,
|
|
|
|
},
|
|
|
|
// Register web with Sidecar on different port
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 1111,
|
|
|
|
"connect": {
|
|
|
|
"SidecarService": {
|
|
|
|
"Port": 6666
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Note here that although the registration here didn't register it, we
|
|
|
|
// should still see the NodeService we pre-registered here.
|
|
|
|
wantNS: &structs.NodeService{
|
|
|
|
Kind: "connect-proxy",
|
|
|
|
ID: "web-sidecar-proxy",
|
|
|
|
Service: "web-sidecar-proxy",
|
|
|
|
LocallyRegisteredAsSidecar: true,
|
|
|
|
Port: 6666,
|
|
|
|
TaggedAddresses: map[string]structs.ServiceAddress{},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 1,
|
|
|
|
Warning: 1,
|
|
|
|
},
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "web",
|
|
|
|
DestinationServiceID: "web",
|
|
|
|
LocalServiceAddress: "127.0.0.1",
|
|
|
|
LocalServicePort: 1111,
|
|
|
|
},
|
|
|
|
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "update that removes sidecar should NOT deregister it",
|
|
|
|
// Add web with a valid sidecar already registered
|
|
|
|
preRegister: &structs.NodeService{
|
|
|
|
ID: "web",
|
|
|
|
Service: "web",
|
|
|
|
Port: 1111,
|
|
|
|
},
|
|
|
|
preRegister2: testDefaultSidecar("web", 1111),
|
|
|
|
// Register (update) web and remove sidecar (and port for sanity check)
|
|
|
|
json: `
|
|
|
|
{
|
|
|
|
"name": "web",
|
|
|
|
"port": 2222
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// Sidecar should still be there such that API can update registration
|
|
|
|
// without accidentally removing a sidecar. This is equivalent to embedded
|
|
|
|
// checks which are not removed by just not being included in an update.
|
|
|
|
// We will document that sidecar registrations via API must be explicitiy
|
|
|
|
// deregistered.
|
|
|
|
wantNS: testDefaultSidecar("web", 1111),
|
|
|
|
// Sanity check the rest of the update happened though.
|
|
|
|
assertStateFn: func(t *testing.T, state *local.State) {
|
|
|
|
svc := state.Service(structs.NewServiceID("web", nil))
|
|
|
|
require.NotNil(t, svc)
|
|
|
|
require.Equal(t, 2222, svc.Port)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
|
|
// Constrain auto ports to 1 available to make it deterministic
|
|
|
|
hcl := `ports {
|
|
|
|
sidecar_min_port = 2222
|
|
|
|
sidecar_max_port = 2222
|
|
|
|
}
|
|
|
|
`
|
|
|
|
if tt.enableACL {
|
|
|
|
hcl = hcl + TestACLConfig()
|
|
|
|
}
|
|
|
|
|
|
|
|
a := NewTestAgent(t, hcl+" "+extraHCL)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
if tt.preRegister != nil {
|
|
|
|
require.NoError(t, a.addServiceFromSource(tt.preRegister, nil, false, "", ConfigSourceLocal))
|
|
|
|
}
|
|
|
|
if tt.preRegister2 != nil {
|
|
|
|
require.NoError(t, a.addServiceFromSource(tt.preRegister2, nil, false, "", ConfigSourceLocal))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an ACL token with require policy
|
|
|
|
var token string
|
2023-02-06 15:35:52 +00:00
|
|
|
if tt.enableACL && tt.policies != "" {
|
|
|
|
token = testCreateToken(t, a, tt.policies)
|
2022-06-06 19:13:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
br := bytes.NewBufferString(tt.json)
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", br)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2022-06-06 19:13:19 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if tt.wantErr != "" {
|
|
|
|
require.Contains(t, strings.ToLower(resp.Body.String()), strings.ToLower(tt.wantErr))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.Equal(t, 200, resp.Code, "request failed with body: %s",
|
|
|
|
resp.Body.String())
|
|
|
|
|
|
|
|
// Sanity the target service registration
|
|
|
|
svcs := a.State.AllServices()
|
|
|
|
|
|
|
|
// Parse the expected definition into a ServiceDefinition
|
|
|
|
var sd structs.ServiceDefinition
|
|
|
|
err := json.Unmarshal([]byte(tt.json), &sd)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, sd.Name)
|
|
|
|
|
|
|
|
svcID := sd.ID
|
|
|
|
if svcID == "" {
|
|
|
|
svcID = sd.Name
|
|
|
|
}
|
|
|
|
sid := structs.NewServiceID(svcID, nil)
|
|
|
|
svc, ok := svcs[sid]
|
|
|
|
require.True(t, ok, "has service "+sid.String())
|
|
|
|
assert.Equal(t, sd.Name, svc.Service)
|
|
|
|
assert.Equal(t, sd.Port, svc.Port)
|
|
|
|
// Ensure that the actual registered service _doesn't_ still have it's
|
|
|
|
// sidecar info since it's duplicate and we don't want that synced up to
|
|
|
|
// the catalog or included in responses particularly - it's just
|
|
|
|
// registration syntax sugar.
|
|
|
|
assert.Nil(t, svc.Connect.SidecarService)
|
|
|
|
|
|
|
|
if tt.wantNS == nil {
|
|
|
|
// Sanity check that there was no service registered, we rely on there
|
|
|
|
// being no services at start of test so we can just use the count.
|
|
|
|
assert.Len(t, svcs, 1, "should be no sidecar registered")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure sidecar
|
|
|
|
svc, ok = svcs[structs.NewServiceID(tt.wantNS.ID, nil)]
|
|
|
|
require.True(t, ok, "no sidecar registered at "+tt.wantNS.ID)
|
|
|
|
assert.Equal(t, tt.wantNS, svc)
|
|
|
|
|
|
|
|
if tt.assertStateFn != nil {
|
|
|
|
tt.assertStateFn(t, a.State)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now verify deregistration also removes sidecar (if there was one and it
|
|
|
|
// was added via sidecar not just coincidental ID clash)
|
|
|
|
{
|
|
|
|
req := httptest.NewRequest("PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
"/v1/agent/service/deregister/"+svcID, nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2022-06-06 19:13:19 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
|
|
|
|
svcs := a.State.AllServices()
|
|
|
|
_, ok = svcs[structs.NewServiceID(tt.wantNS.ID, nil)]
|
|
|
|
if tt.wantSidecarIDLeftAfterDereg {
|
|
|
|
require.True(t, ok, "removed non-sidecar service at "+tt.wantNS.ID)
|
|
|
|
} else {
|
|
|
|
require.False(t, ok, "sidecar not deregistered with service "+svcID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// END HERE
|
|
|
|
|
2018-03-12 20:05:06 +00:00
|
|
|
// This tests that connect proxy validation is done for local agent
|
|
|
|
// registration. This doesn't need to test validation exhaustively since
|
|
|
|
// that is done via a table test in the structs package.
|
2018-04-17 12:29:02 +00:00
|
|
|
func TestAgent_RegisterService_UnmanagedConnectProxyInvalid(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_UnmanagedConnectProxyInvalid(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_UnmanagedConnectProxyInvalid(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_UnmanagedConnectProxyInvalid(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
2018-03-11 01:42:30 +00:00
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2018-03-11 01:42:30 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-11 01:42:30 +00:00
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
2018-09-12 16:07:47 +00:00
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
Name: "connect-proxy",
|
|
|
|
Proxy: &structs.ConnectProxyConfig{
|
|
|
|
DestinationServiceName: "db",
|
|
|
|
},
|
2018-03-11 01:42:30 +00:00
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2018-03-11 01:42:30 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.Code)
|
|
|
|
assert.Contains(t, resp.Body.String(), "Port")
|
2018-03-11 01:42:30 +00:00
|
|
|
|
|
|
|
// Ensure the service doesn't exist
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Nil(t, a.State.Service(structs.NewServiceID("connect-proxy", nil)))
|
2018-03-11 01:42:30 +00:00
|
|
|
}
|
|
|
|
|
2018-06-04 05:20:16 +00:00
|
|
|
// Tests agent registration of a service that is connect native.
|
|
|
|
func TestAgent_RegisterService_ConnectNative(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_ConnectNative(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ConnectNative(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_ConnectNative(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
2018-06-04 05:20:16 +00:00
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2018-06-04 05:20:16 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-06-04 05:20:16 +00:00
|
|
|
|
|
|
|
// Register a proxy. Note that the destination doesn't exist here on
|
|
|
|
// this agent or in the catalog at all. This is intended and part
|
|
|
|
// of the design.
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "web",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
2018-06-05 17:51:05 +00:00
|
|
|
Connect: &structs.ServiceConnect{
|
2018-06-04 05:20:16 +00:00
|
|
|
Native: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, http.StatusOK, resp.Code)
|
2018-06-04 05:20:16 +00:00
|
|
|
|
|
|
|
// Ensure the service
|
2019-12-10 02:26:41 +00:00
|
|
|
svc := a.State.Service(structs.NewServiceID("web", nil))
|
|
|
|
require.NotNil(t, svc)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, svc.Connect.Native)
|
2018-06-04 05:20:16 +00:00
|
|
|
}
|
|
|
|
|
2018-10-11 12:22:11 +00:00
|
|
|
func TestAgent_RegisterService_ScriptCheck_ExecDisable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_ScriptCheck_ExecDisable(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ScriptCheck_ExecDisable(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_ScriptCheck_ExecDisable(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, extraHCL)
|
2018-10-11 12:22:11 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2018-10-11 12:22:11 +00:00
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
Name: "test-check",
|
|
|
|
Interval: time.Second,
|
|
|
|
ScriptArgs: []string{"true"},
|
|
|
|
},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusInternalServerError != resp.Code {
|
|
|
|
t.Fatalf("expected 500 but got %v", resp.Code)
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if !strings.Contains(resp.Body.String(), "Scripts are disabled on this agent") {
|
|
|
|
t.Fatalf("expected script disabled error, got: %s", resp.Body.String())
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
|
|
|
checkID := types.CheckID("test-check")
|
2019-12-10 02:26:41 +00:00
|
|
|
require.Nil(t, a.State.Check(structs.NewCheckID(checkID, nil)), "check registered with exec disabled")
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_RegisterService_ScriptCheck_ExecRemoteDisable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-24 15:04:48 +00:00
|
|
|
t.Run("normal", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
2020-10-01 14:19:14 +00:00
|
|
|
testAgent_RegisterService_ScriptCheck_ExecRemoteDisable(t, "enable_central_service_config = false")
|
2019-09-24 15:04:48 +00:00
|
|
|
})
|
|
|
|
t.Run("service manager", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
testAgent_RegisterService_ScriptCheck_ExecRemoteDisable(t, "enable_central_service_config = true")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func testAgent_RegisterService_ScriptCheck_ExecRemoteDisable(t *testing.T, extraHCL string) {
|
|
|
|
t.Helper()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2018-10-11 12:22:11 +00:00
|
|
|
enable_local_script_checks = true
|
2019-09-24 15:04:48 +00:00
|
|
|
`+extraHCL)
|
2018-10-11 12:22:11 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "test",
|
|
|
|
Meta: map[string]string{"hello": "world"},
|
2022-01-20 12:47:50 +00:00
|
|
|
Tags: []string{"primary"},
|
2018-10-11 12:22:11 +00:00
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
Name: "test-check",
|
|
|
|
Interval: time.Second,
|
|
|
|
ScriptArgs: []string{"true"},
|
|
|
|
},
|
|
|
|
Weights: &structs.Weights{
|
|
|
|
Passing: 100,
|
|
|
|
Warning: 3,
|
|
|
|
},
|
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "abc123")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusInternalServerError != resp.Code {
|
|
|
|
t.Fatalf("expected 500 but got %v", resp.Code)
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
if !strings.Contains(resp.Body.String(), "Scripts are disabled on this agent") {
|
|
|
|
t.Fatalf("expected script disabled error, got: %s", resp.Body.String())
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
|
|
|
checkID := types.CheckID("test-check")
|
2019-12-10 02:26:41 +00:00
|
|
|
require.Nil(t, a.State.Check(structs.NewCheckID(checkID, nil)), "check registered with exec disabled")
|
2018-10-11 12:22:11 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_DeregisterService(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2014-01-30 23:56:03 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
|
|
|
},
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2014-01-30 23:56:03 +00:00
|
|
|
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/deregister/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusOK != resp.Code {
|
|
|
|
t.Fatalf("expected 200 but got %v", resp.Code)
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
assert.Nil(t, a.State.Service(structs.NewServiceID("test", nil)), "have test service")
|
|
|
|
assert.Nil(t, a.State.Check(structs.NewCheckID("test", nil)), "have test check")
|
2014-01-30 23:56:03 +00:00
|
|
|
}
|
2015-01-15 09:17:35 +00:00
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_DeregisterService_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
|
|
|
},
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/deregister/test", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/deregister/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_ServiceMaintenance_BadRequest(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-15 09:17:35 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("not enabled", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2017-05-09 17:46:11 +00:00
|
|
|
if resp.Code != 400 {
|
|
|
|
t.Fatalf("expected 400, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
})
|
2015-01-15 09:17:35 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no service id", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/?enable=true", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2017-05-09 17:46:11 +00:00
|
|
|
if resp.Code != 400 {
|
|
|
|
t.Fatalf("expected 400, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
})
|
2015-01-15 18:51:00 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("bad service id", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/_nope_?enable=true", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-07-15 21:17:49 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, 404, resp.Code)
|
2022-01-05 20:18:08 +00:00
|
|
|
sid := structs.NewServiceID("_nope_", nil)
|
|
|
|
require.Contains(t, resp.Body.String(), fmt.Sprintf(`Unknown service ID %q`, sid))
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2015-01-15 09:17:35 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_ServiceMaintenance_Enable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-15 09:17:35 +00:00
|
|
|
|
|
|
|
// Register the service
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
|
|
|
},
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
2015-01-15 09:17:35 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2015-01-15 09:17:35 +00:00
|
|
|
|
2015-01-15 18:51:00 +00:00
|
|
|
// Force the service into maintenance mode
|
2015-09-10 19:08:08 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/test?enable=true&reason=broken&token=mytoken", nil)
|
2015-01-15 09:17:35 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2015-01-15 09:17:35 +00:00
|
|
|
if resp.Code != 200 {
|
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the maintenance check was registered
|
2019-12-10 02:26:41 +00:00
|
|
|
checkID := serviceMaintCheckID(structs.NewServiceID("test", nil))
|
|
|
|
check := a.State.Check(checkID)
|
|
|
|
if check == nil {
|
2015-01-15 09:17:35 +00:00
|
|
|
t.Fatalf("should have registered maintenance check")
|
|
|
|
}
|
2015-01-21 20:21:57 +00:00
|
|
|
|
2015-09-10 19:08:08 +00:00
|
|
|
// Ensure the token was added
|
2017-08-28 12:17:13 +00:00
|
|
|
if token := a.State.CheckToken(checkID); token != "mytoken" {
|
2015-09-10 19:08:08 +00:00
|
|
|
t.Fatalf("expected 'mytoken', got '%s'", token)
|
|
|
|
}
|
|
|
|
|
2015-01-21 20:21:57 +00:00
|
|
|
// Ensure the reason was set in notes
|
|
|
|
if check.Notes != "broken" {
|
|
|
|
t.Fatalf("bad: %#v", check)
|
|
|
|
}
|
2015-01-15 09:17:35 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_ServiceMaintenance_Disable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-15 09:17:35 +00:00
|
|
|
|
|
|
|
// Register the service
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
|
|
|
},
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
2015-01-15 09:17:35 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2015-01-15 09:17:35 +00:00
|
|
|
|
|
|
|
// Force the service into maintenance mode
|
2019-12-10 02:26:41 +00:00
|
|
|
if err := a.EnableServiceMaintenance(structs.NewServiceID("test", nil), "", ""); err != nil {
|
2015-01-15 09:17:35 +00:00
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Leave maintenance mode
|
2015-01-15 18:51:00 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/test?enable=false", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2015-01-15 09:17:35 +00:00
|
|
|
if resp.Code != 200 {
|
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
|
|
|
}
|
2015-01-15 18:51:00 +00:00
|
|
|
|
|
|
|
// Ensure the maintenance check was removed
|
2019-12-10 02:26:41 +00:00
|
|
|
checkID := serviceMaintCheckID(structs.NewServiceID("test", nil))
|
|
|
|
if existing := a.State.Check(checkID); existing != nil {
|
2015-01-15 18:51:00 +00:00
|
|
|
t.Fatalf("should have removed maintenance check")
|
|
|
|
}
|
2015-01-15 09:17:35 +00:00
|
|
|
}
|
2015-01-15 19:26:14 +00:00
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_ServiceMaintenance_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
|
|
|
// Register the service.
|
2021-12-07 14:44:03 +00:00
|
|
|
serviceReq := AddServiceRequest{
|
|
|
|
Service: &structs.NodeService{
|
|
|
|
ID: "test",
|
|
|
|
Service: "test",
|
|
|
|
},
|
|
|
|
chkTypes: nil,
|
|
|
|
persist: false,
|
|
|
|
token: "",
|
|
|
|
Source: ConfigSourceLocal,
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
require.NoError(t, a.AddService(serviceReq))
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/test?enable=true&reason=broken", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/maintenance/test?enable=true&reason=broken&token=root", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_NodeMaintenance_BadRequest(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-15 19:26:14 +00:00
|
|
|
|
|
|
|
// Fails when no enable flag provided
|
2021-10-26 19:20:57 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance", nil)
|
2017-09-26 06:11:19 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2015-01-15 19:26:14 +00:00
|
|
|
if resp.Code != 400 {
|
|
|
|
t.Fatalf("expected 400, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_NodeMaintenance_Enable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-15 19:26:14 +00:00
|
|
|
|
|
|
|
// Force the node into maintenance mode
|
2021-10-26 19:20:57 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=true&reason=broken&token=mytoken", nil)
|
2015-01-15 19:26:14 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2015-01-15 19:26:14 +00:00
|
|
|
if resp.Code != 200 {
|
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the maintenance check was registered
|
2019-12-10 02:26:41 +00:00
|
|
|
check := a.State.Check(structs.NodeMaintCheckID)
|
|
|
|
if check == nil {
|
2015-01-15 19:26:14 +00:00
|
|
|
t.Fatalf("should have registered maintenance check")
|
|
|
|
}
|
2015-01-21 20:21:57 +00:00
|
|
|
|
2015-09-10 19:08:08 +00:00
|
|
|
// Check that the token was used
|
2019-12-10 02:26:41 +00:00
|
|
|
if token := a.State.CheckToken(structs.NodeMaintCheckID); token != "mytoken" {
|
2015-09-10 19:08:08 +00:00
|
|
|
t.Fatalf("expected 'mytoken', got '%s'", token)
|
|
|
|
}
|
|
|
|
|
2015-01-21 20:21:57 +00:00
|
|
|
// Ensure the reason was set in notes
|
|
|
|
if check.Notes != "broken" {
|
|
|
|
t.Fatalf("bad: %#v", check)
|
|
|
|
}
|
2015-01-15 19:26:14 +00:00
|
|
|
}
|
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_NodeMaintenance_Disable(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-15 19:26:14 +00:00
|
|
|
|
|
|
|
// Force the node into maintenance mode
|
2017-05-21 07:11:09 +00:00
|
|
|
a.EnableNodeMaintenance("", "")
|
2015-01-15 19:26:14 +00:00
|
|
|
|
|
|
|
// Leave maintenance mode
|
2021-10-26 19:20:57 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=false", nil)
|
2015-01-15 19:26:14 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2015-01-15 19:26:14 +00:00
|
|
|
if resp.Code != 200 {
|
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the maintenance check was removed
|
2019-12-10 02:26:41 +00:00
|
|
|
if existing := a.State.Check(structs.NodeMaintCheckID); existing != nil {
|
2015-01-15 19:26:14 +00:00
|
|
|
t.Fatalf("should have removed maintenance check")
|
|
|
|
}
|
|
|
|
}
|
2015-01-14 01:52:17 +00:00
|
|
|
|
2016-12-14 22:16:46 +00:00
|
|
|
func TestAgent_NodeMaintenance_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("no token", func(t *testing.T) {
|
2021-10-26 19:20:57 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=true&reason=broken", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
|
2017-05-09 17:46:11 +00:00
|
|
|
t.Run("root token", func(t *testing.T) {
|
2021-10-26 19:20:57 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/maintenance?enable=true&reason=broken&token=root", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2017-05-09 17:46:11 +00:00
|
|
|
})
|
2016-12-14 22:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_RegisterCheck_Service(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2015-01-14 01:52:17 +00:00
|
|
|
|
2017-06-15 16:46:06 +00:00
|
|
|
args := &structs.ServiceDefinition{
|
2015-01-14 01:52:17 +00:00
|
|
|
Name: "memcache",
|
|
|
|
Port: 8000,
|
2017-06-15 16:46:06 +00:00
|
|
|
Check: structs.CheckType{
|
2015-01-14 01:52:17 +00:00
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2017-05-09 16:58:12 +00:00
|
|
|
// First register the service
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != 200 {
|
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
2015-01-14 01:52:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now register an additional check
|
2017-06-15 16:46:06 +00:00
|
|
|
checkArgs := &structs.CheckDefinition{
|
2015-01-14 01:52:17 +00:00
|
|
|
Name: "memcache_check2",
|
|
|
|
ServiceID: "memcache",
|
2017-05-15 19:49:13 +00:00
|
|
|
TTL: 15 * time.Second,
|
2015-01-14 01:52:17 +00:00
|
|
|
}
|
2017-09-26 06:11:19 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/agent/check/register", jsonReader(checkArgs))
|
2021-12-07 14:44:03 +00:00
|
|
|
resp = httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != 200 {
|
|
|
|
t.Fatalf("expected 200, got %d", resp.Code)
|
2015-01-14 01:52:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure we have a check mapping
|
2019-12-10 02:26:41 +00:00
|
|
|
result := a.State.Checks(nil)
|
|
|
|
if _, ok := result[structs.NewCheckID("service:memcache", nil)]; !ok {
|
2015-01-14 01:52:17 +00:00
|
|
|
t.Fatalf("missing memcached check")
|
|
|
|
}
|
2019-12-10 02:26:41 +00:00
|
|
|
if _, ok := result[structs.NewCheckID("memcache_check2", nil)]; !ok {
|
2015-01-14 01:52:17 +00:00
|
|
|
t.Fatalf("missing memcache_check2 check")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the new check is associated with the service
|
2019-12-10 02:26:41 +00:00
|
|
|
if result[structs.NewCheckID("memcache_check2", nil)].ServiceID != "memcache" {
|
|
|
|
t.Fatalf("bad: %#v", result[structs.NewCheckID("memcached_check2", nil)])
|
2015-01-14 01:52:17 +00:00
|
|
|
}
|
2019-10-17 18:33:11 +00:00
|
|
|
|
|
|
|
// Make sure the new check has the right type
|
2019-12-10 02:26:41 +00:00
|
|
|
if result[structs.NewCheckID("memcache_check2", nil)].Type != "ttl" {
|
|
|
|
t.Fatalf("expected TTL type, got %s", result[structs.NewCheckID("memcache_check2", nil)].Type)
|
2019-10-17 18:33:11 +00:00
|
|
|
}
|
2015-01-14 01:52:17 +00:00
|
|
|
}
|
2016-11-16 21:45:26 +00:00
|
|
|
|
2016-12-14 17:33:57 +00:00
|
|
|
func TestAgent_Monitor(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2016-11-16 21:45:26 +00:00
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
t.Run("unknown log level", func(t *testing.T) {
|
|
|
|
// Try passing an invalid log level
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/monitor?loglevel=invalid", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusBadRequest != resp.Code {
|
|
|
|
t.Fatalf("expected 400 but got %v", resp.Code)
|
2020-01-28 23:50:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
substring := "Unknown log level"
|
2021-12-07 14:44:03 +00:00
|
|
|
if !strings.Contains(resp.Body.String(), substring) {
|
|
|
|
t.Fatalf("got: %s, wanted message containing: %s", resp.Body.String(), substring)
|
2020-01-28 23:50:41 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("stream unstructured logs", func(t *testing.T) {
|
|
|
|
// Try to stream logs until we see the expected log line
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/monitor?loglevel=debug", nil)
|
|
|
|
cancelCtx, cancelFunc := context.WithCancel(context.Background())
|
|
|
|
req = req.WithContext(cancelCtx)
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
codeCh := make(chan int)
|
2020-01-28 23:50:41 +00:00
|
|
|
go func() {
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
codeCh <- resp.Code
|
2020-01-28 23:50:41 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "monitor",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
2016-11-16 21:45:26 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
registerReq, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
res := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(res, registerReq)
|
|
|
|
if http.StatusOK != res.Code {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("expected 200 but got %v", res.Code)
|
2020-01-28 23:50:41 +00:00
|
|
|
}
|
2016-12-15 02:13:30 +00:00
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
// Wait until we have received some type of logging output
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Eventually(r, func() bool {
|
2020-01-28 23:50:41 +00:00
|
|
|
return len(resp.Body.Bytes()) > 0
|
|
|
|
}, 3*time.Second, 100*time.Millisecond)
|
|
|
|
|
|
|
|
cancelFunc()
|
2021-12-07 14:44:03 +00:00
|
|
|
code := <-codeCh
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusOK, code)
|
2020-01-28 23:50:41 +00:00
|
|
|
got := resp.Body.String()
|
|
|
|
|
|
|
|
// Only check a substring that we are highly confident in finding
|
|
|
|
want := "Synced service: service="
|
|
|
|
if !strings.Contains(got, want) {
|
|
|
|
r.Fatalf("got %q and did not find %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
2017-04-29 16:34:02 +00:00
|
|
|
})
|
2016-11-16 21:45:26 +00:00
|
|
|
|
2020-06-08 08:10:08 +00:00
|
|
|
t.Run("stream compressed unstructured logs", func(t *testing.T) {
|
|
|
|
// The only purpose of this test is to see something being
|
|
|
|
// logged. Because /v1/agent/monitor is streaming the response
|
|
|
|
// it needs special handling with the compression.
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/monitor?loglevel=debug", nil)
|
|
|
|
// Usually this would be automatically set by transport content
|
|
|
|
// negotiation, but since this call doesn't go through a real
|
|
|
|
// transport, the header has to be set manually
|
|
|
|
req.Header["Accept-Encoding"] = []string{"gzip"}
|
|
|
|
cancelCtx, cancelFunc := context.WithCancel(context.Background())
|
|
|
|
req = req.WithContext(cancelCtx)
|
|
|
|
|
2023-06-30 13:10:20 +00:00
|
|
|
a.enableDebug.Store(true)
|
|
|
|
|
2020-06-08 08:10:08 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2023-06-30 13:10:20 +00:00
|
|
|
handler := a.srv.handler()
|
2020-07-02 20:47:54 +00:00
|
|
|
go handler.ServeHTTP(resp, req)
|
2020-06-08 08:10:08 +00:00
|
|
|
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "monitor",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
registerReq, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
res := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(res, registerReq)
|
|
|
|
if http.StatusOK != res.Code {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("expected 200 but got %v", res.Code)
|
2020-06-08 08:10:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait until we have received some type of logging output
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Eventually(r, func() bool {
|
2020-06-08 08:10:08 +00:00
|
|
|
return len(resp.Body.Bytes()) > 0
|
|
|
|
}, 3*time.Second, 100*time.Millisecond)
|
|
|
|
cancelFunc()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
t.Run("stream JSON logs", func(t *testing.T) {
|
|
|
|
// Try to stream logs until we see the expected log line
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/monitor?loglevel=debug&logjson", nil)
|
|
|
|
cancelCtx, cancelFunc := context.WithCancel(context.Background())
|
|
|
|
req = req.WithContext(cancelCtx)
|
2016-11-16 21:45:26 +00:00
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
codeCh := make(chan int)
|
2020-01-28 23:50:41 +00:00
|
|
|
go func() {
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
codeCh <- resp.Code
|
2020-01-28 23:50:41 +00:00
|
|
|
}()
|
2016-11-16 21:45:26 +00:00
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
Name: "monitor",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
registerReq, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
2021-12-07 14:44:03 +00:00
|
|
|
res := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(res, registerReq)
|
|
|
|
if http.StatusOK != res.Code {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("expected 200 but got %v", res.Code)
|
2020-01-28 23:50:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Wait until we have received some type of logging output
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Eventually(r, func() bool {
|
2020-01-28 23:50:41 +00:00
|
|
|
return len(resp.Body.Bytes()) > 0
|
|
|
|
}, 3*time.Second, 100*time.Millisecond)
|
|
|
|
|
|
|
|
cancelFunc()
|
2021-12-07 14:44:03 +00:00
|
|
|
code := <-codeCh
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusOK, code)
|
2016-12-15 02:13:30 +00:00
|
|
|
|
2020-01-28 23:50:41 +00:00
|
|
|
// Each line is output as a separate JSON object, we grab the first and
|
|
|
|
// make sure it can be unmarshalled.
|
|
|
|
firstLine := bytes.Split(resp.Body.Bytes(), []byte("\n"))[0]
|
|
|
|
var output map[string]interface{}
|
|
|
|
if err := json.Unmarshal(firstLine, &output); err != nil {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("err: %v", err)
|
2020-01-28 23:50:41 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
// hopefully catch any potential regression in serf/memberlist logging setup.
|
|
|
|
t.Run("serf shutdown logging", func(t *testing.T) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/monitor?loglevel=debug", nil)
|
|
|
|
cancelCtx, cancelFunc := context.WithCancel(context.Background())
|
|
|
|
req = req.WithContext(cancelCtx)
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
codeCh := make(chan int)
|
2020-08-13 21:48:46 +00:00
|
|
|
chStarted := make(chan struct{})
|
2020-01-28 23:50:41 +00:00
|
|
|
go func() {
|
2020-08-13 21:48:46 +00:00
|
|
|
close(chStarted)
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
codeCh <- resp.Code
|
2020-01-28 23:50:41 +00:00
|
|
|
}()
|
|
|
|
|
2020-08-13 21:48:46 +00:00
|
|
|
<-chStarted
|
2020-01-28 23:50:41 +00:00
|
|
|
require.NoError(t, a.Shutdown())
|
|
|
|
|
|
|
|
// Wait until we have received some type of logging output
|
|
|
|
require.Eventually(t, func() bool {
|
|
|
|
return len(resp.Body.Bytes()) > 0
|
|
|
|
}, 3*time.Second, 100*time.Millisecond)
|
|
|
|
|
|
|
|
cancelFunc()
|
2021-12-07 14:44:03 +00:00
|
|
|
code := <-codeCh
|
|
|
|
require.Equal(t, http.StatusOK, code)
|
2020-01-28 23:50:41 +00:00
|
|
|
|
|
|
|
got := resp.Body.String()
|
|
|
|
want := "serf: Shutdown without a Leave"
|
|
|
|
if !strings.Contains(got, want) {
|
|
|
|
t.Fatalf("got %q and did not find %q", got, want)
|
|
|
|
}
|
|
|
|
})
|
2016-11-16 21:45:26 +00:00
|
|
|
}
|
2016-12-14 17:33:57 +00:00
|
|
|
|
|
|
|
func TestAgent_Monitor_ACLDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-05-21 07:54:40 +00:00
|
|
|
t.Parallel()
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2017-05-21 07:11:09 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2016-12-14 17:33:57 +00:00
|
|
|
|
|
|
|
// Try without a token.
|
2017-05-09 11:38:05 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/monitor", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusForbidden != resp.Code {
|
|
|
|
t.Fatalf("expected 403 but got %v", resp.Code)
|
2016-12-14 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This proves we call the ACL function, and we've got the other monitor
|
|
|
|
// test to prove monitor works, which should be sufficient. The monitor
|
|
|
|
// logic is a little complex to set up so isn't worth repeating again
|
|
|
|
// here.
|
|
|
|
}
|
2017-07-26 18:03:43 +00:00
|
|
|
|
2019-10-04 18:37:34 +00:00
|
|
|
func TestAgent_TokenTriggersFullSync(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-10-04 18:37:34 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
body := func(token string) io.Reader {
|
|
|
|
return jsonReader(&api.AgentToken{Token: token})
|
|
|
|
}
|
|
|
|
|
|
|
|
createNodePolicy := func(t *testing.T, a *TestAgent, policyName string) *structs.ACLPolicy {
|
|
|
|
policy := &structs.ACLPolicy{
|
|
|
|
Name: policyName,
|
|
|
|
Rules: `node_prefix "" { policy = "write" }`,
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, err := http.NewRequest("PUT", "/v1/acl/policy", jsonBody(policy))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-10-04 18:37:34 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-10-04 18:37:34 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
policy = &structs.ACLPolicy{}
|
|
|
|
require.NoError(t, dec.Decode(policy))
|
2019-10-04 18:37:34 +00:00
|
|
|
return policy
|
|
|
|
}
|
|
|
|
|
|
|
|
createNodeToken := func(t *testing.T, a *TestAgent, policyName string) *structs.ACLToken {
|
|
|
|
createNodePolicy(t, a, policyName)
|
|
|
|
|
|
|
|
token := &structs.ACLToken{
|
|
|
|
Description: "test",
|
|
|
|
Policies: []structs.ACLTokenPolicyLink{
|
2020-06-16 17:19:31 +00:00
|
|
|
{Name: policyName},
|
2019-10-04 18:37:34 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, err := http.NewRequest("PUT", "/v1/acl/token", jsonBody(token))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-10-04 18:37:34 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
2019-10-04 18:37:34 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
token = &structs.ACLToken{}
|
|
|
|
require.NoError(t, dec.Decode(token))
|
2019-10-04 18:37:34 +00:00
|
|
|
return token
|
|
|
|
}
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
path string
|
|
|
|
tokenGetFn func(*token.Store) string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
path: "acl_agent_token",
|
|
|
|
tokenGetFn: (*token.Store).AgentToken,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "agent",
|
|
|
|
tokenGetFn: (*token.Store).AgentToken,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "acl_token",
|
|
|
|
tokenGetFn: (*token.Store).UserToken,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
path: "default",
|
|
|
|
tokenGetFn: (*token.Store).UserToken,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.path, func(t *testing.T) {
|
2023-01-24 16:21:41 +00:00
|
|
|
url := fmt.Sprintf("/v1/agent/token/%s", tt.path)
|
2019-10-04 18:37:34 +00:00
|
|
|
|
2021-12-07 12:48:50 +00:00
|
|
|
a := NewTestAgent(t, `
|
|
|
|
primary_datacenter = "dc1"
|
|
|
|
|
2019-10-04 18:37:34 +00:00
|
|
|
acl {
|
2021-12-07 12:48:50 +00:00
|
|
|
enabled = true
|
|
|
|
default_policy = "deny"
|
|
|
|
|
2019-10-04 18:37:34 +00:00
|
|
|
tokens {
|
2021-12-07 12:48:50 +00:00
|
|
|
initial_management = "root"
|
2019-10-04 18:37:34 +00:00
|
|
|
default = ""
|
|
|
|
agent = ""
|
2022-01-20 12:47:50 +00:00
|
|
|
agent_recovery = ""
|
2019-10-04 18:37:34 +00:00
|
|
|
replication = ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
|
|
|
|
// create node policy and token
|
|
|
|
token := createNodeToken(t, a, "test")
|
|
|
|
|
|
|
|
req, err := http.NewRequest("PUT", url, body(token.SecretID))
|
2023-01-24 16:21:41 +00:00
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2019-10-04 18:37:34 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
resp := httptest.NewRecorder()
|
2021-11-03 15:12:36 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2019-10-04 18:37:34 +00:00
|
|
|
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
require.Equal(t, token.SecretID, tt.tokenGetFn(a.tokens))
|
|
|
|
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1",
|
|
|
|
testrpc.WithToken("root"),
|
|
|
|
testrpc.WaitForAntiEntropySync())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-26 18:03:43 +00:00
|
|
|
func TestAgent_Token(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2017-07-26 18:03:43 +00:00
|
|
|
t.Parallel()
|
2017-11-28 21:47:30 +00:00
|
|
|
|
|
|
|
// The behavior of this handler when ACLs are disabled is vetted over
|
|
|
|
// in TestACL_Disabled_Response since there's already good infra set
|
|
|
|
// up over there to test this, and it calls the common function.
|
2021-12-07 12:48:50 +00:00
|
|
|
a := NewTestAgent(t, `
|
|
|
|
primary_datacenter = "dc1"
|
|
|
|
|
2019-02-27 19:28:31 +00:00
|
|
|
acl {
|
2021-12-07 12:48:50 +00:00
|
|
|
enabled = true
|
|
|
|
default_policy = "deny"
|
|
|
|
|
2019-02-27 19:28:31 +00:00
|
|
|
tokens {
|
2021-12-07 12:48:50 +00:00
|
|
|
initial_management = "root"
|
2019-02-27 19:28:31 +00:00
|
|
|
default = ""
|
|
|
|
agent = ""
|
2022-01-20 12:47:50 +00:00
|
|
|
agent_recovery = ""
|
2019-02-27 19:28:31 +00:00
|
|
|
replication = ""
|
2023-01-10 16:24:02 +00:00
|
|
|
config_file_service_registration = ""
|
2019-02-27 19:28:31 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-25 18:40:42 +00:00
|
|
|
`)
|
2017-07-26 18:03:43 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2017-07-26 18:03:43 +00:00
|
|
|
|
2017-08-03 22:39:31 +00:00
|
|
|
type tokens struct {
|
2022-01-20 12:47:50 +00:00
|
|
|
user string
|
|
|
|
userSource tokenStore.TokenSource
|
|
|
|
agent string
|
|
|
|
agentSource tokenStore.TokenSource
|
|
|
|
agentRecovery string
|
|
|
|
agentRecoverySource tokenStore.TokenSource
|
|
|
|
repl string
|
|
|
|
replSource tokenStore.TokenSource
|
2023-01-10 16:24:02 +00:00
|
|
|
registration string
|
|
|
|
registrationSource tokenStore.TokenSource
|
2017-08-03 22:39:31 +00:00
|
|
|
}
|
|
|
|
|
2019-02-27 19:28:31 +00:00
|
|
|
resetTokens := func(init tokens) {
|
|
|
|
a.tokens.UpdateUserToken(init.user, init.userSource)
|
|
|
|
a.tokens.UpdateAgentToken(init.agent, init.agentSource)
|
2022-01-20 12:47:50 +00:00
|
|
|
a.tokens.UpdateAgentRecoveryToken(init.agentRecovery, init.agentRecoverySource)
|
2019-02-27 19:28:31 +00:00
|
|
|
a.tokens.UpdateReplicationToken(init.repl, init.replSource)
|
2023-01-10 16:24:02 +00:00
|
|
|
a.tokens.UpdateConfigFileRegistrationToken(init.registration, init.registrationSource)
|
2017-08-03 22:39:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
body := func(token string) io.Reader {
|
2017-07-26 18:03:43 +00:00
|
|
|
return jsonReader(&api.AgentToken{Token: token})
|
|
|
|
}
|
|
|
|
|
|
|
|
badJSON := func() io.Reader {
|
|
|
|
return jsonReader(false)
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
method, url string
|
|
|
|
body io.Reader
|
|
|
|
code int
|
2019-02-27 19:28:31 +00:00
|
|
|
init tokens
|
|
|
|
raw tokens
|
|
|
|
effective tokens
|
2021-10-26 19:20:57 +00:00
|
|
|
expectedErr string
|
2017-07-26 18:03:43 +00:00
|
|
|
}{
|
2017-08-03 22:39:31 +00:00
|
|
|
{
|
2020-08-17 23:30:25 +00:00
|
|
|
name: "bad token name",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "nope",
|
2020-08-17 23:30:25 +00:00
|
|
|
body: body("X"),
|
2021-11-03 15:12:36 +00:00
|
|
|
code: http.StatusNotFound,
|
2021-10-26 19:20:57 +00:00
|
|
|
expectedErr: `Token "nope" is unknown`,
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2021-10-26 19:20:57 +00:00
|
|
|
name: "bad JSON",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_token",
|
2021-10-26 19:20:57 +00:00
|
|
|
body: badJSON(),
|
2021-11-03 15:12:36 +00:00
|
|
|
code: http.StatusBadRequest,
|
2022-04-29 17:42:49 +00:00
|
|
|
expectedErr: `Request decode failed: json: cannot unmarshal bool into Go value of type api.AgentToken`,
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "set user legacy",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_token",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("U"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
raw: tokens{user: "U", userSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{user: "U", agent: "U"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "set default",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "default",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("U"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
raw: tokens{user: "U", userSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{user: "U", agent: "U"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "set agent legacy",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_agent_token",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("A"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
init: tokens{user: "U", agent: "U"},
|
|
|
|
raw: tokens{user: "U", agent: "A", agentSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{user: "U", agent: "A"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "set agent",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "agent",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("A"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
init: tokens{user: "U", agent: "U"},
|
|
|
|
raw: tokens{user: "U", agent: "A", agentSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{user: "U", agent: "A"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "set master legacy",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_agent_master_token",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("M"),
|
|
|
|
code: http.StatusOK,
|
2022-01-20 12:47:50 +00:00
|
|
|
raw: tokens{agentRecovery: "M", agentRecoverySource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{agentRecovery: "M"},
|
2019-02-27 19:28:31 +00:00
|
|
|
},
|
|
|
|
{
|
2021-12-02 17:05:27 +00:00
|
|
|
name: "set master",
|
2019-02-27 19:28:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "agent_master",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("M"),
|
|
|
|
code: http.StatusOK,
|
2022-01-20 12:47:50 +00:00
|
|
|
raw: tokens{agentRecovery: "M", agentRecoverySource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{agentRecovery: "M"},
|
2019-02-27 19:28:31 +00:00
|
|
|
},
|
2021-12-02 17:05:27 +00:00
|
|
|
{
|
|
|
|
name: "set recovery",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "agent_recovery",
|
2021-12-02 17:05:27 +00:00
|
|
|
body: body("R"),
|
|
|
|
code: http.StatusOK,
|
2022-01-20 12:47:50 +00:00
|
|
|
raw: tokens{agentRecovery: "R", agentRecoverySource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{agentRecovery: "R", agentRecoverySource: tokenStore.TokenSourceAPI},
|
2021-12-02 17:05:27 +00:00
|
|
|
},
|
2019-02-27 19:28:31 +00:00
|
|
|
{
|
|
|
|
name: "set repl legacy",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_replication_token",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("R"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
raw: tokens{repl: "R", replSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{repl: "R"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "set repl",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "replication",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body("R"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
raw: tokens{repl: "R", replSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{repl: "R"},
|
|
|
|
},
|
2023-01-10 16:24:02 +00:00
|
|
|
{
|
|
|
|
name: "set registration",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "config_file_service_registration",
|
2023-01-10 16:24:02 +00:00
|
|
|
body: body("G"),
|
|
|
|
code: http.StatusOK,
|
|
|
|
raw: tokens{registration: "G", registrationSource: tokenStore.TokenSourceAPI},
|
|
|
|
effective: tokens{registration: "G"},
|
|
|
|
},
|
2019-02-27 19:28:31 +00:00
|
|
|
{
|
|
|
|
name: "clear user legacy",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_token",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body(""),
|
2017-08-03 22:39:31 +00:00
|
|
|
code: http.StatusOK,
|
2019-02-27 19:28:31 +00:00
|
|
|
init: tokens{user: "U"},
|
|
|
|
raw: tokens{userSource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "clear default",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "default",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body(""),
|
2017-08-03 22:39:31 +00:00
|
|
|
code: http.StatusOK,
|
2019-02-27 19:28:31 +00:00
|
|
|
init: tokens{user: "U"},
|
|
|
|
raw: tokens{userSource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "clear agent legacy",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_agent_token",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body(""),
|
2017-08-03 22:39:31 +00:00
|
|
|
code: http.StatusOK,
|
2019-02-27 19:28:31 +00:00
|
|
|
init: tokens{agent: "A"},
|
|
|
|
raw: tokens{agentSource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "clear agent",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "agent",
|
2019-02-27 19:28:31 +00:00
|
|
|
body: body(""),
|
2017-08-03 22:39:31 +00:00
|
|
|
code: http.StatusOK,
|
2019-02-27 19:28:31 +00:00
|
|
|
init: tokens{agent: "A"},
|
|
|
|
raw: tokens{agentSource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "clear master legacy",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_agent_master_token",
|
2017-08-03 22:39:31 +00:00
|
|
|
body: body(""),
|
|
|
|
code: http.StatusOK,
|
2022-01-20 12:47:50 +00:00
|
|
|
init: tokens{agentRecovery: "M"},
|
|
|
|
raw: tokens{agentRecoverySource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "clear master",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "agent_master",
|
2017-08-03 22:39:31 +00:00
|
|
|
body: body(""),
|
|
|
|
code: http.StatusOK,
|
2022-01-20 12:47:50 +00:00
|
|
|
init: tokens{agentRecovery: "M"},
|
|
|
|
raw: tokens{agentRecoverySource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
2021-12-02 17:05:27 +00:00
|
|
|
{
|
|
|
|
name: "clear recovery",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "agent_recovery",
|
2021-12-02 17:05:27 +00:00
|
|
|
body: body(""),
|
|
|
|
code: http.StatusOK,
|
2022-01-20 12:47:50 +00:00
|
|
|
init: tokens{agentRecovery: "R"},
|
|
|
|
raw: tokens{agentRecoverySource: tokenStore.TokenSourceAPI},
|
2021-12-02 17:05:27 +00:00
|
|
|
},
|
2017-08-03 22:39:31 +00:00
|
|
|
{
|
2019-02-27 19:28:31 +00:00
|
|
|
name: "clear repl legacy",
|
2017-08-03 22:39:31 +00:00
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "acl_replication_token",
|
2017-08-03 22:39:31 +00:00
|
|
|
body: body(""),
|
|
|
|
code: http.StatusOK,
|
2019-02-27 19:28:31 +00:00
|
|
|
init: tokens{repl: "R"},
|
|
|
|
raw: tokens{replSource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "clear repl",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "replication",
|
2017-08-03 22:39:31 +00:00
|
|
|
body: body(""),
|
|
|
|
code: http.StatusOK,
|
2019-02-27 19:28:31 +00:00
|
|
|
init: tokens{repl: "R"},
|
|
|
|
raw: tokens{replSource: tokenStore.TokenSourceAPI},
|
2017-08-03 22:39:31 +00:00
|
|
|
},
|
2023-01-10 16:24:02 +00:00
|
|
|
{
|
|
|
|
name: "clear registration",
|
|
|
|
method: "PUT",
|
2023-01-24 16:21:41 +00:00
|
|
|
url: "config_file_service_registration",
|
2023-01-10 16:24:02 +00:00
|
|
|
body: body(""),
|
|
|
|
code: http.StatusOK,
|
|
|
|
init: tokens{registration: "G"},
|
|
|
|
raw: tokens{registrationSource: tokenStore.TokenSourceAPI},
|
|
|
|
},
|
2017-07-26 18:03:43 +00:00
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2019-02-27 19:28:31 +00:00
|
|
|
resetTokens(tt.init)
|
2017-07-26 18:03:43 +00:00
|
|
|
url := fmt.Sprintf("/v1/agent/token/%s", tt.url)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
req, _ := http.NewRequest(tt.method, url, tt.body)
|
2023-01-24 16:21:41 +00:00
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2020-08-17 23:30:25 +00:00
|
|
|
|
2021-11-03 15:12:36 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, tt.code, resp.Code)
|
2021-10-26 19:20:57 +00:00
|
|
|
if tt.expectedErr != "" {
|
2021-11-03 15:12:36 +00:00
|
|
|
require.Contains(t, resp.Body.String(), tt.expectedErr)
|
2020-08-17 23:30:25 +00:00
|
|
|
return
|
|
|
|
}
|
2019-02-27 19:28:31 +00:00
|
|
|
require.Equal(t, tt.effective.user, a.tokens.UserToken())
|
|
|
|
require.Equal(t, tt.effective.agent, a.tokens.AgentToken())
|
2022-01-20 12:47:50 +00:00
|
|
|
require.Equal(t, tt.effective.agentRecovery, a.tokens.AgentRecoveryToken())
|
2019-02-27 19:28:31 +00:00
|
|
|
require.Equal(t, tt.effective.repl, a.tokens.ReplicationToken())
|
2023-01-10 16:24:02 +00:00
|
|
|
require.Equal(t, tt.effective.registration, a.tokens.ConfigFileRegistrationToken())
|
2019-02-27 19:28:31 +00:00
|
|
|
|
|
|
|
tok, src := a.tokens.UserTokenAndSource()
|
|
|
|
require.Equal(t, tt.raw.user, tok)
|
|
|
|
require.Equal(t, tt.raw.userSource, src)
|
|
|
|
|
|
|
|
tok, src = a.tokens.AgentTokenAndSource()
|
|
|
|
require.Equal(t, tt.raw.agent, tok)
|
|
|
|
require.Equal(t, tt.raw.agentSource, src)
|
|
|
|
|
2021-12-07 12:12:47 +00:00
|
|
|
tok, src = a.tokens.AgentRecoveryTokenAndSource()
|
2022-01-20 12:47:50 +00:00
|
|
|
require.Equal(t, tt.raw.agentRecovery, tok)
|
|
|
|
require.Equal(t, tt.raw.agentRecoverySource, src)
|
2019-02-27 19:28:31 +00:00
|
|
|
|
|
|
|
tok, src = a.tokens.ReplicationTokenAndSource()
|
|
|
|
require.Equal(t, tt.raw.repl, tok)
|
|
|
|
require.Equal(t, tt.raw.replSource, src)
|
2023-01-10 16:24:02 +00:00
|
|
|
|
|
|
|
tok, src = a.tokens.ConfigFileRegistrationTokenAndSource()
|
|
|
|
require.Equal(t, tt.raw.registration, tok)
|
|
|
|
require.Equal(t, tt.raw.registrationSource, src)
|
2017-07-26 18:03:43 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// This one returns an error that is interpreted by the HTTP wrapper, so
|
|
|
|
// doesn't fit into our table above.
|
|
|
|
t.Run("permission denied", func(t *testing.T) {
|
2017-08-03 22:39:31 +00:00
|
|
|
resetTokens(tokens{})
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/token/acl_token", body("X"))
|
2021-11-03 15:12:36 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2019-02-27 19:28:31 +00:00
|
|
|
require.Equal(t, "", a.tokens.UserToken())
|
2017-07-26 18:03:43 +00:00
|
|
|
})
|
|
|
|
}
|
2018-03-21 17:20:35 +00:00
|
|
|
|
|
|
|
func TestAgentConnectCARoots_empty(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-21 17:20:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "connect { enabled = false }")
|
2018-03-21 17:20:35 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-21 17:20:35 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/roots", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusInternalServerError, resp.Code)
|
|
|
|
require.Contains(t, resp.Body.String(), "Connect must be enabled")
|
2018-03-21 17:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgentConnectCARoots_list(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2022-09-14 00:21:04 +00:00
|
|
|
// Disable peering to avoid setting up a roots watch for the server certificate,
|
|
|
|
// which leads to cache hit on the first query below.
|
|
|
|
a := NewTestAgent(t, "peering { enabled = false }")
|
2018-03-21 17:20:35 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-21 17:20:35 +00:00
|
|
|
|
2018-04-30 21:23:49 +00:00
|
|
|
// Set some CAs. Note that NewTestAgent already bootstraps one CA so this just
|
|
|
|
// adds a second and makes it active.
|
|
|
|
ca2 := connect.TestCAConfigSet(t, a, nil)
|
2018-03-21 17:20:35 +00:00
|
|
|
|
|
|
|
// List
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/roots", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
value := &structs.IndexedCARoots{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(value))
|
2018-03-21 17:20:35 +00:00
|
|
|
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, value.ActiveRootID, ca2.ID)
|
2018-05-09 16:15:29 +00:00
|
|
|
// Would like to assert that it's the same as the TestAgent domain but the
|
|
|
|
// only way to access that state via this package is by RPC to the server
|
|
|
|
// implementation running in TestAgent which is more or less a tautology.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.NotEmpty(t, value.TrustDomain)
|
|
|
|
assert.Len(t, value.Roots, 2)
|
2018-03-21 17:20:35 +00:00
|
|
|
|
|
|
|
// We should never have the secret information
|
|
|
|
for _, r := range value.Roots {
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, "", r.SigningCert)
|
|
|
|
assert.Equal(t, "", r.SigningKey)
|
2018-04-11 09:18:24 +00:00
|
|
|
}
|
|
|
|
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2018-04-11 09:18:24 +00:00
|
|
|
|
|
|
|
// Test caching
|
|
|
|
{
|
|
|
|
// List it again
|
2018-06-15 12:13:54 +00:00
|
|
|
resp2 := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp2, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp2.Body)
|
|
|
|
value2 := &structs.IndexedCARoots{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(value2))
|
|
|
|
assert.Equal(t, value, value2)
|
2018-04-11 09:18:24 +00:00
|
|
|
|
|
|
|
// Should cache hit this time and not make request
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, "HIT", resp2.Header().Get("X-Cache"))
|
2018-04-11 09:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test that caching is updated in the background
|
|
|
|
{
|
2018-04-30 21:23:49 +00:00
|
|
|
// Set a new CA
|
|
|
|
ca := connect.TestCAConfigSet(t, a, nil)
|
2018-04-11 09:18:24 +00:00
|
|
|
|
2018-04-22 21:00:32 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
// List it again
|
2018-06-15 12:13:54 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2018-04-11 09:18:24 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
value := &structs.IndexedCARoots{}
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NoError(r, dec.Decode(value))
|
2018-04-22 21:00:32 +00:00
|
|
|
if ca.ID != value.ActiveRootID {
|
|
|
|
r.Fatalf("%s != %s", ca.ID, value.ActiveRootID)
|
|
|
|
}
|
2018-04-30 21:23:49 +00:00
|
|
|
// There are now 3 CAs because we didn't complete rotation on the original
|
|
|
|
// 2
|
|
|
|
if len(value.Roots) != 3 {
|
2018-04-22 21:00:32 +00:00
|
|
|
r.Fatalf("bad len: %d", len(value.Roots))
|
|
|
|
}
|
2018-04-11 09:18:24 +00:00
|
|
|
|
2018-06-15 12:13:54 +00:00
|
|
|
// Should be a cache hit! The data should've updated in the cache
|
|
|
|
// in the background so this should've been fetched directly from
|
|
|
|
// the cache.
|
|
|
|
if resp.Header().Get("X-Cache") != "HIT" {
|
|
|
|
r.Fatalf("should be a cache hit")
|
|
|
|
}
|
|
|
|
})
|
2018-03-21 17:20:35 +00:00
|
|
|
}
|
|
|
|
}
|
2018-03-21 17:55:39 +00:00
|
|
|
|
2018-05-07 04:46:22 +00:00
|
|
|
func TestAgentConnectCALeafCert_aclDefaultDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-05-07 04:46:22 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2018-05-07 04:46:22 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2020-01-30 03:23:11 +00:00
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
2018-05-07 04:46:22 +00:00
|
|
|
|
|
|
|
// Register a service with a managed proxy
|
|
|
|
{
|
|
|
|
reg := &structs.ServiceDefinition{
|
|
|
|
ID: "test-id",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
2019-08-09 19:19:30 +00:00
|
|
|
Connect: &structs.ServiceConnect{},
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(reg))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-05-07 04:46:22 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "body: %s", resp.Body.String())
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2018-05-19 06:27:02 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
2018-05-07 04:46:22 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
func TestAgentConnectCALeafCert_aclServiceWrite(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-05-07 04:46:22 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2018-05-07 04:46:22 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2020-01-30 03:23:11 +00:00
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
2018-05-07 04:46:22 +00:00
|
|
|
|
|
|
|
// Register a service with a managed proxy
|
|
|
|
{
|
|
|
|
reg := &structs.ServiceDefinition{
|
|
|
|
ID: "test-id",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
2019-08-09 19:19:30 +00:00
|
|
|
Connect: &structs.ServiceConnect{},
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(reg))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-05-07 04:46:22 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "body: %s", resp.Body.String())
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2021-07-20 21:52:34 +00:00
|
|
|
token := createACLTokenWithServicePolicy(t, a.srv, "write")
|
2018-05-07 04:46:22 +00:00
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2018-05-07 04:46:22 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2018-05-07 04:46:22 +00:00
|
|
|
|
|
|
|
// Get the issued cert
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
value := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(value))
|
|
|
|
require.NotNil(t, value)
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2021-07-20 21:52:34 +00:00
|
|
|
func createACLTokenWithServicePolicy(t *testing.T, srv *HTTPHandlers, policy string) string {
|
|
|
|
policyReq := &structs.ACLPolicy{
|
|
|
|
Name: "service-test-write",
|
|
|
|
Rules: fmt.Sprintf(`service "test" { policy = "%v" }`, policy),
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/acl/policy", jsonReader(policyReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-07-20 21:52:34 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
_, err := srv.ACLPolicyCreate(resp, req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
tokenReq := &structs.ACLToken{
|
|
|
|
Description: "token-for-test",
|
|
|
|
Policies: []structs.ACLTokenPolicyLink{{Name: "service-test-write"}},
|
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ = http.NewRequest("PUT", "/v1/acl/token", jsonReader(tokenReq))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2021-07-20 21:52:34 +00:00
|
|
|
resp = httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
svcToken := &structs.ACLToken{}
|
|
|
|
require.NoError(t, dec.Decode(svcToken))
|
2021-07-20 21:52:34 +00:00
|
|
|
return svcToken.SecretID
|
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
func TestAgentConnectCALeafCert_aclServiceReadDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-05-07 04:46:22 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2018-05-07 04:46:22 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2020-01-30 03:23:11 +00:00
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
2018-05-07 04:46:22 +00:00
|
|
|
|
|
|
|
// Register a service with a managed proxy
|
|
|
|
{
|
|
|
|
reg := &structs.ServiceDefinition{
|
|
|
|
ID: "test-id",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
2019-08-09 19:19:30 +00:00
|
|
|
Connect: &structs.ServiceConnect{},
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(reg))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-05-07 04:46:22 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code, "body: %s", resp.Body.String())
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2021-07-20 21:52:34 +00:00
|
|
|
token := createACLTokenWithServicePolicy(t, a.srv, "read")
|
2018-05-07 04:46:22 +00:00
|
|
|
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2018-05-07 04:46:22 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusForbidden, resp.Code)
|
2018-05-07 04:46:22 +00:00
|
|
|
}
|
|
|
|
|
2018-03-21 17:55:39 +00:00
|
|
|
func TestAgentConnectCALeafCert_good(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2020-06-10 20:47:35 +00:00
|
|
|
a := StartTestAgent(t, TestAgent{Overrides: `
|
|
|
|
connect {
|
|
|
|
test_ca_leaf_root_change_spread = "1ns"
|
|
|
|
}
|
|
|
|
`})
|
2018-03-21 17:55:39 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2020-01-30 03:23:11 +00:00
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
2018-03-21 17:55:39 +00:00
|
|
|
|
2018-04-30 21:23:49 +00:00
|
|
|
// CA already setup by default by NewTestAgent but force a new one so we can
|
|
|
|
// verify it was signed easily.
|
|
|
|
ca1 := connect.TestCAConfigSet(t, a, nil)
|
|
|
|
|
2018-03-21 17:55:39 +00:00
|
|
|
{
|
|
|
|
// Register a local service
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
ID: "foo",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
if !assert.Equal(t, 200, resp.Code) {
|
2018-03-21 17:55:39 +00:00
|
|
|
t.Log("Body: ", resp.Body.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// List
|
2018-05-19 06:27:02 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2018-06-13 19:43:34 +00:00
|
|
|
|
2018-05-19 06:27:02 +00:00
|
|
|
// Get the issued cert
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued))
|
2018-05-19 06:27:02 +00:00
|
|
|
|
|
|
|
// Verify that the cert is signed by the CA
|
|
|
|
requireLeafValidUnderCA(t, issued, ca1)
|
|
|
|
|
|
|
|
// Verify blocking index
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, issued.ModifyIndex > 0)
|
|
|
|
assert.Equal(t, fmt.Sprintf("%d", issued.ModifyIndex),
|
2018-05-19 06:27:02 +00:00
|
|
|
resp.Header().Get("X-Consul-Index"))
|
|
|
|
|
2020-07-20 20:09:20 +00:00
|
|
|
index := resp.Header().Get("X-Consul-Index")
|
|
|
|
|
2018-05-19 06:27:02 +00:00
|
|
|
// Test caching
|
|
|
|
{
|
|
|
|
// Fetch it again
|
2018-06-15 12:13:54 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued2))
|
|
|
|
require.Equal(t, issued, issued2)
|
2018-05-19 06:27:02 +00:00
|
|
|
}
|
|
|
|
|
2023-06-13 16:12:43 +00:00
|
|
|
replyCh := make(chan *httptest.ResponseRecorder, 1)
|
|
|
|
|
|
|
|
go func(index string) {
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test?index="+index, nil)
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
replyCh <- resp
|
|
|
|
}(index)
|
|
|
|
|
2021-12-02 19:32:15 +00:00
|
|
|
// Set a new CA
|
|
|
|
ca2 := connect.TestCAConfigSet(t, a, nil)
|
|
|
|
|
2020-07-20 20:09:20 +00:00
|
|
|
// Issue a blocking query to ensure that the cert gets updated appropriately
|
2022-08-09 14:36:47 +00:00
|
|
|
t.Run("test blocking queries update leaf cert", func(t *testing.T) {
|
2023-06-13 16:12:43 +00:00
|
|
|
var resp *httptest.ResponseRecorder
|
|
|
|
select {
|
|
|
|
case resp = <-replyCh:
|
|
|
|
case <-time.After(500 * time.Millisecond):
|
|
|
|
t.Fatal("blocking query did not wake up during rotation")
|
|
|
|
}
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued2))
|
|
|
|
require.NotEqual(t, issued.CertPEM, issued2.CertPEM)
|
|
|
|
require.NotEqual(t, issued.PrivateKeyPEM, issued2.PrivateKeyPEM)
|
2018-05-19 06:27:02 +00:00
|
|
|
|
2020-07-20 20:09:20 +00:00
|
|
|
// Verify that the cert is signed by the new CA
|
2021-12-02 19:32:15 +00:00
|
|
|
requireLeafValidUnderCA(t, issued2, ca2)
|
2018-05-19 06:27:02 +00:00
|
|
|
|
2020-07-20 20:09:20 +00:00
|
|
|
// Should not be a cache hit! The data was updated in response to the blocking
|
|
|
|
// query being made.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2022-08-09 14:36:47 +00:00
|
|
|
})
|
2021-12-02 19:32:15 +00:00
|
|
|
|
|
|
|
t.Run("test non-blocking queries update leaf cert", func(t *testing.T) {
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
obj, err := a.srv.AgentConnectCALeafCert(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
2021-12-02 19:32:15 +00:00
|
|
|
|
|
|
|
// Get the issued cert
|
|
|
|
issued, ok := obj.(*structs.IssuedCert)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, ok)
|
2021-12-02 19:32:15 +00:00
|
|
|
|
|
|
|
// Verify that the cert is signed by the CA
|
|
|
|
requireLeafValidUnderCA(t, issued, ca2)
|
|
|
|
|
|
|
|
// Issue a non blocking query to ensure that the cert gets updated appropriately
|
|
|
|
{
|
|
|
|
// Set a new CA
|
|
|
|
ca3 := connect.TestCAConfigSet(t, a, nil)
|
|
|
|
|
|
|
|
req, err := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
2021-12-02 19:32:15 +00:00
|
|
|
|
2022-08-09 14:36:47 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2021-12-02 19:32:15 +00:00
|
|
|
|
2022-08-09 14:36:47 +00:00
|
|
|
// Should not be a cache hit!
|
|
|
|
require.Equal(r, "MISS", resp.Header().Get("X-Cache"))
|
2021-12-02 19:32:15 +00:00
|
|
|
|
2022-08-09 14:36:47 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
|
|
|
require.NoError(r, dec.Decode(issued2))
|
2021-12-02 19:32:15 +00:00
|
|
|
|
2022-08-09 14:36:47 +00:00
|
|
|
require.NotEqual(r, issued.CertPEM, issued2.CertPEM)
|
|
|
|
require.NotEqual(r, issued.PrivateKeyPEM, issued2.PrivateKeyPEM)
|
2021-12-02 19:32:15 +00:00
|
|
|
|
2022-08-09 14:36:47 +00:00
|
|
|
// Verify that the cert is signed by the new CA
|
|
|
|
requireLeafValidUnderCA(r, issued2, ca3)
|
|
|
|
})
|
2021-12-02 19:32:15 +00:00
|
|
|
}
|
|
|
|
})
|
2018-05-07 04:02:44 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Test we can request a leaf cert for a service we have permission for
|
|
|
|
// but is not local to this agent.
|
|
|
|
func TestAgentConnectCALeafCert_goodNotLocal(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-05-07 04:02:44 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-06-10 20:47:35 +00:00
|
|
|
a := StartTestAgent(t, TestAgent{Overrides: `
|
|
|
|
connect {
|
|
|
|
test_ca_leaf_root_change_spread = "1ns"
|
|
|
|
}
|
|
|
|
`})
|
2018-05-07 04:02:44 +00:00
|
|
|
defer a.Shutdown()
|
2019-08-09 19:19:30 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2020-01-30 03:23:11 +00:00
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
2019-08-09 19:19:30 +00:00
|
|
|
|
|
|
|
// CA already setup by default by NewTestAgent but force a new one so we can
|
|
|
|
// verify it was signed easily.
|
|
|
|
ca1 := connect.TestCAConfigSet(t, a, nil)
|
2018-05-07 04:02:44 +00:00
|
|
|
|
|
|
|
{
|
2019-08-09 19:19:30 +00:00
|
|
|
// Register a non-local service (central catalog)
|
|
|
|
args := &structs.RegisterRequest{
|
|
|
|
Node: "foo",
|
2018-05-07 04:02:44 +00:00
|
|
|
Address: "127.0.0.1",
|
2019-08-09 19:19:30 +00:00
|
|
|
Service: &structs.NodeService{
|
|
|
|
Service: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8080,
|
2018-05-07 04:02:44 +00:00
|
|
|
},
|
|
|
|
}
|
2019-08-09 19:19:30 +00:00
|
|
|
req, _ := http.NewRequest("PUT", "/v1/catalog/register", jsonReader(args))
|
2018-05-07 04:02:44 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
if !assert.Equal(t, 200, resp.Code) {
|
2019-08-09 19:19:30 +00:00
|
|
|
t.Log("Body: ", resp.Body.String())
|
2018-05-07 04:02:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// List
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
2018-05-07 04:02:44 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2018-05-07 04:02:44 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Get the issued cert
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued))
|
2018-06-07 13:11:06 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Verify that the cert is signed by the CA
|
|
|
|
requireLeafValidUnderCA(t, issued, ca1)
|
2018-04-26 13:01:20 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Verify blocking index
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, issued.ModifyIndex > 0)
|
|
|
|
assert.Equal(t, fmt.Sprintf("%d", issued.ModifyIndex),
|
2019-08-09 19:19:30 +00:00
|
|
|
resp.Header().Get("X-Consul-Index"))
|
2018-05-03 17:44:10 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Test caching
|
|
|
|
{
|
|
|
|
// Fetch it again
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued2))
|
|
|
|
require.Equal(t, issued, issued2)
|
2018-04-26 13:01:20 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Test Blocking - see https://github.com/hashicorp/consul/issues/4462
|
|
|
|
{
|
|
|
|
// Fetch it again
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
blockingReq, _ := http.NewRequest("GET", fmt.Sprintf("/v1/agent/connect/ca/leaf/test?wait=125ms&index=%d", issued.ModifyIndex), nil)
|
|
|
|
doneCh := make(chan struct{})
|
|
|
|
go func() {
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, blockingReq)
|
2019-08-09 19:19:30 +00:00
|
|
|
close(doneCh)
|
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-time.After(500 * time.Millisecond):
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.FailNow(t, "Shouldn't block for this long - not respecting wait parameter in the query")
|
2019-08-09 19:19:30 +00:00
|
|
|
|
|
|
|
case <-doneCh:
|
|
|
|
}
|
2018-04-26 13:01:20 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Test that caching is updated in the background
|
|
|
|
{
|
|
|
|
// Set a new CA
|
|
|
|
ca := connect.TestCAConfigSet(t, a, nil)
|
2018-04-26 13:01:20 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
// Try and sign again (note no index/wait arg since cache should update in
|
|
|
|
// background even if we aren't actively blocking)
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
2018-04-26 13:01:20 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NoError(r, dec.Decode(issued2))
|
2019-08-09 19:19:30 +00:00
|
|
|
if issued.CertPEM == issued2.CertPEM {
|
|
|
|
r.Fatalf("leaf has not updated")
|
2018-04-26 13:01:20 +00:00
|
|
|
}
|
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Got a new leaf. Sanity check it's a whole new key as well as different
|
|
|
|
// cert.
|
|
|
|
if issued.PrivateKeyPEM == issued2.PrivateKeyPEM {
|
|
|
|
r.Fatalf("new leaf has same private key as before")
|
2018-06-18 19:37:00 +00:00
|
|
|
}
|
2018-04-26 13:01:20 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
// Verify that the cert is signed by the new CA
|
2023-06-07 18:53:27 +00:00
|
|
|
requireLeafValidUnderCA(r, issued2, ca)
|
2019-08-09 19:19:30 +00:00
|
|
|
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NotEqual(r, issued, issued2)
|
2018-04-26 13:01:20 +00:00
|
|
|
})
|
|
|
|
}
|
2018-04-18 20:05:30 +00:00
|
|
|
}
|
|
|
|
|
2022-04-20 17:21:47 +00:00
|
|
|
func TestAgentConnectCALeafCert_nonBlockingQuery_after_blockingQuery_shouldNotBlock(t *testing.T) {
|
|
|
|
// see: https://github.com/hashicorp/consul/issues/12048
|
|
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
a := NewTestAgent(t, "")
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Register a local service
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
ID: "foo",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req := httptest.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if !assert.Equal(t, 200, resp.Code) {
|
|
|
|
t.Log("Body: ", resp.Body.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
serialNumber string
|
|
|
|
index string
|
|
|
|
issued structs.IssuedCert
|
|
|
|
)
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "do initial non-blocking query", func(t *testing.T) {
|
2022-04-20 17:21:47 +00:00
|
|
|
req := httptest.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
require.NoError(t, dec.Decode(&issued))
|
|
|
|
serialNumber = issued.SerialNumber
|
|
|
|
|
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"),
|
|
|
|
"for the leaf cert cache type these are always MISS")
|
|
|
|
index = resp.Header().Get("X-Consul-Index")
|
|
|
|
})
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
go func() {
|
|
|
|
// launch goroutine for blocking query
|
|
|
|
req := httptest.NewRequest("GET", "/v1/agent/connect/ca/leaf/test?index="+index, nil).Clone(ctx)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
}()
|
|
|
|
|
|
|
|
// We just need to ensure that the above blocking query is in-flight before
|
|
|
|
// the next step, so do a little sleep.
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
|
|
|
|
// The initial non-blocking query populated the leaf cert cache entry
|
|
|
|
// implicitly. The agent cache doesn't prune entries very often at all, so
|
|
|
|
// in between both of these steps the data should still be there, causing
|
|
|
|
// this to be a HIT that completes in less than 10m (the default inner leaf
|
|
|
|
// cert blocking query timeout).
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "do a non-blocking query that should not block", func(t *testing.T) {
|
2022-04-20 17:21:47 +00:00
|
|
|
req := httptest.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
var issued2 structs.IssuedCert
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
require.NoError(t, dec.Decode(&issued2))
|
|
|
|
|
|
|
|
require.Equal(t, "HIT", resp.Header().Get("X-Cache"))
|
|
|
|
|
|
|
|
// If this is actually returning a cached result, the serial number
|
|
|
|
// should be unchanged.
|
|
|
|
require.Equal(t, serialNumber, issued2.SerialNumber)
|
|
|
|
|
|
|
|
require.Equal(t, issued, issued2)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-02-08 19:18:51 +00:00
|
|
|
func TestAgentConnectCALeafCert_Vault_doesNotChurnLeafCertsAtIdle(t *testing.T) {
|
|
|
|
ca.SkipIfVaultNotPresent(t)
|
|
|
|
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
testVault := ca.NewTestVaultServer(t)
|
2022-12-06 16:06:36 +00:00
|
|
|
|
|
|
|
vaultToken := ca.CreateVaultTokenWithAttrs(t, testVault.Client(), &ca.VaultTokenAttributes{
|
|
|
|
RootPath: "pki-root",
|
|
|
|
IntermediatePath: "pki-intermediate",
|
|
|
|
ConsulManaged: true,
|
|
|
|
})
|
2021-02-08 19:18:51 +00:00
|
|
|
|
|
|
|
a := StartTestAgent(t, TestAgent{Overrides: fmt.Sprintf(`
|
|
|
|
connect {
|
|
|
|
test_ca_leaf_root_change_spread = "1ns"
|
|
|
|
ca_provider = "vault"
|
|
|
|
ca_config {
|
|
|
|
address = %[1]q
|
|
|
|
token = %[2]q
|
|
|
|
root_pki_path = "pki-root/"
|
|
|
|
intermediate_pki_path = "pki-intermediate/"
|
|
|
|
}
|
|
|
|
}
|
2022-12-06 16:06:36 +00:00
|
|
|
`, testVault.Addr, vaultToken)})
|
2021-02-08 19:18:51 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
testrpc.WaitForActiveCARoot(t, a.RPC, "dc1", nil)
|
|
|
|
|
|
|
|
var ca1 *structs.CARoot
|
|
|
|
{
|
|
|
|
args := &structs.DCSpecificRequest{Datacenter: "dc1"}
|
|
|
|
var reply structs.IndexedCARoots
|
2022-12-14 15:24:22 +00:00
|
|
|
require.NoError(t, a.RPC(context.Background(), "ConnectCA.Roots", args, &reply))
|
2021-02-08 19:18:51 +00:00
|
|
|
for _, r := range reply.Roots {
|
|
|
|
if r.ID == reply.ActiveRootID {
|
|
|
|
ca1 = r
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NotNil(t, ca1)
|
2021-02-08 19:18:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
// Register a local service
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
ID: "foo",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
if !assert.Equal(t, 200, resp.Code) {
|
2021-02-08 19:18:51 +00:00
|
|
|
t.Log("Body: ", resp.Body.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// List
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2021-02-08 19:18:51 +00:00
|
|
|
|
|
|
|
// Get the issued cert
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued))
|
2021-02-08 19:18:51 +00:00
|
|
|
|
|
|
|
// Verify that the cert is signed by the CA
|
|
|
|
requireLeafValidUnderCA(t, issued, ca1)
|
|
|
|
|
|
|
|
// Verify blocking index
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, issued.ModifyIndex > 0)
|
|
|
|
assert.Equal(t, fmt.Sprintf("%d", issued.ModifyIndex),
|
2021-02-08 19:18:51 +00:00
|
|
|
resp.Header().Get("X-Consul-Index"))
|
|
|
|
|
|
|
|
// Test caching
|
|
|
|
{
|
|
|
|
// Fetch it again
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued2))
|
|
|
|
require.Equal(t, issued, issued2)
|
2021-02-08 19:18:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test that we aren't churning leaves for no reason at idle.
|
|
|
|
{
|
|
|
|
ch := make(chan error, 1)
|
|
|
|
go func() {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test?index="+strconv.Itoa(int(issued.ModifyIndex)), nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != http.StatusOK {
|
|
|
|
ch <- fmt.Errorf(resp.Body.String())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
|
|
|
if err := dec.Decode(issued2); err != nil {
|
2021-02-08 19:18:51 +00:00
|
|
|
ch <- err
|
|
|
|
} else {
|
|
|
|
if issued.CertPEM == issued2.CertPEM {
|
|
|
|
ch <- fmt.Errorf("leaf woke up unexpectedly with same cert")
|
|
|
|
} else {
|
|
|
|
ch <- fmt.Errorf("leaf woke up unexpectedly with new cert")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
start := time.Now()
|
|
|
|
select {
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
case err := <-ch:
|
|
|
|
dur := time.Since(start)
|
|
|
|
t.Fatalf("unexpected return from blocking query; leaf churned during idle period, took %s: %v", dur, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-26 16:54:14 +00:00
|
|
|
func TestAgentConnectCALeafCert_secondaryDC_good(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-26 16:54:14 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 20:24:39 +00:00
|
|
|
a1 := StartTestAgent(t, TestAgent{Name: "dc1", HCL: `
|
2019-09-26 16:54:14 +00:00
|
|
|
datacenter = "dc1"
|
|
|
|
primary_datacenter = "dc1"
|
2020-06-10 20:47:35 +00:00
|
|
|
`, Overrides: `
|
|
|
|
connect {
|
|
|
|
test_ca_leaf_root_change_spread = "1ns"
|
|
|
|
}
|
2020-03-31 20:12:33 +00:00
|
|
|
`})
|
2019-09-26 16:54:14 +00:00
|
|
|
defer a1.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a1.RPC, "dc1")
|
|
|
|
|
2020-03-31 20:24:39 +00:00
|
|
|
a2 := StartTestAgent(t, TestAgent{Name: "dc2", HCL: `
|
2019-09-26 16:54:14 +00:00
|
|
|
datacenter = "dc2"
|
|
|
|
primary_datacenter = "dc1"
|
2020-06-10 20:47:35 +00:00
|
|
|
`, Overrides: `
|
|
|
|
connect {
|
|
|
|
test_ca_leaf_root_change_spread = "1ns"
|
|
|
|
}
|
2020-03-31 20:12:33 +00:00
|
|
|
`})
|
2019-09-26 16:54:14 +00:00
|
|
|
defer a2.Shutdown()
|
|
|
|
testrpc.WaitForTestAgent(t, a2.RPC, "dc2")
|
|
|
|
|
|
|
|
// Wait for the WAN join.
|
|
|
|
addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN)
|
|
|
|
_, err := a2.JoinWAN([]string{addr})
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
2019-09-26 16:54:14 +00:00
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a1.RPC, "dc1")
|
|
|
|
testrpc.WaitForLeader(t, a2.RPC, "dc2")
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
if got, want := len(a1.WANMembers()), 2; got < want {
|
|
|
|
r.Fatalf("got %d WAN members want at least %d", got, want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// CA already setup by default by NewTestAgent but force a new one so we can
|
|
|
|
// verify it was signed easily.
|
|
|
|
dc1_ca1 := connect.TestCAConfigSet(t, a1, nil)
|
|
|
|
|
|
|
|
// Wait until root is updated in both dcs.
|
|
|
|
waitForActiveCARoot(t, a1.srv, dc1_ca1)
|
|
|
|
waitForActiveCARoot(t, a2.srv, dc1_ca1)
|
|
|
|
|
|
|
|
{
|
|
|
|
// Register a local service in the SECONDARY
|
|
|
|
args := &structs.ServiceDefinition{
|
|
|
|
ID: "foo",
|
|
|
|
Name: "test",
|
|
|
|
Address: "127.0.0.1",
|
|
|
|
Port: 8000,
|
|
|
|
Check: structs.CheckType{
|
|
|
|
TTL: 15 * time.Second,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("PUT", "/v1/agent/service/register", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a2.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
if !assert.Equal(t, 200, resp.Code) {
|
2019-09-26 16:54:14 +00:00
|
|
|
t.Log("Body: ", resp.Body.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// List
|
2021-12-02 19:32:15 +00:00
|
|
|
req, err := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test", nil)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, err)
|
2019-09-26 16:54:14 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a2.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2019-09-26 16:54:14 +00:00
|
|
|
|
|
|
|
// Get the issued cert
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued))
|
2019-09-26 16:54:14 +00:00
|
|
|
|
|
|
|
// Verify that the cert is signed by the CA
|
|
|
|
requireLeafValidUnderCA(t, issued, dc1_ca1)
|
|
|
|
|
|
|
|
// Verify blocking index
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, issued.ModifyIndex > 0)
|
|
|
|
assert.Equal(t, fmt.Sprintf("%d", issued.ModifyIndex),
|
2019-09-26 16:54:14 +00:00
|
|
|
resp.Header().Get("X-Consul-Index"))
|
|
|
|
|
|
|
|
// Test caching
|
|
|
|
{
|
|
|
|
// Fetch it again
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a2.srv.h.ServeHTTP(resp, req)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(issued2))
|
|
|
|
require.Equal(t, issued, issued2)
|
2019-09-26 16:54:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test that we aren't churning leaves for no reason at idle.
|
|
|
|
{
|
|
|
|
ch := make(chan error, 1)
|
|
|
|
go func() {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/leaf/test?index="+strconv.Itoa(int(issued.ModifyIndex)), nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a2.srv.h.ServeHTTP(resp, req)
|
|
|
|
if resp.Code != http.StatusOK {
|
|
|
|
ch <- fmt.Errorf(resp.Body.String())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
|
|
|
if err := dec.Decode(issued2); err != nil {
|
2019-09-26 16:54:14 +00:00
|
|
|
ch <- err
|
|
|
|
} else {
|
|
|
|
if issued.CertPEM == issued2.CertPEM {
|
|
|
|
ch <- fmt.Errorf("leaf woke up unexpectedly with same cert")
|
|
|
|
} else {
|
|
|
|
ch <- fmt.Errorf("leaf woke up unexpectedly with new cert")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
start := time.Now()
|
|
|
|
|
|
|
|
// Before applying the fix from PR-6513 this would reliably wake up
|
|
|
|
// after ~20ms with a new cert. Since this test is necessarily a bit
|
|
|
|
// timing dependent we'll chill out for 5 seconds which should be enough
|
|
|
|
// time to disprove the original bug.
|
|
|
|
select {
|
|
|
|
case <-time.After(5 * time.Second):
|
|
|
|
case err := <-ch:
|
|
|
|
dur := time.Since(start)
|
|
|
|
t.Fatalf("unexpected return from blocking query; leaf churned during idle period, took %s: %v", dur, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set a new CA
|
|
|
|
dc1_ca2 := connect.TestCAConfigSet(t, a2, nil)
|
|
|
|
|
|
|
|
// Wait until root is updated in both dcs.
|
|
|
|
waitForActiveCARoot(t, a1.srv, dc1_ca2)
|
|
|
|
waitForActiveCARoot(t, a2.srv, dc1_ca2)
|
|
|
|
|
|
|
|
// Test that caching is updated in the background
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
// Try and sign again (note no index/wait arg since cache should update in
|
|
|
|
// background even if we aren't actively blocking)
|
2021-12-07 14:44:03 +00:00
|
|
|
a2.srv.h.ServeHTTP(resp, req)
|
2023-06-07 18:53:27 +00:00
|
|
|
require.Equal(r, http.StatusOK, resp.Code)
|
2019-09-26 16:54:14 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
issued2 := &structs.IssuedCert{}
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NoError(r, dec.Decode(issued2))
|
2019-09-26 16:54:14 +00:00
|
|
|
if issued.CertPEM == issued2.CertPEM {
|
|
|
|
r.Fatalf("leaf has not updated")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Got a new leaf. Sanity check it's a whole new key as well as different
|
|
|
|
// cert.
|
|
|
|
if issued.PrivateKeyPEM == issued2.PrivateKeyPEM {
|
|
|
|
r.Fatalf("new leaf has same private key as before")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify that the cert is signed by the new CA
|
2023-06-07 18:53:27 +00:00
|
|
|
requireLeafValidUnderCA(r, issued2, dc1_ca2)
|
2019-09-26 16:54:14 +00:00
|
|
|
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NotEqual(r, issued, issued2)
|
2019-09-26 16:54:14 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-04 18:42:15 +00:00
|
|
|
func waitForActiveCARoot(t *testing.T, srv *HTTPHandlers, expect *structs.CARoot) {
|
2019-09-26 16:54:14 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/connect/ca/roots", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
srv.h.ServeHTTP(resp, req)
|
|
|
|
if http.StatusOK != resp.Code {
|
2023-06-07 18:53:27 +00:00
|
|
|
r.Fatalf("expected 200 but got %v", resp.Code)
|
2019-09-26 16:54:14 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
roots := &structs.IndexedCARoots{}
|
2023-06-07 18:53:27 +00:00
|
|
|
require.NoError(r, dec.Decode(roots))
|
2019-09-26 16:54:14 +00:00
|
|
|
|
|
|
|
var root *structs.CARoot
|
|
|
|
for _, r := range roots.Roots {
|
|
|
|
if r.ID == roots.ActiveRootID {
|
|
|
|
root = r
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if root == nil {
|
|
|
|
r.Fatal("no active root")
|
|
|
|
}
|
|
|
|
if root.ID != expect.ID {
|
|
|
|
r.Fatalf("current active root is %s; waiting for %s", root.ID, expect.ID)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-09 14:36:47 +00:00
|
|
|
func requireLeafValidUnderCA(t require.TestingT, issued *structs.IssuedCert, ca *structs.CARoot) {
|
2019-09-26 16:54:14 +00:00
|
|
|
leaf, intermediates, err := connect.ParseLeafCerts(issued.CertPEM)
|
|
|
|
require.NoError(t, err)
|
2019-08-09 19:19:30 +00:00
|
|
|
|
|
|
|
roots := x509.NewCertPool()
|
|
|
|
require.True(t, roots.AppendCertsFromPEM([]byte(ca.RootCert)))
|
2019-09-26 16:54:14 +00:00
|
|
|
|
2019-08-09 19:19:30 +00:00
|
|
|
_, err = leaf.Verify(x509.VerifyOptions{
|
2019-09-26 16:54:14 +00:00
|
|
|
Roots: roots,
|
|
|
|
Intermediates: intermediates,
|
2019-08-09 19:19:30 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Verify the private key matches. tls.LoadX509Keypair does this for us!
|
|
|
|
_, err = tls.X509KeyPair([]byte(issued.CertPEM), []byte(issued.PrivateKeyPEM))
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
func TestAgentConnectAuthorize_badBody(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-26 00:52:26 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-26 00:52:26 +00:00
|
|
|
args := []string{}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusBadRequest, resp.Code)
|
|
|
|
assert.Contains(t, resp.Body.String(), "decode failed")
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgentConnectAuthorize_noTarget(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-26 00:52:26 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-26 00:52:26 +00:00
|
|
|
args := &structs.ConnectAuthorizeRequest{}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusBadRequest, resp.Code)
|
|
|
|
assert.Contains(t, resp.Body.String(), "Target service must be specified")
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Client ID is not in the valid URI format
|
|
|
|
func TestAgentConnectAuthorize_idInvalidFormat(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-26 00:52:26 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-26 00:52:26 +00:00
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-03-28 21:29:35 +00:00
|
|
|
Target: "web",
|
|
|
|
ClientCertURI: "tubes",
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusBadRequest, resp.Code)
|
|
|
|
assert.Contains(t, resp.Body.String(), "ClientCertURI not a valid Connect identifier")
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Client ID is a valid URI but its not a service URI
|
|
|
|
func TestAgentConnectAuthorize_idNotService(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-26 00:52:26 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-26 00:52:26 +00:00
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-03-28 21:29:35 +00:00
|
|
|
Target: "web",
|
|
|
|
ClientCertURI: "spiffe://1234.consul",
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, http.StatusBadRequest, resp.Code)
|
|
|
|
assert.Contains(t, resp.Body.String(), "ClientCertURI not a valid Service identifier")
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test when there is an intention allowing the connection
|
|
|
|
func TestAgentConnectAuthorize_allow(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-26 00:52:26 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-26 00:52:26 +00:00
|
|
|
target := "db"
|
|
|
|
|
|
|
|
// Create some intentions
|
2018-04-17 23:26:58 +00:00
|
|
|
var ixnId string
|
2018-03-26 00:52:26 +00:00
|
|
|
{
|
|
|
|
req := structs.IntentionRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Op: structs.IntentionOpCreate,
|
|
|
|
Intention: structs.TestIntention(t),
|
|
|
|
}
|
|
|
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.SourceName = "web"
|
|
|
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.DestinationName = target
|
|
|
|
req.Intention.Action = structs.IntentionActionAllow
|
|
|
|
|
2022-12-14 15:24:22 +00:00
|
|
|
require.Nil(t, a.RPC(context.Background(), "Intention.Apply", &req, &ixnId))
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-05-10 16:04:33 +00:00
|
|
|
Target: target,
|
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code)
|
|
|
|
require.Equal(t, "MISS", resp.Header().Get("X-Cache"))
|
2018-03-26 00:52:26 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(obj))
|
|
|
|
require.True(t, obj.Authorized)
|
|
|
|
require.Contains(t, obj.Reason, "Matched")
|
2018-04-17 23:26:58 +00:00
|
|
|
|
|
|
|
// Make the request again
|
|
|
|
{
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code)
|
2018-04-17 23:26:58 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(obj))
|
|
|
|
require.True(t, obj.Authorized)
|
|
|
|
require.Contains(t, obj.Reason, "Matched")
|
2018-04-17 23:26:58 +00:00
|
|
|
|
2018-06-15 12:13:54 +00:00
|
|
|
// That should've been a cache hit.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, "HIT", resp.Header().Get("X-Cache"))
|
2018-06-15 12:13:54 +00:00
|
|
|
}
|
2018-04-17 23:26:58 +00:00
|
|
|
|
|
|
|
// Change the intention
|
|
|
|
{
|
|
|
|
req := structs.IntentionRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Op: structs.IntentionOpUpdate,
|
|
|
|
Intention: structs.TestIntention(t),
|
|
|
|
}
|
|
|
|
req.Intention.ID = ixnId
|
|
|
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.SourceName = "web"
|
|
|
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.DestinationName = target
|
|
|
|
req.Intention.Action = structs.IntentionActionDeny
|
|
|
|
|
2022-12-14 15:24:22 +00:00
|
|
|
require.Nil(t, a.RPC(context.Background(), "Intention.Apply", &req, &ixnId))
|
2018-04-17 23:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Short sleep lets the cache background refresh happen
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
|
|
|
// Make the request again
|
|
|
|
{
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, 200, resp.Code)
|
2018-04-17 23:26:58 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(obj))
|
|
|
|
require.False(t, obj.Authorized)
|
|
|
|
require.Contains(t, obj.Reason, "Matched")
|
2018-04-17 23:26:58 +00:00
|
|
|
|
2018-06-15 12:13:54 +00:00
|
|
|
// That should've been a cache hit, too, since it updated in the
|
|
|
|
// background.
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.Equal(t, "HIT", resp.Header().Get("X-Cache"))
|
2018-06-15 12:13:54 +00:00
|
|
|
}
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test when there is an intention denying the connection
|
|
|
|
func TestAgentConnectAuthorize_deny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 00:52:26 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-03-26 00:52:26 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-03-26 00:52:26 +00:00
|
|
|
target := "db"
|
|
|
|
|
|
|
|
// Create some intentions
|
|
|
|
{
|
|
|
|
req := structs.IntentionRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Op: structs.IntentionOpCreate,
|
|
|
|
Intention: structs.TestIntention(t),
|
|
|
|
}
|
|
|
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.SourceName = "web"
|
|
|
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.DestinationName = target
|
|
|
|
req.Intention.Action = structs.IntentionActionDeny
|
|
|
|
|
|
|
|
var reply string
|
2022-12-14 15:24:22 +00:00
|
|
|
assert.Nil(t, a.RPC(context.Background(), "Intention.Apply", &req, &reply))
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-05-10 16:04:33 +00:00
|
|
|
Target: target,
|
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, 200, resp.Code)
|
2018-03-26 00:52:26 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
|
|
|
require.NoError(t, dec.Decode(obj))
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.False(t, obj.Authorized)
|
|
|
|
assert.Contains(t, obj.Reason, "Matched")
|
2018-03-26 00:52:26 +00:00
|
|
|
}
|
2018-03-26 01:50:05 +00:00
|
|
|
|
2018-11-12 20:20:12 +00:00
|
|
|
// Test when there is an intention allowing service with a different trust
|
|
|
|
// domain. We allow this because migration between trust domains shouldn't cause
|
|
|
|
// an outage even if we have stale info about current trusted domains. It's safe
|
|
|
|
// because the CA root is either unique to this cluster and not used to sign
|
|
|
|
// anything external, or path validation can be used to ensure that the CA can
|
|
|
|
// only issue certs that are valid for the specific cluster trust domain at x509
|
|
|
|
// level which is enforced by TLS handshake.
|
|
|
|
func TestAgentConnectAuthorize_allowTrustDomain(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-05-09 19:30:43 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-05-09 19:30:43 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-05-09 19:30:43 +00:00
|
|
|
target := "db"
|
|
|
|
|
|
|
|
// Create some intentions
|
|
|
|
{
|
|
|
|
req := structs.IntentionRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Op: structs.IntentionOpCreate,
|
|
|
|
Intention: structs.TestIntention(t),
|
|
|
|
}
|
|
|
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.SourceName = "web"
|
|
|
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.DestinationName = target
|
|
|
|
req.Intention.Action = structs.IntentionActionAllow
|
|
|
|
|
|
|
|
var reply string
|
2022-12-14 15:24:22 +00:00
|
|
|
require.NoError(t, a.RPC(context.Background(), "Intention.Apply", &req, &reply))
|
2018-05-09 19:30:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-05-10 16:04:33 +00:00
|
|
|
Target: target,
|
|
|
|
ClientCertURI: "spiffe://fake-domain.consul/ns/default/dc/dc1/svc/web",
|
2018-05-09 19:30:43 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, 200, resp.Code)
|
2018-05-09 19:30:43 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(obj))
|
|
|
|
require.True(t, obj.Authorized)
|
|
|
|
require.Contains(t, obj.Reason, "Matched")
|
2018-05-09 19:30:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-05 11:53:42 +00:00
|
|
|
func TestAgentConnectAuthorize_denyWildcard(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-04-05 11:53:42 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2018-04-05 11:53:42 +00:00
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
2018-04-05 11:53:42 +00:00
|
|
|
|
|
|
|
target := "db"
|
|
|
|
|
|
|
|
// Create some intentions
|
|
|
|
{
|
|
|
|
// Deny wildcard to DB
|
|
|
|
req := structs.IntentionRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Op: structs.IntentionOpCreate,
|
|
|
|
Intention: structs.TestIntention(t),
|
|
|
|
}
|
|
|
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.SourceName = "*"
|
|
|
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.DestinationName = target
|
|
|
|
req.Intention.Action = structs.IntentionActionDeny
|
|
|
|
|
|
|
|
var reply string
|
2022-12-14 15:24:22 +00:00
|
|
|
require.NoError(t, a.RPC(context.Background(), "Intention.Apply", &req, &reply))
|
2018-04-05 11:53:42 +00:00
|
|
|
}
|
|
|
|
{
|
|
|
|
// Allow web to DB
|
|
|
|
req := structs.IntentionRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Op: structs.IntentionOpCreate,
|
|
|
|
Intention: structs.TestIntention(t),
|
|
|
|
}
|
|
|
|
req.Intention.SourceNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.SourceName = "web"
|
|
|
|
req.Intention.DestinationNS = structs.IntentionDefaultNamespace
|
|
|
|
req.Intention.DestinationName = target
|
|
|
|
req.Intention.Action = structs.IntentionActionAllow
|
|
|
|
|
|
|
|
var reply string
|
2022-12-14 15:24:22 +00:00
|
|
|
assert.Nil(t, a.RPC(context.Background(), "Intention.Apply", &req, &reply))
|
2018-04-05 11:53:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Web should be allowed
|
|
|
|
{
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-05-10 16:04:33 +00:00
|
|
|
Target: target,
|
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
2018-04-05 11:53:42 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, 200, resp.Code)
|
2018-04-05 11:53:42 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(obj))
|
|
|
|
assert.True(t, obj.Authorized)
|
|
|
|
assert.Contains(t, obj.Reason, "Matched")
|
2018-04-05 11:53:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// API should be denied
|
|
|
|
{
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-05-10 16:04:33 +00:00
|
|
|
Target: target,
|
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "api").URI().String(),
|
2018-04-05 11:53:42 +00:00
|
|
|
}
|
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, 200, resp.Code)
|
2018-04-05 11:53:42 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
require.NoError(t, dec.Decode(obj))
|
|
|
|
assert.False(t, obj.Authorized)
|
|
|
|
assert.Contains(t, obj.Reason, "Matched")
|
2018-04-05 11:53:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-26 01:50:05 +00:00
|
|
|
// Test that authorize fails without service:write for the target service.
|
|
|
|
func TestAgentConnectAuthorize_serviceWrite(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 01:50:05 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2018-03-26 01:50:05 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2018-03-26 01:50:05 +00:00
|
|
|
|
2021-07-20 21:52:34 +00:00
|
|
|
token := createACLTokenWithServicePolicy(t, a.srv, "read")
|
2018-03-26 01:50:05 +00:00
|
|
|
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2021-07-20 21:52:34 +00:00
|
|
|
Target: "test",
|
2018-03-28 21:29:35 +00:00
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
2018-03-26 01:50:05 +00:00
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", token)
|
2018-03-26 01:50:05 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, http.StatusForbidden, resp.Code)
|
2018-03-26 01:50:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test when no intentions match w/ a default deny policy
|
|
|
|
func TestAgentConnectAuthorize_defaultDeny(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 01:50:05 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, TestACLConfig())
|
2018-03-26 01:50:05 +00:00
|
|
|
defer a.Shutdown()
|
2018-08-06 23:46:09 +00:00
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2018-03-26 01:50:05 +00:00
|
|
|
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-03-28 21:29:35 +00:00
|
|
|
Target: "foo",
|
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
2018-03-26 01:50:05 +00:00
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-03-26 01:50:05 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, 200, resp.Code)
|
2018-03-26 01:50:05 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
|
|
|
require.NoError(t, dec.Decode(obj))
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.False(t, obj.Authorized)
|
|
|
|
assert.Contains(t, obj.Reason, "Default behavior")
|
2018-03-26 01:50:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Test when no intentions match w/ a default allow policy
|
|
|
|
func TestAgentConnectAuthorize_defaultAllow(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-03-26 01:50:05 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2018-08-06 23:46:09 +00:00
|
|
|
dc1 := "dc1"
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2022-01-20 12:47:50 +00:00
|
|
|
primary_datacenter = "`+dc1+`"
|
|
|
|
|
|
|
|
acl {
|
|
|
|
enabled = true
|
|
|
|
default_policy = "allow"
|
|
|
|
|
|
|
|
tokens {
|
|
|
|
initial_management = "root"
|
|
|
|
agent = "root"
|
|
|
|
agent_recovery = "towel"
|
|
|
|
}
|
|
|
|
}
|
2018-03-26 01:50:05 +00:00
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
2018-09-12 13:49:27 +00:00
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, dc1)
|
2018-03-26 01:50:05 +00:00
|
|
|
|
|
|
|
args := &structs.ConnectAuthorizeRequest{
|
2018-03-28 21:29:35 +00:00
|
|
|
Target: "foo",
|
|
|
|
ClientCertURI: connect.TestSpiffeIDService(t, "web").URI().String(),
|
2018-03-26 01:50:05 +00:00
|
|
|
}
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("POST", "/v1/agent/connect/authorize", jsonReader(args))
|
|
|
|
req.Header.Add("X-Consul-Token", "root")
|
2018-03-26 01:50:05 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Equal(t, 200, resp.Code)
|
2018-03-26 01:50:05 +00:00
|
|
|
|
2021-12-07 14:44:03 +00:00
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
obj := &connectAuthorizeResp{}
|
|
|
|
require.NoError(t, dec.Decode(obj))
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.True(t, obj.Authorized)
|
|
|
|
assert.Contains(t, obj.Reason, "Default behavior")
|
2018-03-26 01:50:05 +00:00
|
|
|
}
|
2018-06-13 08:34:20 +00:00
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
func TestAgent_Host(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
dc1 := "dc1"
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2022-01-20 12:47:50 +00:00
|
|
|
primary_datacenter = "`+dc1+`"
|
|
|
|
|
|
|
|
acl {
|
|
|
|
enabled = true
|
|
|
|
default_policy = "allow"
|
|
|
|
|
|
|
|
tokens {
|
|
|
|
initial_management = "initial-management"
|
|
|
|
agent = "agent"
|
|
|
|
agent_recovery = "towel"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`)
|
2018-10-17 20:20:35 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/host", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "initial-management")
|
2018-10-17 20:20:35 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
// TODO: AgentHost should write to response so that we can test using ServeHTTP()
|
2018-10-17 20:20:35 +00:00
|
|
|
respRaw, err := a.srv.AgentHost(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
assert.NotNil(t, respRaw)
|
2018-10-17 20:20:35 +00:00
|
|
|
|
|
|
|
obj := respRaw.(*debug.HostInfo)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.NotNil(t, obj.CollectionTime)
|
|
|
|
assert.Empty(t, obj.Errors)
|
2018-10-17 20:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAgent_HostBadACL(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2018-10-17 20:20:35 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
dc1 := "dc1"
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, `
|
2022-01-20 12:47:50 +00:00
|
|
|
primary_datacenter = "`+dc1+`"
|
|
|
|
|
|
|
|
acl {
|
|
|
|
enabled = true
|
|
|
|
default_policy = "deny"
|
|
|
|
|
|
|
|
tokens {
|
|
|
|
initial_management = "root"
|
|
|
|
agent = "agent"
|
|
|
|
agent_recovery = "towel"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`)
|
2018-10-17 20:20:35 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
2023-01-24 16:21:41 +00:00
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/host", nil)
|
|
|
|
req.Header.Add("X-Consul-Token", "agent")
|
2018-10-17 20:20:35 +00:00
|
|
|
resp := httptest.NewRecorder()
|
2021-12-07 14:44:03 +00:00
|
|
|
// TODO: AgentHost should write to response so that we can test using ServeHTTP()
|
|
|
|
_, err := a.srv.AgentHost(resp, req)
|
bulk rewrite using this script
set -euo pipefail
unset CDPATH
cd "$(dirname "$0")"
for f in $(git grep '\brequire := require\.New(' | cut -d':' -f1 | sort -u); do
echo "=== require: $f ==="
sed -i '/require := require.New(t)/d' $f
# require.XXX(blah) but not require.XXX(tblah) or require.XXX(rblah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\([^tr]\)/require.\1(t,\2/g' $f
# require.XXX(tblah) but not require.XXX(t, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/require.\1(t,\2/g' $f
# require.XXX(rblah) but not require.XXX(r, blah)
sed -i 's/\brequire\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/require.\1(t,\2/g' $f
gofmt -s -w $f
done
for f in $(git grep '\bassert := assert\.New(' | cut -d':' -f1 | sort -u); do
echo "=== assert: $f ==="
sed -i '/assert := assert.New(t)/d' $f
# assert.XXX(blah) but not assert.XXX(tblah) or assert.XXX(rblah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\([^tr]\)/assert.\1(t,\2/g' $f
# assert.XXX(tblah) but not assert.XXX(t, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(t[^,]\)/assert.\1(t,\2/g' $f
# assert.XXX(rblah) but not assert.XXX(r, blah)
sed -i 's/\bassert\.\([a-zA-Z0-9_]*\)(\(r[^,]\)/assert.\1(t,\2/g' $f
gofmt -s -w $f
done
2022-01-20 16:46:23 +00:00
|
|
|
assert.EqualError(t, err, "ACL not found")
|
|
|
|
assert.Equal(t, http.StatusOK, resp.Code)
|
2018-10-17 20:20:35 +00:00
|
|
|
}
|
2019-09-26 02:55:52 +00:00
|
|
|
|
2023-05-30 22:25:48 +00:00
|
|
|
func TestAgent_Version(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
dc1 := "dc1"
|
|
|
|
a := NewTestAgent(t, `
|
|
|
|
primary_datacenter = "`+dc1+`"
|
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForLeader(t, a.RPC, "dc1")
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/version", nil)
|
|
|
|
// req.Header.Add("X-Consul-Token", "initial-management")
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
respRaw, err := a.srv.AgentVersion(resp, req)
|
|
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
assert.NotNil(t, respRaw)
|
|
|
|
|
|
|
|
obj := respRaw.(*version.BuildInfo)
|
|
|
|
assert.NotNil(t, obj.HumanVersion)
|
|
|
|
}
|
|
|
|
|
2019-09-26 02:55:52 +00:00
|
|
|
// Thie tests that a proxy with an ExposeConfig is returned as expected.
|
|
|
|
func TestAgent_Services_ExposeConfig(t *testing.T) {
|
2020-12-07 18:42:55 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
2019-09-26 02:55:52 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-31 19:59:56 +00:00
|
|
|
a := NewTestAgent(t, "")
|
2019-09-26 02:55:52 +00:00
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
srv1 := &structs.NodeService{
|
|
|
|
Kind: structs.ServiceKindConnectProxy,
|
|
|
|
ID: "proxy-id",
|
|
|
|
Service: "proxy-name",
|
|
|
|
Port: 8443,
|
|
|
|
Proxy: structs.ConnectProxyConfig{
|
|
|
|
Expose: structs.ExposeConfig{
|
|
|
|
Checks: true,
|
|
|
|
Paths: []structs.ExposePath{
|
|
|
|
{
|
|
|
|
ListenerPort: 8080,
|
|
|
|
LocalPathPort: 21500,
|
|
|
|
Protocol: "http2",
|
|
|
|
Path: "/metrics",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2023-01-10 16:24:02 +00:00
|
|
|
a.State.AddServiceWithChecks(srv1, nil, "", false)
|
2019-09-26 02:55:52 +00:00
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/services", nil)
|
2021-12-07 14:44:03 +00:00
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
require.Equal(t, http.StatusOK, resp.Code)
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := make(map[string]*api.AgentService)
|
|
|
|
require.NoError(t, dec.Decode(&val))
|
2019-09-26 02:55:52 +00:00
|
|
|
require.Len(t, val, 1)
|
|
|
|
actual := val["proxy-id"]
|
|
|
|
require.NotNil(t, actual)
|
|
|
|
require.Equal(t, api.ServiceKindConnectProxy, actual.Kind)
|
2021-12-07 14:44:03 +00:00
|
|
|
// Proxy.ToAPI() creates an empty Upstream list instead of keeping nil so do the same with actual.
|
|
|
|
if actual.Proxy.Upstreams == nil {
|
|
|
|
actual.Proxy.Upstreams = make([]api.Upstream, 0)
|
|
|
|
}
|
2019-09-26 02:55:52 +00:00
|
|
|
require.Equal(t, srv1.Proxy.ToAPI(), actual.Proxy)
|
|
|
|
}
|
2023-09-12 13:38:17 +00:00
|
|
|
|
|
|
|
func TestAgent_Self_Reload(t *testing.T) {
|
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("too slow for testing.Short")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
// create new test agent
|
|
|
|
a := NewTestAgent(t, `
|
|
|
|
log_level = "info"
|
|
|
|
raft_snapshot_threshold = 100
|
|
|
|
`)
|
|
|
|
defer a.Shutdown()
|
|
|
|
|
|
|
|
testrpc.WaitForTestAgent(t, a.RPC, "dc1")
|
|
|
|
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
|
|
|
|
resp := httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec := json.NewDecoder(resp.Body)
|
|
|
|
val := &Self{}
|
|
|
|
require.NoError(t, dec.Decode(val))
|
|
|
|
|
|
|
|
require.Equal(t, "info", val.DebugConfig["Logging"].(map[string]interface{})["LogLevel"])
|
|
|
|
require.Equal(t, float64(100), val.DebugConfig["RaftSnapshotThreshold"].(float64))
|
|
|
|
|
|
|
|
// reload with new config
|
|
|
|
shim := &delegateConfigReloadShim{delegate: a.delegate}
|
|
|
|
a.delegate = shim
|
|
|
|
newCfg := TestConfig(testutil.Logger(t), config.FileSource{
|
|
|
|
Name: "Reload",
|
|
|
|
Format: "hcl",
|
|
|
|
Data: `
|
|
|
|
data_dir = "` + a.Config.DataDir + `"
|
|
|
|
log_level = "debug"
|
|
|
|
raft_snapshot_threshold = 200
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
if err := a.reloadConfigInternal(newCfg); err != nil {
|
|
|
|
t.Fatalf("got error %v want nil", err)
|
|
|
|
}
|
|
|
|
require.Equal(t, 200, shim.newCfg.RaftSnapshotThreshold)
|
|
|
|
|
|
|
|
// validate new config is reflected in API response
|
|
|
|
req, _ = http.NewRequest("GET", "/v1/agent/self", nil)
|
|
|
|
resp = httptest.NewRecorder()
|
|
|
|
a.srv.h.ServeHTTP(resp, req)
|
|
|
|
|
|
|
|
dec = json.NewDecoder(resp.Body)
|
|
|
|
val = &Self{}
|
|
|
|
require.NoError(t, dec.Decode(val))
|
|
|
|
require.Equal(t, "debug", val.DebugConfig["Logging"].(map[string]interface{})["LogLevel"])
|
|
|
|
require.Equal(t, float64(200), val.DebugConfig["RaftSnapshotThreshold"].(float64))
|
|
|
|
|
|
|
|
}
|