Skip to content

Commit

Permalink
Flexvolume: Add support for multiple secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
chakri-nelluri committed Apr 15, 2016
1 parent 16e2e87 commit f53bc4e
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 31 deletions.
2 changes: 1 addition & 1 deletion api/swagger-spec/batch_v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -1516,7 +1516,7 @@
},
"secretRef": {
"$ref": "v1.LocalObjectReference",
"description": "Optional: SecretRef is reference to the authentication secret for User, default is empty."
"description": "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts."
},
"readOnly": {
"type": "boolean",
Expand Down
2 changes: 1 addition & 1 deletion api/swagger-spec/extensions_v1beta1.json
Original file line number Diff line number Diff line change
Expand Up @@ -6933,7 +6933,7 @@
},
"secretRef": {
"$ref": "v1.LocalObjectReference",
"description": "Optional: SecretRef is reference to the authentication secret for User, default is empty."
"description": "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts."
},
"readOnly": {
"type": "boolean",
Expand Down
2 changes: 1 addition & 1 deletion api/swagger-spec/v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -16373,7 +16373,7 @@
},
"secretRef": {
"$ref": "v1.LocalObjectReference",
"description": "Optional: SecretRef is reference to the authentication secret for User, default is empty."
"description": "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts."
},
"readOnly": {
"type": "boolean",
Expand Down
4 changes: 2 additions & 2 deletions docs/api-reference/batch/v1/definitions.html
Original file line number Diff line number Diff line change
Expand Up @@ -2617,7 +2617,7 @@ <h3 id="_v1_flexvolumesource">v1.FlexVolumeSource</h3>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">secretRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: SecretRef is reference to the authentication secret for User, default is empty.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.</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_localobjectreference">v1.LocalObjectReference</a></p></td>
<td class="tableblock halign-left valign-top"></td>
Expand Down Expand Up @@ -3882,7 +3882,7 @@ <h3 id="_any">any</h3>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-04-15 01:05:41 UTC
Last updated 2016-04-15 09:27:17 UTC
</div>
</div>
</body>
Expand Down
4 changes: 2 additions & 2 deletions docs/api-reference/extensions/v1beta1/definitions.html
Original file line number Diff line number Diff line change
Expand Up @@ -2373,7 +2373,7 @@ <h3 id="_v1_flexvolumesource">v1.FlexVolumeSource</h3>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">secretRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: SecretRef is reference to the authentication secret for User, default is empty.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.</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_localobjectreference">v1.LocalObjectReference</a></p></td>
<td class="tableblock halign-left valign-top"></td>
Expand Down Expand Up @@ -5872,7 +5872,7 @@ <h3 id="_any">any</h3>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-04-15 01:05:35 UTC
Last updated 2016-04-15 09:26:56 UTC
</div>
</div>
</body>
Expand Down
4 changes: 2 additions & 2 deletions docs/api-reference/v1/definitions.html
Original file line number Diff line number Diff line change
Expand Up @@ -2870,7 +2870,7 @@ <h3 id="_v1_flexvolumesource">v1.FlexVolumeSource</h3>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">secretRef</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: SecretRef is reference to the authentication secret for User, default is empty.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.</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_localobjectreference">v1.LocalObjectReference</a></p></td>
<td class="tableblock halign-left valign-top"></td>
Expand Down Expand Up @@ -7742,7 +7742,7 @@ <h3 id="_any">any</h3>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2016-04-15 01:05:27 UTC
Last updated 2016-04-15 09:26:34 UTC
</div>
</div>
</body>
Expand Down
50 changes: 45 additions & 5 deletions examples/flexvolume/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,62 @@ Driver will be invoked with 'Init' to initialize the driver. It will be invoked
### Driver invocation model:

Init:
\<driver executable\> init

```
<driver executable> init
```

Attach:
\<driver executable\> attach \<json options\>

```
<driver executable> attach <json options>
```

Detach:
\<driver executable\> detach \<mount device\>

```
<driver executable> detach <mount device>
```

Mount:
\<driver executable\> mount \<target mount dir\> \<mount device\> \<json options\>

```
<driver executable> mount <target mount dir> <mount device> <json options>
```

Unmount:
\<driver executable\> unmount \<mount dir\>

```
<driver executable> unmount <mount dir>
```

See lvm[lvm] for a quick example on how to write a simple flexvolume driver.

### Driver output:

Flexvolume expects the driver to reply with the status of the operation in the
following format.

```
{
"status": "<Success/Failure>",
"message": "<Reason for success/failure>",
"device": "<Path to the device attached. This field is valid only for attach calls>"
}
```

### Default Json options

In addition to the flags specified by the user in the Options field of the FlexVolumeSource, the following flags are also passed to the executable.

```
"kubernetes.io/fsType":"<FS type>",
"kubernetes.io/readwrite":"<rw>",
"kubernetes.io/secret/key1":"<secret1>"
...
"kubernetes.io/secret/keyN":"<secretN>"
```

### Example of Flexvolume

See nginx.yaml[nginx.yaml] for a quick example on how to use Flexvolume in a pod.
Expand Down
8 changes: 7 additions & 1 deletion examples/flexvolume/lvm
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# Notes:
# - Please install "jq" package before using this driver.
usage() {
err "Invalid usage. Usage: "
err "\t$0 init"
Expand Down Expand Up @@ -46,6 +48,10 @@ attach() {
SIZE=$(echo $1 | jq -r '.size')
VG=$(echo $1|jq -r '.volumegroup')

# LVM substitutes - with --
VOLUMEID= `echo $VOLUMEID|sed s/-/--/g`
VG=`echo $VG|sed s/-/--/g`

DMDEV="/dev/mapper/${VG}-${VOLUMEID}"
if [ ! -b "${DMDEV}" ]; then
err "{\"status\": \"Failure\", \"message\": \"Volume ${VOLUMEID} does not exist\"}"
Expand Down Expand Up @@ -77,7 +83,7 @@ domount() {

VOLFSTYPE=`blkid -o udev ${DMDEV} 2>/dev/null|grep "ID_FS_TYPE"|cut -d"=" -f2`
if [ "${VOLFSTYPE}" == "" ]; then
mkfs -t ${FSTYPE} ${DMDEV}
mkfs -t ${FSTYPE} ${DMDEV} >/dev/null 2>&1
if [ $? -ne 0 ]; then
err "{ \"status\": \"Failure\", \"message\": \"Failed to create fs ${FSTYPE} on device ${DMDEV}\"}"
exit 1
Expand Down
6 changes: 5 additions & 1 deletion pkg/api/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,11 @@ type FlexVolumeSource struct {
// Must be a filesystem type supported by the host operating system.
// Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script.
FSType string `json:"fsType,omitempty"`
// Optional: SecretRef is reference to the authentication secret for User, default is empty.
// Optional: SecretRef is reference to the secret object containing
// sensitive information to pass to the plugin scripts. This may be
// empty if no secret object is specified. If the secret object
// contains more than one secret, all secrets are passed to the plugin
// scripts.
SecretRef *LocalObjectReference `json:"secretRef,omitempty"`
// Optional: Defaults to false (read/write). ReadOnly here will force
// the ReadOnly setting in VolumeMounts.
Expand Down
6 changes: 5 additions & 1 deletion pkg/api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,11 @@ type FlexVolumeSource struct {
// Must be a filesystem type supported by the host operating system.
// Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script.
FSType string `json:"fsType,omitempty"`
// Optional: SecretRef is reference to the authentication secret for User, default is empty.
// Optional: SecretRef is reference to the secret object containing
// sensitive information to pass to the plugin scripts. This may be
// empty if no secret object is specified. If the secret object
// contains more than one secret, all secrets are passed to the plugin
// scripts.
SecretRef *LocalObjectReference `json:"secretRef,omitempty"`
// Optional: Defaults to false (read/write). ReadOnly here will force
// the ReadOnly setting in VolumeMounts.
Expand Down
2 changes: 1 addition & 1 deletion pkg/api/v1/types_swagger_doc_generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ var map_FlexVolumeSource = map[string]string{
"": "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.",
"driver": "Driver is the name of the driver to use for this volume.",
"fsType": "Filesystem type to mount. Must be a filesystem type supported by the host operating system. Ex. \"ext4\", \"xfs\", \"ntfs\". The default filesystem depends on FlexVolume script.",
"secretRef": "Optional: SecretRef is reference to the authentication secret for User, default is empty.",
"secretRef": "Optional: SecretRef is reference to the secret object containing sensitive information to pass to the plugin scripts. This may be empty if no secret object is specified. If the secret object contains more than one secret, all secrets are passed to the plugin scripts.",
"readOnly": "Optional: Defaults to false (read/write). ReadOnly here will force the ReadOnly setting in VolumeMounts.",
"options": "Optional: Extra command options if any.",
}
Expand Down
23 changes: 12 additions & 11 deletions pkg/volume/flexvolume/flexvolume.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package flexvolume

import (
"encoding/base64"
"fmt"
"io/ioutil"
"os"
Expand Down Expand Up @@ -103,7 +104,7 @@ func (plugin *flexVolumePlugin) getVolumeSource(spec *volume.Spec) *api.FlexVolu
// NewMounter is the mounter routine to build the volume.
func (plugin *flexVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ volume.VolumeOptions) (volume.Mounter, error) {
fv := plugin.getVolumeSource(spec)
secret := ""
secrets := make(map[string]string)
if fv.SecretRef != nil {
kubeClient := plugin.host.GetKubeClient()
if kubeClient == nil {
Expand All @@ -116,15 +117,15 @@ func (plugin *flexVolumePlugin) NewMounter(spec *volume.Spec, pod *api.Pod, _ vo
return nil, err
}
for name, data := range secretName.Data {
secret = string(data)
secrets[name] = base64.StdEncoding.EncodeToString(data)
glog.V(1).Infof("found flex volume secret info: %s", name)
}
}
return plugin.newMounterInternal(spec, pod, &flexVolumeUtil{}, plugin.host.GetMounter(), exec.New(), secret)
return plugin.newMounterInternal(spec, pod, &flexVolumeUtil{}, plugin.host.GetMounter(), exec.New(), secrets)
}

// newMounterInternal is the internal mounter routine to build the volume.
func (plugin *flexVolumePlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod, manager flexVolumeManager, mounter mount.Interface, runner exec.Interface, secret string) (volume.Mounter, error) {
func (plugin *flexVolumePlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod, manager flexVolumeManager, mounter mount.Interface, runner exec.Interface, secrets map[string]string) (volume.Mounter, error) {
source := plugin.getVolumeSource(spec)
return &flexVolumeMounter{
flexVolumeDisk: &flexVolumeDisk{
Expand All @@ -136,7 +137,7 @@ func (plugin *flexVolumePlugin) newMounterInternal(spec *volume.Spec, pod *api.P
execPath: plugin.getExecutable(),
mounter: mounter,
plugin: plugin,
secret: secret,
secrets: secrets,
},
fsType: source.FSType,
readOnly: source.ReadOnly,
Expand Down Expand Up @@ -186,8 +187,8 @@ type flexVolumeDisk struct {
// block device.
mounter mount.Interface
// secret for the volume.
secret string
plugin *flexVolumePlugin
secrets map[string]string
plugin *flexVolumePlugin
}

// FlexVolumeUnmounter is the disk that will be cleaned by this plugin.
Expand Down Expand Up @@ -275,8 +276,8 @@ func (f *flexVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
}

// Extract secret and pass it as options.
if f.secret != "" {
f.options[optionKeySecret] = f.secret
for name, secret := range f.secrets {
f.options[optionKeySecret+"/"+name] = secret
}

device, err := f.manager.attach(f)
Expand All @@ -301,8 +302,8 @@ func (f *flexVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
options = append(options, "rw")
}
// Extract secret and pass it as options.
if f.secret != "" {
options = append(options, "secret="+f.secret)
for name, secret := range f.secrets {
f.options[optionKeySecret+"/"+name] = secret
}

os.MkdirAll(dir, 0750)
Expand Down
8 changes: 6 additions & 2 deletions pkg/volume/flexvolume/flexvolume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package flexvolume

import (
"bytes"
"encoding/base64"
"fmt"
"os"
"path"
Expand Down Expand Up @@ -239,7 +240,9 @@ func doTestPluginAttachDetach(t *testing.T, spec *volume.Spec, tmpDir string) {
}
fake := &mount.FakeMounter{}
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
mounter, err := plugin.(*flexVolumePlugin).newMounterInternal(spec, pod, &flexVolumeUtil{}, fake, exec.New(), "")
secretMap := make(map[string]string)
secretMap["flexsecret"] = base64.StdEncoding.EncodeToString([]byte("foo"))
mounter, err := plugin.(*flexVolumePlugin).newMounterInternal(spec, pod, &flexVolumeUtil{}, fake, exec.New(), secretMap)
volumePath := mounter.GetPath()
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
Expand Down Expand Up @@ -318,7 +321,8 @@ func doTestPluginMountUnmount(t *testing.T, spec *volume.Spec, tmpDir string) {
}
fake := &mount.FakeMounter{}
pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
mounter, err := plugin.(*flexVolumePlugin).newMounterInternal(spec, pod, &flexVolumeUtil{}, fake, exec.New(), "")
// Use nil secret to test for nil secret case.
mounter, err := plugin.(*flexVolumePlugin).newMounterInternal(spec, pod, &flexVolumeUtil{}, fake, exec.New(), nil)
volumePath := mounter.GetPath()
if err != nil {
t.Errorf("Failed to make a new Mounter: %v", err)
Expand Down

0 comments on commit f53bc4e

Please sign in to comment.