mirror of https://github.com/k3s-io/k3s
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
commit
4fe05d8191
|
@ -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",
|
||||||
|
|
|
@ -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`:
|
||||||
|
|
||||||
|
|
|
@ -12,3 +12,4 @@ parameters:
|
||||||
group: "root"
|
group: "root"
|
||||||
quobyteConfig: "BASE"
|
quobyteConfig: "BASE"
|
||||||
quobyteTenant: "DEFAULT"
|
quobyteTenant: "DEFAULT"
|
||||||
|
createQuota: "False"
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
```
|
```
|
|
@ -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{
|
||||||
|
"a{
|
||||||
|
Consumer: []*consumingEntity{
|
||||||
|
&consumingEntity{
|
||||||
|
Type: "VOLUME",
|
||||||
|
Identifier: volumeUUID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Limits: []*resource{
|
||||||
|
&resource{
|
||||||
|
Type: "LOGICAL_DISK_SPACE",
|
||||||
|
Value: quotaSize,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.sendRequest("setQuota", request, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -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"`
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue