Skip to content

Commit

Permalink
Merge pull request #291 from justaugustus/image-ref
Browse files Browse the repository at this point in the history
✨ Support specifying VM images by ID or from Shared Image Gallery
  • Loading branch information
k8s-ci-robot authored Oct 7, 2019
2 parents 2688c11 + 79c3d1b commit 7f17ca1
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 48 deletions.
24 changes: 19 additions & 5 deletions api/v1alpha2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,25 @@ type AvailabilityZone struct {
Enabled *bool `json:"enabled,omitempty"`
}

// Image defines information about the image to use for VM creation.
// There are three ways to specify an image: by ID, by publisher, or by Shared Image Gallery.
// If specifying an image by ID, only the ID field needs to be set.
// If specifying an image by publisher, the Publisher, Offer, SKU, and Version fields must be set.
// If specifying an image from a Shared Image Gallery, the SubscriptionID, ResourceGroup,
// Gallery, Name, and Version fields must be set.
type Image struct {
Publisher string `json:"publisher"`
Offer string `json:"offer"`
SKU string `json:"sku"`
Version string `json:"version"`
Publisher *string `json:"publisher,omitempty"`
Offer *string `json:"offer,omitempty"`
SKU *string `json:"sku,omitempty"`

ID *string `json:"id,omitempty"`

SubscriptionID *string `json:"subscriptionID,omitempty"`
ResourceGroup *string `json:"resourceGroup,omitempty"`
Gallery *string `json:"gallery,omitempty"`
Name *string `json:"name,omitempty"`

Version *string `json:"version,omitempty"`
}

// APIEndpoint represents a reachable Kubernetes API endpoint.
Expand All @@ -427,8 +441,8 @@ type VMIdentity string

type OSDisk struct {
OSType string `json:"osType"`
ManagedDisk ManagedDisk `json:"managedDisk"`
DiskSizeGB int32 `json:"diskSizeGB"`
ManagedDisk ManagedDisk `json:"managedDisk"`
}

