From e30c3cdea882215a943aabb0664acdfaafe3b3a3 Mon Sep 17 00:00:00 2001 From: Ryan Uber Date: Sun, 6 Sep 2015 16:44:17 -0700 Subject: [PATCH] consul/state: basic session destroy works --- consul/state/state_store.go | 41 ++++++++++++++++++++++++++++ consul/state/state_store_test.go | 46 ++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/consul/state/state_store.go b/consul/state/state_store.go index 64bcea756..21e78e92d 100644 --- a/consul/state/state_store.go +++ b/consul/state/state_store.go @@ -1138,3 +1138,44 @@ func (s *StateStore) NodeSessions(nodeID string) (uint64, []*structs.Session, er } return lindex, result, nil } + +// SessionDestroy is used to remove an active session. This will +// implicitly invalidate the session and invoke the specified +// session destroy behavior. +func (s *StateStore) SessionDestroy(idx uint64, sessionID string) error { + tx := s.db.Txn(true) + defer tx.Abort() + + // Call the session deletion + if err := s.sessionDestroyTxn(idx, sessionID, tx); err != nil { + return err + } + + tx.Commit() + return nil +} + +// sessionDestroyTxn is the inner method, which is used to do the actual +// session deletion and handle session invalidation, watch triggers, etc. +func (s *StateStore) sessionDestroyTxn(idx uint64, sessionID string, tx *memdb.Txn) error { + // Look up the session + sess, err := tx.First("sessions", "id", sessionID) + if err != nil { + return fmt.Errorf("failed session lookup: %s", err) + } + if sess == nil { + return nil + } + + // Delete the session and write the new index + if err := tx.Delete("sessions", sess); err != nil { + return fmt.Errorf("failed deleting session: %s", err) + } + if err := tx.Insert("index", &IndexEntry{"sessions", idx}); err != nil { + return fmt.Errorf("failed updating index: %s", err) + } + + // TODO: invalidate session + + return nil +} diff --git a/consul/state/state_store_test.go b/consul/state/state_store_test.go index 8546164b7..651d7f95d 100644 --- a/consul/state/state_store_test.go +++ b/consul/state/state_store_test.go @@ -1431,3 +1431,49 @@ func TestStateStore_NodeSessions(t *testing.T) { t.Fatalf("bad: %#v", res) } } + +func TestStateStore_SessionDestroy(t *testing.T) { + s := testStateStore(t) + + // Session destroy is idempotent and returns no error + // if the session doesn't exist. + if err := s.SessionDestroy(1, "nope"); err != nil { + t.Fatalf("err: %s", err) + } + + // Ensure the index was not updated if nothing was destroyed + if idx := s.maxIndex("sessions"); idx != 0 { + t.Fatalf("bad index: %d", idx) + } + + // Register a node + testRegisterNode(t, s, 1, "node1") + + // Register a new session + sess := &structs.Session{ + ID: "session1", + Node: "node1", + } + if err := s.SessionCreate(2, sess); err != nil { + t.Fatalf("err: %s", err) + } + + // Destroy the session + if err := s.SessionDestroy(3, "session1"); err != nil { + t.Fatalf("err: %s", err) + } + + tx := s.db.Txn(false) + defer tx.Abort() + + // Make sure the session is really gone + sessions, err := tx.Get("sessions", "id") + if err != nil || sessions.Next() != nil { + t.Fatalf("session should not exist") + } + + // Check that the index was updated + if idx := s.maxIndex("sessions"); idx != 3 { + t.Fatalf("bad index: %d", idx) + } +}