mirror of https://github.com/k3s-io/k3s
support Azure File Service volume
Signed-off-by: Huamin Chen <hchen@redhat.com>pull/6/head
parent
242000d790
commit
d7e4b826b9
|
@ -14914,6 +14914,10 @@
|
|||
"$ref": "v1.FlexVolumeSource",
|
||||
"description": "FlexVolume represents a generic volume resource that is provisioned/attached using a exec based plugin. This is an alpha feature and may change in future."
|
||||
},
|
||||
"azureFile": {
|
||||
"$ref": "v1.AzureFileVolumeSource",
|
||||
"description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod."
|
||||
},
|
||||
"accessModes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
@ -15268,6 +15272,28 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureFileVolumeSource": {
|
||||
"id": "v1.AzureFileVolumeSource",
|
||||
"description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
"required": [
|
||||
"secretName",
|
||||
"shareName"
|
||||
],
|
||||
"properties": {
|
||||
"secretName": {
|
||||
"type": "string",
|
||||
"description": "the name of secret that contains Azure Storage Account Name and Key"
|
||||
},
|
||||
"shareName": {
|
||||
"type": "string",
|
||||
"description": "Share Name"
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.PersistentVolumeStatus": {
|
||||
"id": "v1.PersistentVolumeStatus",
|
||||
"description": "PersistentVolumeStatus is the current status of a persistent volume.",
|
||||
|
@ -15498,6 +15524,10 @@
|
|||
"fc": {
|
||||
"$ref": "v1.FCVolumeSource",
|
||||
"description": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod."
|
||||
},
|
||||
"azureFile": {
|
||||
"$ref": "v1.AzureFileVolumeSource",
|
||||
"description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4333,6 +4333,10 @@
|
|||
"fc": {
|
||||
"$ref": "v1.FCVolumeSource",
|
||||
"description": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod."
|
||||
},
|
||||
"azureFile": {
|
||||
"$ref": "v1.AzureFileVolumeSource",
|
||||
"description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -4779,6 +4783,28 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"v1.AzureFileVolumeSource": {
|
||||
"id": "v1.AzureFileVolumeSource",
|
||||
"description": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
"required": [
|
||||
"secretName",
|
||||
"shareName"
|
||||
],
|
||||
"properties": {
|
||||
"secretName": {
|
||||
"type": "string",
|
||||
"description": "the name of secret that contains Azure Storage Account Name and Key"
|
||||
},
|
||||
"shareName": {
|
||||
"type": "string",
|
||||
"description": "Share Name"
|
||||
},
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts."
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.Container": {
|
||||
"id": "v1.Container",
|
||||
"description": "A single application container that you want to run within a pod.",
|
||||
|
|
|
@ -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_file"
|
||||
"k8s.io/kubernetes/pkg/volume/cephfs"
|
||||
"k8s.io/kubernetes/pkg/volume/cinder"
|
||||
"k8s.io/kubernetes/pkg/volume/downwardapi"
|
||||
|
@ -78,7 +79,7 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
|
|||
allPlugins = append(allPlugins, fc.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, flocker.ProbeVolumePlugins()...)
|
||||
allPlugins = append(allPlugins, flexvolume.ProbeVolumePlugins(pluginDir)...)
|
||||
|
||||
allPlugins = append(allPlugins, azure_file.ProbeVolumePlugins()...)
|
||||
return allPlugins
|
||||
}
|
||||
|
||||
|
|
|
@ -2364,6 +2364,54 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azurefilevolumesource">v1.AzureFileVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>AzureFile represents an Azure File Service 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">secretName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">the name of secret that contains Azure Storage Account Name and Key</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">shareName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Share Name</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">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_hostpathvolumesource">v1.HostPathVolumeSource</h3>
|
||||
|
@ -3668,6 +3716,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_fcvolumesource">v1.FCVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">azureFile</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureFile represents an Azure File Service 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_azurefilevolumesource">v1.AzureFileVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -4772,7 +4827,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-02-08 13:55:53 UTC
|
||||
Last updated 2016-02-09 01:06:27 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -1891,6 +1891,54 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
|
|||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_v1_azurefilevolumesource">v1.AzureFileVolumeSource</h3>
|
||||
<div class="paragraph">
|
||||
<p>AzureFile represents an Azure File Service 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">secretName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">the name of secret that contains Azure Storage Account Name and Key</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">shareName</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">Share Name</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">true</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">string</p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">readOnly</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">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_iscsivolumesource">v1.ISCSIVolumeSource</h3>
|
||||
|
@ -3235,6 +3283,13 @@ The resulting set of endpoints can be viewed as:<br>
|
|||
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_fcvolumesource">v1.FCVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">azureFile</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureFile represents an Azure File Service 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_azurefilevolumesource">v1.AzureFileVolumeSource</a></p></td>
|
||||
<td class="tableblock halign-left valign-top"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -5180,6 +5235,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">azureFile</p></td>
|
||||
<td class="tableblock halign-left valign-top"><p class="tableblock">AzureFile represents an Azure File Service 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_azurefilevolumesource">v1.AzureFileVolumeSource</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>
|
||||
|
@ -7316,7 +7378,7 @@ The resulting set of endpoints can be viewed as:<br>
|
|||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2016-02-02 15:03:04 UTC
|
||||
Last updated 2016-02-08 13:47:29 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -67,6 +67,7 @@ Familiarity with [pods](pods.md) is suggested.
|
|||
- [persistentVolumeClaim](#persistentvolumeclaim)
|
||||
- [downwardAPI](#downwardapi)
|
||||
- [FlexVolume](#flexvolume)
|
||||
- [AzureFileVolume](#azurefilevolume)
|
||||
- [Resources](#resources)
|
||||
|
||||
<!-- END MUNGE: GENERATED_TOC -->
|
||||
|
@ -124,6 +125,7 @@ Kubernetes supports several types of Volumes:
|
|||
* `secret`
|
||||
* `persistentVolumeClaim`
|
||||
* `downwardAPI`
|
||||
* `azureFileVolume`
|
||||
|
||||
We welcome additional contributions.
|
||||
|
||||
|
@ -427,6 +429,13 @@ an alpha feature and may change in future.
|
|||
|
||||
More details are in [here](../../examples/flexvolume/README.md)
|
||||
|
||||
### AzureFileVolume
|
||||
|
||||
A `AzureFileVolume` is used to mount a Microsoft Azure File Volume (SMB 2.1 and 3.0)
|
||||
into a Pod.
|
||||
|
||||
More details can be found [here](../../examples/azure_file/README.md)
|
||||
|
||||
## Resources
|
||||
|
||||
The storage media (Disk, SSD, etc) of an `emptyDir` volume is determined by the
|
||||
|
@ -440,7 +449,6 @@ request a certain amount of space using a [resource](compute-resources.md)
|
|||
specification, and to select the type of media to use, for clusters that have
|
||||
several media types.
|
||||
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/volumes.md?pixel)]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<!-- BEGIN MUNGE: UNVERSIONED_WARNING -->
|
||||
|
||||
<!-- BEGIN STRIP_FOR_RELEASE -->
|
||||
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/img/warning.png" alt="WARNING"
|
||||
width="25" height="25">
|
||||
<img src="http://kubernetes.io/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?
|
||||
|
||||
Install *cifs-utils* on the Kubernetes host. For example, on Fedora based Linux
|
||||
|
||||
# yum -y install cifs-utils
|
||||
|
||||
Note, as explained in [Azure File Storage for Linux](https://azure.microsoft.com/en-us/documentation/articles/storage-how-to-use-files-linux/), the Linux hosts and the file share must be in the same Azure region.
|
||||
|
||||
Obtain an Microsoft Azure storage account and create a [secret](secret/azure-secret.yaml) that contains the base64 encoded Azure Storage account name and key. In the secret file, base64-encode Azure Storage account name and pair it with name *azurestorageaccountname*, and base64-encode Azure Storage access key and pair it with name *azurestorageaccountkey*.
|
||||
|
||||
Then create a Pod using the volume spec based on [azure](azure.yaml).
|
||||
|
||||
In the pod, you need to provide the following information:
|
||||
|
||||
- *secretName*: the name of the secret that contains both Azure storage account name and key.
|
||||
- *shareName*: The share name to be used.
|
||||
- *readOnly*: Whether the filesystem is used as readOnly.
|
||||
|
||||
Create the secret:
|
||||
|
||||
```console
|
||||
# kubectl create -f examples/azure_file/secret/azure-secret.yaml
|
||||
```
|
||||
|
||||
You should see the account name and key from `kubectl get secret`
|
||||
|
||||
Then create the Pod:
|
||||
|
||||
```console
|
||||
# kubectl create -f examples/azure_file/azure.yaml
|
||||
```
|
||||
|
||||
<!-- BEGIN MUNGE: GENERATED_ANALYTICS -->
|
||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/examples/azure_file/README.md?pixel)]()
|
||||
<!-- END MUNGE: GENERATED_ANALYTICS -->
|
|
@ -0,0 +1,17 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: azure
|
||||
spec:
|
||||
containers:
|
||||
- image: kubernetes/pause
|
||||
name: azure
|
||||
volumeMounts:
|
||||
- name: azure
|
||||
mountPath: /mnt/azure
|
||||
volumes:
|
||||
- name: azure
|
||||
azureFile:
|
||||
secretName: azure-secret
|
||||
shareName: k8stest
|
||||
readOnly: false
|
|
@ -0,0 +1,8 @@
|
|||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: azure-secret
|
||||
type: Opaque
|
||||
data:
|
||||
azurestorageaccountname: azhzdGVzdA==
|
||||
azurestorageaccountkey: eElGMXpKYm5ub2pGTE1Ta0JwNTBteDAyckhzTUsyc2pVN21GdDRMMTNob0I3ZHJBYUo4akQ2K0E0NDNqSm9nVjd5MkZVT2hRQ1dQbU02WWFOSHk3cWc9PQ==
|
|
@ -402,6 +402,9 @@ func TestExampleObjectSchemas(t *testing.T) {
|
|||
"redis-service": &api.Service{},
|
||||
"job": &extensions.Job{},
|
||||
},
|
||||
"../examples/azure_file": {
|
||||
"azure": &api.Pod{},
|
||||
},
|
||||
}
|
||||
|
||||
capabilities.SetForTests(capabilities.Capabilities{
|
||||
|
|
|
@ -33,6 +33,7 @@ func init() {
|
|||
if err := Scheme.AddGeneratedDeepCopyFuncs(
|
||||
DeepCopy_api_AWSElasticBlockStoreVolumeSource,
|
||||
DeepCopy_api_Affinity,
|
||||
DeepCopy_api_AzureFileVolumeSource,
|
||||
DeepCopy_api_Binding,
|
||||
DeepCopy_api_Capabilities,
|
||||
DeepCopy_api_CephFSVolumeSource,
|
||||
|
@ -203,6 +204,13 @@ func DeepCopy_api_Affinity(in Affinity, out *Affinity, c *conversion.Cloner) err
|
|||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_AzureFileVolumeSource(in AzureFileVolumeSource, out *AzureFileVolumeSource, c *conversion.Cloner) error {
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeepCopy_api_Binding(in Binding, out *Binding, c *conversion.Cloner) error {
|
||||
if err := DeepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
|
@ -1828,6 +1836,15 @@ func DeepCopy_api_PersistentVolumeSource(in PersistentVolumeSource, out *Persist
|
|||
} else {
|
||||
out.Flocker = nil
|
||||
}
|
||||
if in.AzureFile != nil {
|
||||
in, out := in.AzureFile, &out.AzureFile
|
||||
*out = new(AzureFileVolumeSource)
|
||||
if err := DeepCopy_api_AzureFileVolumeSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2912,6 +2929,15 @@ func DeepCopy_api_VolumeSource(in VolumeSource, out *VolumeSource, c *conversion
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
if in.AzureFile != nil {
|
||||
in, out := in.AzureFile, &out.AzureFile
|
||||
*out = new(AzureFileVolumeSource)
|
||||
if err := DeepCopy_api_AzureFileVolumeSource(*in, *out, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -215,6 +215,8 @@ type VolumeSource struct {
|
|||
DownwardAPI *DownwardAPIVolumeSource `json:"downwardAPI,omitempty"`
|
||||
// FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||
FC *FCVolumeSource `json:"fc,omitempty"`
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
AzureFile *AzureFileVolumeSource `json:"azureFile,omitempty"`
|
||||
}
|
||||
|
||||
// Similar to VolumeSource but meant for the administrator who creates PVs.
|
||||
|
@ -251,6 +253,8 @@ type PersistentVolumeSource struct {
|
|||
FC *FCVolumeSource `json:"fc,omitempty"`
|
||||
// Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running
|
||||
Flocker *FlockerVolumeSource `json:"flocker,omitempty"`
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
AzureFile *AzureFileVolumeSource `json:"azureFile,omitempty"`
|
||||
}
|
||||
|
||||
type PersistentVolumeClaimVolumeSource struct {
|
||||
|
@ -672,6 +676,17 @@ type DownwardAPIVolumeFile struct {
|
|||
FieldRef ObjectFieldSelector `json:"fieldRef"`
|
||||
}
|
||||
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
type AzureFileVolumeSource struct {
|
||||
// the name of secret that contains Azure Storage Account Name and Key
|
||||
SecretName string `json:"secretName"`
|
||||
// Share Name
|
||||
ShareName string `json:"shareName"`
|
||||
// Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerPort represents a network port in a single container
|
||||
type ContainerPort struct {
|
||||
// Optional: If specified, this must be an IANA_SVC_NAME Each named port
|
||||
|
|
|
@ -43,6 +43,20 @@ func Convert_api_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolu
|
|||
return autoConvert_api_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in *api.AzureFileVolumeSource, out *AzureFileVolumeSource, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*api.AzureFileVolumeSource))(in)
|
||||
}
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in *api.AzureFileVolumeSource, out *AzureFileVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_Binding_To_v1_Binding(in *api.Binding, out *Binding, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*api.Binding))(in)
|
||||
|
@ -1970,6 +1984,15 @@ func autoConvert_api_PersistentVolumeSource_To_v1_PersistentVolumeSource(in *api
|
|||
} else {
|
||||
out.Flocker = nil
|
||||
}
|
||||
// unable to generate simple pointer conversion for api.AzureFileVolumeSource -> v1.AzureFileVolumeSource
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(AzureFileVolumeSource)
|
||||
if err := Convert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in.AzureFile, out.AzureFile, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -3196,6 +3219,15 @@ func autoConvert_api_VolumeSource_To_v1_VolumeSource(in *api.VolumeSource, out *
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
// unable to generate simple pointer conversion for api.AzureFileVolumeSource -> v1.AzureFileVolumeSource
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(AzureFileVolumeSource)
|
||||
if err := Convert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in.AzureFile, out.AzureFile, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -3231,6 +3263,20 @@ func Convert_v1_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolu
|
|||
return autoConvert_v1_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in *AzureFileVolumeSource, out *api.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*AzureFileVolumeSource))(in)
|
||||
}
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in *AzureFileVolumeSource, out *api.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Binding_To_api_Binding(in *Binding, out *api.Binding, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*Binding))(in)
|
||||
|
@ -5099,6 +5145,15 @@ func autoConvert_v1_PersistentVolumeSource_To_api_PersistentVolumeSource(in *Per
|
|||
} else {
|
||||
out.FlexVolume = nil
|
||||
}
|
||||
// unable to generate simple pointer conversion for v1.AzureFileVolumeSource -> api.AzureFileVolumeSource
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(api.AzureFileVolumeSource)
|
||||
if err := Convert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in.AzureFile, out.AzureFile, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -6274,6 +6329,15 @@ func autoConvert_v1_VolumeSource_To_api_VolumeSource(in *VolumeSource, out *api.
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
// unable to generate simple pointer conversion for v1.AzureFileVolumeSource -> api.AzureFileVolumeSource
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(api.AzureFileVolumeSource)
|
||||
if err := Convert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in.AzureFile, out.AzureFile, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -6284,6 +6348,7 @@ func Convert_v1_VolumeSource_To_api_VolumeSource(in *VolumeSource, out *api.Volu
|
|||
func init() {
|
||||
err := api.Scheme.AddGeneratedConversionFuncs(
|
||||
autoConvert_api_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource,
|
||||
autoConvert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource,
|
||||
autoConvert_api_Binding_To_v1_Binding,
|
||||
autoConvert_api_Capabilities_To_v1_Capabilities,
|
||||
autoConvert_api_CephFSVolumeSource_To_v1_CephFSVolumeSource,
|
||||
|
@ -6410,6 +6475,7 @@ func init() {
|
|||
autoConvert_api_Volume_To_v1_Volume,
|
||||
autoConvert_unversioned_ExportOptions_To_v1_ExportOptions,
|
||||
autoConvert_v1_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolumeSource,
|
||||
autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource,
|
||||
autoConvert_v1_Binding_To_api_Binding,
|
||||
autoConvert_v1_Capabilities_To_api_Capabilities,
|
||||
autoConvert_v1_CephFSVolumeSource_To_api_CephFSVolumeSource,
|
||||
|
|
|
@ -73,6 +73,13 @@ func deepCopy_v1_AWSElasticBlockStoreVolumeSource(in AWSElasticBlockStoreVolumeS
|
|||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_AzureFileVolumeSource(in AzureFileVolumeSource, out *AzureFileVolumeSource, c *conversion.Cloner) error {
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_Binding(in Binding, out *Binding, c *conversion.Cloner) error {
|
||||
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||
return err
|
||||
|
@ -1490,6 +1497,14 @@ func deepCopy_v1_PersistentVolumeSource(in PersistentVolumeSource, out *Persiste
|
|||
} else {
|
||||
out.FlexVolume = nil
|
||||
}
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(AzureFileVolumeSource)
|
||||
if err := deepCopy_v1_AzureFileVolumeSource(*in.AzureFile, out.AzureFile, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2514,6 +2529,14 @@ func deepCopy_v1_VolumeSource(in VolumeSource, out *VolumeSource, c *conversion.
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(AzureFileVolumeSource)
|
||||
if err := deepCopy_v1_AzureFileVolumeSource(*in.AzureFile, out.AzureFile, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -2550,6 +2573,7 @@ func init() {
|
|||
deepCopy_unversioned_Time,
|
||||
deepCopy_unversioned_TypeMeta,
|
||||
deepCopy_v1_AWSElasticBlockStoreVolumeSource,
|
||||
deepCopy_v1_AzureFileVolumeSource,
|
||||
deepCopy_v1_Binding,
|
||||
deepCopy_v1_Capabilities,
|
||||
deepCopy_v1_CephFSVolumeSource,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -261,6 +261,8 @@ type VolumeSource struct {
|
|||
DownwardAPI *DownwardAPIVolumeSource `json:"downwardAPI,omitempty"`
|
||||
// FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.
|
||||
FC *FCVolumeSource `json:"fc,omitempty"`
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
AzureFile *AzureFileVolumeSource `json:"azureFile,omitempty"`
|
||||
}
|
||||
|
||||
// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
|
||||
|
@ -319,6 +321,8 @@ type PersistentVolumeSource struct {
|
|||
// provisioned/attached using a exec based plugin. This is an
|
||||
// alpha feature and may change in future.
|
||||
FlexVolume *FlexVolumeSource `json:"flexVolume,omitempty"`
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
AzureFile *AzureFileVolumeSource `json:"azureFile,omitempty"`
|
||||
}
|
||||
|
||||
// PersistentVolume (PV) is a storage resource provisioned by an administrator.
|
||||
|
@ -791,6 +795,17 @@ type FCVolumeSource struct {
|
|||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
|
||||
type AzureFileVolumeSource struct {
|
||||
// the name of secret that contains Azure Storage Account Name and Key
|
||||
SecretName string `json:"secretName"`
|
||||
// Share Name
|
||||
ShareName string `json:"shareName"`
|
||||
// Defaults to false (read/write). ReadOnly here will force
|
||||
// the ReadOnly setting in VolumeMounts.
|
||||
ReadOnly bool `json:"readOnly,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerPort represents a network port in a single container.
|
||||
type ContainerPort struct {
|
||||
// If specified, this must be an IANA_SVC_NAME and unique within the pod. Each
|
||||
|
|
|
@ -48,6 +48,17 @@ func (Affinity) SwaggerDoc() map[string]string {
|
|||
return map_Affinity
|
||||
}
|
||||
|
||||
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",
|
||||
"shareName": "Share Name",
|
||||
"readOnly": "Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.",
|
||||
}
|
||||
|
||||
func (AzureFileVolumeSource) SwaggerDoc() map[string]string {
|
||||
return map_AzureFileVolumeSource
|
||||
}
|
||||
|
||||
var map_Binding = map[string]string{
|
||||
"": "Binding ties one object to another. For example, a pod is bound to a node by a scheduler.",
|
||||
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
|
||||
|
@ -990,6 +1001,7 @@ var map_PersistentVolumeSource = map[string]string{
|
|||
"fc": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.",
|
||||
"flocker": "Flocker represents a Flocker volume attached to a kubelet's host machine and exposed to the pod for its usage. This depends on the Flocker control service being running",
|
||||
"flexVolume": "FlexVolume represents a generic volume resource that is provisioned/attached using a exec based plugin. This is an alpha feature and may change in future.",
|
||||
"azureFile": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
}
|
||||
|
||||
func (PersistentVolumeSource) SwaggerDoc() map[string]string {
|
||||
|
@ -1541,6 +1553,7 @@ var map_VolumeSource = map[string]string{
|
|||
"flocker": "Flocker represents a Flocker volume attached to a kubelet's host machine. This depends on the Flocker control service being running",
|
||||
"downwardAPI": "DownwardAPI represents downward API about the pod that should populate this volume",
|
||||
"fc": "FC represents a Fibre Channel resource that is attached to a kubelet's host machine and then exposed to the pod.",
|
||||
"azureFile": "AzureFile represents an Azure File Service mount on the host and bind mount to the pod.",
|
||||
}
|
||||
|
||||
func (VolumeSource) SwaggerDoc() map[string]string {
|
||||
|
|
|
@ -494,6 +494,10 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E
|
|||
numVolumes++
|
||||
allErrs = append(allErrs, validateFlexVolumeSource(source.FlexVolume, fldPath.Child("flexVolume"))...)
|
||||
}
|
||||
if source.AzureFile != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureFile(source.AzureFile, fldPath.Child("azureFile"))...)
|
||||
}
|
||||
if numVolumes == 0 {
|
||||
allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
|
||||
}
|
||||
|
@ -718,6 +722,17 @@ func validateFlexVolumeSource(fv *api.FlexVolumeSource, fldPath *field.Path) fie
|
|||
return allErrs
|
||||
}
|
||||
|
||||
func validateAzureFile(azure *api.AzureFileVolumeSource, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
if azure.SecretName == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("secretName"), ""))
|
||||
}
|
||||
if azure.ShareName == "" {
|
||||
allErrs = append(allErrs, field.Required(fldPath.Child("shareName"), ""))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
func ValidatePersistentVolumeName(name string, prefix bool) (bool, string) {
|
||||
return NameIsDNSSubdomain(name, prefix)
|
||||
}
|
||||
|
@ -842,6 +857,10 @@ func ValidatePersistentVolume(pv *api.PersistentVolume) field.ErrorList {
|
|||
numVolumes++
|
||||
allErrs = append(allErrs, validateFlexVolumeSource(pv.Spec.FlexVolume, specPath.Child("flexVolume"))...)
|
||||
}
|
||||
if pv.Spec.AzureFile != nil {
|
||||
numVolumes++
|
||||
allErrs = append(allErrs, validateAzureFile(pv.Spec.AzureFile, specPath.Child("azureFile"))...)
|
||||
}
|
||||
if numVolumes == 0 {
|
||||
allErrs = append(allErrs, field.Required(specPath, "must specify a volume type"))
|
||||
}
|
||||
|
|
|
@ -509,6 +509,7 @@ func TestValidateVolumes(t *testing.T) {
|
|||
}}}},
|
||||
{Name: "fc", VolumeSource: api.VolumeSource{FC: &api.FCVolumeSource{[]string{"some_wwn"}, &lun, "ext4", false}}},
|
||||
{Name: "flexvolume", VolumeSource: api.VolumeSource{FlexVolume: &api.FlexVolumeSource{Driver: "kubernetes.io/blue", FSType: "ext4"}}},
|
||||
{Name: "azure", VolumeSource: api.VolumeSource{AzureFile: &api.AzureFileVolumeSource{"key", "share", false}}},
|
||||
}
|
||||
names, errs := validateVolumes(successCase, field.NewPath("field"))
|
||||
if len(errs) != 0 {
|
||||
|
@ -557,6 +558,8 @@ func TestValidateVolumes(t *testing.T) {
|
|||
zeroWWN := api.VolumeSource{FC: &api.FCVolumeSource{[]string{}, &lun, "ext4", false}}
|
||||
emptyLun := api.VolumeSource{FC: &api.FCVolumeSource{[]string{"wwn"}, nil, "ext4", false}}
|
||||
slashInName := api.VolumeSource{Flocker: &api.FlockerVolumeSource{DatasetName: "foo/bar"}}
|
||||
emptyAzureSecret := api.VolumeSource{AzureFile: &api.AzureFileVolumeSource{"", "share", false}}
|
||||
emptyAzureShare := api.VolumeSource{AzureFile: &api.AzureFileVolumeSource{"name", "", false}}
|
||||
errorCases := map[string]struct {
|
||||
V []api.Volume
|
||||
T field.ErrorType
|
||||
|
@ -678,6 +681,16 @@ func TestValidateVolumes(t *testing.T) {
|
|||
field.ErrorTypeInvalid,
|
||||
"gitRepo.directory", "",
|
||||
},
|
||||
"empty secret": {
|
||||
[]api.Volume{{Name: "emptyaccount", VolumeSource: emptyAzureSecret}},
|
||||
field.ErrorTypeRequired,
|
||||
"azureFile.secretName", "",
|
||||
},
|
||||
"empty share": {
|
||||
[]api.Volume{{Name: "emptyaccount", VolumeSource: emptyAzureShare}},
|
||||
field.ErrorTypeRequired,
|
||||
"azureFile.shareName", "",
|
||||
},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
_, errs := validateVolumes(v.V, field.NewPath("field"))
|
||||
|
|
|
@ -44,6 +44,20 @@ func Convert_api_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolu
|
|||
return autoConvert_api_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in *api.AzureFileVolumeSource, out *v1.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*api.AzureFileVolumeSource))(in)
|
||||
}
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in *api.AzureFileVolumeSource, out *v1.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_api_Capabilities_To_v1_Capabilities(in *api.Capabilities, out *v1.Capabilities, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*api.Capabilities))(in)
|
||||
|
@ -1257,6 +1271,15 @@ func autoConvert_api_VolumeSource_To_v1_VolumeSource(in *api.VolumeSource, out *
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
// unable to generate simple pointer conversion for api.AzureFileVolumeSource -> v1.AzureFileVolumeSource
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(v1.AzureFileVolumeSource)
|
||||
if err := Convert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource(in.AzureFile, out.AzureFile, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1329,6 +1352,20 @@ func Convert_v1_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolu
|
|||
return autoConvert_v1_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in *v1.AzureFileVolumeSource, out *api.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*v1.AzureFileVolumeSource))(in)
|
||||
}
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in *v1.AzureFileVolumeSource, out *api.AzureFileVolumeSource, s conversion.Scope) error {
|
||||
return autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1_Capabilities_To_api_Capabilities(in *v1.Capabilities, out *api.Capabilities, s conversion.Scope) error {
|
||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||
defaulting.(func(*v1.Capabilities))(in)
|
||||
|
@ -2518,6 +2555,15 @@ func autoConvert_v1_VolumeSource_To_api_VolumeSource(in *v1.VolumeSource, out *a
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
// unable to generate simple pointer conversion for v1.AzureFileVolumeSource -> api.AzureFileVolumeSource
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(api.AzureFileVolumeSource)
|
||||
if err := Convert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource(in.AzureFile, out.AzureFile, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -5213,6 +5259,7 @@ func Convert_v1beta1_ThirdPartyResourceList_To_extensions_ThirdPartyResourceList
|
|||
func init() {
|
||||
err := api.Scheme.AddGeneratedConversionFuncs(
|
||||
autoConvert_api_AWSElasticBlockStoreVolumeSource_To_v1_AWSElasticBlockStoreVolumeSource,
|
||||
autoConvert_api_AzureFileVolumeSource_To_v1_AzureFileVolumeSource,
|
||||
autoConvert_api_Capabilities_To_v1_Capabilities,
|
||||
autoConvert_api_CephFSVolumeSource_To_v1_CephFSVolumeSource,
|
||||
autoConvert_api_CinderVolumeSource_To_v1_CinderVolumeSource,
|
||||
|
@ -5320,6 +5367,7 @@ func init() {
|
|||
autoConvert_unversioned_LabelSelectorRequirement_To_v1beta1_LabelSelectorRequirement,
|
||||
autoConvert_unversioned_LabelSelector_To_v1beta1_LabelSelector,
|
||||
autoConvert_v1_AWSElasticBlockStoreVolumeSource_To_api_AWSElasticBlockStoreVolumeSource,
|
||||
autoConvert_v1_AzureFileVolumeSource_To_api_AzureFileVolumeSource,
|
||||
autoConvert_v1_Capabilities_To_api_Capabilities,
|
||||
autoConvert_v1_CephFSVolumeSource_To_api_CephFSVolumeSource,
|
||||
autoConvert_v1_CinderVolumeSource_To_api_CinderVolumeSource,
|
||||
|
|
|
@ -73,6 +73,13 @@ func deepCopy_v1_AWSElasticBlockStoreVolumeSource(in v1.AWSElasticBlockStoreVolu
|
|||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_AzureFileVolumeSource(in v1.AzureFileVolumeSource, out *v1.AzureFileVolumeSource, c *conversion.Cloner) error {
|
||||
out.SecretName = in.SecretName
|
||||
out.ShareName = in.ShareName
|
||||
out.ReadOnly = in.ReadOnly
|
||||
return nil
|
||||
}
|
||||
|
||||
func deepCopy_v1_Capabilities(in v1.Capabilities, out *v1.Capabilities, c *conversion.Cloner) error {
|
||||
if in.Add != nil {
|
||||
out.Add = make([]v1.Capability, len(in.Add))
|
||||
|
@ -964,6 +971,14 @@ func deepCopy_v1_VolumeSource(in v1.VolumeSource, out *v1.VolumeSource, c *conve
|
|||
} else {
|
||||
out.FC = nil
|
||||
}
|
||||
if in.AzureFile != nil {
|
||||
out.AzureFile = new(v1.AzureFileVolumeSource)
|
||||
if err := deepCopy_v1_AzureFileVolumeSource(*in.AzureFile, out.AzureFile, c); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AzureFile = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1981,6 +1996,7 @@ func init() {
|
|||
deepCopy_unversioned_Time,
|
||||
deepCopy_unversioned_TypeMeta,
|
||||
deepCopy_v1_AWSElasticBlockStoreVolumeSource,
|
||||
deepCopy_v1_AzureFileVolumeSource,
|
||||
deepCopy_v1_Capabilities,
|
||||
deepCopy_v1_CephFSVolumeSource,
|
||||
deepCopy_v1_CinderVolumeSource,
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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_file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/util/strings"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// This is the primary entrypoint for volume plugins.
|
||||
func ProbeVolumePlugins() []volume.VolumePlugin {
|
||||
return []volume.VolumePlugin{&azureFilePlugin{nil}}
|
||||
}
|
||||
|
||||
type azureFilePlugin struct {
|
||||
host volume.VolumeHost
|
||||
}
|
||||
|
||||
var _ volume.VolumePlugin = &azureFilePlugin{}
|
||||
var _ volume.PersistentVolumePlugin = &azureFilePlugin{}
|
||||
|
||||
const (
|
||||
azureFilePluginName = "kubernetes.io/azure-file"
|
||||
)
|
||||
|
||||
func (plugin *azureFilePlugin) Init(host volume.VolumeHost) error {
|
||||
plugin.host = host
|
||||
return nil
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) Name() string {
|
||||
return azureFilePluginName
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) CanSupport(spec *volume.Spec) bool {
|
||||
//TODO: check if mount.cifs is there
|
||||
return (spec.PersistentVolume != nil && spec.PersistentVolume.Spec.AzureFile != nil) ||
|
||||
(spec.Volume != nil && spec.Volume.AzureFile != nil)
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) GetAccessModes() []api.PersistentVolumeAccessMode {
|
||||
return []api.PersistentVolumeAccessMode{
|
||||
api.ReadWriteOnce,
|
||||
api.ReadOnlyMany,
|
||||
api.ReadWriteMany,
|
||||
}
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) NewBuilder(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Builder, error) {
|
||||
return plugin.newBuilderInternal(spec, pod, &azureSvc{}, plugin.host.GetMounter())
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) newBuilderInternal(spec *volume.Spec, pod *api.Pod, util azureUtil, mounter mount.Interface) (volume.Builder, error) {
|
||||
var source *api.AzureFileVolumeSource
|
||||
var readOnly bool
|
||||
if spec.Volume != nil && spec.Volume.AzureFile != nil {
|
||||
source = spec.Volume.AzureFile
|
||||
readOnly = spec.Volume.AzureFile.ReadOnly
|
||||
} else {
|
||||
source = spec.PersistentVolume.Spec.AzureFile
|
||||
readOnly = spec.ReadOnly
|
||||
}
|
||||
return &azureFileBuilder{
|
||||
azureFile: &azureFile{
|
||||
volName: spec.Name(),
|
||||
mounter: mounter,
|
||||
pod: pod,
|
||||
plugin: plugin,
|
||||
},
|
||||
util: util,
|
||||
secretName: source.SecretName,
|
||||
shareName: source.ShareName,
|
||||
readOnly: readOnly,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) NewCleaner(volName string, podUID types.UID) (volume.Cleaner, error) {
|
||||
return plugin.newCleanerInternal(volName, podUID, plugin.host.GetMounter())
|
||||
}
|
||||
|
||||
func (plugin *azureFilePlugin) newCleanerInternal(volName string, podUID types.UID, mounter mount.Interface) (volume.Cleaner, error) {
|
||||
return &azureFileCleaner{&azureFile{
|
||||
volName: volName,
|
||||
mounter: mounter,
|
||||
pod: &api.Pod{ObjectMeta: api.ObjectMeta{UID: podUID}},
|
||||
plugin: plugin,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
// azureFile volumes represent mount of an AzureFile share.
|
||||
type azureFile struct {
|
||||
volName string
|
||||
pod *api.Pod
|
||||
mounter mount.Interface
|
||||
plugin *azureFilePlugin
|
||||
volume.MetricsNil
|
||||
}
|
||||
|
||||
func (azureFileVolume *azureFile) GetPath() string {
|
||||
name := azureFilePluginName
|
||||
return azureFileVolume.plugin.host.GetPodVolumeDir(azureFileVolume.pod.UID, strings.EscapeQualifiedNameForDisk(name), azureFileVolume.volName)
|
||||
}
|
||||
|
||||
type azureFileBuilder struct {
|
||||
*azureFile
|
||||
util azureUtil
|
||||
secretName string
|
||||
shareName string
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
var _ volume.Builder = &azureFileBuilder{}
|
||||
|
||||
func (b *azureFileBuilder) GetAttributes() volume.Attributes {
|
||||
return volume.Attributes{
|
||||
ReadOnly: b.readOnly,
|
||||
Managed: !b.readOnly,
|
||||
SupportsSELinux: false,
|
||||
}
|
||||
}
|
||||
|
||||
// SetUp attaches the disk and bind mounts to the volume path.
|
||||
func (b *azureFileBuilder) SetUp(fsGroup *int64) error {
|
||||
return b.SetUpAt(b.GetPath(), fsGroup)
|
||||
}
|
||||
|
||||
func (b *azureFileBuilder) SetUpAt(dir string, fsGroup *int64) error {
|
||||
notMnt, err := b.mounter.IsLikelyNotMountPoint(dir)
|
||||
glog.V(4).Infof("AzureFile mount set up: %s %v %v", dir, !notMnt, err)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if !notMnt {
|
||||
return nil
|
||||
}
|
||||
var accountKey, accountName string
|
||||
if accountName, accountKey, err = b.util.GetAzureCredentials(b.plugin.host, b.pod.Namespace, b.secretName, b.shareName); err != nil {
|
||||
return err
|
||||
}
|
||||
os.MkdirAll(dir, 0750)
|
||||
source := fmt.Sprintf("//%s.file.core.windows.net/%s", accountName, b.shareName)
|
||||
// parameters suggested by https://azure.microsoft.com/en-us/documentation/articles/storage-how-to-use-files-linux/
|
||||
options := []string{fmt.Sprintf("vers=3.0,username=%s,password=%s,dir_mode=0777,file_mode=0777", accountName, accountKey)}
|
||||
if b.readOnly {
|
||||
options = append(options, "ro")
|
||||
}
|
||||
err = b.mounter.Mount(source, dir, "cifs", 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
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ volume.Cleaner = &azureFileCleaner{}
|
||||
|
||||
type azureFileCleaner struct {
|
||||
*azureFile
|
||||
}
|
||||
|
||||
func (c *azureFileCleaner) TearDown() error {
|
||||
return c.TearDownAt(c.GetPath())
|
||||
}
|
||||
|
||||
func (c *azureFileCleaner) TearDownAt(dir string) error {
|
||||
notMnt, err := c.mounter.IsLikelyNotMountPoint(dir)
|
||||
if err != nil {
|
||||
glog.Errorf("Error checking IsLikelyNotMountPoint: %v", err)
|
||||
return err
|
||||
}
|
||||
if notMnt {
|
||||
return os.Remove(dir)
|
||||
}
|
||||
|
||||
if err := c.mounter.Unmount(dir); err != nil {
|
||||
glog.Errorf("Unmounting failed: %v", err)
|
||||
return err
|
||||
}
|
||||
notMnt, mntErr := c.mounter.IsLikelyNotMountPoint(dir)
|
||||
if mntErr != nil {
|
||||
glog.Errorf("IsLikelyNotMountPoint check failed: %v", mntErr)
|
||||
return mntErr
|
||||
}
|
||||
if notMnt {
|
||||
if err := os.Remove(dir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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_file
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/client/testing/fake"
|
||||
"k8s.io/kubernetes/pkg/types"
|
||||
"k8s.io/kubernetes/pkg/util/mount"
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
)
|
||||
|
||||
func TestCanSupport(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "azureFileTest")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
if plug.Name() != "kubernetes.io/azure-file" {
|
||||
t.Errorf("Wrong name: %s", plug.Name())
|
||||
}
|
||||
if !plug.CanSupport(&volume.Spec{Volume: &api.Volume{VolumeSource: api.VolumeSource{AzureFile: &api.AzureFileVolumeSource{}}}}) {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
if !plug.CanSupport(&volume.Spec{PersistentVolume: &api.PersistentVolume{Spec: api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{AzureFile: &api.AzureFileVolumeSource{}}}}}) {
|
||||
t.Errorf("Expected true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccessModes(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "azureFileTest")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))
|
||||
|
||||
plug, err := plugMgr.FindPersistentPluginByName("kubernetes.io/azure-file")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
if !contains(plug.GetAccessModes(), api.ReadWriteOnce) || !contains(plug.GetAccessModes(), api.ReadOnlyMany) || !contains(plug.GetAccessModes(), api.ReadWriteMany) {
|
||||
t.Errorf("Expected three AccessModeTypes: %s, %s, and %s", api.ReadWriteOnce, api.ReadOnlyMany, api.ReadWriteMany)
|
||||
}
|
||||
}
|
||||
|
||||
func contains(modes []api.PersistentVolumeAccessMode, mode api.PersistentVolumeAccessMode) bool {
|
||||
for _, m := range modes {
|
||||
if m == mode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "azurefileTest")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp dir: %v")
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
spec := &api.Volume{
|
||||
Name: "vol1",
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureFile: &api.AzureFileVolumeSource{
|
||||
SecretName: "secret",
|
||||
ShareName: "share",
|
||||
},
|
||||
},
|
||||
}
|
||||
fake := &mount.FakeMounter{}
|
||||
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
||||
builder, err := plug.(*azureFilePlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), pod, &fakeAzureSvc{}, fake)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Builder: %v", err)
|
||||
}
|
||||
if builder == nil {
|
||||
t.Errorf("Got a nil Builder")
|
||||
}
|
||||
volPath := path.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~azure-file/vol1")
|
||||
path := builder.GetPath()
|
||||
if path != volPath {
|
||||
t.Errorf("Got unexpected path: %s", path)
|
||||
}
|
||||
|
||||
if err := builder.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)
|
||||
}
|
||||
}
|
||||
|
||||
cleaner, err := plug.(*azureFilePlugin).newCleanerInternal("vol1", types.UID("poduid"), &mount.FakeMounter{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to make a new Cleaner: %v", err)
|
||||
}
|
||||
if cleaner == nil {
|
||||
t.Errorf("Got a nil Cleaner")
|
||||
}
|
||||
|
||||
if err := cleaner.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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPersistentClaimReadOnlyFlag(t *testing.T) {
|
||||
pv := &api.PersistentVolume{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "pvA",
|
||||
},
|
||||
Spec: api.PersistentVolumeSpec{
|
||||
PersistentVolumeSource: api.PersistentVolumeSource{
|
||||
AzureFile: &api.AzureFileVolumeSource{},
|
||||
},
|
||||
ClaimRef: &api.ObjectReference{
|
||||
Name: "claimA",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
claim := &api.PersistentVolumeClaim{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "claimA",
|
||||
Namespace: "nsA",
|
||||
},
|
||||
Spec: api.PersistentVolumeClaimSpec{
|
||||
VolumeName: "pvA",
|
||||
},
|
||||
Status: api.PersistentVolumeClaimStatus{
|
||||
Phase: api.ClaimBound,
|
||||
},
|
||||
}
|
||||
|
||||
client := fake.NewSimpleClientset(pv, claim)
|
||||
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/tmp/fake", client, nil))
|
||||
plug, _ := plugMgr.FindPluginByName(azureFilePluginName)
|
||||
|
||||
// readOnly bool is supplied by persistent-claim volume source when its builder creates other volumes
|
||||
spec := volume.NewSpecFromPersistentVolume(pv, true)
|
||||
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
||||
builder, _ := plug.NewBuilder(spec, pod, volume.VolumeOptions{})
|
||||
|
||||
if !builder.GetAttributes().ReadOnly {
|
||||
t.Errorf("Expected true for builder.IsReadOnly")
|
||||
}
|
||||
}
|
||||
|
||||
type fakeAzureSvc struct{}
|
||||
|
||||
func (s *fakeAzureSvc) GetAzureCredentials(host volume.VolumeHost, nameSpace, secretName, shareName string) (string, string, error) {
|
||||
return "name", "key", nil
|
||||
}
|
||||
|
||||
func TestBuilderAndCleanerTypeAssert(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir(os.TempDir(), "azurefileTest")
|
||||
if err != nil {
|
||||
t.Fatalf("can't make a temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
plugMgr := volume.VolumePluginMgr{}
|
||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))
|
||||
|
||||
plug, err := plugMgr.FindPluginByName("kubernetes.io/azure-file")
|
||||
if err != nil {
|
||||
t.Errorf("Can't find the plugin by name")
|
||||
}
|
||||
spec := &api.Volume{
|
||||
Name: "vol1",
|
||||
VolumeSource: api.VolumeSource{
|
||||
AzureFile: &api.AzureFileVolumeSource{
|
||||
SecretName: "secret",
|
||||
ShareName: "share",
|
||||
},
|
||||
},
|
||||
}
|
||||
fake := &mount.FakeMounter{}
|
||||
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
||||
builder, err := plug.(*azureFilePlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), pod, &fakeAzureSvc{}, fake)
|
||||
if _, ok := builder.(volume.Cleaner); ok {
|
||||
t.Errorf("Volume Builder can be type-assert to Cleaner")
|
||||
}
|
||||
|
||||
cleaner, err := plug.(*azureFilePlugin).newCleanerInternal("vol1", types.UID("poduid"), &mount.FakeMounter{})
|
||||
if _, ok := cleaner.(volume.Builder); ok {
|
||||
t.Errorf("Volume Cleaner can be type-assert to Builder")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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_file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/volume"
|
||||
)
|
||||
|
||||
// Abstract interface to azure file operations.
|
||||
type azureUtil interface {
|
||||
GetAzureCredentials(host volume.VolumeHost, nameSpace, secretName, shareName string) (string, string, error)
|
||||
}
|
||||
|
||||
type azureSvc struct{}
|
||||
|
||||
func (s *azureSvc) GetAzureCredentials(host volume.VolumeHost, nameSpace, secretName, shareName string) (string, string, error) {
|
||||
var accountKey, accountName string
|
||||
kubeClient := host.GetKubeClient()
|
||||
if kubeClient == nil {
|
||||
return "", "", fmt.Errorf("Cannot get kube client")
|
||||
}
|
||||
|
||||
keys, err := kubeClient.Core().Secrets(nameSpace).Get(secretName)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("Couldn't get secret %v/%v", nameSpace, secretName)
|
||||
}
|
||||
for name, data := range keys.Data {
|
||||
if name == "azurestorageaccountname" {
|
||||
accountName = string(data)
|
||||
}
|
||||
if name == "azurestorageaccountkey" {
|
||||
accountKey = string(data)
|
||||
}
|
||||
}
|
||||
if accountName == "" || accountKey == "" {
|
||||
return "", "", fmt.Errorf("Invalid %v/%v, couldn't extract azurestorageaccountname or azurestorageaccountkey", nameSpace, secretName)
|
||||
}
|
||||
return accountName, accountKey, nil
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors All rights reserved.
|
||||
|
||||
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_file contains the internal representation of
|
||||
// Azure File Service Volume
|
||||
package azure_file
|
Loading…
Reference in New Issue