Merge pull request #794 from mwhudson/lp-1881588

use snapd apis to check for users
This commit is contained in:
Michael Hudson-Doyle 2020-07-10 08:37:51 +12:00 committed by GitHub
commit 317648aec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 44 deletions

View File

@ -16,11 +16,13 @@
import json import json
import logging import logging
import os import os
import pwd
import shlex import shlex
import sys import sys
from subiquitycore.controller import BaseController from subiquitycore.controller import BaseController
from subiquitycore.ssh import host_key_info, get_ips_standalone from subiquitycore.ssh import host_key_info, get_ips_standalone
from subiquitycore.snapd import SnapdConnection
from subiquitycore.utils import disable_console_conf, run_command from subiquitycore.utils import disable_console_conf, run_command
from console_conf.ui.views import IdentityView, LoginView from console_conf.ui.views import IdentityView, LoginView
@ -50,24 +52,34 @@ def get_core_version():
return version return version
def get_device_owner(): def get_managed():
""" Check if device is owned """ """ Check if device is managed """
con = SnapdConnection('', '/run/snapd.socket')
return con.get('v2/system-info').json()['result']['managed']
# TODO: use proper snap APIs.
def get_realname(username):
try: try:
extrausers_fp = open('/var/lib/extrausers/passwd', 'r') info = pwd.getpwnam(username)
except FileNotFoundError: except KeyError:
return None return ''
with extrausers_fp: return info.pw_gecos.split(',', 1)[0]
passwd_line = extrausers_fp.readline()
if passwd_line and len(passwd_line) > 0:
passwd = passwd_line.split(':') def get_device_owner():
result = { """ Get device owner, if any """
'realname': passwd[4].split(',')[0], con = SnapdConnection('', '/run/snapd.socket')
'username': passwd[0], for user in con.get('v2/users').json()['result']:
'homedir': passwd[5], if 'username' not in user:
continue
username = user['username']
homedir = '/home/' + username
if os.path.isdir(homedir):
return {
'username': username,
'realname': get_realname(username),
'homedir': homedir,
} }
return result
return None return None
@ -111,17 +123,21 @@ def write_login_details(fp, username, ips):
def write_login_details_standalone(): def write_login_details_standalone():
owner = get_device_owner() owner = get_device_owner()
if owner is None:
print("No device owner details found.")
return 0
ips = get_ips_standalone() ips = get_ips_standalone()
if len(ips) == 0: if len(ips) == 0:
tty_name = os.ttyname(0)[5:] if owner is None:
version = get_core_version() or "16" print("device managed without user")
print(login_details_tmpl_no_ip.format(tty_name=tty_name, return 2
version=version)) else:
return 2 tty_name = os.ttyname(0)[5:]
write_login_details(sys.stdout, owner['username'], ips) version = get_core_version() or "16"
print(login_details_tmpl_no_ip.format(
tty_name=tty_name, version=version))
return 2
if owner is None:
print("device managed without user @ {}".format(', '.join(ips)))
else:
write_login_details(sys.stdout, owner['username'], ips)
return 0 return 0
@ -133,14 +149,15 @@ class IdentityController(BaseController):
def start_ui(self): def start_ui(self):
self.ui.set_body(IdentityView(self.model, self)) self.ui.set_body(IdentityView(self.model, self))
device_owner = get_device_owner() if get_managed():
if device_owner is not None: device_owner = get_device_owner()
self.model.add_user(device_owner) if device_owner:
key_file = os.path.join(device_owner['homedir'], self.model.add_user(device_owner)
".ssh/authorized_keys") key_file = os.path.join(device_owner['homedir'],
self.model.user.fingerprints = ( ".ssh/authorized_keys")
run_command(['ssh-keygen', '-lf', cp = run_command(['ssh-keygen', '-lf', key_file])
key_file]).stdout.replace('\r', '').splitlines()) self.model.user.fingerprints = (
cp.stdout.replace('\r', '').splitlines())
self.login() self.login()
def identity_done(self, email): def identity_done(self, email):

View File

