// SessionCreate is used to create a new session. The // ID will be populated on a successful return func (s *StateStore) SessionCreate(index uint64, session *structs.Session) error { // Assign the create index session.CreateIndex = index // Start the transaction tx, err := s.tables.StartTxn(false) if err != nil { panic(fmt.Errorf("Failed to start txn: %v", err)) } defer tx.Abort() // Verify that the node exists res, err := s.nodeTable.GetTxn(tx, "id", session.Node) if err != nil { return err } if len(res) == 0 { return fmt.Errorf("Missing node registration") } // Verify that the checks exist and are not critical for _, checkId := range session.Checks { res, err := s.checkTable.GetTxn(tx, "id", session.Node, checkId) if err != nil { return err } if len(res) == 0 { return fmt.Errorf("Missing check '%s' registration", checkId) } chk := res[0].(*structs.HealthCheck) if chk.Status == structs.HealthCritical { return fmt.Errorf("Check '%s' is in %s state", checkId, chk.Status) } } // Generate a new session ID, verify uniqueness session.ID = generateUUID() for { res, err = s.sessionTable.GetTxn(tx, "id", session.ID) if err != nil { return err } // Quit if this ID is unique if len(res) == 0 { break } } // Insert the session if err := s.sessionTable.InsertTxn(tx, session); err != nil { return err } // Insert the check mappings sCheck := sessionCheck{Node: session.Node, Session: session.ID} for _, checkID := range session.Checks { sCheck.CheckID = checkID if err := s.sessionCheckTable.InsertTxn(tx, &sCheck); err != nil { return err } } // Trigger the update notifications if err := s.sessionTable.SetLastIndexTxn(tx, index); err != nil { return err } tx.Defer(func() { s.watch[s.sessionTable].Notify() }) return tx.Commit() }