github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/internal/tests/integration/datasources_consul_test.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package integration
     5  
     6  import (
     7  	"strconv"
     8  	"testing"
     9  
    10  	vaultapi "github.com/hashicorp/vault/api"
    11  	"github.com/stretchr/testify/require"
    12  	"gotest.tools/v3/fs"
    13  	"gotest.tools/v3/icmd"
    14  )
    15  
    16  const consulRootToken = "00000000-1111-2222-3333-444455556666"
    17  
    18  func setupDatasourcesConsulTest(t *testing.T) (string, *vaultClient) {
    19  	pidDir := fs.NewDir(t, "gomplate-inttests-pid")
    20  	t.Cleanup(pidDir.Remove)
    21  
    22  	httpPort, consulAddr := freeport(t)
    23  	serverPort, _ := freeport(t)
    24  	serfLanPort, _ := freeport(t)
    25  
    26  	tmpDir := fs.NewDir(t, "gomplate-inttests",
    27  		fs.WithFile(
    28  			"consul.json",
    29  			`{
    30  				"log_level": "err",
    31  				"primary_datacenter": "dc1",
    32  				"acl": {
    33  					"enabled": true,
    34  					"tokens": {
    35  						"initial_management": "`+consulRootToken+`",
    36  						"default": "`+consulRootToken+`"
    37  					}
    38  				},
    39  				"ports": {
    40  					"http": `+strconv.Itoa(httpPort)+`,
    41  					"server": `+strconv.Itoa(serverPort)+`,
    42  					"serf_lan": `+strconv.Itoa(serfLanPort)+`,
    43  					"serf_wan": -1,
    44  					"dns": -1,
    45  					"grpc": -1
    46  				},
    47  				"connect": { "enabled": false }
    48  			}`,
    49  		),
    50  		fs.WithFile("vault.json", `{
    51  		"pid_file": "`+pidDir.Join("vault.pid")+`"
    52  		}`),
    53  	)
    54  	t.Cleanup(tmpDir.Remove)
    55  
    56  	consul := icmd.Command("consul", "agent",
    57  		"-dev",
    58  		"-config-file="+tmpDir.Join("consul.json"),
    59  		"-pid-file="+pidDir.Join("consul.pid"),
    60  	)
    61  	consulResult := icmd.StartCmd(consul)
    62  	t.Cleanup(func() {
    63  		err := consulResult.Cmd.Process.Kill()
    64  		require.NoError(t, err)
    65  
    66  		consulResult.Cmd.Wait()
    67  
    68  		t.Logf("consul logs:\n%s\n", consulResult.Combined())
    69  
    70  		consulResult.Assert(t, icmd.Expected{ExitCode: 0})
    71  	})
    72  
    73  	t.Logf("Fired up Consul: %v", consul)
    74  
    75  	err := waitForURL(t, "http://"+consulAddr+"/v1/status/leader")
    76  	require.NoError(t, err)
    77  
    78  	_, vaultClient := startVault(t)
    79  
    80  	// create a readonly policy, for use in some tests
    81  	aclResult := icmd.RunCmd(icmd.Command("consul", "acl", "policy", "create",
    82  		"-name", "readonly",
    83  		"-rules", `acl = "read"`,
    84  		"-token", consulRootToken,
    85  		"-http-addr", "http://"+consulAddr,
    86  	))
    87  	aclResult.Assert(t, icmd.Success)
    88  
    89  	return consulAddr, vaultClient
    90  }
    91  
    92  func consulPut(t *testing.T, consulAddr, k, v string) {
    93  	result := icmd.RunCmd(icmd.Command("consul", "kv", "put", k, v),
    94  		func(c *icmd.Cmd) {
    95  			c.Env = []string{"CONSUL_HTTP_ADDR=http://" + consulAddr}
    96  		})
    97  	result.Assert(t, icmd.Success)
    98  	t.Cleanup(func() {
    99  		result := icmd.RunCmd(icmd.Command("consul", "kv", "delete", k),
   100  			func(c *icmd.Cmd) {
   101  				c.Env = []string{"CONSUL_HTTP_ADDR=http://" + consulAddr}
   102  			})
   103  		result.Assert(t, icmd.Success)
   104  	})
   105  }
   106  
   107  func TestDatasources_Consul(t *testing.T) {
   108  	consulAddr, _ := setupDatasourcesConsulTest(t)
   109  	consulPut(t, consulAddr, "foo1", "bar")
   110  
   111  	o, e, err := cmd(t, "-d", "consul=consul://",
   112  		"-i", `{{(ds "consul" "foo1")}}`).
   113  		withEnv("CONSUL_HTTP_ADDR", "http://"+consulAddr).run()
   114  	assertSuccess(t, o, e, err, "bar")
   115  
   116  	consulPut(t, consulAddr, "foo2", `{"bar": "baz"}`)
   117  
   118  	o, e, err = cmd(t, "-d", "consul=consul://?type=application/json",
   119  		"-i", `{{(ds "consul" "foo2").bar}}`).
   120  		withEnv("CONSUL_HTTP_ADDR", "http://"+consulAddr).run()
   121  	assertSuccess(t, o, e, err, "baz")
   122  
   123  	consulPut(t, consulAddr, "foo2", `bar`)
   124  
   125  	o, e, err = cmd(t, "-d", "consul=consul://"+consulAddr,
   126  		"-i", `{{(ds "consul" "foo2")}}`).run()
   127  	assertSuccess(t, o, e, err, "bar")
   128  
   129  	consulPut(t, consulAddr, "foo3", `bar`)
   130  
   131  	o, e, err = cmd(t, "-d", "consul=consul+http://"+consulAddr,
   132  		"-i", `{{(ds "consul" "foo3")}}`).run()
   133  	assertSuccess(t, o, e, err, "bar")
   134  }
   135  
   136  func TestDatasources_Consul_ListKeys(t *testing.T) {
   137  	consulAddr, _ := setupDatasourcesConsulTest(t)
   138  	consulPut(t, consulAddr, "list-of-keys/foo1", `{"bar1": "bar1"}`)
   139  	consulPut(t, consulAddr, "list-of-keys/foo2", "bar2")
   140  
   141  	// Get a list of keys using the ds args
   142  	// expectedResult := `[{"key":"foo1","value":"{\"bar1\": \"bar1\"}"},{"key":"foo2","value":"bar2"}]`
   143  	expectedResult := `["foo1","foo2"]`
   144  	o, e, err := cmd(t, "-d", "consul=consul://",
   145  		"-i", `{{(ds "consul" "list-of-keys/") | data.ToJSON }}`).
   146  		withEnv("CONSUL_HTTP_ADDR", "http://"+consulAddr).run()
   147  	assertSuccess(t, o, e, err, expectedResult)
   148  
   149  	// Get a list of keys using the ds uri
   150  	// expectedResult = `[{"key":"foo1","value":"{\"bar1\": \"bar1\"}"},{"key":"foo2","value":"bar2"}]`
   151  	expectedResult = `["foo1","foo2"]`
   152  	o, e, err = cmd(t, "-d", "consul=consul+http://"+consulAddr+"/list-of-keys/",
   153  		"-i", `{{(ds "consul" ) | data.ToJSON }}`).run()
   154  	assertSuccess(t, o, e, err, expectedResult)
   155  
   156  	// TODO: this doesn't work anymore because consulfs returns a directory
   157  	// listing now.
   158  	//
   159  	// // Get a specific value from the list of Consul keys
   160  	// expectedResult = `{"bar1": "bar1"}`
   161  	// o, e, err = cmd(t, "-d", "consul=consul+http://"+consulAddr+"/list-of-keys/",
   162  	// 	"-i", `{{ $data := ds "consul" }}{{ (index $data 0).value }}`).run()
   163  	// assertSuccess(t, o, e, err, expectedResult)
   164  }
   165  
   166  func TestDatasources_Consul_WithVaultAuth(t *testing.T) {
   167  	consulAddr, v := setupDatasourcesConsulTest(t)
   168  
   169  	err := v.vc.Sys().Mount("consul/", &vaultapi.MountInput{Type: "consul"})
   170  	require.NoError(t, err)
   171  	defer v.vc.Sys().Unmount("consul/")
   172  
   173  	_, err = v.vc.Logical().Write("consul/config/access", map[string]interface{}{
   174  		"address": consulAddr, "token": consulRootToken,
   175  	})
   176  	require.NoError(t, err)
   177  	_, err = v.vc.Logical().Write("consul/roles/readonly", map[string]interface{}{
   178  		"policies": "readonly",
   179  	})
   180  	require.NoError(t, err)
   181  
   182  	consulPut(t, consulAddr, "foo", "bar")
   183  
   184  	o, e, err := cmd(t,
   185  		"-d", "consul=consul://",
   186  		"-i", `{{(ds "consul" "foo")}}`).
   187  		withEnv("VAULT_TOKEN", vaultRootToken).
   188  		withEnv("VAULT_ADDR", "http://"+v.addr).
   189  		withEnv("CONSUL_VAULT_ROLE", "readonly").
   190  		withEnv("CONSUL_HTTP_ADDR", "http://"+consulAddr).
   191  		run()
   192  	assertSuccess(t, o, e, err, "bar")
   193  }