Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install mode (backport #457) #529

Merged
merged 7 commits into from
Jul 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@ ENV ARCH $DAPPER_HOST_ARCH

# mtools and dosfstools are requirements for luet-makeiso >= 0.4.0 to build hybrid ISO.
RUN zypper -n rm container-suseconnect && \
zypper -n install go1.18 git curl docker gzip tar wget zstd squashfs xorriso awk jq mtools dosfstools rsync
zypper -n install go1.18 git curl docker gzip tar wget zstd squashfs xorriso awk jq mtools dosfstools unzip rsync
RUN curl -sfL https://github.com/mikefarah/yq/releases/download/v4.21.1/yq_linux_${ARCH} -o /usr/bin/yq && chmod +x /usr/bin/yq
RUN if [ "${ARCH}" == "amd64" ]; then \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.49.0; \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.49.0; \
fi

RUN zypper addrepo http://download.opensuse.org/distribution/leap/15.4/repo/oss/ oss && \
zypper --gpg-auto-import-keys refresh && \
zypper in -y qemu-x86 qemu-tools

# set up helm
ENV HELM_VERSION v3.3.1
ENV HELM_URL=https://get.helm.sh/helm-${HELM_VERSION}-linux-${ARCH}.tar.gz
Expand All @@ -35,11 +40,11 @@ COPY --from=luet /usr/bin/luet /usr/bin/luet
COPY --from=elemental /usr/bin/elemental /usr/bin/elemental

# You cloud defined your own rke2 url by setup `RKE2_IMAGE_REPO`
ENV DAPPER_ENV REPO TAG DRONE_TAG DRONE_BRANCH CROSS RKE2_IMAGE_REPO USE_LOCAL_IMAGES
ENV DAPPER_ENV REPO TAG DRONE_TAG DRONE_BRANCH CROSS RKE2_IMAGE_REPO USE_LOCAL_IMAGES BUILD_QCOW
ENV DAPPER_SOURCE /go/src/github.com/harvester/harvester-installer/
ENV DAPPER_OUTPUT ./bin ./dist
ENV DAPPER_DOCKER_SOCKET true
ENV DAPPER_RUN_ARGS "-v /run/containerd/containerd.sock:/run/containerd/containerd.sock -v harvester-installer-go:/root/go -v harvester-installer-cache:/root/.cache"
ENV DAPPER_RUN_ARGS "-v /run/containerd/containerd.sock:/run/containerd/containerd.sock -v harvester-installer-go:/root/go -v harvester-installer-cache:/root/.cache --privileged"

ENV HOME ${DAPPER_SOURCE}
WORKDIR ${DAPPER_SOURCE}
Expand Down
6 changes: 6 additions & 0 deletions package/harvester-os/files/usr/sbin/harv-dummy-iface
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash -ex

ip link add type dummy
ip addr add 192.168.1.100/255.255.255.0 dev dummy0
ip link set dummy0 up
ip route add default via 192.168.1.100
3 changes: 3 additions & 0 deletions package/harvester-os/files/usr/sbin/harv-restart-services
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash -ex
systemctl restart --no-block rancherd
systemctl restart getty@tty1.service
51 changes: 51 additions & 0 deletions package/harvester-os/files/usr/sbin/stream-disk
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash

set -e

TARGET=/run/cos/target
DATA_DISK_FSLABEL="HARV_LH_DEFAULT"
DEFAULT_LH_PARTITION="6"

update_boot_args()
{
if [ -z "${HARVESTER_TTY}" ]; then
TTY=$(tty | sed 's!/dev/!!')
else
TTY=$HARVESTER_TTY
fi

if [ -e "/dev/${TTY%,*}" ] && [ "$TTY" != tty1 ] && [ "$TTY" != console ] && [ -n "$TTY" ]; then
sed -i "1s/.*/console_params=\"console=${TTY} console=tty1\"/g" ${TARGET}/etc/cos/bootargs.cfg
fi
}

echo "writing image to disk"
curl --retry 5 --no-buffer -k ${HARVESTER_RAW_DISK_IMAGE_PATH} | zstd -d -T4 | dd of=${HARVESTER_DEVICE} bs=1M iflag=fullblock oflag=direct
echo -e "w" | fdisk ${HARVESTER_DEVICE}
partprobe ${HARVESTER_DEVICE}

# if config_url is set then stream this to userdata.yaml as installer will load it on next boot
echo "checking and writing userdata"
sleep 30
if [ -n "${HARVESTER_STREAMDISK_CLOUDINIT_URL}" ]
then
oem_partition=$(blkid -L COS_OEM)
mount -t ext4 ${oem_partition} /oem
curl -k -o /oem/userdata.yaml ${HARVESTER_STREAMDISK_CLOUDINIT_URL}
cp ${HARVESTER_CONFIG} /oem/harvester.config
umount /oem
fi

echo "patching console"
persistent_partition=$(blkid -L COS_STATE)
mkdir -p $TARGET
mount -t ext4 ${persistent_partition} /mnt
mount /mnt/cOS/active.img ${TARGET}

update_boot_args

# resize HARV_LH_DEFAULT
echo "resizing default data disk"
parted ${HARVESTER_DEVICE} resizepart ${DEFAULT_LH_PARTITION} 100%
mkfs -t ext4 ${HARVESTER_DEVICE}${DEFAULT_LH_PARTITION}
e2label ${HARVESTER_DEVICE}${DEFAULT_LH_PARTITION} ${DATA_DISK_FSLABEL}
61 changes: 56 additions & 5 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strings"

"github.com/imdario/mergo"
yipSchema "github.com/mudler/yip/pkg/schema"
"k8s.io/apimachinery/pkg/util/validation"
)

