Merge branch 'mwhudson/demo'
This commit is contained in:
commit
d3c0bb95d7
|
@ -18,7 +18,7 @@ import argparse
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import signal
|
import signal
|
||||||
from subiquitycore.log import setup_logger, LOGFILE
|
from subiquitycore.log import setup_logger
|
||||||
from subiquitycore import __version__ as VERSION
|
from subiquitycore import __version__ as VERSION
|
||||||
from console_conf.core import ConsoleConf
|
from console_conf.core import ConsoleConf
|
||||||
from subiquitycore.core import ApplicationError
|
from subiquitycore.core import ApplicationError
|
||||||
|
@ -70,10 +70,14 @@ def parse_options(argv):
|
||||||
def control_c_handler(signum, frame):
|
def control_c_handler(signum, frame):
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
LOGDIR = "/writable/.subiquity"
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
opts = parse_options(sys.argv[1:])
|
opts = parse_options(sys.argv[1:])
|
||||||
setup_logger()
|
global LOGDIR
|
||||||
|
if opts.dry_run:
|
||||||
|
LOGDIR = ".subiquity"
|
||||||
|
LOGFILE = setup_logger(dir=LOGDIR)
|
||||||
logger = logging.getLogger('console_conf')
|
logger = logging.getLogger('console_conf')
|
||||||
logger.info("Starting console-conf v{}".format(VERSION))
|
logger.info("Starting console-conf v{}".format(VERSION))
|
||||||
logger.info("Arguments passed: {}".format(sys.argv))
|
logger.info("Arguments passed: {}".format(sys.argv))
|
||||||
|
|
|
@ -16,8 +16,32 @@
|
||||||
|
|
||||||
from subiquitycore.controllers.identity import BaseIdentityController
|
from subiquitycore.controllers.identity import BaseIdentityController
|
||||||
|
|
||||||
from console_conf.ui.views import IdentityView
|
from console_conf.ui.views import IdentityView, LoginView
|
||||||
|
|
||||||
|
|
||||||
class IdentityController(BaseIdentityController):
|
class IdentityController(BaseIdentityController):
|
||||||
identity_view = IdentityView
|
identity_view = IdentityView
|
||||||
|
|
||||||
|
def identity(self):
|
||||||
|
title = "Profile setup"
|
||||||
|
excerpt = "Enter an email address from your account in the store."
|
||||||
|
footer = ""
|
||||||
|
self.ui.set_header(title, excerpt)
|
||||||
|
self.ui.set_footer(footer, 40)
|
||||||
|
self.ui.set_body(self.identity_view(self.model, self.signal, self.opts, self.loop))
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
title = "Configuration Complete"
|
||||||
|
footer = "View configured user and device access methods"
|
||||||
|
self.ui.set_header(title)
|
||||||
|
self.ui.set_footer(footer)
|
||||||
|
|
||||||
|
net_model = self.controllers['Network'].model
|
||||||
|
configured_ifaces = net_model.get_configured_interfaces()
|
||||||
|
login_view = LoginView(self.opts,
|
||||||
|
self.model,
|
||||||
|
self.signal,
|
||||||
|
self.model.user,
|
||||||
|
configured_ifaces)
|
||||||
|
|
||||||
|
self.ui.set_body(login_view)
|
||||||
|
|
|
@ -16,4 +16,5 @@
|
||||||
""" ConsoleConf UI Views """
|
""" ConsoleConf UI Views """
|
||||||
|
|
||||||
from .identity import IdentityView # NOQA
|
from .identity import IdentityView # NOQA
|
||||||
|
from .login import LoginView # NOQA
|
||||||
from .welcome import WelcomeView # NOQA
|
from .welcome import WelcomeView # NOQA
|
||||||
|
|
|
@ -14,19 +14,130 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import pwd
|
||||||
|
|
||||||
from subiquitycore.ui.views.identity import BaseIdentityView
|
from urwid import (Pile, Columns, Text, ListBox)
|
||||||
from subiquitycore.user import create_user
|
from subiquitycore.ui.buttons import done_btn, cancel_btn
|
||||||
|
from subiquitycore.ui.interactive import EmailEditor
|
||||||
|
from subiquitycore.ui.utils import Padding, Color
|
||||||
|
from subiquitycore.utils import run_command
|
||||||
|
from subiquitycore.view import BaseView
|
||||||
|
|
||||||
log = logging.getLogger("console_conf.views.identity")
|
log = logging.getLogger("console_conf.views.identity")
|
||||||
|
|
||||||
|
|
||||||
class IdentityView(BaseIdentityView):
|
'''
|
||||||
def create_user(self, result):
|
+---------------------------------------------------+
|
||||||
try:
|
| |
|
||||||
create_user(
|
| Enter the email address of the account in the |
|
||||||
result, dryrun=self.opts.dry_run, extra_args=['--extrausers'])
|
| store |
|
||||||
except PermissionError:
|
| |
|
||||||
# XXX do something here
|
| +-------------------------+ |
|
||||||
log.exception('Failed to create user.')
|
| Email address: | | |
|
||||||
return None
|
| +-------------------------+ |
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
| +--------+ |
|
||||||
|
| | Done | |
|
||||||
|
| +--------+ |
|
||||||
|
| | Cancel | |
|
||||||
|
| +--------+ |
|
||||||
|
| |
|
||||||
|
+---------------------------------------------------+
|
||||||
|
'''
|
||||||
|
|
||||||
|
class IdentityView(BaseView):
|
||||||
|
|
||||||
|
def __init__(self, model, signal, opts, loop):
|
||||||
|
self.model = model
|
||||||
|
self.signal = signal
|
||||||
|
self.opts = opts
|
||||||
|
self.loop = loop
|
||||||
|
self.items = []
|
||||||
|
self.email = EmailEditor(caption="")
|
||||||
|
self.error = Text("", align="center")
|
||||||
|
self.progress = Text("", align="center")
|
||||||
|
|
||||||
|
body = [
|
||||||
|
Padding.center_90(self._build_model_inputs()),
|
||||||
|
Padding.line_break(""),
|
||||||
|
Padding.center_90(Color.info_error(self.error)),
|
||||||
|
Padding.center_90(self.progress),
|
||||||
|
Padding.line_break(""),
|
||||||
|
Padding.fixed_10(self._build_buttons()),
|
||||||
|
]
|
||||||
|
super().__init__(ListBox(body))
|
||||||
|
|
||||||
|
def _build_model_inputs(self):
|
||||||
|
sl = [
|
||||||
|
Columns(
|
||||||
|
[
|
||||||
|
("weight", 0.2, Text("Email address:", align="right")),
|
||||||
|
("weight", 0.3,
|
||||||
|
Color.string_input(self.email,
|
||||||
|
focus_map="string_input focus"))
|
||||||
|
],
|
||||||
|
dividechars=4
|
||||||
|
),
|
||||||
|
]
|
||||||
|
return Pile(sl)
|
||||||
|
|
||||||
|
def _build_buttons(self):
|
||||||
|
cancel = cancel_btn(on_press=self.cancel)
|
||||||
|
done = done_btn(on_press=self.done)
|
||||||
|
|
||||||
|
buttons = [
|
||||||
|
Color.button(done, focus_map='button focus'),
|
||||||
|
Color.button(cancel, focus_map='button focus')
|
||||||
|
]
|
||||||
|
return Pile(buttons)
|
||||||
|
|
||||||
|
def cancel(self, button):
|
||||||
|
self.signal.prev_signal()
|
||||||
|
|
||||||
|
def done(self, button):
|
||||||
|
if len(self.email.value) < 1:
|
||||||
|
self.error.set_text("Please enter an email address.")
|
||||||
|
return
|
||||||
|
if not self.opts.dry_run:
|
||||||
|
self.progress.set_text("Contacting store...")
|
||||||
|
self.loop.draw_screen()
|
||||||
|
users_before = users()
|
||||||
|
result = run_command(["snap", "create-user", self.email.value])
|
||||||
|
self.progress.set_text("")
|
||||||
|
if result['status'] != 0:
|
||||||
|
self.error.set_text("Creating user failed:\n" + result['err'])
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
users_after = users()
|
||||||
|
new_users = users_after - users_before
|
||||||
|
if len(new_users) != 1:
|
||||||
|
self.error.set_text("uhh")
|
||||||
|
return
|
||||||
|
new_user = pwd.getpwnam(new_users.pop())
|
||||||
|
# Use email for realname until
|
||||||
|
# https://bugs.launchpad.net/snappy/+bug/1607121 is resolved.
|
||||||
|
result = {
|
||||||
|
'realname': self.email.value, #new_user.pw_gecos.split(",")[0]
|
||||||
|
'username': new_user.pw_name,
|
||||||
|
'passwod': '',
|
||||||
|
'confirm_password': ''
|
||||||
|
}
|
||||||
|
# Work around https://bugs.launchpad.net/snappy/+bug/1606815
|
||||||
|
run_command(["chown", "{}:{}".format(new_user.pw_uid, new_user.pw_gid), "-R", new_user.pw_dir])
|
||||||
|
self.model.add_user(result)
|
||||||
|
else:
|
||||||
|
result = {
|
||||||
|
'realname': self.email.value,
|
||||||
|
'username': self.email.value,
|
||||||
|
'passwod': '',
|
||||||
|
'confirm_password': '',
|
||||||
|
}
|
||||||
|
self.model.add_user(result)
|
||||||
|
self.signal.emit_signal('menu:identity:login:main')
|
||||||
|
|
||||||
|
def users():
|
||||||
|
r = set()
|
||||||
|
for pw in pwd.getpwall():
|
||||||
|
r.add(pw.pw_name)
|
||||||
|
return r
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
subiquity (0.0.6~cy3) UNRELEASED; urgency=medium
|
subiquity (0.0.7~1) UNRELEASED; urgency=medium
|
||||||
|
|
||||||
* Release 0.0.6 snapshot: port for yakkety:
|
[ Michael Hudson-Doyle ]
|
||||||
- Build separate subiquitycore, subiquity, and console-conf packages.
|
* Demo-ware.
|
||||||
|
* Install systemd units for console-conf.
|
||||||
|
|
||||||
|
[ Mathieu Trudel-Lapierre ]
|
||||||
|
* Release 0.0.7 snapshot
|
||||||
* debian/control: move Depends on curtin from subiquitycore to subiquity.
|
* debian/control: move Depends on curtin from subiquitycore to subiquity.
|
||||||
|
|
||||||
-- Mathieu Trudel-Lapierre <cyphermox@ubuntu.com> Fri, 08 Jul 2016 16:44:55 -0400
|
-- Mathieu Trudel-Lapierre <cyphermox@ubuntu.com> Fri, 08 Jul 2016 16:44:55 -0400
|
||||||
|
|
|
@ -7,7 +7,7 @@ ExecStop=systemctl start getty@%I
|
||||||
Before=getty.target
|
Before=getty.target
|
||||||
IgnoreOnIsolate=yes
|
IgnoreOnIsolate=yes
|
||||||
ConditionPathExists=/dev/tty0
|
ConditionPathExists=/dev/tty0
|
||||||
ConditionPathExists=!/var/lib/firstboot/firstboot-complete
|
ConditionPathExists=!/writable/firstboot-complete
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Environment=PYTHONPATH=/usr/share/subiquity
|
Environment=PYTHONPATH=/usr/share/subiquity
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#DEBHELPER#
|
||||||
|
|
||||||
|
systemctl enable console-conf@tty1.service
|
||||||
|
systemctl enable serial-console-conf@ttyS1.service
|
|
@ -4,7 +4,7 @@ BindsTo=dev-%i.device
|
||||||
#After=getty@tty.service
|
#After=getty@tty.service
|
||||||
After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
|
After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
|
||||||
After=rc-local.service
|
After=rc-local.service
|
||||||
ConditionPathExists=!/var/lib/firstboot/firstboot-complete
|
ConditionPathExists=!/writable/firstboot-complete
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Environment=PYTHONPATH=/usr/share/subiquity
|
Environment=PYTHONPATH=/usr/share/subiquity
|
||||||
|
|
|
@ -18,14 +18,15 @@ import os
|
||||||
import sys
|
import sys
|
||||||
from logging.handlers import TimedRotatingFileHandler
|
from logging.handlers import TimedRotatingFileHandler
|
||||||
|
|
||||||
LOGDIR = ".subiquity"
|
LOGDIR = "/writable/.subiquity"
|
||||||
LOGFILE = os.path.join(LOGDIR, "subiquity-debug.log")
|
LOGFILE = os.path.join(LOGDIR, "subiquity-debug.log")
|
||||||
|
|
||||||
|
|
||||||
def setup_logger(name=__name__):
|
def setup_logger(name=__name__, dir=LOGDIR):
|
||||||
|
LOGFILE = os.path.join(dir, "subiquity-debug.log")
|
||||||
try:
|
try:
|
||||||
if not os.path.isdir(LOGDIR):
|
if not os.path.isdir(dir):
|
||||||
os.makedirs(LOGDIR)
|
os.makedirs(dir)
|
||||||
log = TimedRotatingFileHandler(LOGFILE,
|
log = TimedRotatingFileHandler(LOGFILE,
|
||||||
when='D',
|
when='D',
|
||||||
interval=1,
|
interval=1,
|
||||||
|
@ -46,4 +47,4 @@ def setup_logger(name=__name__):
|
||||||
logger = logging.getLogger('')
|
logger = logging.getLogger('')
|
||||||
logger.setLevel('DEBUG')
|
logger.setLevel('DEBUG')
|
||||||
logger.addHandler(log)
|
logger.addHandler(log)
|
||||||
return logger
|
return LOGFILE
|
||||||
|
|
|
@ -74,6 +74,20 @@ class RealnameEditor(StringEditor):
|
||||||
return super().keypress(size, key)
|
return super().keypress(size, key)
|
||||||
|
|
||||||
|
|
||||||
|
class EmailEditor(StringEditor):
|
||||||
|
""" Email input prompt with input rules
|
||||||
|
"""
|
||||||
|
|
||||||
|
def keypress(self, size, key):
|
||||||
|
''' restrict what chars we allow for username '''
|
||||||
|
|
||||||
|
realname = r'[-a-zA-Z0-9_.@]'
|
||||||
|
if re.match(realname, key) is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return super().keypress(size, key)
|
||||||
|
|
||||||
|
|
||||||
class UsernameEditor(StringEditor):
|
class UsernameEditor(StringEditor):
|
||||||
""" Username input prompt with input rules
|
""" Username input prompt with input rules
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -202,7 +202,7 @@ def sudo_user():
|
||||||
def mark_firstboot_complete():
|
def mark_firstboot_complete():
|
||||||
""" Touch our firstboot-complete eyecatcher """
|
""" Touch our firstboot-complete eyecatcher """
|
||||||
log.info('marking firstboot service complete')
|
log.info('marking firstboot service complete')
|
||||||
firstboot = '/var/lib/firstboot/firstboot-complete'
|
firstboot = '/writable/firstboot-complete'
|
||||||
if not os.path.exists(os.path.dirname(firstboot)):
|
if not os.path.exists(os.path.dirname(firstboot)):
|
||||||
os.makedirs(os.path.dirname(firstboot))
|
os.makedirs(os.path.dirname(firstboot))
|
||||||
with open(firstboot, 'w') as fp:
|
with open(firstboot, 'w') as fp:
|
||||||
|
|
Loading…
Reference in New Issue