Split out curtin configuration files
Break out curtin configuration data into multiple configuration files This sets up our initial install (network +storage) and our secondary run (postinstall user config). - encrypt the users password and never log the original value Signed-off-by: Ryan Harper <ryan.harper@canonical.com> Conflicts: subiquity/controllers/filesystem.py
This commit is contained in:
parent
53b9e59929
commit
fbee724441
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from subiquity.controller import ControllerPolicy
|
from subiquity.controller import ControllerPolicy
|
||||||
|
from subiquity.models.actions import preserve_action
|
||||||
from subiquity.models import (FilesystemModel, IscsiDiskModel, RaidModel,
|
from subiquity.models import (FilesystemModel, IscsiDiskModel, RaidModel,
|
||||||
CephDiskModel)
|
CephDiskModel)
|
||||||
from subiquity.ui.views import (DiskPartitionView, AddPartitionView,
|
from subiquity.ui.views import (DiskPartitionView, AddPartitionView,
|
||||||
|
@ -23,7 +24,7 @@ from subiquity.ui.views import (DiskPartitionView, AddPartitionView,
|
||||||
import subiquity.utils as utils
|
import subiquity.utils as utils
|
||||||
from subiquity.ui.dummy import DummyView
|
from subiquity.ui.dummy import DummyView
|
||||||
from subiquity.curtin import (curtin_write_storage_actions,
|
from subiquity.curtin import (curtin_write_storage_actions,
|
||||||
curtin_write_postinst_config)
|
curtin_write_preserved_actions)
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.controller.filesystem")
|
log = logging.getLogger("subiquity.controller.filesystem")
|
||||||
|
@ -58,8 +59,11 @@ class FilesystemController(ControllerPolicy):
|
||||||
|
|
||||||
log.info("Rendering curtin config from user choices")
|
log.info("Rendering curtin config from user choices")
|
||||||
curtin_write_storage_actions(actions=actions)
|
curtin_write_storage_actions(actions=actions)
|
||||||
log.info("Generating post-install config")
|
|
||||||
curtin_write_postinst_config()
|
log.info("Rendering preserved config for post install")
|
||||||
|
preserved_actions = [preserve_action(a) for a in actions]
|
||||||
|
curtin_write_preserved_actions(actions=preserved_actions)
|
||||||
|
|
||||||
self.signal.emit_signal('installprogress:do-initial-install')
|
self.signal.emit_signal('installprogress:do-initial-install')
|
||||||
self.signal.emit_signal('identity:show')
|
self.signal.emit_signal('identity:show')
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ import subiquity.utils as utils
|
||||||
from subiquity.models import InstallProgressModel
|
from subiquity.models import InstallProgressModel
|
||||||
from subiquity.ui.views import ProgressView, ProgressOutput
|
from subiquity.ui.views import ProgressView, ProgressOutput
|
||||||
from subiquity.controller import ControllerPolicy
|
from subiquity.controller import ControllerPolicy
|
||||||
|
from subiquity.curtin import (CURTIN_CONFIGS,
|
||||||
|
curtin_install_cmd,
|
||||||
|
curtin_write_postinst_config)
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.controller.installprogress")
|
log = logging.getLogger("subiquity.controller.installprogress")
|
||||||
|
|
||||||
|
@ -34,31 +37,49 @@ class InstallProgressController(ControllerPolicy):
|
||||||
self.signal.emit_signal('refresh')
|
self.signal.emit_signal('refresh')
|
||||||
|
|
||||||
@coroutine
|
@coroutine
|
||||||
def curtin_dispatch(self):
|
def curtin_dispatch(self, postconfig):
|
||||||
|
''' one time curtin dispatch requires the use of
|
||||||
|
the preserved storage config which allows executing
|
||||||
|
in-target commands by remounting up the configured
|
||||||
|
storage.
|
||||||
|
'''
|
||||||
|
log.debug('curtin dispatch using target={}'.format(
|
||||||
|
self.model.target_root))
|
||||||
write_fd = self.loop.watch_pipe(self.install_progress_status)
|
write_fd = self.loop.watch_pipe(self.install_progress_status)
|
||||||
|
|
||||||
|
log.debug('writing out postinst config')
|
||||||
|
curtin_write_postinst_config(postconfig)
|
||||||
|
configs = [CURTIN_CONFIGS['preserved'], CURTIN_CONFIGS['postinstall']]
|
||||||
|
curtin_cmd = curtin_install_cmd(configs, self.mount.target_root)
|
||||||
|
log.debug('Curtin postinstall install cmd: {}'.format(curtin_cmd))
|
||||||
|
|
||||||
if self.opts.dry_run:
|
if self.opts.dry_run:
|
||||||
log.debug("Install Progress: Curtin dispatch dry-run")
|
log.debug("Install Progress: Curtin dispatch dry-run")
|
||||||
yield utils.run_command_async("cat /var/log/syslog",
|
yield utils.run_command_async("cat /var/log/syslog",
|
||||||
write_fd)
|
write_fd)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
yield utils.run_command_async("/usr/local/bin/curtin_wrap.sh",
|
yield utils.run_command_async(" ".join(curtin_cmd),
|
||||||
write_fd)
|
write_fd)
|
||||||
except:
|
except:
|
||||||
log.error("Problem with curtin dispatch run")
|
log.error("Problem with curtin dispatch run")
|
||||||
raise Exception("Problem with curtin dispatch run")
|
raise Exception("Problem with curtin dispatch run")
|
||||||
|
|
||||||
@coroutine
|
@coroutine
|
||||||
def initial_install(self):
|
def initial_install(self, target_root):
|
||||||
|
log.debug('User specified {} to hold rootfs'.format(target_root))
|
||||||
|
self.model.target_root = target_root
|
||||||
write_fd = self.loop.watch_pipe(self.install_progress_status)
|
write_fd = self.loop.watch_pipe(self.install_progress_status)
|
||||||
|
configs = [CURTIN_CONFIGS['network'], CURTIN_CONFIGS['storage']]
|
||||||
|
curtin_cmd = curtin_install_cmd(configs)
|
||||||
|
log.debug('Curtin install cmd: {}'.format(curtin_cmd))
|
||||||
if self.opts.dry_run:
|
if self.opts.dry_run:
|
||||||
log.debug("Filesystem: this is a dry-run")
|
log.debug("Filesystem: this is a dry-run")
|
||||||
yield utils.run_command_async("cat /var/log/syslog",
|
yield utils.run_command_async("cat /var/log/syslog",
|
||||||
write_fd)
|
write_fd)
|
||||||
else:
|
else:
|
||||||
log.debug("filesystem: this is the *real* thing")
|
log.debug("filesystem: this is the *real* thing")
|
||||||
yield utils.run_command_async(
|
yield utils.run_command_async(" ".join(curtin_cmd),
|
||||||
"/usr/local/bin/curtin_wrap.sh",
|
|
||||||
write_fd)
|
write_fd)
|
||||||
|
|
||||||
@coroutine
|
@coroutine
|
||||||
|
@ -74,8 +95,8 @@ class InstallProgressController(ControllerPolicy):
|
||||||
if self.opts.dry_run:
|
if self.opts.dry_run:
|
||||||
banner = [
|
banner = [
|
||||||
"**** DRY_RUN ****",
|
"**** DRY_RUN ****",
|
||||||
"NOT calling:"
|
""
|
||||||
"subprocess.check_call(/usr/local/bin/curtin_wrap.sh)"
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"Press (Q) to Quit."
|
"Press (Q) to Quit."
|
||||||
|
|
|
@ -13,13 +13,30 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# 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 jinja2
|
|
||||||
import os
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import jinja2
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
CURTIN_STORAGE_CONFIG_FILE = '/tmp/subiquity-config.yaml'
|
|
||||||
CURTIN_STORAGE_CONFIG_HEADER = """
|
log = logging.getLogger("subiquity.curtin")
|
||||||
|
|
||||||
|
TMPDIR = '/tmp'
|
||||||
|
CURTIN = '/usr/local/curtin/bin/curtin'
|
||||||
|
CONF_PREFIX = os.path.join(TMPDIR, 'subiquity-config-')
|
||||||
|
CURTIN_NETWORK_CONFIG_FILE = CONF_PREFIX + 'network.yaml'
|
||||||
|
CURTIN_STORAGE_CONFIG_FILE = CONF_PREFIX + 'storage.yaml'
|
||||||
|
CURTIN_PRESERVED_CONFIG_FILE = CONF_PREFIX + 'storage-preserved.yaml'
|
||||||
|
POST_INSTALL_CONFIG_FILE = CONF_PREFIX + 'postinst.yaml'
|
||||||
|
CURTIN_CONFIGS = {
|
||||||
|
'network': CURTIN_NETWORK_CONFIG_FILE,
|
||||||
|
'storage': CURTIN_STORAGE_CONFIG_FILE,
|
||||||
|
'postinstall': POST_INSTALL_CONFIG_FILE,
|
||||||
|
'preserved': CURTIN_PRESERVED_CONFIG_FILE,
|
||||||
|
}
|
||||||
|
CURTIN_CONFIG_HEADER = """
|
||||||
reporter:
|
reporter:
|
||||||
subiquity:
|
subiquity:
|
||||||
path: /tmp/curtin_progress_subiquity
|
path: /tmp/curtin_progress_subiquity
|
||||||
|
@ -28,10 +45,22 @@ reporter:
|
||||||
partitioning_commands:
|
partitioning_commands:
|
||||||
builtin: curtin block-meta custom
|
builtin: curtin block-meta custom
|
||||||
|
|
||||||
|
"""
|
||||||
|
CURTIN_CONFIG_REBOOT = """
|
||||||
|
power_state:
|
||||||
|
message: s-Ubiquity install complete. Rebooting
|
||||||
|
mode: reboot
|
||||||
|
"""
|
||||||
|
CURTIN_STORAGE_CONFIG_HEADER = """
|
||||||
storage:
|
storage:
|
||||||
version: 1
|
version: 1
|
||||||
config:
|
config:
|
||||||
"""
|
"""
|
||||||
|
CURTIN_NETWORK_CONFIG_HEADER = """
|
||||||
|
network:
|
||||||
|
version: 1
|
||||||
|
config:
|
||||||
|
"""
|
||||||
CURTIN_STORAGE_CONFIG_TEMPLATE = """
|
CURTIN_STORAGE_CONFIG_TEMPLATE = """
|
||||||
# Autogenerated by SUbiquity: {{DATE}} UTC
|
# Autogenerated by SUbiquity: {{DATE}} UTC
|
||||||
reporter:
|
reporter:
|
||||||
|
@ -79,20 +108,38 @@ storage:
|
||||||
device: {{TARGET_DISK_NAME}}2_home
|
device: {{TARGET_DISK_NAME}}2_home
|
||||||
"""
|
"""
|
||||||
|
|
||||||
POST_INSTALL_CONFIG_FILE = '/tmp/subiquity-postinst.yaml'
|
|
||||||
# TODO, this should be moved to the in-target cloud-config seed so on first boot
|
# TODO, this should be moved to the in-target cloud-config seed so on first boot
|
||||||
# of the target, it reconfigures datasource_list to none for subsequent boots
|
# of the target, it reconfigures datasource_list to none for subsequent boots
|
||||||
# 12_ds_to_none: [curtin, in-target, --, sh, '-c', "echo 'datasource_list: [ None ]' > /etc/cloud/cloud.cfg.d/
|
# 12_ds_to_none: [curtin, in-target, --, sh, '-c', "echo 'datasource_list: [ None ]' > /etc/cloud/cloud.cfg.d/
|
||||||
POST_INSTALL = '''
|
POST_INSTALL = '''
|
||||||
late_commands:
|
late_commands:
|
||||||
10_set_hostname: curtin in-target -- sh -c 'echo $(petname) > /etc/hostname'
|
10_set_hostname: curtin in-target -- sh -c 'echo $(petname) > /etc/hostname'
|
||||||
11_postinst_seed: [curtin, in-target, --, sh, '-c',"/bin/echo -e '#cloud-config\\npassword: passw0rd\\nchpasswd: { expire: False }\\n' > /var/lib/cloud/seed/nocloud-net/user-data"]
|
11_postinst_seed: [curtin, in-target, --, sh, '-c',"/bin/echo -e '#cloud-config\\npassword: passw0rd\\nchpasswd: {{ expire: False }}\\nusers:\\n{users}' > /var/lib/cloud/seed/nocloud-net/user-data"]
|
||||||
12_disable_subiquity: curtin in-target -- systemctl disable subiquity.service
|
12_disable_subiquity: curtin in-target -- systemctl disable subiquity.service
|
||||||
13_delete_subiquity: curtin in-target -- rm -f /lib/systemd/system/subiquity.service
|
13_delete_subiquity: curtin in-target -- rm -f /lib/systemd/system/subiquity.service
|
||||||
14_remove_subiquity: curtin in-target -- sh -c 'for d in probert curtin subiquity; do rm -rf /usr/local/${d}; rm -rf /usr/local/bin/${d}*; done'
|
14_remove_subiquity: curtin in-target -- sh -c 'for d in probert curtin subiquity; do rm -rf /usr/local/${{d}}; rm -rf /usr/local/bin/${{d}}*; done'
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def curtin_userinfo_to_config(userinfo):
|
||||||
|
user_template = ' - name: {username}\\n' + \
|
||||||
|
' gecos: {realname}\\n' + \
|
||||||
|
' passwd: {password}\\n'
|
||||||
|
return user_template.format(**userinfo)
|
||||||
|
|
||||||
|
|
||||||
|
def curtin_write_postinst_config(userinfo):
|
||||||
|
config = {
|
||||||
|
'users': curtin_userinfo_to_config(userinfo)
|
||||||
|
}
|
||||||
|
with open(POST_INSTALL_CONFIG_FILE, 'w') as conf:
|
||||||
|
datestr = '# Autogenerated by SUbiquity: {} UTC'.format(
|
||||||
|
str(datetime.datetime.utcnow()))
|
||||||
|
conf.write(datestr)
|
||||||
|
conf.write(POST_INSTALL.format(**config))
|
||||||
|
conf.close()
|
||||||
|
|
||||||
|
|
||||||
def curtin_write_storage_actions(actions):
|
def curtin_write_storage_actions(actions):
|
||||||
curtin_config = yaml.dump(actions, default_flow_style=False)
|
curtin_config = yaml.dump(actions, default_flow_style=False)
|
||||||
curtin_config = " " + "\n ".join(curtin_config.splitlines())
|
curtin_config = " " + "\n ".join(curtin_config.splitlines())
|
||||||
|
@ -100,7 +147,19 @@ def curtin_write_storage_actions(actions):
|
||||||
str(datetime.datetime.utcnow()))
|
str(datetime.datetime.utcnow()))
|
||||||
with open(CURTIN_STORAGE_CONFIG_FILE, 'w') as conf:
|
with open(CURTIN_STORAGE_CONFIG_FILE, 'w') as conf:
|
||||||
conf.write(datestr)
|
conf.write(datestr)
|
||||||
conf.write(CURTIN_STORAGE_CONFIG_HEADER)
|
conf.write(CURTIN_CONFIG_HEADER + CURTIN_STORAGE_CONFIG_HEADER)
|
||||||
|
conf.write(curtin_config)
|
||||||
|
conf.close()
|
||||||
|
|
||||||
|
|
||||||
|
def curtin_write_network_actions(actions):
|
||||||
|
curtin_config = yaml.dump(actions, default_flow_style=False)
|
||||||
|
curtin_config = " " + "\n ".join(curtin_config.splitlines())
|
||||||
|
datestr = '# Autogenerated by SUbiquity: {} UTC'.format(
|
||||||
|
str(datetime.datetime.utcnow()))
|
||||||
|
with open(CURTIN_NETWORK_CONFIG_FILE, 'w') as conf:
|
||||||
|
conf.write(datestr)
|
||||||
|
conf.write(CURTIN_CONFIG_HEADER + CURTIN_NETWORK_CONFIG_HEADER)
|
||||||
conf.write(curtin_config)
|
conf.write(curtin_config)
|
||||||
conf.close()
|
conf.close()
|
||||||
|
|
||||||
|
@ -129,10 +188,42 @@ def curtin_write_storage_template(disk_name, disk_model, disk_serial):
|
||||||
return CURTIN_STORAGE_CONFIG_FILE
|
return CURTIN_STORAGE_CONFIG_FILE
|
||||||
|
|
||||||
|
|
||||||
def curtin_write_postinst_config():
|
def curtin_write_preserved_actions(actions):
|
||||||
with open(POST_INSTALL_CONFIG_FILE, 'w') as conf:
|
''' caller must use models.actions.preserve_action on
|
||||||
|
all elements of the actions'''
|
||||||
|
curtin_config = yaml.dump(actions, default_flow_style=False)
|
||||||
|
curtin_config = " " + "\n ".join(curtin_config.splitlines())
|
||||||
datestr = '# Autogenerated by SUbiquity: {} UTC'.format(
|
datestr = '# Autogenerated by SUbiquity: {} UTC'.format(
|
||||||
str(datetime.datetime.utcnow()))
|
str(datetime.datetime.utcnow()))
|
||||||
|
with open(CURTIN_PRESERVED_CONFIG_FILE, 'w') as conf:
|
||||||
conf.write(datestr)
|
conf.write(datestr)
|
||||||
conf.write(POST_INSTALL)
|
conf.write(CURTIN_CONFIG_HEADER + CURTIN_STORAGE_CONFIG_HEADER)
|
||||||
|
conf.write(curtin_config)
|
||||||
conf.close()
|
conf.close()
|
||||||
|
|
||||||
|
|
||||||
|
def curtin_install_cmd(configs):
|
||||||
|
'''
|
||||||
|
curtin -v --showtrace install -c $CONFIGS cp:///
|
||||||
|
'''
|
||||||
|
install_cmd = [CURTIN, '-v', '--showtrace']
|
||||||
|
if configs:
|
||||||
|
install_cmd += ['-c {}'.format(c) for c in configs]
|
||||||
|
install_cmd += ['install', 'cp:///']
|
||||||
|
log.info('curtin install command: {}'.format(" ".join(install_cmd)))
|
||||||
|
|
||||||
|
return install_cmd
|
||||||
|
|
||||||
|
|
||||||
|
def curtin_reboot():
|
||||||
|
cmd = "/sbin/reboot"
|
||||||
|
log.info("powering off with %s", cmd)
|
||||||
|
fid = os.fork()
|
||||||
|
if fid == 0:
|
||||||
|
try:
|
||||||
|
subprocess.call([cmd])
|
||||||
|
os._exit(0)
|
||||||
|
except:
|
||||||
|
log.warn("%s returned non-zero" % cmd)
|
||||||
|
os._exit(1)
|
||||||
|
return
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# 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 copy
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,3 +218,16 @@ class MountAction(DiskAction):
|
||||||
'path': self.path,
|
'path': self.path,
|
||||||
'type': 'mount',
|
'type': 'mount',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def preserve_action(action):
|
||||||
|
a = copy.deepcopy(action)
|
||||||
|
a.update({'preserve': True})
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
def release_action(action):
|
||||||
|
a = copy.deepcopy(action)
|
||||||
|
if 'preserve' in action:
|
||||||
|
del a['preserve']
|
||||||
|
return a
|
||||||
|
|
|
@ -249,10 +249,10 @@ class Blockdev():
|
||||||
log.debug('PartitionAction:\n{}'.format(part_action.get()))
|
log.debug('PartitionAction:\n{}'.format(part_action.get()))
|
||||||
|
|
||||||
self.disk.partitions.update({partnum: part_action})
|
self.disk.partitions.update({partnum: part_action})
|
||||||
|
partpath = "{}{}".format(self.disk.devpath, partnum)
|
||||||
|
|
||||||
# record filesystem formating
|
# record filesystem formating
|
||||||
if fstype:
|
if fstype:
|
||||||
partpath = "{}{}".format(self.disk.devpath, partnum)
|
|
||||||
fs_action = FormatAction(part_action, fstype)
|
fs_action = FormatAction(part_action, fstype)
|
||||||
log.debug('Adding filesystem on {}'.format(partpath))
|
log.debug('Adding filesystem on {}'.format(partpath))
|
||||||
log.debug('FormatAction:\n{}'.format(fs_action.get()))
|
log.debug('FormatAction:\n{}'.format(fs_action.get()))
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from subiquity.model import ModelPolicy
|
from subiquity.model import ModelPolicy
|
||||||
|
from subiquity.utils import crypt_password
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger('subiquity.models.identity')
|
log = logging.getLogger('subiquity.models.identity')
|
||||||
|
@ -57,9 +58,8 @@ class IdentityModel(ModelPolicy):
|
||||||
if x == selection:
|
if x == selection:
|
||||||
return y
|
return y
|
||||||
|
|
||||||
def encrypt_password(self):
|
def encrypt_password(self, passinput):
|
||||||
# TODO: implement
|
return crypt_password(passinput)
|
||||||
pass
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<Username: {}>".format(self.username)
|
return "<Username: {}>".format(self.username)
|
||||||
|
|
|
@ -87,16 +87,17 @@ class IdentityView(ViewPolicy):
|
||||||
return Pile(sl)
|
return Pile(sl)
|
||||||
|
|
||||||
def done(self, result):
|
def done(self, result):
|
||||||
log.debug("User input: {} {} {}".format(self.username.value,
|
cpassword = self.model.encrypt_password(self.password.value)
|
||||||
self.password.value,
|
log.debug("*crypted* User input: {} {} {}".format(
|
||||||
self.confirm_password.value))
|
self.username.value, cpassword, cpassword))
|
||||||
result = {
|
result = {
|
||||||
"username": self.username.value,
|
"username": self.username.value,
|
||||||
"password": self.password.value,
|
"password": cpassword,
|
||||||
"confirm_password": self.confirm_password.value
|
"confirm_password": cpassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("User input: {}".format(result))
|
log.debug("User input: {}".format(result))
|
||||||
self.signal.emit_signal('installprogress:curtin-dispatch')
|
self.signal.emit_signal('installprogress:curtin-dispatch', result)
|
||||||
self.signal.emit_signal('installprogress:show')
|
self.signal.emit_signal('installprogress:show')
|
||||||
|
|
||||||
def cancel(self, button):
|
def cancel(self, button):
|
||||||
|
|
|
@ -13,11 +13,13 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# 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 os
|
import crypt
|
||||||
from subprocess import Popen, PIPE
|
|
||||||
from subiquity.async import Async
|
|
||||||
import errno
|
import errno
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
from subiquity.async import Async
|
||||||
|
|
||||||
log = logging.getLogger("subiquity.utils")
|
log = logging.getLogger("subiquity.utils")
|
||||||
SYS_CLASS_NET = "/sys/class/net/"
|
SYS_CLASS_NET = "/sys/class/net/"
|
||||||
|
@ -87,3 +89,19 @@ def read_sys_net(devname, path, translate=None, enoent=None, keyerror=None):
|
||||||
if e.errno == errno.ENOENT and enoent is not None:
|
if e.errno == errno.ENOENT and enoent is not None:
|
||||||
return enoent
|
return enoent
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
## FIXME: replace with passlib and update package deps
|
||||||
|
def crypt_password(passwd, algo='SHA-512'):
|
||||||
|
# encryption algo - id pairs for crypt()
|
||||||
|
algos = {'SHA-512': '$6$', 'SHA-256': '$5$', 'MD5': '$1$', 'DES': ''}
|
||||||
|
if algo not in algos:
|
||||||
|
raise Exception('Invalid algo({}), must be one of: {}. '.format(
|
||||||
|
algo, ','.join(algos.keys())))
|
||||||
|
|
||||||
|
salt_set = ('abcdefghijklmnopqrstuvwxyz'
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||||
|
'0123456789./')
|
||||||
|
salt = 16 * ' '
|
||||||
|
salt = ''.join([random.choice(salt_set) for c in salt])
|
||||||
|
return crypt.crypt(passwd, algos[algo] + salt)
|
||||||
|
|
Loading…
Reference in New Issue