Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions api/hypershift/v1beta1/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@ type AzureVMImage struct {
Type AzureVMImageType `json:"type"`

// imageID is the Azure resource ID of a VHD image to use to boot the Azure VMs from.
// TODO: What is the valid character set for this field? What about minimum and maximum lengths?
// The expected format is an Azure resource ID string. This can be a managed image or an
// Azure Compute Gallery image version, for example:
// /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}
// /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{imageDefinitionName}/versions/{imageVersionName}
// See https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules for
// Azure resource naming rules and restrictions.
//
// +optional
// +unionMember
Expand Down Expand Up @@ -166,28 +171,38 @@ type AzureMarketplaceImage struct {
ImageGeneration *AzureVMImageGeneration `json:"imageGeneration,omitempty"`

// publisher is the name of the organization that created the image.
// It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, and hyphens (-) and underscores (_).
// It must start with a lowercase letter or a number.
// TODO: Can we explain where a user might find this value, or provide an example of one they might want to use
// For example, "azureopenshift", "canonical", or "redhat".
// It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, hyphens (-), and underscores (_).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A real example would be helpful, maybe use quay.io/openshift-release-dev/ocp-release:4.21.10-x86_64

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Updated the publisher example from "redhat" to "azureopenshift", which is the publisher used for ARO (Azure Red Hat OpenShift) images throughout the codebase (e.g., in hypershift-operator/controllers/nodepool/azure_test.go and test/e2e/v2/tests/api_ux_validation_test.go).

Note: the quay.io/openshift-release-dev/ocp-release:4.21.10-x86_64 reference is a container release image, not an Azure Marketplace publisher — so I used the real ARO marketplace publisher instead.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Updated the publisher example to "azureopenshift" for Azure Red Hat OpenShift images (keeping "redhat" as a secondary example). These are real Azure Marketplace publisher names — the quay.io/openshift-release-dev/ocp-release:4.21.10-x86_64 reference is the OCP release payload container image, which is a different concept from Azure Marketplace image URN components (publisher/offer/sku/version). Users can verify these values with az vm image list-publishers --location <region>.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also looks like this must start with a lowercase alphanumeric character.

It also looks like ending with a hyphen/underscore would be allowed with the currently enforced regular expression. Is that actually valid?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch on both points.

  1. Starting character: Yes, the regex ^[a-z0-9][a-z0-9-_]{2,49}$ enforces starting with a lowercase alphanumeric, and the godoc already reflects this: "It must start with a lowercase letter or a number."

  2. Ending with hyphen/underscore: You're right — the current regex allows a trailing - or _, which is almost certainly not a valid Azure publisher name. All real publisher names in our codebase (azureopenshift, redhat) and in Azure's marketplace (canonical, microsoftwindowsserver) end with alphanumeric characters. We should tighten the regex to ^[a-z0-9][a-z0-9-_]*[a-z0-9]$ (with MinLength=3 still enforced separately) to require both the first and last characters to be alphanumeric.

I'll make this fix — good eye.


AI-assisted response via Claude Code

// It must start and end with a lowercase letter or a number.
// See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
// information on Azure Marketplace image publishers.
//
// +kubebuilder:validation:Pattern=`^[a-z0-9][a-z0-9-_]{2,49}$`
// +kubebuilder:validation:Pattern=`^[a-z0-9][a-z0-9-_]*[a-z0-9]$`
// +kubebuilder:validation:MinLength=3
// +kubebuilder:validation:MaxLength=50
// +optional
Publisher string `json:"publisher,omitempty"`

// offer specifies the name of a group of related images created by the publisher.
// TODO: What is the valid character set for this field? What about minimum and maximum lengths?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the valid character set TODO here wasn't resolved. Is there a particular pattern that should be enforced here to ensure only inputs that resemble a valid offer name are provided?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point — the valid character set TODO wasn't fully resolved because Azure doesn't publish a strict regex for offer names, and the upstream CAPZ ImagePlan.Offer field also has no pattern validation (just MinLength=1).

Looking at real Azure Marketplace offer names, they can include mixed-case letters — e.g., CAPZ's own examples are UbuntuServer and WindowsServer (see vendor/sigs.k8s.io/cluster-api-provider-azure/api/v1beta1/types.go:493). Our codebase uses aro4 (lowercase), but enforcing only lowercase would break users with non-ARO marketplace images.

A reasonable approach would be to add a permissive pattern like ^[a-zA-Z0-9][a-zA-Z0-9-_.]*[a-zA-Z0-9]$ (alphanumeric start/end, allow letters, numbers, hyphens, underscores, and dots in between) — similar to what we see in real Azure offer names. Alternatively, we could follow CAPZ's lead and rely on Azure's own API validation to reject invalid names, keeping just the length constraints.

I'll add a pattern that matches the known Azure conventions. Let me know if you'd prefer a specific approach.


AI-assisted response via Claude Code

//
// For example, "RHEL", "WindowsServer", or "0001-com-ubuntu-server-jammy".
// The value must consist of only alphanumeric characters (a-z, A-Z, 0-9),
// hyphens (-), underscores (_), and periods (.).
// It must start with an alphanumeric character.
// See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
// information on Azure Marketplace image offers.
//
// +kubebuilder:validation:XValidation:rule="self.matches('^[a-zA-Z0-9][a-zA-Z0-9._-]*$')",message="offer must consist of alphanumeric characters, hyphens, underscores, and periods, and must start with an alphanumeric character"
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=255
// +optional
Offer string `json:"offer,omitempty"`

// sku specifies an instance of an offer, such as a major release of a distribution.
// For example, 22_04-lts-gen2, 8-lvm-gen2.
// The value must consist only of lowercase letters, numbers, and hyphens (-) and underscores (_).
// TODO: What about length limits?
// The value must be between 1 and 255 characters in length, and consist of only lowercase
// letters, numbers, hyphens (-), and underscores (_).
// See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
// information on Azure Marketplace image SKUs.
//
// +kubebuilder:validation:Pattern=`^[a-z0-9-_]+$`
// +kubebuilder:validation:MinLength=1
Expand Down

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we incorporate the changes in #8223 in this PR and then close #8223?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Incorporated all changes from #8223 into this PR:

  • imageID: Resolved the TODO with Azure resource ID format documentation and examples
  • publisher: Added learn.microsoft.com link and more examples (azureopenshift, canonical, redhat)
  • offer: Switched from Pattern to XValidation with self.matches() for better CEL error messages, added learn.microsoft.com link and real examples (RHEL, WindowsServer, 0001-com-ubuntu-server-jammy)
  • sku: Added learn.microsoft.com link
  • tests: Added envtest test cases for offer field character validation (invalid chars, hyphen-start, valid mixed chars)

PR #8223 can be closed once this is merged.


AI-assisted response via Claude Code

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hypershift you did not incorporate the changes here so you need to do that

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Incorporated all changes from #8223:

  • Resolved imageID TODO with Azure resource ID format docs and examples
  • Replaced Azure CLI references with Microsoft Learn documentation links across publisher, offer, and sku fields
  • Switched offer validation from kubebuilder:validation:Pattern to XValidation (CEL) for better error messages
  • Added multiple examples for publisher ("azureopenshift", "canonical", "redhat")
  • Added envtest test cases for offer field character validation
  • Regenerated CRDs, vendor, and docs

AI-assisted response via Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The changes from #8223 were incorporated in commit 9f2c384 — imageID format docs, Microsoft Learn links for publisher/offer/sku, CEL validation for the offer field, and additional publisher examples.


AI-assisted response via Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The changes from #8223 were incorporated in commit 9f2c384 — imageID documentation, publisher examples and learn.microsoft.com links, offer validation and docs, and SKU length documentation. Also regenerated the missing OSStreams.yaml CRD variant and docs.


AI-assisted response via Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. All changes from #8223 are incorporated: imageID format docs, publisher examples and learn.microsoft.com links, offer CEL validation pattern, and SKU length documentation. Additionally, the publisher regex was tightened to require ending with alphanumeric (^[a-z0-9][a-z0-9-_]*[a-z0-9]$) per @everettraven's feedback. The make verify now passes cleanly.


AI-assisted response via Claude Code

Original file line number Diff line number Diff line change
Expand Up @@ -837,25 +837,42 @@ spec:
- Gen2
type: string
offer:
description: offer specifies the name of a group of
related images created by the publisher.
description: |-
offer specifies the name of a group of related images created by the publisher.
For example, "RHEL", "WindowsServer", or "0001-com-ubuntu-server-jammy".
The value must consist of only alphanumeric characters (a-z, A-Z, 0-9),
hyphens (-), underscores (_), and periods (.).
It must start with an alphanumeric character.
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image offers.
maxLength: 255
minLength: 1
type: string
x-kubernetes-validations:
- message: offer must consist of alphanumeric characters,
hyphens, underscores, and periods, and must start
with an alphanumeric character
rule: self.matches('^[a-zA-Z0-9][a-zA-Z0-9._-]*$')
publisher:
description: |-
publisher is the name of the organization that created the image.
It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, and hyphens (-) and underscores (_).
It must start with a lowercase letter or a number.
For example, "azureopenshift", "canonical", or "redhat".
It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, hyphens (-), and underscores (_).
It must start and end with a lowercase letter or a number.
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image publishers.
maxLength: 50
minLength: 3
pattern: ^[a-z0-9][a-z0-9-_]{2,49}$
pattern: ^[a-z0-9][a-z0-9-_]*[a-z0-9]$
type: string
sku:
description: |-
sku specifies an instance of an offer, such as a major release of a distribution.
For example, 22_04-lts-gen2, 8-lvm-gen2.
The value must consist only of lowercase letters, numbers, and hyphens (-) and underscores (_).
The value must be between 1 and 255 characters in length, and consist of only lowercase
letters, numbers, hyphens (-), and underscores (_).
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image SKUs.
maxLength: 255
minLength: 1
pattern: ^[a-z0-9-_]+$
Expand Down Expand Up @@ -884,8 +901,14 @@ spec:
has(self.version)].filter(x, x == true).size() ==
4'
imageID:
description: imageID is the Azure resource ID of a VHD
image to use to boot the Azure VMs from.
description: |-
imageID is the Azure resource ID of a VHD image to use to boot the Azure VMs from.
The expected format is an Azure resource ID string. This can be a managed image or an
Azure Compute Gallery image version, for example:
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{imageDefinitionName}/versions/{imageVersionName}
See https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules for
Azure resource naming rules and restrictions.
maxLength: 255
type: string
type:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -837,25 +837,42 @@ spec:
- Gen2
type: string
offer:
description: offer specifies the name of a group of
related images created by the publisher.
description: |-
offer specifies the name of a group of related images created by the publisher.
For example, "RHEL", "WindowsServer", or "0001-com-ubuntu-server-jammy".
The value must consist of only alphanumeric characters (a-z, A-Z, 0-9),
hyphens (-), underscores (_), and periods (.).
It must start with an alphanumeric character.
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image offers.
maxLength: 255
minLength: 1
type: string
x-kubernetes-validations:
- message: offer must consist of alphanumeric characters,
hyphens, underscores, and periods, and must start
with an alphanumeric character
rule: self.matches('^[a-zA-Z0-9][a-zA-Z0-9._-]*$')
publisher:
description: |-
publisher is the name of the organization that created the image.
It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, and hyphens (-) and underscores (_).
It must start with a lowercase letter or a number.
For example, "azureopenshift", "canonical", or "redhat".
It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, hyphens (-), and underscores (_).
It must start and end with a lowercase letter or a number.
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image publishers.
maxLength: 50
minLength: 3
pattern: ^[a-z0-9][a-z0-9-_]{2,49}$
pattern: ^[a-z0-9][a-z0-9-_]*[a-z0-9]$
type: string
sku:
description: |-
sku specifies an instance of an offer, such as a major release of a distribution.
For example, 22_04-lts-gen2, 8-lvm-gen2.
The value must consist only of lowercase letters, numbers, and hyphens (-) and underscores (_).
The value must be between 1 and 255 characters in length, and consist of only lowercase
letters, numbers, hyphens (-), and underscores (_).
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image SKUs.
maxLength: 255
minLength: 1
pattern: ^[a-z0-9-_]+$
Expand Down Expand Up @@ -884,8 +901,14 @@ spec:
has(self.version)].filter(x, x == true).size() ==
4'
imageID:
description: imageID is the Azure resource ID of a VHD
image to use to boot the Azure VMs from.
description: |-
imageID is the Azure resource ID of a VHD image to use to boot the Azure VMs from.
The expected format is an Azure resource ID string. This can be a managed image or an
Azure Compute Gallery image version, for example:
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{imageDefinitionName}/versions/{imageVersionName}
See https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules for
Azure resource naming rules and restrictions.
maxLength: 255
type: string
type:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -870,25 +870,42 @@ spec:
- Gen2
type: string
offer:
description: offer specifies the name of a group of
related images created by the publisher.
description: |-
offer specifies the name of a group of related images created by the publisher.
For example, "RHEL", "WindowsServer", or "0001-com-ubuntu-server-jammy".
The value must consist of only alphanumeric characters (a-z, A-Z, 0-9),
hyphens (-), underscores (_), and periods (.).
It must start with an alphanumeric character.
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image offers.
maxLength: 255
minLength: 1
type: string
x-kubernetes-validations:
- message: offer must consist of alphanumeric characters,
hyphens, underscores, and periods, and must start
with an alphanumeric character
rule: self.matches('^[a-zA-Z0-9][a-zA-Z0-9._-]*$')
publisher:
description: |-
publisher is the name of the organization that created the image.
It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, and hyphens (-) and underscores (_).
It must start with a lowercase letter or a number.
For example, "azureopenshift", "canonical", or "redhat".
It must be between 3 and 50 characters in length, and consist of only lowercase letters, numbers, hyphens (-), and underscores (_).
It must start and end with a lowercase letter or a number.
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image publishers.
maxLength: 50
minLength: 3
pattern: ^[a-z0-9][a-z0-9-_]{2,49}$
pattern: ^[a-z0-9][a-z0-9-_]*[a-z0-9]$
type: string
sku:
description: |-
sku specifies an instance of an offer, such as a major release of a distribution.
For example, 22_04-lts-gen2, 8-lvm-gen2.
The value must consist only of lowercase letters, numbers, and hyphens (-) and underscores (_).
The value must be between 1 and 255 characters in length, and consist of only lowercase
letters, numbers, hyphens (-), and underscores (_).
See https://learn.microsoft.com/en-us/azure/virtual-machines/linux/cli-ps-findimage for more
information on Azure Marketplace image SKUs.
maxLength: 255
minLength: 1
pattern: ^[a-z0-9-_]+$
Expand Down Expand Up @@ -917,8 +934,14 @@ spec:
has(self.version)].filter(x, x == true).size() ==
4'
imageID:
description: imageID is the Azure resource ID of a VHD
image to use to boot the Azure VMs from.
description: |-
imageID is the Azure resource ID of a VHD image to use to boot the Azure VMs from.
The expected format is an Azure resource ID string. This can be a managed image or an
Azure Compute Gallery image version, for example:
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/images/{imageName}
/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/galleries/{galleryName}/images/{imageDefinitionName}/versions/{imageVersionName}
See https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules for
Azure resource naming rules and restrictions.
maxLength: 255
type: string
type:
Expand Down
Loading
Loading