github.com/DerekStrickland/consul@v1.4.5/agent/consul/txn_endpoint_test.go (about)

     1  package consul
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"reflect"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/hashicorp/consul/acl"
    12  	"github.com/hashicorp/consul/agent/structs"
    13  	"github.com/hashicorp/consul/api"
    14  	"github.com/hashicorp/consul/testrpc"
    15  	"github.com/hashicorp/consul/types"
    16  	"github.com/hashicorp/net-rpc-msgpackrpc"
    17  	"github.com/pascaldekloe/goe/verify"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  var testTxnRules = `
    22  key "" {
    23  	policy = "deny"
    24  }
    25  key "foo" {
    26  	policy = "read"
    27  }
    28  key "test" {
    29  	policy = "write"
    30  }
    31  key "test/priv" {
    32  	policy = "read"
    33  }
    34  
    35  service "" {
    36  	policy = "deny"
    37  }
    38  service "foo-svc" {
    39  	policy = "read"
    40  }
    41  service "test-svc" {
    42  	policy = "write"
    43  }
    44  
    45  node "" {
    46  	policy = "deny"
    47  }
    48  node "foo-node" {
    49  	policy = "read"
    50  }
    51  node "test-node" {
    52  	policy = "write"
    53  }
    54  `
    55  
    56  var testNodeID = "9749a7df-fac5-46b4-8078-32a3d96c59f3"
    57  
    58  func TestTxn_CheckNotExists(t *testing.T) {
    59  	t.Parallel()
    60  	dir1, s1 := testServer(t)
    61  	defer os.RemoveAll(dir1)
    62  	defer s1.Shutdown()
    63  	codec := rpcClient(t, s1)
    64  	defer codec.Close()
    65  
    66  	testrpc.WaitForLeader(t, s1.RPC, "dc1")
    67  
    68  	apply := func(arg *structs.TxnRequest) (*structs.TxnResponse, error) {
    69  		out := new(structs.TxnResponse)
    70  		err := msgpackrpc.CallWithCodec(codec, "Txn.Apply", arg, out)
    71  		return out, err
    72  	}
    73  
    74  	checkKeyNotExists := &structs.TxnRequest{
    75  		Datacenter: "dc1",
    76  		Ops: structs.TxnOps{
    77  			{
    78  				KV: &structs.TxnKVOp{
    79  					Verb:   api.KVCheckNotExists,
    80  					DirEnt: structs.DirEntry{Key: "test"},
    81  				},
    82  			},
    83  		},
    84  	}
    85  
    86  	createKey := &structs.TxnRequest{
    87  		Datacenter: "dc1",
    88  		Ops: structs.TxnOps{
    89  			{
    90  				KV: &structs.TxnKVOp{
    91  					Verb:   api.KVSet,
    92  					DirEnt: structs.DirEntry{Key: "test"},
    93  				},
    94  			},
    95  		},
    96  	}
    97  
    98  	if _, err := apply(checkKeyNotExists); err != nil {
    99  		t.Fatalf("testing for non-existent key failed: %s", err)
   100  	}
   101  	if _, err := apply(createKey); err != nil {
   102  		t.Fatalf("creating new key failed: %s", err)
   103  	}
   104  	out, err := apply(checkKeyNotExists)
   105  	if err != nil || out == nil || len(out.Errors) != 1 || out.Errors[0].Error() != `op 0: key "test" exists` {
   106  		t.Fatalf("testing for existent key failed: %#v", out)
   107  	}
   108  }
   109  
   110  func TestTxn_Apply(t *testing.T) {
   111  	t.Parallel()
   112  	dir1, s1 := testServer(t)
   113  	defer os.RemoveAll(dir1)
   114  	defer s1.Shutdown()
   115  	codec := rpcClient(t, s1)
   116  	defer codec.Close()
   117  
   118  	testrpc.WaitForLeader(t, s1.RPC, "dc1")
   119  
   120  	// Do a super basic request. The state store test covers the details so
   121  	// we just need to be sure that the transaction is sent correctly and
   122  	// the results are converted appropriately.
   123  	arg := structs.TxnRequest{
   124  		Datacenter: "dc1",
   125  		Ops: structs.TxnOps{
   126  			&structs.TxnOp{
   127  				KV: &structs.TxnKVOp{
   128  					Verb: api.KVSet,
   129  					DirEnt: structs.DirEntry{
   130  						Key:   "test",
   131  						Flags: 42,
   132  						Value: []byte("test"),
   133  					},
   134  				},
   135  			},
   136  			&structs.TxnOp{
   137  				KV: &structs.TxnKVOp{
   138  					Verb: api.KVGet,
   139  					DirEnt: structs.DirEntry{
   140  						Key: "test",
   141  					},
   142  				},
   143  			},
   144  			&structs.TxnOp{
   145  				Node: &structs.TxnNodeOp{
   146  					Verb: api.NodeSet,
   147  					Node: structs.Node{
   148  						ID:      types.NodeID(testNodeID),
   149  						Node:    "foo",
   150  						Address: "127.0.0.1",
   151  					},
   152  				},
   153  			},
   154  			&structs.TxnOp{
   155  				Node: &structs.TxnNodeOp{
   156  					Verb: api.NodeGet,
   157  					Node: structs.Node{
   158  						ID:   types.NodeID(testNodeID),
   159  						Node: "foo",
   160  					},
   161  				},
   162  			},
   163  			&structs.TxnOp{
   164  				Service: &structs.TxnServiceOp{
   165  					Verb: api.ServiceSet,
   166  					Node: "foo",
   167  					Service: structs.NodeService{
   168  						ID:      "svc-foo",
   169  						Service: "svc-foo",
   170  						Address: "1.1.1.1",
   171  					},
   172  				},
   173  			},
   174  			&structs.TxnOp{
   175  				Service: &structs.TxnServiceOp{
   176  					Verb: api.ServiceGet,
   177  					Node: "foo",
   178  					Service: structs.NodeService{
   179  						ID:      "svc-foo",
   180  						Service: "svc-foo",
   181  					},
   182  				},
   183  			},
   184  			&structs.TxnOp{
   185  				Check: &structs.TxnCheckOp{
   186  					Verb: api.CheckSet,
   187  					Check: structs.HealthCheck{
   188  						Node:    "foo",
   189  						CheckID: types.CheckID("check-foo"),
   190  						Name:    "test",
   191  						Status:  "passing",
   192  					},
   193  				},
   194  			},
   195  			&structs.TxnOp{
   196  				Check: &structs.TxnCheckOp{
   197  					Verb: api.CheckGet,
   198  					Check: structs.HealthCheck{
   199  						Node:    "foo",
   200  						CheckID: types.CheckID("check-foo"),
   201  						Name:    "test",
   202  					},
   203  				},
   204  			},
   205  		},
   206  	}
   207  	var out structs.TxnResponse
   208  	if err := msgpackrpc.CallWithCodec(codec, "Txn.Apply", &arg, &out); err != nil {
   209  		t.Fatalf("err: %v", err)
   210  	}
   211  	if len(out.Errors) != 0 {
   212  		t.Fatalf("errs: %v", out.Errors)
   213  	}
   214  
   215  	// Verify the state store directly.
   216  	state := s1.fsm.State()
   217  	_, d, err := state.KVSGet(nil, "test")
   218  	if err != nil {
   219  		t.Fatalf("err: %v", err)
   220  	}
   221  	if d == nil {
   222  		t.Fatalf("should not be nil")
   223  	}
   224  	if d.Flags != 42 ||
   225  		!bytes.Equal(d.Value, []byte("test")) {
   226  		t.Fatalf("bad: %v", d)
   227  	}
   228  
   229  	_, n, err := state.GetNode("foo")
   230  	if err != nil {
   231  		t.Fatalf("err: %v", err)
   232  	}
   233  	if n.Node != "foo" || n.Address != "127.0.0.1" {
   234  		t.Fatalf("bad: %v", err)
   235  	}
   236  
   237  	_, s, err := state.NodeService("foo", "svc-foo")
   238  	if err != nil {
   239  		t.Fatalf("err: %v", err)
   240  	}
   241  	if s.ID != "svc-foo" || s.Address != "1.1.1.1" {
   242  		t.Fatalf("bad: %v", err)
   243  	}
   244  
   245  	_, c, err := state.NodeCheck("foo", types.CheckID("check-foo"))
   246  	if err != nil {
   247  		t.Fatalf("err: %v", err)
   248  	}
   249  	if c.CheckID != "check-foo" || c.Status != "passing" || c.Name != "test" {
   250  		t.Fatalf("bad: %v", err)
   251  	}
   252  
   253  	// Verify the transaction's return value.
   254  	expected := structs.TxnResponse{
   255  		Results: structs.TxnResults{
   256  			&structs.TxnResult{
   257  				KV: &structs.DirEntry{
   258  					Key:   "test",
   259  					Flags: 42,
   260  					Value: nil,
   261  					RaftIndex: structs.RaftIndex{
   262  						CreateIndex: d.CreateIndex,
   263  						ModifyIndex: d.ModifyIndex,
   264  					},
   265  				},
   266  			},
   267  			&structs.TxnResult{
   268  				KV: &structs.DirEntry{
   269  					Key:   "test",
   270  					Flags: 42,
   271  					Value: []byte("test"),
   272  					RaftIndex: structs.RaftIndex{
   273  						CreateIndex: d.CreateIndex,
   274  						ModifyIndex: d.ModifyIndex,
   275  					},
   276  				},
   277  			},
   278  			&structs.TxnResult{
   279  				Node: n,
   280  			},
   281  			&structs.TxnResult{
   282  				Node: n,
   283  			},
   284  			&structs.TxnResult{
   285  				Service: s,
   286  			},
   287  			&structs.TxnResult{
   288  				Service: s,
   289  			},
   290  			&structs.TxnResult{
   291  				Check: c,
   292  			},
   293  			&structs.TxnResult{
   294  				Check: c,
   295  			},
   296  		},
   297  	}
   298  	verify.Values(t, "", out, expected)
   299  }
   300  
   301  func TestTxn_Apply_ACLDeny(t *testing.T) {
   302  	t.Parallel()
   303  
   304  	require := require.New(t)
   305  
   306  	dir1, s1 := testServerWithConfig(t, func(c *Config) {
   307  		c.ACLDatacenter = "dc1"
   308  		c.ACLsEnabled = true
   309  		c.ACLMasterToken = "root"
   310  		c.ACLDefaultPolicy = "deny"
   311  	})
   312  	defer os.RemoveAll(dir1)
   313  	defer s1.Shutdown()
   314  
   315  	testrpc.WaitForLeader(t, s1.RPC, "dc1")
   316  
   317  	// Set up some state to read back.
   318  	state := s1.fsm.State()
   319  	d := &structs.DirEntry{
   320  		Key:   "nope",
   321  		Value: []byte("hello"),
   322  	}
   323  	require.NoError(state.KVSSet(1, d))
   324  
   325  	node := &structs.Node{
   326  		ID:   types.NodeID(testNodeID),
   327  		Node: "nope",
   328  	}
   329  	require.NoError(state.EnsureNode(2, node))
   330  
   331  	svc := structs.NodeService{ID: "nope", Service: "nope", Address: "127.0.0.1"}
   332  	require.NoError(state.EnsureService(3, "nope", &svc))
   333  
   334  	check := structs.HealthCheck{Node: "nope", CheckID: types.CheckID("nope")}
   335  	state.EnsureCheck(4, &check)
   336  
   337  	// Create the ACL.
   338  	var id string
   339  	{
   340  		arg := structs.ACLRequest{
   341  			Datacenter: "dc1",
   342  			Op:         structs.ACLSet,
   343  			ACL: structs.ACL{
   344  				Name:  "User token",
   345  				Type:  structs.ACLTokenTypeClient,
   346  				Rules: testTxnRules,
   347  			},
   348  			WriteRequest: structs.WriteRequest{Token: "root"},
   349  		}
   350  		if err := s1.RPC("ACL.Apply", &arg, &id); err != nil {
   351  			t.Fatalf("err: %v", err)
   352  		}
   353  	}
   354  
   355  	// Set up a transaction where every operation should get blocked due to
   356  	// ACLs.
   357  	arg := structs.TxnRequest{
   358  		Datacenter: "dc1",
   359  		Ops: structs.TxnOps{
   360  			&structs.TxnOp{
   361  				KV: &structs.TxnKVOp{
   362  					Verb: api.KVSet,
   363  					DirEnt: structs.DirEntry{
   364  						Key: "nope",
   365  					},
   366  				},
   367  			},
   368  			&structs.TxnOp{
   369  				KV: &structs.TxnKVOp{
   370  					Verb: api.KVDelete,
   371  					DirEnt: structs.DirEntry{
   372  						Key: "nope",
   373  					},
   374  				},
   375  			},
   376  			&structs.TxnOp{
   377  				KV: &structs.TxnKVOp{
   378  					Verb: api.KVDeleteCAS,
   379  					DirEnt: structs.DirEntry{
   380  						Key: "nope",
   381  					},
   382  				},
   383  			},
   384  			&structs.TxnOp{
   385  				KV: &structs.TxnKVOp{
   386  					Verb: api.KVDeleteTree,
   387  					DirEnt: structs.DirEntry{
   388  						Key: "nope",
   389  					},
   390  				},
   391  			},
   392  			&structs.TxnOp{
   393  				KV: &structs.TxnKVOp{
   394  					Verb: api.KVCAS,
   395  					DirEnt: structs.DirEntry{
   396  						Key: "nope",
   397  					},
   398  				},
   399  			},
   400  			&structs.TxnOp{
   401  				KV: &structs.TxnKVOp{
   402  					Verb: api.KVLock,
   403  					DirEnt: structs.DirEntry{
   404  						Key: "nope",
   405  					},
   406  				},
   407  			},
   408  			&structs.TxnOp{
   409  				KV: &structs.TxnKVOp{
   410  					Verb: api.KVUnlock,
   411  					DirEnt: structs.DirEntry{
   412  						Key: "nope",
   413  					},
   414  				},
   415  			},
   416  			&structs.TxnOp{
   417  				KV: &structs.TxnKVOp{
   418  					Verb: api.KVGet,
   419  					DirEnt: structs.DirEntry{
   420  						Key: "nope",
   421  					},
   422  				},
   423  			},
   424  			&structs.TxnOp{
   425  				KV: &structs.TxnKVOp{
   426  					Verb: api.KVGetTree,
   427  					DirEnt: structs.DirEntry{
   428  						Key: "nope",
   429  					},
   430  				},
   431  			},
   432  			&structs.TxnOp{
   433  				KV: &structs.TxnKVOp{
   434  					Verb: api.KVCheckSession,
   435  					DirEnt: structs.DirEntry{
   436  						Key: "nope",
   437  					},
   438  				},
   439  			},
   440  			&structs.TxnOp{
   441  				KV: &structs.TxnKVOp{
   442  					Verb: api.KVCheckIndex,
   443  					DirEnt: structs.DirEntry{
   444  						Key: "nope",
   445  					},
   446  				},
   447  			},
   448  			&structs.TxnOp{
   449  				KV: &structs.TxnKVOp{
   450  					Verb: api.KVCheckNotExists,
   451  					DirEnt: structs.DirEntry{
   452  						Key: "nope",
   453  					},
   454  				},
   455  			},
   456  			&structs.TxnOp{
   457  				Node: &structs.TxnNodeOp{
   458  					Verb: api.NodeGet,
   459  					Node: structs.Node{ID: node.ID, Node: node.Node},
   460  				},
   461  			},
   462  			&structs.TxnOp{
   463  				Node: &structs.TxnNodeOp{
   464  					Verb: api.NodeSet,
   465  					Node: structs.Node{ID: node.ID, Node: node.Node},
   466  				},
   467  			},
   468  			&structs.TxnOp{
   469  				Node: &structs.TxnNodeOp{
   470  					Verb: api.NodeCAS,
   471  					Node: structs.Node{ID: node.ID, Node: node.Node},
   472  				},
   473  			},
   474  			&structs.TxnOp{
   475  				Node: &structs.TxnNodeOp{
   476  					Verb: api.NodeDelete,
   477  					Node: structs.Node{ID: node.ID, Node: node.Node},
   478  				},
   479  			},
   480  			&structs.TxnOp{
   481  				Node: &structs.TxnNodeOp{
   482  					Verb: api.NodeDeleteCAS,
   483  					Node: structs.Node{ID: node.ID, Node: node.Node},
   484  				},
   485  			},
   486  			&structs.TxnOp{
   487  				Service: &structs.TxnServiceOp{
   488  					Verb:    api.ServiceGet,
   489  					Node:    "foo-node",
   490  					Service: svc,
   491  				},
   492  			},
   493  			&structs.TxnOp{
   494  				Service: &structs.TxnServiceOp{
   495  					Verb:    api.ServiceSet,
   496  					Node:    "foo-node",
   497  					Service: svc,
   498  				},
   499  			},
   500  			&structs.TxnOp{
   501  				Service: &structs.TxnServiceOp{
   502  					Verb:    api.ServiceCAS,
   503  					Node:    "foo-node",
   504  					Service: svc,
   505  				},
   506  			},
   507  			&structs.TxnOp{
   508  				Service: &structs.TxnServiceOp{
   509  					Verb:    api.ServiceDelete,
   510  					Node:    "foo-node",
   511  					Service: svc,
   512  				},
   513  			},
   514  			&structs.TxnOp{
   515  				Service: &structs.TxnServiceOp{
   516  					Verb:    api.ServiceDeleteCAS,
   517  					Node:    "foo-node",
   518  					Service: svc,
   519  				},
   520  			},
   521  			&structs.TxnOp{
   522  				Check: &structs.TxnCheckOp{
   523  					Verb:  api.CheckGet,
   524  					Check: check,
   525  				},
   526  			},
   527  			&structs.TxnOp{
   528  				Check: &structs.TxnCheckOp{
   529  					Verb:  api.CheckSet,
   530  					Check: check,
   531  				},
   532  			},
   533  			&structs.TxnOp{
   534  				Check: &structs.TxnCheckOp{
   535  					Verb:  api.CheckCAS,
   536  					Check: check,
   537  				},
   538  			},
   539  			&structs.TxnOp{
   540  				Check: &structs.TxnCheckOp{
   541  					Verb:  api.CheckDelete,
   542  					Check: check,
   543  				},
   544  			},
   545  			&structs.TxnOp{
   546  				Check: &structs.TxnCheckOp{
   547  					Verb:  api.CheckDeleteCAS,
   548  					Check: check,
   549  				},
   550  			},
   551  		},
   552  		WriteRequest: structs.WriteRequest{
   553  			Token: id,
   554  		},
   555  	}
   556  	var out structs.TxnResponse
   557  	if err := s1.RPC("Txn.Apply", &arg, &out); err != nil {
   558  		t.Fatalf("err: %v", err)
   559  	}
   560  
   561  	// Verify the transaction's return value.
   562  	var expected structs.TxnResponse
   563  	for i, op := range arg.Ops {
   564  		switch {
   565  		case op.KV != nil:
   566  			switch op.KV.Verb {
   567  			case api.KVGet, api.KVGetTree:
   568  				// These get filtered but won't result in an error.
   569  
   570  			default:
   571  				expected.Errors = append(expected.Errors, &structs.TxnError{
   572  					OpIndex: i,
   573  					What:    acl.ErrPermissionDenied.Error(),
   574  				})
   575  			}
   576  		case op.Node != nil:
   577  			switch op.Node.Verb {
   578  			case api.NodeGet:
   579  				// These get filtered but won't result in an error.
   580  
   581  			default:
   582  				expected.Errors = append(expected.Errors, &structs.TxnError{
   583  					OpIndex: i,
   584  					What:    acl.ErrPermissionDenied.Error(),
   585  				})
   586  			}
   587  		case op.Service != nil:
   588  			switch op.Service.Verb {
   589  			case api.ServiceGet:
   590  				// These get filtered but won't result in an error.
   591  
   592  			default:
   593  				expected.Errors = append(expected.Errors, &structs.TxnError{
   594  					OpIndex: i,
   595  					What:    acl.ErrPermissionDenied.Error(),
   596  				})
   597  			}
   598  		case op.Check != nil:
   599  			switch op.Check.Verb {
   600  			case api.CheckGet:
   601  				// These get filtered but won't result in an error.
   602  
   603  			default:
   604  				expected.Errors = append(expected.Errors, &structs.TxnError{
   605  					OpIndex: i,
   606  					What:    acl.ErrPermissionDenied.Error(),
   607  				})
   608  			}
   609  		}
   610  	}
   611  
   612  	verify.Values(t, "", out, expected)
   613  }
   614  
   615  func TestTxn_Apply_LockDelay(t *testing.T) {
   616  	t.Parallel()
   617  	dir1, s1 := testServer(t)
   618  	defer os.RemoveAll(dir1)
   619  	defer s1.Shutdown()
   620  	codec := rpcClient(t, s1)
   621  	defer codec.Close()
   622  
   623  	testrpc.WaitForLeader(t, s1.RPC, "dc1")
   624  
   625  	// Create and invalidate a session with a lock.
   626  	state := s1.fsm.State()
   627  	if err := state.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil {
   628  		t.Fatalf("err: %v", err)
   629  	}
   630  	session := &structs.Session{
   631  		ID:        generateUUID(),
   632  		Node:      "foo",
   633  		LockDelay: 50 * time.Millisecond,
   634  	}
   635  	if err := state.SessionCreate(2, session); err != nil {
   636  		t.Fatalf("err: %v", err)
   637  	}
   638  	id := session.ID
   639  	d := &structs.DirEntry{
   640  		Key:     "test",
   641  		Session: id,
   642  	}
   643  	if ok, err := state.KVSLock(3, d); err != nil || !ok {
   644  		t.Fatalf("err: %v", err)
   645  	}
   646  	if err := state.SessionDestroy(4, id); err != nil {
   647  		t.Fatalf("err: %v", err)
   648  	}
   649  
   650  	// Make a new session that is valid.
   651  	if err := state.SessionCreate(5, session); err != nil {
   652  		t.Fatalf("err: %v", err)
   653  	}
   654  	validID := session.ID
   655  
   656  	// Make a lock request via an atomic transaction.
   657  	arg := structs.TxnRequest{
   658  		Datacenter: "dc1",
   659  		Ops: structs.TxnOps{
   660  			&structs.TxnOp{
   661  				KV: &structs.TxnKVOp{
   662  					Verb: api.KVLock,
   663  					DirEnt: structs.DirEntry{
   664  						Key:     "test",
   665  						Session: validID,
   666  					},
   667  				},
   668  			},
   669  		},
   670  	}
   671  	{
   672  		var out structs.TxnResponse
   673  		if err := msgpackrpc.CallWithCodec(codec, "Txn.Apply", &arg, &out); err != nil {
   674  			t.Fatalf("err: %v", err)
   675  		}
   676  		if len(out.Results) != 0 ||
   677  			len(out.Errors) != 1 ||
   678  			out.Errors[0].OpIndex != 0 ||
   679  			!strings.Contains(out.Errors[0].What, "due to lock delay") {
   680  			t.Fatalf("bad: %v", out)
   681  		}
   682  	}
   683  
   684  	// Wait for lock-delay.
   685  	time.Sleep(50 * time.Millisecond)
   686  
   687  	// Should acquire.
   688  	{
   689  		var out structs.TxnResponse
   690  		if err := msgpackrpc.CallWithCodec(codec, "Txn.Apply", &arg, &out); err != nil {
   691  			t.Fatalf("err: %v", err)
   692  		}
   693  		if len(out.Results) != 1 ||
   694  			len(out.Errors) != 0 ||
   695  			out.Results[0].KV.LockIndex != 2 {
   696  			t.Fatalf("bad: %v", out)
   697  		}
   698  	}
   699  }
   700  
   701  func TestTxn_Read(t *testing.T) {
   702  	t.Parallel()
   703  
   704  	require := require.New(t)
   705  
   706  	dir1, s1 := testServer(t)
   707  	defer os.RemoveAll(dir1)
   708  	defer s1.Shutdown()
   709  	codec := rpcClient(t, s1)
   710  	defer codec.Close()
   711  
   712  	testrpc.WaitForLeader(t, s1.RPC, "dc1")
   713  
   714  	// Put in a key to read back.
   715  	state := s1.fsm.State()
   716  	d := &structs.DirEntry{
   717  		Key:   "test",
   718  		Value: []byte("hello"),
   719  	}
   720  	if err := state.KVSSet(1, d); err != nil {
   721  		t.Fatalf("err: %v", err)
   722  	}
   723  
   724  	// Put in a node/check/service to read back.
   725  	node := &structs.Node{
   726  		ID:   types.NodeID(testNodeID),
   727  		Node: "foo",
   728  	}
   729  	require.NoError(state.EnsureNode(2, node))
   730  
   731  	svc := structs.NodeService{ID: "svc-foo", Service: "svc-foo", Address: "127.0.0.1"}
   732  	require.NoError(state.EnsureService(3, "foo", &svc))
   733  
   734  	check := structs.HealthCheck{Node: "foo", CheckID: types.CheckID("check-foo")}
   735  	state.EnsureCheck(4, &check)
   736  
   737  	// Do a super basic request. The state store test covers the details so
   738  	// we just need to be sure that the transaction is sent correctly and
   739  	// the results are converted appropriately.
   740  	arg := structs.TxnReadRequest{
   741  		Datacenter: "dc1",
   742  		Ops: structs.TxnOps{
   743  			&structs.TxnOp{
   744  				KV: &structs.TxnKVOp{
   745  					Verb: api.KVGet,
   746  					DirEnt: structs.DirEntry{
   747  						Key: "test",
   748  					},
   749  				},
   750  			},
   751  			&structs.TxnOp{
   752  				Node: &structs.TxnNodeOp{
   753  					Verb: api.NodeGet,
   754  					Node: structs.Node{ID: node.ID, Node: node.Node},
   755  				},
   756  			},
   757  			&structs.TxnOp{
   758  				Service: &structs.TxnServiceOp{
   759  					Verb:    api.ServiceGet,
   760  					Node:    "foo",
   761  					Service: svc,
   762  				},
   763  			},
   764  			&structs.TxnOp{
   765  				Check: &structs.TxnCheckOp{
   766  					Verb:  api.CheckGet,
   767  					Check: check,
   768  				},
   769  			},
   770  		},
   771  	}
   772  	var out structs.TxnReadResponse
   773  	if err := msgpackrpc.CallWithCodec(codec, "Txn.Read", &arg, &out); err != nil {
   774  		t.Fatalf("err: %v", err)
   775  	}
   776  
   777  	// Verify the transaction's return value.
   778  	svc.Weights = &structs.Weights{Passing: 1, Warning: 1}
   779  	svc.RaftIndex = structs.RaftIndex{CreateIndex: 3, ModifyIndex: 3}
   780  	expected := structs.TxnReadResponse{
   781  		TxnResponse: structs.TxnResponse{
   782  			Results: structs.TxnResults{
   783  				&structs.TxnResult{
   784  					KV: &structs.DirEntry{
   785  						Key:   "test",
   786  						Value: []byte("hello"),
   787  						RaftIndex: structs.RaftIndex{
   788  							CreateIndex: 1,
   789  							ModifyIndex: 1,
   790  						},
   791  					},
   792  				},
   793  				&structs.TxnResult{
   794  					Node: node,
   795  				},
   796  				&structs.TxnResult{
   797  					Service: &svc,
   798  				},
   799  				&structs.TxnResult{
   800  					Check: &check,
   801  				},
   802  			},
   803  		},
   804  		QueryMeta: structs.QueryMeta{
   805  			KnownLeader: true,
   806  		},
   807  	}
   808  	verify.Values(t, "", out, expected)
   809  }
   810  
   811  func TestTxn_Read_ACLDeny(t *testing.T) {
   812  	t.Parallel()
   813  
   814  	require := require.New(t)
   815  
   816  	dir1, s1 := testServerWithConfig(t, func(c *Config) {
   817  		c.ACLDatacenter = "dc1"
   818  		c.ACLsEnabled = true
   819  		c.ACLMasterToken = "root"
   820  		c.ACLDefaultPolicy = "deny"
   821  	})
   822  	defer os.RemoveAll(dir1)
   823  	defer s1.Shutdown()
   824  	codec := rpcClient(t, s1)
   825  	defer codec.Close()
   826  
   827  	testrpc.WaitForLeader(t, s1.RPC, "dc1")
   828  
   829  	// Put in a key to read back.
   830  	state := s1.fsm.State()
   831  	d := &structs.DirEntry{
   832  		Key:   "nope",
   833  		Value: []byte("hello"),
   834  	}
   835  	if err := state.KVSSet(1, d); err != nil {
   836  		t.Fatalf("err: %v", err)
   837  	}
   838  
   839  	// Put in a node/check/service to read back.
   840  	node := &structs.Node{
   841  		ID:   types.NodeID(testNodeID),
   842  		Node: "nope",
   843  	}
   844  	require.NoError(state.EnsureNode(2, node))
   845  
   846  	svc := structs.NodeService{ID: "nope", Service: "nope", Address: "127.0.0.1"}
   847  	require.NoError(state.EnsureService(3, "nope", &svc))
   848  
   849  	check := structs.HealthCheck{Node: "nope", CheckID: types.CheckID("nope")}
   850  	state.EnsureCheck(4, &check)
   851  
   852  	// Create the ACL.
   853  	var id string
   854  	{
   855  		arg := structs.ACLRequest{
   856  			Datacenter: "dc1",
   857  			Op:         structs.ACLSet,
   858  			ACL: structs.ACL{
   859  				Name:  "User token",
   860  				Type:  structs.ACLTokenTypeClient,
   861  				Rules: testTxnRules,
   862  			},
   863  			WriteRequest: structs.WriteRequest{Token: "root"},
   864  		}
   865  		if err := msgpackrpc.CallWithCodec(codec, "ACL.Apply", &arg, &id); err != nil {
   866  			t.Fatalf("err: %v", err)
   867  		}
   868  	}
   869  
   870  	// Set up a transaction where every operation should get blocked due to
   871  	// ACLs.
   872  	arg := structs.TxnReadRequest{
   873  		Datacenter: "dc1",
   874  		Ops: structs.TxnOps{
   875  			&structs.TxnOp{
   876  				KV: &structs.TxnKVOp{
   877  					Verb: api.KVGet,
   878  					DirEnt: structs.DirEntry{
   879  						Key: "nope",
   880  					},
   881  				},
   882  			},
   883  			&structs.TxnOp{
   884  				KV: &structs.TxnKVOp{
   885  					Verb: api.KVGetTree,
   886  					DirEnt: structs.DirEntry{
   887  						Key: "nope",
   888  					},
   889  				},
   890  			},
   891  			&structs.TxnOp{
   892  				KV: &structs.TxnKVOp{
   893  					Verb: api.KVCheckSession,
   894  					DirEnt: structs.DirEntry{
   895  						Key: "nope",
   896  					},
   897  				},
   898  			},
   899  			&structs.TxnOp{
   900  				KV: &structs.TxnKVOp{
   901  					Verb: api.KVCheckIndex,
   902  					DirEnt: structs.DirEntry{
   903  						Key: "nope",
   904  					},
   905  				},
   906  			},
   907  			&structs.TxnOp{
   908  				Node: &structs.TxnNodeOp{
   909  					Verb: api.NodeGet,
   910  					Node: structs.Node{ID: node.ID, Node: node.Node},
   911  				},
   912  			},
   913  			&structs.TxnOp{
   914  				Service: &structs.TxnServiceOp{
   915  					Verb:    api.ServiceGet,
   916  					Node:    "foo",
   917  					Service: svc,
   918  				},
   919  			},
   920  			&structs.TxnOp{
   921  				Check: &structs.TxnCheckOp{
   922  					Verb:  api.CheckGet,
   923  					Check: check,
   924  				},
   925  			},
   926  		},
   927  		QueryOptions: structs.QueryOptions{
   928  			Token: id,
   929  		},
   930  	}
   931  	var out structs.TxnReadResponse
   932  	if err := msgpackrpc.CallWithCodec(codec, "Txn.Read", &arg, &out); err != nil {
   933  		t.Fatalf("err: %v", err)
   934  	}
   935  
   936  	// Verify the transaction's return value.
   937  	expected := structs.TxnReadResponse{
   938  		QueryMeta: structs.QueryMeta{
   939  			KnownLeader: true,
   940  		},
   941  	}
   942  	for i, op := range arg.Ops {
   943  		switch {
   944  		case op.KV != nil:
   945  			switch op.KV.Verb {
   946  			case api.KVGet, api.KVGetTree:
   947  				// These get filtered but won't result in an error.
   948  
   949  			default:
   950  				expected.Errors = append(expected.Errors, &structs.TxnError{
   951  					OpIndex: i,
   952  					What:    acl.ErrPermissionDenied.Error(),
   953  				})
   954  			}
   955  		case op.Node != nil:
   956  			switch op.Node.Verb {
   957  			case api.NodeGet:
   958  				// These get filtered but won't result in an error.
   959  
   960  			default:
   961  				expected.Errors = append(expected.Errors, &structs.TxnError{
   962  					OpIndex: i,
   963  					What:    acl.ErrPermissionDenied.Error(),
   964  				})
   965  			}
   966  		case op.Service != nil:
   967  			switch op.Service.Verb {
   968  			case api.ServiceGet:
   969  				// These get filtered but won't result in an error.
   970  
   971  			default:
   972  				expected.Errors = append(expected.Errors, &structs.TxnError{
   973  					OpIndex: i,
   974  					What:    acl.ErrPermissionDenied.Error(),
   975  				})
   976  			}
   977  		case op.Check != nil:
   978  			switch op.Check.Verb {
   979  			case api.CheckGet:
   980  				// These get filtered but won't result in an error.
   981  
   982  			default:
   983  				expected.Errors = append(expected.Errors, &structs.TxnError{
   984  					OpIndex: i,
   985  					What:    acl.ErrPermissionDenied.Error(),
   986  				})
   987  			}
   988  		}
   989  	}
   990  	if !reflect.DeepEqual(out, expected) {
   991  		t.Fatalf("bad %v", out)
   992  	}
   993  }