cleanup: Remove quobyte volume plugins from k8s codebase

This commit is contained in:
Jiawei Wang 2022-08-02 00:34:27 +00:00
parent 83591a1196
commit 9c869b3dfc
17 changed files with 1 additions and 1465 deletions

View File

@ -1,32 +0,0 @@
= 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

View File

@ -40,7 +40,6 @@ import (
"k8s.io/kubernetes/pkg/volume/iscsi"
"k8s.io/kubernetes/pkg/volume/local"
"k8s.io/kubernetes/pkg/volume/nfs"
"k8s.io/kubernetes/pkg/volume/quobyte"
"k8s.io/kubernetes/pkg/volume/storageos"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
@ -125,8 +124,7 @@ func ProbeControllerVolumePlugins(cloud cloudprovider.Interface, config persiste
}
allPlugins = append(allPlugins, nfs.ProbeVolumePlugins(nfsConfig)...)
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
// add rbd provisioner
allPlugins = append(allPlugins, quobyte.ProbeVolumePlugins()...)
var err error
allPlugins, err = appendExpandableLegacyProviderVolumes(allPlugins, utilfeature.DefaultFeatureGate)
if err != nil {

View File

@ -38,7 +38,6 @@ import (
"k8s.io/kubernetes/pkg/volume/local"
"k8s.io/kubernetes/pkg/volume/nfs"
"k8s.io/kubernetes/pkg/volume/projected"
"k8s.io/kubernetes/pkg/volume/quobyte"
"k8s.io/kubernetes/pkg/volume/secret"
"k8s.io/kubernetes/pkg/volume/storageos"
@ -68,7 +67,6 @@ func ProbeVolumePlugins(featureGate featuregate.FeatureGate) ([]volume.VolumePlu
allPlugins = append(allPlugins, secret.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, quobyte.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, cephfs.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)

2
go.mod
View File

@ -63,7 +63,6 @@ require (
github.com/prometheus/client_golang v1.12.1
github.com/prometheus/client_model v0.2.0
github.com/prometheus/common v0.32.1
github.com/quobyte/api v0.1.8
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
@ -473,7 +472,6 @@ replace (
github.com/prometheus/client_model => github.com/prometheus/client_model v0.2.0
github.com/prometheus/common => github.com/prometheus/common v0.32.1
github.com/prometheus/procfs => github.com/prometheus/procfs v0.7.3
github.com/quobyte/api => github.com/quobyte/api v0.1.8
github.com/remyoudompheng/bigfft => github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446
github.com/robfig/cron/v3 => github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/fastuuid => github.com/rogpeppe/fastuuid v1.2.0

2
go.sum
View File

@ -367,8 +367,6 @@ github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuI
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/quobyte/api v0.1.8 h1:+sOX1gIlC/OaLipqVZWrHgly9Kh9Qo8OygeS0mWAg30=
github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=

View File

@ -53,7 +53,6 @@ import (
"k8s.io/kubernetes/pkg/volume/nfs"
"k8s.io/kubernetes/pkg/volume/portworx"
"k8s.io/kubernetes/pkg/volume/projected"
"k8s.io/kubernetes/pkg/volume/quobyte"
"k8s.io/kubernetes/pkg/volume/rbd"
"k8s.io/kubernetes/pkg/volume/secret"
"k8s.io/kubernetes/pkg/volume/storageos"
@ -78,7 +77,6 @@ func volumePlugins() []volume.VolumePlugin {
allPlugins = append(allPlugins, iscsi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, quobyte.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, cephfs.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)

View File

@ -1,11 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- saad-ali
reviewers:
- saad-ali
- jsafrane
- jingxu97
- msau42
emeritus_approvers:
- rootfs

View File

@ -1,19 +0,0 @@
/*
Copyright 2016 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 quobyte contains the internal representation of Quobyte
// volumes.
package quobyte

View File

@ -1,513 +0,0 @@
/*
Copyright 2016 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 quobyte
import (
"errors"
"fmt"
"os"
"path/filepath"
gostrings "strings"
"github.com/google/uuid"
"k8s.io/klog/v2"
"k8s.io/mount-utils"
utilstrings "k8s.io/utils/strings"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/util"
)
// ProbeVolumePlugins is the primary entrypoint for volume plugins.
func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{&quobytePlugin{nil}}
}
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 `datapolicy:"password"`
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"
)
func (plugin *quobytePlugin) Init(host volume.VolumeHost) error {
if host == nil {
return errors.New("host must not be nil")
}
plugin.host = host
return nil
}
func (plugin *quobytePlugin) GetPluginName() string {
return quobytePluginName
}
func (plugin *quobytePlugin) GetVolumeName(spec *volume.Spec) (string, error) {
volumeSource, _, err := getVolumeSource(spec)
if err != nil {
return "", err
}
return fmt.Sprintf(
"%v:%v",
volumeSource.Registry,
volumeSource.Volume), nil
}
func (plugin *quobytePlugin) CanSupport(spec *volume.Spec) bool {
if (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Quobyte == nil) ||
(spec.Volume != nil && spec.Volume.Quobyte == nil) {
return false
}
// If Quobyte is already mounted we don't need to check if the binary is installed
if mounter, err := plugin.newMounterInternal(spec, nil, plugin.host.GetMounter(plugin.GetPluginName())); err == nil {
qm, _ := mounter.(*quobyteMounter)
pluginDir := plugin.host.GetPluginDir(utilstrings.EscapeQualifiedName(quobytePluginName))
if mounted, err := qm.pluginDirIsMounted(pluginDir); mounted && err == nil {
klog.V(4).Infof("quobyte: can support")
return true
}
} else {
klog.V(4).Infof("quobyte: Error: %v", err)
}
exec := plugin.host.GetExec(plugin.GetPluginName())
if out, err := exec.Command("ls", "/sbin/mount.quobyte").CombinedOutput(); err == nil {
klog.V(4).Infof("quobyte: can support: %s", string(out))
return true
}
return false
}
func (plugin *quobytePlugin) RequiresRemount(spec *volume.Spec) bool {
return false
}
func (plugin *quobytePlugin) SupportsMountOption() bool {
return true
}
func (plugin *quobytePlugin) SupportsBulkVolumeVerification() bool {
return false
}
func (plugin *quobytePlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
return []v1.PersistentVolumeAccessMode{
v1.ReadWriteOnce,
v1.ReadOnlyMany,
v1.ReadWriteMany,
}
}
func getVolumeSource(spec *volume.Spec) (*v1.QuobyteVolumeSource, bool, error) {
if spec.Volume != nil && spec.Volume.Quobyte != nil {
return spec.Volume.Quobyte, spec.Volume.Quobyte.ReadOnly, nil
} else if spec.PersistentVolume != nil &&
spec.PersistentVolume.Spec.Quobyte != nil {
return spec.PersistentVolume.Spec.Quobyte, spec.ReadOnly, nil
}
return nil, false, fmt.Errorf("Spec does not reference a Quobyte volume type")
}
func (plugin *quobytePlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
quobyteVolume := &v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
Quobyte: &v1.QuobyteVolumeSource{
Volume: volumeName,
},
},
}
return volume.NewSpecFromVolume(quobyteVolume), nil
}
func (plugin *quobytePlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter(plugin.GetPluginName()))
}
func (plugin *quobytePlugin) newMounterInternal(spec *volume.Spec, pod *v1.Pod, mounter mount.Interface) (volume.Mounter, error) {
source, readOnly, err := getVolumeSource(spec)
if err != nil {
return nil, err
}
return &quobyteMounter{
quobyte: &quobyte{
volName: spec.Name(),
user: source.User,
group: source.Group,
mounter: mounter,
pod: pod,
volume: source.Volume,
plugin: plugin,
},
registry: source.Registry,
readOnly: readOnly,
mountOptions: util.MountOptionFromSpec(spec),
}, nil
}
func (plugin *quobytePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter(plugin.GetPluginName()))
}
func (plugin *quobytePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Unmounter, error) {
return &quobyteUnmounter{
&quobyte{
volName: volName,
mounter: mounter,
pod: &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: podUID}},
plugin: plugin,
},
}, nil
}
// Quobyte volumes represent a bare host directory mount of an quobyte export.
type quobyte struct {
volName string
pod *v1.Pod
user string
group string
volume string
tenant string
config string
mounter mount.Interface
plugin *quobytePlugin
volume.MetricsNil
}
type quobyteMounter struct {
*quobyte
registry string
readOnly bool
mountOptions []string
}
var _ volume.Mounter = &quobyteMounter{}
func (mounter *quobyteMounter) GetAttributes() volume.Attributes {
return volume.Attributes{
ReadOnly: mounter.readOnly,
Managed: false,
SELinuxRelabel: false,
}
}
// SetUp attaches the disk and bind mounts to the volume path.
func (mounter *quobyteMounter) SetUp(mounterArgs volume.MounterArgs) error {
pluginDir := mounter.plugin.host.GetPluginDir(utilstrings.EscapeQualifiedName(quobytePluginName))
return mounter.SetUpAt(pluginDir, mounterArgs)
}
func (mounter *quobyteMounter) SetUpAt(dir string, mounterArgs volume.MounterArgs) error {
// Check if Quobyte is already mounted on the host in the Plugin Dir
// if so we can use this mountpoint instead of creating a new one
// IsLikelyNotMountPoint wouldn't check the mount type
if mounted, err := mounter.pluginDirIsMounted(dir); err != nil {
return err
} else if mounted {
return nil
}
if err := os.MkdirAll(dir, 0750); err != nil {
return err
}
var options []string
options = append(options, "allow-usermapping-in-volumename")
if mounter.readOnly {
options = append(options, "ro")
}
//if a trailing slash is missing we add it here
mountOptions := util.JoinMountOptions(mounter.mountOptions, options)
if err := mounter.mounter.MountSensitiveWithoutSystemd(mounter.correctTraillingSlash(mounter.registry), dir, "quobyte", mountOptions, nil); err != nil {
return fmt.Errorf("quobyte: mount failed: %v", err)
}
klog.V(4).Infof("quobyte: mount set up: %s", dir)
return nil
}
// GetPath returns the path to the user specific mount of a Quobyte 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(utilstrings.EscapeQualifiedName(quobytePluginName))
return filepath.Join(pluginDir, fmt.Sprintf("%s#%s@%s", user, group, quobyteVolume.volume))
}
type quobyteUnmounter struct {
*quobyte
}
var _ volume.Unmounter = &quobyteUnmounter{}
func (unmounter *quobyteUnmounter) TearDown() error {
return unmounter.TearDownAt(unmounter.GetPath())
}
// We don't need to unmount on the host because only one mount exists
func (unmounter *quobyteUnmounter) TearDownAt(dir string) error {
return nil
}
type quobyteVolumeDeleter struct {
*quobyteMounter
pv *v1.PersistentVolume
dialOptions *proxyutil.FilteredDialOptions
}
func (plugin *quobytePlugin) NewDeleter(spec *volume.Spec) (volume.Deleter, error) {
if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.Quobyte == nil {
return nil, fmt.Errorf("spec.PersistentVolume.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
}
if plugin.host == nil {
return nil, errors.New("host must not be nil")
}
return &quobyteVolumeDeleter{
quobyteMounter: &quobyteMounter{
quobyte: &quobyte{
volName: spec.Name(),
user: source.User,
group: source.Group,
volume: source.Volume,
plugin: plugin,
tenant: source.Tenant,
},
registry: source.Registry,
readOnly: readOnly,
},
pv: spec.PersistentVolume,
dialOptions: plugin.host.GetFilteredDialOptions(),
}, nil
}
func (plugin *quobytePlugin) NewProvisioner(options volume.VolumeOptions) (volume.Provisioner, error) {
return plugin.newProvisionerInternal(options)
}
func (plugin *quobytePlugin) newProvisionerInternal(options volume.VolumeOptions) (volume.Provisioner, error) {
if plugin.host == nil {
return nil, errors.New("host must not be nil")
}
return &quobyteVolumeProvisioner{
quobyteMounter: &quobyteMounter{
quobyte: &quobyte{
plugin: plugin,
},
},
options: options,
dialOptions: plugin.host.GetFilteredDialOptions(),
}, nil
}
type quobyteVolumeProvisioner struct {
*quobyteMounter
options volume.VolumeOptions
dialOptions *proxyutil.FilteredDialOptions
}
func (provisioner *quobyteVolumeProvisioner) Provision(selectedNode *v1.Node, allowedTopologies []v1.TopologySelectorTerm) (*v1.PersistentVolume, error) {
if !util.ContainsAllAccessModes(provisioner.plugin.GetAccessModes(), provisioner.options.PVC.Spec.AccessModes) {
return nil, fmt.Errorf("invalid AccessModes %v: only AccessModes %v are supported", provisioner.options.PVC.Spec.AccessModes, provisioner.plugin.GetAccessModes())
}
if util.CheckPersistentVolumeClaimModeBlock(provisioner.options.PVC) {
return nil, fmt.Errorf("%s does not support block volume provisioning", provisioner.plugin.GetPluginName())
}
if provisioner.options.PVC.Spec.Selector != nil {
return nil, fmt.Errorf("claim Selector is not supported")
}
provisioner.config = "BASE"
provisioner.tenant = "DEFAULT"
createQuota := false
cfg, err := parseAPIConfig(provisioner.plugin, provisioner.options.Parameters)
if err != nil {
return nil, err
}
for k, v := range provisioner.options.Parameters {
switch gostrings.ToLower(k) {
case "registry":
provisioner.registry = v
case "user":
provisioner.user = v
case "group":
provisioner.group = v
case "quobytetenant":
provisioner.tenant = v
case "quobyteconfig":
provisioner.config = v
case "createquota":
createQuota = gostrings.ToLower(v) == "true"
case "adminsecretname",
"adminsecretnamespace",
"quobyteapiserver":
continue
default:
return nil, fmt.Errorf("invalid option %q for volume plugin %s", k, provisioner.plugin.GetPluginName())
}
}
if !validateRegistry(provisioner.registry) {
return nil, fmt.Errorf("quobyte registry missing or malformed: must be a host:port pair or multiple pairs separated by commas")
}
// create random image name
provisioner.volume = fmt.Sprintf("kubernetes-dynamic-pvc-%s", uuid.New().String())
manager := &quobyteVolumeManager{
config: cfg,
dialOptions: provisioner.dialOptions,
}
vol, sizeGB, err := manager.createVolume(provisioner, createQuota)
if err != nil {
// don't log error details from client calls in events
klog.V(4).Infof("CreateVolume failed: %v", err)
return nil, errors.New("CreateVolume failed: see kube-controller-manager.log for details")
}
pv := new(v1.PersistentVolume)
metav1.SetMetaDataAnnotation(&pv.ObjectMeta, util.VolumeDynamicallyCreatedByKey, "quobyte-dynamic-provisioner")
pv.Spec.PersistentVolumeSource.Quobyte = vol
pv.Spec.PersistentVolumeReclaimPolicy = provisioner.options.PersistentVolumeReclaimPolicy
pv.Spec.AccessModes = provisioner.options.PVC.Spec.AccessModes
if len(pv.Spec.AccessModes) == 0 {
pv.Spec.AccessModes = provisioner.plugin.GetAccessModes()
}
pv.Spec.Capacity = v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): resource.MustParse(fmt.Sprintf("%dGi", sizeGB)),
}
pv.Spec.MountOptions = provisioner.options.MountOptions
pv.Spec.PersistentVolumeSource.Quobyte.Tenant = provisioner.tenant
return pv, nil
}
func (deleter *quobyteVolumeDeleter) GetPath() string {
return deleter.quobyte.GetPath()
}
func (deleter *quobyteVolumeDeleter) Delete() error {
class, err := util.GetClassForVolume(deleter.plugin.host.GetKubeClient(), deleter.pv)
if err != nil {
return err
}
cfg, err := parseAPIConfig(deleter.plugin, class.Parameters)
if err != nil {
return err
}
manager := &quobyteVolumeManager{
config: cfg,
dialOptions: deleter.dialOptions,
}
err = manager.deleteVolume(deleter)
if err != nil {
// don't log error details from client calls in events
klog.V(4).Infof("DeleteVolume failed: %v", err)
return errors.New("DeleteVolume failed: see kube-controller-manager.log for details")
}
return nil
}
// Parse API configuration (url, username and password) out of class.Parameters.
func parseAPIConfig(plugin *quobytePlugin, params map[string]string) (*quobyteAPIConfig, error) {
var apiServer, secretName string
secretNamespace := "default"
for k, v := range params {
switch gostrings.ToLower(k) {
case "adminsecretname":
secretName = v
case "adminsecretnamespace":
secretNamespace = v
case "quobyteapiserver":
apiServer = v
}
}
if len(apiServer) == 0 {
return nil, fmt.Errorf("quobyte API server missing or malformed: must be a http(s)://host:port pair or multiple pairs separated by commas")
}
secretMap, err := util.GetSecretForPV(secretNamespace, secretName, quobytePluginName, plugin.host.GetKubeClient())
if err != nil {
return nil, err
}
cfg := &quobyteAPIConfig{
quobyteAPIServer: apiServer,
}
var ok bool
if cfg.quobyteUser, ok = secretMap["user"]; !ok {
return nil, fmt.Errorf("missing \"user\" in secret %s/%s", secretNamespace, secretName)
}
if cfg.quobytePassword, ok = secretMap["password"]; !ok {
return nil, fmt.Errorf("missing \"password\" in secret %s/%s", secretNamespace, secretName)
}
return cfg, nil
}

View File

@ -1,197 +0,0 @@
/*
Copyright 2016 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 quobyte
import (
"fmt"
"os"
"path/filepath"
"testing"
"k8s.io/mount-utils"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/fake"
utiltesting "k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/volume"
volumetest "k8s.io/kubernetes/pkg/volume/testing"
)
func TestCanSupport(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("quobyte_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte")
if err != nil {
t.Fatal("Can't find the plugin by name")
}
if plug.GetPluginName() != "kubernetes.io/quobyte" {
t.Errorf("Wrong name: %s", plug.GetPluginName())
}
if plug.CanSupport(&volume.Spec{PersistentVolume: &v1.PersistentVolume{Spec: v1.PersistentVolumeSpec{PersistentVolumeSource: v1.PersistentVolumeSource{}}}}) {
t.Errorf("Expected false")
}
if plug.CanSupport(&volume.Spec{Volume: &v1.Volume{VolumeSource: v1.VolumeSource{}}}) {
t.Errorf("Expected false")
}
}
func TestGetAccessModes(t *testing.T) {
tmpDir, err := utiltesting.MkTmpdir("quobyte_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/quobyte")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
if !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadWriteOnce) || !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadOnlyMany) || !volumetest.ContainsAccessMode(plug.GetAccessModes(), v1.ReadWriteMany) {
t.Errorf("Expected three AccessModeTypes: %s, %s, and %s", v1.ReadWriteOnce, v1.ReadOnlyMany, v1.ReadWriteMany)
}
}
func doTestPlugin(t *testing.T, spec *volume.Spec) {
tmpDir, err := utiltesting.MkTmpdir("quobyte_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, nil, nil))
plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte")
if err != nil {
t.Errorf("Can't find the plugin by name")
}
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
mounter, err := plug.(*quobytePlugin).newMounterInternal(spec, pod, mount.NewFakeMounter(nil))
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
}
if mounter == nil {
t.Fatal("Got a nil Mounter")
}
volumePath := mounter.GetPath()
if volumePath != filepath.Join(tmpDir, "plugins/kubernetes.io~quobyte/root#root@vol") {
t.Errorf("Got unexpected path: %s expected: %s", volumePath, fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir))
}
if err := mounter.SetUp(volume.MounterArgs{}); err != nil {
t.Errorf("Expected success, got: %v", err)
}
unmounter, err := plug.(*quobytePlugin).newUnmounterInternal("vol", types.UID("poduid"), mount.NewFakeMounter(nil))
if err != nil {
t.Errorf("Failed to make a new unmounter: %v", err)
}
if unmounter == nil {
t.Error("Got a nil unmounter")
}
if err := unmounter.TearDown(); err != nil {
t.Errorf("Expected success, got: %v", err)
}
// We don't need to check tear down, we don't unmount quobyte
}
func TestPluginVolume(t *testing.T) {
vol := &v1.Volume{
Name: "vol1",
VolumeSource: v1.VolumeSource{
Quobyte: &v1.QuobyteVolumeSource{Registry: "reg:7861", Volume: "vol", ReadOnly: false, User: "root", Group: "root"},
},
}
doTestPlugin(t, volume.NewSpecFromVolume(vol))
}
func TestPluginPersistentVolume(t *testing.T) {
vol := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "vol1",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
Quobyte: &v1.QuobyteVolumeSource{Registry: "reg:7861", Volume: "vol", ReadOnly: false, User: "root", Group: "root"},
},
},
}
doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
}
func TestPersistentClaimReadOnlyFlag(t *testing.T) {
pv := &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pvA",
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeSource: v1.PersistentVolumeSource{
Quobyte: &v1.QuobyteVolumeSource{Registry: "reg:7861", Volume: "vol", ReadOnly: false, User: "root", Group: "root"},
},
ClaimRef: &v1.ObjectReference{
Name: "claimA",
},
},
}
claim := &v1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{
Name: "claimA",
Namespace: "nsA",
},
Spec: v1.PersistentVolumeClaimSpec{
VolumeName: "pvA",
},
Status: v1.PersistentVolumeClaimStatus{
Phase: v1.ClaimBound,
},
}
tmpDir, err := utiltesting.MkTmpdir("quobyte_test")
if err != nil {
t.Fatalf("error creating temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
client := fake.NewSimpleClientset(pv, claim)
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, volumetest.NewFakeVolumeHost(t, tmpDir, client, nil))
plug, _ := plugMgr.FindPluginByName(quobytePluginName)
// readOnly bool is supplied by persistent-claim volume source when its mounter creates other volumes
spec := volume.NewSpecFromPersistentVolume(pv, true)
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{UID: types.UID("poduid")}}
mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
if mounter == nil {
t.Fatalf("Got a nil Mounter")
}
if !mounter.GetAttributes().ReadOnly {
t.Errorf("Expected true for mounter.IsReadOnly")
}
}

View File

@ -1,132 +0,0 @@
/*
Copyright 2016 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 quobyte
import (
"net"
"net/http"
"os"
"path/filepath"
"strings"
v1 "k8s.io/api/core/v1"
volumehelpers "k8s.io/cloud-provider/volume/helpers"
proxyutil "k8s.io/kubernetes/pkg/proxy/util"
quobyteapi "github.com/quobyte/api"
"k8s.io/klog/v2"
)
type quobyteVolumeManager struct {
config *quobyteAPIConfig
dialOptions *proxyutil.FilteredDialOptions
}
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)]
volumeSize, err := volumehelpers.RoundUpToGiBInt(capacity)
if err != nil {
return nil, 0, err
}
// Quobyte has the concept of Volumes which doesn't have a specific size (they can grow unlimited)
// to simulate a size constraint we set here a Quota for logical space
volumeRequest := &quobyteapi.CreateVolumeRequest{
Name: provisioner.volume,
RootUserID: provisioner.user,
RootGroupID: provisioner.group,
TenantID: provisioner.tenant,
ConfigurationName: provisioner.config,
}
quobyteClient := manager.createQuobyteClient()
volumeUUID, err := quobyteClient.CreateVolume(volumeRequest)
if err != nil {
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
}
}
klog.V(4).Infof("Created Quobyte volume %s", provisioner.volume)
return &v1.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() *quobyteapi.QuobyteClient {
client := quobyteapi.NewQuobyteClient(
manager.config.quobyteAPIServer,
manager.config.quobyteUser,
manager.config.quobytePassword,
)
// quobyte client library @v0.1.7 uses a zero-value http.Client with a nil
// transport which is equivalent to using http.DefaultTransport.
rt := http.DefaultTransport.(*http.Transport).Clone()
rt.DialContext = proxyutil.NewFilteredDialContext(rt.DialContext, nil, manager.dialOptions)
client.SetTransport(rt)
return client
}
func (mounter *quobyteMounter) pluginDirIsMounted(pluginDir string) (bool, error) {
mounts, err := mounter.mounter.List()
if err != nil {
return false, err
}
for _, mountPoint := range mounts {
if strings.HasPrefix(mountPoint.Type, "quobyte") {
continue
}
if mountPoint.Path == pluginDir {
klog.V(4).Infof("quobyte: found mountpoint %s in /proc/mounts", mountPoint.Path)
return true, nil
}
}
return false, nil
}
func (mounter *quobyteMounter) correctTraillingSlash(regStr string) string {
return filepath.Clean(regStr) + string(os.PathSeparator)
}
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
}

View File

@ -1,28 +0,0 @@
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.

View File

@ -1,40 +0,0 @@
# Quobyte API Clients
Get the quobyte 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")
client.SetAPIRetryPolicy(quobyte_api.RetryInfinitely) // Default quobyte_api.RetryInteractive
req := &quobyte_api.CreateVolumeRequest{
Name: "MyVolume",
RootUserID: "root",
RootGroupID: "root",
ConfigurationName: "BASE",
Labels: []quobyte_api.Label{
{Name: "label1", Value: "value1"},
{Name: "label2", Value: "value2"},
},
}
volumeUUID, err := client.CreateVolume(req)
if err != nil {
log.Fatalf("Error:", err)
}
log.Printf("%s", volumeUUID)
}
```

View File

@ -1,245 +0,0 @@
// Package quobyte represents a golang API for the Quobyte Storage System
package quobyte
import (
"net/http"
"regexp"
)
// retry policy codes
const (
RetryNever string = "NEVER"
RetryInteractive string = "INTERACTIVE"
RetryInfinitely string = "INFINITELY"
RetryOncePerTarget string = "ONCE_PER_TARGET"
)
var UUIDValidator = regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$")
type QuobyteClient struct {
client *http.Client
url string
username string
password string
apiRetryPolicy string
}
func (client *QuobyteClient) SetAPIRetryPolicy(retry string) {
client.apiRetryPolicy = retry
}
func (client *QuobyteClient) GetAPIRetryPolicy() string {
return client.apiRetryPolicy
}
func (client *QuobyteClient) SetTransport(t http.RoundTripper) {
client.client.Transport = t
}
// 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,
apiRetryPolicy: RetryInteractive,
}
}
// 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
tenantUUID, err := client.GetTenantUUID(request.TenantID)
if err != nil {
return "", err
}
request.TenantID = tenantUUID
if err = client.sendRequest("createVolume", request, &response); err != nil {
return "", err
}
return response.VolumeUUID, nil
}
// GetVolumeUUID resolves the volumeUUID for the given volume and tenant name.
// This method should be used when it is not clear if the given string is volume UUID or Name.
func (client QuobyteClient) GetVolumeUUID(volume, tenant string) (string, error) {
if len(volume) != 0 && !IsValidUUID(volume) {
tenantUUID, err := client.GetTenantUUID(tenant)
if err != nil {
return "", err
}
volUUID, err := client.ResolveVolumeNameToUUID(volume, tenantUUID)
if err != nil {
return "", err
}
return volUUID, nil
}
return volume, nil
}
// GetTenantUUID resolves the tenatnUUID for the given name
// This method should be used when it is not clear if the given string is Tenant UUID or Name.
func (client QuobyteClient) GetTenantUUID(tenant string) (string, error) {
if len(tenant) != 0 && !IsValidUUID(tenant) {
tenantUUID, err := client.ResolveTenantNameToUUID(tenant)
if err != nil {
return "", err
}
return tenantUUID, nil
}
return tenant, 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
}
// DeleteVolumeByResolvingNamesToUUID deletes the volume by resolving the volume name and tenant name to
// respective UUID if required.
// This method should be used if the given volume, tenant information is name or UUID.
func (client *QuobyteClient) DeleteVolumeByResolvingNamesToUUID(volume, tenant string) error {
volumeUUID, err := client.GetVolumeUUID(volume, tenant)
if err != nil {
return err
}
return client.DeleteVolume(volumeUUID)
}
// 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
}
// SetVolumeQuota sets a Quota to the specified Volume
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)
}
// GetTenant returns the Tenant configuration for all specified tenants
func (client *QuobyteClient) GetTenant(tenantIDs []string) (GetTenantResponse, error) {
request := &getTenantRequest{TenantIDs: tenantIDs}
var response GetTenantResponse
err := client.sendRequest("getTenant", request, &response)
if err != nil {
return response, err
}
return response, nil
}
// GetTenantMap returns a map that contains all tenant names and there ID's
func (client *QuobyteClient) GetTenantMap() (map[string]string, error) {
result := map[string]string{}
response, err := client.GetTenant([]string{})
if err != nil {
return result, err
}
for _, tenant := range response.Tenants {
result[tenant.Name] = tenant.TenantID
}
return result, nil
}
// SetTenant creates a Tenant with the specified name
func (client *QuobyteClient) SetTenant(tenantName string) (string, error) {
request := &setTenantRequest{
&TenantDomainConfiguration{
Name: tenantName,
},
retryPolicy{client.GetAPIRetryPolicy()},
}
var response setTenantResponse
err := client.sendRequest("setTenant", request, &response)
if err != nil {
return "", err
}
return response.TenantID, nil
}
// IsValidUUID Validates the given uuid
func IsValidUUID(uuid string) bool {
return UUIDValidator.MatchString(uuid)
}
// ResolveTenantNameToUUID Returns UUID for given name, error if not found.
func (client *QuobyteClient) ResolveTenantNameToUUID(name string) (string, error) {
request := &resolveTenantNameRequest{
TenantName: name,
}
var response resolveTenantNameResponse
err := client.sendRequest("resolveTenantName", request, &response)
if err != nil {
return "", err
}
return response.TenantID, nil
}

View File

@ -1,124 +0,0 @@
package quobyte
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"math/rand"
"net/http"
"reflect"
"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 {
etype := reflect.ValueOf(request).Elem()
field := etype.FieldByName("RetryPolicy")
if field.IsValid() {
field.SetString(client.GetAPIRetryPolicy())
}
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()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
log.Printf("Warning: HTTP status code for request is %s\n",
strconv.Itoa(resp.StatusCode))
if resp.StatusCode == 401 {
return errors.New("Unable to authenticate with Quobyte API service")
}
return fmt.Errorf("JsonRPC failed with error code %d", resp.StatusCode)
}
return decodeResponse(resp.Body, &response)
}

View File

@ -1,109 +0,0 @@
package quobyte
type retryPolicy struct {
RetryPolicy string `json:"retry,omitempty"`
}
// 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"`
Labels []Label `json:"label,omitempty"`
AccessMode uint32 `json:"access_mode,uint32,omitempty"`
TenantID string `json:"tenant_id,omitempty"`
retryPolicy
}
type Label struct {
Name string `json:"name,string,omitempty"`
Value string `json:"value,string,omitempty"`
}
type resolveVolumeNameRequest struct {
VolumeName string `json:"volume_name,omitempty"`
TenantDomain string `json:"tenant_domain,omitempty"`
retryPolicy
}
type resolveTenantNameRequest struct {
TenantName string `json:"tenant_name,omitempty"`
}
type resolveTenantNameResponse struct {
TenantID string `json:"tenant_id,omitempty"`
}
type volumeUUID struct {
VolumeUUID string `json:"volume_uuid,omitempty"`
}
type getClientListRequest struct {
TenantDomain string `json:"tenant_domain,omitempty"`
retryPolicy
}
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"`
}
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"`
retryPolicy
}
type getTenantRequest struct {
TenantIDs []string `json:"tenant_id,omitempty"`
retryPolicy
}
type GetTenantResponse struct {
Tenants []*TenantDomainConfiguration `json:"tenant,omitempty"`
}
type TenantDomainConfiguration struct {
TenantID string `json:"tenant_id,omitempty"`
Name string `json:"name,omitempty"`
RestrictToNetwork []string `json:"restrict_to_network,omitempty"`
VolumeAccess []*TenantDomainConfigurationVolumeAccess `json:"volume_access,omitempty"`
}
type TenantDomainConfigurationVolumeAccess struct {
VolumeUUID string `json:"volume_uuid,omitempty"`
RestrictToNetwork string `json:"restrict_to_network,omitempty"`
ReadOnly bool `json:"read_only,omitempty"`
}
type setTenantRequest struct {
Tenants *TenantDomainConfiguration `json:"tenant,omitempty"`
retryPolicy
}
type setTenantResponse struct {
TenantID string `json:"tenant_id,omitempty"`
}

4
vendor/modules.txt vendored
View File

@ -734,9 +734,6 @@ github.com/prometheus/common/model
github.com/prometheus/procfs
github.com/prometheus/procfs/internal/fs
github.com/prometheus/procfs/internal/util
# github.com/quobyte/api v0.1.8 => github.com/quobyte/api v0.1.8
## explicit
github.com/quobyte/api
# github.com/robfig/cron/v3 v3.0.1 => github.com/robfig/cron/v3 v3.0.1
## explicit; go 1.12
github.com/robfig/cron/v3
@ -2763,7 +2760,6 @@ sigs.k8s.io/yaml
# github.com/prometheus/client_model => github.com/prometheus/client_model v0.2.0
# github.com/prometheus/common => github.com/prometheus/common v0.32.1
# github.com/prometheus/procfs => github.com/prometheus/procfs v0.7.3
# github.com/quobyte/api => github.com/quobyte/api v0.1.8
# github.com/remyoudompheng/bigfft => github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446
# github.com/robfig/cron/v3 => github.com/robfig/cron/v3 v3.0.1
# github.com/rogpeppe/fastuuid => github.com/rogpeppe/fastuuid v1.2.0