archi - набор скриптов для установки Arch linux

Приветствую единомышленников.

Хочу рассказать о своём проекте. archi - live-iso с графическим инсталлятором Arch linux.

Условно проект можно разделить на две части:
- Профиль к archiso для создания образа iso.
- archi.py - скрипт на python для установки.

На образе установлен графический режим по умолчанию(xfce4).
За основу взят профиль для официального образа.
Несколько дополнительный приложений включенных в образ:
- AdGuardHome - локальный DNS сервер с настроенными правилами фильтрации.
- Ассистент - удалённый помощник.
archi.py для графического интерфейса используется библиотека TK.
Есть пару страничек документации в WiKi.

ссылка репозитория на гитхаб - https://github.com/ksandronline/archi

p.s. После того как я написал ядро скрипта, нашёл много давно написанных решений.
Но тем не менее мне всё равно приятно иметь под рукой свой дистрибутив со своими настройками.

И немного картинок:
1
https://raw.githubusercontent.com/ksandronline/archi/main/screenshots/screen-1.png

2
https://raw.githubusercontent.com/ksandronline/archi/main/screenshots/screen-2.png

3
https://raw.githubusercontent.com/ksandronline/archi/main/screenshots/screen-3.png

4
https://raw.githubusercontent.com/ksandronline/archi/main/screenshots/screen-4.png
ksandr, это всё хорошо, но не универсально.
Вот если бы был выбор, между разными DE для установки и выбора какие драйвера на видео ставить.
ksandr
И немного картинок:
Картинки удалил, оставил только ссылки.
Хотите показать картинки - используйте превьюшки, а не полноразмерные изображения.
Очень не хватает, описания системы которая получится в результате: какая разметка диска, DE, файловая система. Также ограничения по использованию - если у меня, например, два диска или мне нужен дуалбут - как это сработает?..
Более подробнее описание профиля.

В официальный профиль Arch linux добавлены некоторые приложения и настройки.
Доп. приложения на диске.
- Xorg + XFCE4
- Браузеры Firefox и Chromium.
- Фильтрующий DNS-сервер AdGuardHome.
- Редактор Sublime 4.
- Антивирусы Clamav + rkhunter.
- Средство помощник для удалённого администрирования "Ассистент".
- KDEconnect - для передачи файлов между смартфонами и компьютером.
- Список не полный есть ещё много повседневных программок.

Настройки по умолчанию:
Настроена локализация на русский язык, согласно официальной документации.
Для настройки сети включён по умолчанию Network Manager и настроен на динамическое получение ИП-адресов.
В качестве DNS сервера указан локальный хост. (Рекомендации по этому вопросу есть на рабочем столе системы.)
Включён tigervnc.
Включён sshd.
Включён Avahi. ()

Что убрано/отключено:
#reflector - Причины две: 1. Субъективная(НЕ нравиться). 2. Прописаны Российские зеркала по умолчанию.
#linux-atm - Что это такое?(Кому надо тот включит.)
#grml-zsh-config - настроена своя тема zsh.

.
Более подробнее описание скрипта установки.

Скрипт разбит на несколько секций.
В первом разделе содержаться переменный с параметрами для настройки.
Во втором необходимые функции и самой первой arch_install()
Также есть раздел с функциями для GUI.

Настройки по умолчанию я старался подбирать из расчёта на "новичков", подробнее:

Разбиение диска - на данный момент есть два варианта:
использовать весь диск.
использовать существующий раздел диска.

При первом выборе.
По умолчанию форматирование производиться в btrfs.
диск разбивается на разделы: SWAP = ОЗУ
и всё остальное отдаётся под корневую систему.

При выборе установки на существующий раздел.
Раздел не форматируется. Раздел просто монтируется и скрипт пытается установить на него систему.
При необходимости ручного разбиения диска, рекомендуется сначала использовать Gparted.
В интерфейсе есть кнопка для его запуска и ссылка на официальную документацию на русском языке.

Переменная со списком устанавливаемых пакетов находится в самом начале скрипта, не заметить - не возможно.
Возможности выбирать пакеты из интерфейса нет.(пока)
Все пакеты устанавливаются из официальных репозиториев, кроме последней группы. Она устанавливается из специально созданного репозитория archi, они специально собраны в одном месте для удобства их редактировать.

