1package api
2
3import (
4	"context"
5	"encoding/json"
6	"errors"
7	"fmt"
8	"io/ioutil"
9	"net/http"
10	"net/http/httptest"
11	"net/http/httputil"
12	"os"
13	"path/filepath"
14	"strings"
15	"testing"
16	"time"
17
18	"github.com/hashicorp/consul/sdk/testutil"
19	"github.com/hashicorp/consul/sdk/testutil/retry"
20	"github.com/hashicorp/serf/serf"
21	"github.com/stretchr/testify/require"
22)
23
24func TestAPI_AgentSelf(t *testing.T) {
25	t.Parallel()
26	c, s := makeClient(t)
27	defer s.Stop()
28
29	agent := c.Agent()
30
31	info, err := agent.Self()
32	if err != nil {
33		t.Fatalf("err: %v", err)
34	}
35
36	name := info["Config"]["NodeName"].(string)
37	if name == "" {
38		t.Fatalf("bad: %v", info)
39	}
40}
41
42func TestAPI_AgentMetrics(t *testing.T) {
43	t.Parallel()
44	c, s := makeClient(t)
45	defer s.Stop()
46
47	agent := c.Agent()
48	s.WaitForSerfCheck(t)
49
50	timer := &retry.Timer{Timeout: 10 * time.Second, Wait: 500 * time.Millisecond}
51	retry.RunWith(timer, t, func(r *retry.R) {
52		metrics, err := agent.Metrics()
53		if err != nil {
54			r.Fatalf("err: %v", err)
55		}
56		for _, g := range metrics.Gauges {
57			if g.Name == "consul.runtime.alloc_bytes" {
58				return
59			}
60		}
61		r.Fatalf("missing runtime metrics")
62	})
63}
64
65func TestAPI_AgentHost(t *testing.T) {
66	t.Parallel()
67	c, s := makeClient(t)
68	defer s.Stop()
69
70	agent := c.Agent()
71	timer := &retry.Timer{}
72	retry.RunWith(timer, t, func(r *retry.R) {
73		host, err := agent.Host()
74		if err != nil {
75			r.Fatalf("err: %v", err)
76		}
77
78		// CollectionTime should exist on all responses
79		if host["CollectionTime"] == nil {
80			r.Fatalf("missing host response")
81		}
82	})
83}
84
85func TestAPI_AgentReload(t *testing.T) {
86	t.Parallel()
87
88	// Create our initial empty config file, to be overwritten later
89	cfgDir := testutil.TempDir(t, "consul-config")
90
91	cfgFilePath := filepath.Join(cfgDir, "reload.json")
92	configFile, err := os.Create(cfgFilePath)
93	if err != nil {
94		t.Fatalf("Unable to create file %v, got error:%v", cfgFilePath, err)
95	}
96
97	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
98		conf.Args = []string{"-config-file", configFile.Name()}
99	})
100	defer s.Stop()
101
102	agent := c.Agent()
103
104	// Update the config file with a service definition
105	config := `{"service":{"name":"redis", "port":1234, "Meta": {"some": "meta"}}}`
106	err = ioutil.WriteFile(configFile.Name(), []byte(config), 0644)
107	if err != nil {
108		t.Fatalf("err: %v", err)
109	}
110
111	if err = agent.Reload(); err != nil {
112		t.Fatalf("err: %v", err)
113	}
114
115	services, err := agent.Services()
116	if err != nil {
117		t.Fatalf("err: %v", err)
118	}
119
120	service, ok := services["redis"]
121	if !ok {
122		t.Fatalf("bad: %v", ok)
123	}
124	if service.Port != 1234 {
125		t.Fatalf("bad: %v", service.Port)
126	}
127	if service.Meta["some"] != "meta" {
128		t.Fatalf("Missing metadata some:=meta in %v", service)
129	}
130}
131
132func TestAPI_AgentMembersOpts(t *testing.T) {
133	t.Parallel()
134	c, s1 := makeClient(t)
135	_, s2 := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
136		c.Datacenter = "dc2"
137	})
138	defer s1.Stop()
139	defer s2.Stop()
140
141	agent := c.Agent()
142
143	s2.JoinWAN(t, s1.WANAddr)
144
145	members, err := agent.MembersOpts(MembersOpts{WAN: true})
146	if err != nil {
147		t.Fatalf("err: %v", err)
148	}
149
150	if len(members) != 2 {
151		t.Fatalf("bad: %v", members)
152	}
153}
154
155func TestAPI_AgentMembers(t *testing.T) {
156	t.Parallel()
157	c, s := makeClient(t)
158	defer s.Stop()
159
160	agent := c.Agent()
161
162	members, err := agent.Members(false)
163	if err != nil {
164		t.Fatalf("err: %v", err)
165	}
166
167	if len(members) != 1 {
168		t.Fatalf("bad: %v", members)
169	}
170}
171
172func TestAPI_AgentServiceAndReplaceChecks(t *testing.T) {
173	t.Parallel()
174	c, s := makeClient(t)
175	defer s.Stop()
176
177	agent := c.Agent()
178	s.WaitForSerfCheck(t)
179
180	reg := &AgentServiceRegistration{
181		Name: "foo",
182		ID:   "foo",
183		Tags: []string{"bar", "baz"},
184		TaggedAddresses: map[string]ServiceAddress{
185			"lan": {
186				Address: "198.18.0.1",
187				Port:    80,
188			},
189		},
190		Port: 8000,
191		Check: &AgentServiceCheck{
192			TTL: "15s",
193		},
194	}
195
196	regupdate := &AgentServiceRegistration{
197		Name: "foo",
198		ID:   "foo",
199		Tags: []string{"bar", "baz"},
200		TaggedAddresses: map[string]ServiceAddress{
201			"lan": {
202				Address: "198.18.0.1",
203				Port:    80,
204			},
205		},
206		Port: 9000,
207	}
208
209	if err := agent.ServiceRegister(reg); err != nil {
210		t.Fatalf("err: %v", err)
211	}
212
213	ctx := context.Background()
214	opts := ServiceRegisterOpts{ReplaceExistingChecks: true}.WithContext(ctx)
215	if err := agent.ServiceRegisterOpts(regupdate, opts); err != nil {
216		t.Fatalf("err: %v", err)
217	}
218
219	services, err := agent.Services()
220	if err != nil {
221		t.Fatalf("err: %v", err)
222	}
223
224	if _, ok := services["foo"]; !ok {
225		t.Fatalf("missing service: %#v", services)
226	}
227
228	checks, err := agent.Checks()
229	if err != nil {
230		t.Fatalf("err: %v", err)
231	}
232
233	if len(checks) != 0 {
234		t.Fatalf("checks are not removed: %v", checks)
235	}
236
237	state, out, err := agent.AgentHealthServiceByID("foo")
238	require.Nil(t, err)
239	require.NotNil(t, out)
240	require.Equal(t, HealthPassing, state)
241	require.Equal(t, 9000, out.Service.Port)
242
243	state, outs, err := agent.AgentHealthServiceByName("foo")
244	require.Nil(t, err)
245	require.NotNil(t, outs)
246	require.Equal(t, HealthPassing, state)
247	require.Equal(t, 9000, outs[0].Service.Port)
248
249	if err := agent.ServiceDeregister("foo"); err != nil {
250		t.Fatalf("err: %v", err)
251	}
252}
253
254func TestAgent_ServiceRegisterOpts_WithContextTimeout(t *testing.T) {
255	c, err := NewClient(DefaultConfig())
256	require.NoError(t, err)
257
258	ctx, cancel := context.WithTimeout(context.Background(), time.Nanosecond)
259	t.Cleanup(cancel)
260
261	opts := ServiceRegisterOpts{}.WithContext(ctx)
262	err = c.Agent().ServiceRegisterOpts(&AgentServiceRegistration{}, opts)
263	require.True(t, errors.Is(err, context.DeadlineExceeded), "expected timeout")
264}
265
266func TestAPI_AgentServices(t *testing.T) {
267	t.Parallel()
268	c, s := makeClient(t)
269	defer s.Stop()
270
271	agent := c.Agent()
272	s.WaitForSerfCheck(t)
273
274	reg := &AgentServiceRegistration{
275		Name: "foo",
276		ID:   "foo",
277		Tags: []string{"bar", "baz"},
278		TaggedAddresses: map[string]ServiceAddress{
279			"lan": {
280				Address: "198.18.0.1",
281				Port:    80,
282			},
283		},
284		Port: 8000,
285		Check: &AgentServiceCheck{
286			TTL: "15s",
287		},
288	}
289	if err := agent.ServiceRegister(reg); err != nil {
290		t.Fatalf("err: %v", err)
291	}
292
293	services, err := agent.Services()
294	if err != nil {
295		t.Fatalf("err: %v", err)
296	}
297	if _, ok := services["foo"]; !ok {
298		t.Fatalf("missing service: %#v", services)
299	}
300	checks, err := agent.Checks()
301	if err != nil {
302		t.Fatalf("err: %v", err)
303	}
304	chk, ok := checks["service:foo"]
305	if !ok {
306		t.Fatalf("missing check: %v", checks)
307	}
308
309	// Checks should default to critical
310	if chk.Status != HealthCritical {
311		t.Fatalf("Bad: %#v", chk)
312	}
313
314	state, out, err := agent.AgentHealthServiceByID("foo2")
315	require.Nil(t, err)
316	require.Nil(t, out)
317	require.Equal(t, HealthCritical, state)
318
319	state, out, err = agent.AgentHealthServiceByID("foo")
320	require.Nil(t, err)
321	require.NotNil(t, out)
322	require.Equal(t, HealthCritical, state)
323	require.Equal(t, 8000, out.Service.Port)
324
325	state, outs, err := agent.AgentHealthServiceByName("foo")
326	require.Nil(t, err)
327	require.NotNil(t, outs)
328	require.Equal(t, HealthCritical, state)
329	require.Equal(t, 8000, outs[0].Service.Port)
330
331	if err := agent.ServiceDeregister("foo"); err != nil {
332		t.Fatalf("err: %v", err)
333	}
334}
335
336func TestAPI_AgentServicesWithFilterOpts(t *testing.T) {
337	t.Parallel()
338	c, s := makeClient(t)
339	defer s.Stop()
340
341	agent := c.Agent()
342
343	reg := &AgentServiceRegistration{
344		Name: "foo",
345		ID:   "foo",
346		Tags: []string{"bar", "baz"},
347		Port: 8000,
348		Check: &AgentServiceCheck{
349			TTL: "15s",
350		},
351	}
352	require.NoError(t, agent.ServiceRegister(reg))
353
354	reg = &AgentServiceRegistration{
355		Name: "foo",
356		ID:   "foo2",
357		Tags: []string{"foo", "baz"},
358		Port: 8001,
359		Check: &AgentServiceCheck{
360			TTL: "15s",
361		},
362	}
363	require.NoError(t, agent.ServiceRegister(reg))
364
365	opts := &QueryOptions{Namespace: defaultNamespace}
366	services, err := agent.ServicesWithFilterOpts("foo in Tags", opts)
367	require.NoError(t, err)
368	require.Len(t, services, 1)
369	_, ok := services["foo2"]
370	require.True(t, ok)
371}
372
373func TestAPI_AgentServices_SidecarService(t *testing.T) {
374	t.Parallel()
375	c, s := makeClient(t)
376	defer s.Stop()
377
378	agent := c.Agent()
379
380	// Register service
381	reg := &AgentServiceRegistration{
382		Name: "foo",
383		Port: 8000,
384		Connect: &AgentServiceConnect{
385			SidecarService: &AgentServiceRegistration{},
386		},
387	}
388	if err := agent.ServiceRegister(reg); err != nil {
389		t.Fatalf("err: %v", err)
390	}
391
392	services, err := agent.Services()
393	if err != nil {
394		t.Fatalf("err: %v", err)
395	}
396	if _, ok := services["foo"]; !ok {
397		t.Fatalf("missing service: %v", services)
398	}
399	if _, ok := services["foo-sidecar-proxy"]; !ok {
400		t.Fatalf("missing sidecar service: %v", services)
401	}
402
403	if err := agent.ServiceDeregister("foo"); err != nil {
404		t.Fatalf("err: %v", err)
405	}
406
407	// Deregister should have removed both service and it's sidecar
408	services, err = agent.Services()
409	require.NoError(t, err)
410
411	if _, ok := services["foo"]; ok {
412		t.Fatalf("didn't remove service: %v", services)
413	}
414	if _, ok := services["foo-sidecar-proxy"]; ok {
415		t.Fatalf("didn't remove sidecar service: %v", services)
416	}
417}
418
419func TestAPI_AgentServices_ExternalConnectProxy(t *testing.T) {
420	t.Parallel()
421	c, s := makeClient(t)
422	defer s.Stop()
423
424	agent := c.Agent()
425
426	// Register service
427	reg := &AgentServiceRegistration{
428		Name: "foo",
429		Port: 8000,
430	}
431	if err := agent.ServiceRegister(reg); err != nil {
432		t.Fatalf("err: %v", err)
433	}
434	// Register proxy
435	reg = &AgentServiceRegistration{
436		Kind: ServiceKindConnectProxy,
437		Name: "foo-proxy",
438		Port: 8001,
439		Proxy: &AgentServiceConnectProxyConfig{
440			DestinationServiceName: "foo",
441			Mode:                   ProxyModeTransparent,
442		},
443	}
444	if err := agent.ServiceRegister(reg); err != nil {
445		t.Fatalf("err: %v", err)
446	}
447
448	services, err := agent.Services()
449	if err != nil {
450		t.Fatalf("err: %v", err)
451	}
452	if _, ok := services["foo"]; !ok {
453		t.Fatalf("missing service: %v", services)
454	}
455	if _, ok := services["foo-proxy"]; !ok {
456		t.Fatalf("missing proxy service: %v", services)
457	}
458	if services["foo-proxy"].Proxy.Mode != ProxyModeTransparent {
459		t.Fatalf("expected transparent proxy mode to be enabled")
460	}
461
462	if err := agent.ServiceDeregister("foo"); err != nil {
463		t.Fatalf("err: %v", err)
464	}
465	if err := agent.ServiceDeregister("foo-proxy"); err != nil {
466		t.Fatalf("err: %v", err)
467	}
468}
469
470func TestAPI_AgentServices_CheckPassing(t *testing.T) {
471	t.Parallel()
472	c, s := makeClient(t)
473	defer s.Stop()
474
475	agent := c.Agent()
476	reg := &AgentServiceRegistration{
477		Name: "foo",
478		Tags: []string{"bar", "baz"},
479		Port: 8000,
480		Check: &AgentServiceCheck{
481			TTL:    "15s",
482			Status: HealthPassing,
483		},
484	}
485	if err := agent.ServiceRegister(reg); err != nil {
486		t.Fatalf("err: %v", err)
487	}
488
489	services, err := agent.Services()
490	if err != nil {
491		t.Fatalf("err: %v", err)
492	}
493	if _, ok := services["foo"]; !ok {
494		t.Fatalf("missing service: %v", services)
495	}
496
497	checks, err := agent.Checks()
498	if err != nil {
499		t.Fatalf("err: %v", err)
500	}
501	chk, ok := checks["service:foo"]
502	if !ok {
503		t.Fatalf("missing check: %v", checks)
504	}
505
506	if chk.Status != HealthPassing {
507		t.Fatalf("Bad: %#v", chk)
508	}
509	if err := agent.ServiceDeregister("foo"); err != nil {
510		t.Fatalf("err: %v", err)
511	}
512}
513
514func TestAPI_AgentServices_CheckBadStatus(t *testing.T) {
515	t.Parallel()
516	c, s := makeClient(t)
517	defer s.Stop()
518
519	agent := c.Agent()
520	reg := &AgentServiceRegistration{
521		Name: "foo",
522		Tags: []string{"bar", "baz"},
523		Port: 8000,
524		Check: &AgentServiceCheck{
525			TTL:    "15s",
526			Status: "fluffy",
527		},
528	}
529	if err := agent.ServiceRegister(reg); err == nil {
530		t.Fatalf("bad status accepted")
531	}
532}
533
534func TestAPI_AgentServices_CheckID(t *testing.T) {
535	t.Parallel()
536	c, s := makeClient(t)
537	defer s.Stop()
538
539	agent := c.Agent()
540	reg := &AgentServiceRegistration{
541		Name: "foo",
542		Tags: []string{"bar", "baz"},
543		Port: 8000,
544		Check: &AgentServiceCheck{
545			CheckID: "foo-ttl",
546			TTL:     "15s",
547		},
548	}
549	if err := agent.ServiceRegister(reg); err != nil {
550		t.Fatalf("err: %v", err)
551	}
552
553	checks, err := agent.Checks()
554	if err != nil {
555		t.Fatalf("err: %v", err)
556	}
557	if _, ok := checks["foo-ttl"]; !ok {
558		t.Fatalf("missing check: %v", checks)
559	}
560}
561
562func TestAPI_AgentServiceAddress(t *testing.T) {
563	t.Parallel()
564	c, s := makeClient(t)
565	defer s.Stop()
566
567	agent := c.Agent()
568
569	reg1 := &AgentServiceRegistration{
570		Name:    "foo1",
571		Port:    8000,
572		Address: "192.168.0.42",
573	}
574	reg2 := &AgentServiceRegistration{
575		Name: "foo2",
576		Port: 8000,
577		TaggedAddresses: map[string]ServiceAddress{
578			"lan": {
579				Address: "192.168.0.43",
580				Port:    8000,
581			},
582			"wan": {
583				Address: "198.18.0.1",
584				Port:    80,
585			},
586		},
587	}
588	if err := agent.ServiceRegister(reg1); err != nil {
589		t.Fatalf("err: %v", err)
590	}
591	if err := agent.ServiceRegister(reg2); err != nil {
592		t.Fatalf("err: %v", err)
593	}
594
595	services, err := agent.Services()
596	if err != nil {
597		t.Fatalf("err: %v", err)
598	}
599
600	if _, ok := services["foo1"]; !ok {
601		t.Fatalf("missing service: %v", services)
602	}
603	if _, ok := services["foo2"]; !ok {
604		t.Fatalf("missing service: %v", services)
605	}
606
607	if services["foo1"].Address != "192.168.0.42" {
608		t.Fatalf("missing Address field in service foo1: %v", services)
609	}
610	if services["foo2"].Address != "" {
611		t.Fatalf("missing Address field in service foo2: %v", services)
612	}
613	require.NotNil(t, services["foo2"].TaggedAddresses)
614	require.Contains(t, services["foo2"].TaggedAddresses, "lan")
615	require.Contains(t, services["foo2"].TaggedAddresses, "wan")
616	require.Equal(t, services["foo2"].TaggedAddresses["lan"].Address, "192.168.0.43")
617	require.Equal(t, services["foo2"].TaggedAddresses["lan"].Port, 8000)
618	require.Equal(t, services["foo2"].TaggedAddresses["wan"].Address, "198.18.0.1")
619	require.Equal(t, services["foo2"].TaggedAddresses["wan"].Port, 80)
620
621	if err := agent.ServiceDeregister("foo"); err != nil {
622		t.Fatalf("err: %v", err)
623	}
624}
625
626func TestAPI_AgentEnableTagOverride(t *testing.T) {
627	t.Parallel()
628	c, s := makeClient(t)
629	defer s.Stop()
630
631	agent := c.Agent()
632
633	reg1 := &AgentServiceRegistration{
634		Name:              "foo1",
635		Port:              8000,
636		Address:           "192.168.0.42",
637		EnableTagOverride: true,
638	}
639	reg2 := &AgentServiceRegistration{
640		Name: "foo2",
641		Port: 8000,
642	}
643	if err := agent.ServiceRegister(reg1); err != nil {
644		t.Fatalf("err: %v", err)
645	}
646	if err := agent.ServiceRegister(reg2); err != nil {
647		t.Fatalf("err: %v", err)
648	}
649
650	services, err := agent.Services()
651	if err != nil {
652		t.Fatalf("err: %v", err)
653	}
654
655	if _, ok := services["foo1"]; !ok {
656		t.Fatalf("missing service: %v", services)
657	}
658	if services["foo1"].EnableTagOverride != true {
659		t.Fatalf("tag override not set on service foo1: %v", services)
660	}
661	if _, ok := services["foo2"]; !ok {
662		t.Fatalf("missing service: %v", services)
663	}
664	if services["foo2"].EnableTagOverride != false {
665		t.Fatalf("tag override set on service foo2: %v", services)
666	}
667}
668
669func TestAPI_AgentServices_MultipleChecks(t *testing.T) {
670	t.Parallel()
671	c, s := makeClient(t)
672	defer s.Stop()
673
674	agent := c.Agent()
675
676	reg := &AgentServiceRegistration{
677		Name: "foo",
678		Tags: []string{"bar", "baz"},
679		Port: 8000,
680		Checks: AgentServiceChecks{
681			&AgentServiceCheck{
682				TTL: "15s",
683			},
684			&AgentServiceCheck{
685				TTL: "30s",
686			},
687		},
688	}
689	if err := agent.ServiceRegister(reg); err != nil {
690		t.Fatalf("err: %v", err)
691	}
692
693	services, err := agent.Services()
694	if err != nil {
695		t.Fatalf("err: %v", err)
696	}
697	if _, ok := services["foo"]; !ok {
698		t.Fatalf("missing service: %v", services)
699	}
700
701	checks, err := agent.Checks()
702	if err != nil {
703		t.Fatalf("err: %v", err)
704	}
705	if _, ok := checks["service:foo:1"]; !ok {
706		t.Fatalf("missing check: %v", checks)
707	}
708	if _, ok := checks["service:foo:2"]; !ok {
709		t.Fatalf("missing check: %v", checks)
710	}
711}
712
713func TestAPI_AgentService(t *testing.T) {
714	t.Parallel()
715	c, s := makeClient(t)
716	defer s.Stop()
717
718	agent := c.Agent()
719
720	require := require.New(t)
721
722	reg := &AgentServiceRegistration{
723		Name: "foo",
724		Tags: []string{"bar", "baz"},
725		Port: 8000,
726		Checks: AgentServiceChecks{
727			&AgentServiceCheck{
728				TTL: "15s",
729			},
730			&AgentServiceCheck{
731				TTL: "30s",
732			},
733		},
734	}
735	require.NoError(agent.ServiceRegister(reg))
736
737	got, qm, err := agent.Service("foo", nil)
738	require.NoError(err)
739
740	expect := &AgentService{
741		ID:          "foo",
742		Service:     "foo",
743		Tags:        []string{"bar", "baz"},
744		ContentHash: "f72563cae6924fb5",
745		Port:        8000,
746		Weights: AgentWeights{
747			Passing: 1,
748			Warning: 1,
749		},
750		Meta:       map[string]string{},
751		Namespace:  defaultNamespace,
752		Datacenter: "dc1",
753	}
754	require.Equal(expect, got)
755	require.Equal(expect.ContentHash, qm.LastContentHash)
756
757	// Sanity check blocking behavior - this is more thoroughly tested in the
758	// agent endpoint tests but this ensures that the API package is at least
759	// passing the hash param properly.
760	opts := QueryOptions{
761		WaitHash: qm.LastContentHash,
762		WaitTime: 100 * time.Millisecond, // Just long enough to be reliably measurable
763	}
764	start := time.Now()
765	_, _, err = agent.Service("foo", &opts)
766	elapsed := time.Since(start)
767	require.NoError(err)
768	require.True(elapsed >= opts.WaitTime)
769}
770
771func TestAPI_AgentSetTTLStatus(t *testing.T) {
772	t.Parallel()
773	c, s := makeClient(t)
774	defer s.Stop()
775
776	agent := c.Agent()
777	s.WaitForSerfCheck(t)
778
779	reg := &AgentServiceRegistration{
780		Name: "foo",
781		Check: &AgentServiceCheck{
782			TTL: "15s",
783		},
784	}
785	if err := agent.ServiceRegister(reg); err != nil {
786		t.Fatalf("err: %v", err)
787	}
788
789	verify := func(status, output string) {
790		checks, err := agent.Checks()
791		if err != nil {
792			t.Fatalf("err: %v", err)
793		}
794		chk, ok := checks["service:foo"]
795		if !ok {
796			t.Fatalf("missing check: %v", checks)
797		}
798		if chk.Status != status {
799			t.Fatalf("Bad: %#v", chk)
800		}
801		if chk.Output != output {
802			t.Fatalf("Bad: %#v", chk)
803		}
804	}
805
806	if err := agent.WarnTTL("service:foo", "foo"); err != nil {
807		t.Fatalf("err: %v", err)
808	}
809	verify(HealthWarning, "foo")
810
811	if err := agent.PassTTL("service:foo", "bar"); err != nil {
812		t.Fatalf("err: %v", err)
813	}
814	verify(HealthPassing, "bar")
815
816	if err := agent.FailTTL("service:foo", "baz"); err != nil {
817		t.Fatalf("err: %v", err)
818	}
819	verify(HealthCritical, "baz")
820
821	if err := agent.UpdateTTL("service:foo", "foo", "warn"); err != nil {
822		t.Fatalf("err: %v", err)
823	}
824	verify(HealthWarning, "foo")
825
826	if err := agent.UpdateTTL("service:foo", "bar", "pass"); err != nil {
827		t.Fatalf("err: %v", err)
828	}
829	verify(HealthPassing, "bar")
830
831	if err := agent.UpdateTTL("service:foo", "baz", "fail"); err != nil {
832		t.Fatalf("err: %v", err)
833	}
834	verify(HealthCritical, "baz")
835
836	if err := agent.UpdateTTL("service:foo", "foo", HealthWarning); err != nil {
837		t.Fatalf("err: %v", err)
838	}
839	verify(HealthWarning, "foo")
840
841	if err := agent.UpdateTTL("service:foo", "bar", HealthPassing); err != nil {
842		t.Fatalf("err: %v", err)
843	}
844	verify(HealthPassing, "bar")
845
846	if err := agent.UpdateTTL("service:foo", "baz", HealthCritical); err != nil {
847		t.Fatalf("err: %v", err)
848	}
849	verify(HealthCritical, "baz")
850
851	if err := agent.ServiceDeregister("foo"); err != nil {
852		t.Fatalf("err: %v", err)
853	}
854}
855
856func TestAPI_AgentUpdateTTLOpts(t *testing.T) {
857	t.Parallel()
858	c, s := makeClient(t)
859	defer s.Stop()
860
861	agent := c.Agent()
862	s.WaitForSerfCheck(t)
863
864	reg := &AgentServiceRegistration{
865		Name: "foo",
866		Check: &AgentServiceCheck{
867			TTL: "15s",
868		},
869	}
870	if err := agent.ServiceRegister(reg); err != nil {
871		t.Fatalf("err: %v", err)
872	}
873
874	verify := func(status, output string) {
875		checks, err := agent.Checks()
876		if err != nil {
877			t.Fatalf("err: %v", err)
878		}
879		chk, ok := checks["service:foo"]
880		if !ok {
881			t.Fatalf("missing check: %v", checks)
882		}
883		if chk.Status != status {
884			t.Fatalf("Bad: %#v", chk)
885		}
886		if chk.Output != output {
887			t.Fatalf("Bad: %#v", chk)
888		}
889	}
890
891	opts := &QueryOptions{Namespace: defaultNamespace}
892
893	if err := agent.UpdateTTLOpts("service:foo", "foo", HealthWarning, opts); err != nil {
894		t.Fatalf("err: %v", err)
895	}
896	verify(HealthWarning, "foo")
897
898	if err := agent.UpdateTTLOpts("service:foo", "bar", HealthPassing, opts); err != nil {
899		t.Fatalf("err: %v", err)
900	}
901	verify(HealthPassing, "bar")
902
903	if err := agent.UpdateTTL("service:foo", "baz", HealthCritical); err != nil {
904		t.Fatalf("err: %v", err)
905	}
906	verify(HealthCritical, "baz")
907
908	if err := agent.ServiceDeregister("foo"); err != nil {
909		t.Fatalf("err: %v", err)
910	}
911}
912
913func TestAPI_AgentChecks(t *testing.T) {
914	t.Parallel()
915	c, s := makeClient(t)
916	defer s.Stop()
917
918	agent := c.Agent()
919
920	reg := &AgentCheckRegistration{
921		Name: "foo",
922	}
923	reg.TTL = "15s"
924	if err := agent.CheckRegister(reg); err != nil {
925		t.Fatalf("err: %v", err)
926	}
927
928	checks, err := agent.Checks()
929	if err != nil {
930		t.Fatalf("err: %v", err)
931	}
932	chk, ok := checks["foo"]
933	if !ok {
934		t.Fatalf("missing check: %v", checks)
935	}
936	if chk.Status != HealthCritical {
937		t.Fatalf("check not critical: %v", chk)
938	}
939	if chk.Type != "ttl" {
940		t.Fatalf("expected type ttl, got %s", chk.Type)
941	}
942
943	if err := agent.CheckDeregister("foo"); err != nil {
944		t.Fatalf("err: %v", err)
945	}
946}
947
948func TestAPI_AgentChecksWithFilterOpts(t *testing.T) {
949	t.Parallel()
950	c, s := makeClient(t)
951	defer s.Stop()
952
953	agent := c.Agent()
954
955	reg := &AgentCheckRegistration{
956		Name: "foo",
957	}
958	reg.TTL = "15s"
959	require.NoError(t, agent.CheckRegister(reg))
960	reg = &AgentCheckRegistration{
961		Name: "bar",
962	}
963	reg.TTL = "15s"
964	require.NoError(t, agent.CheckRegister(reg))
965
966	opts := &QueryOptions{Namespace: defaultNamespace}
967	checks, err := agent.ChecksWithFilterOpts("Name == foo", opts)
968	require.NoError(t, err)
969	require.Len(t, checks, 1)
970	_, ok := checks["foo"]
971	require.True(t, ok)
972}
973
974func TestAPI_AgentScriptCheck(t *testing.T) {
975	t.Parallel()
976	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
977		c.EnableScriptChecks = true
978	})
979	defer s.Stop()
980
981	agent := c.Agent()
982
983	t.Run("node script check", func(t *testing.T) {
984		reg := &AgentCheckRegistration{
985			Name: "foo",
986			AgentServiceCheck: AgentServiceCheck{
987				Interval: "10s",
988				Args:     []string{"sh", "-c", "false"},
989			},
990		}
991		if err := agent.CheckRegister(reg); err != nil {
992			t.Fatalf("err: %v", err)
993		}
994
995		checks, err := agent.Checks()
996		if err != nil {
997			t.Fatalf("err: %v", err)
998		}
999		if _, ok := checks["foo"]; !ok {
1000			t.Fatalf("missing check: %v", checks)
1001		}
1002	})
1003
1004	t.Run("service script check", func(t *testing.T) {
1005		reg := &AgentServiceRegistration{
1006			Name: "bar",
1007			Port: 1234,
1008			Checks: AgentServiceChecks{
1009				&AgentServiceCheck{
1010					Interval: "10s",
1011					Args:     []string{"sh", "-c", "false"},
1012				},
1013			},
1014		}
1015		if err := agent.ServiceRegister(reg); err != nil {
1016			t.Fatalf("err: %v", err)
1017		}
1018
1019		services, err := agent.Services()
1020		if err != nil {
1021			t.Fatalf("err: %v", err)
1022		}
1023		if _, ok := services["bar"]; !ok {
1024			t.Fatalf("missing service: %v", services)
1025		}
1026
1027		checks, err := agent.Checks()
1028		if err != nil {
1029			t.Fatalf("err: %v", err)
1030		}
1031		if _, ok := checks["service:bar"]; !ok {
1032			t.Fatalf("missing check: %v", checks)
1033		}
1034	})
1035}
1036
1037func TestAPI_AgentCheckStartPassing(t *testing.T) {
1038	t.Parallel()
1039	c, s := makeClient(t)
1040	defer s.Stop()
1041
1042	agent := c.Agent()
1043
1044	reg := &AgentCheckRegistration{
1045		Name: "foo",
1046		AgentServiceCheck: AgentServiceCheck{
1047			Status: HealthPassing,
1048		},
1049	}
1050	reg.TTL = "15s"
1051	if err := agent.CheckRegister(reg); err != nil {
1052		t.Fatalf("err: %v", err)
1053	}
1054
1055	checks, err := agent.Checks()
1056	if err != nil {
1057		t.Fatalf("err: %v", err)
1058	}
1059	chk, ok := checks["foo"]
1060	if !ok {
1061		t.Fatalf("missing check: %v", checks)
1062	}
1063	if chk.Status != HealthPassing {
1064		t.Fatalf("check not passing: %v", chk)
1065	}
1066
1067	if err := agent.CheckDeregister("foo"); err != nil {
1068		t.Fatalf("err: %v", err)
1069	}
1070}
1071
1072func TestAPI_AgentChecks_serviceBound(t *testing.T) {
1073	t.Parallel()
1074	c, s := makeClient(t)
1075	defer s.Stop()
1076
1077	agent := c.Agent()
1078	s.WaitForSerfCheck(t)
1079
1080	// First register a service
1081	serviceReg := &AgentServiceRegistration{
1082		Name: "redis",
1083	}
1084	if err := agent.ServiceRegister(serviceReg); err != nil {
1085		t.Fatalf("err: %v", err)
1086	}
1087
1088	// Register a check bound to the service
1089	reg := &AgentCheckRegistration{
1090		Name:      "redischeck",
1091		ServiceID: "redis",
1092	}
1093	reg.TTL = "15s"
1094	reg.DeregisterCriticalServiceAfter = "nope"
1095	err := agent.CheckRegister(reg)
1096	if err == nil || !strings.Contains(err.Error(), "invalid duration") {
1097		t.Fatalf("err: %v", err)
1098	}
1099
1100	reg.DeregisterCriticalServiceAfter = "90m"
1101	if err := agent.CheckRegister(reg); err != nil {
1102		t.Fatalf("err: %v", err)
1103	}
1104
1105	checks, err := agent.Checks()
1106	if err != nil {
1107		t.Fatalf("err: %v", err)
1108	}
1109
1110	check, ok := checks["redischeck"]
1111	if !ok {
1112		t.Fatalf("missing check: %v", checks)
1113	}
1114	if check.ServiceID != "redis" {
1115		t.Fatalf("missing service association for check: %v", check)
1116	}
1117	if check.Type != "ttl" {
1118		t.Fatalf("expected type ttl, got %s", check.Type)
1119	}
1120}
1121
1122func TestAPI_AgentChecks_Docker(t *testing.T) {
1123	t.Parallel()
1124	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
1125		c.EnableScriptChecks = true
1126	})
1127	defer s.Stop()
1128
1129	agent := c.Agent()
1130
1131	// First register a service
1132	serviceReg := &AgentServiceRegistration{
1133		Name: "redis",
1134	}
1135	if err := agent.ServiceRegister(serviceReg); err != nil {
1136		t.Fatalf("err: %v", err)
1137	}
1138
1139	// Register a check bound to the service
1140	reg := &AgentCheckRegistration{
1141		Name:      "redischeck",
1142		ServiceID: "redis",
1143		AgentServiceCheck: AgentServiceCheck{
1144			DockerContainerID: "f972c95ebf0e",
1145			Args:              []string{"/bin/true"},
1146			Shell:             "/bin/bash",
1147			Interval:          "10s",
1148		},
1149	}
1150	if err := agent.CheckRegister(reg); err != nil {
1151		t.Fatalf("err: %v", err)
1152	}
1153
1154	checks, err := agent.Checks()
1155	if err != nil {
1156		t.Fatalf("err: %v", err)
1157	}
1158
1159	check, ok := checks["redischeck"]
1160	if !ok {
1161		t.Fatalf("missing check: %v", checks)
1162	}
1163	if check.ServiceID != "redis" {
1164		t.Fatalf("missing service association for check: %v", check)
1165	}
1166	if check.Type != "docker" {
1167		t.Fatalf("expected type docker, got %s", check.Type)
1168	}
1169}
1170
1171func TestAPI_AgentJoin(t *testing.T) {
1172	t.Parallel()
1173	c, s := makeClient(t)
1174	defer s.Stop()
1175
1176	agent := c.Agent()
1177
1178	info, err := agent.Self()
1179	if err != nil {
1180		t.Fatalf("err: %v", err)
1181	}
1182
1183	// Join ourself
1184	addr := info["DebugConfig"]["SerfAdvertiseAddrLAN"].(string)
1185	// strip off 'tcp://'
1186	addr = addr[len("tcp://"):]
1187	err = agent.Join(addr, false)
1188	if err != nil {
1189		t.Fatalf("err: %v", err)
1190	}
1191}
1192
1193func TestAPI_AgentLeave(t *testing.T) {
1194	t.Parallel()
1195	c1, s1 := makeClient(t)
1196	defer s1.Stop()
1197
1198	c2, s2 := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
1199		conf.Server = false
1200		conf.Bootstrap = false
1201	})
1202	defer s2.Stop()
1203
1204	if err := c2.Agent().Join(s1.LANAddr, false); err != nil {
1205		t.Fatalf("err: %v", err)
1206	}
1207
1208	// We sometimes see an EOF response to this one, depending on timing.
1209	err := c2.Agent().Leave()
1210	if err != nil && !strings.Contains(err.Error(), "EOF") {
1211		t.Fatalf("err: %v", err)
1212	}
1213
1214	// Make sure the second agent's status is 'Left'
1215	members, err := c1.Agent().Members(false)
1216	if err != nil {
1217		t.Fatalf("err: %v", err)
1218	}
1219	member := members[0]
1220	if member.Name == s1.Config.NodeName {
1221		member = members[1]
1222	}
1223	if member.Status != int(serf.StatusLeft) {
1224		t.Fatalf("bad: %v", *member)
1225	}
1226}
1227
1228func TestAPI_AgentForceLeave(t *testing.T) {
1229	t.Parallel()
1230	c, s := makeClient(t)
1231	defer s.Stop()
1232
1233	agent := c.Agent()
1234
1235	// Eject somebody
1236	err := agent.ForceLeave(s.Config.NodeName)
1237	if err != nil {
1238		t.Fatalf("err: %v", err)
1239	}
1240}
1241
1242func TestAPI_AgentForceLeavePrune(t *testing.T) {
1243	t.Parallel()
1244	c, s := makeClient(t)
1245	defer s.Stop()
1246
1247	agent := c.Agent()
1248
1249	// Eject somebody
1250	err := agent.ForceLeavePrune(s.Config.NodeName)
1251	if err != nil {
1252		t.Fatalf("err: %v", err)
1253	}
1254}
1255
1256func TestAPI_AgentMonitor(t *testing.T) {
1257	t.Parallel()
1258	c, s := makeClient(t)
1259	defer s.Stop()
1260
1261	agent := c.Agent()
1262
1263	logCh, err := agent.Monitor("debug", nil, nil)
1264	if err != nil {
1265		t.Fatalf("err: %v", err)
1266	}
1267
1268	retry.Run(t, func(r *retry.R) {
1269		{
1270			// Register a service to be sure something happens in secs
1271			serviceReg := &AgentServiceRegistration{
1272				Name: "redis",
1273			}
1274			if err := agent.ServiceRegister(serviceReg); err != nil {
1275				r.Fatalf("err: %v", err)
1276			}
1277		}
1278		// Wait for the first log message and validate it
1279		select {
1280		case log := <-logCh:
1281			if !(strings.Contains(log, "[INFO]") || strings.Contains(log, "[DEBUG]")) {
1282				r.Fatalf("bad: %q", log)
1283			}
1284		case <-time.After(10 * time.Second):
1285			r.Fatalf("failed to get a log message")
1286		}
1287	})
1288}
1289
1290func TestAPI_AgentMonitorJSON(t *testing.T) {
1291	t.Parallel()
1292	c, s := makeClient(t)
1293	defer s.Stop()
1294
1295	agent := c.Agent()
1296
1297	logCh, err := agent.MonitorJSON("debug", nil, nil)
1298	if err != nil {
1299		t.Fatalf("err: %v", err)
1300	}
1301
1302	retry.Run(t, func(r *retry.R) {
1303		{
1304			// Register a service to be sure something happens in secs
1305			serviceReg := &AgentServiceRegistration{
1306				Name: "redis",
1307			}
1308			if err := agent.ServiceRegister(serviceReg); err != nil {
1309				r.Fatalf("err: %v", err)
1310			}
1311		}
1312		// Wait for the first log message and validate it is valid JSON
1313		select {
1314		case log := <-logCh:
1315			var output map[string]interface{}
1316			if err := json.Unmarshal([]byte(log), &output); err != nil {
1317				r.Fatalf("log output was not JSON: %q", log)
1318			}
1319		case <-time.After(10 * time.Second):
1320			r.Fatalf("failed to get a log message")
1321		}
1322	})
1323}
1324
1325func TestAPI_ServiceMaintenance(t *testing.T) {
1326	t.Parallel()
1327	c, s := makeClient(t)
1328	defer s.Stop()
1329
1330	agent := c.Agent()
1331
1332	// First register a service
1333	serviceReg := &AgentServiceRegistration{
1334		Name: "redis",
1335	}
1336	if err := agent.ServiceRegister(serviceReg); err != nil {
1337		t.Fatalf("err: %v", err)
1338	}
1339
1340	// Enable maintenance mode
1341	if err := agent.EnableServiceMaintenance("redis", "broken"); err != nil {
1342		t.Fatalf("err: %s", err)
1343	}
1344
1345	// Ensure a critical check was added
1346	checks, err := agent.Checks()
1347	if err != nil {
1348		t.Fatalf("err: %v", err)
1349	}
1350	found := false
1351	for _, check := range checks {
1352		if strings.Contains(check.CheckID, "maintenance") {
1353			found = true
1354			if check.Status != HealthCritical || check.Notes != "broken" {
1355				t.Fatalf("bad: %#v", checks)
1356			}
1357		}
1358	}
1359	if !found {
1360		t.Fatalf("bad: %#v", checks)
1361	}
1362
1363	// Disable maintenance mode
1364	if err := agent.DisableServiceMaintenance("redis"); err != nil {
1365		t.Fatalf("err: %s", err)
1366	}
1367
1368	// Ensure the critical health check was removed
1369	checks, err = agent.Checks()
1370	if err != nil {
1371		t.Fatalf("err: %s", err)
1372	}
1373	for _, check := range checks {
1374		if strings.Contains(check.CheckID, "maintenance") {
1375			t.Fatalf("should have removed health check")
1376		}
1377		if check.Type != "maintenance" {
1378			t.Fatalf("expected type 'maintenance', got %s", check.Type)
1379		}
1380	}
1381}
1382
1383func TestAPI_NodeMaintenance(t *testing.T) {
1384	t.Parallel()
1385	c, s := makeClient(t)
1386	defer s.Stop()
1387
1388	agent := c.Agent()
1389	s.WaitForSerfCheck(t)
1390
1391	// Enable maintenance mode
1392	if err := agent.EnableNodeMaintenance("broken"); err != nil {
1393		t.Fatalf("err: %s", err)
1394	}
1395
1396	// Check that a critical check was added
1397	checks, err := agent.Checks()
1398	if err != nil {
1399		t.Fatalf("err: %s", err)
1400	}
1401	found := false
1402	for _, check := range checks {
1403		if strings.Contains(check.CheckID, "maintenance") {
1404			found = true
1405			if check.Status != HealthCritical || check.Notes != "broken" {
1406				t.Fatalf("bad: %#v", checks)
1407			}
1408		}
1409	}
1410	if !found {
1411		t.Fatalf("bad: %#v", checks)
1412	}
1413
1414	// Disable maintenance mode
1415	if err := agent.DisableNodeMaintenance(); err != nil {
1416		t.Fatalf("err: %s", err)
1417	}
1418
1419	// Ensure the check was removed
1420	checks, err = agent.Checks()
1421	if err != nil {
1422		t.Fatalf("err: %s", err)
1423	}
1424	for _, check := range checks {
1425		if strings.Contains(check.CheckID, "maintenance") {
1426			t.Fatalf("should have removed health check")
1427		}
1428		if check.Type != "maintenance" {
1429			t.Fatalf("expected type 'maintenance', got %s", check.Type)
1430		}
1431	}
1432}
1433
1434func TestAPI_AgentUpdateToken(t *testing.T) {
1435	t.Parallel()
1436	c, s := makeACLClient(t)
1437	defer s.Stop()
1438
1439	t.Run("deprecated", func(t *testing.T) {
1440		agent := c.Agent()
1441		if _, err := agent.UpdateACLToken("root", nil); err != nil {
1442			t.Fatalf("err: %v", err)
1443		}
1444
1445		if _, err := agent.UpdateACLAgentToken("root", nil); err != nil {
1446			t.Fatalf("err: %v", err)
1447		}
1448
1449		if _, err := agent.UpdateACLAgentMasterToken("root", nil); err != nil {
1450			t.Fatalf("err: %v", err)
1451		}
1452
1453		if _, err := agent.UpdateACLReplicationToken("root", nil); err != nil {
1454			t.Fatalf("err: %v", err)
1455		}
1456	})
1457
1458	t.Run("new with no fallback", func(t *testing.T) {
1459		agent := c.Agent()
1460		if _, err := agent.UpdateDefaultACLToken("root", nil); err != nil {
1461			t.Fatalf("err: %v", err)
1462		}
1463
1464		if _, err := agent.UpdateAgentACLToken("root", nil); err != nil {
1465			t.Fatalf("err: %v", err)
1466		}
1467
1468		if _, err := agent.UpdateAgentMasterACLToken("root", nil); err != nil {
1469			t.Fatalf("err: %v", err)
1470		}
1471
1472		if _, err := agent.UpdateReplicationACLToken("root", nil); err != nil {
1473			t.Fatalf("err: %v", err)
1474		}
1475	})
1476
1477	t.Run("new with fallback", func(t *testing.T) {
1478		// Respond with 404 for the new paths to trigger fallback.
1479		failer := func(w http.ResponseWriter, req *http.Request) {
1480			w.WriteHeader(404)
1481		}
1482		notfound := httptest.NewServer(http.HandlerFunc(failer))
1483		defer notfound.Close()
1484
1485		raw := c // real consul client
1486
1487		// Set up a reverse proxy that will send some requests to the
1488		// 404 server and pass everything else through to the real Consul
1489		// server.
1490		director := func(req *http.Request) {
1491			req.URL.Scheme = "http"
1492
1493			switch req.URL.Path {
1494			case "/v1/agent/token/default",
1495				"/v1/agent/token/agent",
1496				"/v1/agent/token/agent_master",
1497				"/v1/agent/token/replication":
1498				req.URL.Host = notfound.URL[7:] // Strip off "http://".
1499			default:
1500				req.URL.Host = raw.config.Address
1501			}
1502		}
1503		proxy := httptest.NewServer(&httputil.ReverseProxy{Director: director})
1504		defer proxy.Close()
1505
1506		// Make another client that points at the proxy instead of the real
1507		// Consul server.
1508		config := raw.config
1509		config.Address = proxy.URL[7:] // Strip off "http://".
1510		c, err := NewClient(&config)
1511		require.NoError(t, err)
1512
1513		agent := c.Agent()
1514
1515		_, err = agent.UpdateDefaultACLToken("root", nil)
1516		require.NoError(t, err)
1517
1518		_, err = agent.UpdateAgentACLToken("root", nil)
1519		require.NoError(t, err)
1520
1521		_, err = agent.UpdateAgentMasterACLToken("root", nil)
1522		require.NoError(t, err)
1523
1524		_, err = agent.UpdateReplicationACLToken("root", nil)
1525		require.NoError(t, err)
1526	})
1527
1528	t.Run("new with 403s", func(t *testing.T) {
1529		failer := func(w http.ResponseWriter, req *http.Request) {
1530			w.WriteHeader(403)
1531		}
1532		authdeny := httptest.NewServer(http.HandlerFunc(failer))
1533		defer authdeny.Close()
1534
1535		raw := c // real consul client
1536
1537		// Make another client that points at the proxy instead of the real
1538		// Consul server.
1539		config := raw.config
1540		config.Address = authdeny.URL[7:] // Strip off "http://".
1541		c, err := NewClient(&config)
1542		require.NoError(t, err)
1543
1544		agent := c.Agent()
1545
1546		_, err = agent.UpdateDefaultACLToken("root", nil)
1547		require.Error(t, err)
1548
1549		_, err = agent.UpdateAgentACLToken("root", nil)
1550		require.Error(t, err)
1551
1552		_, err = agent.UpdateAgentMasterACLToken("root", nil)
1553		require.Error(t, err)
1554
1555		_, err = agent.UpdateReplicationACLToken("root", nil)
1556		require.Error(t, err)
1557	})
1558}
1559
1560func TestAPI_AgentConnectCARoots_empty(t *testing.T) {
1561	t.Parallel()
1562
1563	require := require.New(t)
1564	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
1565		c.Connect = nil // disable connect to prevent CA being bootstrapped
1566	})
1567	defer s.Stop()
1568
1569	agent := c.Agent()
1570	_, _, err := agent.ConnectCARoots(nil)
1571	require.Error(err)
1572	require.Contains(err.Error(), "Connect must be enabled")
1573}
1574
1575func TestAPI_AgentConnectCARoots_list(t *testing.T) {
1576	t.Parallel()
1577
1578	require := require.New(t)
1579	c, s := makeClient(t)
1580	defer s.Stop()
1581
1582	agent := c.Agent()
1583	s.WaitForSerfCheck(t)
1584	list, meta, err := agent.ConnectCARoots(nil)
1585	require.NoError(err)
1586	require.True(meta.LastIndex > 0)
1587	require.Len(list.Roots, 1)
1588}
1589
1590func TestAPI_AgentConnectCALeaf(t *testing.T) {
1591	t.Parallel()
1592
1593	require := require.New(t)
1594	c, s := makeClient(t)
1595	defer s.Stop()
1596
1597	// ensure we don't try to sign a leaf cert before connect has been initialized
1598	s.WaitForActiveCARoot(t)
1599
1600	agent := c.Agent()
1601	// Setup service
1602	reg := &AgentServiceRegistration{
1603		Name: "foo",
1604		Tags: []string{"bar", "baz"},
1605		Port: 8000,
1606	}
1607	require.NoError(agent.ServiceRegister(reg))
1608
1609	leaf, meta, err := agent.ConnectCALeaf("foo", nil)
1610	require.NoError(err)
1611	require.True(meta.LastIndex > 0)
1612	// Sanity checks here as we have actual certificate validation checks at many
1613	// other levels.
1614	require.NotEmpty(leaf.SerialNumber)
1615	require.NotEmpty(leaf.CertPEM)
1616	require.NotEmpty(leaf.PrivateKeyPEM)
1617	require.Equal("foo", leaf.Service)
1618	require.True(strings.HasSuffix(leaf.ServiceURI, "/svc/foo"))
1619	require.True(leaf.ModifyIndex > 0)
1620	require.True(leaf.ValidAfter.Before(time.Now()))
1621	require.True(leaf.ValidBefore.After(time.Now()))
1622}
1623
1624func TestAPI_AgentConnectAuthorize(t *testing.T) {
1625	t.Parallel()
1626	require := require.New(t)
1627	c, s := makeClient(t)
1628	defer s.Stop()
1629
1630	agent := c.Agent()
1631	s.WaitForSerfCheck(t)
1632	params := &AgentAuthorizeParams{
1633		Target:           "foo",
1634		ClientCertSerial: "fake",
1635		// Importing connect.TestSpiffeIDService creates an import cycle
1636		ClientCertURI: "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/ny1/svc/web",
1637	}
1638	auth, err := agent.ConnectAuthorize(params)
1639	require.Nil(err)
1640	require.True(auth.Authorized)
1641	require.Equal(auth.Reason, "ACLs disabled, access is allowed by default")
1642}
1643
1644func TestAPI_AgentHealthService(t *testing.T) {
1645	t.Parallel()
1646	c, s := makeClient(t)
1647	defer s.Stop()
1648
1649	agent := c.Agent()
1650
1651	requireServiceHealthID := func(t *testing.T, serviceID, expected string, shouldExist bool) {
1652		msg := fmt.Sprintf("service id:%s, shouldExist:%v, expectedStatus:%s : bad %%s", serviceID, shouldExist, expected)
1653
1654		state, out, err := agent.AgentHealthServiceByID(serviceID)
1655		require.Nil(t, err, msg, "err")
1656		require.Equal(t, expected, state, msg, "state")
1657		if !shouldExist {
1658			require.Nil(t, out, msg, "shouldExist")
1659		} else {
1660			require.NotNil(t, out, msg, "output")
1661			require.Equal(t, serviceID, out.Service.ID, msg, "output")
1662		}
1663	}
1664	requireServiceHealthName := func(t *testing.T, serviceName, expected string, shouldExist bool) {
1665		msg := fmt.Sprintf("service name:%s, shouldExist:%v, expectedStatus:%s : bad %%s", serviceName, shouldExist, expected)
1666
1667		state, outs, err := agent.AgentHealthServiceByName(serviceName)
1668		require.Nil(t, err, msg, "err")
1669		require.Equal(t, expected, state, msg, "state")
1670		if !shouldExist {
1671			require.Equal(t, 0, len(outs), msg, "output")
1672		} else {
1673			require.True(t, len(outs) > 0, msg, "output")
1674			for _, o := range outs {
1675				require.Equal(t, serviceName, o.Service.Service, msg, "output")
1676			}
1677		}
1678	}
1679
1680	requireServiceHealthID(t, "_i_do_not_exist_", HealthCritical, false)
1681	requireServiceHealthName(t, "_i_do_not_exist_", HealthCritical, false)
1682
1683	testServiceID1 := "foo"
1684	testServiceID2 := "foofoo"
1685	testServiceName := "bar"
1686
1687	// register service
1688	reg := &AgentServiceRegistration{
1689		Name: testServiceName,
1690		ID:   testServiceID1,
1691		Port: 8000,
1692		Check: &AgentServiceCheck{
1693			TTL: "15s",
1694		},
1695	}
1696	err := agent.ServiceRegister(reg)
1697	require.Nil(t, err)
1698	requireServiceHealthID(t, testServiceID1, HealthCritical, true)
1699	requireServiceHealthName(t, testServiceName, HealthCritical, true)
1700
1701	err = agent.WarnTTL(fmt.Sprintf("service:%s", testServiceID1), "I am warn")
1702	require.Nil(t, err)
1703	requireServiceHealthName(t, testServiceName, HealthWarning, true)
1704	requireServiceHealthID(t, testServiceID1, HealthWarning, true)
1705
1706	err = agent.PassTTL(fmt.Sprintf("service:%s", testServiceID1), "I am good :)")
1707	require.Nil(t, err)
1708	requireServiceHealthName(t, testServiceName, HealthPassing, true)
1709	requireServiceHealthID(t, testServiceID1, HealthPassing, true)
1710
1711	err = agent.FailTTL(fmt.Sprintf("service:%s", testServiceID1), "I am dead.")
1712	require.Nil(t, err)
1713	requireServiceHealthName(t, testServiceName, HealthCritical, true)
1714	requireServiceHealthID(t, testServiceID1, HealthCritical, true)
1715
1716	// register another service
1717	reg = &AgentServiceRegistration{
1718		Name: testServiceName,
1719		ID:   testServiceID2,
1720		Port: 8000,
1721		Check: &AgentServiceCheck{
1722			TTL: "15s",
1723		},
1724	}
1725	err = agent.ServiceRegister(reg)
1726	require.Nil(t, err)
1727	requireServiceHealthName(t, testServiceName, HealthCritical, true)
1728
1729	err = agent.PassTTL(fmt.Sprintf("service:%s", testServiceID1), "I am good :)")
1730	require.Nil(t, err)
1731	requireServiceHealthName(t, testServiceName, HealthCritical, true)
1732
1733	err = agent.WarnTTL(fmt.Sprintf("service:%s", testServiceID2), "I am warn")
1734	require.Nil(t, err)
1735	requireServiceHealthName(t, testServiceName, HealthWarning, true)
1736
1737	err = agent.PassTTL(fmt.Sprintf("service:%s", testServiceID2), "I am good :)")
1738	require.Nil(t, err)
1739	requireServiceHealthName(t, testServiceName, HealthPassing, true)
1740}
1741
1742func TestAgentService_JSON_OmitTaggedAdddresses(t *testing.T) {
1743	t.Parallel()
1744	cases := []struct {
1745		name string
1746		as   AgentService
1747	}{
1748		{
1749			"nil",
1750			AgentService{
1751				TaggedAddresses: nil,
1752			},
1753		},
1754		{
1755			"empty",
1756			AgentService{
1757				TaggedAddresses: make(map[string]ServiceAddress),
1758			},
1759		},
1760	}
1761
1762	for _, tc := range cases {
1763		name := tc.name
1764		as := tc.as
1765		t.Run(name, func(t *testing.T) {
1766			t.Parallel()
1767			data, err := json.Marshal(as)
1768			require.NoError(t, err)
1769			var raw map[string]interface{}
1770			err = json.Unmarshal(data, &raw)
1771			require.NoError(t, err)
1772			require.NotContains(t, raw, "TaggedAddresses")
1773			require.NotContains(t, raw, "tagged_addresses")
1774		})
1775	}
1776}
1777
1778func TestAgentService_Register_MeshGateway(t *testing.T) {
1779	t.Parallel()
1780	c, s := makeClient(t)
1781	defer s.Stop()
1782
1783	agent := c.Agent()
1784
1785	reg := AgentServiceRegistration{
1786		Kind:    ServiceKindMeshGateway,
1787		Name:    "mesh-gateway",
1788		Address: "10.1.2.3",
1789		Port:    8443,
1790		Proxy: &AgentServiceConnectProxyConfig{
1791			Config: map[string]interface{}{
1792				"foo": "bar",
1793			},
1794		},
1795	}
1796
1797	err := agent.ServiceRegister(&reg)
1798	require.NoError(t, err)
1799
1800	svc, _, err := agent.Service("mesh-gateway", nil)
1801	require.NoError(t, err)
1802	require.NotNil(t, svc)
1803	require.Equal(t, ServiceKindMeshGateway, svc.Kind)
1804	require.NotNil(t, svc.Proxy)
1805	require.Contains(t, svc.Proxy.Config, "foo")
1806	require.Equal(t, "bar", svc.Proxy.Config["foo"])
1807}
1808
1809func TestAgentService_Register_TerminatingGateway(t *testing.T) {
1810	t.Parallel()
1811	c, s := makeClient(t)
1812	defer s.Stop()
1813
1814	agent := c.Agent()
1815
1816	reg := AgentServiceRegistration{
1817		Kind:    ServiceKindTerminatingGateway,
1818		Name:    "terminating-gateway",
1819		Address: "10.1.2.3",
1820		Port:    8443,
1821		Proxy: &AgentServiceConnectProxyConfig{
1822			Config: map[string]interface{}{
1823				"foo": "bar",
1824			},
1825		},
1826	}
1827
1828	err := agent.ServiceRegister(&reg)
1829	require.NoError(t, err)
1830
1831	svc, _, err := agent.Service("terminating-gateway", nil)
1832	require.NoError(t, err)
1833	require.NotNil(t, svc)
1834	require.Equal(t, ServiceKindTerminatingGateway, svc.Kind)
1835	require.NotNil(t, svc.Proxy)
1836	require.Contains(t, svc.Proxy.Config, "foo")
1837	require.Equal(t, "bar", svc.Proxy.Config["foo"])
1838}
1839
1840func TestAgentService_ExposeChecks(t *testing.T) {
1841	t.Parallel()
1842	c, s := makeClient(t)
1843	defer s.Stop()
1844
1845	agent := c.Agent()
1846
1847	path := ExposePath{
1848		LocalPathPort: 8080,
1849		ListenerPort:  21500,
1850		Path:          "/metrics",
1851		Protocol:      "http2",
1852	}
1853	reg := AgentServiceRegistration{
1854		Kind:    ServiceKindConnectProxy,
1855		Name:    "expose-proxy",
1856		Address: "10.1.2.3",
1857		Port:    8443,
1858		Proxy: &AgentServiceConnectProxyConfig{
1859			DestinationServiceName: "expose",
1860			Expose: ExposeConfig{
1861				Checks: true,
1862				Paths: []ExposePath{
1863					path,
1864				},
1865			},
1866		},
1867	}
1868
1869	err := agent.ServiceRegister(&reg)
1870	require.NoError(t, err)
1871
1872	svc, _, err := agent.Service("expose-proxy", nil)
1873	require.NoError(t, err)
1874	require.NotNil(t, svc)
1875	require.Equal(t, ServiceKindConnectProxy, svc.Kind)
1876	require.NotNil(t, svc.Proxy)
1877	require.Len(t, svc.Proxy.Expose.Paths, 1)
1878	require.True(t, svc.Proxy.Expose.Checks)
1879	require.Equal(t, path, svc.Proxy.Expose.Paths[0])
1880}
1881
1882func TestMemberACLMode(t *testing.T) {
1883	type testCase struct {
1884		tagValue     string
1885		expectedMode MemberACLMode
1886	}
1887
1888	cases := map[string]testCase{
1889		"disabled": {
1890			tagValue:     "0",
1891			expectedMode: ACLModeDisabled,
1892		},
1893		"enabled": {
1894			tagValue:     "1",
1895			expectedMode: ACLModeEnabled,
1896		},
1897		"legacy": {
1898			tagValue:     "2",
1899			expectedMode: ACLModeLegacy,
1900		},
1901		"unknown-3": {
1902			tagValue:     "3",
1903			expectedMode: ACLModeUnknown,
1904		},
1905		"unknown-other": {
1906			tagValue:     "77",
1907			expectedMode: ACLModeUnknown,
1908		},
1909		"unknown-not-present": {
1910			tagValue:     "",
1911			expectedMode: ACLModeUnknown,
1912		},
1913	}
1914
1915	for name, tcase := range cases {
1916		t.Run(name, func(t *testing.T) {
1917			tags := map[string]string{}
1918
1919			if tcase.tagValue != "" {
1920				tags[MemberTagKeyACLMode] = tcase.tagValue
1921			}
1922
1923			m := AgentMember{
1924				Tags: tags,
1925			}
1926
1927			require.Equal(t, tcase.expectedMode, m.ACLMode())
1928		})
1929	}
1930}
1931
1932func TestMemberIsConsulServer(t *testing.T) {
1933	type testCase struct {
1934		tagValue string
1935		isServer bool
1936	}
1937
1938	cases := map[string]testCase{
1939		"not-present": {
1940			tagValue: "",
1941			isServer: false,
1942		},
1943		"server": {
1944			tagValue: MemberTagValueRoleServer,
1945			isServer: true,
1946		},
1947		"client": {
1948			tagValue: "client",
1949			isServer: false,
1950		},
1951	}
1952
1953	for name, tcase := range cases {
1954		t.Run(name, func(t *testing.T) {
1955			tags := map[string]string{}
1956
1957			if tcase.tagValue != "" {
1958				tags[MemberTagKeyRole] = tcase.tagValue
1959			}
1960
1961			m := AgentMember{
1962				Tags: tags,
1963			}
1964
1965			require.Equal(t, tcase.isServer, m.IsConsulServer())
1966		})
1967	}
1968}
1969