Configurable mode and ownership via PVC annotations and provider wide defaults
This commit is contained in:
parent
59a3ca2cd1
commit
0f7a89aab9
12
README.md
12
README.md
|
|
@ -293,6 +293,18 @@ spec:
|
|||
storage: 1Mi
|
||||
```
|
||||
|
||||
**Step 8: Controlling the permissions and ownership of subdirs**
|
||||
|
||||
By default new directories will be created with `root:root` ownership, and `0777` permissions in most environments. If you have a need to control this, you can do so by providing the `NFS_DEFAULT_MODE`, `NFS_DEFAULT_UID` and `NFS_DEFAULT_GID` environment variables (or the appropriate configuration in the Helm chart values). The mode must be an octal representation of a file mode, for example `777`, `0755` etc. The uid and gid must be the numeric ids of your desired user and group, so `1000` not `my_user`.
|
||||
|
||||
If your usecase requires per-PVC ownership and/or mode, this can be done via annotations on your PVC:
|
||||
|
||||
- `k8s-sigs.io/nfs-directory-mode`
|
||||
- `k8s-sigs.io/nfs-directory-uid`
|
||||
- `k8s-sigs.io/nfs-directory-gid`
|
||||
|
||||
The order of precedence is PVC annotations, ENV vars, then root:root 0777 if nothing else has been specified.
|
||||
|
||||
# Build and publish your own container image
|
||||
|
||||
To build your own custom container image from this repository, you will have to build and push the nfs-subdir-external-provisioner image using the following instructions.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@ spec:
|
|||
value: {{ .Values.nfs.server }}
|
||||
- name: NFS_PATH
|
||||
value: {{ .Values.nfs.path }}
|
||||
- name: NFS_DEFAULT_MODE
|
||||
value: {{ .Values.nfs.defaultMode}}
|
||||
- name: NFS_DEFAULT_UID
|
||||
value: {{ .Values.nfs.defaultUid }}
|
||||
- name: NFS_DEFAULT_GID
|
||||
value: {{ .Values.nfs.defaultGid }}
|
||||
{{- if eq .Values.leaderElection.enabled false }}
|
||||
- name: ENABLE_LEADER_ELECTION
|
||||
value: "false"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ nfs:
|
|||
path: /nfs-storage
|
||||
mountOptions:
|
||||
volumeName: nfs-subdir-external-provisioner-root
|
||||
defaultMode: "777"
|
||||
defaultUid: "0"
|
||||
defaultGid: "0"
|
||||
# Reclaim policy for the main nfs volume
|
||||
reclaimPolicy: Retain
|
||||
|
||||
|
|
|
|||
|
|
@ -44,9 +44,12 @@ const (
|
|||
)
|
||||
|
||||
type nfsProvisioner struct {
|
||||
client kubernetes.Interface
|
||||
server string
|
||||
path string
|
||||
client kubernetes.Interface
|
||||
server string
|
||||
path string
|
||||
defaultMode os.FileMode
|
||||
defaultUid int
|
||||
defaultGid int
|
||||
}
|
||||
|
||||
type pvcMetadata struct {
|
||||
|
|
@ -74,7 +77,8 @@ func (meta *pvcMetadata) stringParser(str string) string {
|
|||
}
|
||||
|
||||
const (
|
||||
mountPath = "/persistentvolumes"
|
||||
mountPath = "/persistentvolumes"
|
||||
annotationPrefix = "k8s-sigs.io"
|
||||
)
|
||||
|
||||
var _ controller.Provisioner = &nfsProvisioner{}
|
||||
|
|
@ -111,15 +115,54 @@ func (p *nfsProvisioner) Provision(ctx context.Context, options controller.Provi
|
|||
}
|
||||
}
|
||||
|
||||
// Check if the PVC has an annotation requesting a specific mode. Fallback to defaults if not.
|
||||
mode := p.defaultMode
|
||||
pvcMode := metadata.annotations[annotationPrefix+"/nfs-directory-mode"]
|
||||
if pvcMode != "" {
|
||||
var err error
|
||||
mode, err = getModeFromString(pvcMode)
|
||||
if err != nil {
|
||||
return nil, controller.ProvisioningFinished, fmt.Errorf("invalid directoryMode %s: %v", pvcMode, err)
|
||||
}
|
||||
}
|
||||
glog.V(4).Infof("creating path %s", fullPath)
|
||||
if err := os.MkdirAll(fullPath, 0o777); err != nil {
|
||||
if err := os.MkdirAll(fullPath, mode); err != nil {
|
||||
return nil, controller.ProvisioningFinished, errors.New("unable to create directory to provision new pv: " + err.Error())
|
||||
}
|
||||
err := os.Chmod(fullPath, 0o777)
|
||||
err := os.Chmod(fullPath, mode)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// Check if the PVC has an annotation requesting a specific UID and GID. Again, fallback to defaults if not.
|
||||
uid := p.defaultUid
|
||||
pvcUid := metadata.annotations[annotationPrefix+"/nfs-directory-uid"]
|
||||
if pvcUid != "" {
|
||||
var err error
|
||||
uid, err = getIdFromString(pvcUid)
|
||||
if err != nil {
|
||||
// No real point in returning an error here as the dir will have already been created as root:root
|
||||
// log the error and continue with the default uid
|
||||
glog.Errorf("invalid directoryUid %s: %v", pvcUid, err)
|
||||
uid = p.defaultUid
|
||||
}
|
||||
}
|
||||
gid := p.defaultGid
|
||||
pvcGid := metadata.annotations[annotationPrefix+"/nfs-directory-gid"]
|
||||
if pvcGid != "" {
|
||||
var err error
|
||||
gid, err = getIdFromString(pvcGid)
|
||||
if err != nil {
|
||||
// No real point in returning an error here as the dir will have already been created as root:root
|
||||
// log the error and continue with the default gid
|
||||
glog.Errorf("invalid directoryGid %s: %v", pvcGid, err)
|
||||
gid = p.defaultGid
|
||||
}
|
||||
}
|
||||
err = os.Chown(fullPath, uid, gid)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
pv := &v1.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: options.PVName,
|
||||
|
|
@ -205,6 +248,36 @@ func (p *nfsProvisioner) getClassForVolume(ctx context.Context, pv *v1.Persisten
|
|||
return class, nil
|
||||
}
|
||||
|
||||
func getModeFromString(mode string) (os.FileMode, error) {
|
||||
if mode == "" {
|
||||
return os.FileMode(0o777), nil // Default to 0777, per current behavior
|
||||
}
|
||||
var modeInt int64
|
||||
var err error
|
||||
modeInt, err = strconv.ParseInt(mode, 8, 64)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid mode %s: %v", mode, err)
|
||||
}
|
||||
if modeInt < 0 || modeInt > 0o777 {
|
||||
return 0, fmt.Errorf("mode must be between 0 and 0777, got %s", mode)
|
||||
}
|
||||
return os.FileMode(modeInt), nil
|
||||
}
|
||||
|
||||
func getIdFromString(id string) (int, error) {
|
||||
if id == "" {
|
||||
return 0, nil // Default to 0 aka root, per current behavior
|
||||
}
|
||||
idInt, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid id %s: %v", id, err)
|
||||
}
|
||||
if idInt < 0 || idInt > 65535 {
|
||||
return 0, fmt.Errorf("id must be between 0 and 65535, got %s", id)
|
||||
}
|
||||
return idInt, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
flag.Set("logtostderr", "true")
|
||||
|
|
@ -221,6 +294,19 @@ func main() {
|
|||
if provisionerName == "" {
|
||||
glog.Fatalf("environment variable %s is not set! Please set it.", provisionerNameKey)
|
||||
}
|
||||
// Get the default mode, uid, and gid from environment variables
|
||||
mode, err := getModeFromString(os.Getenv("NFS_DEFAULT_MODE"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to parse NFS_DEFAULT_MODE: %v", err)
|
||||
}
|
||||
uid, err := getIdFromString(os.Getenv("NFS_DEFAULT_UID"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to parse NFS_DEFAULT_UID: %v", err)
|
||||
}
|
||||
gid, err := getIdFromString(os.Getenv("NFS_DEFAULT_GID"))
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to parse NFS_DEFAULT_GID: %v", err)
|
||||
}
|
||||
kubeconfig := os.Getenv("KUBECONFIG")
|
||||
var config *rest.Config
|
||||
if kubeconfig != "" {
|
||||
|
|
@ -262,9 +348,12 @@ func main() {
|
|||
}
|
||||
|
||||
clientNFSProvisioner := &nfsProvisioner{
|
||||
client: clientset,
|
||||
server: server,
|
||||
path: path,
|
||||
client: clientset,
|
||||
server: server,
|
||||
path: path,
|
||||
defaultMode: mode,
|
||||
defaultUid: uid,
|
||||
defaultGid: gid,
|
||||
}
|
||||
// Start the provision controller which will dynamically provision efs NFS
|
||||
// PVs
|
||||
|
|
|
|||
Loading…
Reference in New Issue