@ -57,6 +57,17 @@ class LoginView(BaseView):
] ]
def _build_model_inputs(self): def _build_model_inputs(self):
user = self.model.user
ips = []
for dev in self.netdevs:
for addr in dev.actual_global_ip_addresses:
ips.append(addr)
if not user:
sl = []
sl.append(Text("no owner"))
return sl
local_tpl = ( local_tpl = (
"This device is registered to {realname}.") "This device is registered to {realname}.")
@ -67,17 +78,12 @@ class LoginView(BaseView):
"device via SSH:") "device via SSH:")
sl = [] sl = []
user = self.model.user
login_info = { login_info = {
'realname': user.realname, 'realname': user.realname,
'username': user.username, 'username': user.username,
} }
login_text = local_tpl.format(**login_info) login_text = local_tpl.format(**login_info)
login_text += remote_tpl.format(**login_info) login_text += remote_tpl.format(**login_info)
ips = []
for dev in self.netdevs:
for addr in dev.actual_global_ip_addresses:
ips.append(addr)
sl += [Text(login_text), Padding.line_break("")] sl += [Text(login_text), Padding.line_break("")]
for ip in ips: for ip in ips:

2
debian/control vendored
View File

@ -23,6 +23,8 @@ Depends: probert-network,
python3-urwid (>= 1.2.1), python3-urwid (>= 1.2.1),
python3-attr, python3-attr,
python3-yaml, python3-yaml,
python3-requests,
python3-requests-unixsocket,
${misc:Depends}, ${misc:Depends},
${python3:Depends} ${python3:Depends}
Description: Ubuntu Server Installer - core libraries Description: Ubuntu Server Installer - core libraries

View File

@ -49,6 +49,7 @@ subiquitycore/ui/stretchy.py
subiquitycore/ui/container.py subiquitycore/ui/container.py
subiquitycore/ui/frame.py subiquitycore/ui/frame.py
subiquitycore/file_util.py subiquitycore/file_util.py
subiquitycore/snapd.py
subiquitycore/view.py subiquitycore/view.py
subiquity/controllers/identity.py subiquity/controllers/identity.py
subiquity/controllers/package.py subiquity/controllers/package.py
@ -76,7 +77,6 @@ subiquity/cmd/__init__.py
subiquity/cmd/tui.py subiquity/cmd/tui.py
subiquity/cmd/schema.py subiquity/cmd/schema.py
subiquity/journald.py subiquity/journald.py
subiquity/snapd.py
subiquity/lockfile.py subiquity/lockfile.py
subiquity/models/identity.py subiquity/models/identity.py
subiquity/models/locale.py subiquity/models/locale.py

View File

@ -35,6 +35,11 @@ from subiquitycore.async_helpers import (
) )
from subiquitycore.controller import Skip from subiquitycore.controller import Skip
from subiquitycore.core import Application from subiquitycore.core import Application
from subiquitycore.snapd import (
AsyncSnapd,
FakeSnapdConnection,
SnapdConnection,
)
from subiquitycore.view import BaseView from subiquitycore.view import BaseView
from subiquity.controllers.error import ( from subiquity.controllers.error import (
@ -43,11 +48,6 @@ from subiquity.controllers.error import (
from subiquity.journald import journald_listener from subiquity.journald import journald_listener
from subiquity.lockfile import Lockfile from subiquity.lockfile import Lockfile
from subiquity.models.subiquity import SubiquityModel from subiquity.models.subiquity import SubiquityModel
from subiquity.snapd import (
AsyncSnapd,
FakeSnapdConnection,
SnapdConnection,
)
from subiquity.ui.frame import SubiquityUI from subiquity.ui.frame import SubiquityUI
from subiquity.ui.views.error import ErrorReportStretchy from subiquity.ui.views.error import ErrorReportStretchy
from subiquity.ui.views.help import HelpMenu from subiquity.ui.views.help import HelpMenu

View File

@ -31,7 +31,7 @@ from subiquitycore.utils import run_command
import requests_unixsocket import requests_unixsocket
log = logging.getLogger('subiquity.snapd') log = logging.getLogger('subiquitycore.snapd')
# Every method in this module blocks. Do not call them from the main thread! # Every method in this module blocks. Do not call them from the main thread!