Commit 3544f8a7 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #29836 from rootfs/azuredd

Automatic merge from submit-queue support Azure data disk volume This is a WIP of supporting azure data disk volume. Will add test and dynamic provisioning support once #29006 is merged replace #25915 fix #23259 @kubernetes/sig-storage @colemickens @brendandburns
parents cfab3516 dea4b022
......@@ -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
}
......
......@@ -2965,6 +2965,68 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</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>
<div class="paragraph">
<p>Represents a vSphere volume resource.</p>
......@@ -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>
......@@ -4121,6 +4190,10 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div>
<div class="sect2">
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
</div>
<div class="sect2">
<h3 id="_v1_rbdvolumesource">v1.RBDVolumeSource</h3>
<div class="paragraph">
<p>Represents a Rados Block Device mount that lasts the lifetime of a pod. RBD volumes support ownership management and SELinux relabeling.</p>
......@@ -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>
......
......@@ -2791,6 +2791,68 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</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>
<div class="paragraph">
<p>Maps a string key to a path within a volume.</p>
......@@ -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>
......@@ -6599,6 +6668,10 @@ Both these may change in the future. Incoming requests are matched against the h
</div>
<div class="sect2">
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
</div>
<div class="sect2">
<h3 id="_any">any</h3>
<div class="paragraph">
<p>Represents an untyped JSON map - see the description of the field for more info about the structure of this object.</p>
......@@ -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>
......
......@@ -3160,6 +3160,68 @@ The resulting set of endpoints can be viewed as:<br>
</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>
<div class="paragraph">
<p>Maps a string key to a path within a volume.</p>
......@@ -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>
......@@ -8344,6 +8420,10 @@ The resulting set of endpoints can be viewed as:<br>
</div>
<div class="sect2">
<h3 id="_v1_azuredatadiskcachingmode">v1.AzureDataDiskCachingMode</h3>
</div>
<div class="sect2">
<h3 id="_any">any</h3>
<div class="paragraph">
<p>Represents an untyped JSON map - see the description of the field for more info about the structure of this object.</p>
......@@ -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{
......
<!-- 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 -->
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}
},
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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]
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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 = "*"
)
......
/*
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)
......
/*
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
}
}
/*
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)
}
}
/*
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)
}
}
/*
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)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment