def enable_spi(): # FIXME: instead of rebooting, add a reboot_required property to # Changed/Unchanged and allow chaining these. # # e.g. # # c = some_operation() # c = c.chain(another_operation, msg=....) # # return c # # at any point in time, c.reboot_required can be resolved, either # in a plan/operation or by the driver ("reboot_if_needed()") # FIXME: check for /etc/modprobe.d/raspi-blacklist.conf # mentioned at https://www.raspberrypi.org/documentation/ # hardware/raspberrypi/spi/README.md with fs.edit('/boot/config.txt', create=False) as boot: boot.insert_line('dtparam=spi=on') boot.insert_line('dtoverlay=spi-bcm2835-overlay') if boot.changed: linux.enable_module('spi_bcm2835', load=False) return Changed('Enabled SPI, need to reboot now') if linux.enable_module('spi_bcm2835').changed: return Changed('SPI kernel module enabled') return Unchanged('SPI already enabled')
def set_password(name, password=None, hashed=False, salt=None): if salt is None: salt = hashlib.sha1(os.urandom(64)).hexdigest() if not hashed: # hash using sha256 hash = crypt(password, "$6$" + salt) else: hash = password # at this point, we have a hashed password with fs.edit('/etc/shadow', create=False) as shadow: new_lines = [] for line in shadow.lines(): entry = ShadowEntry.from_line(line) if entry.name == name: # we need to check if the password already matches (with a # different salt) pwc = entry.password_encrypted need_update = True if hashed: # we were supplied a hashed password, simply compare the # hashes need_update = (pwc != password) else: # not hashed if '$' in pwc: lead = pwc[:pwc.rindex('$')] need_update = (crypt(password, lead) != pwc) if need_update: entry = entry._replace(password_encrypted=hash) new_lines.append(entry.to_line()) continue new_lines.append(line) shadow.set_lines(new_lines) if shadow.changed: return Changed(msg='Updated password for user {}'.format(name)) return Unchanged(msg='Password for {} already set'.format(name))
def enable_systemd(): changed = False changed |= apt.install_packages(['systemd']).changed with fs.edit('/boot/cmdline.txt', create=False) as e: flag = 'init=/bin/systemd' lines = e.lines() assert len(lines) == 1 if flag not in lines[0]: lines[0] += ' ' + flag e.set_lines(lines) changed |= e.changed if changed: return Changed(msg='Installed systemd') return Unchanged(msg='systemd already active')
def enable_module(module_name, load=True, modules_file="/etc/modules"): mods = info["linux.modules"] c = False # load module if not loaded if load and module_name not in mods: proc.run(["modprobe", module_name]) c = True # ensure module is found in modules_files with fs.edit(modules_file) as mf: mf.insert_line(module_name) c |= mf.changed if c: return Changed(msg="Kernel module {}, enabled in {}".format(module_name, modules_file)) return Unchanged(msg="Kernel module {} already enabled in {}".format(module_name, modules_file))
def set_unlocked_no_password(names): # FIXME: decide API guidelines, add typechecking once Python3 is available # example: passing a string to names will work, but result in non-sensical # results. with fs.edit('/etc/shadow', create=False) as shadow: new_lines = [] for line in shadow.lines(): entry = ShadowEntry.from_line(line) if entry.name in names: entry = entry._replace(password_encrypted='*') new_lines.append(entry.to_line()) else: new_lines.append(line) shadow.set_lines(new_lines) if shadow.changed: return Changed(msg='Unlocked users {}'.format(names)) return Unchanged(msg='Users {} already unlocked'.format(names))
def enable_module(module_name, load=True, modules_file='/etc/modules'): mods = info['linux.modules'] c = False # load module if not loaded if load and module_name not in mods: proc.run(['modprobe', module_name]) c = True # ensure module is found in modules_files with fs.edit(modules_file) as mf: mf.insert_line(module_name) c |= mf.changed if c: return Changed(msg='Kernel module {}, enabled in {}'.format( module_name, modules_file)) return Unchanged(msg='Kernel module {} already enabled in {}'.format( module_name, modules_file))
def set_hostname(hostname, domain=None, config_only=False): prev_hostname = info_hostname() changed = False changed |= fs.upload_string('{}\n'.format(hostname), '/etc/hostname').changed if not config_only and prev_hostname != hostname: proc.run(['hostname', hostname]) changed = True # update /etc/hosts # this will also set the domain name # see http://jblevins.org/log/hostname # # we adopt the following convention: host_line = '127.0.1.1\t' + hostname if domain: host_line = '127.0.1.1\t{}.{}\t{}'.format(hostname, domain, hostname) with fs.edit('/etc/hosts') as hosts: if host_line not in hosts.lines(): hosts.comment_out(r'^127.0.1.1') # comment out old lines lines = [host_line] + hosts.lines() hosts.set_lines(lines) changed |= hosts.changed if changed: info_hostname.invalidate_cache() info_fqdn.invalidate_cache() return Changed(msg='Hostname changed from {} to {}'.format( prev_hostname, hostname)) return Unchanged(msg='Hostname already set to {}'.format(hostname))