github.com/wuhuizuo/gomplate@v3.5.0+incompatible/tests/integration/datasources_consul_test.go (about)

     1  //+build integration
     2  //+build !windows
     3  
     4  package integration
     5  
     6  import (
     7  	"encoding/base64"
     8  	"io/ioutil"
     9  	"os"
    10  	"os/user"
    11  	"path"
    12  	"strconv"
    13  
    14  	. "gopkg.in/check.v1"
    15  
    16  	"github.com/gotestyourself/gotestyourself/fs"
    17  	"github.com/gotestyourself/gotestyourself/icmd"
    18  	vaultapi "github.com/hashicorp/vault/api"
    19  )
    20  
    21  type ConsulDatasourcesSuite struct {
    22  	tmpDir       *fs.Dir
    23  	pidDir       *fs.Dir
    24  	consulAddr   string
    25  	consulResult *icmd.Result
    26  	vaultAddr    string
    27  	vaultResult  *icmd.Result
    28  }
    29  
    30  var _ = Suite(&ConsulDatasourcesSuite{})
    31  
    32  const consulRootToken = "00000000-1111-2222-3333-444455556666"
    33  
    34  func (s *ConsulDatasourcesSuite) SetUpSuite(c *C) {
    35  	s.pidDir = fs.NewDir(c, "gomplate-inttests-pid")
    36  	s.tmpDir = fs.NewDir(c, "gomplate-inttests",
    37  		fs.WithFile(
    38  			"consul.json",
    39  			`{"acl_datacenter": "dc1", "acl_master_token": "`+consulRootToken+`"}`,
    40  		),
    41  		fs.WithFile("vault.json", `{
    42  			"pid_file": "`+s.pidDir.Join("vault.pid")+`"
    43  			}`),
    44  	)
    45  	var port int
    46  	port, s.consulAddr = freeport()
    47  	consul := icmd.Command("consul", "agent",
    48  		"-dev",
    49  		"-config-file="+s.tmpDir.Join("consul.json"),
    50  		"-log-level=err",
    51  		"-http-port="+strconv.Itoa(port),
    52  		"-pid-file="+s.pidDir.Join("consul.pid"),
    53  	)
    54  	s.consulResult = icmd.StartCmd(consul)
    55  
    56  	c.Logf("Fired up Consul: %v", consul)
    57  
    58  	err := waitForURL(c, "http://"+s.consulAddr+"/v1/status/leader")
    59  	handle(c, err)
    60  
    61  	s.startVault(c)
    62  }
    63  
    64  func (s *ConsulDatasourcesSuite) startVault(c *C) {
    65  	// rename any existing token so it doesn't get overridden
    66  	u, _ := user.Current()
    67  	homeDir := u.HomeDir
    68  	tokenFile := path.Join(homeDir, ".vault-token")
    69  	info, err := os.Stat(tokenFile)
    70  	if err == nil && info.Mode().IsRegular() {
    71  		os.Rename(tokenFile, path.Join(homeDir, ".vault-token.bak"))
    72  	}
    73  
    74  	_, s.vaultAddr = freeport()
    75  	vault := icmd.Command("vault", "server",
    76  		"-dev",
    77  		"-dev-root-token-id="+vaultRootToken,
    78  		"-log-level=err",
    79  		"-dev-listen-address="+s.vaultAddr,
    80  		"-config="+s.tmpDir.Join("vault.json"),
    81  	)
    82  	s.vaultResult = icmd.StartCmd(vault)
    83  
    84  	c.Logf("Fired up Vault: %v", vault)
    85  
    86  	err = waitForURL(c, "http://"+s.vaultAddr+"/v1/sys/health")
    87  	handle(c, err)
    88  }
    89  
    90  func killByPidFile(pidFile string) error {
    91  	p, err := ioutil.ReadFile(pidFile)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	pid, err := strconv.Atoi(string(p))
    96  	if err != nil {
    97  		return err
    98  	}
    99  	process, err := os.FindProcess(pid)
   100  	if err != nil {
   101  		return err
   102  	}
   103  	err = process.Kill()
   104  	return err
   105  }
   106  
   107  func (s *ConsulDatasourcesSuite) TearDownSuite(c *C) {
   108  	defer s.tmpDir.Remove()
   109  	defer s.pidDir.Remove()
   110  
   111  	err := killByPidFile(s.pidDir.Join("vault.pid"))
   112  	handle(c, err)
   113  
   114  	err = killByPidFile(s.pidDir.Join("consul.pid"))
   115  	handle(c, err)
   116  
   117  	// restore old vault token if it was backed up
   118  	u, _ := user.Current()
   119  	homeDir := u.HomeDir
   120  	tokenFile := path.Join(homeDir, ".vault-token.bak")
   121  	info, err := os.Stat(tokenFile)
   122  	if err == nil && info.Mode().IsRegular() {
   123  		os.Rename(tokenFile, path.Join(homeDir, ".vault-token"))
   124  	}
   125  }
   126  
   127  func (s *ConsulDatasourcesSuite) consulPut(c *C, k, v string) {
   128  	result := icmd.RunCmd(icmd.Command("consul", "kv", "put", k, v),
   129  		func(c *icmd.Cmd) {
   130  			c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
   131  		})
   132  	result.Assert(c, icmd.Success)
   133  }
   134  
   135  func (s *ConsulDatasourcesSuite) consulDelete(c *C, k string) {
   136  	result := icmd.RunCmd(icmd.Command("consul", "kv", "delete", k),
   137  		func(c *icmd.Cmd) {
   138  			c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
   139  		})
   140  	result.Assert(c, icmd.Success)
   141  }
   142  
   143  func (s *ConsulDatasourcesSuite) TestConsulDatasource(c *C) {
   144  	s.consulPut(c, "foo1", "bar")
   145  	defer s.consulDelete(c, "foo1")
   146  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   147  		"-d", "consul=consul://",
   148  		"-i", `{{(ds "consul" "foo1")}}`,
   149  	), func(c *icmd.Cmd) {
   150  		c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
   151  	})
   152  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   153  
   154  	s.consulPut(c, "foo2", `{"bar": "baz"}`)
   155  	defer s.consulDelete(c, "foo2")
   156  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   157  		"-d", "consul=consul://?type=application/json",
   158  		"-i", `{{(ds "consul" "foo2").bar}}`,
   159  	), func(c *icmd.Cmd) {
   160  		c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
   161  	})
   162  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "baz"})
   163  
   164  	s.consulPut(c, "foo2", `bar`)
   165  	defer s.consulDelete(c, "foo2")
   166  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   167  		"-d", "consul=consul://"+s.consulAddr,
   168  		"-i", `{{(ds "consul" "foo2")}}`,
   169  	))
   170  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   171  
   172  	s.consulPut(c, "foo3", `bar`)
   173  	defer s.consulDelete(c, "foo3")
   174  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   175  		"-d", "consul=consul+http://"+s.consulAddr,
   176  		"-i", `{{(ds "consul" "foo3")}}`,
   177  	))
   178  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   179  }
   180  
   181  func (s *ConsulDatasourcesSuite) TestConsulDatasourceListKeys(c *C) {
   182  	s.consulPut(c, "list-of-keys/foo1", `{"bar1": "bar1"}`)
   183  	s.consulPut(c, "list-of-keys/foo2", "bar2")
   184  	defer s.consulDelete(c, "list-of-keys")
   185  
   186  	// Get a list of keys using the ds args
   187  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   188  		"-d", "consul=consul://",
   189  		"-i", `{{(ds "consul" "list-of-keys/") | data.ToJSON }}`,
   190  	), func(c *icmd.Cmd) {
   191  		c.Env = []string{"CONSUL_HTTP_ADDR=http://" + s.consulAddr}
   192  	})
   193  	expectedResult := `[{"key":"foo1","value":"{\"bar1\": \"bar1\"}"},{"key":"foo2","value":"bar2"}]`
   194  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: expectedResult})
   195  
   196  	// Get a list of keys using the ds uri
   197  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   198  		"-d", "consul=consul+http://"+s.consulAddr+"/list-of-keys/",
   199  		"-i", `{{(ds "consul" ) | data.ToJSON }}`,
   200  	))
   201  	expectedResult = `[{"key":"foo1","value":"{\"bar1\": \"bar1\"}"},{"key":"foo2","value":"bar2"}]`
   202  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: expectedResult})
   203  
   204  	// Get a specific value from the list of Consul keys
   205  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   206  		"-d", "consul=consul+http://"+s.consulAddr+"/list-of-keys/",
   207  		"-i", `{{ $data := (ds "consul") }} {{ (index $data 0).value }}`,
   208  	))
   209  	expectedResult = `{"bar1": "bar1"}`
   210  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: expectedResult})
   211  }
   212  
   213  func (s *ConsulDatasourcesSuite) TestConsulWithVaultAuth(c *C) {
   214  	v, err := createVaultClient(s.vaultAddr, vaultRootToken)
   215  	handle(c, err)
   216  
   217  	err = v.vc.Sys().Mount("consul/", &vaultapi.MountInput{Type: "consul"})
   218  	handle(c, err)
   219  	defer v.vc.Sys().Unmount("consul/")
   220  
   221  	_, err = v.vc.Logical().Write("consul/config/access", map[string]interface{}{
   222  		"address": s.consulAddr, "token": consulRootToken,
   223  	})
   224  	handle(c, err)
   225  	policy := base64.StdEncoding.EncodeToString([]byte(`key "" { policy = "read" }`))
   226  	_, err = v.vc.Logical().Write("consul/roles/readonly", map[string]interface{}{"policy": policy})
   227  	handle(c, err)
   228  
   229  	s.consulPut(c, "foo", "bar")
   230  	defer s.consulDelete(c, "foo")
   231  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   232  		"-d", "consul=consul://",
   233  		"-i", `{{(ds "consul" "foo")}}`,
   234  	), func(c *icmd.Cmd) {
   235  		c.Env = []string{
   236  			"VAULT_TOKEN=" + vaultRootToken,
   237  			"VAULT_ADDR=http://" + s.vaultAddr,
   238  			"CONSUL_VAULT_ROLE=readonly",
   239  			"CONSUL_HTTP_ADDR=http://" + s.consulAddr,
   240  		}
   241  	})
   242  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   243  }