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 }