// CreateVolume creates a GCE PD. // Returns: volumeID, volumeSizeGB, labels, error func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (string, int, map[string]string, error) { cloud, err := getCloudProvider(c.gcePersistentDisk.plugin) if err != nil { return "", 0, nil, err } name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters requestBytes := c.options.Capacity.Value() // GCE works with gigabytes, convert to GiB with rounding up requestGB := volume.RoundUpSize(requestBytes, 1024*1024*1024) // The disk will be created in the zone in which this code is currently running // TODO: We should support auto-provisioning volumes in multiple/specified zones zone, err := cloud.GetZone() if err != nil { glog.V(2).Infof("error getting zone information from GCE: %v", err) return "", 0, nil, err } err = cloud.CreateDisk(name, zone.FailureDomain, int64(requestGB), *c.options.CloudTags) if err != nil { glog.V(2).Infof("Error creating GCE PD volume: %v", err) return "", 0, nil, err } glog.V(2).Infof("Successfully created GCE PD volume %s", name) labels, err := cloud.GetAutoLabelsForPD(name) if err != nil { // We don't really want to leak the volume here... glog.Errorf("error getting labels for volume %q: %v", name, err) } return name, int(requestGB), labels, nil }
func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (volumeID string, volumeSizeGB int, err error) { cloud, err := getCloudProvider() if err != nil { return "", 0, err } // AWS volumes don't have Name field, store the name in Name tag var tags map[string]string if c.options.CloudTags == nil { tags = make(map[string]string) } else { tags = *c.options.CloudTags } tags["Name"] = volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // AWS tags can have 255 characters requestBytes := c.options.Capacity.Value() // AWS works with gigabytes, convert to GiB with rounding up requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) volumeOptions := &aws.VolumeOptions{ CapacityGB: requestGB, Tags: &tags, } name, err := cloud.CreateDisk(volumeOptions) if err != nil { glog.V(2).Infof("Error creating EBS Disk volume: %v", err) return "", 0, err } glog.V(2).Infof("Successfully created EBS Disk volume %s", name) return name, int(requestGB), nil }
// CreateVolume creates a GCE PD. // Returns: volumeID, volumeSizeGB, labels, error func (gceutil *GCEDiskUtil) CreateVolume(c *gcePersistentDiskProvisioner) (string, int, map[string]string, error) { cloud, err := getCloudProvider(c.gcePersistentDisk.plugin.host.GetCloudProvider()) if err != nil { return "", 0, nil, err } name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 63) // GCE PD name can have up to 63 characters capacity := c.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] requestBytes := capacity.Value() // GCE works with gigabytes, convert to GiB with rounding up requestGB := volume.RoundUpSize(requestBytes, 1024*1024*1024) // Apply Parameters (case-insensitive). We leave validation of // the values to the cloud provider. diskType := "" zone := "" for k, v := range c.options.Parameters { switch strings.ToLower(k) { case "type": diskType = v case "zone": zone = v default: return "", 0, nil, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName()) } } // TODO: implement PVC.Selector parsing if c.options.PVC.Spec.Selector != nil { return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on GCE") } if zone == "" { // No zone specified, choose one randomly in the same region as the // node is running. zones, err := cloud.GetAllZones() if err != nil { glog.V(2).Infof("error getting zone information from GCE: %v", err) return "", 0, nil, err } zone = volume.ChooseZoneForVolume(zones, c.options.PVC.Name) } err = cloud.CreateDisk(name, diskType, zone, int64(requestGB), *c.options.CloudTags) if err != nil { glog.V(2).Infof("Error creating GCE PD volume: %v", err) return "", 0, nil, err } glog.V(2).Infof("Successfully created GCE PD volume %s", name) labels, err := cloud.GetAutoLabelsForPD(name, zone) if err != nil { // We don't really want to leak the volume here... glog.Errorf("error getting labels for volume %q: %v", name, err) } return name, int(requestGB), labels, nil }
func (a *azureDiskProvisioner) Provision() (*v1.PersistentVolume, error) { var sku, location, account string // maxLength = 79 - (4 for ".vhd") = 75 name := volume.GenerateVolumeName(a.options.ClusterName, a.options.PVName, 75) capacity := a.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] requestBytes := capacity.Value() requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) // Apply ProvisionerParameters (case-insensitive). We leave validation of // the values to the cloud provider. for k, v := range a.options.Parameters { switch strings.ToLower(k) { case "skuname": sku = v case "location": location = v case "storageaccount": account = v default: return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, a.plugin.GetPluginName()) } } // TODO: implement c.options.ProvisionerSelector parsing if a.options.PVC.Spec.Selector != nil { return nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Azure disk") } diskName, diskUri, sizeGB, err := a.azureProvider.CreateVolume(name, account, sku, location, requestGB) if err != nil { return nil, err } pv := &v1.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: a.options.PVName, Labels: map[string]string{}, Annotations: map[string]string{ "kubernetes.io/createdby": "azure-disk-dynamic-provisioner", }, }, Spec: v1.PersistentVolumeSpec{ PersistentVolumeReclaimPolicy: a.options.PersistentVolumeReclaimPolicy, AccessModes: a.options.PVC.Spec.AccessModes, Capacity: v1.ResourceList{ v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)), }, PersistentVolumeSource: v1.PersistentVolumeSource{ AzureDisk: &v1.AzureDiskVolumeSource{ DiskName: diskName, DataDiskURI: diskUri, }, }, }, } return pv, nil }
// CreateVolume creates a vSphere volume. func (util *VsphereDiskUtil) CreateVolume(v *vsphereVolumeProvisioner) (vmDiskPath string, volumeSizeKB int, err error) { cloud, err := v.plugin.getCloudProvider() if err != nil { return "", 0, err } volSizeBytes := v.options.Capacity.Value() // vSphere works with kilobytes, convert to KiB with rounding up volSizeKB := int(volume.RoundUpSize(volSizeBytes, 1024)) name := volume.GenerateVolumeName(v.options.ClusterName, v.options.PVName, 255) vmDiskPath, err = cloud.CreateVolume(name, volSizeKB, v.options.CloudTags) if err != nil { glog.V(2).Infof("Error creating vsphere volume: %v", err) return "", 0, err } glog.V(2).Infof("Successfully created vsphere volume %s", name) return vmDiskPath, volSizeKB, nil }
func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, err error) { cloud, err := c.plugin.getCloudProvider() if err != nil { return "", 0, err } volSizeBytes := c.options.Capacity.Value() // Cinder works with gigabytes, convert to GiB with rounding up volSizeGB := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024)) name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // Cinder volume name can have up to 255 characters name, err = cloud.CreateVolume(name, volSizeGB, c.options.CloudTags) if err != nil { glog.V(2).Infof("Error creating cinder volume: %v", err) return "", 0, err } glog.V(2).Infof("Successfully created cinder volume %s", name) return name, volSizeGB, nil }
// CreateVolume creates a vSphere volume. func (util *VsphereDiskUtil) CreateVolume(v *vsphereVolumeProvisioner) (vmDiskPath string, volumeSizeKB int, err error) { cloud, err := getCloudProvider(v.plugin.host.GetCloudProvider()) if err != nil { return "", 0, err } capacity := v.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] volSizeBytes := capacity.Value() // vSphere works with kilobytes, convert to KiB with rounding up volSizeKB := int(volume.RoundUpSize(volSizeBytes, 1024)) name := volume.GenerateVolumeName(v.options.ClusterName, v.options.PVName, 255) volumeOptions := &vsphere.VolumeOptions{ CapacityKB: volSizeKB, Tags: *v.options.CloudTags, Name: name, } // Apply Parameters (case-insensitive). We leave validation of // the values to the cloud provider. for parameter, value := range v.options.Parameters { switch strings.ToLower(parameter) { case "diskformat": volumeOptions.DiskFormat = value default: return "", 0, fmt.Errorf("invalid option %q for volume plugin %s", parameter, v.plugin.GetPluginName()) } } // TODO: implement PVC.Selector parsing if v.options.PVC.Spec.Selector != nil { return "", 0, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on vSphere") } vmDiskPath, err = cloud.CreateVolume(volumeOptions) if err != nil { glog.V(2).Infof("Error creating vsphere volume: %v", err) return "", 0, err } glog.V(2).Infof("Successfully created vsphere volume %s", name) return vmDiskPath, volSizeKB, nil }
// CreateVolume creates an AWS EBS volume. // Returns: volumeID, volumeSizeGB, labels, error func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (string, int, map[string]string, error) { cloud, err := getCloudProvider(c.awsElasticBlockStore.plugin.host.GetCloudProvider()) if err != nil { return "", 0, nil, err } // AWS volumes don't have Name field, store the name in Name tag var tags map[string]string if c.options.CloudTags == nil { tags = make(map[string]string) } else { tags = *c.options.CloudTags } tags["Name"] = volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // AWS tags can have 255 characters requestBytes := c.options.Capacity.Value() // AWS works with gigabytes, convert to GiB with rounding up requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) volumeOptions := &aws.VolumeOptions{ CapacityGB: requestGB, Tags: tags, PVCName: c.options.PVCName, } name, err := cloud.CreateDisk(volumeOptions) if err != nil { glog.V(2).Infof("Error creating EBS Disk volume: %v", err) return "", 0, nil, err } glog.V(2).Infof("Successfully created EBS Disk volume %s", name) labels, err := cloud.GetVolumeLabels(name) if err != nil { // We don't really want to leak the volume here... glog.Errorf("error building labels for new EBS volume %q: %v", name, err) } return name, int(requestGB), labels, nil }
func (util *CinderDiskUtil) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, err error) { cloud, err := c.plugin.getCloudProvider() if err != nil { return "", 0, err } capacity := c.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] volSizeBytes := capacity.Value() // Cinder works with gigabytes, convert to GiB with rounding up volSizeGB := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024)) name := volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // Cinder volume name can have up to 255 characters vtype := "" availability := "" // Apply ProvisionerParameters (case-insensitive). We leave validation of // the values to the cloud provider. for k, v := range c.options.Parameters { switch strings.ToLower(k) { case "type": vtype = v case "availability": availability = v default: return "", 0, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName()) } } // TODO: implement PVC.Selector parsing if c.options.PVC.Spec.Selector != nil { return "", 0, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on Cinder") } name, err = cloud.CreateVolume(name, volSizeGB, vtype, availability, c.options.CloudTags) if err != nil { glog.V(2).Infof("Error creating cinder volume: %v", err) return "", 0, err } glog.V(2).Infof("Successfully created cinder volume %s", name) return name, volSizeGB, nil }
// CreateVolume creates a PhotonController persistent disk. func (util *PhotonDiskUtil) CreateVolume(p *photonPersistentDiskProvisioner) (pdID string, capacityGB int, err error) { cloud, err := getCloudProvider(p.plugin.host.GetCloudProvider()) if err != nil { glog.Errorf("Photon Controller Util: CreateVolume failed to get cloud provider. Error [%v]", err) return "", 0, err } capacity := p.options.PVC.Spec.Resources.Requests[api.ResourceName(api.ResourceStorage)] volSizeBytes := capacity.Value() // PhotonController works with GB, convert to GB with rounding up volSizeGB := int(volume.RoundUpSize(volSizeBytes, 1024*1024*1024)) name := volume.GenerateVolumeName(p.options.ClusterName, p.options.PVName, 255) volumeOptions := &photon.VolumeOptions{ CapacityGB: volSizeGB, Tags: *p.options.CloudTags, Name: name, } for parameter, value := range p.options.Parameters { switch strings.ToLower(parameter) { case "flavor": volumeOptions.Flavor = value default: glog.Errorf("Photon Controller Util: invalid option %s for volume plugin %s.", parameter, p.plugin.GetPluginName()) return "", 0, fmt.Errorf("Photon Controller Util: invalid option %s for volume plugin %s.", parameter, p.plugin.GetPluginName()) } } pdID, err = cloud.CreateDisk(volumeOptions) if err != nil { glog.Errorf("Photon Controller Util: failed to CreateDisk. Error [%v]", err) return "", 0, err } glog.V(4).Infof("Successfully created Photon Controller persistent disk %s", name) return pdID, volSizeGB, nil }
// CreateVolume creates an AWS EBS volume. // Returns: volumeID, volumeSizeGB, labels, error func (util *AWSDiskUtil) CreateVolume(c *awsElasticBlockStoreProvisioner) (aws.KubernetesVolumeID, int, map[string]string, error) { cloud, err := getCloudProvider(c.awsElasticBlockStore.plugin.host.GetCloudProvider()) if err != nil { return "", 0, nil, err } // AWS volumes don't have Name field, store the name in Name tag var tags map[string]string if c.options.CloudTags == nil { tags = make(map[string]string) } else { tags = *c.options.CloudTags } tags["Name"] = volume.GenerateVolumeName(c.options.ClusterName, c.options.PVName, 255) // AWS tags can have 255 characters capacity := c.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] requestBytes := capacity.Value() // AWS works with gigabytes, convert to GiB with rounding up requestGB := int(volume.RoundUpSize(requestBytes, 1024*1024*1024)) volumeOptions := &aws.VolumeOptions{ CapacityGB: requestGB, Tags: tags, PVCName: c.options.PVC.Name, } // Apply Parameters (case-insensitive). We leave validation of // the values to the cloud provider. for k, v := range c.options.Parameters { switch strings.ToLower(k) { case "type": volumeOptions.VolumeType = v case "zone": volumeOptions.AvailabilityZone = v case "iopspergb": volumeOptions.IOPSPerGB, err = strconv.Atoi(v) if err != nil { return "", 0, nil, fmt.Errorf("invalid iopsPerGB value %q, must be integer between 1 and 30: %v", v, err) } case "encrypted": volumeOptions.Encrypted, err = strconv.ParseBool(v) if err != nil { return "", 0, nil, fmt.Errorf("invalid encrypted boolean value %q, must be true or false: %v", v, err) } case "kmskeyid": volumeOptions.KmsKeyId = v default: return "", 0, nil, fmt.Errorf("invalid option %q for volume plugin %s", k, c.plugin.GetPluginName()) } } // TODO: implement PVC.Selector parsing if c.options.PVC.Spec.Selector != nil { return "", 0, nil, fmt.Errorf("claim.Spec.Selector is not supported for dynamic provisioning on AWS") } name, err := cloud.CreateDisk(volumeOptions) if err != nil { glog.V(2).Infof("Error creating EBS Disk volume: %v", err) return "", 0, nil, err } glog.V(2).Infof("Successfully created EBS Disk volume %s", name) labels, err := cloud.GetVolumeLabels(name) if err != nil { // We don't really want to leak the volume here... glog.Errorf("error building labels for new EBS volume %q: %v", name, err) } return name, int(requestGB), labels, nil }