Merge pull request #48264 from johscheuer/set-quota-for-volumes

Automatic merge from submit-queue (batch tested with PRs 48264, 48324, 48125, 47944, 47489)

Set quota for volumes

**What this PR does / why we need it**:
This PR allows users of the Quobyte Storage class to specify if automatically a Quota for the volume should be created. With a Quota a Quobyte volume can only grow in the specified size.

**Special notes for your reviewer**:
Update the Quobyte API version for the needed functionality.
pull/6/head
Kubernetes Submit Queue 2017-06-30 20:58:24 -07:00 committed by GitHub
commit 4fe05d8191
8 changed files with 72 additions and 10 deletions

2
Godeps/Godeps.json generated
View File

@ -2222,7 +2222,7 @@
}, },
{ {
"ImportPath": "github.com/quobyte/api", "ImportPath": "github.com/quobyte/api",
"Rev": "bf713b5a4333f44504fa1ce63690de45cfed6413" "Rev": "cb10db90715b14d4784465d2fa3b915dfacc0628"
}, },
{ {
"ImportPath": "github.com/rackspace/gophercloud", "ImportPath": "github.com/rackspace/gophercloud",

View File

@ -256,6 +256,7 @@ parameters:
* **group** maps all access to this group. Default is `nfsnobody`. * **group** maps all access to this group. Default is `nfsnobody`.
* **quobyteConfig** use the specified configuration to create the volume. You can create a new configuration or modify an existing one with the Web console or the quobyte CLI. Default is `BASE` * **quobyteConfig** use the specified configuration to create the volume. You can create a new configuration or modify an existing one with the Web console or the quobyte CLI. Default is `BASE`
* **quobyteTenant** use the specified tenant ID to create/delete the volume. This Quobyte tenant has to be already present in Quobyte. For Quobyte < 1.4 use an empty string `""` as `DEFAULT` tenant. Default is `DEFAULT` * **quobyteTenant** use the specified tenant ID to create/delete the volume. This Quobyte tenant has to be already present in Quobyte. For Quobyte < 1.4 use an empty string `""` as `DEFAULT` tenant. Default is `DEFAULT`
* **createQuota** if set all volumes created by this storage class will get a Quota for the specified size. The quota is set for the logical disk size (which can differ from the physical size e.q. if replication is used). Default is ``False
First create Quobyte admin's Secret in the system namespace. Here the Secret is created in `kube-system`: First create Quobyte admin's Secret in the system namespace. Here the Secret is created in `kube-system`:

View File

@ -12,3 +12,4 @@ parameters:
group: "root" group: "root"
quobyteConfig: "BASE" quobyteConfig: "BASE"
quobyteTenant: "DEFAULT" quobyteTenant: "DEFAULT"
createQuota: "False"

View File

@ -365,6 +365,7 @@ func (provisioner *quobyteVolumeProvisioner) Provision() (*v1.PersistentVolume,
} }
provisioner.config = "BASE" provisioner.config = "BASE"
provisioner.tenant = "DEFAULT" provisioner.tenant = "DEFAULT"
createQuota := false
cfg, err := parseAPIConfig(provisioner.plugin, provisioner.options.Parameters) cfg, err := parseAPIConfig(provisioner.plugin, provisioner.options.Parameters)
if err != nil { if err != nil {
@ -382,6 +383,8 @@ func (provisioner *quobyteVolumeProvisioner) Provision() (*v1.PersistentVolume,
provisioner.tenant = v provisioner.tenant = v
case "quobyteconfig": case "quobyteconfig":
provisioner.config = v provisioner.config = v
case "createquota":
createQuota = gostrings.ToLower(v) == "true"
case "adminsecretname", case "adminsecretname",
"adminsecretnamespace", "adminsecretnamespace",
"quobyteapiserver": "quobyteapiserver":
@ -402,7 +405,7 @@ func (provisioner *quobyteVolumeProvisioner) Provision() (*v1.PersistentVolume,
config: cfg, config: cfg,
} }
vol, sizeGB, err := manager.createVolume(provisioner) vol, sizeGB, err := manager.createVolume(provisioner, createQuota)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -32,11 +32,11 @@ type quobyteVolumeManager struct {
config *quobyteAPIConfig config *quobyteAPIConfig
} }
func (manager *quobyteVolumeManager) createVolume(provisioner *quobyteVolumeProvisioner) (quobyte *v1.QuobyteVolumeSource, size int, err error) { func (manager *quobyteVolumeManager) createVolume(provisioner *quobyteVolumeProvisioner, createQuota bool) (quobyte *v1.QuobyteVolumeSource, size int, err error) {
capacity := provisioner.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] capacity := provisioner.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
volumeSize := int(volume.RoundUpSize(capacity.Value(), 1024*1024*1024)) volumeSize := int(volume.RoundUpSize(capacity.Value(), 1024*1024*1024))
// Quobyte has the concept of Volumes which doen't have a specific size (they can grow unlimited) // Quobyte has the concept of Volumes which doen't have a specific size (they can grow unlimited)
// to simulate a size constraint we could set here a Quota // to simulate a size constraint we set here a Quota for logical space
volumeRequest := &quobyteapi.CreateVolumeRequest{ volumeRequest := &quobyteapi.CreateVolumeRequest{
Name: provisioner.volume, Name: provisioner.volume,
RootUserID: provisioner.user, RootUserID: provisioner.user,
@ -45,10 +45,20 @@ func (manager *quobyteVolumeManager) createVolume(provisioner *quobyteVolumeProv
ConfigurationName: provisioner.config, ConfigurationName: provisioner.config,
} }
if _, err := manager.createQuobyteClient().CreateVolume(volumeRequest); err != nil { quobyteClient := manager.createQuobyteClient()
volumeUUID, err := quobyteClient.CreateVolume(volumeRequest)
if err != nil {
return &v1.QuobyteVolumeSource{}, volumeSize, err return &v1.QuobyteVolumeSource{}, volumeSize, err
} }
// Set Quota for Volume with specified byte size
if createQuota {
err = quobyteClient.SetVolumeQuota(volumeUUID, uint64(capacity.Value()))
if err != nil {
return &v1.QuobyteVolumeSource{}, volumeSize, err
}
}
glog.V(4).Infof("Created Quobyte volume %s", provisioner.volume) glog.V(4).Infof("Created Quobyte volume %s", provisioner.volume)
return &v1.QuobyteVolumeSource{ return &v1.QuobyteVolumeSource{
Registry: provisioner.registry, Registry: provisioner.registry,

View File

@ -22,14 +22,14 @@ func main() {
Name: "MyVolume", Name: "MyVolume",
RootUserID: "root", RootUserID: "root",
RootGroupID: "root", RootGroupID: "root",
ConfigurationName: "base", ConfigurationName: "BASE",
} }
volume_uuid, err := client.CreateVolume(req) volumeUUID, err := client.CreateVolume(req)
if err != nil { if err != nil {
log.Fatalf("Error:", err) log.Fatalf("Error:", err)
} }
log.Printf("%s", volume_uuid) log.Printf("%s", volumeUUID)
} }
``` ```

View File

@ -1,7 +1,9 @@
// Package quobyte represents a golang API for the Quobyte Storage System // Package quobyte represents a golang API for the Quobyte Storage System
package quobyte package quobyte
import "net/http" import (
"net/http"
)
type QuobyteClient struct { type QuobyteClient struct {
client *http.Client client *http.Client
@ -77,3 +79,26 @@ func (client *QuobyteClient) GetClientList(tenant string) (GetClientListResponse
return response, nil return response, nil
} }
func (client *QuobyteClient) SetVolumeQuota(volumeUUID string, quotaSize uint64) error {
request := &setQuotaRequest{
Quotas: []*quota{
&quota{
Consumer: []*consumingEntity{
&consumingEntity{
Type: "VOLUME",
Identifier: volumeUUID,
},
},
Limits: []*resource{
&resource{
Type: "LOGICAL_DISK_SPACE",
Value: quotaSize,
},
},
},
},
}
return client.sendRequest("setQuota", request, nil)
}

View File

@ -32,3 +32,25 @@ type Client struct {
MountedUserName string `json:"mount_user_name,omitempty"` MountedUserName string `json:"mount_user_name,omitempty"`
MountedVolumeUUID string `json:"mounted_volume_uuid,omitempty"` MountedVolumeUUID string `json:"mounted_volume_uuid,omitempty"`
} }
type consumingEntity struct {
Type string `json:"type,omitempty"`
Identifier string `json:"identifier,omitempty"`
TenantID string `json:"tenant_id,omitempty"`
}
type resource struct {
Type string `json:"type,omitempty"`
Value uint64 `json:"value,omitempty"`
}
type quota struct {
ID string `json:"id,omitempty"`
Consumer []*consumingEntity `json:"consumer,omitempty"`
Limits []*resource `json:"limits,omitempty"`
Currentusage []*resource `json:"current_usage,omitempty"`
}
type setQuotaRequest struct {
Quotas []*quota `json:"quotas,omitempty"`
}