Установка Grub - есть три варианта: BIOS, UEFI, None. (None - не устанавливать.)

Некоторые "особенные" настройки:
Включён по умолчанию: lightdm, и tigervnc. Настройки tigervnc взяты с официальной документации.(Можно подключиться к экрану выбора пользователей.)
Включён и настроен AdGuardHome, файл настроек тот же что и на live-iso.
Включён настроен Avahi. ()
Установлен pamac. Из пакета из доп. репозитория archi.

Конфигурационный файл pacman.conf в готовой системы используется стандартный установленный pacman`ом по умолчанию.
Конфигурационный файл pacman.conf для установки системы используется /root/pacman.conf(отличается включенным репозиторием archi)

GUI будет заменён. Сейчас используется библиотека TK будет скорее всего Qt.
Принцип работы GUI.
После нажатия кнопки установить, запускается процесс установки параллельным потоком. Высь вывод этого процесса записывается в лог-файл.
В интерфейс обычным tail выводиться содержимое этого лог-файла.
Самое важное!
Различия между профилем и скриптом для установки.
Профиль создаётся для создания iso в качестве rescue диска. Тоесть в нём будет много коммуникационным программок и утилит.

Скрипт для установки, устанавливает систему Arch linux с наименьшим необходимым, но достаточным списком пакетов.

Списки пакетов и настройки, используемые в профиле и скрипте могут(Так оно и есть) отличаться.

Основная задача: Создание удобной простой и интуитивно понятной системы, для создания собственного образа iso и скрипта для основной установки системы + пользовательские добавления.

И вместо картинок несколько кусочков листинга скрипта установки:


def install_arch():
    prepare_disk()                          # Подготовка диска
    _run(pacstrap + [root_mount_path] + base_sys)    # Установка базовой системы
    basic_configure()                               # Конфигурирование базовой системы

    # Берём конфиг с iso для установки
    _run(["cp", "-v", "/etc/pacman.conf", root_mount_path + "/root/pacman.conf"])
    # Копируем настройки пользователя по умолчанию
    _run(["cp", "-aT", "/etc/skel/", root_mount_path + "/etc/skel/"])

    args = ["useradd", "--create-home", "--password", cryptPassword(user_pass,"md5"), add_user]    # Добавляем пользователя
    _run(chroot + args)
    _run(chroot + ["chmod", "+x", "-v", "/home/"+ add_user +"/Desktop/*.desktop"])

    args = ["usermod", "--password", cryptPassword(root_pass,"md5"), "root"]    # Меняем пароль для Root`а
    _run(chroot + args)
    _run(["cp", "-v", "/etc/skel/.zshrc", root_mount_path + "/root/.zshrc"])
    fr_st_base_sys.configure(background=color3) # Первый пункт выполнен

    # Ядро
    if kernel_var.get() == 1:   linux = linux_std
    elif kernel_var.get() == 2: linux = linux_lts
    elif kernel_var.get() == 3: linux = linux_zen
    _run(["cp", "-v", "/etc/default/grub", root_mount_path + "/etc/default/grub"])
    _run(chroot + pacman + kernel + linux)  # Установка ядра и загрузчика
    _run(["mkdir", "-v", root_mount_path + "/boot/grub", root_mount_path + "/boot/grub/themes"])
    _run(["cp", "-aT", "/root/grub/themes/", root_mount_path + "/boot/grub/themes/"])

    # Загрузчик
    if grub_var.get() == 1:
        while _run(chroot + ["grub-install", "/dev/"+use_disk.get()]) > 0:  # BIOS
            time.sleep(1)
        time.sleep(1)
    elif grub_var.get() == 2:
        while _run(chroot + ["grub-install"]) > 0:  # UEFI
            time.sleep(1)
        time.sleep(1)
    elif grub_var.get() == 3:
        _show("Загрузчик не установлен.")

    grub_mkconfig = ["grub-mkconfig", "-o", "/boot/grub/grub.cfg"]
    while _run(chroot + grub_mkconfig) > 0:
        time.sleep(1)
    time.sleep(1)

    fr_st_kernel.configure(background=color3)   # Второй пункт выполен

# Xorg
    _run(chroot + pacman + xorg)

    _write([lightdm_conf],               root_mount_path + "/etc/lightdm/lightdm.conf")
    _write([lightdm_gtk_greeter_conf],   root_mount_path + "/etc/lightdm/lightdm-gtk-greeter.conf")

    _write([xvnc_service],   root_mount_path + "/etc/systemd/system/[email protected]")
    _write([xvnc_socket],    root_mount_path + "/etc/systemd/system/xvnc.socket")

    _run(chroot + ["systemctl", "enable", "lightdm.service"])
    fr_st_xorg.configure(background=color3)     # Третий пункт

# xfce4
    _run(chroot + pacman + xfce4)

    for dev in net_devs:        # Сетевые интерфейсы
        if net_devs[dev]["tk_var_DHCP"].get() == 1:
            wired_network = """# DHCP
[connection]
id=LAN
uuid=28ffe244-9a09-3c28-8bea-4ce030028109
type=ethernet
interface-name={dev}
permissions=

[ethernet]
mac-address-blacklist=

[ipv4]
dns=127.0.0.1;
dns-search={domain}
ignore-auto-dns=true
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

[proxy]
""".format(dev=dev, domain=domain)
            _write([wired_network],root_mount_path + "/etc/NetworkManager/system-connections/LAN.nmconnection")
        else:
            wired_network = """# Статический ip-адрес
[connection]
id=LAN
uuid=28ffe244-9a09-3c28-8bea-4ce030028109
type=ethernet
interface-name={dev}
permissions=

[ethernet]
mac-address-blacklist=

[ipv4]
address1={ip},{gw}
dns={dns};
dns-search={domain}
ignore-auto-dns=true
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

[proxy]
""".format(dev=dev, ip=net_devs[dev]["ent_ip"].get(), gw=net_devs[dev]["ent_gw"].get(), dns=net_devs[dev]["ent_dns"].get(), domain=domain)
            _write([wired_network],root_mount_path + "/etc/NetworkManager/system-connections/LAN.nmconnection")

    _run(chroot + ["chmod", "-v", "600", "/etc/NetworkManager/system-connections/LAN.nmconnection"])
    if net_manager_default == "networkmanager":
        _run(chroot + ["systemctl", "enable", "NetworkManager.service"])
    fr_st_xfce4.configure(background=color3)

# Дополнения
    _run(chroot + pacman + utils)
    usermod = ["usermod", "--shell", "/bin/zsh", "root"]    # Меняем шелл для Root`а
    _run(chroot + usermod)
    usermod = ["usermod", "--shell", "/bin/zsh", add_user]    # Меняем шелл для юзера.
    _run(chroot + usermod)
    _run(chroot + ["ln", "-svf", "/usr/share/doc/arch-wiki/html/ru", "/home/"+ add_user +"/Desktop/Оффициальное WiKi локальная версия"])
    _write([add_user, "ALL=(ALL)", "ALL"], root_mount_path + "/etc/sudoers.d/archi")  # Разрешаем юзеру sudo

    _write([nsswitch_conf], root_mount_path + "/etc/nsswitch.conf")      # Настраиваем Avahi
    _write([avahi_vnc_service], root_mount_path + "/etc/avahi/services/vnc.service")
    _write([avahi_ssh_service], root_mount_path + "/etc/avahi/services/ssh.service")
    _run(chroot + ["systemctl", "enable", "avahi-daemon.service"])
    _run(chroot + ["systemctl", "enable", "xvnc.socket"])

    _run(chroot + ["systemctl", "enable", "sshd.service"])       # Запускаем SSH сервер

    _write_end([default_pa], root_mount_path + "/etc/pulse/default.pa")      # Настраиваем звук по сети.
    fr_st_utils.configure(background=color3)

# Pamac
    _run(chroot + pacman + pamac_aur)
    _write([pamac_conf],root_mount_path + "/etc/pamac.conf")
    fr_st_pamac.configure(background=color3)

    _show("Пока из aur пакеты не собираются.")
    #_run(chroot + pamac + utils_aur)
    if TRUE:
        fr_st_utils_aur.configure(background="RED")
    else:
        fr_st_utils_aur.configure(background=color3)

# Шрифты
    _run(chroot + pacman + fonts)
    fr_st_fonts.configure(background=color3)

    _run(chroot + pacman + brows)
    fr_st_brows.configure(background=color3)

