Skip to content

Commit ee51f04

Browse files
committed
chore: azure e2e
Add code to support azure e2e Signed-off-by: Noel Georgi <git@frezbo.dev>
1 parent 55dd41c commit ee51f04

10 files changed

Lines changed: 213 additions & 130 deletions

File tree

.drone.jsonnet

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -739,16 +739,17 @@ local integration_pipelines = [
739739
Pipeline('cron-integration-qemu-csi', default_pipeline_steps + [integration_qemu_csi], [default_cron_pipeline]) + cron_trigger(['nightly']),
740740
Pipeline('cron-integration-images', default_pipeline_steps + [integration_images], [default_cron_pipeline]) + cron_trigger(['nightly']),
741741
Pipeline('cron-integration-reproducibility-test', default_pipeline_steps + [integration_reproducibility_test], [default_cron_pipeline]) + cron_trigger(['nightly']),
742-
Pipeline('cron-image-factory', default_pipeline_steps + [
743-
integration_factory_16_iso,
744-
integration_factory_16_image,
745-
integration_factory_16_pxe,
746-
integration_factory_16_secureboot,
747-
integration_factory_15_iso,
748-
integration_factory_13_iso,
749-
integration_factory_13_image,
750-
],
751-
[default_cron_pipeline]) + cron_trigger(['nightly']),
742+
Pipeline('cron-image-factory',
743+
default_pipeline_steps + [
744+
integration_factory_16_iso,
745+
integration_factory_16_image,
746+
integration_factory_16_pxe,
747+
integration_factory_16_secureboot,
748+
integration_factory_15_iso,
749+
integration_factory_13_iso,
750+
integration_factory_13_image,
751+
],
752+
[default_cron_pipeline]) + cron_trigger(['nightly']),
752753
];
753754

754755

@@ -835,11 +836,75 @@ local E2EAWS(target) =
835836

836837
targets;
837838

839+
local E2EAzure() =
840+
local depends_on = [load_artifacts];
841+
842+
local e2e_azure_prepare = Step(
843+
'e2e-azure-prepare',
844+
depends_on=depends_on,
845+
environment=creds_env_vars {
846+
IMAGE_REGISTRY: local_registry,
847+
},
848+
extra_commands=[
849+
'az login --service-principal -u "$${AZURE_CLIENT_ID}" -p "$${AZURE_CLIENT_SECRET}" --tenant "$${AZURE_TENANT_ID}"',
850+
'az storage blob upload-batch --overwrite -s _out --pattern "e2e-azure-generated/*" -d "${CI_COMMIT_SHA}${DRONE_TAG//./-}"',
851+
]
852+
);
853+
854+
local tf_apply = TriggerDownstream(
855+
'tf-apply',
856+
'e2e-talos-tf-apply',
857+
['siderolabs/contrib@main'],
858+
params=[
859+
'BUCKET_PATH=${CI_COMMIT_SHA}${DRONE_TAG//./-}',
860+
'TYPE=azure',
861+
],
862+
depends_on=[e2e_azure_prepare],
863+
);
864+
865+
local e2e_azure_tf_apply_post = Step(
866+
'e2e-azure-download-artifacts',
867+
with_make=false,
868+
environment=creds_env_vars,
869+
extra_commands=[
870+
'az login --service-principal -u "$${AZURE_CLIENT_ID}" -p "$${AZURE_CLIENT_SECRET}" --tenant "$${AZURE_TENANT_ID}"',
871+
'az storage blob download -f _out/e2e-azure-talosconfig -n e2e-azure-talosconfig -c ${CI_COMMIT_SHA}${DRONE_TAG//./-}',
872+
'az storage blob download -f _out/e2e-azure-kubeconfig -n e2e-azure-kubeconfig -c ${CI_COMMIT_SHA}${DRONE_TAG//./-}',
873+
],
874+
depends_on=[tf_apply],
875+
);
876+
877+
local e2e_azure = Step(
878+
'e2e-azure',
879+
depends_on=[e2e_azure_tf_apply_post],
880+
environment=creds_env_vars {}
881+
);
882+
883+
local tf_destroy = TriggerDownstream(
884+
'tf-destroy',
885+
'e2e-talos-tf-destroy',
886+
['siderolabs/contrib@main'],
887+
params=[
888+
'BUCKET_PATH=${CI_COMMIT_SHA}${DRONE_TAG//./-}',
889+
'TYPE=azure',
890+
],
891+
depends_on=[e2e_azure],
892+
when={
893+
status: [
894+
'failure',
895+
'success',
896+
],
897+
},
898+
);
899+
900+
local targets = [e2e_azure_prepare, tf_apply, e2e_azure_tf_apply_post, e2e_azure, tf_destroy];
901+
902+
targets;
903+
838904

