@@ -19,10 +19,11 @@
19 19 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Nick string
20 20 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Type string
21 21 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Config []byte // JSON-encoded EngagementConfig
22 22 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
CreatedAt time.Time
23 23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Revoked bool
24 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ LastSeen *time.Time
24 25 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
25 26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
26 27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
// AdminRow is the flat database representation of an admin account.
27 28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
type AdminRow struct {
28 29 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
Username string
@@ -84,35 +85,47 @@
84 85 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
`CREATE TABLE IF NOT EXISTS policies (
85 86 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
id INTEGER PRIMARY KEY,
86 87 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
data TEXT NOT NULL
87 88 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
)`,
88 89 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
90 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ // Run base schema.
89 91 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
for _, stmt := range stmts {
90 92 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if _, err := s.db.Exec(stmt); err != nil {
91 93 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return fmt.Errorf("migrate: %w", err)
92 94 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
93 95 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ // Additive migrations — safe to re-run.
97 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ addColumns := []string{
98 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ `ALTER TABLE agents ADD COLUMN last_seen TEXT`,
99 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
100 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ for _, stmt := range addColumns {
101 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _, _ = s.db.Exec(stmt) // ignore "column already exists"
102 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
94 103 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return nil
95 104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
97 105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
// AgentUpsert inserts or updates an agent row by nick.
98 106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
func (s *Store) AgentUpsert(r *AgentRow) error {
99 107 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
revoked := 0
100 108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if r.Revoked {
101 109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
revoked = 1
102 110 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ var lastSeen string
112 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if r.LastSeen != nil {
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ lastSeen = r.LastSeen.UTC().Format(time.RFC3339Nano)
114 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
103 115 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
q := fmt.Sprintf(
104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- `INSERT INTO agents (nick, type, config, created_at, revoked)
105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- VALUES (%s, %s, %s, %s, %s)
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ `INSERT INTO agents (nick, type, config, created_at, revoked, last_seen)
117 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ VALUES (%s, %s, %s, %s, %s, %s)
106 118 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
ON CONFLICT(nick) DO UPDATE SET
107 119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
type=EXCLUDED.type, config=EXCLUDED.config,
108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- created_at=EXCLUDED.created_at, revoked=EXCLUDED.revoked`,
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- s.ph(1), s.ph(2), s.ph(3), s.ph(4), s.ph(5),
120 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ created_at=EXCLUDED.created_at, revoked=EXCLUDED.revoked,
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ last_seen=EXCLUDED.last_seen`,
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ s.ph(1), s.ph(2), s.ph(3), s.ph(4), s.ph(5), s.ph(6),
110 123 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
)
111 124 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
_, err := s.db.Exec(q,
112 125 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
r.Nick, r.Type, string(r.Config),
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- r.CreatedAt.UTC().Format(time.RFC3339), revoked,
126 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ r.CreatedAt.UTC().Format(time.RFC3339), revoked, lastSeen,
114 127 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
)
115 128 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return err
116 129 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
117 130 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
118 131 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
// AgentDelete removes an agent row entirely.
@@ -124,29 +137,34 @@
124 137 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return err
125 138 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
126 139 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
127 140 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
// AgentList returns all agent rows, including revoked ones.
128 141 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
func (s *Store) AgentList() ([]*AgentRow, error) {
129 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- rows, err := s.db.Query(`SELECT nick, type, config, created_at, revoked FROM agents`)
142 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ rows, err := s.db.Query(`SELECT nick, type, config, created_at, revoked, COALESCE(last_seen,'') FROM agents`)
130 143 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if err != nil {
131 144 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return nil, err
132 145 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
133 146 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
defer rows.Close()
134 147 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
135 148 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
var out []*AgentRow
136 149 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
for rows.Next() {
137 150 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
var r AgentRow
138 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- var cfg, ts string
151 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ var cfg, ts, lastSeenStr string
139 152 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
var revokedInt int
140 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- if err := rows.Scan(&r.Nick, &r.Type, &cfg, &ts, &revokedInt); err != nil {
153 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if err := rows.Scan(&r.Nick, &r.Type, &cfg, &ts, &revokedInt, &lastSeenStr); err != nil {
141 154 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return nil, err
142 155 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
143 156 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
r.Config = []byte(cfg)
144 157 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
r.Revoked = revokedInt != 0
145 158 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
r.CreatedAt, err = time.Parse(time.RFC3339, ts)
146 159 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
if err != nil {
147 160 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return nil, fmt.Errorf("store: agent %s timestamp: %w", r.Nick, err)
161 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
162 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if lastSeenStr != "" {
163 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if t, err := time.Parse(time.RFC3339Nano, lastSeenStr); err == nil {
164 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ r.LastSeen = &t
165 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
148 166 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
149 167 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
out = append(out, &r)
150 168 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
151 169 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return out, rows.Err()
152 170 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
}
153 171 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!