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

     1  package configimage
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/openshift/assisted-image-service/pkg/isoeditor"
    11  	"github.com/openshift/installer/pkg/asset"
    12  	"github.com/openshift/installer/pkg/types/imagebased"
    13  )
    14  
    15  const (
    16  	configImageFilename = "imagebasedconfig.iso"
    17  	configImageLabel    = imagebased.BlockDeviceLabel
    18  
    19  	clusterConfigurationDir = "cluster-configuration"
    20  	extraManifestsDir       = "extra-manifests"
    21  )
    22  
    23  var (
    24  	manifestsDir = filepath.Join(clusterConfigurationDir, "manifests")
    25  )
    26  
    27  // ConfigImage is an asset that generates a configuration ISO that can be used to
    28  // configure image-based installer provisioned hosts.
    29  type ConfigImage struct {
    30  	tmpPath string
    31  }
    32  
    33  var _ asset.WritableAsset = (*ConfigImage)(nil)
    34  
    35  // Dependencies returns the assets on which the Config asset depends.
    36  func (ci *ConfigImage) Dependencies() []asset.Asset {
    37  	return []asset.Asset{
    38  		&ClusterConfiguration{},
    39  		&ImageDigestSources{},
    40  		&ExtraManifests{},
    41  	}
    42  }
    43  
    44  // Generate generates the configuration image file.
    45  func (ci *ConfigImage) Generate(_ context.Context, dependencies asset.Parents) error {
    46  	// Save the image to a temp file
    47  	tmpPath, err := os.MkdirTemp("", "imagebased")
    48  	if err != nil {
    49  		return fmt.Errorf("could not create temp directory: %w", err)
    50  	}
    51  	ci.tmpPath = tmpPath
    52  
    53  	dirs := []string{
    54  		clusterConfigurationDir,
    55  		manifestsDir,
    56  		extraManifestsDir,
    57  	}
    58  	for _, dir := range dirs {
    59  		if err := os.MkdirAll(filepath.Join(ci.tmpPath, dir), 0755); err != nil {
    60  			return fmt.Errorf("could not create %s directory: %w", dir, err)
    61  		}
    62  	}
    63  
    64  	createFile := func(file *asset.File) error {
    65  		f, err := os.Create(filepath.Join(ci.tmpPath, file.Filename))
    66  		if err != nil {
    67  			return fmt.Errorf("could not create %s: %w", file.Filename, err)
    68  		}
    69  		defer f.Close()
    70  
    71  		if _, err := f.Write(file.Data); err != nil {
    72  			return fmt.Errorf("could not write %s: %w", file.Filename, err)
    73  		}
    74  		return nil
    75  	}
    76  
    77  	for _, a := range []asset.WritableAsset{
    78  		&ClusterConfiguration{},
    79  		&ImageDigestSources{},
    80  		&ExtraManifests{},
    81  	} {
    82  		dependencies.Get(a)
    83  
    84  		for _, file := range a.Files() {
    85  			if err := createFile(file); err != nil {
    86  				return err
    87  			}
    88  		}
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  // PersistToFile writes the ISO image in the assets folder.
    95  func (ci *ConfigImage) PersistToFile(directory string) error {
    96  	defer os.RemoveAll(ci.tmpPath)
    97  
    98  	// If the tmpPath is not set then it means that either one of the Config
    99  	// dependencies or the asset itself failed for some reason
   100  	if ci.tmpPath == "" {
   101  		return errors.New("cannot generate config image due to configuration errors")
   102  	}
   103  
   104  	configImageFile := filepath.Join(directory, configImageFilename)
   105  
   106  	// Remove symlink if it exists
   107  	os.Remove(configImageFile)
   108  
   109  	err := isoeditor.Create(configImageFile, ci.tmpPath, configImageLabel)
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  // Name returns the human-friendly name of the asset.
   118  func (ci *ConfigImage) Name() string {
   119  	return "Image-based Installer Config ISO"
   120  }
   121  
   122  // Load returns the ISO from disk.
   123  func (ci *ConfigImage) Load(f asset.FileFetcher) (bool, error) {
   124  	// The ISO will not be needed by another asset so load is noop.
   125  	// This is implemented because it is required by WritableAsset
   126  	return false, nil
   127  }
   128  
   129  // Files returns the files generated by the asset.
   130  func (ci *ConfigImage) Files() []*asset.File {
   131  	// Return empty array because File will never be loaded.
   132  	return []*asset.File{}
   133  }