Skip to content

Commit

Permalink
lang: core: embedded: Add standalone provisioning tool
Browse files Browse the repository at this point in the history
This commit adds the ability to build a standalone provisioning tool.
This is the first useful public mcl code base as well. It is not
perfect, but does serve as a rough starting point to show what is
possible. In the future as the language and the engine evolve, this will
likely get more elegant, and also grow new features.

To build this, run `make clean && GOTAGS='embedded_provisioner' make`.
To run this, run `mgmt provisioner`.
  • Loading branch information
purpleidea committed Mar 27, 2024
1 parent 375fe19 commit 4d9c780
Show file tree
Hide file tree
Showing 8 changed files with 1,436 additions and 0 deletions.
37 changes: 37 additions & 0 deletions lang/core/embedded/provisioner.go
@@ -0,0 +1,37 @@
// Mgmt
// Copyright (C) 2013-2024+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// Additional permission under GNU GPL version 3 section 7
//
// If you modify this program, or any covered work, by linking or combining it
// with embedded mcl code and modules (and that the embedded mcl code and
// modules which link with this program, contain a copy of their source code in
// the authoritative form) containing parts covered by the terms of any other
// license, the licensors of this program grant you additional permission to
// convey the resulting work. Furthermore, the licensors of this program grant
// the original author, James Shubin, additional permission to update this
// additional permission if he deems it necessary to achieve the goals of this
// additional permission.

//go:build embedded_provisioner

package coreembedded

import (
// import so it registers
_ "github.com/purpleidea/mgmt/lang/core/embedded/provisioner"
)
18 changes: 18 additions & 0 deletions lang/core/embedded/provisioner/files/bios-menu.tmpl
@@ -0,0 +1,18 @@
default vesamenu.c32
prompt 1
timeout 150