# Бонусы
    _run(chroot + pacman + custom)
    _run(["cp", "-v", "/var/lib/adguardhome/AdGuardHome.yaml", root_mount_path + "/var/lib/adguardhome/AdGuardHome.yaml"])
    _run(["mkdir", "-v", root_mount_path + "/etc/systemd/resolved.conf.d"])
    _run(["cp", "-v", "/etc/systemd/resolved.conf.d/adguardhome.conf", root_mount_path + "/etc/systemd/resolved.conf.d/adguardhome.conf"])
    _run(chroot + ["/var/lib/adguardhome/AdGuardHome", "-v", "--service", "install"])

    fr_st_custom.configure(background=color3)

    _run(["cp", "-v", log_install, root_mount_path + "/root/install.log"])
    _run(["umount", root_mount_path])
    time.sleep(1)

    _show("Установка Arch linux завершена.")
    _show("Лог-файл установки скопирован в /root/install.log")



def prepare_disk():
    # Если BIOS: отступаем 1 Мб от начала диска, создаём swap = ОЗУ, на всём оставшемся создаём раздел для корневой системы.
    # Если UEFI: создаём FAT раздел на 512 Мб, создаём swap = ОЗУ, на всём оставшемся создаём раздел для корневой системы.
    if use_disk_or_partition.get() == 1:    # Использовать весь диск
        if use_disk.get():
            parted = ["parted", "--script", "/dev/"+use_disk.get()]
            mem_bytes = os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')
            mem_gib = mem_bytes/(1024.**3)
            mem_str = str(round(mem_gib))
            if grub_var.get() == 1:         # BIOS
                _run(parted + ["mklabel", "msdos"])
                _run(parted + ["mkpart", "primary", "linux-swap", "1MiB", mem_str+"GiB"])
                _run(parted + ["mkpart", "primary", "btrfs", mem_str+"GiB", "100%"])

                _run(["mkswap", "/dev/"+use_disk.get()+"1"])
                mkfs_command = ["mkfs.btrfs", "-f"]
                root_partition = ["/dev/"+use_disk.get()+"2"]
                _run(mkfs_command + root_partition)

                _run(["swapon", "/dev/"+use_disk.get()+"1"])
                _run(["mount", "/dev/"+use_disk.get()+"2", root_mount_path])
            elif grub_var.get() == 2:       # UEFI
                _run(parted + ["mklabel", "gpt"])
                _run(parted + ["mkpart", "primary", "fat32", "1MiB", "512MiB"])
                _run(parted + ["name", "1", "EFI"])
                _run(parted + ["set", "1", "esp", "on"])
                _run(parted + ["set", "1", "boot", "on"])
                _run(parted + ["mkpart", "primary", "linux-swap", "512MiB", mem_str+"GiB"])  # TODO Добавить к swap "512MiB"
                _run(parted + ["mkpart", "primary", "btrfs", mem_str+"GiB", "100%"])

                mkfs_command = ["mkfs.fat", "-F", "32"]
                uefi_partition = ["/dev/"+use_disk.get()+"1"]
                _run(mkfs_command + uefi_partition)
                uefi_mount = ["mount", "/dev/"+use_disk.get()+"1", root_mount_path+"/boot/efi"]
                _run(uefi_mount)

                _run(["mkswap", "/dev/"+use_disk.get()+"2"])
                mkfs_command = ["mkfs.btrfs", "-f"]
                root_partition = ["/dev/"+use_disk.get()+"3"]
                _run(mkfs_command + root_partition)

                _run(["swapon", "/dev/"+use_disk.get()+"2"])
                _run(["mount", "/dev/"+use_disk.get()+"3", root_mount_path])
            elif grub_var.get() == 3:       # None
                _run(parted + ["mklabel", "msdos"])
                _run(parted + ["mkpart", "primary", "linux-swap", "1MiB", mem_str+"GiB"])
                _run(parted + ["mkpart", "primary", "btrfs", mem_str+"GiB", "100%"])

                _run(["mkswap", "/dev/"+use_disk.get()+"1"])
                mkfs_command = ["mkfs.btrfs", "-f"]
                root_partition = ["/dev/"+use_disk.get()+"2"]
                _run(mkfs_command + root_partition)

                _run(["swapon", "/dev/"+use_disk.get()+"1"])
                _run(["mount", "/dev/"+use_disk.get()+"2", root_mount_path])
        else:
            _show("Необходимо выбрать диск.")
    elif use_disk_or_partition.get() == 2:  # Использовать выбранный раздел.
        if select_partition.get():
            mkfs_command = ["mkfs.btrfs", "-f", select_partition.get()]
            _run(["mkfs.btrfs", "-f", select_partition.get()])
            _run(["mount", select_partition.get(), root_mount_path])
        else:
            _show("Необходимо выбрать раздел.")


