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

     1  package configimage
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/pkg/errors"
    10  	"github.com/sirupsen/logrus"
    11  	"github.com/vincent-petithory/dataurl"
    12  
    13  	"github.com/openshift/assisted-image-service/pkg/isoeditor"
    14  	"github.com/openshift/installer/pkg/asset"
    15  	"github.com/openshift/installer/pkg/asset/agent/image"
    16  )
    17  
    18  const (
    19  	configImageFilename = "agentconfig.noarch.iso"
    20  	configImageLabel    = "agent_configimage"
    21  	configCpioArchive   = "config.gz"
    22  )
    23  
    24  // ConfigImage is an asset that generates a configuration ISO that can be used configure hosts.
    25  type ConfigImage struct {
    26  	tmpPath string
    27  }
    28  
    29  var _ asset.WritableAsset = (*ConfigImage)(nil)
    30  
    31  // Dependencies returns the assets on which the Config asset depends.
    32  func (a *ConfigImage) Dependencies() []asset.Asset {
    33  	return []asset.Asset{
    34  		&image.Ignition{},
    35  	}
    36  }
    37  
    38  // Generate generates the configuration image file.
    39  func (a *ConfigImage) Generate(_ context.Context, dependencies asset.Parents) error {
    40  	ignition := &image.Ignition{}
    41  
    42  	dependencies.Get(ignition)
    43  
    44  	ca := image.NewCpioArchive()
    45  
    46  	// Walk the list of ignition files.
    47  	// For the ones to be included in the configimage add to cpio archive
    48  	for _, file := range ignition.Config.Storage.Files {
    49  		filename := file.Node.Path
    50  		mode := *file.FileEmbedded1.Mode
    51  		if includeFileInImage(filename) {
    52  			logrus.Debugf("Including file %s", filename)
    53  			contents := ""
    54  			if file.FileEmbedded1.Contents.Source != nil {
    55  				output, err := dataurl.DecodeString(*file.FileEmbedded1.Contents.Source)
    56  				if err != nil {
    57  					return errors.Wrapf(err, "decode string failed for %s", filename)
    58  				}
    59  				contents = string(output.Data)
    60  			}
    61  
    62  			err := ca.StoreBytes(filename, []byte(contents), mode)
    63  			if err != nil {
    64  				return errors.Wrapf(err, "failure storing file %s in cpio", filename)
    65  			}
    66  		}
    67  	}
    68  
    69  	// Save the cpi archive to a temp file
    70  	tmpPath, err := os.MkdirTemp("", "agent")
    71  	if err != nil {
    72  		return err
    73  	}
    74  	a.tmpPath = tmpPath
    75  
    76  	output := filepath.Join(tmpPath, configCpioArchive)
    77  
    78  	err = ca.Save(output)
    79  	if err != nil {
    80  		return errors.Wrapf(err, "failure saving cpio file %s", configCpioArchive)
    81  	}
    82  
    83  	return nil
    84  }
    85  
    86  // PersistToFile writes the iso image in the assets folder.
    87  func (a *ConfigImage) PersistToFile(directory string) error {
    88  	defer os.RemoveAll(a.tmpPath)
    89  
    90  	// If the tmpPath are not set then it means that either one of the Config
    91  	// dependencies or the asset itself failed for some reason
    92  	if a.tmpPath == "" {
    93  		return errors.New("cannot generate Config image due to configuration errors")
    94  	}
    95  
    96  	configImageFile := filepath.Join(directory, configImageFilename)
    97  
    98  	// Remove symlink if it exists
    99  	os.Remove(configImageFile)
   100  
   101  	err := isoeditor.Create(configImageFile, a.tmpPath, configImageLabel)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	return nil
   107  }
   108  
   109  // Name returns the human-friendly name of the asset.
   110  func (a *ConfigImage) Name() string {
   111  	return "Agent Config ISO"
   112  }
   113  
   114  // Load returns the ISO from disk.
   115  func (a *ConfigImage) 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  // Files returns the files generated by the asset.
   122  func (a *ConfigImage) Files() []*asset.File {
   123  	// Return empty array because File will never be loaded.
   124  	return []*asset.File{}
   125  }
   126  
   127  func includeFileInImage(f string) bool {
   128  	fileFilters := image.GetConfigImageFiles()
   129  	for _, filter := range fileFilters {
   130  		if strings.Contains(f, filter) {
   131  			return true
   132  		}
   133  	}
   134  	return false
   135  }