Commit 668184b0 authored by Nigel Kukard's avatar Nigel Kukard
Browse files

Added preseed support

parent d7b32f4f
......@@ -17,16 +17,20 @@
import argparse
from idmslinux_installer.ili import Ili
from idmslinux_installer.ili import Ili, __version__
def main():
"""Entry point for execution from the commandline."""
print('IDMS Linux Installer v{ili.__version__} - Copyright © 2019, AllWorldIT.\n')
print(f'IDMS Linux Installer v{__version__} - Copyright © 2019, AllWorldIT.\n')
# Start argument parser
argparser = argparse.ArgumentParser(add_help=False)
# Create argument group for installer options
installer_group = argparser.add_argument_group('Installer options')
installer_group.add_argument('--preseed-uri', dest='preseed_uri', action='store',
help='Load installer preseed config from URI')
# Create argument group for optionals
optional_group = argparser.add_argument_group('Optional arguments')
optional_group.add_argument('-h', '--help', action="help", help="Show this help message and exit")
......@@ -34,8 +38,15 @@ def main():
# Parse args
args = argparser.parse_args()
# Args to pass to installer
kwargs = {}
if args.preseed_uri:
kwargs['preseed_uri'] = args.preseed_uri
# Fire up the installer
installer = Ili()
installer.start()
installer.start(**kwargs)
if __name__ == '__main__':
......
......@@ -15,10 +15,13 @@
"""Guts of the IDMS Linux Installer."""
import json
import locale
import re
from typing import Optional
from configparser import ConfigParser
from typing import Any, Optional
import requests
from dialog import Dialog # type: ignore
from idmslinux_installer.ilistate import IliState
......@@ -37,6 +40,9 @@ class Ili:
# The main dialog handle
dialog: Dialog
# This is our preseed config if we have one
preseed: ConfigParser
# This is the state of the installation
state: IliState
......@@ -52,8 +58,8 @@ class Ili:
# Load plugins
self.plugins = PluginCollection('idmslinux_installer.plugins')
# Load the system block devices
self.block_devices = BlockDevices()
# Initialize the config parser to None
self.preseed = None
# Initialize the install state
self.state = IliState()
......@@ -63,15 +69,22 @@ class Ili:
# Fire up Dialog
self.dialog = Dialog(dialog='dialog', autowidgetsize=True)
self.dialog.set_background_title('IDMS Linux Installer')
self.dialog.set_background_title(f'IDMS Linux Installer v{__version__}')
# Set output callback
self.state.output_callback = self._status_callback
def start(self):
"""Testing during development."""
def start(self, preseed_uri: Optional[str] = None):
"""Start the installer."""
# Load preseed URI if it was provided
if preseed_uri:
self._status_callback('Downloading preseed "{preseed_uri}"...')
self._load_preseed(preseed_uri)
if not self.state.install_disks:
# Load the system block devices
self.block_devices = BlockDevices()
self._get_install_disks()
if not self.state.diskusage_strategy:
......@@ -98,10 +111,116 @@ class Ili:
self.plugins.install_packages(self.state)
self.plugins.post_install(self.state)
print(f"DEBUG: {self.state}")
# self.dialog.gauge_stop()
# C901 - Ignore warning about code complexity
# R0912 - Ignore warning that we have about the number of branches
# R0915 - Ignore warning about number of statements
# pylama:ignore=C901,R0912,R0915
def _load_preseed(self, preseed_uri: str):
"""Load installer configuration from preseed file."""
# Parse config
self.preseed = ConfigParser()
# HTTP
if re.match('^https?://', preseed_uri):
try:
# Grab HTTP resource
resource = requests.get(preseed_uri, headers={'User-Agent': f'Ili/{__version__}'})
config_data = resource.text
except requests.exceptions.RequestException as exception:
self._critical_error('Error loading preseed', str(exception))
# File
elif re.match('^/', preseed_uri):
try:
# Read config file
with open(preseed_uri, 'r') as config_file:
config_data = config_file.read()
except OSError as exception:
self._critical_error('Error loading preseed', str(exception))
else:
self._critical_error('Error with preseed URI', f'Preseed URI type is not supported:\n{preseed_uri}')
# Read config as string
self.preseed.read_string(config_data)
sects = self.preseed.sections()
print(f'SECTIONS: {sects}')
# Process storage section
if self.preseed.has_section('storage'):
# Process install disks
if self.preseed.has_option('storage', 'install_disks'):
self._status_callback('preseed storage -> install_disks')
self.state.add_install_disks(self._preseed_read_json('storage', 'install_disks'))
# Process diskusage strategy
if self.preseed.has_option('storage', 'diskusage_strategy'):
self._status_callback('preseed storage -> diskusage_strategy')
self.state.diskusage_strategy = self.preseed.get('storage', 'diskusage_strategy').upper()
# Process disklayout strategy
if self.preseed.has_option('storage', 'disklayout_strategy'):
self._status_callback('preseed storage -> disklayout_strategy')
self.state.disklayout_strategy = self.preseed.get('storage', 'disklayout_strategy').upper()
# Process system section
if self.preseed.has_section('system'):
# Process hostname
if self.preseed.has_option('system', 'hostname'):
self._status_callback('preseed system -> hostname')
self.state.hostname = self.preseed.get('system', 'hostname')
# Process locale
if self.preseed.has_option('system', 'locale'):
self._status_callback('preseed system -> locale')
self.state.hostname = self.preseed.get('system', 'locale')
# Process timezone
if self.preseed.has_option('system', 'timezone'):
self._status_callback('preseed system -> timezone')
self.state.hostname = self.preseed.get('system', 'timezone')
# Process install_microcode
if self.preseed.has_option('system', 'install_microcode'):
self._status_callback('preseed system -> install_microcode')
self.state.hostname = self.preseed.getboolean('system', 'install_microcode')
# Process repository section
if self.preseed.has_section('repository'):
# Process mirrorlist
if self.preseed.has_option('repository', 'mirrorlist'):
self._status_callback('preseed repository -> mirrorlist')
self.state.mirrorlist = self._preseed_read_json('repository', 'mirrorlist')
# Process packages
if self.preseed.has_option('repository', 'packages'):
self._status_callback('preseed repository -> packages')
self.state.mirrorlist = self._preseed_read_json('repository', 'mirrorlist')
# Process users section
if self.preseed.has_section('users'):
# Process root_password
if self.preseed.has_option('users', 'root_password'):
self._status_callback('preseed users -> root_password')
self.state.root_password = self.preseed.get('users', 'root_password')
# Process user_username
if self.preseed.has_option('users', 'user_username'):
self._status_callback('preseed users -> user_username')
self.state.user_username = self.preseed.get('users', 'user_username')
# Process user_password
if self.preseed.has_option('users', 'user_password'):
self._status_callback('preseed users -> user_password')
self.state.user_password = self.preseed.get('users', 'user_password')
# Process user_sshkeys
if self.preseed.has_option('users', 'user_sshkeys'):
self._status_callback('preseed users -> user_sshkeys')
self.state.user_sshkeys = self._preseed_read_json('users', 'user_sshkeys')
# Process services section
if self.preseed.has_section('services'):
# Process enable_services
if self.preseed.has_option('services', 'enable_services'):
self._status_callback('preseed services -> enable_services')
self.state.mirrorlist = json.loads(self.preseed.get('services', 'enable_services'))
def _get_install_disks(self):
"""Get the user to choose the disks to install on."""
......
......@@ -38,7 +38,7 @@ class IliState:
_diskusage_strategy: Optional[str]
_disklayout_strategy: Optional[str]
# Chosen hostname
_hostname: str
_hostname: Optional[str]
# Chosen locale
_locale: str
# Chosen timezone
......@@ -105,7 +105,7 @@ class IliState:
self._install_disks = []
self._diskusage_strategy = None
self._disklayout_strategy = None
self._hostname = 'idms-linux-rolling.local'
self._hostname = None
self._locale = 'en_US.UTF-8'
self._timezone = 'UTC'
self._mirrorlist = None
......@@ -317,6 +317,11 @@ class IliState:
"""Return the user_sshkeys."""
return self._user_sshkeys
@user_sshkeys.setter
def user_sshkeys(self, value: List[str]):
"""Set the user_sshkeys."""
self._user_sshkeys = value
# Users
def add_enable_service(self, service: str):
"""Add a service to enable."""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment