mirror of https://github.com/k3s-io/k3s
support Azure data disk volume
Signed-off-by: Huamin Chen <hchen@redhat.com>pull/6/head
parent
88c977c34a
commit
dea4b0226d
|
@ -1425,6 +1425,10 @@
|
|||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
},
|
||||
"azureDisk": {
|
||||
"$ref": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2023,6 +2027,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDiskVolumeSource": {
|
||||
"id": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"required": [
|
||||
"diskName",
|
||||
"diskURI"
|
||||
],
|
||||
"properties": {
|
||||
"diskName": {
|
||||
"type": "string",
|
||||
"description": "The Name of the data disk in the blob storage"
|
||||
},
|
||||
"diskURI": {
|
||||
"type": "string",
|
||||
"description": "The URI the data disk in the blob storage"
|
||||
},
|
||||
"cachingMode": {
|
||||
"$ref": "v1.AzureDataDiskCachingMode",
|
||||
"description": "Host Caching mode: None, Read Only, Read Write."
|
||||
},
|
||||
"fsType": {
|
||||
"type": "string",
|
||||
"description": "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."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDataDiskCachingMode": {
|
||||
"id": "v1.AzureDataDiskCachingMode",
|
||||
"properties": {}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
|
|
@ -1430,6 +1430,10 @@
|
|||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
},
|
||||
"azureDisk": {
|
||||
"$ref": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2028,6 +2032,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDiskVolumeSource": {
|
||||
"id": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"required": [
|
||||
"diskName",
|
||||
"diskURI"
|
||||
],
|
||||
"properties": {
|
||||
"diskName": {
|
||||
"type": "string",
|
||||
"description": "The Name of the data disk in the blob storage"
|
||||
},
|
||||
"diskURI": {
|
||||
"type": "string",
|
||||
"description": "The URI the data disk in the blob storage"
|
||||
},
|
||||
"cachingMode": {
|
||||
"$ref": "v1.AzureDataDiskCachingMode",
|
||||
"description": "Host Caching mode: None, Read Only, Read Write."
|
||||
},
|
||||
"fsType": {
|
||||
"type": "string",
|
||||
"description": "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."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDataDiskCachingMode": {
|
||||
"id": "v1.AzureDataDiskCachingMode",
|
||||
"properties": {}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
|
|
@ -8594,6 +8594,10 @@
|
|||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
},
|
||||
"azureDisk": {
|
||||
"$ref": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -9192,6 +9196,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDiskVolumeSource": {
|
||||
"id": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"required": [
|
||||
"diskName",
|
||||
"diskURI"
|
||||
],
|
||||
"properties": {
|
||||
"diskName": {
|
||||
"type": "string",
|
||||
"description": "The Name of the data disk in the blob storage"
|
||||
},
|
||||
"diskURI": {
|
||||
"type": "string",
|
||||
"description": "The URI the data disk in the blob storage"
|
||||
},
|
||||
"cachingMode": {
|
||||
"$ref": "v1.AzureDataDiskCachingMode",
|
||||
"description": "Host Caching mode: None, Read Only, Read Write."
|
||||
},
|
||||
"fsType": {
|
||||
"type": "string",
|
||||
"description": "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."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDataDiskCachingMode": {
|
||||
"id": "v1.AzureDataDiskCachingMode",
|
||||
"properties": {}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
|
|
@ -17317,6 +17317,10 @@
|
|||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
},
|
||||
"azureDisk": {
|
||||
"$ref": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod."
|
||||
},
|
||||
"accessModes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
@ -17732,6 +17736,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDiskVolumeSource": {
|
||||
"id": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"required": [
|
||||
"diskName",
|
||||
"diskURI"
|
||||
],
|
||||
"properties": {
|
||||
"diskName": {
|
||||
"type": "string",
|
||||
"description": "The Name of the data disk in the blob storage"
|
||||
},
|
||||
"diskURI": {
|
||||
"type": "string",
|
||||
"description": "The URI the data disk in the blob storage"
|
||||
},
|
||||
"cachingMode": {
|
||||
"$ref": "v1.AzureDataDiskCachingMode",
|
||||
"description": "Host Caching mode: None, Read Only, Read Write."
|
||||
},
|
||||
"fsType": {
|
||||
"type": "string",
|
||||
"description": "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."
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureDataDiskCachingMode": {
|
||||
"id": "v1.AzureDataDiskCachingMode",
|
||||
"properties": {}
|
||||
},
|
||||
"v1.PersistentVolumeStatus": {
|
||||
"id": "v1.PersistentVolumeStatus",
|
||||
"description": "PersistentVolumeStatus is the current status of a persistent volume.",
|
||||
|
@ -17986,6 +18024,10 @@
|
|||
"quobyte": {
|
||||
"$ref": "v1.QuobyteVolumeSource",
|
||||
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime"
|
||||
},
|
||||
"azureDisk": {
|
||||
"$ref": "v1.AzureDiskVolumeSource",
|
||||
"description": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -37,6 +37,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/util/io"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/aws_ebs"
|
||||
"k8s.io/kubernetes/pkg/volume/azure_dd"
|
||||
"k8s.io/kubernetes/pkg/volume/cinder"
|
||||
"k8s.io/kubernetes/pkg/volume/flexvolume"
|
||||
"k8s.io/kubernetes/pkg/volume/gce_pd"
|
||||
|
@ -60,6 +61,7 @@ func ProbeAttachableVolumePlugins(config componentconfig.VolumeConfiguration) []
|
|||
allPlugins = append(allPlugins, cinder.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, flexvolume.ProbeVolumePlugins(config.FlexVolumePluginDir)...)
|
||||
allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
|
||||
return allPlugins
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import (
|
|||
// Volume plugins
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/aws_ebs"
|
||||
"k8s.io/kubernetes/pkg/volume/azure_dd"
|
||||
"k8s.io/kubernetes/pkg/volume/azure_file"
|
||||
"k8s.io/kubernetes/pkg/volume/cephfs"
|
||||
"k8s.io/kubernetes/pkg/volume/cinder"
|
||||
|
@ -84,6 +85,7 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
|
|||
allPlugins = append(allPlugins, azure_file.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, configmap.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
|
||||
return allPlugins
|
||||
}
|
||||
|
||||
|
|
|
@ -2963,6 +2963,68 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azurediskvolumesource">v1.AzureDiskVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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">diskName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The Name of the data disk in the blob storage</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">diskURI</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The URI the data disk in the blob storage</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">cachingMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Host Caching mode: None, Read Only, Read Write.</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_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">fsType</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">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.</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">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.</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>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_vspherevirtualdiskvolumesource">v1.VsphereVirtualDiskVolumeSource</h3>
|
||||
|
@ -3313,6 +3375,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_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">azureDisk</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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_azurediskvolumesource">v1.AzureDiskVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -4119,6 +4188,10 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_rbdvolumesource">v1.RBDVolumeSource</h3>
|
||||
|
@ -4214,7 +4287,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-23 04:34:09 UTC
|
||||
Last updated 2016-08-23 13:11:42 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -2789,6 +2789,68 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azurediskvolumesource">v1.AzureDiskVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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">diskName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The Name of the data disk in the blob storage</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">diskURI</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The URI the data disk in the blob storage</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">cachingMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Host Caching mode: None, Read Only, Read Write.</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_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">fsType</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">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.</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">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.</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>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_keytopath">v1.KeyToPath</h3>
|
||||
|
@ -3118,6 +3180,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_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">azureDisk</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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_azurediskvolumesource">v1.AzureDiskVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -6597,6 +6666,10 @@ Both these may change in the future. Incoming requests are matched against the h
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_any">any</h3>
|
||||
|
@ -6609,7 +6682,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-23 04:33:54 UTC
|
||||
Last updated 2016-08-23 13:11:31 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -3158,6 +3158,68 @@ The resulting set of endpoints can be viewed as:<br>
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azurediskvolumesource">v1.AzureDiskVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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">diskName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The Name of the data disk in the blob storage</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">diskURI</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">The URI the data disk in the blob storage</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">cachingMode</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Host Caching mode: None, Read Only, Read Write.</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_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">fsType</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">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.</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">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.</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>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_keytopath">v1.KeyToPath</h3>
|
||||
|
@ -3725,6 +3787,13 @@ The resulting set of endpoints can be viewed as:<br>
|
|||
<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">azureDisk</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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_azurediskvolumesource">v1.AzureDiskVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -5985,6 +6054,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">azureDisk</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.</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_azurediskvolumesource">v1.AzureDiskVolumeSource</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>
|
||||
|
@ -8342,6 +8418,10 @@ The resulting set of endpoints can be viewed as:<br>
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_any">any</h3>
|
||||
|
@ -8354,7 +8434,7 @@ The resulting set of endpoints can be viewed as:<br>
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-08-23 04:33:41 UTC
|
||||
Last updated 2016-08-23 13:11:18 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -404,6 +404,9 @@ func TestExampleObjectSchemas(t *testing.T) {
|
|||
"../examples/volumes/azure_file": {
|
||||
"azure": &api.Pod{},
|
||||
},
|
||||
"../examples/volumes/azure_disk": {
|
||||
"azure": &api.Pod{},
|
||||
},
|
||||
}
|
||||
|
||||
capabilities.SetForTests(capabilities.Capabilities{
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<!-- 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 -->
|
||||
|
||||
# How to Use it?
|
||||
|
||||
On Azure VM, create a Pod using the volume spec based on [azure](azure.yaml).
|
||||
|
||||
In the pod, you need to provide the following information:
|
||||
|
||||
- *diskName*: (required) the name of the VHD blob object.
|
||||
- *diskURI*: (required) the URI of the vhd blob object.
|
||||
- *cachingMode*: (optional) disk caching mode. Must be one of None, ReadOnly, or ReadWrite. Default is None.
|
||||
- *fsType*: (optional) the filesytem type to mount. Default is ext4.
|
||||
- *readOnly*: (optional) whether the filesystem is used as readOnly. Default is false.
|
||||
|
||||
|
||||
Launch the Pod:
|
||||
|
||||
```console
|
||||
# kubectl create -f examples/volumes/azure_disk/azure.yaml
|
||||
```
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/examples/volumes/azure_disk/README.md?pixel)]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
|
@ -0,0 +1,16 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: azure
|
||||
spec:
|
||||
containers:
|
||||
- image: kubernetes/pause
|
||||
name: azure
|
||||
volumeMounts:
|
||||
- name: azure
|
||||
mountPath: /mnt/azure
|
||||
volumes:
|
||||
- name: azure
|
||||
azureDisk:
|
||||
diskName: test.vhd
|
||||
diskURI: https://someaccount.blob.microsoft.net/vhds/test.vhd
|
|
@ -416,6 +416,20 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source)
|
|||
types := []api.PersistentVolumeClaimPhase{api.ClaimBound, api.ClaimPending, api.ClaimLost}
|
||||
pvc.Status.Phase = types[c.Rand.Intn(len(types))]
|
||||
},
|
||||
func(obj *api.AzureDiskVolumeSource, c fuzz.Continue) {
|
||||
if obj.CachingMode == nil {
|
||||
obj.CachingMode = new(api.AzureDataDiskCachingMode)
|
||||
*obj.CachingMode = api.AzureDataDiskCachingNone
|
||||
}
|
||||
if obj.FSType == nil {
|
||||
obj.FSType = new(string)
|
||||
*obj.FSType = "ext4"
|
||||
}
|
||||
if obj.ReadOnly == nil {
|
||||
obj.ReadOnly = new(bool)
|
||||
*obj.ReadOnly = false
|
||||
}
|
||||
},
|
||||
func(s *api.NamespaceSpec, c fuzz.Continue) {
|
||||
s.Finalizers = []api.FinalizerName{api.FinalizerKubernetes}
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -241,6 +241,8 @@ type VolumeSource struct {
|
|||
ConfigMap *ConfigMapVolumeSource `json:"configMap,omitempty"`
|
||||
// VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine
|
||||
VsphereVolume *VsphereVirtualDiskVolumeSource `json:"vsphereVolume,omitempty"`
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
AzureDisk *AzureDiskVolumeSource `json:"azureDisk,omitempty"`
|
||||
}
|
||||
|
||||
// Similar to VolumeSource but meant for the administrator who creates PVs.
|
||||
|
@ -283,6 +285,8 @@ type PersistentVolumeSource struct {
|
|||
AzureFile *AzureFileVolumeSource `json:"azureFile,omitempty"`
|
||||
// VsphereVolume represents a vSphere volume attached and mounted on kubelets host machine
|
||||
VsphereVolume *VsphereVirtualDiskVolumeSource `json:"vsphereVolume,omitempty"`
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
AzureDisk *AzureDiskVolumeSource `json:"azureDisk,omitempty"`
|
||||
}
|
||||
|
||||
type PersistentVolumeClaimVolumeSource struct {
|
||||
|
@ -793,6 +797,31 @@ type VsphereVirtualDiskVolumeSource struct {
|
|||
FSType string `json:"fsType,omitempty"`
|
||||
}
|
||||
|
||||
type AzureDataDiskCachingMode string
|
||||
|
||||
const (
|
||||
AzureDataDiskCachingNone AzureDataDiskCachingMode = "None"
|
||||
AzureDataDiskCachingReadOnly AzureDataDiskCachingMode = "ReadOnly"
|
||||
AzureDataDiskCachingReadWrite AzureDataDiskCachingMode = "ReadWrite"
|
||||
)
|
||||
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
type AzureDiskVolumeSource struct {
|
||||
// The Name of the data disk in the blob storage
|
||||
DiskName string `json:"diskName"`
|
||||
// The URI the the data disk in the blob storage
|
||||
DataDiskURI string `json:"diskURI"`
|
||||
// Host Caching mode: None, Read Only, Read Write.
|
||||
CachingMode *AzureDataDiskCachingMode `json:"cachingMode,omitempty"`
|
||||
// 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.
|
||||
FSType *string `json:"fsType,omitempty"`
|
||||
// Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly *bool `json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// Adapts a ConfigMap into a volume.
|
||||
//
|
||||
// The contents of the target ConfigMap's Data field will be presented in a
|
||||
|
|
|
@ -218,6 +218,20 @@ func SetDefaults_ISCSIVolumeSource(obj *ISCSIVolumeSource) {
|
|||
obj.ISCSIInterface = "default"
|
||||
}
|
||||
}
|
||||
func SetDefaults_AzureDiskVolumeSource(obj *AzureDiskVolumeSource) {
|
||||
if obj.CachingMode == nil {
|
||||
obj.CachingMode = new(AzureDataDiskCachingMode)
|
||||
*obj.CachingMode = AzureDataDiskCachingNone
|
||||
}
|
||||
if obj.FSType == nil {
|
||||
obj.FSType = new(string)
|
||||
*obj.FSType = "ext4"
|
||||
}
|
||||
if obj.ReadOnly == nil {
|
||||
obj.ReadOnly = new(bool)
|
||||
*obj.ReadOnly = false
|
||||
}
|
||||
}
|
||||
func SetDefaults_Endpoints(obj *Endpoints) {
|
||||
for i := range obj.Subsets {
|
||||
ss := &obj.Subsets[i]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -89,6 +89,27 @@ message AvoidPods {
|
|||
repeated PreferAvoidPodsEntry preferAvoidPods = 1;
|
||||
}
|
||||
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
message AzureDiskVolumeSource {
|
||||
// The Name of the data disk in the blob storage
|
||||
optional string diskName = 1;
|
||||
|
||||
// The URI the data disk in the blob storage
|
||||
optional string diskURI = 2;
|
||||
|
||||
// Host Caching mode: None, Read Only, Read Write.
|
||||
optional string cachingMode = 3;
|
||||
|
||||
// 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.
|
||||
optional string fsType = 4;
|
||||
|
||||
// Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
optional bool readOnly = 5;
|
||||
}
|
||||
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
message AzureFileVolumeSource {
|
||||
// the name of secret that contains Azure Storage Account Name and Key
|
||||
|
@ -1757,6 +1778,9 @@ message PersistentVolumeSource {
|
|||
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
optional QuobyteVolumeSource quobyte = 15;
|
||||
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
optional AzureDiskVolumeSource azureDisk = 16;
|
||||
}
|
||||
|
||||
// PersistentVolumeSpec is the specification of a persistent volume.
|
||||
|
@ -3036,6 +3060,9 @@ message VolumeSource {
|
|||
|
||||
// Quobyte represents a Quobyte mount on the host that shares a pod's lifetime
|
||||
optional QuobyteVolumeSource quobyte = 21;
|
||||
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
optional AzureDiskVolumeSource azureDisk = 22;
|
||||
}
|
||||
|
||||
// Represents a vSphere volume resource.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -280,6 +280,8 @@ type VolumeSource struct {
|
|||
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"`
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
AzureDisk *AzureDiskVolumeSource `json:"azureDisk,omitempty" protobuf:"bytes,22,opt,name=azureDisk"`
|
||||
}
|
||||
|
||||
// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
|
||||
|
@ -344,6 +346,8 @@ type PersistentVolumeSource struct {
|
|||
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"`
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
AzureDisk *AzureDiskVolumeSource `json:"azureDisk,omitempty" protobuf:"bytes,16,opt,name=azureDisk"`
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
|
@ -891,6 +895,30 @@ type VsphereVirtualDiskVolumeSource struct {
|
|||
// Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.
|
||||
FSType string `json:"fsType,omitempty" protobuf:"bytes,2,opt,name=fsType"`
|
||||
}
|
||||
type AzureDataDiskCachingMode string
|
||||
|
||||
const (
|
||||
AzureDataDiskCachingNone AzureDataDiskCachingMode = "None"
|
||||
AzureDataDiskCachingReadOnly AzureDataDiskCachingMode = "ReadOnly"
|
||||
AzureDataDiskCachingReadWrite AzureDataDiskCachingMode = "ReadWrite"
|
||||
)
|
||||
|
||||
// AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.
|
||||
type AzureDiskVolumeSource struct {
|
||||
// The Name of the data disk in the blob storage
|
||||
DiskName string `json:"diskName" protobuf:"bytes,1,opt,name=diskName"`
|
||||
// The URI the data disk in the blob storage
|
||||
DataDiskURI string `json:"diskURI" protobuf:"bytes,2,opt,name=diskURI"`
|
||||
// Host Caching mode: None, Read Only, Read Write.
|
||||
CachingMode *AzureDataDiskCachingMode `json:"cachingMode,omitempty" protobuf:"bytes,3,opt,name=cachingMode,casttype=AzureDataDiskCachingMode"`
|
||||
// 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.
|
||||
FSType *string `json:"fsType,omitempty" protobuf:"bytes,4,opt,name=fsType"`
|
||||
// Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly *bool `json:"readOnly,omitempty" protobuf:"varint,5,opt,name=readOnly"`
|
||||
}
|
||||
|
||||
// Adapts a ConfigMap into a volume.
|
||||
//
|
||||
|
|
|
@ -69,6 +69,19 @@ func (AvoidPods) SwaggerDoc() map[string]string {
|
|||
return map_AvoidPods
|
||||
}
|
||||
|
||||
var map_AzureDiskVolumeSource = map[string]string{
|
||||
"": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
"diskName": "The Name of the data disk in the blob storage",
|
||||
"diskURI": "The URI the data disk in the blob storage",
|
||||
"cachingMode": "Host Caching mode: None, Read Only, Read Write.",
|
||||
"fsType": "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.",
|
||||
"readOnly": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.",
|
||||
}
|
||||
|
||||
func (AzureDiskVolumeSource) SwaggerDoc() map[string]string {
|
||||
return map_AzureDiskVolumeSource
|
||||
}
|
||||
|
||||
var map_AzureFileVolumeSource = map[string]string{
|
||||
"": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
"secretName": "the name of secret that contains Azure Storage Account Name and Key",
|
||||
|
@ -1083,6 +1096,7 @@ var map_PersistentVolumeSource = map[string]string{
|
|||
"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",
|
||||
"azureDisk": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
}
|
||||
|
||||
func (PersistentVolumeSource) SwaggerDoc() map[string]string {
|
||||
|
@ -1767,6 +1781,7 @@ var map_VolumeSource = map[string]string{
|
|||
"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",
|
||||
"azureDisk": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
|
||||
}
|
||||
|
||||
func (VolumeSource) SwaggerDoc() map[string]string {
|
||||
|
|
|
@ -44,6 +44,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
|||
Convert_api_AttachedVolume_To_v1_AttachedVolume,
|
||||
Convert_v1_AvoidPods_To_api_AvoidPods,
|
||||
Convert_api_AvoidPods_To_v1_AvoidPods,
|
||||
Convert_v1_AzureDiskVolumeSource_To_api_AzureDiskVolumeSource,
|
||||
Convert_api_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource,
|
||||
Convert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource,
|
||||
Convert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource,
|
||||
Convert_v1_Binding_To_api_Binding,
|
||||
|
@ -497,6 +499,45 @@ func Convert_api_AvoidPods_To_v1_AvoidPods(in *api.AvoidPods, out *AvoidPods, s
|
|||
return autoConvert_api_AvoidPods_To_v1_AvoidPods(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_AzureDiskVolumeSource_To_api_AzureDiskVolumeSource(in *AzureDiskVolumeSource, out *api.AzureDiskVolumeSource, s conversion.Scope) error {
|
||||
SetDefaults_AzureDiskVolumeSource(in)
|
||||
out.DiskName = in.DiskName
|
||||
out.DataDiskURI = in.DataDiskURI
|
||||
if in.CachingMode != nil {
|
||||
in, out := &in.CachingMode, &out.CachingMode
|
||||
*out = new(api.AzureDataDiskCachingMode)
|
||||
**out = api.AzureDataDiskCachingMode(**in)
|
||||
} else {
|
||||
out.CachingMode = nil
|
||||
}
|
||||
out.FSType = in.FSType
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_AzureDiskVolumeSource_To_api_AzureDiskVolumeSource(in *AzureDiskVolumeSource, out *api.AzureDiskVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_v1_AzureDiskVolumeSource_To_api_AzureDiskVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(in *api.AzureDiskVolumeSource, out *AzureDiskVolumeSource, s conversion.Scope) error {
|
||||
out.DiskName = in.DiskName
|
||||
out.DataDiskURI = in.DataDiskURI
|
||||
if in.CachingMode != nil {
|
||||
in, out := &in.CachingMode, &out.CachingMode
|
||||
*out = new(AzureDataDiskCachingMode)
|
||||
**out = AzureDataDiskCachingMode(**in)
|
||||
} else {
|
||||
out.CachingMode = nil
|
||||
}
|
||||
out.FSType = in.FSType
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(in *api.AzureDiskVolumeSource, out *AzureDiskVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_api_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in *AzureFileVolumeSource, out *api.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
|
@ -4210,6 +4251,15 @@ func autoConvert_v1_PersistentVolumeSource_To_api_PersistentVolumeSource(in *Per
|
|||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(api.AzureDiskVolumeSource)
|
||||
if err := Convert_v1_AzureDiskVolumeSource_To_api_AzureDiskVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -4353,6 +4403,15 @@ func autoConvert_api_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *api
|
|||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(AzureDiskVolumeSource)
|
||||
if err := Convert_api_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -6803,6 +6862,15 @@ func autoConvert_v1_VolumeSource_To_api_VolumeSource(in *VolumeSource, out *api.
|
|||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(api.AzureDiskVolumeSource)
|
||||
if err := Convert_v1_AzureDiskVolumeSource_To_api_AzureDiskVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -7000,6 +7068,15 @@ func autoConvert_api_VolumeSource_To_v1_VolumeSource(in *api.VolumeSource, out *
|
|||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(AzureDiskVolumeSource)
|
||||
if err := Convert_api_AzureDiskVolumeSource_To_v1_AzureDiskVolumeSource(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
|||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Affinity, InType: reflect.TypeOf(&Affinity{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_AttachedVolume, InType: reflect.TypeOf(&AttachedVolume{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_AvoidPods, InType: reflect.TypeOf(&AvoidPods{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_AzureDiskVolumeSource, InType: reflect.TypeOf(&AzureDiskVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_AzureFileVolumeSource, InType: reflect.TypeOf(&AzureFileVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Binding, InType: reflect.TypeOf(&Binding{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Capabilities, InType: reflect.TypeOf(&Capabilities{})},
|
||||
|
@ -268,6 +269,37 @@ func DeepCopy_v1_AvoidPods(in interface{}, out interface{}, c *conversion.Cloner
|
|||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1_AzureDiskVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*AzureDiskVolumeSource)
|
||||
out := out.(*AzureDiskVolumeSource)
|
||||
out.DiskName = in.DiskName
|
||||
out.DataDiskURI = in.DataDiskURI
|
||||
if in.CachingMode != nil {
|
||||
in, out := &in.CachingMode, &out.CachingMode
|
||||
*out = new(AzureDataDiskCachingMode)
|
||||
**out = **in
|
||||
} else {
|
||||
out.CachingMode = nil
|
||||
}
|
||||
if in.FSType != nil {
|
||||
in, out := &in.FSType, &out.FSType
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
} else {
|
||||
out.FSType = nil
|
||||
}
|
||||
if in.ReadOnly != nil {
|
||||
in, out := &in.ReadOnly, &out.ReadOnly
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
} else {
|
||||
out.ReadOnly = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_v1_AzureFileVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*AzureFileVolumeSource)
|
||||
|
@ -2188,6 +2220,15 @@ func DeepCopy_v1_PersistentVolumeSource(in interface{}, out interface{}, c *conv
|
|||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(AzureDiskVolumeSource)
|
||||
if err := DeepCopy_v1_AzureDiskVolumeSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -3626,6 +3667,15 @@ func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Clo
|
|||
} else {
|
||||
out.Quobyte = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(AzureDiskVolumeSource)
|
||||
if err := DeepCopy_v1_AzureDiskVolumeSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -631,6 +631,11 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E
|
|||
allErrs = append(allErrs, validateVsphereVolumeSource(source.VsphereVolume, fldPath.Child("vsphereVolume"))...)
|
||||
}
|
||||
}
|
||||
if source.AzureDisk != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...)
|
||||
}
|
||||
|
||||
if numVolumes == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
|
||||
}
|
||||
|
@ -941,6 +946,22 @@ func validateAzureFile(azure *api.AzureFileVolumeSource, fldPath *field.Path) fi
|
|||
return allErrs
|
||||
}
|
||||
|
||||
var supportedCachingModes = sets.NewString(string(api.AzureDataDiskCachingNone), string(api.AzureDataDiskCachingReadOnly), string(api.AzureDataDiskCachingReadWrite))
|
||||
|
||||
func validateAzureDisk(azure *api.AzureDiskVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if azure.DiskName == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("diskName"), ""))
|
||||
}
|
||||
if azure.DataDiskURI == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("diskURI"), ""))
|
||||
}
|
||||
if azure.CachingMode != nil && !supportedCachingModes.Has(string(*azure.CachingMode)) {
|
||||
allErrs = append(allErrs, field.NotSupported(fldPath.Child("cachingMode"), *azure.CachingMode, supportedCachingModes.List()))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func validateVsphereVolumeSource(cd *api.VsphereVirtualDiskVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if len(cd.VolumePath) == 0 {
|
||||
|
@ -1093,6 +1114,11 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
|
|||
allErrs = append(allErrs, validateVsphereVolumeSource(pv.Spec.VsphereVolume, specPath.Child("vsphereVolume"))...)
|
||||
}
|
||||
}
|
||||
if pv.Spec.AzureDisk != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureDisk(pv.Spec.AzureDisk, specPath.Child("azureDisk"))...)
|
||||
}
|
||||
|
||||
if numVolumes == 0 {
|
||||
allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
|
||||
}
|
||||
|
|
|
@ -2063,6 +2063,47 @@ func TestValidateVolumes(t *testing.T) {
|
|||
errtype: field.ErrorTypeRequired,
|
||||
errfield: "quobyte.volume",
|
||||
},
|
||||
// AzureDisk
|
||||
{
|
||||
name: "valid AzureDisk",
|
||||
vol: api.Volume{
|
||||
Name: "azure-disk",
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureDisk: &api.AzureDiskVolumeSource{
|
||||
DiskName: "foo",
|
||||
DataDiskURI: "https://blob/vhds/bar.vhd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AzureDisk empty disk name",
|
||||
vol: api.Volume{
|
||||
Name: "azure-disk",
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureDisk: &api.AzureDiskVolumeSource{
|
||||
DiskName: "",
|
||||
DataDiskURI: "https://blob/vhds/bar.vhd",
|
||||
},
|
||||
},
|
||||
},
|
||||
errtype: field.ErrorTypeRequired,
|
||||
errfield: "azureDisk.diskName",
|
||||
},
|
||||
{
|
||||
name: "AzureDisk empty disk uri",
|
||||
vol: api.Volume{
|
||||
Name: "azure-disk",
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureDisk: &api.AzureDiskVolumeSource{
|
||||
DiskName: "foo",
|
||||
DataDiskURI: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
errtype: field.ErrorTypeRequired,
|
||||
errfield: "azureDisk.diskURI",
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
|
|
|
@ -42,6 +42,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
|||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Affinity, InType: reflect.TypeOf(&Affinity{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_AttachedVolume, InType: reflect.TypeOf(&AttachedVolume{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_AvoidPods, InType: reflect.TypeOf(&AvoidPods{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_AzureDiskVolumeSource, InType: reflect.TypeOf(&AzureDiskVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_AzureFileVolumeSource, InType: reflect.TypeOf(&AzureFileVolumeSource{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Binding, InType: reflect.TypeOf(&Binding{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Capabilities, InType: reflect.TypeOf(&Capabilities{})},
|
||||
|
@ -272,6 +273,37 @@ func DeepCopy_api_AvoidPods(in interface{}, out interface{}, c *conversion.Clone
|
|||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_AzureDiskVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*AzureDiskVolumeSource)
|
||||
out := out.(*AzureDiskVolumeSource)
|
||||
out.DiskName = in.DiskName
|
||||
out.DataDiskURI = in.DataDiskURI
|
||||
if in.CachingMode != nil {
|
||||
in, out := &in.CachingMode, &out.CachingMode
|
||||
*out = new(AzureDataDiskCachingMode)
|
||||
**out = **in
|
||||
} else {
|
||||
out.CachingMode = nil
|
||||
}
|
||||
if in.FSType != nil {
|
||||
in, out := &in.FSType, &out.FSType
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
} else {
|
||||
out.FSType = nil
|
||||
}
|
||||
if in.ReadOnly != nil {
|
||||
in, out := &in.ReadOnly, &out.ReadOnly
|
||||
*out = new(bool)
|
||||
**out = **in
|
||||
} else {
|
||||
out.ReadOnly = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DeepCopy_api_AzureFileVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
{
|
||||
in := in.(*AzureFileVolumeSource)
|
||||
|
@ -2246,6 +2278,15 @@ func DeepCopy_api_PersistentVolumeSource(in interface{}, out interface{}, c *con
|
|||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(AzureDiskVolumeSource)
|
||||
if err := DeepCopy_api_AzureDiskVolumeSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -3661,6 +3702,15 @@ func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cl
|
|||
} else {
|
||||
out.VsphereVolume = nil
|
||||
}
|
||||
if in.AzureDisk != nil {
|
||||
in, out := &in.AzureDisk, &out.AzureDisk
|
||||
*out = new(AzureDiskVolumeSource)
|
||||
if err := DeepCopy_api_AzureDiskVolumeSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureDisk = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -718,6 +718,7 @@ var (
|
|||
ConfigMap FSType = "configMap"
|
||||
VsphereVolume FSType = "vsphereVolume"
|
||||
Quobyte FSType = "quobyte"
|
||||
AzureDisk FSType = "azureDisk"
|
||||
All FSType = "*"
|
||||
)
|
||||
|
||||
|
|
|
@ -996,6 +996,7 @@ var (
|
|||
FC FSType = "fc"
|
||||
ConfigMap FSType = "configMap"
|
||||
Quobyte FSType = "quobyte"
|
||||
AzureDisk FSType = "azureDisk"
|
||||
All FSType = "*"
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
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 azure
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
)
|
||||
|
||||
const (
|
||||
maxLUN = 64 // max number of LUNs per VM
|
||||
)
|
||||
|
||||
// AttachDisk attaches a vhd to vm
|
||||
// the vhd must exist, can be identified by diskName, diskURI, and lun.
|
||||
func (az *Cloud) AttachDisk(diskName, diskURI, vmName string, lun int32, cachingMode compute.CachingTypes) error {
|
||||
vm, exists, err := az.getVirtualMachine(vmName)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return cloudprovider.InstanceNotFound
|
||||
}
|
||||
disks := *vm.Properties.StorageProfile.DataDisks
|
||||
disks = append(disks,
|
||||
compute.DataDisk{
|
||||
Name: &diskName,
|
||||
Vhd: &compute.VirtualHardDisk{
|
||||
URI: &diskURI,
|
||||
},
|
||||
Lun: &lun,
|
||||
Caching: cachingMode,
|
||||
CreateOption: "attach",
|
||||
})
|
||||
|
||||
newVM := compute.VirtualMachine{
|
||||
Location: vm.Location,
|
||||
Properties: &compute.VirtualMachineProperties{
|
||||
StorageProfile: &compute.StorageProfile{
|
||||
DataDisks: &disks,
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = az.VirtualMachinesClient.CreateOrUpdate(az.ResourceGroup, vmName, newVM, nil)
|
||||
if err != nil {
|
||||
glog.Errorf("azure attach failed, err: %v", err)
|
||||
detail := err.Error()
|
||||
if strings.Contains(detail, "Code=\"AcquireDiskLeaseFailed\"") {
|
||||
// if lease cannot be acquired, immediately detach the disk and return the original error
|
||||
glog.Infof("failed to acquire disk lease, try detach")
|
||||
az.DetachDiskByName(diskName, diskURI, vmName)
|
||||
}
|
||||
} else {
|
||||
glog.V(4).Infof("azure attach succeeded")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// DetachDiskByName detaches a vhd from host
|
||||
// the vhd can be identified by diskName or diskURI
|
||||
func (az *Cloud) DetachDiskByName(diskName, diskURI, vmName string) error {
|
||||
vm, exists, err := az.getVirtualMachine(vmName)
|
||||
if err != nil || !exists {
|
||||
// if host doesn't exist, no need to detach
|
||||
glog.Warningf("cannot find node %s, skip detaching disk %s", vmName, diskName)
|
||||
return nil
|
||||
}
|
||||
|
||||
disks := *vm.Properties.StorageProfile.DataDisks
|
||||
for i, disk := range disks {
|
||||
if (disk.Name != nil && diskName != "" && *disk.Name == diskName) || (disk.Vhd.URI != nil && diskURI != "" && *disk.Vhd.URI == diskURI) {
|
||||
// found the disk
|
||||
glog.V(4).Infof("detach disk: name %q uri %q", diskName, diskURI)
|
||||
disks = append(disks[:i], disks[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
newVM := compute.VirtualMachine{
|
||||
Location: vm.Location,
|
||||
Properties: &compute.VirtualMachineProperties{
|
||||
StorageProfile: &compute.StorageProfile{
|
||||
DataDisks: &disks,
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err = az.VirtualMachinesClient.CreateOrUpdate(az.ResourceGroup, vmName, newVM, nil)
|
||||
if err != nil {
|
||||
glog.Errorf("azure disk detach failed, err: %v", err)
|
||||
} else {
|
||||
glog.V(4).Infof("azure disk detach succeeded")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDiskLun finds the lun on the host that the vhd is attached to, given a vhd's diskName and diskURI
|
||||
func (az *Cloud) GetDiskLun(diskName, diskURI, vmName string) (int32, error) {
|
||||
vm, exists, err := az.getVirtualMachine(vmName)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
} else if !exists {
|
||||
return -1, cloudprovider.InstanceNotFound
|
||||
}
|
||||
disks := *vm.Properties.StorageProfile.DataDisks
|
||||
for _, disk := range disks {
|
||||
if disk.Lun != nil && (disk.Name != nil && diskName != "" && *disk.Name == diskName) || (disk.Vhd.URI != nil && diskURI != "" && *disk.Vhd.URI == diskURI) {
|
||||
// found the disk
|
||||
glog.V(4).Infof("find disk: lun %d name %q uri %q", *disk.Lun, diskName, diskURI)
|
||||
return *disk.Lun, nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("Cannot find Lun for disk %s", diskName)
|
||||
}
|
||||
|
||||
// GetNextDiskLun searches all vhd attachment on the host and find unused lun
|
||||
// return -1 if all luns are used
|
||||
func (az *Cloud) GetNextDiskLun(vmName string) (int32, error) {
|
||||
vm, exists, err := az.getVirtualMachine(vmName)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
} else if !exists {
|
||||
return -1, cloudprovider.InstanceNotFound
|
||||
}
|
||||
used := make([]bool, maxLUN)
|
||||
disks := *vm.Properties.StorageProfile.DataDisks
|
||||
for _, disk := range disks {
|
||||
if disk.Lun != nil {
|
||||
used[*disk.Lun] = true
|
||||
}
|
||||
}
|
||||
for k, v := range used {
|
||||
if !v {
|
||||
return int32(k), nil
|
||||
}
|
||||
}
|
||||
return -1, fmt.Errorf("All Luns are used")
|
||||
}
|
|
@ -608,6 +608,8 @@ func describeVolumes(volumes []api.Volume, out io.Writer, space string) {
|
|||
printQuobyteVolumeSource(volume.VolumeSource.Quobyte, out)
|
||||
case volume.VolumeSource.DownwardAPI != nil:
|
||||
printDownwardAPIVolumeSource(volume.VolumeSource.DownwardAPI, out)
|
||||
case volume.VolumeSource.AzureDisk != nil:
|
||||
printAzureDiskVolumeSource(volume.VolumeSource.AzureDisk, out)
|
||||
default:
|
||||
fmt.Fprintf(out, " <unknown>\n")
|
||||
}
|
||||
|
@ -726,6 +728,16 @@ func printDownwardAPIVolumeSource(d *api.DownwardAPIVolumeSource, out io.Writer)
|
|||
}
|
||||
}
|
||||
|
||||
func printAzureDiskVolumeSource(d *api.AzureDiskVolumeSource, out io.Writer) {
|
||||
fmt.Fprintf(out, " Type:\tAzureDisk (an Azure Data Disk mount on the host and bind mount to the pod)\n"+
|
||||
" DiskName:\t%v\n"+
|
||||
" DiskURI:\t%v\n"+
|
||||
" FSType:\t%v\n"+
|
||||
" CachingMode:\t%v\n"+
|
||||
" ReadOnly:\t%v\n",
|
||||
d.DiskName, d.DataDiskURI, *d.FSType, *d.CachingMode, *d.ReadOnly)
|
||||
}
|
||||
|
||||
type PersistentVolumeDescriber struct {
|
||||
client.Interface
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ func GetAllFSTypesAsSet() sets.String {
|
|||
string(extensions.FC),
|
||||
string(extensions.ConfigMap),
|
||||
string(extensions.VsphereVolume),
|
||||
string(extensions.Quobyte))
|
||||
string(extensions.Quobyte),
|
||||
string(extensions.AzureDisk))
|
||||
return fstypes
|
||||
}
|
||||
|
||||
|
@ -108,6 +109,8 @@ func GetVolumeFSType(v api.Volume) (extensions.FSType, error) {
|
|||
return extensions.VsphereVolume, nil
|
||||
case v.Quobyte != nil:
|
||||
return extensions.Quobyte, nil
|
||||
case v.AzureDisk != nil:
|
||||
return extensions.AzureDisk, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("unknown volume type for volume: %#v", v)
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
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 azure_dd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
"k8s.io/kubernetes/pkg/util/keymutex"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/util/wait"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
"k8s.io/kubernetes/pkg/volume/util"
|
||||
)
|
||||
|
||||
type azureDiskAttacher struct {
|
||||
host volume.VolumeHost
|
||||
azureProvider azureCloudProvider
|
||||
}
|
||||
|
||||
var _ volume.Attacher = &azureDiskAttacher{}
|
||||
|
||||
var _ volume.AttachableVolumePlugin = &azureDataDiskPlugin{}
|
||||
|
||||
const (
|
||||
checkSleepDuration = time.Second
|
||||
)
|
||||
|
||||
// acquire lock to get an lun number
|
||||
var getLunMutex = keymutex.NewKeyMutex()
|
||||
|
||||
// NewAttacher initializes an Attacher
|
||||
func (plugin *azureDataDiskPlugin) NewAttacher() (volume.Attacher, error) {
|
||||
azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider())
|
||||
if err != nil {
|
||||
glog.V(4).Infof("failed to get azure provider")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &azureDiskAttacher{
|
||||
host: plugin.host,
|
||||
azureProvider: azure,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Attach attaches a volume.Spec to a Azure VM referenced by hostname, returning the disk's LUN
|
||||
func (attacher *azureDiskAttacher) Attach(spec *volume.Spec, hostName string) (string, error) {
|
||||
volumeSource, err := getVolumeSource(spec)
|
||||
if err != nil {
|
||||
glog.Warningf("failed to get azure disk spec")
|
||||
return "", err
|
||||
}
|
||||
instanceid, err := attacher.azureProvider.InstanceID(hostName)
|
||||
if err != nil {
|
||||
glog.Warningf("failed to get azure instance id")
|
||||
return "", fmt.Errorf("failed to get azure instance id for host %q", hostName)
|
||||
}
|
||||
if ind := strings.LastIndex(instanceid, "/"); ind >= 0 {
|
||||
instanceid = instanceid[(ind + 1):]
|
||||
}
|
||||
|
||||
lun, err := attacher.azureProvider.GetDiskLun(volumeSource.DiskName, volumeSource.DataDiskURI, instanceid)
|
||||
if err == cloudprovider.InstanceNotFound {
|
||||
// Log error and continue with attach
|
||||
glog.Warningf(
|
||||
"Error checking if volume is already attached to current node (%q). Will continue and try attach anyway. err=%v",
|
||||
instanceid, err)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// Volume is already attached to node.
|
||||
glog.V(4).Infof("Attach operation is successful. volume %q is already attached to node %q at lun %d.", volumeSource.DiskName, instanceid, lun)
|
||||
} else {
|
||||
getLunMutex.LockKey(instanceid)
|
||||
defer getLunMutex.UnlockKey(instanceid)
|
||||
|
||||
lun, err = attacher.azureProvider.GetNextDiskLun(instanceid)
|
||||
if err != nil {
|
||||
glog.Warningf("no LUN available for instance %q", instanceid)
|
||||
return "", fmt.Errorf("all LUNs are used, cannot attach volume %q to instance %q", volumeSource.DiskName, instanceid)
|
||||
}
|
||||
|
||||
err = attacher.azureProvider.AttachDisk(volumeSource.DiskName, volumeSource.DataDiskURI, instanceid, lun, compute.CachingTypes(*volumeSource.CachingMode))
|
||||
if err == nil {
|
||||
glog.V(4).Infof("Attach operation successful: volume %q attached to node %q.", volumeSource.DataDiskURI, instanceid)
|
||||
} else {
|
||||
glog.V(2).Infof("Attach volume %q to instance %q failed with %v", volumeSource.DataDiskURI, instanceid, err)
|
||||
return "", fmt.Errorf("Attach volume %q to instance %q failed with %v", volumeSource.DiskName, instanceid, err)
|
||||
}
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(lun)), err
|
||||
}
|
||||
|
||||
// WaitForAttach runs on the node to detect if the volume (referenced by LUN) is attached. If attached, the device path is returned
|
||||
func (attacher *azureDiskAttacher) WaitForAttach(spec *volume.Spec, lunStr string, timeout time.Duration) (string, error) {
|
||||
volumeSource, err := getVolumeSource(spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(lunStr) == 0 {
|
||||
return "", fmt.Errorf("WaitForAttach failed for Azure disk %q: lun is empty.", volumeSource.DiskName)
|
||||
}
|
||||
|
||||
lun, err := strconv.Atoi(lunStr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("WaitForAttach: wrong lun %q, err: %v", lunStr, err)
|
||||
}
|
||||
scsiHostRescan(&osIOHandler{})
|
||||
exe := exec.New()
|
||||
devicePath := ""
|
||||
|
||||
err = wait.Poll(checkSleepDuration, timeout, func() (bool, error) {
|
||||
glog.V(4).Infof("Checking Azure disk %q(lun %s) is attached.", volumeSource.DiskName, lunStr)
|
||||
if devicePath, err = findDiskByLun(lun, &osIOHandler{}, exe); err == nil {
|
||||
glog.V(4).Infof("Successfully found attached Azure disk %q(lun %s, device path %s).", volumeSource.DiskName, lunStr, devicePath)
|
||||
return true, nil
|
||||
} else {
|
||||
//Log error, if any, and continue checking periodically
|
||||
glog.V(4).Infof("Error Stat Azure disk (%q) is attached: %v", volumeSource.DiskName, err)
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
return devicePath, err
|
||||
}
|
||||
|
||||
// GetDeviceMountPath finds the volume's mount path on the node
|
||||
func (attacher *azureDiskAttacher) GetDeviceMountPath(spec *volume.Spec) (string, error) {
|
||||
volumeSource, err := getVolumeSource(spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return makeGlobalPDPath(attacher.host, volumeSource.DiskName), nil
|
||||
}
|
||||
|
||||
// MountDevice runs mount command on the node to mount the volume
|
||||
func (attacher *azureDiskAttacher) MountDevice(spec *volume.Spec, devicePath string, deviceMountPath string) error {
|
||||
mounter := attacher.host.GetMounter()
|
||||
notMnt, err := mounter.IsLikelyNotMountPoint(deviceMountPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(deviceMountPath, 0750); err != nil {
|
||||
return err
|
||||
}
|
||||
notMnt = true
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
volumeSource, err := getVolumeSource(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
options := []string{}
|
||||
if spec.ReadOnly {
|
||||
options = append(options, "ro")
|
||||
}
|
||||
if notMnt {
|
||||
diskMounter := &mount.SafeFormatAndMount{Interface: mounter, Runner: exec.New()}
|
||||
err = diskMounter.FormatAndMount(devicePath, deviceMountPath, *volumeSource.FSType, options)
|
||||
if err != nil {
|
||||
os.Remove(deviceMountPath)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type azureDiskDetacher struct {
|
||||
mounter mount.Interface
|
||||
azureProvider azureCloudProvider
|
||||
}
|
||||
|
||||
var _ volume.Detacher = &azureDiskDetacher{}
|
||||
|
||||
// NewDetacher initializes a volume Detacher
|
||||
func (plugin *azureDataDiskPlugin) NewDetacher() (volume.Detacher, error) {
|
||||
azure, err := getAzureCloudProvider(plugin.host.GetCloudProvider())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &azureDiskDetacher{
|
||||
mounter: plugin.host.GetMounter(),
|
||||
azureProvider: azure,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Detach detaches disk from Azure VM.
|
||||
func (detacher *azureDiskDetacher) Detach(diskName string, hostName string) error {
|
||||
if diskName == "" {
|
||||
return fmt.Errorf("invalid disk to detach: %q", diskName)
|
||||
}
|
||||
instanceid, err := detacher.azureProvider.InstanceID(hostName)
|
||||
if err != nil {
|
||||
glog.Warningf("no instance id for host %q, skip detaching", hostName)
|
||||
return nil
|
||||
}
|
||||
if ind := strings.LastIndex(instanceid, "/"); ind >= 0 {
|
||||
instanceid = instanceid[(ind + 1):]
|
||||
}
|
||||
|
||||
glog.V(4).Infof("detach %v from host %q", diskName, instanceid)
|
||||
err = detacher.azureProvider.DetachDiskByName(diskName, "" /* diskURI */, instanceid)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to detach azure disk %q, err %v", diskName, err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// WaitForDetach detects if the disk is detached on the node
|
||||
func (detacher *azureDiskDetacher) WaitForDetach(devicePath string, timeout time.Duration) error {
|
||||
return wait.Poll(checkSleepDuration, timeout, func() (bool, error) {
|
||||
glog.V(4).Infof("Checking device %q is detached.", devicePath)
|
||||
if pathExists, err := util.PathExists(devicePath); err != nil {
|
||||
return false, fmt.Errorf("Error checking if device path exists: %v", err)
|
||||
} else if !pathExists {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// UnmountDevice unmounts the volume on the node
|
||||
func (detacher *azureDiskDetacher) UnmountDevice(deviceMountPath string) error {
|
||||
volume := path.Base(deviceMountPath)
|
||||
if err := util.UnmountPath(deviceMountPath, detacher.mounter); err != nil {
|
||||
glog.Errorf("Error unmounting %q: %v", volume, err)
|
||||
return err
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
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 azure_dd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider/providers/azure"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
"k8s.io/kubernetes/pkg/util/keymutex"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
utilstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
)
|
||||
|
||||
// This is the primary entrypoint for volume plugins.
|
||||
func ProbeVolumePlugins() []volume.VolumePlugin {
|
||||
return []volume.VolumePlugin{&azureDataDiskPlugin{}}
|
||||
}
|
||||
|
||||
type azureDataDiskPlugin struct {
|
||||
host volume.VolumeHost
|
||||
volumeLocks keymutex.KeyMutex
|
||||
}
|
||||
|
||||
// Abstract interface to disk operations.
|
||||
// azure cloud provider should implement it
|
||||
type azureCloudProvider interface {
|
||||
// Attaches the disk to the host machine.
|
||||
AttachDisk(diskName, diskUri, vmName string, lun int32, cachingMode compute.CachingTypes) error
|
||||
// Detaches the disk, identified by disk name or uri, from the host machine.
|
||||
DetachDiskByName(diskName, diskUri, vmName string) error
|
||||
// Get the LUN number of the disk that is attached to the host
|
||||
GetDiskLun(diskName, diskUri, vmName string) (int32, error)
|
||||
// Get the next available LUN number to attach a new VHD
|
||||
GetNextDiskLun(vmName string) (int32, error)
|
||||
// InstanceID returns the cloud provider ID of the specified instance.
|
||||
InstanceID(name string) (string, error)
|
||||
}
|
||||
|
||||
var _ volume.VolumePlugin = &azureDataDiskPlugin{}
|
||||
var _ volume.PersistentVolumePlugin = &azureDataDiskPlugin{}
|
||||
|
||||
const (
|
||||
azureDataDiskPluginName = "kubernetes.io/azure-disk"
|
||||
)
|
||||
|
||||
func (plugin *azureDataDiskPlugin) Init(host volume.VolumeHost) error {
|
||||
plugin.host = host
|
||||
plugin.volumeLocks = keymutex.NewKeyMutex()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) GetPluginName() string {
|
||||
return azureDataDiskPluginName
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
|
||||
volumeSource, err := getVolumeSource(spec)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return volumeSource.DiskName, nil
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) CanSupport(spec *volume.Spec) bool {
|
||||
return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureDisk != nil) ||
|
||||
(spec.Volume != nil && spec.Volume.AzureDisk != nil)
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) RequiresRemount() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
|
||||
return []api.PersistentVolumeAccessMode{
|
||||
api.ReadWriteOnce,
|
||||
}
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
|
||||
return plugin.newMounterInternal(spec, pod.UID, plugin.host.GetMounter())
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) newMounterInternal(spec *volume.Spec, podUID types.UID, mounter mount.Interface) (volume.Mounter, error) {
|
||||
// azures used directly in a pod have a ReadOnly flag set by the pod author.
|
||||
// azures used as a PersistentVolume gets the ReadOnly flag indirectly through the persistent-claim volume used to mount the PV
|
||||
azure, err := getVolumeSource(spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fsType := *azure.FSType
|
||||
diskName := azure.DiskName
|
||||
diskUri := azure.DataDiskURI
|
||||
cachingMode := *azure.CachingMode
|
||||
return &azureDiskMounter{
|
||||
azureDisk: &azureDisk{
|
||||
podUID: podUID,
|
||||
volName: spec.Name(),
|
||||
diskName: diskName,
|
||||
diskUri: diskUri,
|
||||
cachingMode: cachingMode,
|
||||
mounter: mounter,
|
||||
plugin: plugin,
|
||||
},
|
||||
fsType: fsType,
|
||||
readOnly: *azure.ReadOnly,
|
||||
diskMounter: &mount.SafeFormatAndMount{Interface: plugin.host.GetMounter(), Runner: exec.New()}}, nil
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
|
||||
return plugin.newUnmounterInternal(volName, podUID, plugin.host.GetMounter())
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) newUnmounterInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Unmounter, error) {
|
||||
return &azureDiskUnmounter{
|
||||
&azureDisk{
|
||||
podUID: podUID,
|
||||
volName: volName,
|
||||
mounter: mounter,
|
||||
plugin: plugin,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) ConstructVolumeSpec(volName, mountPath string) (*volume.Spec, error) {
|
||||
mounter := plugin.host.GetMounter()
|
||||
pluginDir := plugin.host.GetPluginDir(plugin.GetPluginName())
|
||||
sourceName, err := mounter.GetDeviceNameFromMount(mountPath, pluginDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
azVolume := &api.Volume{
|
||||
Name: volName,
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureDisk: &api.AzureDiskVolumeSource{
|
||||
DiskName: sourceName,
|
||||
},
|
||||
},
|
||||
}
|
||||
return volume.NewSpecFromVolume(azVolume), nil
|
||||
}
|
||||
|
||||
func (plugin *azureDataDiskPlugin) GetDeviceMountRefs(deviceMountPath string) ([]string, error) {
|
||||
mounter := plugin.host.GetMounter()
|
||||
return mount.GetMountRefs(mounter, deviceMountPath)
|
||||
}
|
||||
|
||||
type azureDisk struct {
|
||||
volName string
|
||||
podUID types.UID
|
||||
diskName string
|
||||
diskUri string
|
||||
cachingMode api.AzureDataDiskCachingMode
|
||||
mounter mount.Interface
|
||||
plugin *azureDataDiskPlugin
|
||||
volume.MetricsNil
|
||||
}
|
||||
|
||||
type azureDiskMounter struct {
|
||||
*azureDisk
|
||||
// Filesystem type, optional.
|
||||
fsType string
|
||||
// Specifies whether the disk will be attached as read-only.
|
||||
readOnly bool
|
||||
// diskMounter provides the interface that is used to mount the actual block device.
|
||||
diskMounter *mount.SafeFormatAndMount
|
||||
}
|
||||
|
||||
var _ volume.Mounter = &azureDiskMounter{}
|
||||
|
||||
func (b *azureDiskMounter) GetAttributes() volume.Attributes {
|
||||
return volume.Attributes{
|
||||
ReadOnly: b.readOnly,
|
||||
Managed: !b.readOnly,
|
||||
SupportsSELinux: true,
|
||||
}
|
||||
}
|
||||
|
||||
// SetUp attaches the disk and bind mounts to the volume path.
|
||||
func (b *azureDiskMounter) SetUp(fsGroup *int64) error {
|
||||
return b.SetUpAt(b.GetPath(), fsGroup)
|
||||
}
|
||||
|
||||
// SetUpAt attaches the disk and bind mounts to the volume path.
|
||||
func (b *azureDiskMounter) SetUpAt(dir string, fsGroup *int64) error {
|
||||
b.plugin.volumeLocks.LockKey(b.diskName)
|
||||
defer b.plugin.volumeLocks.UnlockKey(b.diskName)
|
||||
|
||||
// TODO: handle failed mounts here.
|
||||
notMnt, err := b.mounter.IsLikelyNotMountPoint(dir)
|
||||
glog.V(4).Infof("DataDisk set up: %s %v %v", dir, !notMnt, err)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
glog.Errorf("IsLikelyNotMountPoint failed: %v", err)
|
||||
return err
|
||||
}
|
||||
if !notMnt {
|
||||
glog.V(4).Infof("%s is a mount point", dir)
|
||||
return nil
|
||||
}
|
||||
|
||||
globalPDPath := makeGlobalPDPath(b.plugin.host, b.diskName)
|
||||
|
||||
if err := os.MkdirAll(dir, 0750); err != nil {
|
||||
glog.V(4).Infof("Could not create directory %s: %v", dir, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform a bind mount to the full path to allow duplicate mounts of the same PD.
|
||||
options := []string{"bind"}
|
||||
if b.readOnly {
|
||||
options = append(options, "ro")
|
||||
}
|
||||
err = b.mounter.Mount(globalPDPath, dir, "", options)
|
||||
if err != nil {
|
||||
notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
|
||||
if mntErr != nil {
|
||||
glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
|
||||
return err
|
||||
}
|
||||
if !notMnt {
|
||||
if mntErr = b.mounter.Unmount(dir); mntErr != nil {
|
||||
glog.Errorf("Failed to unmount: %v", mntErr)
|
||||
return err
|
||||
}
|
||||
notMnt, mntErr := b.mounter.IsLikelyNotMountPoint(dir)
|
||||
if mntErr != nil {
|
||||
glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
|
||||
return err
|
||||
}
|
||||
if !notMnt {
|
||||
// This is very odd, we don't expect it. We'll try again next sync loop.
|
||||
glog.Errorf("%s is still mounted, despite call to unmount(). Will try again next sync loop.", dir)
|
||||
return err
|
||||
}
|
||||
}
|
||||
os.Remove(dir)
|
||||
return err
|
||||
}
|
||||
|
||||
if !b.readOnly {
|
||||
volume.SetVolumeOwnership(b, fsGroup)
|
||||
}
|
||||
glog.V(3).Infof("Azure disk volume %s mounted to %s", b.diskName, dir)
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeGlobalPDPath(host volume.VolumeHost, volume string) string {
|
||||
return path.Join(host.GetPluginDir(azureDataDiskPluginName), "mounts", volume)
|
||||
}
|
||||
|
||||
func (azure *azureDisk) GetPath() string {
|
||||
name := azureDataDiskPluginName
|
||||
return azure.plugin.host.GetPodVolumeDir(azure.podUID, utilstrings.EscapeQualifiedNameForDisk(name), azure.volName)
|
||||
}
|
||||
|
||||
type azureDiskUnmounter struct {
|
||||
*azureDisk
|
||||
}
|
||||
|
||||
var _ volume.Unmounter = &azureDiskUnmounter{}
|
||||
|
||||
// Unmounts the bind mount, and detaches the disk only if the PD
|
||||
// resource was the last reference to that disk on the kubelet.
|
||||
func (c *azureDiskUnmounter) TearDown() error {
|
||||
return c.TearDownAt(c.GetPath())
|
||||
}
|
||||
|
||||
// Unmounts the bind mount, and detaches the disk only if the PD
|
||||
// resource was the last reference to that disk on the kubelet.
|
||||
func (c *azureDiskUnmounter) TearDownAt(dir string) error {
|
||||
notMnt, err := c.mounter.IsLikelyNotMountPoint(dir)
|
||||
if err != nil {
|
||||
glog.Errorf("Error checking if mountpoint %s: %v", dir, err)
|
||||
return err
|
||||
}
|
||||
if notMnt {
|
||||
glog.V(2).Info("Not mountpoint, deleting")
|
||||
return os.Remove(dir)
|
||||
}
|
||||
// lock the volume (and thus wait for any concurrrent SetUpAt to finish)
|
||||
c.plugin.volumeLocks.LockKey(c.diskName)
|
||||
defer c.plugin.volumeLocks.UnlockKey(c.diskName)
|
||||
refs, err := mount.GetMountRefs(c.mounter, dir)
|
||||
if err != nil {
|
||||
glog.Errorf("Error getting mountrefs for %s: %v", dir, err)
|
||||
return err
|
||||
}
|
||||
if len(refs) == 0 {
|
||||
glog.Errorf("Did not find pod-mount for %s during tear down", dir)
|
||||
return fmt.Errorf("%s is not mounted", dir)
|
||||
}
|
||||
c.diskName = path.Base(refs[0])
|
||||
glog.V(4).Infof("Found volume %s mounted to %s", c.diskName, dir)
|
||||
|
||||
// Unmount the bind-mount inside this pod
|
||||
if err := c.mounter.Unmount(dir); err != nil {
|
||||
glog.Errorf("Error unmounting dir %s %v", dir, err)
|
||||
return err
|
||||
}
|
||||
notMnt, mntErr := c.mounter.IsLikelyNotMountPoint(dir)
|
||||
if mntErr != nil {
|
||||
glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
|
||||
return err
|
||||
}
|
||||
if notMnt {
|
||||
if err := os.Remove(dir); err != nil {
|
||||
glog.Errorf("Error removing mountpoint %s %v", dir, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getVolumeSource(spec *volume.Spec) (*api.AzureDiskVolumeSource, error) {
|
||||
if spec.Volume != nil && spec.Volume.AzureDisk != nil {
|
||||
return spec.Volume.AzureDisk, nil
|
||||
}
|
||||
if spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureDisk != nil {
|
||||
return spec.PersistentVolume.Spec.AzureDisk, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Spec does not reference an Azure disk volume type")
|
||||
}
|
||||
|
||||
// Return cloud provider
|
||||
func getAzureCloudProvider(cloudProvider cloudprovider.Interface) (azureCloudProvider, error) {
|
||||
azureCloudProvider, ok := cloudProvider.(*azure.Cloud)
|
||||
if !ok || azureCloudProvider == nil {
|
||||
return nil, fmt.Errorf("Failed to get Azure Cloud Provider. GetCloudProvider returned %v instead", cloudProvider)
|
||||
}
|
||||
|
||||
return azureCloudProvider, nil
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
Copyright 2015 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 azure_dd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"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("azure_dd")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil, "" /* rootContext */))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName(azureDataDiskPluginName)
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
if plug.GetPluginName() != azureDataDiskPluginName {
|
||||
t.Errorf("Wrong name: %s", plug.GetPluginName())
|
||||
}
|
||||
if !plug.CanSupport(&volume.Spec{Volume: &api.Volume{VolumeSource: api.VolumeSource{AzureDisk: &api.AzureDiskVolumeSource{}}}}) {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
|
||||
if !plug.CanSupport(&volume.Spec{PersistentVolume: &api.PersistentVolume{Spec: api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{AzureDisk: &api.AzureDiskVolumeSource{}}}}}) {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
fakeDiskName = "foo"
|
||||
fakeDiskUri = "https://azure/vhds/bar.vhd"
|
||||
fakeLun = 2
|
||||
)
|
||||
|
||||
type fakeAzureProvider struct {
|
||||
}
|
||||
|
||||
func (fake *fakeAzureProvider) AttachDisk(diskName, diskUri, vmName string, lun int32, cachingMode compute.CachingTypes) error {
|
||||
if diskName != fakeDiskName || diskUri != fakeDiskUri || lun != fakeLun {
|
||||
return fmt.Errorf("wrong disk")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (fake *fakeAzureProvider) DetachDiskByName(diskName, diskUri, vmName string) error {
|
||||
if diskName != fakeDiskName || diskUri != fakeDiskUri {
|
||||
return fmt.Errorf("wrong disk")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (fake *fakeAzureProvider) GetDiskLun(diskName, diskUri, vmName string) (int32, error) {
|
||||
return int32(fakeLun), nil
|
||||
}
|
||||
|
||||
func (fake *fakeAzureProvider) GetNextDiskLun(vmName string) (int32, error) {
|
||||
return fakeLun, nil
|
||||
}
|
||||
func (fake *fakeAzureProvider) InstanceID(name string) (string, error) {
|
||||
return "localhost", nil
|
||||
}
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
tmpDir, err := utiltesting.MkTmpdir("azure_ddTest")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(tmpDir, nil, nil, "" /* rootContext */))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName(azureDataDiskPluginName)
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
fs := "ext4"
|
||||
ro := false
|
||||
caching := api.AzureDataDiskCachingNone
|
||||
spec := &api.Volume{
|
||||
Name: "vol1",
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureDisk: &api.AzureDiskVolumeSource{
|
||||
DiskName: fakeDiskName,
|
||||
DataDiskURI: fakeDiskUri,
|
||||
FSType: &fs,
|
||||
CachingMode: &caching,
|
||||
ReadOnly: &ro,
|
||||
},
|
||||
},
|
||||
}
|
||||
mounter, err := plug.(*azureDataDiskPlugin).newMounterInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &mount.FakeMounter{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Mounter: %v", err)
|
||||
}
|
||||
if mounter == nil {
|
||||
t.Errorf("Got a nil Mounter")
|
||||
}
|
||||
volPath := path.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~azure-disk/vol1")
|
||||
path := mounter.GetPath()
|
||||
if path != volPath {
|
||||
t.Errorf("Got unexpected path: %s, should be %s", path, volPath)
|
||||
}
|
||||
|
||||
if err := mounter.SetUp(nil); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed, volume path not created: %s", path)
|
||||
} else {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed, volume path not created: %s", path)
|
||||
} else {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
unmounter, err := plug.(*azureDataDiskPlugin).newUnmounterInternal("vol1", types.UID("poduid"), &mount.FakeMounter{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Unmounter: %v", err)
|
||||
}
|
||||
if unmounter == nil {
|
||||
t.Errorf("Got a nil Unmounter")
|
||||
}
|
||||
|
||||
if err := unmounter.TearDown(); err != nil {
|
||||
t.Errorf("Expected success, got: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
t.Errorf("TearDown() failed, volume path still exists: %s", path)
|
||||
} else if !os.IsNotExist(err) {
|
||||
t.Errorf("SetUp() failed: %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
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 azure_dd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
type ioHandler interface {
|
||||
ReadDir(dirname string) ([]os.FileInfo, error)
|
||||
WriteFile(filename string, data []byte, perm os.FileMode) error
|
||||
}
|
||||
|
||||
type osIOHandler struct{}
|
||||
|
||||
func (handler *osIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) {
|
||||
return ioutil.ReadDir(dirname)
|
||||
}
|
||||
func (handler *osIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
return ioutil.WriteFile(filename, data, perm)
|
||||
}
|
||||
|
||||
// given a LUN find the VHD device path like /dev/sdb
|
||||
// VHD disks under sysfs are like /sys/bus/scsi/devices/3:0:1:0
|
||||
// return empty string if no disk is found
|
||||
func findDiskByLun(lun int, io ioHandler, exe exec.Interface) (string, error) {
|
||||
var err error
|
||||
sys_path := "/sys/bus/scsi/devices"
|
||||
if dirs, err := io.ReadDir(sys_path); err == nil {
|
||||
for _, f := range dirs {
|
||||
name := f.Name()
|
||||
// look for path like /sys/bus/scsi/devices/3:0:1:0
|
||||
arr := strings.Split(name, ":")
|
||||
if len(arr) < 4 {
|
||||
continue
|
||||
}
|
||||
target, err := strconv.Atoi(arr[0])
|
||||
if err != nil {
|
||||
glog.Errorf("failed to parse target from %v (%v), err %v", arr[0], name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// as observed, targets 0-3 are used by OS disks. Skip them
|
||||
if target > 3 {
|
||||
l, err := strconv.Atoi(arr[3])
|
||||
if err != nil {
|
||||
// unknown path format, continue to read the next one
|
||||
glog.Errorf("failed to parse lun from %v (%v), err %v", arr[3], name, err)
|
||||
continue
|
||||
}
|
||||
if lun == l {
|
||||
// find the matching LUN
|
||||
// read vendor and model to ensure it is a VHD disk
|
||||
vendor := path.Join(sys_path, name, "vendor")
|
||||
model := path.Join(sys_path, name, "model")
|
||||
out, err := exe.Command("cat", vendor, model).CombinedOutput()
|
||||
if err != nil {
|
||||
glog.Errorf("failed to cat device vendor and model, err: %v", err)
|
||||
continue
|
||||
}
|
||||
matched, err := regexp.MatchString("^MSFT[ ]{0,}\nVIRTUAL DISK[ ]{0,}\n$", strings.ToUpper(string(out)))
|
||||
if err != nil || !matched {
|
||||
glog.V(4).Infof("doesn't match VHD, output %v, error %v", string(out), err)
|
||||
continue
|
||||
}
|
||||
// find it!
|
||||
dir := path.Join(sys_path, name, "block")
|
||||
dev, err := io.ReadDir(dir)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to read %s", dir)
|
||||
} else {
|
||||
return "/dev/" + dev[0].Name(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
// rescan scsi bus
|
||||
func scsiHostRescan(io ioHandler) {
|
||||
scsi_path := "/sys/class/scsi_host/"
|
||||
if dirs, err := io.ReadDir(scsi_path); err == nil {
|
||||
for _, f := range dirs {
|
||||
name := scsi_path + f.Name() + "/scan"
|
||||
data := []byte("- - -")
|
||||
if err = io.WriteFile(name, data, 0666); err != nil {
|
||||
glog.Errorf("failed to rescan scsi host %s", name)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
glog.Errorf("failed to read %s, err %v", scsi_path, err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
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 azure_dd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/exec"
|
||||
)
|
||||
|
||||
type fakeFileInfo struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (fi *fakeFileInfo) Name() string {
|
||||
return fi.name
|
||||
}
|
||||
|
||||
func (fi *fakeFileInfo) Size() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fi *fakeFileInfo) Mode() os.FileMode {
|
||||
return 777
|
||||
}
|
||||
|
||||
func (fi *fakeFileInfo) ModTime() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
func (fi *fakeFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (fi *fakeFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
lun = 1
|
||||
lunStr = "1"
|
||||
diskPath = "4:0:0:" + lunStr
|
||||
devName = "sda"
|
||||
)
|
||||
|
||||
type fakeIOHandler struct{}
|
||||
|
||||
func (handler *fakeIOHandler) ReadDir(dirname string) ([]os.FileInfo, error) {
|
||||
switch dirname {
|
||||
case "/sys/bus/scsi/devices":
|
||||
f1 := &fakeFileInfo{
|
||||
name: "3:0:0:1",
|
||||
}
|
||||
f2 := &fakeFileInfo{
|
||||
name: "4:0:0:0",
|
||||
}
|
||||
f3 := &fakeFileInfo{
|
||||
name: diskPath,
|
||||
}
|
||||
f4 := &fakeFileInfo{
|
||||
name: "host1",
|
||||
}
|
||||
f5 := &fakeFileInfo{
|
||||
name: "target2:0:0",
|
||||
}
|
||||
return []os.FileInfo{f1, f2, f3, f4, f5}, nil
|
||||
case "/sys/bus/scsi/devices/" + diskPath + "/block":
|
||||
n := &fakeFileInfo{
|
||||
name: devName,
|
||||
}
|
||||
return []os.FileInfo{n}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("bad dir")
|
||||
}
|
||||
|
||||
func (handler *fakeIOHandler) WriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestIoHandler(t *testing.T) {
|
||||
var fcmd exec.FakeCmd
|
||||
fcmd = exec.FakeCmd{
|
||||
CombinedOutputScript: []exec.FakeCombinedOutputAction{
|
||||
// cat
|
||||
func() ([]byte, error) {
|
||||
return []byte("Msft \nVirtual Disk \n"), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
fake := exec.FakeExec{
|
||||
CommandScript: []exec.FakeCommandAction{
|
||||
func(cmd string, args ...string) exec.Cmd { return exec.InitFakeCmd(&fcmd, cmd, args...) },
|
||||
},
|
||||
}
|
||||
disk, err := findDiskByLun(lun, &fakeIOHandler{}, &fake)
|
||||
// if no disk matches lun, exit
|
||||
if disk != "/dev/"+devName || err != nil {
|
||||
t.Errorf("no data disk disk found: disk %v err %v", disk, err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue