github.com/openshift/installer@v1.4.17/pkg/asset/imagebased/image/image.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"github.com/sirupsen/logrus"
    12  
    13  	"github.com/openshift/assisted-image-service/pkg/isoeditor"
    14  	"github.com/openshift/installer/pkg/asset"
    15  	"github.com/openshift/installer/pkg/types/imagebased"
    16  )
    17  
    18  const (
    19  	isoFilename = "rhcos-ibi.iso"
    20  )
    21  
    22  // Image is an asset that generates the bootable image used to install clusters.
    23  type Image struct {
    24  	Config       *imagebased.InstallationConfig
    25  	IgnitionByte []byte
    26  	ISOPath      string
    27  
    28  	tmpPath string
    29  }
    30  
    31  var _ asset.WritableAsset = (*Image)(nil)
    32  
    33  // Dependencies returns the assets on which the image asset depends.
    34  func (i *Image) Dependencies() []asset.Asset {
    35  	return []asset.Asset{
    36  		&ImageBasedInstallationConfig{},
    37  		&Ignition{},
    38  		&BaseIso{},
    39  	}
    40  }
    41  
    42  // Generate generates the image file for the ISO asset.
    43  func (i *Image) Generate(_ context.Context, dependencies asset.Parents) error {
    44  	installationConfig := &ImageBasedInstallationConfig{}
    45  	baseIso := &BaseIso{}
    46  	ignition := &Ignition{}
    47  	dependencies.Get(installationConfig, baseIso, ignition)
    48  
    49  	ignitionByte, err := json.Marshal(ignition.Config)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	i.Config = installationConfig.Config
    55  	i.ISOPath = baseIso.File.Filename
    56  	i.IgnitionByte = ignitionByte
    57  
    58  	return nil
    59  }
    60  
    61  // PersistToFile writes the ISO image in the assets folder.
    62  func (i *Image) PersistToFile(directory string) error {
    63  	if i.Config == nil || len(i.IgnitionByte) == 0 {
    64  		return fmt.Errorf("could not generate image because of configuration errors")
    65  	}
    66  
    67  	// Create a tmp folder to store all the pieces required to generate the image-based installer artifacts.
    68  	tmpPath, err := os.MkdirTemp("", "imagebased")
    69  	if err != nil {
    70  		return err
    71  	}
    72  	i.tmpPath = tmpPath
    73  	if err := os.MkdirAll(i.tmpPath, 0755); err != nil {
    74  		return fmt.Errorf("failed to create temporary directory: %w", err)
    75  	}
    76  	defer os.RemoveAll(i.tmpPath)
    77  
    78  	isoFile := filepath.Join(directory, isoFilename)
    79  
    80  	// Remove symlink if it exists.
    81  	os.Remove(isoFile)
    82  
    83  	ignitionc := &isoeditor.IgnitionContent{}
    84  	ignitionc.Config = i.IgnitionByte
    85  	reader, err := isoeditor.NewRHCOSStreamReader(i.ISOPath, ignitionc, nil, nil)
    86  	if err != nil {
    87  		return fmt.Errorf("failed to create reader for RHCOS base ISO: %w", err)
    88  	}
    89  	logrus.Info("Creating Image-based Installation ISO with embedded ignition")
    90  
    91  	file, err := os.Create(isoFile)
    92  	if err != nil {
    93  		return fmt.Errorf("failed to create Image-based Installation ISO file: %w", err)
    94  	}
    95  	defer file.Close()
    96  
    97  	if _, err := io.Copy(file, reader); err != nil {
    98  		return fmt.Errorf("failed to copy reader to file: %w", err)
    99  	}
   100  
   101  	if err := file.Sync(); err != nil {
   102  		return fmt.Errorf("failed to sync file: %w", err)
   103  	}
   104  
   105  	return nil
   106  }
   107  
   108  // Files returns the files generated by the asset.
   109  func (i *Image) Files() []*asset.File {
   110  	// Return empty array because File will never be loaded.
   111  	return []*asset.File{}
   112  }
   113  
   114  // Load returns the ISO from disk.
   115  func (i *Image) Load(f asset.FileFetcher) (bool, error) {
   116  	// The ISO will not be needed by another asset so load is noop.
   117  	// This is implemented because it is required by WritableAsset
   118  	return false, nil
   119  }
   120  
   121  // Name returns the human-friendly name of the asset.
   122  func (i *Image) Name() string {
   123  	return "Image-based Installation ISO"
   124  }