type ManagedDisk struct {
Expand Down
51 changes: 48 additions & 3 deletions api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion cloud/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ limitations under the License.

package azure

import "fmt"
import (
"fmt"
)

const (
// DefaultUserName is the default username for created vm
Expand Down
108 changes: 91 additions & 17 deletions cloud/services/virtualmachines/virtualmachines.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error {
return errors.New("invalid vm specification")
}

storageProfile, err := generateStorageProfile(*vmSpec)
if err != nil {
return err
}

klog.V(2).Infof("getting nic %s", vmSpec.NICName)
nicInterface, err := networkinterfaces.NewService(s.Scope).Get(ctx, &networkinterfaces.Spec{Name: vmSpec.NICName})
if err != nil {
Expand Down Expand Up @@ -108,23 +113,7 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error {
HardwareProfile: &compute.HardwareProfile{
VMSize: compute.VirtualMachineSizeTypes(vmSpec.Size),
},
StorageProfile: &compute.StorageProfile{
ImageReference: &compute.ImageReference{
Publisher: to.StringPtr(vmSpec.Image.Publisher),
Offer: to.StringPtr(vmSpec.Image.Offer),
Sku: to.StringPtr(vmSpec.Image.SKU),
Version: to.StringPtr(vmSpec.Image.Version),
},
OsDisk: &compute.OSDisk{
Name: to.StringPtr(azure.GenerateOSDiskName(vmSpec.Name)),
OsType: compute.OperatingSystemTypes(vmSpec.OSDisk.OSType),
CreateOption: compute.DiskCreateOptionTypesFromImage,
DiskSizeGB: to.Int32Ptr(vmSpec.OSDisk.DiskSizeGB),
ManagedDisk: &compute.ManagedDiskParameters{
StorageAccountType: compute.StorageAccountTypes(vmSpec.OSDisk.ManagedDisk.StorageAccountType),
},
},
},
StorageProfile: storageProfile,
OsProfile: &compute.OSProfile{
ComputerName: to.StringPtr(vmSpec.Name),
AdminUsername: to.StringPtr(azure.DefaultUserName),
Expand Down Expand Up @@ -211,6 +200,91 @@ func (s *Service) Delete(ctx context.Context, spec interface{}) error {
return err
}

// generateStorageProfile generates a pointer to a compute.StorageProfile which can utilized for VM creation.
func generateStorageProfile(vmSpec Spec) (*compute.StorageProfile, error) {
// TODO: Validate parameters before building storage profile
storageProfile := &compute.StorageProfile{
OsDisk: &compute.OSDisk{
Name: to.StringPtr(azure.GenerateOSDiskName(vmSpec.Name)),
OsType: compute.OperatingSystemTypes(vmSpec.OSDisk.OSType),
CreateOption: compute.DiskCreateOptionTypesFromImage,
DiskSizeGB: to.Int32Ptr(vmSpec.OSDisk.DiskSizeGB),
ManagedDisk: &compute.ManagedDiskParameters{
StorageAccountType: compute.StorageAccountTypes(vmSpec.OSDisk.ManagedDisk.StorageAccountType),
},
},
}

imageRef, err := generateImageReference(vmSpec.Image)
if err != nil {
return nil, err
}

storageProfile.ImageReference = imageRef

return storageProfile, nil
}

// generateImageReference generates a pointer to a compute.ImageReference which can utilized for VM creation.
func generateImageReference(image infrav1.Image) (*compute.ImageReference, error) {
imageRef := &compute.ImageReference{}

if image.ID != nil {
imageRef.ID = to.StringPtr(*image.ID)

// return early since we should only need the image ID
return imageRef, nil
} else if image.SubscriptionID != nil && image.ResourceGroup != nil && image.Gallery != nil && image.Name != nil && image.Version != nil {
imageID, err := generateImageID(image)
if err != nil {
return nil, err
}

imageRef.ID = to.StringPtr(imageID)

// return early since we're referencing an image that may not be published
return imageRef, nil
}

if image.Publisher != nil {
imageRef.Publisher = image.Publisher
}
if image.Offer != nil {
imageRef.Offer = image.Offer
}
if image.SKU != nil {
imageRef.Sku = image.SKU
}
if image.Version != nil {
imageRef.Version = image.Version

return imageRef, nil
}

return nil, errors.Errorf("Image reference cannot be generated, as fields are missing: %+v", *imageRef)
}

// generateImageID generates the resource ID for an image stored in an Azure Shared Image Gallery.
func generateImageID(image infrav1.Image) (string, error) {
if image.SubscriptionID == nil {
return "", errors.New("Image subscription ID cannot be nil when specifying an image from an Azure Shared Image Gallery")
}
if image.ResourceGroup == nil {
return "", errors.New("Image resource group cannot be nil when specifying an image from an Azure Shared Image Gallery")
}
if image.Gallery == nil {
return "", errors.New("Image gallery cannot be nil when specifying an image from an Azure Shared Image Gallery")
}
if image.Name == nil {
return "", errors.New("Image name cannot be nil when specifying an image from an Azure Shared Image Gallery")
}
if image.Version == nil {
return "", errors.New("Image version cannot be nil when specifying an image from an Azure Shared Image Gallery")
}

return fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/galleries/%s/images/%s/versions/%s", *image.SubscriptionID, *image.ResourceGroup, *image.Gallery, *image.Name, *image.Version), nil
}

// GenerateRandomString returns a URL-safe, base64 encoded
// securely generated random string.
// It will return an error if the system's secure random
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,24 @@ spec:
image:
description: Storage profile
properties:
gallery:
type: string
id:
type: string
name:
type: string
offer:
type: string
publisher:
type: string
resourceGroup:
type: string
sku:
type: string
subscriptionID:
type: string
version:
type: string
required:
- offer
- publisher
- sku
- version
type: object
name:
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,32 @@ spec:
type: string
type: object
image:
description: 'Image defines information about the image to use for VM
creation. There are three ways to specify an image: by ID, by publisher,
or by Shared Image Gallery. If specifying an image by ID, only the
ID field needs to be set. If specifying an image by publisher, the
Publisher, Offer, SKU, and Version fields must be set. If specifying
an image from a Shared Image Gallery, the SubscriptionID, ResourceGroup,
Gallery, Name, and Version fields must be set.'
properties:
gallery:
type: string
id:
type: string
name:
type: string
offer:
type: string
publisher:
type: string
resourceGroup:
type: string
sku:
type: string
subscriptionID:
type: string
version:
type: string
required:
- offer
- publisher
- sku
- version
type: object
location:
type: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,33 @@ spec:
type: string
type: object
image:
description: 'Image defines information about the image to use
for VM creation. There are three ways to specify an image:
by ID, by publisher, or by Shared Image Gallery. If specifying
an image by ID, only the ID field needs to be set. If specifying
an image by publisher, the Publisher, Offer, SKU, and Version
fields must be set. If specifying an image from a Shared Image
Gallery, the SubscriptionID, ResourceGroup, Gallery, Name,
and Version fields must be set.'
properties:
gallery:
type: string
id:
type: string
name:
type: string
offer:
type: string
publisher:
type: string
resourceGroup:
type: string
sku:
type: string
subscriptionID:
type: string
version:
type: string
required:
- offer
- publisher
- sku
- version
type: object
location:
type: string
Expand Down
6 changes: 3 additions & 3 deletions examples/controlplane/controlplane.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ spec:
version: "latest"
osDisk:
osType: "Linux"
diskSizeGB: 30
managedDisk:
storageAccountType: "Premium_LRS"
diskSizeGB: 30
sshPublicKey: ${SSH_PUBLIC_KEY}
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
Expand Down Expand Up @@ -189,9 +189,9 @@ spec:
version: "latest"
osDisk:
osType: "Linux"
diskSizeGB: 30
managedDisk:
storageAccountType: "Premium_LRS"
diskSizeGB: 30
sshPublicKey: ${SSH_PUBLIC_KEY}
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
Expand Down Expand Up @@ -325,9 +325,9 @@ spec:
version: "latest"
osDisk:
osType: "Linux"
diskSizeGB: 30
managedDisk:
storageAccountType: "Premium_LRS"
diskSizeGB: 30
sshPublicKey: ${SSH_PUBLIC_KEY}
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
Expand Down
Loading

0 comments on commit 7f17ca1

Please sign in to comment.