Skip to content

Commit 724fd9e

Browse files
committed
Create a Page Blob for Ignition Shim when CMK is provided
1 parent 250b8ae commit 724fd9e

File tree

2 files changed

+115
-30
lines changed

2 files changed

+115
-30
lines changed

pkg/infrastructure/azure/azure.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
307307

308308
imageLength := headResponse.ContentLength
309309
if imageLength%512 != 0 {
310-
return fmt.Errorf("image length is not alisnged on a 512 byte boundary")
310+
return fmt.Errorf("image length is not aligned on a 512 byte boundary")
311311
}
312312

313313
userTags := platform.UserTags
@@ -768,16 +768,41 @@ func (p Provider) Ignition(ctx context.Context, in clusterapi.IgnitionInput) ([]
768768
blobIgnitionContainer := createBlobContainerOutput.BlobContainer
769769
logrus.Debugf("BlobIgnitionContainer.ID=%s", *blobIgnitionContainer.ID)
770770

771-
sasURL, err := CreateBlockBlob(ctx, &CreateBlockBlobInput{
772-
StorageURL: p.StorageURL,
773-
BlobURL: blobURL,
774-
StorageAccountName: p.StorageAccountName,
775-
StorageAccountKeys: p.StorageAccountKeys,
776-
CloudConfiguration: cloudConfiguration,
777-
BootstrapIgnData: bootstrapIgnData,
778-
})
779-
if err != nil {
780-
return nil, err
771+
sasURL := ""
772+
773+
if in.InstallConfig.Config.Azure.CustomerManagedKey == nil {
774+
logrus.Debugf("Creating a Block Blob for ignition shim")
775+
sasURL, err = CreateBlockBlob(ctx, &CreateBlockBlobInput{
776+
StorageURL: p.StorageURL,
777+
BlobURL: blobURL,
778+
StorageAccountName: p.StorageAccountName,
779+
StorageAccountKeys: p.StorageAccountKeys,
780+
CloudConfiguration: cloudConfiguration,
781+
BootstrapIgnData: bootstrapIgnData,
782+
})
783+
if err != nil {
784+
return nil, fmt.Errorf("failed to create BlockBlob for ignition shim: %w", err)
785+
}
786+
} else {
787+
logrus.Debugf("Creating a Page Blob for ignition shim because Customer Managed Key is provided")
788+
lengthBootstrapFile := int64(len(bootstrapIgnData))
789+
if lengthBootstrapFile%512 != 0 {
790+
lengthBootstrapFile = (((lengthBootstrapFile / 512) + 1) * 512)
791+
}
792+
793+
sasURL, err = CreatePageBlob(ctx, &CreatePageBlobInput{
794+
StorageURL: p.StorageURL,
795+
BlobURL: blobURL,
796+
ImageURL: "",
797+
StorageAccountName: p.StorageAccountName,
798+
BootstrapIgnData: bootstrapIgnData,
799+
ImageLength: lengthBootstrapFile,
800+
StorageAccountKeys: p.StorageAccountKeys,
801+
CloudConfiguration: cloudConfiguration,
802+
})
803+
if err != nil {
804+
return nil, fmt.Errorf("failed to create PageBlob for ignition shim: %w", err)
805+
}
781806
}
782807
ignShim, err := bootstrap.GenerateIgnitionShimWithCertBundleAndProxy(sasURL, in.InstallConfig.Config.AdditionalTrustBundle, in.InstallConfig.Config.Proxy)
783808
if err != nil {

pkg/infrastructure/azure/storage.go

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"fmt"
7+
"strings"
78
"sync"
89
"time"
910

@@ -222,6 +223,7 @@ type CreatePageBlobInput struct {
222223
BlobURL string
223224
ImageURL string
224225
StorageAccountName string
226+
BootstrapIgnData []byte
225227
ImageLength int64
226228
StorageAccountKeys []armstorage.AccountKey
227229
CloudConfiguration cloud.Configuration
@@ -234,13 +236,13 @@ type CreatePageBlobOutput struct {
234236
}
235237

236238
// CreatePageBlob creates a blob and uploads a file from a URL to it.
237-
func CreatePageBlob(ctx context.Context, in *CreatePageBlobInput) (*CreatePageBlobOutput, error) {
239+
func CreatePageBlob(ctx context.Context, in *CreatePageBlobInput) (string, error) {
238240
logrus.Debugf("Getting page blob credentials")
239241

240242
// XXX: Should try all of them until one is successful
241243
sharedKeyCredential, err := azblob.NewSharedKeyCredential(in.StorageAccountName, *in.StorageAccountKeys[0].Value)
242244
if err != nil {
243-
return nil, fmt.Errorf("failed to get shared credentials for storage account: %w", err)
245+
return "", fmt.Errorf("failed to get shared credentials for storage account: %w", err)
244246
}
245247

246248
logrus.Debugf("Getting page blob client")
@@ -254,30 +256,88 @@ func CreatePageBlob(ctx context.Context, in *CreatePageBlobInput) (*CreatePageBl
254256
},
255257
)
256258
if err != nil {
257-
return nil, fmt.Errorf("failed to get page blob client: %w", err)
259+
return "", fmt.Errorf("failed to get page blob client: %w", err)
258260
}
259261

260-
// This is used in terraform, not sure if it matters
261-
metadata := make(map[string]*string, 1)
262-
metadata["source_uri"] = to.Ptr(in.ImageURL)
262+
logrus.Debugf("Creating Page blob and uploading image to it")
263+
if in.ImageURL == "" {
264+
_, err = pageBlobClient.Create(ctx, in.ImageLength, nil)
265+
if err != nil {
266+
return "", fmt.Errorf("failed to create page blob with image contents: %w", err)
267+
}
268+
// This image (example: ignition shim) needs to be uploaded from a local file.
269+
err = doUploadPages(ctx, pageBlobClient, in.BootstrapIgnData, in.ImageLength)
270+
if err != nil {
271+
return "", fmt.Errorf("failed to upload page blob image contents: %w", err)
272+
}
273+
} else {
274+
// This is used in terraform, not sure if it matters
275+
metadata := map[string]*string{
276+
"source_uri": to.Ptr(in.ImageURL),
277+
}
278+
279+
_, err = pageBlobClient.Create(ctx, in.ImageLength, &pageblob.CreateOptions{
280+
Metadata: metadata,
281+
})
282+
if err != nil {
283+
return "", fmt.Errorf("failed to create page blob with image URL: %w", err)
284+
}
263285

264-
logrus.Debugf("Creating blob")
265-
_, err = pageBlobClient.Create(ctx, in.ImageLength, &pageblob.CreateOptions{
266-
Metadata: metadata,
267-
})
268-
if err != nil {
269-
return nil, fmt.Errorf("failed to create blob: %w", err)
286+
err = doUploadPagesFromURL(ctx, pageBlobClient, in.ImageURL, in.ImageLength)
287+
if err != nil {
288+
return "", fmt.Errorf("failed to upload page blob image from URL %s: %w", in.ImageURL, err)
289+
}
270290
}
271291

272-
logrus.Debugf("Uploading to blob")
273-
err = doUploadPagesFromURL(ctx, pageBlobClient, in.ImageURL, in.ImageLength)
292+
// Is this addition OK for when CreatePageBlob() is called from InfraReady()
293+
sasURL, err := pageBlobClient.GetSASURL(sas.BlobPermissions{Read: true}, time.Now().Add(time.Minute*60), &blob.GetSASURLOptions{})
274294
if err != nil {
275-
return nil, fmt.Errorf("failed to upload blob image %s: %w", in.ImageURL, err)
295+
return "", fmt.Errorf("failed to get Page Blob SAS URL: %w", err)
276296
}
277-
return &CreatePageBlobOutput{
278-
PageBlobClient: pageBlobClient,
279-
SharedKeyCredential: sharedKeyCredential,
280-
}, nil
297+
return sasURL, nil
298+
}
299+
300+
func doUploadPages(ctx context.Context, pageBlobClient *pageblob.Client, imageData []byte, imageLength int64) error {
301+
logrus.Debugf("Uploading to Page Blob with Image of length :%d", imageLength)
302+
303+
// Page blobs file size must be a multiple of 512, hence a little padding is needed to push the file.
304+
// imageLength has already been adjusted to the next highest size divisible by 512.
305+
// So, here we are padding the image to match this size.
306+
// Bootstrap Ignition is a json file. For parsing of this file to succeed with the padding, the
307+
// file needs to end with a }.
308+
logrus.Debugf("Original Image length: %d", int64(len(imageData)))
309+
padding := imageLength - int64(len(imageData))
310+
paddingString := strings.Repeat(" ", int(padding)) + string(imageData[len(imageData)-1])
311+
imageData = append(imageData[0:len(imageData)-1], paddingString...)
312+
logrus.Debugf("New Image length (after padding): %d", int64(len(imageData)))
313+
314+
pageSize := int64(1024 * 1024 * 4)
315+
newOffset := int64(0)
316+
remainingImageLength := imageLength
317+
318+
for remainingImageLength > 0 {
319+
if remainingImageLength < pageSize {
320+
pageSize = remainingImageLength
321+
}
322+
323+
logrus.Debugf("Uploading pages with Offset :%d and Count :%d", newOffset, pageSize)
324+
325+
_, err := pageBlobClient.UploadPages(
326+
ctx,
327+
streaming.NopCloser(bytes.NewReader(imageData)),
328+
blob.HTTPRange{
329+
Offset: newOffset,
330+
Count: pageSize,
331+
},
332+
nil)
333+
if err != nil {
334+
return fmt.Errorf("failed uploading Image to page blob: %w", err)
335+
}
336+
newOffset += pageSize
337+
remainingImageLength -= pageSize
338+
logrus.Debugf("newOffset :%d and remainingImageLength :%d", newOffset, remainingImageLength)
339+
}
340+
return nil
281341
}
282342

283343
func doUploadPagesFromURL(ctx context.Context, pageBlobClient *pageblob.Client, imageURL string, imageLength int64) error {

0 commit comments

Comments
 (0)