mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #31434 from johscheuer/quobyte-dynamic-prov
Automatic merge from submit-queue Support Quobyte as StorageClass This PR allows Users to use Quobyte as StorageClass for dynamic volume provisioning and implements the Provisioner/Deleter Interface. @quolix @kubernetes/sig-storage @rootfs
This commit is contained in:
		
							
								
								
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							@@ -1907,6 +1907,10 @@
 | 
			
		||||
			"ImportPath": "github.com/prometheus/procfs",
 | 
			
		||||
			"Rev": "454a56f35412459b5e684fd5ec0f9211b94f002a"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/quobyte/api",
 | 
			
		||||
			"Rev": "bf713b5a4333f44504fa1ce63690de45cfed6413"
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			"ImportPath": "github.com/rackspace/gophercloud",
 | 
			
		||||
			"Comment": "v1.0.0-920-g934dbf8",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										36
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							@@ -60578,6 +60578,42 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
================================================================================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
================================================================================
 | 
			
		||||
= vendor/github.com/quobyte/api licensed under: =
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2016, Quobyte Inc.
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
* Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
* Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
  this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
  and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
* Neither the name of quobyte-automation nor the names of its
 | 
			
		||||
  contributors may be used to endorse or promote products derived from
 | 
			
		||||
  this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
			
		||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
			
		||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
= vendor/github.com/quobyte/api/LICENSE beacc5ea3bcda24bdcec545022dbb0b4  -
 | 
			
		||||
================================================================================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
================================================================================
 | 
			
		||||
= vendor/github.com/rackspace/gophercloud licensed under: =
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@ import (
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/glusterfs"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/host_path"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/nfs"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/quobyte"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/rbd"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/vsphere_volume"
 | 
			
		||||
)
 | 
			
		||||