839905
local e2e_aws = [step for step in E2EAWS('default')];
840906
local e2e_aws_nvidia_oss = [step for step in E2EAWS('nvidia-oss')];
841-
842-
local e2e_azure = Step('e2e-azure', depends_on=[e2e_capi], environment=creds_env_vars);
907+
local e2e_azure = [step for step in E2EAzure()];
843908
local e2e_gcp = Step('e2e-gcp', depends_on=[e2e_capi], environment=creds_env_vars);
844909

845910
local e2e_trigger(names) = {
@@ -854,10 +919,12 @@ local e2e_pipelines = [
854919
// regular pipelines, triggered on promote events
855920
Pipeline('e2e-aws', default_pipeline_steps + e2e_aws) + e2e_trigger(['e2e-aws']),
856921
Pipeline('e2e-aws-nvidia-oss', default_pipeline_steps + e2e_aws_nvidia_oss) + e2e_trigger(['e2e-aws-nvidia-oss']),
922+
Pipeline('e2e-azure', default_pipeline_steps + e2e_azure) + e2e_trigger(['e2e-azure']),
857923
Pipeline('e2e-gcp', default_pipeline_steps + [capi_docker, e2e_capi, e2e_gcp]) + e2e_trigger(['e2e-gcp']),
858924

859925
// cron pipelines, triggered on schedule events
860926
Pipeline('cron-e2e-aws', default_pipeline_steps + e2e_aws, [default_cron_pipeline]) + cron_trigger(['thrice-daily', 'nightly']),
927+
Pipeline('cron-e2e-azure', default_pipeline_steps + e2e_azure, [default_cron_pipeline]) + cron_trigger(['thrice-daily', 'nightly']),
861928
Pipeline('cron-e2e-gcp', default_pipeline_steps + [capi_docker, e2e_capi, e2e_gcp], [default_cron_pipeline]) + cron_trigger(['thrice-daily', 'nightly']),
862929
];
863930

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ image-%: ## Builds the specified image. Valid options are aws, azure, digital-oc
370370
docker run --rm -t -v /dev:/dev -v $(PWD)/$(ARTIFACTS):/secureboot:ro -v $(PWD)/$(ARTIFACTS):/out --network=host --privileged $(REGISTRY_AND_USERNAME)/imager:$(IMAGE_TAG) $* --arch $$arch $(IMAGER_ARGS) ; \
371371
done
372372

373-
images-essential: image-aws image-gcp image-metal secureboot-installer ## Builds only essential images used in the CI (AWS, GCP, and Metal).
373+
images-essential: image-aws image-azure image-gcp image-metal secureboot-installer ## Builds only essential images used in the CI (AWS, GCP, and Metal).
374374

375375
images: image-aws image-azure image-digital-ocean image-exoscale image-gcp image-hcloud image-iso image-metal image-nocloud image-opennebula image-openstack image-oracle image-scaleway image-upcloud image-vmware image-vultr ## Builds all known images (AWS, Azure, DigitalOcean, Exoscale, GCP, HCloud, Metal, NoCloud, OpenNebula, Openstack, Oracle, Scaleway, UpCloud, Vultr and VMware).
376376

hack/cloud-image-uploader.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set -e
44

55
cd hack/cloud-image-uploader
66

7-
go run . --artifacts-path="../../${ARTIFACTS}" --tag="${TAG}" --abbrev-tag="${ABBREV_TAG}" "$@"
7+
go run . --artifacts-path="../../${ARTIFACTS}" --tag="${TAG}" "$@"

hack/cloud-image-uploader/azure.go

Lines changed: 60 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"github.com/Azure/go-autorest/autorest/azure/auth"
2828
"github.com/blang/semver/v4"
2929
"github.com/siderolabs/gen/channel"
30+
"github.com/siderolabs/gen/xslices"
3031
"github.com/ulikunitz/xz"
3132
"golang.org/x/sync/errgroup"
3233
)
@@ -47,29 +48,31 @@ var azureArchitectures = map[string]string{
4748
type AzureUploader struct {
4849
Options Options
4950

51+
preRelease bool
52+
5053
helper azureHelper
5154
}
5255

5356
// extractVersion extracts the version number in the format of int.int.int for Azure and assigns to the Options.AzureTag value.
5457
func (azu *AzureUploader) setVersion() error {
55-
v, err := semver.ParseTolerant(azu.Options.AzureAbbrevTag)
58+
v, err := semver.ParseTolerant(azu.Options.Tag)
5659
if err != nil {
5760
return err
5861
}
5962

6063
versionCore := fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
6164

62-
if fmt.Sprintf("v%s", versionCore) != azu.Options.AzureAbbrevTag {
65+
azu.helper.version = versionCore
66+
azu.Options.AzureGalleryName = "SideroLabs"
67+
68+
if fmt.Sprintf("v%s", versionCore) != azu.Options.Tag {
69+
azu.preRelease = true
6370
azu.Options.AzureGalleryName = "SideroGalleryTest"
64-
azu.Options.AzureCoreTag = versionCore
65-
fmt.Println(azu.Options.AzureGalleryName)
66-
} else {
67-
azu.Options.AzureGalleryName = "SideroLabs"
68-
azu.Options.AzureCoreTag = versionCore
69-
fmt.Println(azu.Options.AzureGalleryName)
7071
}
7172

72-
return err
73+
log.Println("azure: using Azure Gallery:", azu.Options.AzureGalleryName)
74+
75+
return nil
7376
}
7477

7578
// AzureGalleryUpload uploads the image to Azure.
@@ -91,11 +94,13 @@ func (azu *AzureUploader) AzureGalleryUpload(ctx context.Context) error {
9194
return fmt.Errorf("error setting default Azure credentials: %w", err)
9295
}
9396

94-
log.Printf("azure: getting locations")
97+
if len(azu.Options.AzureRegions) == 0 {
98+
regions, err := azu.helper.getAzureLocations(ctx)
99+
if err != nil {
100+
return fmt.Errorf("azure: error setting default Azure credentials: %w", err)
101+
}
95102

96-
err = azu.helper.getAzureLocations(ctx)
97-
if err != nil {
98-
return fmt.Errorf("azure: error setting default Azure credentials: %w", err)
103+
azu.Options.AzureRegions = regions
99104
}
100105

101106
// Upload blob
@@ -245,14 +250,16 @@ uploadLoop:
245250
}
246251

247252
func (azu *AzureUploader) createAzureImageVersion(ctx context.Context, arch string) error {
248-
targetRegions := make([]*armcompute.TargetRegion, 0, len(azu.helper.locations))
249-
250-
for _, region := range azu.helper.locations {
251-
targetRegions = append(targetRegions, &armcompute.TargetRegion{
252-
Name: to.Ptr(region.Name),
253-
ExcludeFromLatest: to.Ptr(false),
254-
RegionalReplicaCount: to.Ptr[int32](1),
255-
StorageAccountType: to.Ptr(armcompute.StorageAccountTypeStandardLRS),
253+
var targetRegions []*armcompute.TargetRegion
254+
255+
if !azu.preRelease {
256+
targetRegions = xslices.Map(azu.Options.AzureRegions, func(region string) *armcompute.TargetRegion {
257+
return &armcompute.TargetRegion{
258+
Name: to.Ptr(region),
259+
ExcludeFromLatest: to.Ptr(false),
260+
RegionalReplicaCount: to.Ptr[int32](1),
261+
StorageAccountType: to.Ptr(armcompute.StorageAccountTypeStandardLRS),
262+
}
256263
})
257264
}
258265

@@ -265,8 +272,8 @@ func (azu *AzureUploader) createAzureImageVersion(ctx context.Context, arch stri
265272
}
266273

267274
for _, v := range page.Value {
268-
if *v.Name == azu.Options.AzureCoreTag {
269-
log.Printf("azure: image version exists for %s\n azure: removing old image version\n", *v.Name)
275+
if *v.Name == azu.helper.version {
276+
log.Printf("azure: image version exists for %s\n", *v.Name)
270277

271278
err = azu.deleteImageVersion(ctx, arch)
272279
if err != nil {
@@ -283,7 +290,7 @@ func (azu *AzureUploader) createAzureImageVersion(ctx context.Context, arch stri
283290
resourceGroupName,
284291
azu.Options.AzureGalleryName,
285292
fmt.Sprintf("talos-%s", azureArchitectures[arch]),
286-
azu.Options.AzureCoreTag,
293+
azu.helper.version,
287294
armcompute.GalleryImageVersion{
288295
Location: to.Ptr(defaultRegion),
289296
Properties: &armcompute.GalleryImageVersionProperties{
@@ -309,21 +316,34 @@ func (azu *AzureUploader) createAzureImageVersion(ctx context.Context, arch stri
309316
return fmt.Errorf("azure: failed to create image version: %w", err)
310317
}
311318

312-
_, err = poller.PollUntilDone(ctx, nil)
319+
res, err := poller.PollUntilDone(ctx, nil)
313320
if err != nil {
314321
return fmt.Errorf("azure: failed to pull the result for image version creation: %w", err)
315322
}
316323

317-
return err
324+
for _, region := range azu.Options.AzureRegions {
325+
pushResult(CloudImage{
326+
Cloud: "azure",
327+
Tag: azu.Options.Tag,
328+
Region: region,
329+
Arch: arch,
330+
Type: "vhd",
331+
ID: *res.ID,
332+
})
333+
}
334+
335+
return nil
318336
}
319337

320338
func (azu *AzureUploader) deleteImageVersion(ctx context.Context, arch string) error {
339+
log.Println("azure: removing old image version")
340+
321341
poller, err := azu.helper.clientFactory.NewGalleryImageVersionsClient().BeginDelete(
322342
ctx,
323343
resourceGroupName,
324344
azu.Options.AzureGalleryName,
325345
fmt.Sprintf("talos-%s", azureArchitectures[arch]),
326-
azu.Options.AzureCoreTag,
346+
azu.helper.version,
327347
nil)
328348
if err != nil {
329349
return fmt.Errorf("azure: failed to delete image: %w", err)
@@ -334,16 +354,16 @@ func (azu *AzureUploader) deleteImageVersion(ctx context.Context, arch string) e
334354
return fmt.Errorf("azure: failed to pull the result for image deletion: %w", err)
335355
}
336356

337-
return err
357+
return nil
338358
}
339359

340360
type azureHelper struct {
361+
version string
341362
subscriptionID string
342363
clientFactory *armcompute.ClientFactory
343364
cred *azidentity.DefaultAzureCredential
344365
authorizer autorest.Authorizer
345366
providersClient resources.ProvidersClient
346-
locations map[string]Location
347367
}
348368

349369
func (helper *azureHelper) setDefaultAzureCreds() error {
@@ -385,52 +405,27 @@ func (helper *azureHelper) setDefaultAzureCreds() error {
385405
return nil
386406
}
387407

388-
//nolint:gocyclo
389-
func (helper *azureHelper) getAzureLocations(ctx context.Context) error {
390-
providers, err := helper.listProviders(ctx)
391-
if err != nil {
392-
return err
393-
}
394-
395-
var computeProvider resources.Provider
408+
func (helper *azureHelper) getAzureLocations(ctx context.Context) ([]string, error) {
409+
var regions []string
396410

397-
for _, provider := range providers {
398-
if provider.Namespace != nil && *provider.Namespace == "Microsoft.Compute" {
399-
computeProvider = provider
400-
401-
break
402-
}
411+
result, err := helper.providersClient.Get(ctx, "Microsoft.Compute", "")
412+
if err != nil {
413+
return nil, fmt.Errorf("azure: error getting Microsoft.Compute: %w", err)
403414
}
404415

405-
helper.locations = make(map[string]Location)
406-
407-
if computeProvider.ResourceTypes != nil {
408-
for _, rt := range *computeProvider.ResourceTypes {
416+
if result.ResourceTypes != nil {
417+
for _, rt := range *result.ResourceTypes {
409418
if rt.ResourceType != nil && *rt.ResourceType == "virtualMachines" {
410419
if rt.Locations != nil {
411-
for _, region := range *rt.Locations {
412-
abbr := strings.ReplaceAll(region, " ", "")
413-
abbr = strings.ToLower(abbr)
414-
helper.locations[abbr] = Location{Abbreviation: abbr, Name: region}
415-
}
420+
regions = xslices.Map(*rt.Locations, func(s string) string {
421+
return strings.ToLower(strings.ReplaceAll(s, " ", ""))
422+
})
416423
}
417424

418425
break
419426
}
420427
}
421428
}
422429

423-
return err
424-
}
425-
426-
func (helper *azureHelper) listProviders(ctx context.Context) (result []resources.Provider, err error) {
427-
for list, err := helper.providersClient.List(ctx, ""); list.NotDone(); err = list.NextWithContext(ctx) {
428-
if err != nil {
429-
return nil, fmt.Errorf("azure: error getting providers list: %v", err)
430-
}
431-
432-
result = append(result, list.Values()...)
433-
}
434-
435-
return
430+
return regions, nil
436431
}

0 commit comments

Comments
 (0)