1package api
2
3import (
4	"io/ioutil"
5	"os"
6	"path/filepath"
7	"strings"
8	"testing"
9	"time"
10
11	"github.com/hashicorp/consul/testutil"
12	"github.com/hashicorp/consul/testutil/retry"
13	"github.com/hashicorp/serf/serf"
14	"github.com/stretchr/testify/require"
15)
16
17func TestAPI_AgentSelf(t *testing.T) {
18	t.Parallel()
19	c, s := makeClient(t)
20	defer s.Stop()
21
22	agent := c.Agent()
23
24	info, err := agent.Self()
25	if err != nil {
26		t.Fatalf("err: %v", err)
27	}
28
29	name := info["Config"]["NodeName"].(string)
30	if name == "" {
31		t.Fatalf("bad: %v", info)
32	}
33}
34
35func TestAPI_AgentMetrics(t *testing.T) {
36	t.Parallel()
37	c, s := makeClient(t)
38	defer s.Stop()
39
40	agent := c.Agent()
41	timer := &retry.Timer{Timeout: 10 * time.Second, Wait: 500 * time.Millisecond}
42	retry.RunWith(timer, t, func(r *retry.R) {
43		metrics, err := agent.Metrics()
44		if err != nil {
45			r.Fatalf("err: %v", err)
46		}
47		for _, g := range metrics.Gauges {
48			if g.Name == "consul.runtime.alloc_bytes" {
49				return
50			}
51		}
52		r.Fatalf("missing runtime metrics")
53	})
54}
55
56func TestAPI_AgentReload(t *testing.T) {
57	t.Parallel()
58
59	// Create our initial empty config file, to be overwritten later
60	cfgDir := testutil.TempDir(t, "consul-config")
61	defer os.RemoveAll(cfgDir)
62
63	cfgFilePath := filepath.Join(cfgDir, "reload.json")
64	configFile, err := os.Create(cfgFilePath)
65	if err != nil {
66		t.Fatalf("Unable to create file %v, got error:%v", cfgFilePath, err)
67	}
68
69	c, s := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
70		conf.Args = []string{"-config-file", configFile.Name()}
71	})
72	defer s.Stop()
73
74	agent := c.Agent()
75
76	// Update the config file with a service definition
77	config := `{"service":{"name":"redis", "port":1234, "Meta": {"some": "meta"}}}`
78	err = ioutil.WriteFile(configFile.Name(), []byte(config), 0644)
79	if err != nil {
80		t.Fatalf("err: %v", err)
81	}
82
83	if err = agent.Reload(); err != nil {
84		t.Fatalf("err: %v", err)
85	}
86
87	services, err := agent.Services()
88	if err != nil {
89		t.Fatalf("err: %v", err)
90	}
91
92	service, ok := services["redis"]
93	if !ok {
94		t.Fatalf("bad: %v", ok)
95	}
96	if service.Port != 1234 {
97		t.Fatalf("bad: %v", service.Port)
98	}
99	if service.Meta["some"] != "meta" {
100		t.Fatalf("Missing metadata some:=meta in %v", service)
101	}
102}
103
104func TestAPI_AgentMembersOpts(t *testing.T) {
105	t.Parallel()
106	c, s1 := makeClient(t)
107	_, s2 := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
108		c.Datacenter = "dc2"
109	})
110	defer s1.Stop()
111	defer s2.Stop()
112
113	agent := c.Agent()
114
115	s2.JoinWAN(t, s1.WANAddr)
116
117	members, err := agent.MembersOpts(MembersOpts{WAN: true})
118	if err != nil {
119		t.Fatalf("err: %v", err)
120	}
121
122	if len(members) != 2 {
123		t.Fatalf("bad: %v", members)
124	}
125}
126
127func TestAPI_AgentMembers(t *testing.T) {
128	t.Parallel()
129	c, s := makeClient(t)
130	defer s.Stop()
131
132	agent := c.Agent()
133
134	members, err := agent.Members(false)
135	if err != nil {
136		t.Fatalf("err: %v", err)
137	}
138
139	if len(members) != 1 {
140		t.Fatalf("bad: %v", members)
141	}
142}
143
144func TestAPI_AgentServices(t *testing.T) {
145	t.Parallel()
146	c, s := makeClient(t)
147	defer s.Stop()
148
149	agent := c.Agent()
150
151	reg := &AgentServiceRegistration{
152		Name: "foo",
153		Tags: []string{"bar", "baz"},
154		Port: 8000,
155		Check: &AgentServiceCheck{
156			TTL: "15s",
157		},
158	}
159	if err := agent.ServiceRegister(reg); err != nil {
160		t.Fatalf("err: %v", err)
161	}
162
163	services, err := agent.Services()
164	if err != nil {
165		t.Fatalf("err: %v", err)
166	}
167	if _, ok := services["foo"]; !ok {
168		t.Fatalf("missing service: %v", services)
169	}
170	checks, err := agent.Checks()
171	if err != nil {
172		t.Fatalf("err: %v", err)
173	}
174	chk, ok := checks["service:foo"]
175	if !ok {
176		t.Fatalf("missing check: %v", checks)
177	}
178
179	// Checks should default to critical
180	if chk.Status != HealthCritical {
181		t.Fatalf("Bad: %#v", chk)
182	}
183
184	if err := agent.ServiceDeregister("foo"); err != nil {
185		t.Fatalf("err: %v", err)
186	}
187}
188
189func TestAPI_AgentServices_ManagedConnectProxy(t *testing.T) {
190	t.Parallel()
191	c, s := makeClient(t)
192	defer s.Stop()
193
194	agent := c.Agent()
195
196	reg := &AgentServiceRegistration{
197		Name: "foo",
198		Tags: []string{"bar", "baz"},
199		Port: 8000,
200		Check: &AgentServiceCheck{
201			TTL: "15s",
202		},
203		Connect: &AgentServiceConnect{
204			Proxy: &AgentServiceConnectProxy{
205				ExecMode: ProxyExecModeScript,
206				Command:  []string{"foo.rb"},
207				Config: map[string]interface{}{
208					"foo": "bar",
209				},
210				Upstreams: []Upstream{{
211					DestinationType: "prepared_query",
212					DestinationName: "bar",
213					LocalBindPort:   9191,
214				}},
215			},
216		},
217	}
218	if err := agent.ServiceRegister(reg); err != nil {
219		t.Fatalf("err: %v", err)
220	}
221
222	services, err := agent.Services()
223	if err != nil {
224		t.Fatalf("err: %v", err)
225	}
226	if _, ok := services["foo"]; !ok {
227		t.Fatalf("missing service: %v", services)
228	}
229	checks, err := agent.Checks()
230	if err != nil {
231		t.Fatalf("err: %v", err)
232	}
233	chk, ok := checks["service:foo"]
234	if !ok {
235		t.Fatalf("missing check: %v", checks)
236	}
237
238	// Checks should default to critical
239	if chk.Status != HealthCritical {
240		t.Fatalf("Bad: %#v", chk)
241	}
242
243	// Proxy config should be correct
244	require.Equal(t, reg.Connect, services["foo"].Connect)
245
246	if err := agent.ServiceDeregister("foo"); err != nil {
247		t.Fatalf("err: %v", err)
248	}
249}
250
251func TestAPI_AgentServices_ManagedConnectProxyDeprecatedUpstreams(t *testing.T) {
252	t.Parallel()
253	c, s := makeClient(t)
254	defer s.Stop()
255
256	agent := c.Agent()
257
258	reg := &AgentServiceRegistration{
259		Name: "foo",
260		Tags: []string{"bar", "baz"},
261		Port: 8000,
262		Check: &AgentServiceCheck{
263			TTL: "15s",
264		},
265		Connect: &AgentServiceConnect{
266			Proxy: &AgentServiceConnectProxy{
267				ExecMode: ProxyExecModeScript,
268				Command:  []string{"foo.rb"},
269				Config: map[string]interface{}{
270					"foo": "bar",
271					"upstreams": []interface{}{
272						map[string]interface{}{
273							"destination_type":   "prepared_query",
274							"destination_name":   "bar",
275							"local_bind_port":    9191,
276							"connect_timeout_ms": 1000,
277						},
278					},
279				},
280			},
281		},
282	}
283	if err := agent.ServiceRegister(reg); err != nil {
284		t.Fatalf("err: %v", err)
285	}
286
287	services, err := agent.Services()
288	if err != nil {
289		t.Fatalf("err: %v", err)
290	}
291	if _, ok := services["foo"]; !ok {
292		t.Fatalf("missing service: %v", services)
293	}
294	checks, err := agent.Checks()
295	if err != nil {
296		t.Fatalf("err: %v", err)
297	}
298	chk, ok := checks["service:foo"]
299	if !ok {
300		t.Fatalf("missing check: %v", checks)
301	}
302
303	// Checks should default to critical
304	if chk.Status != HealthCritical {
305		t.Fatalf("Bad: %#v", chk)
306	}
307
308	// Proxy config should be present in response, minus the upstreams
309	delete(reg.Connect.Proxy.Config, "upstreams")
310	// Upstreams should be translated into proper field
311	reg.Connect.Proxy.Upstreams = []Upstream{{
312		DestinationType: "prepared_query",
313		DestinationName: "bar",
314		LocalBindPort:   9191,
315		Config: map[string]interface{}{
316			"connect_timeout_ms": float64(1000),
317		},
318	}}
319	require.Equal(t, reg.Connect, services["foo"].Connect)
320
321	if err := agent.ServiceDeregister("foo"); err != nil {
322		t.Fatalf("err: %v", err)
323	}
324}
325
326func TestAPI_AgentServices_SidecarService(t *testing.T) {
327	t.Parallel()
328	c, s := makeClient(t)
329	defer s.Stop()
330
331	agent := c.Agent()
332
333	// Register service
334	reg := &AgentServiceRegistration{
335		Name: "foo",
336		Port: 8000,
337		Connect: &AgentServiceConnect{
338			SidecarService: &AgentServiceRegistration{},
339		},
340	}
341	if err := agent.ServiceRegister(reg); err != nil {
342		t.Fatalf("err: %v", err)
343	}
344
345	services, err := agent.Services()
346	if err != nil {
347		t.Fatalf("err: %v", err)
348	}
349	if _, ok := services["foo"]; !ok {
350		t.Fatalf("missing service: %v", services)
351	}
352	if _, ok := services["foo-sidecar-proxy"]; !ok {
353		t.Fatalf("missing sidecar service: %v", services)
354	}
355
356	if err := agent.ServiceDeregister("foo"); err != nil {
357		t.Fatalf("err: %v", err)
358	}
359
360	// Deregister should have removed both service and it's sidecar
361	services, err = agent.Services()
362	require.NoError(t, err)
363
364	if _, ok := services["foo"]; ok {
365		t.Fatalf("didn't remove service: %v", services)
366	}
367	if _, ok := services["foo-sidecar-proxy"]; ok {
368		t.Fatalf("didn't remove sidecar service: %v", services)
369	}
370}
371
372func TestAPI_AgentServices_ExternalConnectProxy(t *testing.T) {
373	t.Parallel()
374	c, s := makeClient(t)
375	defer s.Stop()
376
377	agent := c.Agent()
378
379	// Register service
380	reg := &AgentServiceRegistration{
381		Name: "foo",
382		Port: 8000,
383	}
384	if err := agent.ServiceRegister(reg); err != nil {
385		t.Fatalf("err: %v", err)
386	}
387	// Register proxy
388	reg = &AgentServiceRegistration{
389		Kind: ServiceKindConnectProxy,
390		Name: "foo-proxy",
391		Port: 8001,
392		Proxy: &AgentServiceConnectProxyConfig{
393			DestinationServiceName: "foo",
394		},
395	}
396	if err := agent.ServiceRegister(reg); err != nil {
397		t.Fatalf("err: %v", err)
398	}
399
400	services, err := agent.Services()
401	if err != nil {
402		t.Fatalf("err: %v", err)
403	}
404	if _, ok := services["foo"]; !ok {
405		t.Fatalf("missing service: %v", services)
406	}
407	if _, ok := services["foo-proxy"]; !ok {
408		t.Fatalf("missing proxy service: %v", services)
409	}
410
411	if err := agent.ServiceDeregister("foo"); err != nil {
412		t.Fatalf("err: %v", err)
413	}
414	if err := agent.ServiceDeregister("foo-proxy"); err != nil {
415		t.Fatalf("err: %v", err)
416	}
417}
418
419func TestAPI_AgentServices_CheckPassing(t *testing.T) {
420	t.Parallel()
421	c, s := makeClient(t)
422	defer s.Stop()
423
424	agent := c.Agent()
425	reg := &AgentServiceRegistration{
426		Name: "foo",
427		Tags: []string{"bar", "baz"},
428		Port: 8000,
429		Check: &AgentServiceCheck{
430			TTL:    "15s",
431			Status: HealthPassing,
432		},
433	}
434	if err := agent.ServiceRegister(reg); err != nil {
435		t.Fatalf("err: %v", err)
436	}
437
438	services, err := agent.Services()
439	if err != nil {
440		t.Fatalf("err: %v", err)
441	}
442	if _, ok := services["foo"]; !ok {
443		t.Fatalf("missing service: %v", services)
444	}
445
446	checks, err := agent.Checks()
447	if err != nil {
448		t.Fatalf("err: %v", err)
449	}
450	chk, ok := checks["service:foo"]
451	if !ok {
452		t.Fatalf("missing check: %v", checks)
453	}
454
455	if chk.Status != HealthPassing {
456		t.Fatalf("Bad: %#v", chk)
457	}
458	if err := agent.ServiceDeregister("foo"); err != nil {
459		t.Fatalf("err: %v", err)
460	}
461}
462
463func TestAPI_AgentServices_CheckBadStatus(t *testing.T) {
464	t.Parallel()
465	c, s := makeClient(t)
466	defer s.Stop()
467
468	agent := c.Agent()
469	reg := &AgentServiceRegistration{
470		Name: "foo",
471		Tags: []string{"bar", "baz"},
472		Port: 8000,
473		Check: &AgentServiceCheck{
474			TTL:    "15s",
475			Status: "fluffy",
476		},
477	}
478	if err := agent.ServiceRegister(reg); err == nil {
479		t.Fatalf("bad status accepted")
480	}
481}
482
483func TestAPI_AgentServices_CheckID(t *testing.T) {
484	t.Parallel()
485	c, s := makeClient(t)
486	defer s.Stop()
487
488	agent := c.Agent()
489	reg := &AgentServiceRegistration{
490		Name: "foo",
491		Tags: []string{"bar", "baz"},
492		Port: 8000,
493		Check: &AgentServiceCheck{
494			CheckID: "foo-ttl",
495			TTL:     "15s",
496		},
497	}
498	if err := agent.ServiceRegister(reg); err != nil {
499		t.Fatalf("err: %v", err)
500	}
501
502	checks, err := agent.Checks()
503	if err != nil {
504		t.Fatalf("err: %v", err)
505	}
506	if _, ok := checks["foo-ttl"]; !ok {
507		t.Fatalf("missing check: %v", checks)
508	}
509}
510
511func TestAPI_AgentServiceAddress(t *testing.T) {
512	t.Parallel()
513	c, s := makeClient(t)
514	defer s.Stop()
515
516	agent := c.Agent()
517
518	reg1 := &AgentServiceRegistration{
519		Name:    "foo1",
520		Port:    8000,
521		Address: "192.168.0.42",
522	}
523	reg2 := &AgentServiceRegistration{
524		Name: "foo2",
525		Port: 8000,
526	}
527	if err := agent.ServiceRegister(reg1); err != nil {
528		t.Fatalf("err: %v", err)
529	}
530	if err := agent.ServiceRegister(reg2); err != nil {
531		t.Fatalf("err: %v", err)
532	}
533
534	services, err := agent.Services()
535	if err != nil {
536		t.Fatalf("err: %v", err)
537	}
538
539	if _, ok := services["foo1"]; !ok {
540		t.Fatalf("missing service: %v", services)
541	}
542	if _, ok := services["foo2"]; !ok {
543		t.Fatalf("missing service: %v", services)
544	}
545
546	if services["foo1"].Address != "192.168.0.42" {
547		t.Fatalf("missing Address field in service foo1: %v", services)
548	}
549	if services["foo2"].Address != "" {
550		t.Fatalf("missing Address field in service foo2: %v", services)
551	}
552
553	if err := agent.ServiceDeregister("foo"); err != nil {
554		t.Fatalf("err: %v", err)
555	}
556}
557
558func TestAPI_AgentEnableTagOverride(t *testing.T) {
559	t.Parallel()
560	c, s := makeClient(t)
561	defer s.Stop()
562
563	agent := c.Agent()
564
565	reg1 := &AgentServiceRegistration{
566		Name:              "foo1",
567		Port:              8000,
568		Address:           "192.168.0.42",
569		EnableTagOverride: true,
570	}
571	reg2 := &AgentServiceRegistration{
572		Name: "foo2",
573		Port: 8000,
574	}
575	if err := agent.ServiceRegister(reg1); err != nil {
576		t.Fatalf("err: %v", err)
577	}
578	if err := agent.ServiceRegister(reg2); err != nil {
579		t.Fatalf("err: %v", err)
580	}
581
582	services, err := agent.Services()
583	if err != nil {
584		t.Fatalf("err: %v", err)
585	}
586
587	if _, ok := services["foo1"]; !ok {
588		t.Fatalf("missing service: %v", services)
589	}
590	if services["foo1"].EnableTagOverride != true {
591		t.Fatalf("tag override not set on service foo1: %v", services)
592	}
593	if _, ok := services["foo2"]; !ok {
594		t.Fatalf("missing service: %v", services)
595	}
596	if services["foo2"].EnableTagOverride != false {
597		t.Fatalf("tag override set on service foo2: %v", services)
598	}
599}
600
601func TestAPI_AgentServices_MultipleChecks(t *testing.T) {
602	t.Parallel()
603	c, s := makeClient(t)
604	defer s.Stop()
605
606	agent := c.Agent()
607
608	reg := &AgentServiceRegistration{
609		Name: "foo",
610		Tags: []string{"bar", "baz"},
611		Port: 8000,
612		Checks: AgentServiceChecks{
613			&AgentServiceCheck{
614				TTL: "15s",
615			},
616			&AgentServiceCheck{
617				TTL: "30s",
618			},
619		},
620	}
621	if err := agent.ServiceRegister(reg); err != nil {
622		t.Fatalf("err: %v", err)
623	}
624
625	services, err := agent.Services()
626	if err != nil {
627		t.Fatalf("err: %v", err)
628	}
629	if _, ok := services["foo"]; !ok {
630		t.Fatalf("missing service: %v", services)
631	}
632
633	checks, err := agent.Checks()
634	if err != nil {
635		t.Fatalf("err: %v", err)
636	}
637	if _, ok := checks["service:foo:1"]; !ok {
638		t.Fatalf("missing check: %v", checks)
639	}
640	if _, ok := checks["service:foo:2"]; !ok {
641		t.Fatalf("missing check: %v", checks)
642	}
643}
644
645func TestAPI_AgentService(t *testing.T) {
646	t.Parallel()
647	c, s := makeClient(t)
648	defer s.Stop()
649
650	agent := c.Agent()
651
652	require := require.New(t)
653
654	reg := &AgentServiceRegistration{
655		Name: "foo",
656		Tags: []string{"bar", "baz"},
657		Port: 8000,
658		Checks: AgentServiceChecks{
659			&AgentServiceCheck{
660				TTL: "15s",
661			},
662			&AgentServiceCheck{
663				TTL: "30s",
664			},
665		},
666	}
667	require.NoError(agent.ServiceRegister(reg))
668
669	got, qm, err := agent.Service("foo", nil)
670	require.NoError(err)
671
672	expect := &AgentService{
673		ID:          "foo",
674		Service:     "foo",
675		Tags:        []string{"bar", "baz"},
676		ContentHash: "5d286f5494330b04",
677		Port:        8000,
678	}
679	require.Equal(expect, got)
680	require.Equal(expect.ContentHash, qm.LastContentHash)
681
682	// Sanity check blocking behaviour - this is more thoroughly tested in the
683	// agent endpoint tests but this ensures that the API package is at least
684	// passing the hash param properly.
685	opts := QueryOptions{
686		WaitHash: "5d286f5494330b04",
687		WaitTime: 100 * time.Millisecond, // Just long enough to be reliably measurable
688	}
689	start := time.Now()
690	got, qm, err = agent.Service("foo", &opts)
691	elapsed := time.Since(start)
692	require.NoError(err)
693	require.True(elapsed >= opts.WaitTime)
694}
695
696func TestAPI_AgentSetTTLStatus(t *testing.T) {
697	t.Parallel()
698	c, s := makeClient(t)
699	defer s.Stop()
700
701	agent := c.Agent()
702
703	reg := &AgentServiceRegistration{
704		Name: "foo",
705		Check: &AgentServiceCheck{
706			TTL: "15s",
707		},
708	}
709	if err := agent.ServiceRegister(reg); err != nil {
710		t.Fatalf("err: %v", err)
711	}
712
713	verify := func(status, output string) {
714		checks, err := agent.Checks()
715		if err != nil {
716			t.Fatalf("err: %v", err)
717		}
718		chk, ok := checks["service:foo"]
719		if !ok {
720			t.Fatalf("missing check: %v", checks)
721		}
722		if chk.Status != status {
723			t.Fatalf("Bad: %#v", chk)
724		}
725		if chk.Output != output {
726			t.Fatalf("Bad: %#v", chk)
727		}
728	}
729
730	if err := agent.WarnTTL("service:foo", "foo"); err != nil {
731		t.Fatalf("err: %v", err)
732	}
733	verify(HealthWarning, "foo")
734
735	if err := agent.PassTTL("service:foo", "bar"); err != nil {
736		t.Fatalf("err: %v", err)
737	}
738	verify(HealthPassing, "bar")
739
740	if err := agent.FailTTL("service:foo", "baz"); err != nil {
741		t.Fatalf("err: %v", err)
742	}
743	verify(HealthCritical, "baz")
744
745	if err := agent.UpdateTTL("service:foo", "foo", "warn"); err != nil {
746		t.Fatalf("err: %v", err)
747	}
748	verify(HealthWarning, "foo")
749
750	if err := agent.UpdateTTL("service:foo", "bar", "pass"); err != nil {
751		t.Fatalf("err: %v", err)
752	}
753	verify(HealthPassing, "bar")
754
755	if err := agent.UpdateTTL("service:foo", "baz", "fail"); err != nil {
756		t.Fatalf("err: %v", err)
757	}
758	verify(HealthCritical, "baz")
759
760	if err := agent.UpdateTTL("service:foo", "foo", HealthWarning); err != nil {
761		t.Fatalf("err: %v", err)
762	}
763	verify(HealthWarning, "foo")
764
765	if err := agent.UpdateTTL("service:foo", "bar", HealthPassing); err != nil {
766		t.Fatalf("err: %v", err)
767	}
768	verify(HealthPassing, "bar")
769
770	if err := agent.UpdateTTL("service:foo", "baz", HealthCritical); err != nil {
771		t.Fatalf("err: %v", err)
772	}
773	verify(HealthCritical, "baz")
774
775	if err := agent.ServiceDeregister("foo"); err != nil {
776		t.Fatalf("err: %v", err)
777	}
778}
779
780func TestAPI_AgentChecks(t *testing.T) {
781	t.Parallel()
782	c, s := makeClient(t)
783	defer s.Stop()
784
785	agent := c.Agent()
786
787	reg := &AgentCheckRegistration{
788		Name: "foo",
789	}
790	reg.TTL = "15s"
791	if err := agent.CheckRegister(reg); err != nil {
792		t.Fatalf("err: %v", err)
793	}
794
795	checks, err := agent.Checks()
796	if err != nil {
797		t.Fatalf("err: %v", err)
798	}
799	chk, ok := checks["foo"]
800	if !ok {
801		t.Fatalf("missing check: %v", checks)
802	}
803	if chk.Status != HealthCritical {
804		t.Fatalf("check not critical: %v", chk)
805	}
806
807	if err := agent.CheckDeregister("foo"); err != nil {
808		t.Fatalf("err: %v", err)
809	}
810}
811
812func TestAPI_AgentScriptCheck(t *testing.T) {
813	t.Parallel()
814	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
815		c.EnableScriptChecks = true
816	})
817	defer s.Stop()
818
819	agent := c.Agent()
820
821	t.Run("node script check", func(t *testing.T) {
822		reg := &AgentCheckRegistration{
823			Name: "foo",
824			AgentServiceCheck: AgentServiceCheck{
825				Interval: "10s",
826				Args:     []string{"sh", "-c", "false"},
827			},
828		}
829		if err := agent.CheckRegister(reg); err != nil {
830			t.Fatalf("err: %v", err)
831		}
832
833		checks, err := agent.Checks()
834		if err != nil {
835			t.Fatalf("err: %v", err)
836		}
837		if _, ok := checks["foo"]; !ok {
838			t.Fatalf("missing check: %v", checks)
839		}
840	})
841
842	t.Run("service script check", func(t *testing.T) {
843		reg := &AgentServiceRegistration{
844			Name: "bar",
845			Port: 1234,
846			Checks: AgentServiceChecks{
847				&AgentServiceCheck{
848					Interval: "10s",
849					Args:     []string{"sh", "-c", "false"},
850				},
851			},
852		}
853		if err := agent.ServiceRegister(reg); err != nil {
854			t.Fatalf("err: %v", err)
855		}
856
857		services, err := agent.Services()
858		if err != nil {
859			t.Fatalf("err: %v", err)
860		}
861		if _, ok := services["bar"]; !ok {
862			t.Fatalf("missing service: %v", services)
863		}
864
865		checks, err := agent.Checks()
866		if err != nil {
867			t.Fatalf("err: %v", err)
868		}
869		if _, ok := checks["service:bar"]; !ok {
870			t.Fatalf("missing check: %v", checks)
871		}
872	})
873}
874
875func TestAPI_AgentCheckStartPassing(t *testing.T) {
876	t.Parallel()
877	c, s := makeClient(t)
878	defer s.Stop()
879
880	agent := c.Agent()
881
882	reg := &AgentCheckRegistration{
883		Name: "foo",
884		AgentServiceCheck: AgentServiceCheck{
885			Status: HealthPassing,
886		},
887	}
888	reg.TTL = "15s"
889	if err := agent.CheckRegister(reg); err != nil {
890		t.Fatalf("err: %v", err)
891	}
892
893	checks, err := agent.Checks()
894	if err != nil {
895		t.Fatalf("err: %v", err)
896	}
897	chk, ok := checks["foo"]
898	if !ok {
899		t.Fatalf("missing check: %v", checks)
900	}
901	if chk.Status != HealthPassing {
902		t.Fatalf("check not passing: %v", chk)
903	}
904
905	if err := agent.CheckDeregister("foo"); err != nil {
906		t.Fatalf("err: %v", err)
907	}
908}
909
910func TestAPI_AgentChecks_serviceBound(t *testing.T) {
911	t.Parallel()
912	c, s := makeClient(t)
913	defer s.Stop()
914
915	agent := c.Agent()
916
917	// First register a service
918	serviceReg := &AgentServiceRegistration{
919		Name: "redis",
920	}
921	if err := agent.ServiceRegister(serviceReg); err != nil {
922		t.Fatalf("err: %v", err)
923	}
924
925	// Register a check bound to the service
926	reg := &AgentCheckRegistration{
927		Name:      "redischeck",
928		ServiceID: "redis",
929	}
930	reg.TTL = "15s"
931	reg.DeregisterCriticalServiceAfter = "nope"
932	err := agent.CheckRegister(reg)
933	if err == nil || !strings.Contains(err.Error(), "invalid duration") {
934		t.Fatalf("err: %v", err)
935	}
936
937	reg.DeregisterCriticalServiceAfter = "90m"
938	if err := agent.CheckRegister(reg); err != nil {
939		t.Fatalf("err: %v", err)
940	}
941
942	checks, err := agent.Checks()
943	if err != nil {
944		t.Fatalf("err: %v", err)
945	}
946
947	check, ok := checks["redischeck"]
948	if !ok {
949		t.Fatalf("missing check: %v", checks)
950	}
951	if check.ServiceID != "redis" {
952		t.Fatalf("missing service association for check: %v", check)
953	}
954}
955
956func TestAPI_AgentChecks_Docker(t *testing.T) {
957	t.Parallel()
958	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
959		c.EnableScriptChecks = true
960	})
961	defer s.Stop()
962
963	agent := c.Agent()
964
965	// First register a service
966	serviceReg := &AgentServiceRegistration{
967		Name: "redis",
968	}
969	if err := agent.ServiceRegister(serviceReg); err != nil {
970		t.Fatalf("err: %v", err)
971	}
972
973	// Register a check bound to the service
974	reg := &AgentCheckRegistration{
975		Name:      "redischeck",
976		ServiceID: "redis",
977		AgentServiceCheck: AgentServiceCheck{
978			DockerContainerID: "f972c95ebf0e",
979			Args:              []string{"/bin/true"},
980			Shell:             "/bin/bash",
981			Interval:          "10s",
982		},
983	}
984	if err := agent.CheckRegister(reg); err != nil {
985		t.Fatalf("err: %v", err)
986	}
987
988	checks, err := agent.Checks()
989	if err != nil {
990		t.Fatalf("err: %v", err)
991	}
992
993	check, ok := checks["redischeck"]
994	if !ok {
995		t.Fatalf("missing check: %v", checks)
996	}
997	if check.ServiceID != "redis" {
998		t.Fatalf("missing service association for check: %v", check)
999	}
1000}
1001
1002func TestAPI_AgentJoin(t *testing.T) {
1003	t.Parallel()
1004	c, s := makeClient(t)
1005	defer s.Stop()
1006
1007	agent := c.Agent()
1008
1009	info, err := agent.Self()
1010	if err != nil {
1011		t.Fatalf("err: %v", err)
1012	}
1013
1014	// Join ourself
1015	addr := info["DebugConfig"]["SerfAdvertiseAddrLAN"].(string)
1016	// strip off 'tcp://'
1017	addr = addr[len("tcp://"):]
1018	err = agent.Join(addr, false)
1019	if err != nil {
1020		t.Fatalf("err: %v", err)
1021	}
1022}
1023
1024func TestAPI_AgentLeave(t *testing.T) {
1025	t.Parallel()
1026	c1, s1 := makeClient(t)
1027	defer s1.Stop()
1028
1029	c2, s2 := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
1030		conf.Server = false
1031		conf.Bootstrap = false
1032	})
1033	defer s2.Stop()
1034
1035	if err := c2.Agent().Join(s1.LANAddr, false); err != nil {
1036		t.Fatalf("err: %v", err)
1037	}
1038
1039	// We sometimes see an EOF response to this one, depending on timing.
1040	err := c2.Agent().Leave()
1041	if err != nil && !strings.Contains(err.Error(), "EOF") {
1042		t.Fatalf("err: %v", err)
1043	}
1044
1045	// Make sure the second agent's status is 'Left'
1046	members, err := c1.Agent().Members(false)
1047	if err != nil {
1048		t.Fatalf("err: %v", err)
1049	}
1050	member := members[0]
1051	if member.Name == s1.Config.NodeName {
1052		member = members[1]
1053	}
1054	if member.Status != int(serf.StatusLeft) {
1055		t.Fatalf("bad: %v", *member)
1056	}
1057}
1058
1059func TestAPI_AgentForceLeave(t *testing.T) {
1060	t.Parallel()
1061	c, s := makeClient(t)
1062	defer s.Stop()
1063
1064	agent := c.Agent()
1065
1066	// Eject somebody
1067	err := agent.ForceLeave("foo")
1068	if err != nil {
1069		t.Fatalf("err: %v", err)
1070	}
1071}
1072
1073func TestAPI_AgentMonitor(t *testing.T) {
1074	t.Parallel()
1075	c, s := makeClient(t)
1076	defer s.Stop()
1077
1078	agent := c.Agent()
1079
1080	logCh, err := agent.Monitor("info", nil, nil)
1081	if err != nil {
1082		t.Fatalf("err: %v", err)
1083	}
1084
1085	// Wait for the first log message and validate it
1086	select {
1087	case log := <-logCh:
1088		if !strings.Contains(log, "[INFO]") {
1089			t.Fatalf("bad: %q", log)
1090		}
1091	case <-time.After(10 * time.Second):
1092		t.Fatalf("failed to get a log message")
1093	}
1094}
1095
1096func TestAPI_ServiceMaintenance(t *testing.T) {
1097	t.Parallel()
1098	c, s := makeClient(t)
1099	defer s.Stop()
1100
1101	agent := c.Agent()
1102
1103	// First register a service
1104	serviceReg := &AgentServiceRegistration{
1105		Name: "redis",
1106	}
1107	if err := agent.ServiceRegister(serviceReg); err != nil {
1108		t.Fatalf("err: %v", err)
1109	}
1110
1111	// Enable maintenance mode
1112	if err := agent.EnableServiceMaintenance("redis", "broken"); err != nil {
1113		t.Fatalf("err: %s", err)
1114	}
1115
1116	// Ensure a critical check was added
1117	checks, err := agent.Checks()
1118	if err != nil {
1119		t.Fatalf("err: %v", err)
1120	}
1121	found := false
1122	for _, check := range checks {
1123		if strings.Contains(check.CheckID, "maintenance") {
1124			found = true
1125			if check.Status != HealthCritical || check.Notes != "broken" {
1126				t.Fatalf("bad: %#v", checks)
1127			}
1128		}
1129	}
1130	if !found {
1131		t.Fatalf("bad: %#v", checks)
1132	}
1133
1134	// Disable maintenance mode
1135	if err := agent.DisableServiceMaintenance("redis"); err != nil {
1136		t.Fatalf("err: %s", err)
1137	}
1138
1139	// Ensure the critical health check was removed
1140	checks, err = agent.Checks()
1141	if err != nil {
1142		t.Fatalf("err: %s", err)
1143	}
1144	for _, check := range checks {
1145		if strings.Contains(check.CheckID, "maintenance") {
1146			t.Fatalf("should have removed health check")
1147		}
1148	}
1149}
1150
1151func TestAPI_NodeMaintenance(t *testing.T) {
1152	t.Parallel()
1153	c, s := makeClient(t)
1154	defer s.Stop()
1155
1156	agent := c.Agent()
1157
1158	// Enable maintenance mode
1159	if err := agent.EnableNodeMaintenance("broken"); err != nil {
1160		t.Fatalf("err: %s", err)
1161	}
1162
1163	// Check that a critical check was added
1164	checks, err := agent.Checks()
1165	if err != nil {
1166		t.Fatalf("err: %s", err)
1167	}
1168	found := false
1169	for _, check := range checks {
1170		if strings.Contains(check.CheckID, "maintenance") {
1171			found = true
1172			if check.Status != HealthCritical || check.Notes != "broken" {
1173				t.Fatalf("bad: %#v", checks)
1174			}
1175		}
1176	}
1177	if !found {
1178		t.Fatalf("bad: %#v", checks)
1179	}
1180
1181	// Disable maintenance mode
1182	if err := agent.DisableNodeMaintenance(); err != nil {
1183		t.Fatalf("err: %s", err)
1184	}
1185
1186	// Ensure the check was removed
1187	checks, err = agent.Checks()
1188	if err != nil {
1189		t.Fatalf("err: %s", err)
1190	}
1191	for _, check := range checks {
1192		if strings.Contains(check.CheckID, "maintenance") {
1193			t.Fatalf("should have removed health check")
1194		}
1195	}
1196}
1197
1198func TestAPI_AgentUpdateToken(t *testing.T) {
1199	t.Parallel()
1200	c, s := makeACLClient(t)
1201	defer s.Stop()
1202
1203	agent := c.Agent()
1204
1205	if _, err := agent.UpdateACLToken("root", nil); err != nil {
1206		t.Fatalf("err: %v", err)
1207	}
1208
1209	if _, err := agent.UpdateACLAgentToken("root", nil); err != nil {
1210		t.Fatalf("err: %v", err)
1211	}
1212
1213	if _, err := agent.UpdateACLAgentMasterToken("root", nil); err != nil {
1214		t.Fatalf("err: %v", err)
1215	}
1216
1217	if _, err := agent.UpdateACLReplicationToken("root", nil); err != nil {
1218		t.Fatalf("err: %v", err)
1219	}
1220}
1221
1222func TestAPI_AgentConnectCARoots_empty(t *testing.T) {
1223	t.Parallel()
1224
1225	require := require.New(t)
1226	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
1227		c.Connect = nil // disable connect to prevent CA being bootstrapped
1228	})
1229	defer s.Stop()
1230
1231	agent := c.Agent()
1232	_, _, err := agent.ConnectCARoots(nil)
1233	require.Error(err)
1234	require.Contains(err.Error(), "Connect must be enabled")
1235}
1236
1237func TestAPI_AgentConnectCARoots_list(t *testing.T) {
1238	t.Parallel()
1239
1240	require := require.New(t)
1241	c, s := makeClient(t)
1242	defer s.Stop()
1243
1244	agent := c.Agent()
1245	s.WaitForSerfCheck(t)
1246	list, meta, err := agent.ConnectCARoots(nil)
1247	require.NoError(err)
1248	require.True(meta.LastIndex > 0)
1249	require.Len(list.Roots, 1)
1250}
1251
1252func TestAPI_AgentConnectCALeaf(t *testing.T) {
1253	t.Parallel()
1254
1255	require := require.New(t)
1256	c, s := makeClient(t)
1257	defer s.Stop()
1258
1259	agent := c.Agent()
1260	// Setup service
1261	reg := &AgentServiceRegistration{
1262		Name: "foo",
1263		Tags: []string{"bar", "baz"},
1264		Port: 8000,
1265	}
1266	require.NoError(agent.ServiceRegister(reg))
1267
1268	leaf, meta, err := agent.ConnectCALeaf("foo", nil)
1269	require.NoError(err)
1270	require.True(meta.LastIndex > 0)
1271	// Sanity checks here as we have actual certificate validation checks at many
1272	// other levels.
1273	require.NotEmpty(leaf.SerialNumber)
1274	require.NotEmpty(leaf.CertPEM)
1275	require.NotEmpty(leaf.PrivateKeyPEM)
1276	require.Equal("foo", leaf.Service)
1277	require.True(strings.HasSuffix(leaf.ServiceURI, "/svc/foo"))
1278	require.True(leaf.ModifyIndex > 0)
1279	require.True(leaf.ValidAfter.Before(time.Now()))
1280	require.True(leaf.ValidBefore.After(time.Now()))
1281}
1282
1283func TestAPI_AgentConnectAuthorize(t *testing.T) {
1284	t.Parallel()
1285	require := require.New(t)
1286	c, s := makeClient(t)
1287	defer s.Stop()
1288
1289	agent := c.Agent()
1290	s.WaitForSerfCheck(t)
1291	params := &AgentAuthorizeParams{
1292		Target:           "foo",
1293		ClientCertSerial: "fake",
1294		// Importing connect.TestSpiffeIDService creates an import cycle
1295		ClientCertURI: "spiffe://11111111-2222-3333-4444-555555555555.consul/ns/default/dc/ny1/svc/web",
1296	}
1297	auth, err := agent.ConnectAuthorize(params)
1298	require.Nil(err)
1299	require.True(auth.Authorized)
1300	require.Equal(auth.Reason, "ACLs disabled, access is allowed by default")
1301}
1302
1303func TestAPI_AgentConnectProxyConfig(t *testing.T) {
1304	t.Parallel()
1305	c, s := makeClientWithConfig(t, nil, func(c *testutil.TestServerConfig) {
1306		// Force auto port range to 1 port so we have deterministic response.
1307		c.Ports.ProxyMinPort = 20000
1308		c.Ports.ProxyMaxPort = 20000
1309	})
1310	defer s.Stop()
1311
1312	agent := c.Agent()
1313	reg := &AgentServiceRegistration{
1314		Name: "foo",
1315		Tags: []string{"bar", "baz"},
1316		Port: 8000,
1317		Connect: &AgentServiceConnect{
1318			Proxy: &AgentServiceConnectProxy{
1319				Command: []string{"consul", "connect", "proxy"},
1320				Config: map[string]interface{}{
1321					"foo": "bar",
1322				},
1323				Upstreams: testUpstreams(t),
1324			},
1325		},
1326	}
1327	if err := agent.ServiceRegister(reg); err != nil {
1328		t.Fatalf("err: %v", err)
1329	}
1330
1331	config, qm, err := agent.ConnectProxyConfig("foo-proxy", nil)
1332	require.NoError(t, err)
1333	expectConfig := &ConnectProxyConfig{
1334		ProxyServiceID:    "foo-proxy",
1335		TargetServiceID:   "foo",
1336		TargetServiceName: "foo",
1337		ContentHash:       "acdf5eb6f5794a14",
1338		ExecMode:          "daemon",
1339		Command:           []string{"consul", "connect", "proxy"},
1340		Config: map[string]interface{}{
1341			"bind_address":          "127.0.0.1",
1342			"bind_port":             float64(20000),
1343			"foo":                   "bar",
1344			"local_service_address": "127.0.0.1:8000",
1345		},
1346		Upstreams: testExpectUpstreamsWithDefaults(t, reg.Connect.Proxy.Upstreams),
1347	}
1348	require.Equal(t, expectConfig, config)
1349	require.Equal(t, expectConfig.ContentHash, qm.LastContentHash)
1350}
1351