@@ -105,6 +106,8 @@ func ProbeControllerVolumePlugins(cloud cloudprovider.Interface, config componen
 | 
			
		||||
	allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
 | 
			
		||||
	// add rbd provisioner
 | 
			
		||||
	allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
 | 
			
		||||
	allPlugins = append(allPlugins, quobyte.ProbeVolumePlugins()...)
 | 
			
		||||
 | 
			
		||||
	if cloud != nil {
 | 
			
		||||
		switch {
 | 
			
		||||
		case aws.ProviderName == cloud.ProviderName():
 | 
			
		||||
 
 | 
			
		||||
@@ -191,6 +191,94 @@ parameters:
 | 
			
		||||
* `userId`: Ceph client ID that is used to map the RBD image. Default is the same as `adminId`.
 | 
			
		||||
* `userSecretName`: The name of Ceph Secret for `userId` to map RBD image. It must exist in the same namespace as PVCs. It is required.
 | 
			
		||||
 | 
			
		||||
#### Quobyte
 | 
			
		||||
 | 
			
		||||
<!-- BEGIN MUNGE: EXAMPLE quobyte/quobyte-storage-class.yaml -->
 | 
			
		||||
 | 
			
		||||
```yaml
 | 
			
		||||
apiVersion: storage.k8s.io/v1beta1
 | 
			
		||||
kind: StorageClass
 | 
			
		||||
metadata:
 | 
			
		||||
   name: slow
 | 
			
		||||
provisioner: kubernetes.io/quobyte
 | 
			
		||||
parameters:
 | 
			
		||||
    quobyteAPIServer: "http://138.68.74.142:7860"
 | 
			
		||||
    registry: "138.68.74.142:7861"
 | 
			
		||||
    adminSecretName: "quobyte-admin-secret"
 | 
			
		||||
    adminSecretNamespace: "kube-system"
 | 
			
		||||
    user: "root"
 | 
			
		||||
    group: "root"
 | 
			
		||||
    quobyteConfig: "BASE"
 | 
			
		||||
    quobyteTenant: "DEFAULT"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[Download example](quobyte/quobyte-storage-class.yaml?raw=true)
 | 
			
		||||
<!-- END MUNGE: EXAMPLE quobyte/quobyte-storage-class.yaml -->
 | 
			
		||||
 | 
			
		||||
* **quobyteAPIServer** API Server of Quobyte in the format http(s)://api-server:7860
 | 
			
		||||
* **registry** Quobyte registry to use to mount the volume. You can specifiy the registry as <host>:<port> pair or if you want to specify multiple registries you just have to put a comma between them e.q. <host1>:<port>,<host2>:<port>,<host3>:<port>. The host can be an IP address or if you have a working DNS you can also provide the DNS names.
 | 
			
		||||
* **adminSecretName** secret that holds information about the Quobyte user and the password to authenticate agains the API server.
 | 
			
		||||
* **adminSecretNamespace** The namespace for **adminSecretName**. Default is `default`.
 | 
			
		||||
* **user** maps all access to this user. Default is `root`.
 | 
			
		||||
* **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`
 | 
			
		||||
* **quobyteTenant** use the specified tenant ID to create/delete the volume. This Quobyte tenant has to be already present in Quobyte. Default is `DEFAULT`
 | 
			
		||||
 | 
			
		||||
First create Quobyte admin's Secret in the system namespace. Here the Secret is created in `kube-system`:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ kubectl create -f examples/experimental/persistent-volume-provisioning/quobyte/quobyte-admin-secret.yaml --namespace=kube-system
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then create the Quobyte storage class:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ kubectl create -f examples/experimental/persistent-volume-provisioning/quobyte/quobyte-storage-class.yaml
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Now create a PVC
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ kubectl create -f examples/experimental/persistent-volume-provisioning/claim1.json
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Check the created PVC:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ kubectl describe pvc
 | 
			
		||||
Name:       claim1
 | 
			
		||||
Namespace:      default
 | 
			
		||||
Status:     Bound
 | 
			
		||||
Volume:     pvc-bdb82652-694a-11e6-b811-080027242396
 | 
			
		||||
Labels:     <none>
 | 
			
		||||
Capacity:       3Gi
 | 
			
		||||
Access Modes:   RWO
 | 
			
		||||
No events.
 | 
			
		||||
 | 
			
		||||
$ kubectl describe pv
 | 
			
		||||
Name:  		pvc-bdb82652-694a-11e6-b811-080027242396
 | 
			
		||||
Labels:		<none>
 | 
			
		||||
Status:		Bound
 | 
			
		||||
Claim: 		default/claim1
 | 
			
		||||
Reclaim Policy:	Delete
 | 
			
		||||
Access Modes:  	RWO
 | 
			
		||||
Capacity:      	3Gi
 | 
			
		||||
Message:
 | 
			
		||||
Source:
 | 
			
		||||
    Type:      	Quobyte (a Quobyte mount on the host that shares a pod's lifetime)
 | 
			
		||||
    Registry:  	138.68.79.14:7861
 | 
			
		||||
    Volume:    	kubernetes-dynamic-pvc-bdb97c58-694a-11e6-91b6-080027242396
 | 
			
		||||
    ReadOnly:  	false
 | 
			
		||||
No events.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Create a Pod to use the PVC:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ kubectl create -f examples/experimental/persistent-volume-provisioning/quobyte/example-pod.yaml
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### User provisioning requests
 | 
			
		||||
 | 
			
		||||
Users request dynamically provisioned storage by including a storage class in their `PersistentVolumeClaim`.
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
apiVersion: v1
 | 
			
		||||
kind: ReplicationController
 | 
			
		||||
metadata:
 | 
			
		||||
  name: server
 | 
			
		||||
spec:
 | 
			
		||||
  replicas: 1
 | 
			
		||||
  selector:
 | 
			
		||||
    role: server
 | 
			
		||||
  template:
 | 
			
		||||
    metadata:
 | 
			
		||||
      labels:
 | 
			
		||||
        role: server
 | 
			
		||||
    spec:
 | 
			
		||||
      containers:
 | 
			
		||||
      - name: server
 | 
			
		||||
        image: nginx 
 | 
			
		||||
        volumeMounts:
 | 
			
		||||
          - mountPath: /var/lib/www/html
 | 
			
		||||
            name: quobytepvc
 | 
			
		||||
      volumes:
 | 
			
		||||
        - name: quobytepvc
 | 
			
		||||
          persistentVolumeClaim:
 | 
			
		||||
            claimName: claim1
 | 
			
		||||
@@ -0,0 +1,7 @@
 | 
			
		||||
apiVersion: v1
 | 
			
		||||
kind: Secret
 | 
			
		||||
metadata:
 | 
			
		||||
  name: quobyte-admin-secret
 | 
			
		||||
data:
 | 
			
		||||
  password: cXVvYnl0ZQ==
 | 
			
		||||
  user: YWRtaW4=
 | 
			
		||||
@@ -0,0 +1,14 @@
 | 
			
		||||
apiVersion: storage.k8s.io/v1beta1
 | 
			
		||||
kind: StorageClass
 | 
			
		||||
metadata:
 | 
			
		||||
   name: slow
 | 
			
		||||
provisioner: kubernetes.io/quobyte
 | 
			
		||||
parameters:
 | 
			
		||||
    quobyteAPIServer: "http://138.68.74.142:7860"
 | 
			
		||||
    registry: "138.68.74.142:7861"
 | 
			
		||||
    adminSecretName: "quobyte-admin-secret"
 | 
			
		||||
    adminSecretNamespace: "kube-system"
 | 
			
		||||
    user: "root"
 | 
			
		||||
    group: "root"
 | 
			
		||||
    quobyteConfig: "BASE"
 | 
			
		||||
    quobyteTenant: "DEFAULT"
 | 
			
		||||
@@ -94,11 +94,11 @@ spec:
 | 
			
		||||
<!-- END MUNGE: EXAMPLE ./quobyte-pod.yaml -->
 | 
			
		||||
 | 
			
		||||
Parameters:
 | 
			
		||||
* **registry** Quobyte registry to use to mount the volume. You can specifiy the registry as <host>:<port> pair or if you want to specify multiple registries you just have to put a semicolon between them e.q. <host1>:<port>,<host2>:<port>,<host3>:<port>. The host can be an IP address or if you have a working DNS you can also provide the DNS names.
 | 
			
		||||
* **registry** Quobyte registry to use to mount the volume. You can specifiy the registry as <host>:<port> pair or if you want to specify multiple registries you just have to put a comma between them e.q. <host1>:<port>,<host2>:<port>,<host3>:<port>. The host can be an IP address or if you have a working DNS you can also provide the DNS names.
 | 
			
		||||
* **volume** volume represents a Quobyte volume which must be created before usage.
 | 
			
		||||
* **readOnly** is the boolean that sets the mountpoint readOnly or readWrite.
 | 
			
		||||
* **user** maps all access to this user. Default is root.
 | 
			
		||||
* **group** maps all access to this group. Default is empty.
 | 
			
		||||
* **user** maps all access to this user. Default is `root`.
 | 
			
		||||
* **group** maps all access to this group. Default is `nfsnobody`.
 | 
			
		||||
 | 
			
		||||
Creating the pod:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,14 +20,18 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	goStrings "strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"github.com/pborman/uuid"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api/resource"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/types"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/exec"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/mount"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/strings"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ProbeVolumePlugins is the primary entrypoint for volume plugins.
 | 
			
		||||
@@ -39,11 +43,27 @@ type quobytePlugin struct {
 | 
			
		||||
	host volume.VolumeHost
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This user is used to authenticate against the
 | 
			
		||||
// Quobyte API server and holds all information
 | 
			
		||||
type quobyteAPIConfig struct {
 | 
			
		||||
	quobyteUser      string
 | 
			
		||||
	quobytePassword  string
 | 
			
		||||
	quobyteAPIServer string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ volume.VolumePlugin = &quobytePlugin{}
 | 
			
		||||
var _ volume.PersistentVolumePlugin = &quobytePlugin{}
 | 
			
		||||
var _ volume.DeletableVolumePlugin = &quobytePlugin{}
 | 
			
		||||
var _ volume.ProvisionableVolumePlugin = &quobytePlugin{}
 | 
			
		||||
var _ volume.Provisioner = &quobyteVolumeProvisioner{}
 | 
			
		||||
var _ volume.Deleter = &quobyteVolumeDeleter{}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	quobytePluginName = "kubernetes.io/quobyte"
 | 
			
		||||
 | 
			
		||||
	annotationQuobyteAPIServer          = "quobyte.kubernetes.io/api"
 | 
			
		||||
	annotationQuobyteAPISecret          = "quobyte.kubernetes.io/apiuser"
 | 
			
		||||
	annotationQuobyteAPISecretNamespace = "quobyte.kubernetes.io/apipassword"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) Init(host volume.VolumeHost) error {
 | 
			
		||||
@@ -149,7 +169,8 @@ func (plugin *quobytePlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod,
 | 
			
		||||
			plugin:  plugin,
 | 
			
		||||
		},
 | 
			
		||||
		registry: source.Registry,
 | 
			
		||||
		readOnly: readOnly}, nil
 | 
			
		||||
		readOnly: readOnly,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
 | 
			
		||||
@@ -157,12 +178,14 @@ func (plugin *quobytePlugin) NewUnmounter(volName string, podUID types.UID) (vol
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Unmounter, error) {
 | 
			
		||||
	return &quobyteUnmounter{&quobyte{
 | 
			
		||||
	return &quobyteUnmounter{
 | 
			
		||||
		&quobyte{
 | 
			
		||||
			volName: volName,
 | 
			
		||||
			mounter: mounter,
 | 
			
		||||
			pod:     &api.Pod{ObjectMeta: api.ObjectMeta{UID: podUID}},
 | 
			
		||||
			plugin:  plugin,
 | 
			
		||||
	}}, nil
 | 
			
		||||
		},
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Quobyte volumes represent a bare host directory mount of an quobyte export.
 | 
			
		||||
@@ -172,6 +195,8 @@ type quobyte struct {
 | 
			
		||||
	user    string
 | 
			
		||||
	group   string
 | 
			
		||||
	volume  string
 | 
			
		||||
	tenant  string
 | 
			
		||||
	config  string
 | 
			
		||||
	mounter mount.Interface
 | 
			
		||||
	plugin  *quobytePlugin
 | 
			
		||||
	volume.MetricsNil
 | 
			
		||||
@@ -226,22 +251,22 @@ func (mounter *quobyteMounter) SetUpAt(dir string, fsGroup *int64) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPath returns the path to the user specific mount of a Quobyte volume
 | 
			
		||||
// Returns a path in the format ../user@volume e.g. ../root@MyVolume
 | 
			
		||||
// or if a group is set ../user#group@volume
 | 
			
		||||
// Returns a path in the format ../user#group@volume
 | 
			
		||||
func (quobyteVolume *quobyte) GetPath() string {
 | 
			
		||||
	user := quobyteVolume.user
 | 
			
		||||
	if len(user) == 0 {
 | 
			
		||||
		user = "root"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	group := quobyteVolume.group
 | 
			
		||||
	if len(group) == 0 {
 | 
			
		||||
		group = "nfsnobody"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Quobyte has only one mount in the PluginDir where all Volumes are mounted
 | 
			
		||||
	// The Quobyte client does a fixed-user mapping
 | 
			
		||||
	pluginDir := quobyteVolume.plugin.host.GetPluginDir(strings.EscapeQualifiedNameForDisk(quobytePluginName))
 | 
			
		||||
	if len(quobyteVolume.group) > 0 {
 | 
			
		||||
		return path.Join(pluginDir, fmt.Sprintf("%s#%s@%s", user, quobyteVolume.group, quobyteVolume.volume))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return path.Join(pluginDir, fmt.Sprintf("%s@%s", user, quobyteVolume.volume))
 | 
			
		||||
	return path.Join(pluginDir, fmt.Sprintf("%s#%s@%s", user, group, quobyteVolume.volume))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quobyteUnmounter struct {
 | 
			
		||||
@@ -258,3 +283,192 @@ func (unmounter *quobyteUnmounter) TearDown() error {
 | 
			
		||||
func (unmounter *quobyteUnmounter) TearDownAt(dir string) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quobyteVolumeDeleter struct {
 | 
			
		||||
	*quobyteMounter
 | 
			
		||||
	pv *api.PersistentVolume
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
 | 
			
		||||
	if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Quobyte == nil {
 | 
			
		||||
		return nil, fmt.Errorf("spec.PersistentVolumeSource.Spec.Quobyte is nil")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return plugin.newDeleterInternal(spec)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) newDeleterInternal(spec *volume.Spec) (volume.Deleter, error) {
 | 
			
		||||
	source, readOnly, err := getVolumeSource(spec)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &quobyteVolumeDeleter{
 | 
			
		||||
		quobyteMounter: &quobyteMounter{
 | 
			
		||||
			quobyte: &quobyte{
 | 
			
		||||
				volName: spec.Name(),
 | 
			
		||||
				user:    source.User,
 | 
			
		||||
				group:   source.Group,
 | 
			
		||||
				volume:  source.Volume,
 | 
			
		||||
				plugin:  plugin,
 | 
			
		||||
			},
 | 
			
		||||
			registry: source.Registry,
 | 
			
		||||
			readOnly: readOnly,
 | 
			
		||||
		},
 | 
			
		||||
		pv: spec.PersistentVolume,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
 | 
			
		||||
	if len(options.AccessModes) == 0 {
 | 
			
		||||
		options.AccessModes = plugin.GetAccessModes()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return plugin.newProvisionerInternal(options)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (plugin *quobytePlugin) newProvisionerInternal(options volume.VolumeOptions) (volume.Provisioner, error) {
 | 
			
		||||
	return &quobyteVolumeProvisioner{
 | 
			
		||||
		quobyteMounter: &quobyteMounter{
 | 
			
		||||
			quobyte: &quobyte{
 | 
			
		||||
				plugin: plugin,
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		options: options,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type quobyteVolumeProvisioner struct {
 | 
			
		||||
	*quobyteMounter
 | 
			
		||||
	options volume.VolumeOptions
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (provisioner *quobyteVolumeProvisioner) Provision() (*api.PersistentVolume, error) {
 | 
			
		||||
	if provisioner.options.Selector != nil {
 | 
			
		||||
		return nil, fmt.Errorf("claim Selector is not supported")
 | 
			
		||||
	}
 | 
			
		||||
	var apiServer, adminSecretName, quobyteUser, quobytePassword string
 | 
			
		||||
	adminSecretNamespace := "default"
 | 
			
		||||
	provisioner.config = "BASE"
 | 
			
		||||
	provisioner.tenant = "DEFAULT"
 | 
			
		||||
 | 
			
		||||
	for k, v := range provisioner.options.Parameters {
 | 
			
		||||
		switch goStrings.ToLower(k) {
 | 
			
		||||
		case "registry":
 | 
			
		||||
			provisioner.registry = v
 | 
			
		||||
		case "adminsecretname":
 | 
			
		||||
			adminSecretName = v
 | 
			
		||||
		case "adminsecretnamespace":
 | 
			
		||||
			adminSecretNamespace = v
 | 
			
		||||
		case "quobyteapiserver":
 | 
			
		||||
			apiServer = v
 | 
			
		||||
		case "user":
 | 
			
		||||
			provisioner.user = v
 | 
			
		||||
		case "group":
 | 
			
		||||
			provisioner.group = v
 | 
			
		||||
		case "quobytetenant":
 | 
			
		||||
			provisioner.tenant = v
 | 
			
		||||
		case "quobyteconfig":
 | 
			
		||||
			provisioner.config = v
 | 
			
		||||
		default:
 | 
			
		||||
			return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, provisioner.plugin.GetPluginName())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	secretMap, err := util.GetSecret(adminSecretNamespace, adminSecretName, provisioner.plugin.host.GetKubeClient())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ok bool
 | 
			
		||||
	if quobyteUser, ok = secretMap["user"]; !ok {
 | 
			
		||||
		return nil, fmt.Errorf("Missing \"user\" in secret")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if quobytePassword, ok = secretMap["password"]; !ok {
 | 
			
		||||
		return nil, fmt.Errorf("Missing \"password\" in secret")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !validateRegistry(provisioner.registry) {
 | 
			
		||||
		return nil, fmt.Errorf("Quoybte registry missing or malformed: must be a host:port pair or multiple pairs seperated by commas")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(apiServer) == 0 {
 | 
			
		||||
		return nil, fmt.Errorf("Quoybte API server missing or malformed: must be a http(s)://host:port pair or multiple pairs seperated by commas")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create random image name
 | 
			
		||||
	provisioner.volume = fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.NewUUID())
 | 
			
		||||
 | 
			
		||||
	cfg := &quobyteAPIConfig{
 | 
			
		||||
		quobyteAPIServer: apiServer,
 | 
			
		||||
		quobyteUser:      quobyteUser,
 | 
			
		||||
		quobytePassword:  quobytePassword,
 | 
			
		||||
	}
 | 
			
		||||
	manager := &quobyteVolumeManager{
 | 
			
		||||
		config: cfg,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vol, sizeGB, err := manager.createVolume(provisioner)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	pv := new(api.PersistentVolume)
 | 
			
		||||
	pv.Spec.PersistentVolumeSource.Quobyte = vol
 | 
			
		||||
	pv.Spec.PersistentVolumeReclaimPolicy = provisioner.options.PersistentVolumeReclaimPolicy
 | 
			
		||||
	pv.Spec.AccessModes = provisioner.options.AccessModes
 | 
			
		||||
	pv.Spec.Capacity = api.ResourceList{
 | 
			
		||||
		api.ResourceName(api.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	util.AddVolumeAnnotations(pv, map[string]string{
 | 
			
		||||
		annotationQuobyteAPIServer:          apiServer,
 | 
			
		||||
		annotationQuobyteAPISecret:          adminSecretName,
 | 
			
		||||
		annotationQuobyteAPISecretNamespace: adminSecretNamespace,
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return pv, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (deleter *quobyteVolumeDeleter) GetPath() string {
 | 
			
		||||
	return deleter.quobyte.GetPath()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (deleter *quobyteVolumeDeleter) Delete() error {
 | 
			
		||||
	var quobyteUser, quobytePassword string
 | 
			
		||||
	annotations, err := util.ParseVolumeAnnotations(deleter.pv, []string{
 | 
			
		||||
		annotationQuobyteAPISecret,
 | 
			
		||||
		annotationQuobyteAPISecretNamespace,
 | 
			
		||||
		annotationQuobyteAPIServer})
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	secretMap, err := util.GetSecret(
 | 
			
		||||
		annotations[annotationQuobyteAPISecretNamespace],
 | 
			
		||||
		annotations[annotationQuobyteAPISecret],
 | 
			
		||||
		deleter.plugin.host.GetKubeClient())
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var ok bool
 | 
			
		||||
	if quobyteUser, ok = secretMap["user"]; !ok {
 | 
			
		||||
		return fmt.Errorf("Missing \"user\" in secret")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if quobytePassword, ok = secretMap["password"]; !ok {
 | 
			
		||||
		return fmt.Errorf("Missing \"password\" in secret")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	manager := &quobyteVolumeManager{
 | 
			
		||||
		config: &quobyteAPIConfig{
 | 
			
		||||
			quobyteUser:      quobyteUser,
 | 
			
		||||
			quobytePassword:  quobytePassword,
 | 
			
		||||
			quobyteAPIServer: annotations[annotationQuobyteAPIServer],
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	return manager.deleteVolume(deleter)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,58 @@ limitations under the License.
 | 
			
		||||
package quobyte
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"net"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/volume"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	quobyte_api "github.com/quobyte/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type quobyteVolumeManager struct {
 | 
			
		||||
	config *quobyteAPIConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (manager *quobyteVolumeManager) createVolume(provisioner *quobyteVolumeProvisioner) (quobyte *api.QuobyteVolumeSource, size int, err error) {
 | 
			
		||||
	volumeSize := int(volume.RoundUpSize(provisioner.options.Capacity.Value(), 1024*1024*1024))
 | 
			
		||||
	// 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
 | 
			
		||||
	volumeRequest := &quobyte_api.CreateVolumeRequest{
 | 
			
		||||
		Name:              provisioner.volume,
 | 
			
		||||
		RootUserID:        provisioner.user,
 | 
			
		||||
		RootGroupID:       provisioner.group,
 | 
			
		||||
		TenantID:          provisioner.tenant,
 | 
			
		||||
		ConfigurationName: provisioner.config,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err := manager.createQuobyteClient().CreateVolume(volumeRequest); err != nil {
 | 
			
		||||
		return &api.QuobyteVolumeSource{}, volumeSize, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glog.V(4).Infof("Created Quobyte volume %s", provisioner.volume)
 | 
			
		||||
	return &api.QuobyteVolumeSource{
 | 
			
		||||
		Registry: provisioner.registry,
 | 
			
		||||
		Volume:   provisioner.volume,
 | 
			
		||||
		User:     provisioner.user,
 | 
			
		||||
		Group:    provisioner.group,
 | 
			
		||||
	}, volumeSize, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (manager *quobyteVolumeManager) deleteVolume(deleter *quobyteVolumeDeleter) error {
 | 
			
		||||
	return manager.createQuobyteClient().DeleteVolumeByName(deleter.volume, deleter.tenant)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (manager *quobyteVolumeManager) createQuobyteClient() *quobyte_api.QuobyteClient {
 | 
			
		||||
	return quobyte_api.NewQuobyteClient(
 | 
			
		||||
		manager.config.quobyteAPIServer,
 | 
			
		||||
		manager.config.quobyteUser,
 | 
			
		||||
		manager.config.quobytePassword,
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mounter *quobyteMounter) pluginDirIsMounted(pluginDir string) (bool, error) {
 | 
			
		||||
	mounts, err := mounter.mounter.List()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -46,3 +92,17 @@ func (mounter *quobyteMounter) pluginDirIsMounted(pluginDir string) (bool, error
 | 
			
		||||
func (mounter *quobyteMounter) correctTraillingSlash(regStr string) string {
 | 
			
		||||
	return path.Clean(regStr) + "/"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func validateRegistry(registry string) bool {
 | 
			
		||||
	if len(registry) == 0 {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, hostPortPair := range strings.Split(registry, ",") {
 | 
			
		||||
		if _, _, err := net.SplitHostPort(hostPortPair); err != nil {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ import (
 | 
			
		||||
	"path"
 | 
			
		||||
 | 
			
		||||
	"github.com/golang/glog"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/api"
 | 
			
		||||
	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
 | 
			
		||||
	"k8s.io/kubernetes/pkg/util/mount"
 | 
			
		||||
)
 | 
			
		||||
@@ -126,3 +127,33 @@ func GetSecret(namespace, secretName string, kubeClient clientset.Interface) (ma
 | 
			
		||||
	}
 | 
			
		||||
	return secret, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddVolumeAnnotations adds a golang Map as annotation to a PersistentVolume
 | 
			
		||||
func AddVolumeAnnotations(pv *api.PersistentVolume, annotations map[string]string) {
 | 
			
		||||
	if pv.Annotations == nil {
 | 
			
		||||
		pv.Annotations = map[string]string{}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for k, v := range annotations {
 | 
			
		||||
		pv.Annotations[k] = v
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseVolumeAnnotations reads the defined annoations from a PersistentVolume
 | 
			
		||||
func ParseVolumeAnnotations(pv *api.PersistentVolume, parseAnnotations []string) (map[string]string, error) {
 | 
			
		||||
	result := map[string]string{}
 | 
			
		||||
 | 
			
		||||
	if pv.Annotations == nil {
 | 
			
		||||
		return result, fmt.Errorf("cannot parse volume annotations: no annotations found")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, annotation := range parseAnnotations {
 | 
			
		||||
		if val, ok := pv.Annotations[annotation]; ok {
 | 
			
		||||
			result[annotation] = val
 | 
			
		||||
		} else {
 | 
			
		||||
			return result, fmt.Errorf("cannot parse volume annotations: annotation %s not found", annotation)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return result, nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/quobyte/api/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/quobyte/api/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2016, Quobyte Inc.
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
* Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
* Redistributions in binary form must reproduce the above copyright notice,
 | 
			
		||||
  this list of conditions and the following disclaimer in the documentation
 | 
			
		||||
  and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
* Neither the name of quobyte-automation nor the names of its
 | 
			
		||||
  contributors may be used to endorse or promote products derived from
 | 
			
		||||
  this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
			
		||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
			
		||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										35
									
								
								vendor/github.com/quobyte/api/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/quobyte/api/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
# Quobyte API Clients
 | 
			
		||||
 | 
			
		||||
Get the quoybte api client
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
go get github.com/quobyte/api
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
  "log"
 | 
			
		||||
  quobyte_api "github.com/quobyte/api"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
    client := quobyte_api.NewQuobyteClient("http://apiserver:7860", "user", "password")
 | 
			
		||||
    req := &quobyte_api.CreateVolumeRequest{
 | 
			
		||||
        Name:              "MyVolume",
 | 
			
		||||
        RootUserID:        "root",
 | 
			
		||||
        RootGroupID:       "root",
 | 
			
		||||
        ConfigurationName: "base",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    volume_uuid, err := client.CreateVolume(req)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Fatalf("Error:", err)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    log.Printf("%s", volume_uuid)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										79
									
								
								vendor/github.com/quobyte/api/quobyte.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/quobyte/api/quobyte.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
// Package quobyte represents a golang API for the Quobyte Storage System
 | 
			
		||||
package quobyte
 | 
			
		||||
 | 
			
		||||
import "net/http"
 | 
			
		||||
 | 
			
		||||
type QuobyteClient struct {
 | 
			
		||||
	client   *http.Client
 | 
			
		||||
	url      string
 | 
			
		||||
	username string
 | 
			
		||||
	password string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewQuobyteClient creates a new Quobyte API client
 | 
			
		||||
func NewQuobyteClient(url string, username string, password string) *QuobyteClient {
 | 
			
		||||
	return &QuobyteClient{
 | 
			
		||||
		client:   &http.Client{},
 | 
			
		||||
		url:      url,
 | 
			
		||||
		username: username,
 | 
			
		||||
		password: password,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateVolume creates a new Quobyte volume. Its root directory will be owned by given user and group
 | 
			
		||||
func (client QuobyteClient) CreateVolume(request *CreateVolumeRequest) (string, error) {
 | 
			
		||||
	var response volumeUUID
 | 
			
		||||
	if err := client.sendRequest("createVolume", request, &response); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return response.VolumeUUID, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ResolveVolumeNameToUUID resolves a volume name to a UUID
 | 
			
		||||
func (client *QuobyteClient) ResolveVolumeNameToUUID(volumeName, tenant string) (string, error) {
 | 
			
		||||
	request := &resolveVolumeNameRequest{
 | 
			
		||||
		VolumeName:   volumeName,
 | 
			
		||||
		TenantDomain: tenant,
 | 
			
		||||
	}
 | 
			
		||||
	var response volumeUUID
 | 
			
		||||
	if err := client.sendRequest("resolveVolumeName", request, &response); err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return response.VolumeUUID, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteVolume deletes a Quobyte volume
 | 
			
		||||
func (client *QuobyteClient) DeleteVolume(UUID string) error {
 | 
			
		||||
	return client.sendRequest(
 | 
			
		||||
		"deleteVolume",
 | 
			
		||||
		&volumeUUID{
 | 
			
		||||
			VolumeUUID: UUID,
 | 
			
		||||
		},
 | 
			
		||||
		nil)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteVolumeByName deletes a volume by a given name
 | 
			
		||||
func (client *QuobyteClient) DeleteVolumeByName(volumeName, tenant string) error {
 | 
			
		||||
	uuid, err := client.ResolveVolumeNameToUUID(volumeName, tenant)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return client.DeleteVolume(uuid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetClientList returns a list of all active clients
 | 
			
		||||
func (client *QuobyteClient) GetClientList(tenant string) (GetClientListResponse, error) {
 | 
			
		||||
	request := &getClientListRequest{
 | 
			
		||||
		TenantDomain: tenant,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var response GetClientListResponse
 | 
			
		||||
	if err := client.sendRequest("getClientListRequest", request, &response); err != nil {
 | 
			
		||||
		return response, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return response, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										108
									
								
								vendor/github.com/quobyte/api/rpc_client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								vendor/github.com/quobyte/api/rpc_client.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
package quobyte
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	emptyResponse string = "Empty result and no error occured"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type request struct {
 | 
			
		||||
	ID      string      `json:"id"`
 | 
			
		||||
	Version string      `json:"jsonrpc"`
 | 
			
		||||
	Method  string      `json:"method"`
 | 
			
		||||
	Params  interface{} `json:"params"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type response struct {
 | 
			
		||||
	ID      string           `json:"id"`
 | 
			
		||||
	Version string           `json:"jsonrpc"`
 | 
			
		||||
	Result  *json.RawMessage `json:"result"`
 | 
			
		||||
	Error   *json.RawMessage `json:"error"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type rpcError struct {
 | 
			
		||||
	Code    int64  `json:"code"`
 | 
			
		||||
	Message string `json:"message"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (err *rpcError) decodeErrorCode() string {
 | 
			
		||||
	switch err.Code {
 | 
			
		||||
	case -32600:
 | 
			
		||||
		return "ERROR_CODE_INVALID_REQUEST"
 | 
			
		||||
	case -32603:
 | 
			
		||||
		return "ERROR_CODE_JSON_ENCODING_FAILED"
 | 
			
		||||
	case -32601:
 | 
			
		||||
		return "ERROR_CODE_METHOD_NOT_FOUND"
 | 
			
		||||
	case -32700:
 | 
			
		||||
		return "ERROR_CODE_PARSE_ERROR"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func encodeRequest(method string, params interface{}) ([]byte, error) {
 | 
			
		||||
	return json.Marshal(&request{
 | 
			
		||||
		// Generate random ID and convert it to a string
 | 
			
		||||
		ID:      strconv.FormatInt(rand.Int63(), 10),
 | 
			
		||||
		Version: "2.0",
 | 
			
		||||
		Method:  method,
 | 
			
		||||
		Params:  params,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func decodeResponse(ioReader io.Reader, reply interface{}) error {
 | 
			
		||||
	var resp response
 | 
			
		||||
	if err := json.NewDecoder(ioReader).Decode(&resp); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if resp.Error != nil {
 | 
			
		||||
		var rpcErr rpcError
 | 
			
		||||
		if err := json.Unmarshal(*resp.Error, &rpcErr); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if rpcErr.Message != "" {
 | 
			
		||||
			return errors.New(rpcErr.Message)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		respError := rpcErr.decodeErrorCode()
 | 
			
		||||
		if respError != "" {
 | 
			
		||||
			return errors.New(respError)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if resp.Result != nil && reply != nil {
 | 
			
		||||
		return json.Unmarshal(*resp.Result, reply)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return errors.New(emptyResponse)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client QuobyteClient) sendRequest(method string, request interface{}, response interface{}) error {
 | 
			
		||||
	message, err := encodeRequest(method, request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	req, err := http.NewRequest("POST", client.url, bytes.NewBuffer(message))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("Content-Type", "application/json")
 | 
			
		||||
	req.SetBasicAuth(client.username, client.password)
 | 
			
		||||
	resp, err := client.client.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
 | 
			
		||||
	return decodeResponse(resp.Body, &response)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/quobyte/api/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/quobyte/api/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
package quobyte
 | 
			
		||||
 | 
			
		||||
// CreateVolumeRequest represents a CreateVolumeRequest
 | 
			
		||||
type CreateVolumeRequest struct {
 | 
			
		||||
	Name              string   `json:"name,omitempty"`
 | 
			
		||||
	RootUserID        string   `json:"root_user_id,omitempty"`
 | 
			
		||||
	RootGroupID       string   `json:"root_group_id,omitempty"`
 | 
			
		||||
	ReplicaDeviceIDS  []uint64 `json:"replica_device_ids,string,omitempty"`
 | 
			
		||||
	ConfigurationName string   `json:"configuration_name,omitempty"`
 | 
			
		||||
	AccessMode        uint32   `json:"access_mode,string,omitempty"`
 | 
			
		||||
	TenantID          string   `json:"tenant_id,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type resolveVolumeNameRequest struct {
 | 
			
		||||
	VolumeName   string `json:"volume_name,omitempty"`
 | 
			
		||||
	TenantDomain string `json:"tenant_domain,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type volumeUUID struct {
 | 
			
		||||
	VolumeUUID string `json:"volume_uuid,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getClientListRequest struct {
 | 
			
		||||
	TenantDomain string `json:"tenant_domain,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type GetClientListResponse struct {
 | 
			
		||||
	Clients []Client `json:"client,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Client struct {
 | 
			
		||||
	MountedUserName   string `json:"mount_user_name,omitempty"`
 | 
			
		||||
	MountedVolumeUUID string `json:"mounted_volume_uuid,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user