agent/consul: support updating intentions

This commit is contained in:
Mitchell Hashimoto 2018-02-28 21:11:35 -08:00
parent 0d96cdc0a5
commit 771b1737e3
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 103 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package consul
import ( import (
"errors" "errors"
"fmt"
"time" "time"
"github.com/armon/go-metrics" "github.com/armon/go-metrics"
@ -58,6 +59,18 @@ func (s *Intention) Apply(
} }
*reply = args.Intention.ID *reply = args.Intention.ID
// If this is not a create, then we have to verify the ID.
if args.Op != structs.IntentionOpCreate {
state := s.srv.fsm.State()
_, ixn, err := state.IntentionGet(nil, args.Intention.ID)
if err != nil {
return fmt.Errorf("Intention lookup failed: %v", err)
}
if ixn == nil {
return fmt.Errorf("Cannot modify non-existent intention: '%s'", args.Intention.ID)
}
}
// Commit // Commit
resp, err := s.srv.raftApply(structs.IntentionRequestType, args) resp, err := s.srv.raftApply(structs.IntentionRequestType, args)
if err != nil { if err != nil {

View File

@ -3,6 +3,7 @@ package consul
import ( import (
"os" "os"
"reflect" "reflect"
"strings"
"testing" "testing"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
@ -10,6 +11,7 @@ import (
"github.com/hashicorp/net-rpc-msgpackrpc" "github.com/hashicorp/net-rpc-msgpackrpc"
) )
// Test basic creation
func TestIntentionApply_new(t *testing.T) { func TestIntentionApply_new(t *testing.T) {
t.Parallel() t.Parallel()
dir1, s1 := testServer(t) dir1, s1 := testServer(t)
@ -63,6 +65,94 @@ func TestIntentionApply_new(t *testing.T) {
} }
} }
// Test basic updating
func TestIntentionApply_updateGood(t *testing.T) {
t.Parallel()
dir1, s1 := testServer(t)
defer os.RemoveAll(dir1)
defer s1.Shutdown()
codec := rpcClient(t, s1)
defer codec.Close()
testrpc.WaitForLeader(t, s1.RPC, "dc1")
// Setup a basic record to create
ixn := structs.IntentionRequest{
Datacenter: "dc1",
Op: structs.IntentionOpCreate,
Intention: &structs.Intention{
SourceName: "test",
},
}
var reply string
// Create
if err := msgpackrpc.CallWithCodec(codec, "Intention.Apply", &ixn, &reply); err != nil {
t.Fatalf("err: %v", err)
}
if reply == "" {
t.Fatal("reply should be non-empty")
}
// Update
ixn.Op = structs.IntentionOpUpdate
ixn.Intention.ID = reply
ixn.Intention.SourceName = "bar"
if err := msgpackrpc.CallWithCodec(codec, "Intention.Apply", &ixn, &reply); err != nil {
t.Fatalf("err: %v", err)
}
// Read
ixn.Intention.ID = reply
{
req := &structs.IntentionQueryRequest{
Datacenter: "dc1",
IntentionID: ixn.Intention.ID,
}
var resp structs.IndexedIntentions
if err := msgpackrpc.CallWithCodec(codec, "Intention.Get", req, &resp); err != nil {
t.Fatalf("err: %v", err)
}
if len(resp.Intentions) != 1 {
t.Fatalf("bad: %v", resp)
}
actual := resp.Intentions[0]
actual.CreateIndex, actual.ModifyIndex = 0, 0
if !reflect.DeepEqual(actual, ixn.Intention) {
t.Fatalf("bad: %v", actual)
}
}
}
// Shouldn't be able to update a non-existent intention
func TestIntentionApply_updateNonExist(t *testing.T) {
t.Parallel()
dir1, s1 := testServer(t)
defer os.RemoveAll(dir1)
defer s1.Shutdown()
codec := rpcClient(t, s1)
defer codec.Close()
testrpc.WaitForLeader(t, s1.RPC, "dc1")
// Setup a basic record to create
ixn := structs.IntentionRequest{
Datacenter: "dc1",
Op: structs.IntentionOpUpdate,
Intention: &structs.Intention{
ID: generateUUID(),
SourceName: "test",
},
}
var reply string
// Create
err := msgpackrpc.CallWithCodec(codec, "Intention.Apply", &ixn, &reply)
if err == nil || !strings.Contains(err.Error(), "Cannot modify non-existent intention") {
t.Fatalf("bad: %v", err)
}
}
func TestIntentionList(t *testing.T) { func TestIntentionList(t *testing.T) {
t.Parallel() t.Parallel()
dir1, s1 := testServer(t) dir1, s1 := testServer(t)