mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
Merge pull request #24977 from johscheuer/quobyte-plugin
Automatic merge from submit-queue Quobyte Volume plugin @quofelix and myself developed a volume plugin for [Quobyte](http://www.quobyte.com) which is a software-defined storage solution. This PR allows Kubernetes users to mount a Quobyte Volume inside their containers over Kubernetes. Here are some further informations about [Quobyte and Storage for containers](http://www.quobyte.com/containers)
This commit is contained in:
commit
dbc9063c17
@ -1413,6 +1413,10 @@
|
||||
"vsphereVolume": {
|
||||
"$ref": "v1.VsphereVirtualDiskVolumeSource",
|
||||
"description": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine"
|
||||
},
|
||||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1981,6 +1985,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.QuobyteVolumeSource": {
|
||||
"id": "v1.QuobyteVolumeSource",
|
||||
"description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
|
||||
"required": [
|
||||
"registry",
|
||||
"volume"
|
||||
],
|
||||
"properties": {
|
||||
"registry": {
|
||||
"type": "string",
|
||||
"description": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes"
|
||||
},
|
||||
"volume": {
|
||||
"type": "string",
|
||||
"description": "Volume is a string that references an already created Quobyte volume by name."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"description": "User to map volume access to Defaults to serivceaccount user"
|
||||
},
|
||||
"group": {
|
||||
"type": "string",
|
||||
"description": "Group to map volume access to Default is no group"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
@ -1418,6 +1418,10 @@
|
||||
"vsphereVolume": {
|
||||
"$ref": "v1.VsphereVirtualDiskVolumeSource",
|
||||
"description": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine"
|
||||
},
|
||||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1986,6 +1990,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.QuobyteVolumeSource": {
|
||||
"id": "v1.QuobyteVolumeSource",
|
||||
"description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
|
||||
"required": [
|
||||
"registry",
|
||||
"volume"
|
||||
],
|
||||
"properties": {
|
||||
"registry": {
|
||||
"type": "string",
|
||||
"description": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes"
|
||||
},
|
||||
"volume": {
|
||||
"type": "string",
|
||||
"description": "Volume is a string that references an already created Quobyte volume by name."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"description": "User to map volume access to Defaults to serivceaccount user"
|
||||
},
|
||||
"group": {
|
||||
"type": "string",
|
||||
"description": "Group to map volume access to Default is no group"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
@ -8582,6 +8582,10 @@
|
||||
"vsphereVolume": {
|
||||
"$ref": "v1.VsphereVirtualDiskVolumeSource",
|
||||
"description": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine"
|
||||
},
|
||||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -9150,6 +9154,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.QuobyteVolumeSource": {
|
||||
"id": "v1.QuobyteVolumeSource",
|
||||
"description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
|
||||
"required": [
|
||||
"registry",
|
||||
"volume"
|
||||
],
|
||||
"properties": {
|
||||
"registry": {
|
||||
"type": "string",
|
||||
"description": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes"
|
||||
},
|
||||
"volume": {
|
||||
"type": "string",
|
||||
"description": "Volume is a string that references an already created Quobyte volume by name."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"description": "User to map volume access to Defaults to serivceaccount user"
|
||||
},
|
||||
"group": {
|
||||
"type": "string",
|
||||
"description": "Group to map volume access to Default is no group"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
@ -17244,6 +17244,10 @@
|
||||
"$ref": "v1.VsphereVirtualDiskVolumeSource",
|
||||
"description": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine"
|
||||
},
|
||||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
},
|
||||
"accessModes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@ -17629,6 +17633,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.QuobyteVolumeSource": {
|
||||
"id": "v1.QuobyteVolumeSource",
|
||||
"description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
|
||||
"required": [
|
||||
"registry",
|
||||
"volume"
|
||||
],
|
||||
"properties": {
|
||||
"registry": {
|
||||
"type": "string",
|
||||
"description": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes"
|
||||
},
|
||||
"volume": {
|
||||
"type": "string",
|
||||
"description": "Volume is a string that references an already created Quobyte volume by name."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false."
|
||||
},
|
||||
"user": {
|
||||
"type": "string",
|
||||
"description": "User to map volume access to Defaults to serivceaccount user"
|
||||
},
|
||||
"group": {
|
||||
"type": "string",
|
||||
"description": "Group to map volume access to Default is no group"
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.PersistentVolumeStatus": {
|
||||
"id": "v1.PersistentVolumeStatus",
|
||||
"description": "PersistentVolumeStatus is the current status of a persistent volume.",
|
||||
@ -17879,6 +17913,10 @@
|
||||
"vsphereVolume": {
|
||||
"$ref": "v1.VsphereVirtualDiskVolumeSource",
|
||||
"description": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine"
|
||||
},
|
||||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -44,6 +44,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/volume/host_path"
|
||||
"k8s.io/kubernetes/pkg/volume/iscsi"
|
||||
"k8s.io/kubernetes/pkg/volume/nfs"
|
||||
"k8s.io/kubernetes/pkg/volume/quobyte"
|
||||
"k8s.io/kubernetes/pkg/volume/rbd"
|
||||
"k8s.io/kubernetes/pkg/volume/secret"
|
||||
"k8s.io/kubernetes/pkg/volume/vsphere_volume"
|
||||
@ -74,6 +75,7 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
|
||||
allPlugins = append(allPlugins, glusterfs.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, rbd.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, cinder.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, quobyte.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, cephfs.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, downwardapi.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
|
||||
|
@ -1327,7 +1327,7 @@ Examples:<br>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-06-28 21:15:27 UTC
|
||||
Last updated 2016-07-19 08:57:41 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -2314,6 +2314,68 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_quobytevolumesource">v1.QuobyteVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all" style="width:100%; ">
|
||||
<colgroup>
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
<th class="tableblock halign-left valign-top">Required</th>
|
||||
<th class="tableblock halign-left valign-top">Schema</th>
|
||||
<th class="tableblock halign-left valign-top">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">registry</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volume</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Volume is a string that references an already created Quobyte volume by name.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">user</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">User to map volume access to Defaults to serivceaccount user</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">group</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Group to map volume access to Default is no group</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_job">v1.Job</h3>
|
||||
@ -3237,6 +3299,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_vspherevirtualdiskvolumesource">v1.VsphereVirtualDiskVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">quobyte</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Quobyte represents a Quobyte mount on the host that shares a pod’s lifetime</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_quobytevolumesource">v1.QuobyteVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -4138,7 +4207,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-08-17 18:39:38 UTC
|
||||
Last updated 2016-08-18 14:23:21 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -3104,6 +3104,13 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_vspherevirtualdiskvolumesource">v1.VsphereVirtualDiskVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">quobyte</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Quobyte represents a Quobyte mount on the host that shares a pod’s lifetime</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_quobytevolumesource">v1.QuobyteVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -5892,6 +5899,68 @@ Both these may change in the future. Incoming requests are matched against the h
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_quobytevolumesource">v1.QuobyteVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all" style="width:100%; ">
|
||||
<colgroup>
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
<th class="tableblock halign-left valign-top">Required</th>
|
||||
<th class="tableblock halign-left valign-top">Schema</th>
|
||||
<th class="tableblock halign-left valign-top">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">registry</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volume</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Volume is a string that references an already created Quobyte volume by name.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">user</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">User to map volume access to Defaults to serivceaccount user</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">group</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Group to map volume access to Default is no group</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1beta1_labelselectorrequirement">v1beta1.LabelSelectorRequirement</h3>
|
||||
@ -6526,7 +6595,7 @@ Both these may change in the future. Incoming requests are matched against the h
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-08-17 18:39:29 UTC
|
||||
Last updated 2016-08-18 14:23:14 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -3711,6 +3711,13 @@ The resulting set of endpoints can be viewed as:<br>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_vspherevirtualdiskvolumesource">v1.VsphereVirtualDiskVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">quobyte</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Quobyte represents a Quobyte mount on the host that shares a pod’s lifetime</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_quobytevolumesource">v1.QuobyteVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -5964,6 +5971,13 @@ The resulting set of endpoints can be viewed as:<br>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">quobyte</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Quobyte represents a Quobyte mount on the host that shares a pod’s lifetime</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_quobytevolumesource">v1.QuobyteVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">accessModes</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AccessModes contains all ways the volume can be mounted. More info: <a href="http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes">http://releases.k8s.io/HEAD/docs/user-guide/persistent-volumes.md#access-modes</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
@ -6778,6 +6792,68 @@ The resulting set of endpoints can be viewed as:<br>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_quobytevolumesource">v1.QuobyteVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.</p>
|
||||
</div>
|
||||
<table class="tableblock frame-all grid-all" style="width:100%; ">
|
||||
<colgroup>
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
<col style="width:20%;">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="tableblock halign-left valign-top">Name</th>
|
||||
<th class="tableblock halign-left valign-top">Description</th>
|
||||
<th class="tableblock halign-left valign-top">Required</th>
|
||||
<th class="tableblock halign-left valign-top">Schema</th>
|
||||
<th class="tableblock halign-left valign-top">Default</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">registry</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">volume</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Volume is a string that references an already created Quobyte volume by name.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">user</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">User to map volume access to Defaults to serivceaccount user</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">group</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Group to map volume access to Default is no group</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_containerimage">v1.ContainerImage</h3>
|
||||
@ -8202,7 +8278,7 @@ The resulting set of endpoints can be viewed as:<br>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-08-17 18:39:19 UTC
|
||||
Last updated 2016-08-18 14:23:04 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
127
examples/volumes/quobyte/Readme.md
Normal file
127
examples/volumes/quobyte/Readme.md
Normal file
@ -0,0 +1,127 @@
|
||||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
<!-- BEGIN STRIP_FOR_RELEASE -->
|
||||
|
||||
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/kubernetes/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
|
||||
<h2>PLEASE NOTE: This document applies to the HEAD of the source tree</h2>
|
||||
|
||||
If you are using a released version of Kubernetes, you should
|
||||
refer to the docs that go with that version.
|
||||
|
||||
Documentation for other releases can be found at
|
||||
[releases.k8s.io](http://releases.k8s.io).
|
||||
</strong>
|
||||
--
|
||||
|
||||
<!-- END STRIP_FOR_RELEASE -->
|
||||
|
||||
<!-- END MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_TOC -->
|
||||
|
||||
- [Quobyte Volume](#quobyte-volume)
|
||||
- [Quobyte](#quobyte)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Fixed user Mounts](#fixed-user-mounts)
|
||||
- [Creating a pod](#creating-a-pod)
|
||||
|
||||
<!-- END MUNGE: GENERATED_TOC -->
|
||||
|
||||
# Quobyte Volume
|
||||
|
||||
## Quobyte
|
||||
|
||||
[Quobyte](http://www.quobyte.com) is software that turns commodity servers into a reliable and highly automated multi-data center file system.
|
||||
|
||||
The example assumes that you already have a running Kubernetes cluster and you already have setup Quobyte-Client (1.3+) on each Kubernetes node.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Running Quobyte storage cluster
|
||||
- Quobyte client (1.3+) installed on the Kubernetes nodes more information how you can install Quobyte on your Kubernetes nodes, can be found in the [documentation](https://support.quobyte.com) of Quobyte.
|
||||
- To get access to Quobyte and the documentation please [contact us](http://www.quobyte.com/get-quobyte)
|
||||
- Already created Quobyte Volume
|
||||
- Added the line `allow-usermapping-in-volumename` in `/etc/quobyte/client.cfg` to allow the fixed user mounts
|
||||
|
||||
### Fixed user Mounts
|
||||
|
||||
Quobyte supports since 1.3 fixed user mounts. The fixed-user mounts simply allow to mount all Quobyte Volumes inside one directory and use them as different users. All access to the Quobyte Volume will be rewritten to the specified user and group – both are optional, independent of the user inside the container. You can read more about it [here](https://blog.inovex.de/docker-plugins) under the section "Quobyte Mount and Docker — what’s special"
|
||||
|
||||
## Creating a pod
|
||||
|
||||
See example:
|
||||
|
||||
<!-- BEGIN MUNGE: EXAMPLE ./quobyte-pod.yaml -->
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: quobyte
|
||||
spec:
|
||||
containers:
|
||||
- name: quobyte
|
||||
image: kubernetes/pause
|
||||
volumeMounts:
|
||||
- mountPath: /mnt
|
||||
name: quobytevolume
|
||||
volumes:
|
||||
- name: quobytevolume
|
||||
quobyte:
|
||||
registry: registry:7861
|
||||
volume: testVolume
|
||||
readOnly: false
|
||||
user: root
|
||||
group: root
|
||||
```
|
||||
|
||||
[Download example](quobyte-pod.yaml?raw=true)
|
||||
<!-- 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.
|
||||
* **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.
|
||||
|
||||
Creating the pod:
|
||||
|
||||
```bash
|
||||
$ kubectl create -f examples/volumes/quobyte/quobyte-pod.yaml
|
||||
```
|
||||
|
||||
Verify that the pod is running:
|
||||
|
||||
```bash
|
||||
$ kubectl get pods quobyte
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
quobyte 1/1 Running 0 48m
|
||||
|
||||
$ kubectl get pods quobyte --template '{{.status.hostIP}}{{"\n"}}'
|
||||
10.245.1.3
|
||||
```
|
||||
|
||||
SSH onto the Machine and validate that quobyte is mounted:
|
||||
|
||||
```bash
|
||||
$ mount | grep quobyte
|
||||
quobyte@10.239.10.21:7861/ on /var/lib/kubelet/plugins/kubernetes.io~quobyte type fuse (rw,nosuid,nodev,noatime,user_id=0,group_id=0,default_permissions,allow_other)
|
||||
|
||||
$ docker inspect --format '{{ range .Mounts }}{{ if eq .Destination "/mnt"}}{{ .Source }}{{ end }}{{ end }}' 55ab97593cd3
|
||||
/var/lib/kubelet/plugins/kubernetes.io~quobyte/root#root@testVolume
|
||||
```
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
19
examples/volumes/quobyte/quobyte-pod.yaml
Normal file
19
examples/volumes/quobyte/quobyte-pod.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: quobyte
|
||||
spec:
|
||||
containers:
|
||||
- name: quobyte
|
||||
image: kubernetes/pause
|
||||
volumeMounts:
|
||||
- mountPath: /mnt
|
||||
name: quobytevolume
|
||||
volumes:
|
||||
- name: quobytevolume
|
||||
quobyte:
|
||||
registry: registry:7861
|
||||
volume: testVolume
|
||||
readOnly: false
|
||||
user: root
|
||||
group: root
|
@ -199,3 +199,4 @@ test/soak/cauldron
|
||||
test/soak/serve_hostnames
|
||||
third_party/forked/golang/expansion
|
||||
pkg/util/maps
|
||||
pkg/volume/quobyte
|
||||
|
@ -40,7 +40,8 @@
|
||||
"secret": null,
|
||||
"nfs": null,
|
||||
"iscsi": null,
|
||||
"glusterfs": null
|
||||
"glusterfs": null,
|
||||
"quobyte": null
|
||||
}
|
||||
],
|
||||
"containers": [
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -209,6 +209,10 @@ type VolumeSource struct {
|
||||
PersistentVolumeClaim *PersistentVolumeClaimVolumeSource `json:"persistentVolumeClaim,omitempty"`
|
||||
// RBD represents a Rados Block Device mount on the host that shares a pod's lifetime
|
||||
RBD *RBDVolumeSource `json:"rbd,omitempty"`
|
||||
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty"`
|
||||
|
||||
// FlexVolume represents a generic volume resource that is
|
||||
// provisioned/attached using a exec based plugin. This is an alpha feature and may change in future.
|
||||
FlexVolume *FlexVolumeSource `json:"flexVolume,omitempty"`
|
||||
@ -254,6 +258,8 @@ type PersistentVolumeSource struct {
|
||||
NFS *NFSVolumeSource `json:"nfs,omitempty"`
|
||||
// RBD represents a Rados Block Device mount on the host that shares a pod's lifetime
|
||||
RBD *RBDVolumeSource `json:"rbd,omitempty"`
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty"`
|
||||
// ISCSIVolumeSource represents an ISCSI resource that is attached to a
|
||||
// kubelet's host machine and then exposed to the pod.
|
||||
ISCSI *ISCSIVolumeSource `json:"iscsi,omitempty"`
|
||||
@ -628,6 +634,30 @@ type NFSVolumeSource struct {
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// Represents a Quobyte mount that lasts the lifetime of a pod.
|
||||
// Quobyte volumes do not support ownership management or SELinux relabeling.
|
||||
type QuobyteVolumeSource struct {
|
||||
// Registry represents a single or multiple Quobyte Registry services
|
||||
// specified as a string as host:port pair (multiple entries are separated with commas)
|
||||
// which acts as the central registry for volumes
|
||||
Registry string `json:"registry"`
|
||||
|
||||
// Volume is a string that references an already created Quobyte volume by name.
|
||||
Volume string `json:"volume"`
|
||||
|
||||
// Defaults to false (read/write). ReadOnly here will force
|
||||
// the Quobyte to be mounted with read-only permissions
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
|
||||
// User to map volume access to
|
||||
// Defaults to the root user
|
||||
User string `json:"user,omitempty"`
|
||||
|
||||
// Group to map volume access to
|
||||
// Default is no group
|
||||
Group string `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
// Represents a Glusterfs mount that lasts the lifetime of a pod.
|
||||
// Glusterfs volumes do not support ownership management or SELinux relabeling.
|
||||
type GlusterfsVolumeSource struct {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1748,6 +1748,9 @@ message PersistentVolumeSource {
|
||||
|
||||
// VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine
|
||||
optional VsphereVirtualDiskVolumeSource vsphereVolume = 14;
|
||||
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
optional QuobyteVolumeSource quobyte = 15;
|
||||
}
|
||||
|
||||
// PersistentVolumeSpec is the specification of a persistent volume.
|
||||
@ -2317,6 +2320,30 @@ message Probe {
|
||||
optional int32 failureThreshold = 6;
|
||||
}
|
||||
|
||||
// Represents a Quobyte mount that lasts the lifetime of a pod.
|
||||
// Quobyte volumes do not support ownership management or SELinux relabeling.
|
||||
message QuobyteVolumeSource {
|
||||
// Registry represents a single or multiple Quobyte Registry services
|
||||
// specified as a string as host:port pair (multiple entries are separated with commas)
|
||||
// which acts as the central registry for volumes
|
||||
optional string registry = 1;
|
||||
|
||||
// Volume is a string that references an already created Quobyte volume by name.
|
||||
optional string volume = 2;
|
||||
|
||||
// ReadOnly here will force the Quobyte volume to be mounted with read-only permissions.
|
||||
// Defaults to false.
|
||||
optional bool readOnly = 3;
|
||||
|
||||
// User to map volume access to
|
||||
// Defaults to serivceaccount user
|
||||
optional string user = 4;
|
||||
|
||||
// Group to map volume access to
|
||||
// Default is no group
|
||||
optional string group = 5;
|
||||
}
|
||||
|
||||
// Represents a Rados Block Device mount that lasts the lifetime of a pod.
|
||||
// RBD volumes support ownership management and SELinux relabeling.
|
||||
message RBDVolumeSource {
|
||||
@ -2977,6 +3004,9 @@ message VolumeSource {
|
||||
|
||||
// VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine
|
||||
optional VsphereVirtualDiskVolumeSource vsphereVolume = 20;
|
||||
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
optional QuobyteVolumeSource quobyte = 21;
|
||||
}
|
||||
|
||||
// Represents a vSphere volume resource.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -259,13 +259,10 @@ type VolumeSource struct {
|
||||
// Cinder represents a cinder volume attached and mounted on kubelets host machine
|
||||
// More info: http://releases.k8s.io/HEAD/examples/mysql-cinder-pd/README.md
|
||||
Cinder *CinderVolumeSource `json:"cinder,omitempty" protobuf:"bytes,13,opt,name=cinder"`
|
||||
|
||||
// CephFS represents a Ceph FS mount on the host that shares a pod's lifetime
|
||||
CephFS *CephFSVolumeSource `json:"cephfs,omitempty" protobuf:"bytes,14,opt,name=cephfs"`
|
||||
|
||||
// Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running
|
||||
Flocker *FlockerVolumeSource `json:"flocker,omitempty" protobuf:"bytes,15,opt,name=flocker"`
|
||||
|
||||
// DownwardAPI represents downward API about the pod that should populate this volume
|
||||
DownwardAPI *DownwardAPIVolumeSource `json:"downwardAPI,omitempty" protobuf:"bytes,16,opt,name=downwardAPI"`
|
||||
// FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||
@ -276,6 +273,8 @@ type VolumeSource struct {
|
||||
ConfigMap *ConfigMapVolumeSource `json:"configMap,omitempty" protobuf:"bytes,19,opt,name=configMap"`
|
||||
// VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine
|
||||
VsphereVolume *VsphereVirtualDiskVolumeSource `json:"vsphereVolume,omitempty" protobuf:"bytes,20,opt,name=vsphereVolume"`
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty" protobuf:"bytes,21,opt,name=quobyte"`
|
||||
}
|
||||
|
||||
// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
|
||||
@ -338,6 +337,8 @@ type PersistentVolumeSource struct {
|
||||
AzureFile *AzureFileVolumeSource `json:"azureFile,omitempty" protobuf:"bytes,13,opt,name=azureFile"`
|
||||
// VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine
|
||||
VsphereVolume *VsphereVirtualDiskVolumeSource `json:"vsphereVolume,omitempty" protobuf:"bytes,14,opt,name=vsphereVolume"`
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
Quobyte *QuobyteVolumeSource `json:"quobyte,omitempty" protobuf:"bytes,15,opt,name=quobyte"`
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
@ -688,6 +689,30 @@ type GCEPersistentDiskVolumeSource struct {
|
||||
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,4,opt,name=readOnly"`
|
||||
}
|
||||
|
||||
// Represents a Quobyte mount that lasts the lifetime of a pod.
|
||||
// Quobyte volumes do not support ownership management or SELinux relabeling.
|
||||
type QuobyteVolumeSource struct {
|
||||
// Registry represents a single or multiple Quobyte Registry services
|
||||
// specified as a string as host:port pair (multiple entries are separated with commas)
|
||||
// which acts as the central registry for volumes
|
||||
Registry string `json:"registry" protobuf:"bytes,1,opt,name=registry"`
|
||||
|
||||
// Volume is a string that references an already created Quobyte volume by name.
|
||||
Volume string `json:"volume" protobuf:"bytes,2,opt,name=volume"`
|
||||
|
||||
// ReadOnly here will force the Quobyte volume to be mounted with read-only permissions.
|
||||
// Defaults to false.
|
||||
ReadOnly bool `json:"readOnly,omitempty" protobuf:"varint,3,opt,name=readOnly"`
|
||||
|
||||
// User to map volume access to
|
||||
// Defaults to serivceaccount user
|
||||
User string `json:"user,omitempty" protobuf:"bytes,4,opt,name=user"`
|
||||
|
||||
// Group to map volume access to
|
||||
// Default is no group
|
||||
Group string `json:"group,omitempty" protobuf:"bytes,5,opt,name=group"`
|
||||
}
|
||||
|
||||
// FlexVolume represents a generic volume resource that is
|
||||
// provisioned/attached using a exec based plugin. This is an alpha feature and may change in future.
|
||||
type FlexVolumeSource struct {
|
||||
|
@ -1081,6 +1081,7 @@ var map_PersistentVolumeSource = map[string]string{
|
||||
"flexVolume": "FlexVolume represents a generic volume resource that is provisioned/attached using a exec based plugin. This is an alpha feature and may change in future.",
|
||||
"azureFile": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
"vsphereVolume": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine",
|
||||
"quobyte": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime",
|
||||
}
|
||||
|
||||
func (PersistentVolumeSource) SwaggerDoc() map[string]string {
|
||||
@ -1375,6 +1376,19 @@ func (Probe) SwaggerDoc() map[string]string {
|
||||
return map_Probe
|
||||
}
|
||||
|
||||
var map_QuobyteVolumeSource = map[string]string{
|
||||
"": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
|
||||
"registry": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes",
|
||||
"volume": "Volume is a string that references an already created Quobyte volume by name.",
|
||||
"readOnly": "ReadOnly here will force the Quobyte volume to be mounted with read-only permissions. Defaults to false.",
|
||||
"user": "User to map volume access to Defaults to serivceaccount user",
|
||||
"group": "Group to map volume access to Default is no group",
|
||||
}
|
||||
|
||||
func (QuobyteVolumeSource) SwaggerDoc() map[string]string {
|
||||
return map_QuobyteVolumeSource
|
||||
}
|
||||
|
||||
var map_RBDVolumeSource = map[string]string{
|
||||
"": "Represents a Rados Block Device mount that lasts the lifetime of a pod. RBD volumes support ownership management and SELinux relabeling.",
|
||||
"monitors": "A collection of Ceph monitors. More info: http://releases.k8s.io/HEAD/examples/volumes/rbd/README.md#how-to-use-it",
|
||||
@ -1749,6 +1763,7 @@ var map_VolumeSource = map[string]string{
|
||||
"azureFile": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
"configMap": "ConfigMap represents a configMap that should populate this volume",
|
||||
"vsphereVolume": "VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine",
|
||||
"quobyte": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime",
|
||||
}
|
||||
|
||||
func (VolumeSource) SwaggerDoc() map[string]string {
|
||||
|
@ -270,6 +270,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_api_PreferredSchedulingTerm_To_v1_PreferredSchedulingTerm,
|
||||
Convert_v1_Probe_To_api_Probe,
|
||||
Convert_api_Probe_To_v1_Probe,
|
||||
Convert_v1_QuobyteVolumeSource_To_api_QuobyteVolumeSource,
|
||||
Convert_api_QuobyteVolumeSource_To_v1_QuobyteVolumeSource,
|
||||
Convert_v1_RBDVolumeSource_To_api_RBDVolumeSource,
|
||||
Convert_api_RBDVolumeSource_To_v1_RBDVolumeSource,
|
||||
Convert_v1_RangeAllocation_To_api_RangeAllocation,
|
||||
@ -4197,6 +4199,15 @@ func autoConvert_v1_PersistentVolumeSource_To_api_PersistentVolumeSource(in *Per
|
||||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(api.QuobyteVolumeSource)
|
||||
if err := Convert_v1_QuobyteVolumeSource_To_api_QuobyteVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -4259,6 +4270,15 @@ func autoConvert_api_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *api
|
||||
} else {
|
||||
out.RBD = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(QuobyteVolumeSource)
|
||||
if err := Convert_api_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.ISCSI != nil {
|
||||
in, out := &in.ISCSI, &out.ISCSI
|
||||
*out = new(ISCSIVolumeSource)
|
||||
@ -5359,6 +5379,32 @@ func Convert_api_Probe_To_v1_Probe(in *api.Probe, out *Probe, s conversion.Scope
|
||||
return autoConvert_api_Probe_To_v1_Probe(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_QuobyteVolumeSource_To_api_QuobyteVolumeSource(in *QuobyteVolumeSource, out *api.QuobyteVolumeSource, s conversion.Scope) error {
|
||||
out.Registry = in.Registry
|
||||
out.Volume = in.Volume
|
||||
out.ReadOnly = in.ReadOnly
|
||||
out.User = in.User
|
||||
out.Group = in.Group
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_QuobyteVolumeSource_To_api_QuobyteVolumeSource(in *QuobyteVolumeSource, out *api.QuobyteVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_v1_QuobyteVolumeSource_To_api_QuobyteVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(in *api.QuobyteVolumeSource, out *QuobyteVolumeSource, s conversion.Scope) error {
|
||||
out.Registry = in.Registry
|
||||
out.Volume = in.Volume
|
||||
out.ReadOnly = in.ReadOnly
|
||||
out.User = in.User
|
||||
out.Group = in.Group
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(in *api.QuobyteVolumeSource, out *QuobyteVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_api_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_RBDVolumeSource_To_api_RBDVolumeSource(in *RBDVolumeSource, out *api.RBDVolumeSource, s conversion.Scope) error {
|
||||
SetDefaults_RBDVolumeSource(in)
|
||||
out.CephMonitors = in.CephMonitors
|
||||
@ -6742,6 +6788,15 @@ func autoConvert_v1_VolumeSource_To_api_VolumeSource(in *VolumeSource, out *api.
|
||||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(api.QuobyteVolumeSource)
|
||||
if err := Convert_v1_QuobyteVolumeSource_To_api_QuobyteVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -6849,6 +6904,15 @@ func autoConvert_api_VolumeSource_To_v1_VolumeSource(in *api.VolumeSource, out *
|
||||
} else {
|
||||
out.RBD = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(QuobyteVolumeSource)
|
||||
if err := Convert_api_QuobyteVolumeSource_To_v1_QuobyteVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.FlexVolume != nil {
|
||||
in, out := &in.FlexVolume, &out.FlexVolume
|
||||
*out = new(FlexVolumeSource)
|
||||
|
@ -153,6 +153,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_PreferAvoidPodsEntry, InType: reflect.TypeOf(&PreferAvoidPodsEntry{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_PreferredSchedulingTerm, InType: reflect.TypeOf(&PreferredSchedulingTerm{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Probe, InType: reflect.TypeOf(&Probe{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_QuobyteVolumeSource, InType: reflect.TypeOf(&QuobyteVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_RBDVolumeSource, InType: reflect.TypeOf(&RBDVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_RangeAllocation, InType: reflect.TypeOf(&RangeAllocation{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ReplicationController, InType: reflect.TypeOf(&ReplicationController{})},
|
||||
@ -2179,6 +2180,13 @@ func DeepCopy_v1_PersistentVolumeSource(in interface{}, out interface{}, c *conv
|
||||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(QuobyteVolumeSource)
|
||||
**out = **in
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -2782,6 +2790,19 @@ func DeepCopy_v1_Probe(in interface{}, out interface{}, c *conversion.Cloner) er
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1_QuobyteVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*QuobyteVolumeSource)
|
||||
out := out.(*QuobyteVolumeSource)
|
||||
out.Registry = in.Registry
|
||||
out.Volume = in.Volume
|
||||
out.ReadOnly = in.ReadOnly
|
||||
out.User = in.User
|
||||
out.Group = in.Group
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1_RBDVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RBDVolumeSource)
|
||||
@ -3595,6 +3616,13 @@ func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Clo
|
||||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(QuobyteVolumeSource)
|
||||
**out = **in
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -534,6 +534,14 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E
|
||||
allErrs = append(allErrs, validateCephFSVolumeSource(source.CephFS, fldPath.Child("cephfs"))...)
|
||||
}
|
||||
}
|
||||
if source.Quobyte != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("quobyte"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateQuobyteVolumeSource(source.Quobyte, fldPath.Child("quobyte"))...)
|
||||
}
|
||||
}
|
||||
if source.DownwardAPI != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwarAPI"), "may not specify more than 1 volume type"))
|
||||
@ -732,6 +740,24 @@ func validateNFSVolumeSource(nfs *api.NFSVolumeSource, fldPath *field.Path) fiel
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateQuobyteVolumeSource(quobyte *api.QuobyteVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(quobyte.Registry) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("registry"), "must be a host:port pair or multiple pairs seperated by commas"))
|
||||
} else {
|
||||
for _, hostPortPair := range strings.Split(quobyte.Registry, ",") {
|
||||
if _, _, err := net.SplitHostPort(hostPortPair); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("registry"), quobyte.Registry, "must be a host:port pair or multiple pairs seperated by commas"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(quobyte.Volume) == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("volume"), ""))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateGlusterfs(glusterfs *api.GlusterfsVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(glusterfs.EndpointsName) == 0 {
|
||||
@ -966,6 +992,14 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
|
||||
allErrs = append(allErrs, validateRBDVolumeSource(pv.Spec.RBD, specPath.Child("rbd"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.Quobyte != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("quobyte"), "may not specify more than 1 volume type"))
|
||||
} else {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateQuobyteVolumeSource(pv.Spec.Quobyte, specPath.Child("quobyte"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.CephFS != nil {
|
||||
if numVolumes > 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(specPath.Child("cephFS"), "may not specify more than 1 volume type"))
|
||||
|
@ -1970,6 +1970,76 @@ func TestValidateVolumes(t *testing.T) {
|
||||
errtype: field.ErrorTypeRequired,
|
||||
errfield: "azureFile.shareName",
|
||||
},
|
||||
// Quobyte
|
||||
{
|
||||
name: "valid Quobyte",
|
||||
vol: api.Volume{
|
||||
Name: "quobyte",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{
|
||||
Registry: "registry:7861",
|
||||
Volume: "volume",
|
||||
ReadOnly: false,
|
||||
User: "root",
|
||||
Group: "root",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty registry quobyte",
|
||||
vol: api.Volume{
|
||||
Name: "quobyte",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{
|
||||
Volume: "/test",
|
||||
},
|
||||
},
|
||||
},
|
||||
errtype: field.ErrorTypeRequired,
|
||||
errfield: "quobyte.registry",
|
||||
},
|
||||
{
|
||||
name: "wrong format registry quobyte",
|
||||
vol: api.Volume{
|
||||
Name: "quobyte",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{
|
||||
Registry: "registry7861",
|
||||
Volume: "/test",
|
||||
},
|
||||
},
|
||||
},
|
||||
errtype: field.ErrorTypeInvalid,
|
||||
errfield: "quobyte.registry",
|
||||
},
|
||||
{
|
||||
name: "wrong format multiple registries quobyte",
|
||||
vol: api.Volume{
|
||||
Name: "quobyte",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{
|
||||
Registry: "registry:7861,reg2",
|
||||
Volume: "/test",
|
||||
},
|
||||
},
|
||||
},
|
||||
errtype: field.ErrorTypeInvalid,
|
||||
errfield: "quobyte.registry",
|
||||
},
|
||||
{
|
||||
name: "empty volume quobyte",
|
||||
vol: api.Volume{
|
||||
Name: "quobyte",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{
|
||||
Registry: "registry:7861",
|
||||
},
|
||||
},
|
||||
},
|
||||
errtype: field.ErrorTypeRequired,
|
||||
errfield: "quobyte.volume",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
|
@ -157,6 +157,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PreferAvoidPodsEntry, InType: reflect.TypeOf(&PreferAvoidPodsEntry{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PreferredSchedulingTerm, InType: reflect.TypeOf(&PreferredSchedulingTerm{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Probe, InType: reflect.TypeOf(&Probe{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_QuobyteVolumeSource, InType: reflect.TypeOf(&QuobyteVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RBDVolumeSource, InType: reflect.TypeOf(&RBDVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RangeAllocation, InType: reflect.TypeOf(&RangeAllocation{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ReplicationController, InType: reflect.TypeOf(&ReplicationController{})},
|
||||
@ -2175,6 +2176,13 @@ func DeepCopy_api_PersistentVolumeSource(in interface{}, out interface{}, c *con
|
||||
} else {
|
||||
out.RBD = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(QuobyteVolumeSource)
|
||||
**out = **in
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.ISCSI != nil {
|
||||
in, out := &in.ISCSI, &out.ISCSI
|
||||
*out = new(ISCSIVolumeSource)
|
||||
@ -2839,6 +2847,19 @@ func DeepCopy_api_Probe(in interface{}, out interface{}, c *conversion.Cloner) e
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_QuobyteVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*QuobyteVolumeSource)
|
||||
out := out.(*QuobyteVolumeSource)
|
||||
out.Registry = in.Registry
|
||||
out.Volume = in.Volume
|
||||
out.ReadOnly = in.ReadOnly
|
||||
out.User = in.User
|
||||
out.Group = in.Group
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_RBDVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*RBDVolumeSource)
|
||||
@ -3557,6 +3578,13 @@ func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cl
|
||||
} else {
|
||||
out.RBD = nil
|
||||
}
|
||||
if in.Quobyte != nil {
|
||||
in, out := &in.Quobyte, &out.Quobyte
|
||||
*out = new(QuobyteVolumeSource)
|
||||
**out = **in
|
||||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.FlexVolume != nil {
|
||||
in, out := &in.FlexVolume, &out.FlexVolume
|
||||
*out = new(FlexVolumeSource)
|
||||
|
@ -714,6 +714,7 @@ var (
|
||||
FC FSType = "fc"
|
||||
ConfigMap FSType = "configMap"
|
||||
VsphereVolume FSType = "vsphereVolume"
|
||||
Quobyte FSType = "quobyte"
|
||||
All FSType = "*"
|
||||
)
|
||||
|
||||
|
@ -992,6 +992,7 @@ var (
|
||||
DownwardAPI FSType = "downwardAPI"
|
||||
FC FSType = "fc"
|
||||
ConfigMap FSType = "configMap"
|
||||
Quobyte FSType = "quobyte"
|
||||
All FSType = "*"
|
||||
)
|
||||
|
||||
|
@ -604,6 +604,8 @@ func describeVolumes(volumes []api.Volume, out io.Writer, space string) {
|
||||
printPersistentVolumeClaimVolumeSource(volume.VolumeSource.PersistentVolumeClaim, out)
|
||||
case volume.VolumeSource.RBD != nil:
|
||||
printRBDVolumeSource(volume.VolumeSource.RBD, out)
|
||||
case volume.VolumeSource.Quobyte != nil:
|
||||
printQuobyteVolumeSource(volume.VolumeSource.Quobyte, out)
|
||||
case volume.VolumeSource.DownwardAPI != nil:
|
||||
printDownwardAPIVolumeSource(volume.VolumeSource.DownwardAPI, out)
|
||||
default:
|
||||
@ -665,6 +667,14 @@ func printNFSVolumeSource(nfs *api.NFSVolumeSource, out io.Writer) {
|
||||
nfs.Server, nfs.Path, nfs.ReadOnly)
|
||||
}
|
||||
|
||||
func printQuobyteVolumeSource(quobyte *api.QuobyteVolumeSource, out io.Writer) {
|
||||
fmt.Fprintf(out, " Type:\tQuobyte (a Quobyte mount on the host that shares a pod's lifetime)\n"+
|
||||
" Registry:\t%v\n"+
|
||||
" Volume:\t%v\n"+
|
||||
" ReadOnly:\t%v\n",
|
||||
quobyte.Registry, quobyte.Volume, quobyte.ReadOnly)
|
||||
}
|
||||
|
||||
func printISCSIVolumeSource(iscsi *api.ISCSIVolumeSource, out io.Writer) {
|
||||
fmt.Fprintf(out, " Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n"+
|
||||
" TargetPortal:\t%v\n"+
|
||||
@ -765,6 +775,8 @@ func (d *PersistentVolumeDescriber) Describe(namespace, name string, describerSe
|
||||
printGlusterfsVolumeSource(pv.Spec.Glusterfs, out)
|
||||
case pv.Spec.RBD != nil:
|
||||
printRBDVolumeSource(pv.Spec.RBD, out)
|
||||
case pv.Spec.Quobyte != nil:
|
||||
printQuobyteVolumeSource(pv.Spec.Quobyte, out)
|
||||
}
|
||||
|
||||
if events != nil {
|
||||
|
@ -530,6 +530,13 @@ func TestPersistentVolumeDescriber(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"quobyte": {
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, pv := range tests {
|
||||
|
@ -58,7 +58,8 @@ func GetAllFSTypesAsSet() sets.String {
|
||||
string(extensions.DownwardAPI),
|
||||
string(extensions.FC),
|
||||
string(extensions.ConfigMap),
|
||||
string(extensions.VsphereVolume))
|
||||
string(extensions.VsphereVolume),
|
||||
string(extensions.Quobyte))
|
||||
return fstypes
|
||||
}
|
||||
|
||||
@ -105,6 +106,8 @@ func GetVolumeFSType(v api.Volume) (extensions.FSType, error) {
|
||||
return extensions.ConfigMap, nil
|
||||
case v.VsphereVolume != nil:
|
||||
return extensions.VsphereVolume, nil
|
||||
case v.Quobyte != nil:
|
||||
return extensions.Quobyte, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unknown volume type for volume: %#v", v)
|
||||
|
3
pkg/volume/quobyte/OWNERS
Normal file
3
pkg/volume/quobyte/OWNERS
Normal file
@ -0,0 +1,3 @@
|
||||
maintainers:
|
||||
- johscheuer
|
||||
- quofelix
|
19
pkg/volume/quobyte/doc.go
Normal file
19
pkg/volume/quobyte/doc.go
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
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
|
260
pkg/volume/quobyte/quobyte.go
Normal file
260
pkg/volume/quobyte/quobyte.go
Normal file
@ -0,0 +1,260 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"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"
|
||||
)
|
||||
|
||||
// ProbeVolumePlugins is the primary entrypoint for volume plugins.
|
||||
func ProbeVolumePlugins() []volume.VolumePlugin {
|
||||
return []volume.VolumePlugin{&quobytePlugin{nil}}
|
||||
}
|
||||
|
||||
type quobytePlugin struct {
|
||||
host volume.VolumeHost
|
||||
}
|
||||
|
||||
var _ volume.VolumePlugin = &quobytePlugin{}
|
||||
var _ volume.PersistentVolumePlugin = &quobytePlugin{}
|
||||
|
||||
const (
|
||||
quobytePluginName = "kubernetes.io/quobyte"
|
||||
)
|
||||
|
||||
func (plugin *quobytePlugin) Init(host volume.VolumeHost) error {
|
||||
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()); err == nil {
|
||||
qm, _ := mounter.(*quobyteMounter)
|
||||
pluginDir := plugin.host.GetPluginDir(strings.EscapeQualifiedNameForDisk(quobytePluginName))
|
||||
if mounted, err := qm.pluginDirIsMounted(pluginDir); mounted && err == nil {
|
||||
glog.V(4).Infof("quobyte: can support")
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
glog.V(4).Infof("quobyte: Error: %v", err)
|
||||
}
|
||||
|
||||
if out, err := exec.New().Command("ls", "/sbin/mount.quobyte").CombinedOutput(); err == nil {
|
||||
glog.V(4).Infof("quobyte: can support: %s", string(out))
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (plugin *quobytePlugin) RequiresRemount() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (plugin *quobytePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
|
||||
return []api.PersistentVolumeAccessMode{
|
||||
api.ReadWriteOnce,
|
||||
api.ReadOnlyMany,
|
||||
api.ReadWriteMany,
|
||||
}
|
||||
}
|
||||
|
||||
func getVolumeSource(spec *volume.Spec) (*api.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 := &api.Volume{
|
||||
Name: volumeName,
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{
|
||||
Volume: volumeName,
|
||||
},
|
||||
},
|
||||
}
|
||||
return volume.NewSpecFromVolume(quobyteVolume), nil
|
||||
}
|
||||
|
||||
func (plugin *quobytePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
||||
return plugin.newMounterInternal(spec, pod, plugin.host.GetMounter())
|
||||
}
|
||||
|
||||
func (plugin *quobytePlugin) newMounterInternal(spec *volume.Spec, pod *api.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}, nil
|
||||
}
|
||||
|
||||
func (plugin *quobytePlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
|
||||
return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter())
|
||||
}
|
||||
|
||||
func (plugin *quobytePlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Unmounter, error) {
|
||||
return &quobyteUnmounter{&quobyte{
|
||||
volName: volName,
|
||||
mounter: mounter,
|
||||
pod: &api.Pod{ObjectMeta: api.ObjectMeta{UID: podUID}},
|
||||
plugin: plugin,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
// Quobyte volumes represent a bare host directory mount of an quobyte export.
|
||||
type quobyte struct {
|
||||
volName string
|
||||
pod *api.Pod
|
||||
user string
|
||||
group string
|
||||
volume string
|
||||
mounter mount.Interface
|
||||
plugin *quobytePlugin
|
||||
volume.MetricsNil
|
||||
}
|
||||
|
||||
type quobyteMounter struct {
|
||||
*quobyte
|
||||
registry string
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
var _ volume.Mounter = &quobyteMounter{}
|
||||
|
||||
func (mounter *quobyteMounter) GetAttributes() volume.Attributes {
|
||||
return volume.Attributes{
|
||||
ReadOnly: mounter.readOnly,
|
||||
Managed: false,
|
||||
SupportsSELinux: false,
|
||||
}
|
||||
}
|
||||
|
||||
// SetUp attaches the disk and bind mounts to the volume path.
|
||||
func (mounter *quobyteMounter) SetUp(fsGroup *int64) error {
|
||||
pluginDir := mounter.plugin.host.GetPluginDir(strings.EscapeQualifiedNameForDisk(quobytePluginName))
|
||||
return mounter.SetUpAt(pluginDir, fsGroup)
|
||||
}
|
||||
|
||||
func (mounter *quobyteMounter) SetUpAt(dir string, fsGroup *int64) 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
|
||||
}
|
||||
|
||||
os.MkdirAll(dir, 0750)
|
||||
var options []string
|
||||
if mounter.readOnly {
|
||||
options = append(options, "ro")
|
||||
}
|
||||
|
||||
//if a trailling slash is missing we add it here
|
||||
if err := mounter.mounter.Mount(mounter.correctTraillingSlash(mounter.registry), dir, "quobyte", options); err != nil {
|
||||
return fmt.Errorf("quobyte: mount failed: %v", err)
|
||||
}
|
||||
|
||||
glog.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@volume e.g. ../root@MyVolume
|
||||
// or if a group is set ../user#group@volume
|
||||
func (quobyteVolume *quobyte) GetPath() string {
|
||||
user := quobyteVolume.user
|
||||
if len(user) == 0 {
|
||||
user = "root"
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
200
pkg/volume/quobyte/quobyte_test.go
Normal file
200
pkg/volume/quobyte/quobyte_test.go
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
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"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
utiltesting "k8s.io/kubernetes/pkg/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(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil, ""))
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte")
|
||||
if err != nil {
|
||||
t.Errorf("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: &api.PersistentVolume{Spec: api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{}}}}) {
|
||||
t.Errorf("Expected false")
|
||||
}
|
||||
if plug.CanSupport(&volume.Spec{Volume: &api.Volume{VolumeSource: api.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(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil, ""))
|
||||
|
||||
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/quobyte")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
if !contains(plug.GetAccessModes(), api.ReadWriteOnce) || !contains(plug.GetAccessModes(), api.ReadOnlyMany) || !contains(plug.GetAccessModes(), api.ReadWriteMany) {
|
||||
t.Errorf("Expected three AccessModeTypes: %s, %s, and %s", api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany)
|
||||
}
|
||||
}
|
||||
|
||||
func contains(modes []api.PersistentVolumeAccessMode, mode api.PersistentVolumeAccessMode) bool {
|
||||
for _, m := range modes {
|
||||
if m == mode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
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(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil, ""))
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/quobyte")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
|
||||
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
||||
mounter, err := plug.(*quobytePlugin).newMounterInternal(spec, pod, &mount.FakeMounter{})
|
||||
volumePath := mounter.GetPath()
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Mounter: %v", err)
|
||||
}
|
||||
if mounter == nil {
|
||||
t.Error("Got a nil Mounter")
|
||||
}
|
||||
|
||||
if volumePath != fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir) {
|
||||
t.Errorf("Got unexpected path: %s expected: %s", volumePath, fmt.Sprintf("%s/plugins/kubernetes.io~quobyte/root#root@vol", tmpDir))
|
||||
}
|
||||
if err := mounter.SetUp(nil); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
unmounter, err := plug.(*quobytePlugin).newUnmounterInternal("vol", types.UID("poduid"), &mount.FakeMounter{})
|
||||
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 := &api.Volume{
|
||||
Name: "vol1",
|
||||
VolumeSource: api.VolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{Registry: "reg:7861", Volume: "vol", ReadOnly: false, User: "root", Group: "root"},
|
||||
},
|
||||
}
|
||||
doTestPlugin(t, volume.NewSpecFromVolume(vol))
|
||||
}
|
||||
|
||||
func TestPluginPersistentVolume(t *testing.T) {
|
||||
vol := &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "vol1",
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{Registry: "reg:7861", Volume: "vol", ReadOnly: false, User: "root", Group: "root"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
doTestPlugin(t, volume.NewSpecFromPersistentVolume(vol, false))
|
||||
}
|
||||
|
||||
func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
||||
pv := &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "pvA",
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
Quobyte: &api.QuobyteVolumeSource{Registry: "reg:7861", Volume: "vol", ReadOnly: false, User: "root", Group: "root"},
|
||||
},
|
||||
ClaimRef: &api.ObjectReference{
|
||||
Name: "claimA",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
claim := &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "claimA",
|
||||
Namespace: "nsA",
|
||||
},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
VolumeName: "pvA",
|
||||
},
|
||||
Status: api.PersistentVolumeClaimStatus{
|
||||
Phase: api.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(), volumetest.NewFakeVolumeHost(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 := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
||||
mounter, _ := plug.NewMounter(spec, pod, volume.VolumeOptions{})
|
||||
|
||||
if !mounter.GetAttributes().ReadOnly {
|
||||
t.Errorf("Expected true for mounter.IsReadOnly")
|
||||
}
|
||||
}
|
48
pkg/volume/quobyte/quobyte_util.go
Normal file
48
pkg/volume/quobyte/quobyte_util.go
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
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 (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
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 {
|
||||
glog.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 path.Clean(regStr) + "/"
|
||||
}
|
Loading…
Reference in New Issue
Block a user