diff --git a/pkg/api/testing/fuzzer.go b/pkg/api/testing/fuzzer.go index 185b6f906bc..6f0a06f5e1d 100644 --- a/pkg/api/testing/fuzzer.go +++ b/pkg/api/testing/fuzzer.go @@ -427,7 +427,11 @@ func coreFuncs(t apitesting.TestingCommon) []interface{} { func(obj *api.AzureDiskVolumeSource, c fuzz.Continue) { if obj.CachingMode == nil { obj.CachingMode = new(api.AzureDataDiskCachingMode) - *obj.CachingMode = api.AzureDataDiskCachingNone + *obj.CachingMode = api.AzureDataDiskCachingReadWrite + } + if obj.Kind == nil { + obj.Kind = new(api.AzureDataDiskKind) + *obj.Kind = api.AzureSharedBlobDisk } if obj.FSType == nil { obj.FSType = new(string) diff --git a/pkg/api/types.go b/pkg/api/types.go index 28387b4a711..0984bab2f68 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -1059,11 +1059,16 @@ type PortworxVolumeSource struct { } type AzureDataDiskCachingMode string +type AzureDataDiskKind string const ( AzureDataDiskCachingNone AzureDataDiskCachingMode = "None" AzureDataDiskCachingReadOnly AzureDataDiskCachingMode = "ReadOnly" AzureDataDiskCachingReadWrite AzureDataDiskCachingMode = "ReadWrite" + + AzureSharedBlobDisk AzureDataDiskKind = "Shared" + AzureDedicatedBlobDisk AzureDataDiskKind = "Dedicated" + AzureManagedDisk AzureDataDiskKind = "Managed" ) // AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. @@ -1084,6 +1089,8 @@ type AzureDiskVolumeSource struct { // the ReadOnly setting in VolumeMounts. // +optional ReadOnly *bool + // Expected values Shared: mulitple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared + Kind *AzureDataDiskKind } // ScaleIOVolumeSource represents a persistent ScaleIO volume diff --git a/pkg/api/v1/defaults.go b/pkg/api/v1/defaults.go index 5472223cd72..84e95cc3341 100644 --- a/pkg/api/v1/defaults.go +++ b/pkg/api/v1/defaults.go @@ -239,7 +239,11 @@ func SetDefaults_ISCSIVolumeSource(obj *ISCSIVolumeSource) { func SetDefaults_AzureDiskVolumeSource(obj *AzureDiskVolumeSource) { if obj.CachingMode == nil { obj.CachingMode = new(AzureDataDiskCachingMode) - *obj.CachingMode = AzureDataDiskCachingNone + *obj.CachingMode = AzureDataDiskCachingReadWrite + } + if obj.Kind == nil { + obj.Kind = new(AzureDataDiskKind) + *obj.Kind = AzureSharedBlobDisk } if obj.FSType == nil { obj.FSType = new(string) diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index c0ae4a06798..0e9dfed4603 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -1124,11 +1124,16 @@ type PhotonPersistentDiskVolumeSource struct { } type AzureDataDiskCachingMode string +type AzureDataDiskKind string const ( AzureDataDiskCachingNone AzureDataDiskCachingMode = "None" AzureDataDiskCachingReadOnly AzureDataDiskCachingMode = "ReadOnly" AzureDataDiskCachingReadWrite AzureDataDiskCachingMode = "ReadWrite" + + AzureSharedBlobDisk AzureDataDiskKind = "Shared" + AzureDedicatedBlobDisk AzureDataDiskKind = "Dedicated" + AzureManagedDisk AzureDataDiskKind = "Managed" ) // AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod. @@ -1149,6 +1154,8 @@ type AzureDiskVolumeSource struct { // the ReadOnly setting in VolumeMounts. // +optional ReadOnly *bool `json:"readOnly,omitempty" protobuf:"varint,5,opt,name=readOnly"` + // Expected values Shared: mulitple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared + Kind *AzureDataDiskKind `json:"kind,omitempty" protobuf:"bytes,6,opt,name=kind,casttype=AzureDataDiskKind"` } // PortworxVolumeSource represents a Portworx volume resource. diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 57f4666fd33..4728b119eb0 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -542,10 +542,16 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E allErrs = append(allErrs, validateConfigMapVolumeSource(source.ConfigMap, fldPath.Child("configMap"))...) } } + if source.AzureFile != nil { - numVolumes++ - allErrs = append(allErrs, validateAzureFile(source.AzureFile, fldPath.Child("azureFile"))...) + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureFile"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureFile(source.AzureFile, fldPath.Child("azureFile"))...) + } } + if source.VsphereVolume != nil { if numVolumes > 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("vsphereVolume"), "may not specify more than 1 volume type")) @@ -571,8 +577,12 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E } } if source.AzureDisk != nil { - numVolumes++ - allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...) + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("azureDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...) + } } if source.Projected != nil { if numVolumes > 0 { @@ -1017,19 +1027,39 @@ func validateAzureFile(azure *api.AzureFileVolumeSource, fldPath *field.Path) fi return allErrs } -var supportedCachingModes = sets.NewString(string(api.AzureDataDiskCachingNone), string(api.AzureDataDiskCachingReadOnly), string(api.AzureDataDiskCachingReadWrite)) - func validateAzureDisk(azure *api.AzureDiskVolumeSource, fldPath *field.Path) field.ErrorList { + var supportedCachingModes = sets.NewString(string(api.AzureDataDiskCachingNone), string(api.AzureDataDiskCachingReadOnly), string(api.AzureDataDiskCachingReadWrite)) + var supportedDiskKinds = sets.NewString(string(api.AzureSharedBlobDisk), string(api.AzureDedicatedBlobDisk), string(api.AzureManagedDisk)) + + diskUriSupportedManaged := []string{"/subscriptions/{sub-id}/resourcegroups/{group-name}/providers/microsoft.compute/disks/{disk-id}"} + diskUriSupportedblob := []string{"https://{account-name}.blob.core.windows.net/{container-name}/{disk-name}.vhd"} + allErrs := field.ErrorList{} if azure.DiskName == "" { allErrs = append(allErrs, field.Required(fldPath.Child("diskName"), "")) } + if azure.DataDiskURI == "" { allErrs = append(allErrs, field.Required(fldPath.Child("diskURI"), "")) } + if azure.CachingMode != nil && !supportedCachingModes.Has(string(*azure.CachingMode)) { allErrs = append(allErrs, field.NotSupported(fldPath.Child("cachingMode"), *azure.CachingMode, supportedCachingModes.List())) } + + if azure.Kind != nil && !supportedDiskKinds.Has(string(*azure.Kind)) { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("kind"), *azure.Kind, supportedDiskKinds.List())) + } + + // validate that DiskUri is the correct format + if azure.Kind != nil && *azure.Kind == api.AzureManagedDisk && strings.Index(azure.DataDiskURI, "/subscriptions/") != 0 { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("diskURI"), azure.DataDiskURI, diskUriSupportedManaged)) + } + + if azure.Kind != nil && *azure.Kind != api.AzureManagedDisk && strings.Index(azure.DataDiskURI, "https://") != 0 { + allErrs = append(allErrs, field.NotSupported(fldPath.Child("diskURI"), azure.DataDiskURI, diskUriSupportedblob)) + } + return allErrs } @@ -1211,9 +1241,15 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList { allErrs = append(allErrs, validateFlexVolumeSource(pv.Spec.FlexVolume, specPath.Child("flexVolume"))...) } if pv.Spec.AzureFile != nil { - numVolumes++ - allErrs = append(allErrs, validateAzureFile(pv.Spec.AzureFile, specPath.Child("azureFile"))...) + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(specPath.Child("azureFile"), "may not specify more than 1 volume type")) + + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureFile(pv.Spec.AzureFile, specPath.Child("azureFile"))...) + } } + if pv.Spec.VsphereVolume != nil { if numVolumes > 0 { allErrs = append(allErrs, field.Forbidden(specPath.Child("vsphereVolume"), "may not specify more than 1 volume type")) @@ -1239,8 +1275,12 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList { } } if pv.Spec.AzureDisk != nil { - numVolumes++ - allErrs = append(allErrs, validateAzureDisk(pv.Spec.AzureDisk, specPath.Child("azureDisk"))...) + if numVolumes > 0 { + allErrs = append(allErrs, field.Forbidden(specPath.Child("azureDisk"), "may not specify more than 1 volume type")) + } else { + numVolumes++ + allErrs = append(allErrs, validateAzureDisk(pv.Spec.AzureDisk, specPath.Child("azureDisk"))...) + } } if pv.Spec.ScaleIO != nil { if numVolumes > 0 { diff --git a/pkg/printers/internalversion/describe.go b/pkg/printers/internalversion/describe.go index f24eff9c88c..9b4619b5a4a 100644 --- a/pkg/printers/internalversion/describe.go +++ b/pkg/printers/internalversion/describe.go @@ -866,10 +866,11 @@ func printAzureDiskVolumeSource(d *api.AzureDiskVolumeSource, w PrefixWriter) { w.Write(LEVEL_2, "Type:\tAzureDisk (an Azure Data Disk mount on the host and bind mount to the pod)\n"+ " DiskName:\t%v\n"+ " DiskURI:\t%v\n"+ + " Kind: \t%v\n"+ " FSType:\t%v\n"+ " CachingMode:\t%v\n"+ " ReadOnly:\t%v\n", - d.DiskName, d.DataDiskURI, *d.FSType, *d.CachingMode, *d.ReadOnly) + d.DiskName, d.DataDiskURI, *d.Kind, *d.FSType, *d.CachingMode, *d.ReadOnly) } func printVsphereVolumeSource(vsphere *api.VsphereVirtualDiskVolumeSource, w PrefixWriter) {