2017-07-13 11:55:32 +00:00
/ *
Copyright 2017 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package azure_dd
import (
"fmt"
"io/ioutil"
"os"
2018-04-24 13:38:38 +00:00
"path/filepath"
2017-07-13 11:55:32 +00:00
libstrings "strings"
2018-04-24 06:34:03 +00:00
"github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage"
2017-07-13 11:55:32 +00:00
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
2017-11-08 22:34:54 +00:00
api "k8s.io/kubernetes/pkg/apis/core"
2017-07-13 11:55:32 +00:00
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
"k8s.io/kubernetes/pkg/util/mount"
"k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
)
const (
2018-02-24 04:00:20 +00:00
defaultStorageAccountType = storage . StandardLRS
defaultAzureDiskKind = v1 . AzureSharedBlobDisk
defaultAzureDataDiskCachingMode = v1 . AzureDataDiskCachingNone
2017-07-13 11:55:32 +00:00
)
type dataDisk struct {
volume . MetricsProvider
volumeName string
diskName string
podUID types . UID
2018-05-07 09:14:40 +00:00
plugin * azureDataDiskPlugin
2017-07-13 11:55:32 +00:00
}
var (
supportedCachingModes = sets . NewString (
string ( api . AzureDataDiskCachingNone ) ,
string ( api . AzureDataDiskCachingReadOnly ) ,
string ( api . AzureDataDiskCachingReadWrite ) )
supportedDiskKinds = sets . NewString (
string ( api . AzureSharedBlobDisk ) ,
string ( api . AzureDedicatedBlobDisk ) ,
string ( api . AzureManagedDisk ) )
2017-11-17 09:13:17 +00:00
supportedStorageAccountTypes = sets . NewString ( "Premium_LRS" , "Standard_LRS" , "Standard_GRS" , "Standard_RAGRS" )
2017-07-13 11:55:32 +00:00
)
func getPath ( uid types . UID , volName string , host volume . VolumeHost ) string {
return host . GetPodVolumeDir ( uid , strings . EscapeQualifiedNameForDisk ( azureDataDiskPluginName ) , volName )
}
// creates a unique path for disks (even if they share the same *.vhd name)
func makeGlobalPDPath ( host volume . VolumeHost , diskUri string , isManaged bool ) ( string , error ) {
diskUri = libstrings . ToLower ( diskUri ) // always lower uri because users may enter it in caps.
uniqueDiskNameTemplate := "%s%s"
hashedDiskUri := azure . MakeCRC32 ( diskUri )
prefix := "b"
if isManaged {
prefix = "m"
}
// "{m for managed b for blob}{hashed diskUri or DiskId depending on disk kind }"
diskName := fmt . Sprintf ( uniqueDiskNameTemplate , prefix , hashedDiskUri )
2018-04-24 13:38:38 +00:00
pdPath := filepath . Join ( host . GetPluginDir ( azureDataDiskPluginName ) , mount . MountsInGlobalPDPath , diskName )
2017-07-13 11:55:32 +00:00
return pdPath , nil
}
2018-05-07 09:14:40 +00:00
func makeDataDisk ( volumeName string , podUID types . UID , diskName string , host volume . VolumeHost , plugin * azureDataDiskPlugin ) * dataDisk {
2017-07-13 11:55:32 +00:00
var metricProvider volume . MetricsProvider
if podUID != "" {
metricProvider = volume . NewMetricsStatFS ( getPath ( podUID , volumeName , host ) )
}
return & dataDisk {
MetricsProvider : metricProvider ,
volumeName : volumeName ,
diskName : diskName ,
podUID : podUID ,
2018-05-07 09:14:40 +00:00
plugin : plugin ,
2017-07-13 11:55:32 +00:00
}
}
2018-05-07 09:14:40 +00:00
func getVolumeSource ( spec * volume . Spec ) ( volumeSource * v1 . AzureDiskVolumeSource , readOnly bool , err error ) {
2017-07-13 11:55:32 +00:00
if spec . Volume != nil && spec . Volume . AzureDisk != nil {
2018-05-07 09:14:40 +00:00
return spec . Volume . AzureDisk , spec . Volume . AzureDisk . ReadOnly != nil && * spec . Volume . AzureDisk . ReadOnly , nil
2017-07-13 11:55:32 +00:00
}
if spec . PersistentVolume != nil && spec . PersistentVolume . Spec . AzureDisk != nil {
2018-05-07 09:14:40 +00:00
return spec . PersistentVolume . Spec . AzureDisk , spec . ReadOnly , nil
2017-07-13 11:55:32 +00:00
}
2018-05-07 09:14:40 +00:00
return nil , false , fmt . Errorf ( "azureDisk - Spec does not reference an Azure disk volume type" )
2017-07-13 11:55:32 +00:00
}
func normalizeKind ( kind string ) ( v1 . AzureDataDiskKind , error ) {
if kind == "" {
2017-10-24 07:11:52 +00:00
return defaultAzureDiskKind , nil
2017-07-13 11:55:32 +00:00
}
if ! supportedDiskKinds . Has ( kind ) {
return "" , fmt . Errorf ( "azureDisk - %s is not supported disk kind. Supported values are %s" , kind , supportedDiskKinds . List ( ) )
}
return v1 . AzureDataDiskKind ( kind ) , nil
}
func normalizeStorageAccountType ( storageAccountType string ) ( storage . SkuName , error ) {
if storageAccountType == "" {
return defaultStorageAccountType , nil
}
if ! supportedStorageAccountTypes . Has ( storageAccountType ) {
return "" , fmt . Errorf ( "azureDisk - %s is not supported sku/storageaccounttype. Supported values are %s" , storageAccountType , supportedStorageAccountTypes . List ( ) )
}
return storage . SkuName ( storageAccountType ) , nil
}
func normalizeCachingMode ( cachingMode v1 . AzureDataDiskCachingMode ) ( v1 . AzureDataDiskCachingMode , error ) {
if cachingMode == "" {
2018-02-24 04:00:20 +00:00
return defaultAzureDataDiskCachingMode , nil
2017-07-13 11:55:32 +00:00
}
if ! supportedCachingModes . Has ( string ( cachingMode ) ) {
return "" , fmt . Errorf ( "azureDisk - %s is not supported cachingmode. Supported values are %s" , cachingMode , supportedCachingModes . List ( ) )
}
return cachingMode , nil
}
type ioHandler interface {
ReadDir ( dirname string ) ( [ ] os . FileInfo , error )
WriteFile ( filename string , data [ ] byte , perm os . FileMode ) error
Readlink ( name string ) ( string , error )
2017-08-22 08:01:33 +00:00
ReadFile ( filename string ) ( [ ] byte , error )
2017-07-13 11:55:32 +00:00
}
//TODO: check if priming the iscsi interface is actually needed
type osIOHandler struct { }
func ( handler * osIOHandler ) ReadDir ( dirname string ) ( [ ] os . FileInfo , error ) {
return ioutil . ReadDir ( dirname )
}
func ( handler * osIOHandler ) WriteFile ( filename string , data [ ] byte , perm os . FileMode ) error {
return ioutil . WriteFile ( filename , data , perm )
}
func ( handler * osIOHandler ) Readlink ( name string ) ( string , error ) {
return os . Readlink ( name )
}
2017-08-22 08:01:33 +00:00
func ( handler * osIOHandler ) ReadFile ( filename string ) ( [ ] byte , error ) {
return ioutil . ReadFile ( filename )
}
2017-07-13 11:55:32 +00:00
func getDiskController ( host volume . VolumeHost ) ( DiskController , error ) {
cloudProvider := host . GetCloudProvider ( )
az , ok := cloudProvider . ( * azure . Cloud )
if ! ok || az == nil {
return nil , fmt . Errorf ( "AzureDisk - failed to get Azure Cloud Provider. GetCloudProvider returned %v instead" , cloudProvider )
}
return az , nil
}
func getCloud ( host volume . VolumeHost ) ( * azure . Cloud , error ) {
cloudProvider := host . GetCloudProvider ( )
az , ok := cloudProvider . ( * azure . Cloud )
if ! ok || az == nil {
return nil , fmt . Errorf ( "AzureDisk - failed to get Azure Cloud Provider. GetCloudProvider returned %v instead" , cloudProvider )
}
return az , nil
}
func strFirstLetterToUpper ( str string ) string {
if len ( str ) < 2 {
return str
}
return libstrings . ToUpper ( string ( str [ 0 ] ) ) + str [ 1 : ]
}