def basic_configure():
    # fstab
    _show("Генерируем файл /etc/fstab")
    genfstab_command = ["genfstab", "-U", root_mount_path]
    while _run(genfstab_command) > 0:
        time.sleep(1)
    time.sleep(1)
    fstab = root_mount_path + "/etc/fstab"
    with open(fstab, "w") as file:
        Popen(genfstab_command, stdout=file, encoding='utf-8', text=True).wait()

    # Locale
    locale_gen = """
ru_RU.UTF-8 UTF-8
en_US.UTF-8 UTF-8
    """
    _write([locale_gen],root_mount_path + "/etc/locale.gen")
    while _run(chroot + ["locale-gen"]) > 0:
        time.sleep(1)
    time.sleep(1)
    _write(["LANG=ru_RU.UTF-8"],root_mount_path + "/etc/locale.conf")
    vconsole_conf = """
KEYMAP=ru
FONT=cyr-sun16
    """
    _write([vconsole_conf],root_mount_path + "/etc/vconsole.conf")

    # Net
    hostname = entry_hostname.get()
    _write([hostname],root_mount_path + "/etc/hostname")

    hosts = """
127.0.0.1   localhost
127.0.0.1   {hostname}.local {hostname}
    """.format(hostname=hostname)    # TODO Поменять ip
    _write([hosts],root_mount_path + "/etc/hosts")

    for dev in net_devs:        # Сетевые интерфейсы
        if net_devs[dev]["tk_var_DHCP"].get() == 1:
            wired_network = """# DHCP
[Match]
Name={dev}

[Network]
DHCP=yes
""".format(dev=dev)
            _write([wired_network],root_mount_path + "/etc/systemd/network/20-wired.network")
        else:
            wired_network = """# Статический ip-адрес
[Match]
Name={dev}

[Network]
Address={ip}
Gateway={gw}
DNS={dns}
""".format(dev=dev, ip=net_devs[dev]["ent_ip"].get(), gw=net_devs[dev]["ent_gw"].get(), dns=net_devs[dev]["ent_dns"].get())
            _write([wired_network],root_mount_path + "/etc/systemd/network/20-wired.network")

    if net_manager_default == "systemd":
        _run(chroot + ["systemctl", "enable", "systemd-networkd"])
    _run(chroot + ["systemctl", "enable", "systemd-resolved"])

    resolv_conf = """
nameserver 127.0.0.1
domain {domain}
    """.format(domain=domain)
    _write([resolv_conf],root_mount_path + "/etc/resolv.conf")

    # Time
    _run(chroot + ["ln", "-sfv", "/usr/share/zoneinfo/"+ array_tz[combo_tz.get()][1], "/etc/localtime"])
    _run(chroot + ["hwclock", "--systohc"])
    _show("Часовой пояс: "+ combo_tz.get()+ " "+ array_tz[combo_tz.get()][0])

p.s. to Admin/Moderator: Я очень редко пишу на форумах. На указанные мне ошибки буду обращать внимание и делать исправления.
ksandr
Средство помощник для удалённого администрирования "Ассистент".
vadik, товарища надо забанить для профилактики.
Ошибки в тексте-неповторимый стиль автора©
indeviral, что не так (я действительно не в курсе)?
vadik
что не так
По умолчанию вроде ставится удаленный доступ, с какими конфигами не смотрел.
Зачем это все? Если трудно установить, используй манджару, там все уже реализовано.
vadik
что не так
ну эта проприетарная шляпа которая постоянно ломится на внешку(TeamViewer и т.п.)
может афтор конечно ничего плохого и не хочет... но желание добавить малоизвестные софт с таким функционалом, немножко настораживает.
тем более устанавливается это чудо из репозитория афтора.
Ошибки в тексте-неповторимый стиль автора©
 
Зарегистрироваться или войдите чтобы оставить сообщение.