package serf import ( "bytes" "encoding/base64" "net" "testing" "github.com/hashicorp/memberlist" "basic.com/valib/serf.git/testutil" ) func testKeyring() (*memberlist.Keyring, error) { keys := []string{ "ZWTL+bgjHyQPhJRKcFe3ccirc2SFHmc/Nw67l8NQfdk=", "WbL6oaTPom+7RG7Q/INbJWKy09OLar/Hf2SuOAdoQE4=", "HvY8ubRZMgafUOWvrOadwOckVa1wN3QWAo46FVKbVN8=", } keysDecoded := make([][]byte, len(keys)) for i, key := range keys { decoded, err := base64.StdEncoding.DecodeString(key) if err != nil { return nil, err } keysDecoded[i] = decoded } return memberlist.NewKeyring(keysDecoded, keysDecoded[0]) } func testKeyringSerf(t *testing.T, ip net.IP) (*Serf, error) { config := testConfig(t, ip) keyring, err := testKeyring() if err != nil { return nil, err } config.MemberlistConfig.Keyring = keyring s, err := Create(config) if err != nil { return nil, err } return s, nil } func keyExistsInRing(kr *memberlist.Keyring, key []byte) bool { for _, installedKey := range kr.GetKeys() { if bytes.Equal(key, installedKey) { return true } } return false } func TestSerf_InstallKey(t *testing.T) { ip1, returnFn1 := testutil.TakeIP() defer returnFn1() ip2, returnFn2 := testutil.TakeIP() defer returnFn2() s1, err := testKeyringSerf(t, ip1) if err != nil { t.Fatalf("err: %v", err) } defer s1.Shutdown() s2, err := testKeyringSerf(t, ip2) if err != nil { t.Fatalf("err: %v", err) } defer s2.Shutdown() primaryKey := s1.config.MemberlistConfig.Keyring.GetPrimaryKey() waitUntilNumNodes(t, 1, s1, s2) // Join s1 and s2 _, err = s1.Join([]string{s2.config.NodeName + "/" + s2.config.MemberlistConfig.BindAddr}, false) if err != nil { t.Fatalf("err: %v", err) } waitUntilNumNodes(t, 2, s1, s2) // Begin tests newKey := "HvY8ubRZMgafUOWvrOadwOckVa1wN3QWAo46FVKbVN8=" newKeyBytes, err := base64.StdEncoding.DecodeString(newKey) if err != nil { t.Fatalf("err: %v", err) } manager := s1.KeyManager() // Install a new key onto the existing ring. This is a blocking call, so no // need for a yield. _, err = manager.InstallKey(newKey) if err != nil { t.Fatalf("err: %v", err) } // Key installation did not affect the current primary key if !bytes.Equal(primaryKey, s1.config.MemberlistConfig.Keyring.GetPrimaryKey()) { t.Fatal("Unexpected primary key change on s1") } if !bytes.Equal(primaryKey, s2.config.MemberlistConfig.Keyring.GetPrimaryKey()) { t.Fatal("Unexpected primary key change on s2") } // New key was successfully broadcasted and installed on all members if !keyExistsInRing(s1.config.MemberlistConfig.Keyring, newKeyBytes) { t.Fatal("Newly-installed key not found in keyring on s1") } if !keyExistsInRing(s2.config.MemberlistConfig.Keyring, newKeyBytes) { t.Fatal("Newly-installed key not found in keyring on s2") } } func TestSerf_UseKey(t *testing.T) { ip1, returnFn1 := testutil.TakeIP() defer returnFn1() ip2, returnFn2 := testutil.TakeIP() defer returnFn2() s1, err := testKeyringSerf(t, ip1) if err != nil { t.Fatalf("err: %v", err) } defer s1.Shutdown() s2, err := testKeyringSerf(t, ip2) if err != nil { t.Fatalf("err: %v", err) } defer s2.Shutdown() waitUntilNumNodes(t, 1, s1, s2) // Join s1 and s2 _, err = s1.Join([]string{s2.config.NodeName + "/" + s2.config.MemberlistConfig.BindAddr}, false) if err != nil { t.Fatalf("err: %v", err) } waitUntilNumNodes(t, 2, s1, s2) // Begin tests useKey := "HvY8ubRZMgafUOWvrOadwOckVa1wN3QWAo46FVKbVN8=" useKeyBytes, err := base64.StdEncoding.DecodeString(useKey) if err != nil { t.Fatalf("err: %v", err) } manager := s1.KeyManager() // Change the primary encryption key _, err = manager.UseKey(useKey) if err != nil { t.Fatalf("err: %v", err) } // First make sure that the primary key is what we expect it to be if !bytes.Equal(useKeyBytes, s1.config.MemberlistConfig.Keyring.GetPrimaryKey()) { t.Fatal("Unexpected primary key on s1") } if !bytes.Equal(useKeyBytes, s2.config.MemberlistConfig.Keyring.GetPrimaryKey()) { t.Fatal("Unexpected primary key on s2") } // Make sure an error is thrown if the key doesn't exist _, err = manager.UseKey("T9jncgl9mbLus+baTTa7q7nPSUrXwbDi2dhbtqir37s=") if err == nil { t.Fatalf("Expected error changing to non-existent primary key") } } func TestSerf_RemoveKey(t *testing.T) { ip1, returnFn1 := testutil.TakeIP() defer returnFn1() ip2, returnFn2 := testutil.TakeIP() defer returnFn2() s1, err := testKeyringSerf(t, ip1) if err != nil { t.Fatalf("err: %v", err) } defer s1.Shutdown() s2, err := testKeyringSerf(t, ip2) if err != nil { t.Fatalf("err: %v", err) } defer s2.Shutdown() waitUntilNumNodes(t, 1, s1, s2) // Join s1 and s2 _, err = s1.Join([]string{s2.config.NodeName + "/" + s2.config.MemberlistConfig.BindAddr}, false) if err != nil { t.Fatalf("err: %v", err) } waitUntilNumNodes(t, 2, s1, s2) // Begin tests removeKey := "T9jncgl9mbLus+baTTa7q7nPSUrXwbDi2dhbtqir37s=" removeKeyBytes, err := base64.StdEncoding.DecodeString(removeKey) if err != nil { t.Fatalf("err: %v", err) } manager := s1.KeyManager() // Remove a key from the ring _, err = manager.RemoveKey(removeKey) if err != nil { t.Fatalf("err: %v", err) } // Key was successfully removed from all members if keyExistsInRing(s1.config.MemberlistConfig.Keyring, removeKeyBytes) { t.Fatal("Key not removed from keyring on s1") } if keyExistsInRing(s2.config.MemberlistConfig.Keyring, removeKeyBytes) { t.Fatal("Key not removed from keyring on s2") } } func TestSerf_ListKeys(t *testing.T) { ip1, returnFn1 := testutil.TakeIP() defer returnFn1() ip2, returnFn2 := testutil.TakeIP() defer returnFn2() s1, err := testKeyringSerf(t, ip1) if err != nil { t.Fatalf("err: %v", err) } defer s1.Shutdown() s2, err := testKeyringSerf(t, ip2) if err != nil { t.Fatalf("err: %v", err) } defer s2.Shutdown() manager := s1.KeyManager() initialKeyringLen := len(s1.config.MemberlistConfig.Keyring.GetKeys()) // Extra key on s2 to make sure we see it in the list extraKey := "5K9OtfP7efFrNKe5WCQvXvnaXJ5cWP0SvXiwe0kkjM4=" extraKeyBytes, err := base64.StdEncoding.DecodeString(extraKey) if err != nil { t.Fatalf("err: %v", err) } s2.config.MemberlistConfig.Keyring.AddKey(extraKeyBytes) waitUntilNumNodes(t, 1, s1, s2) // Join s1 and s2 _, err = s1.Join([]string{s2.config.NodeName + "/" + s2.config.MemberlistConfig.BindAddr}, false) if err != nil { t.Fatalf("err: %v", err) } waitUntilNumNodes(t, 2, s1, s2) resp, err := manager.ListKeys() if err != nil { t.Fatalf("err: %v", err) } // Found all keys in the list expected := initialKeyringLen + 1 if expected != len(resp.Keys) { t.Fatalf("Expected %d keys in result, found %d", expected, len(resp.Keys)) } found := false for key, _ := range resp.Keys { if key == extraKey { found = true } } if !found { t.Fatalf("Did not find expected key in list: %s", extraKey) } // Number of members with extra key installed should be 1 for key, num := range resp.Keys { if key == extraKey && num != 1 { t.Fatalf("Expected 1 nodes with key %s but have %d", extraKey, num) } } }