github.com/openshift/installer@v1.4.17/pkg/rhcos/builds.go (about)

     1  // package rhcos contains APIs for interacting with the RHEL (or Fedora) CoreOS
     2  // bootimages embedded as stream metadata JSON with the installer
     3  // For more information, see docs/dev/pinned-coreos.md
     4  
     5  package rhcos
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"fmt"
    11  	"io"
    12  	"net/url"
    13  
    14  	"github.com/coreos/stream-metadata-go/stream"
    15  	"github.com/pkg/errors"
    16  
    17  	"github.com/openshift/installer/data"
    18  )
    19  
    20  // FetchRawCoreOSStream returns the raw stream metadata for the
    21  // bootimages embedded in the installer.
    22  func FetchRawCoreOSStream(ctx context.Context) ([]byte, error) {
    23  	file, err := data.Assets.Open(getStreamFileName())
    24  	if err != nil {
    25  		return nil, errors.Wrapf(err, "failed to read embedded CoreOS stream metadata")
    26  	}
    27  	defer file.Close()
    28  
    29  	body, err := io.ReadAll(file)
    30  	if err != nil {
    31  		return nil, errors.Wrap(err, "failed to read CoreOS stream metadata")
    32  	}
    33  	return body, nil
    34  }
    35  
    36  // FetchCoreOSBuild returns the pinned version of RHEL/Fedora CoreOS used
    37  // by the installer to provision the bootstrap node and control plane currently.
    38  // For more information, see e.g. https://github.com/openshift/enhancements/pull/201
    39  func FetchCoreOSBuild(ctx context.Context) (*stream.Stream, error) {
    40  	body, err := FetchRawCoreOSStream(ctx)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	var st stream.Stream
    45  	if err := json.Unmarshal(body, &st); err != nil {
    46  		return nil, errors.Wrap(err, "failed to parse CoreOS stream metadata")
    47  	}
    48  	return &st, nil
    49  }
    50  
    51  // FormatURLWithIntegrity squashes an artifact into a URL string
    52  // with the uncompressed sha256 as a query parameter.  This is necessary
    53  // currently because various parts of the installer pass around this
    54  // reference as a string, and it's also exposed to users via install-config overrides.
    55  func FormatURLWithIntegrity(artifact *stream.Artifact) (string, error) {
    56  	u, err := url.Parse(artifact.Location)
    57  	if err != nil {
    58  		return "", fmt.Errorf("failed to parse artifact URL: %v", err)
    59  	}
    60  	q := u.Query()
    61  	q.Set("sha256", artifact.UncompressedSha256)
    62  	u.RawQuery = q.Encode()
    63  	return u.String(), nil
    64  }
    65  
    66  // FindArtifactURL returns a single "disk" artifact type; this
    67  // mainly abstracts over e.g. `qcow2.xz` and `qcow2.gz`.  (FCOS uses
    68  // xz, RHCOS uses gzip right now)
    69  //
    70  // Use this function only for cases where there's a single artifact type, such
    71  // as `qemu` and `openstack`.
    72  //
    73  // Some platforms have multiple artifact types; for example, `metal` has an ISO
    74  // as well as PXE files.  This function will error in such a case.
    75  func FindArtifactURL(artifacts stream.PlatformArtifacts) (string, error) {
    76  	var artifact *stream.Artifact
    77  	for _, v := range artifacts.Formats {
    78  		if v.Disk != nil {
    79  			if artifact != nil {
    80  				return "", fmt.Errorf("multiple \"disk\" artifacts found")
    81  			}
    82  			artifact = v.Disk
    83  		}
    84  	}
    85  	if artifact != nil {
    86  		return FormatURLWithIntegrity(artifact)
    87  	}
    88  	return "", fmt.Errorf("no \"disk\" artifact found")
    89  }