Skip to content

Commit b62341b

Browse files
authored
Merge pull request #777 from alexeldeib/ace/ephemeral
✨ implement ephemeral os
2 parents 87f35a2 + 0aa24fa commit b62341b

24 files changed

+593
-31
lines changed

api/v1alpha2/azurecluster_conversion.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func (src *AzureCluster) ConvertTo(dstRaw conversion.Hub) error { // nolint
5959
}
6060

6161
dst.Status.FailureDomains = restored.Status.FailureDomains
62+
dst.Status.Bastion.OSDisk.DiffDiskSettings = restored.Status.Bastion.OSDisk.DiffDiskSettings
6263

6364
for _, restoredSubnet := range restored.Spec.NetworkSpec.Subnets {
6465
if restoredSubnet != nil {

api/v1alpha2/azuremachine_conversion.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package v1alpha2
1919
import (
2020
apiconversion "k8s.io/apimachinery/pkg/conversion"
2121
infrav1alpha3 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3"
22+
v1alpha3 "sigs.k8s.io/cluster-api-provider-azure/api/v1alpha3"
2223
utilconversion "sigs.k8s.io/cluster-api/util/conversion"
2324
"sigs.k8s.io/controller-runtime/pkg/conversion"
2425
)
@@ -62,6 +63,7 @@ func restoreAzureMachineSpec(restored, dst *infrav1alpha3.AzureMachineSpec) {
6263
if len(restored.DataDisks) != 0 {
6364
dst.DataDisks = restored.DataDisks
6465
}
66+
dst.OSDisk.DiffDiskSettings = restored.OSDisk.DiffDiskSettings
6567
}
6668

6769
// ConvertFrom converts from the Hub version (v1alpha3) to this version.
@@ -186,6 +188,11 @@ func Convert_v1alpha3_Image_To_v1alpha2_Image(in *infrav1alpha3.Image, out *Imag
186188
return nil
187189
}
188190

191+
// Convert_v1alpha3_OSDisk_To_v1alpha2_OSDisk converts between api versions
192+
func Convert_v1alpha3_OSDisk_To_v1alpha2_OSDisk(in *v1alpha3.OSDisk, out *OSDisk, s apiconversion.Scope) error {
193+
return autoConvert_v1alpha3_OSDisk_To_v1alpha2_OSDisk(in, out, s)
194+
}
195+
189196
func isAzureMarketPlaceImage(in *Image) bool {
190197
if in.Publisher == nil || in.Offer == nil || in.SKU == nil || in.Version == nil {
191198
return false

api/v1alpha2/zz_generated.conversion.go

Lines changed: 6 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1alpha3/azuremachine_validation.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,76 @@ func ValidateOSDisk(osDisk OSDisk, fieldPath *field.Path) field.ErrorList {
102102

103103
allErrs = append(allErrs, validateStorageAccountType(osDisk.ManagedDisk.StorageAccountType, fieldPath)...)
104104

105+
if errs := ValidateManagedDisk(osDisk.ManagedDisk, osDisk.ManagedDisk, fieldPath.Child("managedDisk")); len(errs) > 0 {
106+
allErrs = append(allErrs, errs...)
107+
}
108+
109+
if err := validateDiffDiskSetings(osDisk.DiffDiskSettings, fieldPath.Child("diffDiskSettings")); err != nil {
110+
allErrs = append(allErrs, err)
111+
}
112+
113+
if osDisk.DiffDiskSettings != nil && osDisk.DiffDiskSettings.Option == string(compute.Local) && osDisk.ManagedDisk.StorageAccountType != "Standard_LRS" {
114+
allErrs = append(allErrs, field.Invalid(
115+
fieldPath.Child("managedDisks").Child("storageAccountType"),
116+
osDisk.ManagedDisk.StorageAccountType,
117+
"storageAccountType must be Standard_LRS when diffDiskSettings.option is 'Local'",
118+
))
119+
}
120+
121+
return allErrs
122+
}
123+
124+
// ValidateManagedDisk validates updates to the ManagedDisk field.
125+
func ValidateManagedDisk(old, new ManagedDisk, fieldPath *field.Path) field.ErrorList {
126+
allErrs := field.ErrorList{}
127+
128+
if old.StorageAccountType != new.StorageAccountType {
129+
allErrs = append(allErrs, field.Invalid(fieldPath.Child("storageAccountType"), new, "changing storage account type after machine creation is not allowed"))
130+
}
131+
132+
return allErrs
133+
}
134+
135+
func validateDiffDiskSetings(d *DiffDiskSettings, fldPath *field.Path) *field.Error {
136+
if d != nil {
137+
if d.Option != string(compute.Local) {
138+
return field.Invalid(
139+
fldPath.Child("option"),
140+
d,
141+
fmt.Sprintf("changing ephemeral os settings after machine creation is not allowed"),
142+
)
143+
}
144+
}
145+
return nil
146+
}
147+
148+
func validateDiffDiskSettingsUpdate(old, new *DiffDiskSettings, fieldPath *field.Path) field.ErrorList {
149+
allErrs := field.ErrorList{}
150+
fldPath := fieldPath.Child("diffDiskSettings")
151+
152+
if old == nil && new != nil {
153+
allErrs = append(allErrs, field.Invalid(fldPath, new, fmt.Sprintf("enabling ephemeral os after machine creation is not allowed")))
154+
return allErrs
155+
}
156+
if old != nil && new == nil {
157+
allErrs = append(allErrs, field.Invalid(fldPath, new, fmt.Sprintf("disabling ephemeral os after machine creation is not allowed")))
158+
return allErrs
159+
}
160+
161+
if old != nil && new != nil {
162+
if old.Option != new.Option {
163+
allErrs = append(
164+
allErrs,
165+
field.Invalid(
166+
fldPath.Child("option"),
167+
new,
168+
fmt.Sprintf("changing ephemeral os settings after machine creation is not allowed"),
169+
),
170+
)
171+
return allErrs
172+
}
173+
}
174+
105175
return allErrs
106176
}
107177

api/v1alpha3/azuremachine_validation_test.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ import (
2020
"crypto/rand"
2121
"crypto/rsa"
2222
"encoding/base64"
23-
"github.com/Azure/go-autorest/autorest/to"
23+
"fmt"
2424
"testing"
2525

26+
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-01/compute"
27+
"github.com/Azure/go-autorest/autorest/to"
28+
2629
. "github.com/onsi/gomega"
2730
"golang.org/x/crypto/ssh"
2831
"k8s.io/apimachinery/pkg/util/validation/field"
@@ -81,6 +84,20 @@ func TestAzureMachine_ValidateOSDisk(t *testing.T) {
8184
wantErr: false,
8285
osDisk: generateValidOSDisk(),
8386
},
87+
{
88+
name: "valid ephemeral os disk spec",
89+
wantErr: false,
90+
osDisk: OSDisk{
91+
DiskSizeGB: 30,
92+
OSType: "blah",
93+
DiffDiskSettings: &DiffDiskSettings{
94+
Option: string(compute.Local),
95+
},
96+
ManagedDisk: ManagedDisk{
97+
StorageAccountType: "Standard_LRS",
98+
},
99+
},
100+
},
84101
}
85102
testcases = append(testcases, generateNegativeTestCases()...)
86103

@@ -137,11 +154,21 @@ func generateNegativeTestCases() []osDiskTestInput {
137154
StorageAccountType: "invalid_type",
138155
},
139156
},
157+
{
158+
DiskSizeGB: 30,
159+
OSType: "blah",
160+
ManagedDisk: ManagedDisk{
161+
StorageAccountType: "Premium_LRS",
162+
},
163+
DiffDiskSettings: &DiffDiskSettings{
164+
Option: string(compute.Local),
165+
},
166+
},
140167
}
141168

142-
for _, input := range invalidDiskSpecs {
169+
for i, input := range invalidDiskSpecs {
143170
inputs = append(inputs, osDiskTestInput{
144-
name: testCaseName,
171+
name: fmt.Sprintf("%s-%d", testCaseName, i),
145172
wantErr: true,
146173
osDisk: input,
147174
})
@@ -159,7 +186,6 @@ func generateValidOSDisk() OSDisk {
159186
},
160187
}
161188
}
162-
163189
func TestAzureMachine_ValidateDataDisks(t *testing.T) {
164190
g := NewWithT(t)
165191

api/v1alpha3/azuremachine_webhook.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,12 @@ func (m *AzureMachine) ValidateCreate() error {
7171
}
7272

7373
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
74-
func (m *AzureMachine) ValidateUpdate(old runtime.Object) error {
74+
func (m *AzureMachine) ValidateUpdate(oldRaw runtime.Object) error {
7575
machinelog.Info("validate update", "name", m.Name)
7676
var allErrs field.ErrorList
7777

78+
old := oldRaw.(*AzureMachine)
79+
7880
if errs := ValidateSSHKey(m.Spec.SSHPublicKey, field.NewPath("sshPublicKey")); len(errs) > 0 {
7981
allErrs = append(allErrs, errs...)
8082
}
@@ -87,6 +89,14 @@ func (m *AzureMachine) ValidateUpdate(old runtime.Object) error {
8789
allErrs = append(allErrs, errs...)
8890
}
8991

92+
if errs := ValidateManagedDisk(old.Spec.OSDisk.ManagedDisk, m.Spec.OSDisk.ManagedDisk, field.NewPath("osDisk").Child("managedDisk")); len(errs) > 0 {
93+
allErrs = append(allErrs, errs...)
94+
}
95+
96+
if errs := validateDiffDiskSettingsUpdate(old.Spec.OSDisk.DiffDiskSettings, m.Spec.OSDisk.DiffDiskSettings, field.NewPath("osDisk").Child("diffDiskSettings")); len(errs) > 0 {
97+
allErrs = append(allErrs, errs...)
98+
}
99+
90100
if len(allErrs) == 0 {
91101
return nil
92102
}

api/v1alpha3/types.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,10 @@ type UserAssignedIdentity struct {
307307

308308
// OSDisk defines the operating system disk for a VM.
309309
type OSDisk struct {
310-
OSType string `json:"osType"`
311-
DiskSizeGB int32 `json:"diskSizeGB"`
312-
ManagedDisk ManagedDisk `json:"managedDisk"`
310+
OSType string `json:"osType"`
311+
DiskSizeGB int32 `json:"diskSizeGB"`
312+
ManagedDisk ManagedDisk `json:"managedDisk"`
313+
DiffDiskSettings *DiffDiskSettings `json:"diffDiskSettings,omitempty"`
313314
}
314315

315316
// DataDisk specifies the parameters that are used to add one or more data disks to the machine.
@@ -329,6 +330,14 @@ type ManagedDisk struct {
329330
StorageAccountType string `json:"storageAccountType"`
330331
}
331332

333+
// DiffDiskSettings describe ephemeral disk settings for the os disk.
334+
type DiffDiskSettings struct {
335+
// Option enables ephemeral OS when set to "Local"
336+
// See https://docs.microsoft.com/en-us/azure/virtual-machines/linux/ephemeral-os-disks for full details
337+
// +kubebuilder:validation:Enum=Local
338+
Option string `json:"option"`
339+
}
340+
332341
// SubnetRole defines the unique role of a subnet.
333342
type SubnetRole string
334343

api/v1alpha3/zz_generated.deepcopy.go

Lines changed: 22 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cloud/services/resourceskus/client.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
type Client interface {
3232
List(context.Context, string) ([]compute.ResourceSku, error)
3333
HasAcceleratedNetworking(context.Context, string) (bool, error)
34+
HasEphemeralOSDiskSupport(context.Context, string) (bool, error)
3435
}
3536

3637
// AzureClient contains the Azure go-sdk Client
@@ -98,3 +99,29 @@ func (ac *AzureClient) HasAcceleratedNetworking(ctx context.Context, name string
9899
}
99100
return false, nil
100101
}
102+
103+
// HasEphemeralOSDiskSupport returns whether the given compute SKU supports ephemeral os.
104+
func (ac *AzureClient) HasEphemeralOSDiskSupport(ctx context.Context, name string) (bool, error) {
105+
if name == "" {
106+
return false, nil
107+
}
108+
skus, err := ac.List(ctx, "") // "filter" argument only works for location, so filter in code
109+
if err != nil {
110+
return false, err
111+
}
112+
for _, sku := range skus {
113+
if sku.Name != nil && *sku.Name == name {
114+
if sku.Capabilities != nil {
115+
for _, c := range *sku.Capabilities {
116+
if c.Name != nil && *c.Name == "EphemeralOSDiskSupported" {
117+
if c.Value != nil && strings.EqualFold(*c.Value, "True") {
118+
return true, nil
119+
}
120+
}
121+
}
122+
}
123+
break
124+
}
125+
}
126+
return false, nil
127+
}

cloud/services/resourceskus/mock_resourceskus/resourceskus_mock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)