label kickstart
menu label ^Install {{ .distro }} {{ .version }} {{ .arch }} ( kickstart )
menu default
kernel {{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz
append initrd={{ .distro }}{{ .version }}-{{ .arch }}/initrd.img inst.stage2={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/ ip=dhcp inst.ks={{ .ks }}

label manual
menu label ^Install {{ .distro }} {{ .version }} {{ .arch }} ( manual )
kernel {{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz
append initrd={{ .distro }}{{ .version }}-{{ .arch }}/initrd.img inst.stage2={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/ ip=dhcp

label local
menu label Boot from ^local drive
localboot 0xffff
186 changes: 186 additions & 0 deletions lang/core/embedded/provisioner/files/kickstart.ks.tmpl
@@ -0,0 +1,186 @@
{{ if .comment -}}
#
# {{ .comment }}
#
{{- end }}
#
# readme
#
# All of this is based on reading docs, experimentation, and the kickstarts repo
# at: https://pagure.io/fedora-kickstarts which I am not an expert at reading.
# If you have recommendations for improvements, please let us know! Thanks.
#
# flavour: {{ .flavour }}
# part: {{ .part }}
# bios: {{ .bios }}

#
# system
#
text # text based install (not graphical)
{{ if .lang -}}
{{- $length_minus1 := math_minus1 (len .lang | printf "%d" | golang_strconv_atoi ) -}}
lang {{ index .lang 0 }}
{{- if gt (len .lang) 1 }} --addsupport=
{{- range $i, $x := .lang -}}
{{ if eq $i 0 }}{{ continue }}{{ end }}
{{- $x -}}
{{- if lt $i $length_minus1 -}},{{- end -}}
{{- end -}}
{{- end -}}
{{- end }}
keyboard us
{{ if .timezone -}}
# System timezone
timezone {{ .timezone }} --isUtc
{{- if .ntp_servers }} --ntpservers={{ golang_strings_join .ntp_servers "," }}{{ end -}}
{{- end }}

#
# security
#
{{ if .password -}}
# password can be crypted with:
# python3 -c 'import crypt; print(crypt.crypt("password", crypt.mksalt(crypt.METHOD_SHA512)))'
# or
# openssl passwd -6 -salt <YOUR_SALT> (salt can be omitted to generate one)
rootpw --iscrypted --allow-ssh {{ .password }}
{{ else }}
rootpw --iscrypted --lock
{{- end }}
selinux --enforcing
services --enabled=sshd,NetworkManager,chronyd
{{ if .sshkeys -}}
# TODO: sort in a deterministic order
{{ range $user, $pubkey := .sshkeys -}}
sshkey --username {{ $user }} "{{ $pubkey }}"
{{- end -}}
{{- end }}

#
# networking
#
# --device=link
# specifies the first interface with its link in the up state
# --activate
# any matching devices beyond the first will also be activated
#
network --bootproto=dhcp --device=link --activate

firewall --enabled --service=mdns

#
# partitioning
#
# TODO: add more magic partitioning schemes
zerombr
clearpart --all --initlabel --disklabel={{ if .bios }}msdos{{ else }}gpt{{ end }}
{{ if eq .part "btrfs" -}}
autopart --type=btrfs --noswap
{{- else if eq .part "plain" -}}
autopart --type=plain
{{- else -}}
autopart --type=plain
{{- end }}

#
# repositories
#
{{ if .url -}}
url --url="{{ .url }}"
{{- end }}

{{ if .repos -}}
# TODO: sort in a deterministic order
{{- range $name, $baseurl := .repos }}
repo --name="{{ $name }}" --baseurl="{{ $baseurl }}"
{{- end }}
{{- end }}

#
# packages
#
%packages
@core
@standard
@hardware-support
{{ if eq .flavour "Workstation" -}}
# Packages for Workstation:
-initial-setup
-initial-setup-gui
gnome-initial-setup
#anaconda-webui
@base-x
@fonts
@input-methods
@multimedia
@printing
-@guest-desktop-agents
#initial-setup-gui
glibc-all-langpacks
-@dial-up
-@input-methods
-@standard
# Install workstation-product-environment to resolve RhBug:1891500
@^workstation-product-environment
# Exclude unwanted packages from @anaconda-tools group
-gfs2-utils
-reiserfs-utils
{{- else if eq .flavour "Server" -}}
# Packages for Server:
fedora-release-server
# install the default groups for the server environment since installing the environment is not working
@server-product
@headless-management
@networkmanager-submodules
@container-management
@domain-client
@guest-agents
@server-hardware-support
-initial-setup-gui
-generic-release*
{{- end }}
# User packages:
{{ range $i, $x := .packages -}}
{{ $x }}
{{ end -}}
%end

#
# misc
#
bootloader --timeout=1

# make sure that initial-setup runs and lets us do all the configuration bits
firstboot --reconfig

#
# flavour
#
{{ if eq .flavour "Workstation" -}}
%post
# Explicitly set graphical.target as default as this is how initial-setup detects which version to run
systemctl set-default graphical.target
%end
{{ else if eq .flavour "Server" -}}
%post
# setup systemd to boot to the right runlevel
echo -n "Setting default runlevel to multiuser text mode"
systemctl set-default multi-user.target
echo .
%end
{{ end -}}

#
# post
#
%post
{{ range $i, $x := .post -}}
{{ $x }}
{{ end -}}
%end

#
# reboot after installation
#
reboot
23 changes: 23 additions & 0 deletions lang/core/embedded/provisioner/files/uefi-menu.tmpl
@@ -0,0 +1,23 @@
function load_video {
insmod efi_gop
insmod efi_uga
insmod video_bochs
insmod video_cirrus
insmod all_video
}

load_video
set gfxpayload=keep
insmod gzio
set default=0
set timeout=15

menuentry 'Install {{ .distro }} {{ .version }} {{ .arch }} ( kickstart )' --class fedora --class gnu-linux --class gnu --class os {
linuxefi /{{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz ip=dhcp inst.repo={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/ inst.ks={{ .ks }}
initrdefi /{{ .distro }}{{ .version }}-{{ .arch }}/initrd.img
}

menuentry 'Install {{ .distro }} {{ .version }} {{ .arch }} ( manual )' --class fedora --class gnu-linux --class gnu --class os {
linuxefi /{{ .distro }}{{ .version }}-{{ .arch }}/vmlinuz ip=dhcp inst.repo={{ .inst_repo_base }}releases/{{ .version }}/{{ .flavour }}/{{ .arch }}/os/
initrdefi /{{ .distro }}{{ .version }}-{{ .arch }}/initrd.img
}

0 comments on commit 4d9c780

Please sign in to comment.