Expand Down Expand Up @@ -148,11 +149,11 @@ type Install struct {
ForceMBR bool `json:"forceMbr,omitempty"`
DataDisk string `json:"dataDisk,omitempty"`

Webhooks []Webhook `json:"webhooks,omitempty"`
Addons map[string]Addon `json:"addons,omitempty"`
Harvester HarvesterChartValues `json:"harvester,omitempty"`

PersistentPartitionSize string `json:"persistentPartitionSize,omitempty"`
Webhooks []Webhook `json:"webhooks,omitempty"`
Addons map[string]Addon `json:"addons,omitempty"`
Harvester HarvesterChartValues `json:"harvester,omitempty"`
RawDiskImagePath string `json:"rawDiskImagePath,omitempty"`
PersistentPartitionSize string `json:"persistentPartitionSize,omitempty"`
}

type Wifi struct {
Expand Down Expand Up @@ -362,3 +363,53 @@ func (n *NetworkInterface) FindNetworkInterfaceHwAddr() error {
// Default, there is no Name or HwAddress, do nothing. Let validation capture it
return nil
}

func GenerateRancherdConfig(config *HarvesterConfig) (*yipSchema.YipConfig, error) {

runtimeConfig := yipSchema.Stage{
Users: make(map[string]yipSchema.User),
TimeSyncd: make(map[string]string),
SSHKeys: make(map[string][]string),
Sysctl: make(map[string]string),
Environment: make(map[string]string),
SystemdFirstBoot: make(map[string]string),
}

runtimeConfig.Hostname = config.OS.Hostname
if len(config.OS.NTPServers) > 0 {
runtimeConfig.TimeSyncd["NTP"] = strings.Join(config.OS.NTPServers, " ")
runtimeConfig.Systemctl.Enable = append(runtimeConfig.Systemctl.Enable, ntpdService)
runtimeConfig.Systemctl.Enable = append(runtimeConfig.Systemctl.Enable, timeWaitSyncService)
}
if len(config.OS.DNSNameservers) > 0 {
runtimeConfig.Commands = append(runtimeConfig.Commands, getAddStaticDNSServersCmd(config.OS.DNSNameservers))
}
err := initRancherdStage(config, &runtimeConfig)
if err != nil {
return nil, err
}

if err := UpdateWifiConfig(&runtimeConfig, config.OS.Wifi, true); err != nil {
return nil, err
}

if _, err := UpdateManagementInterfaceConfig(&runtimeConfig, config.ManagementInterface, true); err != nil {
return nil, err
}

runtimeConfig.SSHKeys[cosLoginUser] = config.OS.SSHAuthorizedKeys
runtimeConfig.Users[cosLoginUser] = yipSchema.User{
PasswordHash: config.OS.Password,
}

conf := &yipSchema.YipConfig{
Name: "RancherD Configuration",
Stages: map[string][]yipSchema.Stage{
"live": {
runtimeConfig,
},
},
}

return conf, nil
}
1 change: 1 addition & 0 deletions pkg/config/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const (
ModeCreate = "create"
ModeJoin = "join"
ModeUpgrade = "upgrade"
ModeInstall = "install"

NetworkMethodDHCP = "dhcp"
NetworkMethodStatic = "static"
Expand Down
84 changes: 39 additions & 45 deletions pkg/config/cos.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,29 @@ func ConvertToCOS(config *HarvesterConfig) (*yipSchema.YipConfig, error) {
TimeSyncd: make(map[string]string),
}

// TOP
if err := initRancherdStage(config, &initramfs); err != nil {
return nil, err
afterNetwork := yipSchema.Stage{
SSHKeys: make(map[string][]string),
}

initramfs.Users[cosLoginUser] = yipSchema.User{
PasswordHash: cfg.OS.Password,
}

// Use modprobe to load modules as a temporary solution
for _, module := range cfg.OS.Modules {
initramfs.Commands = append(initramfs.Commands, "modprobe "+module)
}

initramfs.Sysctl = cfg.OS.Sysctls
initramfs.Environment = cfg.OS.Environment

// OS
for _, ff := range cfg.OS.WriteFiles {
perm, err := strconv.ParseUint(ff.RawFilePermissions, 8, 32)
if err != nil {
logrus.Warnf("fail to parse permission %s, use default permission.", err)
perm = 0600
}

initramfs.Files = append(initramfs.Files, yipSchema.File{
Path: ff.Path,
Content: ff.Content,
Expand All @@ -142,42 +152,34 @@ func ConvertToCOS(config *HarvesterConfig) (*yipSchema.YipConfig, error) {
})
}

initramfs.Hostname = cfg.OS.Hostname
initramfs.Sysctl = cfg.OS.Sysctls
if len(cfg.OS.NTPServers) > 0 {
initramfs.TimeSyncd["NTP"] = strings.Join(cfg.OS.NTPServers, " ")
initramfs.Systemctl.Enable = append(initramfs.Systemctl.Enable, ntpdService)
initramfs.Systemctl.Enable = append(initramfs.Systemctl.Enable, timeWaitSyncService)
}
if len(cfg.OS.DNSNameservers) > 0 {
initramfs.Commands = append(initramfs.Commands, getAddStaticDNSServersCmd(cfg.OS.DNSNameservers))
}
// TOP
if cfg.Mode != ModeInstall {
if err := initRancherdStage(config, &initramfs); err != nil {
return nil, err
}

if err := UpdateWifiConfig(&initramfs, cfg.OS.Wifi, false); err != nil {
return nil, err
}
initramfs.Hostname = cfg.OS.Hostname

initramfs.Users[cosLoginUser] = yipSchema.User{
PasswordHash: cfg.OS.Password,
}

initramfs.Environment = cfg.OS.Environment
if len(cfg.OS.NTPServers) > 0 {
initramfs.TimeSyncd["NTP"] = strings.Join(cfg.OS.NTPServers, " ")
initramfs.Systemctl.Enable = append(initramfs.Systemctl.Enable, ntpdService)
initramfs.Systemctl.Enable = append(initramfs.Systemctl.Enable, timeWaitSyncService)
}
if len(cfg.OS.DNSNameservers) > 0 {
initramfs.Commands = append(initramfs.Commands, getAddStaticDNSServersCmd(cfg.OS.DNSNameservers))
}

// Use modprobe to load modules as a temporary solution
for _, module := range cfg.OS.Modules {
initramfs.Commands = append(initramfs.Commands, "modprobe "+module)
}
if err := UpdateWifiConfig(&initramfs, cfg.OS.Wifi, false); err != nil {
return nil, err
}

_, err = UpdateManagementInterfaceConfig(&initramfs, cfg.ManagementInterface, false)
if err != nil {
return nil, err
}
_, err = UpdateManagementInterfaceConfig(&initramfs, cfg.ManagementInterface, false)
if err != nil {
return nil, err
}

// After network is available
afterNetwork := yipSchema.Stage{
SSHKeys: make(map[string][]string),
afterNetwork.SSHKeys[cosLoginUser] = cfg.OS.SSHAuthorizedKeys
}
afterNetwork.SSHKeys[cosLoginUser] = cfg.OS.SSHAuthorizedKeys

cosConfig := &yipSchema.YipConfig{
Name: "Harvester Configuration",
Expand Down Expand Up @@ -280,15 +282,6 @@ func initRancherdStage(config *HarvesterConfig, stage *yipSchema.Stage) error {
)

if config.Install.Mode == "create" {
stage.Directories = append(stage.Directories,
yipSchema.Directory{
Path: rancherdBootstrapDir,
Permissions: 0600,
Owner: 0,
Group: 0,
},
)

bootstrapResources, err := genBootstrapResources(config)
if err != nil {
return err
Expand Down Expand Up @@ -412,6 +405,7 @@ func SaveOriginalNetworkConfig() error {
return err
}
originalNetworkConfigs[filepath.Base(path)] = bytes

}
return nil
}
Expand Down Expand Up @@ -638,7 +632,7 @@ func UpdateWifiConfig(stage *yipSchema.Stage, wifis []Wifi, run bool) error {
return nil
}

interfaces := make([]string, len(wifis))
var interfaces []string
for i, wifi := range wifis {
iface := fmt.Sprintf("wlan%d", i)

Expand Down Expand Up @@ -755,7 +749,7 @@ func CreateRootPartitioningLayout(elementalConfig *ElementalConfig, hvstConfig *
}

elementalConfig.Install.ExtraPartitions = []ElementalPartition{
{
ElementalPartition{
FilesystemLabel: "HARV_LH_DEFAULT",
Size: 0,
FS: "ext4",
Expand Down
Loading