mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Refactor RBD volume
This commit is contained in:
parent
6f06408eea
commit
1411c2698e
@ -355,6 +355,20 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
r.Keyring = "/etc/ceph/keyring"
|
||||
}
|
||||
},
|
||||
func(r *api.RBDPersistentVolumeSource, c fuzz.Continue) {
|
||||
r.RBDPool = c.RandString()
|
||||
if r.RBDPool == "" {
|
||||
r.RBDPool = "rbd"
|
||||
}
|
||||
r.RadosUser = c.RandString()
|
||||
if r.RadosUser == "" {
|
||||
r.RadosUser = "admin"
|
||||
}
|
||||
r.Keyring = c.RandString()
|
||||
if r.Keyring == "" {
|
||||
r.Keyring = "/etc/ceph/keyring"
|
||||
}
|
||||
},
|
||||
func(obj *api.HostPathVolumeSource, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(obj)
|
||||
types := []api.HostPathType{api.HostPathUnset, api.HostPathDirectoryOrCreate, api.HostPathDirectory,
|
||||
|
@ -64,8 +64,16 @@ func VisitPVSecretNames(pv *api.PersistentVolume, visitor Visitor) bool {
|
||||
return false
|
||||
}
|
||||
case source.RBD != nil:
|
||||
if source.RBD.SecretRef != nil && !visitor(getClaimRefNamespace(pv), source.RBD.SecretRef.Name) {
|
||||
return false
|
||||
if source.RBD.SecretRef != nil {
|
||||
// previously persisted PV objects use claimRef namespace
|
||||
ns := getClaimRefNamespace(pv)
|
||||
if len(source.RBD.SecretRef.Namespace) > 0 {
|
||||
// use the secret namespace if namespace is set
|
||||
ns = source.RBD.SecretRef.Namespace
|
||||
}
|
||||
if !visitor(ns, source.RBD.SecretRef.Name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
case source.ScaleIO != nil:
|
||||
if source.ScaleIO.SecretRef != nil && !visitor(getClaimRefNamespace(pv), source.ScaleIO.SecretRef.Name) {
|
||||
|
@ -65,9 +65,16 @@ func TestPVSecrets(t *testing.T) {
|
||||
{Spec: api.PersistentVolumeSpec{
|
||||
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
RBD: &api.RBDVolumeSource{
|
||||
SecretRef: &api.LocalObjectReference{
|
||||
RBD: &api.RBDPersistentVolumeSource{
|
||||
SecretRef: &api.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.RBD.SecretRef"}}}}},
|
||||
{Spec: api.PersistentVolumeSpec{
|
||||
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
RBD: &api.RBDPersistentVolumeSource{
|
||||
SecretRef: &api.SecretReference{
|
||||
Name: "Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
Namespace: "rbdns"}}}}},
|
||||
{Spec: api.PersistentVolumeSpec{
|
||||
ClaimRef: &api.ObjectReference{Namespace: "claimrefns", Name: "claimrefname"},
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
@ -141,6 +148,7 @@ func TestPVSecrets(t *testing.T) {
|
||||
"cephfs/Spec.PersistentVolumeSource.CephFS.SecretRef",
|
||||
"claimrefns/Spec.PersistentVolumeSource.FlexVolume.SecretRef",
|
||||
"claimrefns/Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
"rbdns/Spec.PersistentVolumeSource.RBD.SecretRef",
|
||||
"claimrefns/Spec.PersistentVolumeSource.ScaleIO.SecretRef",
|
||||
"claimrefns/Spec.PersistentVolumeSource.ISCSI.SecretRef",
|
||||
"storageosns/Spec.PersistentVolumeSource.StorageOS.SecretRef",
|
||||
|
@ -343,7 +343,7 @@ type PersistentVolumeSource struct {
|
||||
NFS *NFSVolumeSource
|
||||
// RBD represents a Rados Block Device mount on the host that shares a pod's lifetime
|
||||
// +optional
|
||||
RBD *RBDVolumeSource
|
||||
RBD *RBDPersistentVolumeSource
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
// +optional
|
||||
Quobyte *QuobyteVolumeSource
|
||||
@ -1006,6 +1006,37 @@ type RBDVolumeSource struct {
|
||||
ReadOnly bool
|
||||
}
|
||||
|
||||
// Represents a Rados Block Device mount that lasts the lifetime of a pod.
|
||||
// RBD volumes support ownership management and SELinux relabeling.
|
||||
type RBDPersistentVolumeSource struct {
|
||||
// Required: CephMonitors is a collection of Ceph monitors
|
||||
CephMonitors []string
|
||||
// Required: RBDImage is the rados image name
|
||||
RBDImage string
|
||||
// Filesystem type to mount.
|
||||
// Must be a filesystem type supported by the host operating system.
|
||||
// Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
|
||||
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||
// +optional
|
||||
FSType string
|
||||
// Optional: RadosPool is the rados pool name,default is rbd
|
||||
// +optional
|
||||
RBDPool string
|
||||
// Optional: RBDUser is the rados user name, default is admin
|
||||
// +optional
|
||||
RadosUser string
|
||||
// Optional: Keyring is the path to key ring for RBDUser, default is /etc/ceph/keyring
|
||||
// +optional
|
||||
Keyring string
|
||||
// Optional: SecretRef is reference to the authentication secret for User, default is empty.
|
||||
// +optional
|
||||
SecretRef *SecretReference
|
||||
// Optional: Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
// +optional
|
||||
ReadOnly bool
|
||||
}
|
||||
|
||||
// Represents a cinder volume resource in Openstack. A Cinder volume
|
||||
// must exist before mounting to a container. The volume must also be
|
||||
// in the same region as the kubelet. Cinder volumes support ownership
|
||||
|
@ -368,6 +368,18 @@ func SetDefaults_RBDVolumeSource(obj *v1.RBDVolumeSource) {
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_RBDPersistentVolumeSource(obj *v1.RBDPersistentVolumeSource) {
|
||||
if obj.RBDPool == "" {
|
||||
obj.RBDPool = "rbd"
|
||||
}
|
||||
if obj.RadosUser == "" {
|
||||
obj.RadosUser = "admin"
|
||||
}
|
||||
if obj.Keyring == "" {
|
||||
obj.Keyring = "/etc/ceph/keyring"
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_ScaleIOVolumeSource(obj *v1.ScaleIOVolumeSource) {
|
||||
if obj.ProtectionDomain == "" {
|
||||
obj.ProtectionDomain = "default"
|
||||
|
@ -1088,6 +1088,17 @@ func validateRBDVolumeSource(rbd *api.RBDVolumeSource, fldPath *field.Path) fiel
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateRBDPersistentVolumeSource(rbd *api.RBDPersistentVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(rbd.CephMonitors) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("monitors"), ""))
|
||||
}
|
||||
if len(rbd.RBDImage) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("image"), ""))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateCinderVolumeSource(cd *api.CinderVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(cd.VolumeID) == 0 {
|
||||
@ -1380,7 +1391,7 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("rbd"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateRBDVolumeSource(pv.Spec.RBD, specPath.Child("rbd"))...)
|
||||
allErrs = append(allErrs, validateRBDPersistentVolumeSource(pv.Spec.RBD, specPath.Child("rbd"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.Quobyte != nil {
|
||||
|
@ -898,6 +898,19 @@ func printRBDVolumeSource(rbd *api.RBDVolumeSource, w PrefixWriter) {
|
||||
rbd.CephMonitors, rbd.RBDImage, rbd.FSType, rbd.RBDPool, rbd.RadosUser, rbd.Keyring, rbd.SecretRef, rbd.ReadOnly)
|
||||
}
|
||||
|
||||
func printRBDPersistentVolumeSource(rbd *api.RBDPersistentVolumeSource, w PrefixWriter) {
|
||||
w.Write(LEVEL_2, "Type:\tRBD (a Rados Block Device mount on the host that shares a pod's lifetime)\n"+
|
||||
" CephMonitors:\t%v\n"+
|
||||
" RBDImage:\t%v\n"+
|
||||
" FSType:\t%v\n"+
|
||||
" RBDPool:\t%v\n"+
|
||||
" RadosUser:\t%v\n"+
|
||||
" Keyring:\t%v\n"+
|
||||
" SecretRef:\t%v\n"+
|
||||
" ReadOnly:\t%v\n",
|
||||
rbd.CephMonitors, rbd.RBDImage, rbd.FSType, rbd.RBDPool, rbd.RadosUser, rbd.Keyring, rbd.SecretRef, rbd.ReadOnly)
|
||||
}
|
||||
|
||||
func printDownwardAPIVolumeSource(d *api.DownwardAPIVolumeSource, w PrefixWriter) {
|
||||
w.Write(LEVEL_2, "Type:\tDownwardAPI (a volume populated by information about the pod)\n Items:\n")
|
||||
for _, mapping := range d.Items {
|
||||
@ -1108,7 +1121,7 @@ func describePersistentVolume(pv *api.PersistentVolume, events *api.EventList) (
|
||||
case pv.Spec.Glusterfs != nil:
|
||||
printGlusterfsVolumeSource(pv.Spec.Glusterfs, w)
|
||||
case pv.Spec.RBD != nil:
|
||||
printRBDVolumeSource(pv.Spec.RBD, w)
|
||||
printRBDPersistentVolumeSource(pv.Spec.RBD, w)
|
||||
case pv.Spec.Quobyte != nil:
|
||||
printQuobyteVolumeSource(pv.Spec.Quobyte, w)
|
||||
case pv.Spec.VsphereVolume != nil:
|
||||
|
@ -776,7 +776,7 @@ func TestPersistentVolumeDescriber(t *testing.T) {
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
RBD: &api.RBDVolumeSource{},
|
||||
RBD: &api.RBDPersistentVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -39,7 +39,7 @@ type diskManager interface {
|
||||
// Detaches the disk from the kubelet's host machine.
|
||||
DetachDisk(disk rbdUnmounter, mntPath string) error
|
||||
// Creates a rbd image
|
||||
CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDVolumeSource, volumeSizeGB int, err error)
|
||||
CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, volumeSizeGB int, err error)
|
||||
// Deletes a rbd image
|
||||
DeleteImage(deleter *rbdVolumeDeleter) error
|
||||
}
|
||||
|
@ -78,15 +78,19 @@ func (plugin *rbdPlugin) GetPluginName() string {
|
||||
}
|
||||
|
||||
func (plugin *rbdPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
|
||||
volumeSource, _, err := getVolumeSource(spec)
|
||||
mon, err := getVolumeSourceMonitors(spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
img, err := getVolumeSourceImage(spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"%v:%v",
|
||||
volumeSource.CephMonitors,
|
||||
volumeSource.RBDImage), nil
|
||||
mon,
|
||||
img), nil
|
||||
}
|
||||
|
||||
func (plugin *rbdPlugin) CanSupport(spec *volume.Spec) bool {
|
||||
@ -117,55 +121,79 @@ func (plugin *rbdPlugin) GetAccessModes() []v1.PersistentVolumeAccessMode {
|
||||
}
|
||||
|
||||
func (plugin *rbdPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
||||
var secret string
|
||||
var err error
|
||||
source, _ := plugin.getRBDVolumeSource(spec)
|
||||
|
||||
if source.SecretRef != nil {
|
||||
if secret, err = parsePodSecret(pod, source.SecretRef.Name, plugin.host.GetKubeClient()); err != nil {
|
||||
glog.Errorf("Couldn't get secret from %v/%v", pod.Namespace, source.SecretRef)
|
||||
secretName, secretNs, err := getSecretNameAndNamespace(spec, pod.Namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret := ""
|
||||
if len(secretName) > 0 && len(secretNs) > 0 {
|
||||
// if secret is provideded, retrieve it
|
||||
kubeClient := plugin.host.GetKubeClient()
|
||||
if kubeClient == nil {
|
||||
return nil, fmt.Errorf("Cannot get kube client")
|
||||
}
|
||||
secrets, err := kubeClient.Core().Secrets(secretNs).Get(secretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Couldn't get secret %v/%v err: %v", secretNs, secretName, err)
|
||||
return nil, err
|
||||
}
|
||||
for _, data := range secrets.Data {
|
||||
secret = string(data)
|
||||
}
|
||||
}
|
||||
|
||||
// Inject real implementations here, test through the internal function.
|
||||
return plugin.newMounterInternal(spec, pod.UID, &RBDUtil{}, plugin.host.GetMounter(plugin.GetPluginName()), plugin.host.GetExec(plugin.GetPluginName()), secret)
|
||||
}
|
||||
|
||||
func (plugin *rbdPlugin) getRBDVolumeSource(spec *volume.Spec) (*v1.RBDVolumeSource, bool) {
|
||||
// rbd volumes used directly in a pod have a ReadOnly flag set by the pod author.
|
||||
// rbd volumes used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD, spec.Volume.RBD.ReadOnly
|
||||
} else {
|
||||
return spec.PersistentVolume.Spec.RBD, spec.ReadOnly
|
||||
}
|
||||
}
|
||||
|
||||
func (plugin *rbdPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, manager diskManager, mounter mount.Interface, exec mount.Exec, secret string) (volume.Mounter, error) {
|
||||
source, readOnly := plugin.getRBDVolumeSource(spec)
|
||||
pool := source.RBDPool
|
||||
id := source.RadosUser
|
||||
keyring := source.Keyring
|
||||
mon, err := getVolumeSourceMonitors(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
img, err := getVolumeSourceImage(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fstype, err := getVolumeSourceFSType(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pool, err := getVolumeSourcePool(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := getVolumeSourceUser(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyring, err := getVolumeSourceKeyRing(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ro, err := getVolumeSourceReadOnly(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &rbdMounter{
|
||||
rbd: &rbd{
|
||||
podUID: podUID,
|
||||
volName: spec.Name(),
|
||||
Image: source.RBDImage,
|
||||
Image: img,
|
||||
Pool: pool,
|
||||
ReadOnly: readOnly,
|
||||
ReadOnly: ro,
|
||||
manager: manager,
|
||||
mounter: &mount.SafeFormatAndMount{Interface: mounter, Exec: exec},
|
||||
exec: exec,
|
||||
plugin: plugin,
|
||||
MetricsProvider: volume.NewMetricsStatFS(getPath(podUID, spec.Name(), plugin.host)),
|
||||
},
|
||||
Mon: source.CephMonitors,
|
||||
Mon: mon,
|
||||
Id: id,
|
||||
Keyring: keyring,
|
||||
Secret: secret,
|
||||
fsType: source.FSType,
|
||||
fsType: fstype,
|
||||
mountOptions: volume.MountOptionFromSpec(spec),
|
||||
}, nil
|
||||
}
|
||||
@ -289,8 +317,9 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
var err error
|
||||
adminSecretName := ""
|
||||
adminSecretNamespace := rbdDefaultAdminSecretNamespace
|
||||
secretName := ""
|
||||
secret := ""
|
||||
secretName := ""
|
||||
secretNamespace := ""
|
||||
imageFormat := rbdImageFormat2
|
||||
fstype := ""
|
||||
|
||||
@ -313,6 +342,8 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
r.Pool = v
|
||||
case "usersecretname":
|
||||
secretName = v
|
||||
case "usersecretnamespace":
|
||||
secretNamespace = v
|
||||
case "imageformat":
|
||||
imageFormat = v
|
||||
case "imagefeatures":
|
||||
@ -370,8 +401,9 @@ func (r *rbdVolumeProvisioner) Provision() (*v1.PersistentVolume, error) {
|
||||
glog.Infof("successfully created rbd image %q", image)
|
||||
pv := new(v1.PersistentVolume)
|
||||
metav1.SetMetaDataAnnotation(&pv.ObjectMeta, volumehelper.VolumeDynamicallyCreatedByKey, "rbd-dynamic-provisioner")
|
||||
rbd.SecretRef = new(v1.LocalObjectReference)
|
||||
rbd.SecretRef = new(v1.SecretReference)
|
||||
rbd.SecretRef.Name = secretName
|
||||
rbd.SecretRef.Namespace = secretNamespace
|
||||
rbd.RadosUser = r.Id
|
||||
rbd.FSType = fstype
|
||||
pv.Spec.PersistentVolumeSource.RBD = rbd
|
||||
@ -486,16 +518,83 @@ func (c *rbdUnmounter) TearDownAt(dir string) error {
|
||||
return diskTearDown(c.manager, *c, dir, c.mounter)
|
||||
}
|
||||
|
||||
func getVolumeSource(
|
||||
spec *volume.Spec) (*v1.RBDVolumeSource, bool, error) {
|
||||
func getVolumeSourceMonitors(spec *volume.Spec) ([]string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD, spec.Volume.RBD.ReadOnly, nil
|
||||
return spec.Volume.RBD.CephMonitors, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
return spec.PersistentVolume.Spec.RBD, spec.ReadOnly, nil
|
||||
return spec.PersistentVolume.Spec.RBD.CephMonitors, nil
|
||||
}
|
||||
|
||||
return nil, false, fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
return nil, fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func getVolumeSourceImage(spec *volume.Spec) (string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD.RBDImage, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
return spec.PersistentVolume.Spec.RBD.RBDImage, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func getVolumeSourceFSType(spec *volume.Spec) (string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD.FSType, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
return spec.PersistentVolume.Spec.RBD.FSType, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func getVolumeSourcePool(spec *volume.Spec) (string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD.RBDPool, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
return spec.PersistentVolume.Spec.RBD.RBDPool, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func getVolumeSourceUser(spec *volume.Spec) (string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD.RadosUser, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
return spec.PersistentVolume.Spec.RBD.RadosUser, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func getVolumeSourceKeyRing(spec *volume.Spec) (string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD.Keyring, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
return spec.PersistentVolume.Spec.RBD.Keyring, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func getVolumeSourceReadOnly(spec *volume.Spec) (bool, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
return spec.Volume.RBD.ReadOnly, nil
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
// rbd volumes used as a PersistentVolume gets the ReadOnly flag indirectly through
|
||||
// the persistent-claim volume used to mount the PV
|
||||
return spec.ReadOnly, nil
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("Spec does not reference a RBD volume type")
|
||||
}
|
||||
|
||||
func parsePodSecret(pod *v1.Pod, secretName string, kubeClient clientset.Interface) (string, error) {
|
||||
@ -531,3 +630,26 @@ func parseSecretMap(secretMap map[string]string) (string, error) {
|
||||
// If not found, the last secret in the map wins as done before
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
func getSecretNameAndNamespace(spec *volume.Spec, defaultNamespace string) (string, string, error) {
|
||||
if spec.Volume != nil && spec.Volume.RBD != nil {
|
||||
localSecretRef := spec.Volume.RBD.SecretRef
|
||||
if localSecretRef != nil {
|
||||
return localSecretRef.Name, defaultNamespace, nil
|
||||
}
|
||||
return "", "", nil
|
||||
|
||||
} else if spec.PersistentVolume != nil &&
|
||||
spec.PersistentVolume.Spec.RBD != nil {
|
||||
secretRef := spec.PersistentVolume.Spec.RBD.SecretRef
|
||||
secretNs := defaultNamespace
|
||||
if secretRef != nil {
|
||||
if len(secretRef.Namespace) != 0 {
|
||||
secretNs = secretRef.Namespace
|
||||
}
|
||||
return secretRef.Name, secretNs, nil
|
||||
}
|
||||
return "", "", nil
|
||||
}
|
||||
return "", "", fmt.Errorf("Spec does not reference an RBD volume type")
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -92,7 +93,7 @@ func (fake *fakeDiskManager) DetachDisk(c rbdUnmounter, mntPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fake *fakeDiskManager) CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDVolumeSource, volumeSizeGB int, err error) {
|
||||
func (fake *fakeDiskManager) CreateImage(provisioner *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, volumeSizeGB int, err error) {
|
||||
return nil, 0, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
@ -180,7 +181,7 @@ func TestPluginPersistentVolume(t *testing.T) {
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
RBD: &v1.RBDVolumeSource{
|
||||
RBD: &v1.RBDPersistentVolumeSource{
|
||||
CephMonitors: []string{"a", "b"},
|
||||
RBDImage: "bar",
|
||||
FSType: "ext4",
|
||||
@ -205,7 +206,7 @@ func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
||||
},
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
RBD: &v1.RBDVolumeSource{
|
||||
RBD: &v1.RBDPersistentVolumeSource{
|
||||
CephMonitors: []string{"a", "b"},
|
||||
RBDImage: "bar",
|
||||
FSType: "ext4",
|
||||
@ -329,3 +330,35 @@ func TestPersistAndLoadRBD(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSecretNameAndNamespace(t *testing.T) {
|
||||
secretName := "test-secret-name"
|
||||
secretNamespace := "test-secret-namespace"
|
||||
|
||||
volSpec := &volume.Spec{
|
||||
PersistentVolume: &v1.PersistentVolume{
|
||||
Spec: v1.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: v1.PersistentVolumeSource{
|
||||
RBD: &v1.RBDPersistentVolumeSource{
|
||||
CephMonitors: []string{"a", "b"},
|
||||
RBDImage: "bar",
|
||||
FSType: "ext4",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
secretRef := new(v1.SecretReference)
|
||||
secretRef.Name = secretName
|
||||
secretRef.Namespace = secretNamespace
|
||||
volSpec.PersistentVolume.Spec.PersistentVolumeSource.RBD.SecretRef = secretRef
|
||||
|
||||
foundSecretName, foundSecretNamespace, err := getSecretNameAndNamespace(volSpec, "default")
|
||||
if err != nil {
|
||||
t.Errorf("getSecretNameAndNamespace failed to get Secret's name and namespace: %v", err)
|
||||
}
|
||||
if strings.Compare(secretName, foundSecretName) != 0 || strings.Compare(secretNamespace, foundSecretNamespace) != 0 {
|
||||
t.Errorf("getSecretNameAndNamespace returned incorrect values, expected %s and %s but got %s and %s", secretName, secretNamespace, foundSecretName, foundSecretNamespace)
|
||||
}
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ func (util *RBDUtil) DetachDisk(c rbdUnmounter, mntPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDVolumeSource, size int, err error) {
|
||||
func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDPersistentVolumeSource, size int, err error) {
|
||||
var output []byte
|
||||
capacity := p.options.PVC.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
|
||||
volSizeBytes := capacity.Value()
|
||||
@ -400,7 +400,7 @@ func (util *RBDUtil) CreateImage(p *rbdVolumeProvisioner) (r *v1.RBDVolumeSource
|
||||
return nil, 0, fmt.Errorf("failed to create rbd image: %v, command output: %s", err, string(output))
|
||||
}
|
||||
|
||||
return &v1.RBDVolumeSource{
|
||||
return &v1.RBDPersistentVolumeSource{
|
||||
CephMonitors: p.rbdMounter.Mon,
|
||||
RBDImage: p.rbdMounter.Image,
|
||||
RBDPool: p.rbdMounter.Pool,
|
||||
|
@ -398,7 +398,7 @@ type PersistentVolumeSource struct {
|
||||
// RBD represents a Rados Block Device mount on the host that shares a pod's lifetime.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md
|
||||
// +optional
|
||||
RBD *RBDVolumeSource `json:"rbd,omitempty" protobuf:"bytes,6,opt,name=rbd"`
|
||||
RBD *RBDPersistentVolumeSource `json:"rbd,omitempty" protobuf:"bytes,6,opt,name=rbd"`
|
||||
// ISCSI represents an ISCSI Disk resource that is attached to a
|
||||
// kubelet's host machine and then exposed to the pod. Provisioned by an admin.
|
||||
// +optional
|
||||
@ -838,6 +838,50 @@ type RBDVolumeSource struct {
|
||||
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,8,opt,name=readOnly"`
|
||||
}
|
||||
|
||||
// Represents a Rados Block Device mount that lasts the lifetime of a pod.
|
||||
// RBD volumes support ownership management and SELinux relabeling.
|
||||
type RBDPersistentVolumeSource struct {
|
||||
// A collection of Ceph monitors.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
CephMonitors []string `json:"monitors" protobuf:"bytes,1,rep,name=monitors"`
|
||||
// The rados image name.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
RBDImage string `json:"image" protobuf:"bytes,2,opt,name=image"`
|
||||
// Filesystem type of the volume that you want to mount.
|
||||
// Tip: Ensure that the filesystem type is supported by the host operating system.
|
||||
// Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
|
||||
// More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd
|
||||
// TODO: how do we prevent errors in the filesystem from compromising the machine
|
||||
// +optional
|
||||
FSType string `json:"fsType,omitempty" protobuf:"bytes,3,opt,name=fsType"`
|
||||
// The rados pool name.
|
||||
// Default is rbd.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
// +optional
|
||||
RBDPool string `json:"pool,omitempty" protobuf:"bytes,4,opt,name=pool"`
|
||||
// The rados user name.
|
||||
// Default is admin.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
// +optional
|
||||
RadosUser string `json:"user,omitempty" protobuf:"bytes,5,opt,name=user"`
|
||||
// Keyring is the path to key ring for RBDUser.
|
||||
// Default is /etc/ceph/keyring.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
// +optional
|
||||
Keyring string `json:"keyring,omitempty" protobuf:"bytes,6,opt,name=keyring"`
|
||||
// SecretRef is name of the authentication secret for RBDUser. If provided
|
||||
// overrides keyring.
|
||||
// Default is nil.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
// +optional
|
||||
SecretRef *SecretReference `json:"secretRef,omitempty" protobuf:"bytes,7,opt,name=secretRef"`
|
||||
// ReadOnly here will force the ReadOnly setting in VolumeMounts.
|
||||
// Defaults to false.
|
||||
// More info: https://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it
|
||||
// +optional
|
||||
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,8,opt,name=readOnly"`
|
||||
}
|
||||
|
||||
// Represents a cinder volume resource in Openstack.
|
||||
// A Cinder volume must exist before mounting to a container.
|
||||
// The volume must also be in the same region as the kubelet.
|
||||
|
Loading…
Reference in New Issue
Block a user