Skip to content

Commit

Permalink
DNM: PoC use RHCOS stream Azure marketplace images
Browse files Browse the repository at this point in the history
This is a WIP implementation of using Azure marketplace images from
the coreOS stream:
- reads marketplace images instead of azure disk from stream
- sets up images in control plane machine manifests (needs more work)
- removes image upload

Also includes a marketplace-rhcos.json file which was generated with
STREAM_RELEASE_OVERRIDE=417.94.202407010000-0 go run -mod=vendor ./hack/rhcos/populate-marketplace-imagestream.go
  • Loading branch information
patrickdillon committed Dec 19, 2024
1 parent ebc41a4 commit 6944b1b
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 183 deletions.
35 changes: 35 additions & 0 deletions data/data/coreos/marketplace-rhcos.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"aarch64": {
"azure": {
"no-purchase-plan": {
"hyperVGen2": {
"publisher": "azureopenshift",
"offer": "aro4",
"sku": "417-arm",
"version": "417.94.20240701",
"thirdParty": false
}
}
}
},
"x86_64": {
"azure": {
"no-purchase-plan": {
"hyperVGen1": {
"publisher": "azureopenshift",
"offer": "aro4",
"sku": "aro_417",
"version": "417.94.20240701",
"thirdParty": false
},
"hyperVGen2": {
"publisher": "azureopenshift",
"offer": "aro4",
"sku": "417-v2",
"version": "417.94.20240701",
"thirdParty": false
}
}
}
}
}
16 changes: 16 additions & 0 deletions pkg/asset/machines/azure/azuremachines.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type MachineInput struct {
Role string
UserDataSecret string
HyperVGen string
RHCOSImage string
UseImageGallery bool
Private bool
UserTags map[string]string
Expand Down Expand Up @@ -93,6 +94,21 @@ func GenerateMachines(clusterID, resourceGroup, subscriptionID string, in *Machi
image = &capz.Image{ID: &imageID}
}

// DNM: Testing/POC
// TODO: Integrate this fully, remove managed disk, handle hypervgen, make default except for ASH
urn := strings.Split(in.RHCOSImage, ":")
image = &capz.Image{
Marketplace: &capz.AzureMarketplaceImage{
ImagePlan: capz.ImagePlan{
Publisher: urn[0],
Offer: urn[1],
SKU: urn[2],
},
Version: urn[3],
ThirdPartyImage: false,
},
}

// Set up OSDisk
osDisk := capz.OSDisk{
OSType: "Linux",
Expand Down
9 changes: 9 additions & 0 deletions pkg/asset/machines/azure/machines.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,15 @@ func provider(platform *azure.Platform, mpool *azure.MachinePool, osImage string
}
image.ResourceID = imageID
}
// DNM: Testing, PoC. Need to figure out which image selection logic we need to keep (if any).
urn := strings.Split(osImage, ":")
image = machineapi.Image{
Publisher: urn[0],
Offer: urn[1],
SKU: urn[2],
Version: urn[3],
Type: machineapi.AzureImageTypeMarketplaceNoPlan,
}

networkResourceGroup, virtualNetwork, subnet, err := getNetworkInfo(platform, clusterID, role)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/asset/machines/clusterapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ func (c *ClusterAPI) Generate(ctx context.Context, dependencies asset.Parents) e
Role: "master",
UserDataSecret: "master-user-data",
HyperVGen: hyperVGen,
RHCOSImage: rhcosImage.ControlPlane,
UseImageGallery: false,
Private: installConfig.Config.Publish == types.InternalPublishingStrategy,
UserTags: installConfig.Config.Platform.Azure.UserTags,
Expand Down
21 changes: 17 additions & 4 deletions pkg/asset/rhcos/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,24 @@ func osImage(ctx context.Context, config *types.InstallConfig, nodeArch types.Ar
if ext == nil {
return "", fmt.Errorf("%s: No azure build found", st.FormatPrefix(archName))
}
azd := ext.AzureDisk
if azd == nil {
return "", fmt.Errorf("%s: No azure build found", st.FormatPrefix(archName))
azm := ext.Marketplace
if azm == nil {
return "", fmt.Errorf("%s: No marketplace found", st.FormatPrefix(archName))
}
maz := azm.Azure
if maz == nil {
return "", fmt.Errorf("%s: No azure marketplace found", st.FormatPrefix(archName))
}
azp := maz.NoPurchasePlan
if azp == nil {
return "", fmt.Errorf("%s: No azure marketplace plan found", st.FormatPrefix(archName))
}
azi := azp.Gen2
if azi == nil {
return "", fmt.Errorf("%s: No azure gen2 marketplace image found", st.FormatPrefix(archName))
}
return azd.URL, nil
//TODO: move all this nil checking to a function
return azi.URN(), nil
case baremetal.Name:
// Check for image URL override
if oi := config.Platform.BareMetal.ClusterOSImage; oi != "" {
Expand Down
179 changes: 0 additions & 179 deletions pkg/infrastructure/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"fmt"
"math/rand"
"net/http"
"os"
"strings"
"time"

Expand All @@ -20,7 +18,6 @@ import (
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v2"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources"
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
"github.com/coreos/stream-metadata-go/arch"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
corev1 "k8s.io/api/core/v1"
Expand All @@ -32,8 +29,6 @@ import (
azconfig "github.com/openshift/installer/pkg/asset/installconfig/azure"
"github.com/openshift/installer/pkg/asset/manifests/capiutils"
"github.com/openshift/installer/pkg/infrastructure/clusterapi"
"github.com/openshift/installer/pkg/rhcos"
"github.com/openshift/installer/pkg/types"
aztypes "github.com/openshift/installer/pkg/types/azure"
)

Expand Down Expand Up @@ -297,49 +292,8 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
subscriptionID := session.Credentials.SubscriptionID
cloudConfiguration := session.CloudConfig

var architecture armcompute.Architecture
if installConfig.ControlPlane.Architecture == types.ArchitectureARM64 {
architecture = armcompute.ArchitectureArm64
} else {
architecture = armcompute.ArchitectureX64
}

resourceGroupName := p.ResourceGroupName
storageAccountName := getStorageAccountName(in.InfraID)
containerName := "vhd"
blobName := fmt.Sprintf("rhcos%s.vhd", randomString(5))

stream, err := rhcos.FetchCoreOSBuild(ctx)
if err != nil {
return fmt.Errorf("failed to get rhcos stream: %w", err)
}
archName := arch.RpmArch(string(installConfig.ControlPlane.Architecture))
streamArch, err := stream.GetArchitecture(archName)
if err != nil {
return fmt.Errorf("failed to get rhcos architecture: %w", err)
}

azureDisk := streamArch.RHELCoreOSExtensions.AzureDisk
imageURL := azureDisk.URL

rawImageVersion := strings.ReplaceAll(azureDisk.Release, "-", "_")
imageVersion := rawImageVersion[:len(rawImageVersion)-6]

galleryName := fmt.Sprintf("gallery_%s", strings.ReplaceAll(in.InfraID, "-", "_"))
galleryImageName := in.InfraID
galleryImageVersionName := imageVersion
galleryGen2ImageName := fmt.Sprintf("%s-gen2", in.InfraID)
galleryGen2ImageVersionName := imageVersion

headResponse, err := http.Head(imageURL) // nolint:gosec
if err != nil {
return fmt.Errorf("failed HEAD request for image URL %s: %w", imageURL, err)
}

imageLength := headResponse.ContentLength
if imageLength%512 != 0 {
return fmt.Errorf("image length is not aligned on a 512 byte boundary")
}

userTags := platform.UserTags
tags := make(map[string]*string, len(userTags)+1)
Expand All @@ -350,7 +304,6 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput

tokenCredential := session.TokenCreds
storageURL := fmt.Sprintf("https://%s.blob.%s", storageAccountName, session.Environment.StorageEndpointSuffix)
blobURL := fmt.Sprintf("%s/%s/%s", storageURL, containerName, blobName)

// Create storage account
createStorageAccountOutput, err := CreateStorageAccount(ctx, &CreateStorageAccountInput{
Expand All @@ -375,138 +328,6 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput

logrus.Debugf("StorageAccount.ID=%s", *storageAccount.ID)

// Create blob storage container
publicAccess := armstorage.PublicAccessNone
createBlobContainerOutput, err := CreateBlobContainer(ctx, &CreateBlobContainerInput{
SubscriptionID: subscriptionID,
ResourceGroupName: resourceGroupName,
StorageAccountName: storageAccountName,
ContainerName: containerName,
PublicAccess: to.Ptr(publicAccess),
StorageClientFactory: storageClientFactory,
})
if err != nil {
return err
}

blobContainer := createBlobContainerOutput.BlobContainer
logrus.Debugf("BlobContainer.ID=%s", *blobContainer.ID)

// Upload the image to the container
if _, ok := os.LookupEnv("OPENSHIFT_INSTALL_SKIP_IMAGE_UPLOAD"); !ok {
_, err = CreatePageBlob(ctx, &CreatePageBlobInput{
StorageURL: storageURL,
BlobURL: blobURL,
ImageURL: imageURL,
ImageLength: imageLength,
StorageAccountName: storageAccountName,
StorageAccountKeys: storageAccountKeys,
CloudConfiguration: cloudConfiguration,
})
if err != nil {
return err
}

// Create image gallery
createImageGalleryOutput, err := CreateImageGallery(ctx, &CreateImageGalleryInput{
SubscriptionID: subscriptionID,
ResourceGroupName: resourceGroupName,
GalleryName: galleryName,
Region: platform.Region,
Tags: tags,
TokenCredential: tokenCredential,
CloudConfiguration: cloudConfiguration,
})
if err != nil {
return err
}

computeClientFactory := createImageGalleryOutput.ComputeClientFactory

// Create gallery images
_, err = CreateGalleryImage(ctx, &CreateGalleryImageInput{
ResourceGroupName: resourceGroupName,
GalleryName: galleryName,
GalleryImageName: galleryImageName,
Region: platform.Region,
Publisher: "RedHat",
Offer: "rhcos",
SKU: "basic",
Tags: tags,
TokenCredential: tokenCredential,
CloudConfiguration: cloudConfiguration,
Architecture: architecture,
OSType: armcompute.OperatingSystemTypesLinux,
OSState: armcompute.OperatingSystemStateTypesGeneralized,
HyperVGeneration: armcompute.HyperVGenerationV1,
ComputeClientFactory: computeClientFactory,
SecurityType: "",
})
if err != nil {
return err
}
// If Control Plane Security Type is provided, then pass that along
// during Gen V2 Gallery Image creation. It will be added as a
// supported feature of the image.
securityType, err := getMachinePoolSecurityType(in)
if err != nil {
return err
}

_, err = CreateGalleryImage(ctx, &CreateGalleryImageInput{
ResourceGroupName: resourceGroupName,
GalleryName: galleryName,
GalleryImageName: galleryGen2ImageName,
Region: platform.Region,
Publisher: "RedHat-gen2",
Offer: "rhcos-gen2",
SKU: "gen2",
Tags: tags,
TokenCredential: tokenCredential,
CloudConfiguration: cloudConfiguration,
Architecture: architecture,
OSType: armcompute.OperatingSystemTypesLinux,
OSState: armcompute.OperatingSystemStateTypesGeneralized,
HyperVGeneration: armcompute.HyperVGenerationV2,
ComputeClientFactory: computeClientFactory,
SecurityType: securityType,
})
if err != nil {
return err
}

// Create gallery image versions
_, err = CreateGalleryImageVersion(ctx, &CreateGalleryImageVersionInput{
ResourceGroupName: resourceGroupName,
StorageAccountID: *storageAccount.ID,
GalleryName: galleryName,
GalleryImageName: galleryImageName,
GalleryImageVersionName: galleryImageVersionName,
Region: platform.Region,
BlobURL: blobURL,
RegionalReplicaCount: int32(1),
ComputeClientFactory: computeClientFactory,
})
if err != nil {
return err
}

_, err = CreateGalleryImageVersion(ctx, &CreateGalleryImageVersionInput{
ResourceGroupName: resourceGroupName,
StorageAccountID: *storageAccount.ID,
GalleryName: galleryName,
GalleryImageName: galleryGen2ImageName,
GalleryImageVersionName: galleryGen2ImageVersionName,
Region: platform.Region,
BlobURL: blobURL,
RegionalReplicaCount: int32(1),
ComputeClientFactory: computeClientFactory,
})
if err != nil {
return err
}
}

networkClientFactory, err := armnetwork.NewClientFactory(subscriptionID, session.TokenCreds,
&arm.ClientOptions{
ClientOptions: policy.ClientOptions{
Expand Down

0 comments on commit 6944b1b

Please sign in to comment.