-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
systemd: Add lastlog2 support for "last login" health card item #21176
systemd: Add lastlog2 support for "last login" health card item #21176
Conversation
This
Update: As the failures on old OSes show, it's not only gross, but wrong:
There is no hope of parsing this properly. I'll leave lastlog1 parsing as-is, and re-do lastlog2 as SQL. |
f0a1291
to
8d31bbc
Compare
This flake is rather annoying.. As this test touches the users page, they all have to pass 3x. "Unexpected error when getting locked account information" sounds rather unrelated. I tried this locally, and it passed 10 times in a row. Polluted VM from a previous test? -- No, I ran the exact same tests in the same order as in CI, and it passes.
These happen in successful runs, too..
This on the other hand doesn't, so may be related to the terminate_sessions() failure. Moving to draft, and amplifying/debugging. |
8d31bbc
to
9db5989
Compare
Cool, works! Good enough. |
9db5989
to
3906b8f
Compare
This avoids calling `cockpit.LoginMessages` and `cockpit.user` multiple times during each initialization, and simplifies the structure.
We'll soon need more information (tty and remote host) from lastlog2. This is impossible to parse from the `lastlog[2]` CLI: With modern versions and their variable-width multi-space-separated columns it's merely hard and gross, but older `lastlog` versions misalign the columns. So give up on this, and read lastlog2's sqlite database directly. Fortunately Python comes with the `sqlite3` module built in. This also gets rid of the brittle date/time parsing. Make this a library, as we will use it from the Overview page as well.
Phase out the last login information from cockpit-session. With distributions moving to lastlog2 [1], we can get that information from the Overview page directly. For now, support both sources. [1] cockpit-project/bots#7033
Otherwise in our test logs it comes out as "Object(5)", which is useless.
Log out the root session at the end. This helps with stopping logind in our test cleanup. DRY, use `login_and_go()` to drive the login page.
3906b8f
to
0362e07
Compare
|
||
con = sqlite3.connect(DB) | ||
cur = con.cursor() | ||
query = "SELECT Name, Time, TTY, RemoteHost FROM Lastlog2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the schema documented somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just got it from .schema
in sqlite3. The manpage doesn't document it. Otherwise, it's just in the upstream source code.
The format doesn't look prone to changes, but of course it could happen in principle. Then our tests should pick it up and we need to deal with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks!
const out = await python.spawn(lastlog2_py, user ? [user] : [], { err: "message" }); | ||
return JSON.parse(out); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 added lines are not executed by any test.
} else { | ||
// empty reply is okay -- older bridges just don't send that information | ||
if (obj.version !== undefined) | ||
console.error("unknown login-messages:", reply); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This added line is not executed by any test.
} catch (error) { | ||
console.error("failed to fetch login messages:", error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 added lines are not executed by any test.
setLastlog((await getLastlog2(user.name))[user.name]); | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 added lines are not executed by any test.
|
||
if (messages === null || !messages['last-login-time']) { | ||
const lastLoginTime = messages?.['last-login-time'] ?? lastlog?.time; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This added line is not executed by any test.
const lastLoginFrom = messages?.['last-login-host'] || lastlog?.from; | ||
const lastLoginPort = messages?.['last-login-line'] || lastlog?.port; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 added lines are not executed by any test.
@@ -207,43 +208,42 @@ async function getLoginDetails(logind_client) { | |||
details[name] = { ...details[name], isLocked: hash.startsWith("!") }; | |||
} | |||
} catch (err) { | |||
console.warn("Unexpected error when getting locked accounts from /etc/shadow:", err); | |||
console.warn("Unexpected error when getting locked accounts from /etc/shadow:", err.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This added line is not executed by any test.
for (const [name, last] of Object.entries(await getLastlog2())) | ||
details[name] = { ...details[name], lastLogin: last.time * 1000 }; | ||
} catch (err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 3 added lines are not executed by any test.
} catch (e) { | ||
console.warn(`Failed to parse date from lastlog line '${line}': ${e.toString()}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 added lines are not executed by any test.
} catch (ex) { | ||
console.warn(`Failed to run lastlog: ${ex.toString()}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 2 added lines are not executed by any test.
Latest debian testing dropped support for the old wtmp/lastlog stack. Other distributions will follow soon.
Blocks cockpit-project/bots#7033
The extra debian-testing/{other,expensive}@Bots#7033 tests here prove that this works.