2019-07-31 17:16:10 +00:00
/ * This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/. */
package installer
import (
2019-10-16 04:50:06 +00:00
"fmt"
2019-07-31 17:16:10 +00:00
"io"
"io/ioutil"
"os"
"path/filepath"
"unsafe"
2019-09-12 14:32:42 +00:00
"golang.org/x/sys/unix"
2019-07-31 17:16:10 +00:00
"github.com/talos-systems/talos/internal/pkg/installer/bootloader/syslinux"
"github.com/talos-systems/talos/internal/pkg/installer/manifest"
"github.com/talos-systems/talos/internal/pkg/kernel"
"github.com/talos-systems/talos/internal/pkg/mount"
"github.com/talos-systems/talos/internal/pkg/mount/manager"
"github.com/talos-systems/talos/internal/pkg/mount/manager/owned"
2019-09-30 14:30:11 -07:00
"github.com/talos-systems/talos/pkg/config/machine"
2019-08-01 23:01:31 +00:00
"github.com/talos-systems/talos/pkg/constants"
2019-07-31 17:16:10 +00:00
)
// Installer represents the installer logic. It serves as the entrypoint to all
// installation methods.
type Installer struct {
cmdline * kernel . Cmdline
2019-09-30 14:30:11 -07:00
install machine . Install
2019-07-31 17:16:10 +00:00
manifest * manifest . Manifest
}
// NewInstaller initializes and returns an Installer.
2019-09-30 14:30:11 -07:00
func NewInstaller ( cmdline * kernel . Cmdline , install machine . Install ) ( i * Installer , err error ) {
2019-08-15 15:21:55 +00:00
i = & Installer {
2019-07-31 17:16:10 +00:00
cmdline : cmdline ,
2019-09-30 14:30:11 -07:00
install : install ,
2019-07-31 17:16:10 +00:00
}
2019-09-30 14:30:11 -07:00
i . manifest , err = manifest . NewManifest ( install )
2019-08-15 15:21:55 +00:00
if err != nil {
2019-10-16 04:50:06 +00:00
return nil , fmt . Errorf ( "failed to create installation manifest: %w" , err )
2019-08-15 15:21:55 +00:00
}
2019-07-31 17:16:10 +00:00
2019-08-15 15:21:55 +00:00
return i , nil
2019-07-31 17:16:10 +00:00
}
// Install fetches the necessary data locations and copies or extracts
// to the target locations.
// nolint: gocyclo
func ( i * Installer ) Install ( ) ( err error ) {
2019-09-30 14:30:11 -07:00
if i . install . Zero ( ) {
if err = zero ( i . manifest ) ; err != nil {
2019-10-16 04:50:06 +00:00
return fmt . Errorf ( "failed to wipe device(s): %w" , err )
2019-07-31 17:16:10 +00:00
}
}
// Partition and format the block device(s).
2019-09-30 14:30:11 -07:00
if err = i . manifest . ExecuteManifest ( i . manifest ) ; err != nil {
2019-07-31 17:16:10 +00:00
return err
}
// Mount the partitions.
2019-08-08 00:16:43 -05:00
mountpoints := mount . NewMountPoints ( )
// look for mountpoints across all target devices
for dev := range i . manifest . Targets {
var mp * mount . Points
mp , err = owned . MountPointsForDevice ( dev )
2019-10-10 01:00:42 +03:00
2019-07-31 17:16:10 +00:00
if err != nil {
return err
}
2019-08-08 00:16:43 -05:00
iter := mp . Iter ( )
for iter . Next ( ) {
mountpoints . Set ( iter . Key ( ) , iter . Value ( ) )
2019-07-31 17:16:10 +00:00
}
}
m := manager . NewManager ( mountpoints )
if err = m . MountAll ( ) ; err != nil {
return err
}
2019-08-08 00:16:43 -05:00
// nolint: errcheck
defer m . UnmountAll ( )
2019-07-31 17:16:10 +00:00
// Install the assets.
for _ , targets := range i . manifest . Targets {
for _ , target := range targets {
switch target . Label {
case constants . BootPartitionLabel :
if err = syslinux . Prepare ( target . Device ) ; err != nil {
return err
}
2019-08-15 12:12:22 +00:00
case constants . EphemeralPartitionLabel :
2019-07-31 17:16:10 +00:00
continue
}
// Handle the download and extraction of assets.
if err = target . Save ( ) ; err != nil {
return err
}
}
}
// Install the bootloader.
2019-09-30 14:30:11 -07:00
if ! i . install . WithBootloader ( ) {
2019-07-31 17:16:10 +00:00
return nil
}
syslinuxcfg := & syslinux . Cfg {
Default : "default" ,
Labels : [ ] * syslinux . Label {
{
Root : "default" ,
2019-08-26 18:54:15 +00:00
Initrd : filepath . Join ( "/" , "default" , constants . InitramfsAsset ) ,
Kernel : filepath . Join ( "/" , "default" , constants . KernelAsset ) ,
2019-07-31 17:16:10 +00:00
Append : i . cmdline . String ( ) ,
} ,
} ,
}
if err = syslinux . Install ( filepath . Join ( constants . BootMountPoint ) , syslinuxcfg ) ; err != nil {
return err
}
if err = ioutil . WriteFile ( filepath . Join ( constants . BootMountPoint , "installed" ) , [ ] byte { } , 0400 ) ; err != nil {
return err
}
return nil
}
2019-09-30 14:30:11 -07:00
func zero ( manifest * manifest . Manifest ) ( err error ) {
2019-07-31 17:16:10 +00:00
var zero * os . File
2019-10-10 01:00:42 +03:00
2019-07-31 17:16:10 +00:00
if zero , err = os . Open ( "/dev/zero" ) ; err != nil {
return err
}
for dev := range manifest . Targets {
var f * os . File
2019-10-10 01:00:42 +03:00
2019-07-31 17:16:10 +00:00
if f , err = os . OpenFile ( dev , os . O_RDWR , os . ModeDevice ) ; err != nil {
return err
}
2019-10-10 01:00:42 +03:00
2019-07-31 17:16:10 +00:00
var size uint64
2019-10-10 01:00:42 +03:00
2019-07-31 17:16:10 +00:00
if _ , _ , ret := unix . Syscall ( unix . SYS_IOCTL , f . Fd ( ) , unix . BLKGETSIZE64 , uintptr ( unsafe . Pointer ( & size ) ) ) ; ret != 0 {
2019-10-16 04:50:06 +00:00
return fmt . Errorf ( "failed to got block device size: %v" , ret )
2019-07-31 17:16:10 +00:00
}
2019-10-10 01:00:42 +03:00
2019-07-31 17:16:10 +00:00
if _ , err = io . CopyN ( f , zero , int64 ( size ) ) ; err != nil {
return err
}
if err = f . Close ( ) ; err != nil {
return err
}
}
if err = zero . Close ( ) ; err != nil {
return err
}
return nil
}