Skip to content
Snippets Groups Projects
Commit 9f18bde6 authored by Dmitry Chirikov's avatar Dmitry Chirikov Committed by Derek Su
Browse files

Enable shared filesystem support

(cherry picked from commit 974c9db7)
parent 42952d54
Branches
Tags
No related merge requests found
...@@ -74,6 +74,7 @@ type NodePathMapData struct { ...@@ -74,6 +74,7 @@ type NodePathMapData struct {
type ConfigData struct { type ConfigData struct {
NodePathMap []*NodePathMapData `json:"nodePathMap,omitempty"` NodePathMap []*NodePathMapData `json:"nodePathMap,omitempty"`
CmdTimeoutSeconds int `json:"cmdTimeoutSeconds,omitempty"` CmdTimeoutSeconds int `json:"cmdTimeoutSeconds,omitempty"`
SharedFileSystemPath string `json:"sharedFileSystemPath,omitempty"`
} }
type NodePathMap struct { type NodePathMap struct {
...@@ -83,6 +84,7 @@ type NodePathMap struct { ...@@ -83,6 +84,7 @@ type NodePathMap struct {
type Config struct { type Config struct {
NodePathMap map[string]*NodePathMap NodePathMap map[string]*NodePathMap
CmdTimeoutSeconds int CmdTimeoutSeconds int
SharedFileSystemPath string
} }
func NewProvisioner(stopCh chan struct{}, kubeClient *clientset.Clientset, func NewProvisioner(stopCh chan struct{}, kubeClient *clientset.Clientset,
...@@ -170,6 +172,15 @@ func (p *LocalPathProvisioner) getRandomPathOnNode(node string) (string, error) ...@@ -170,6 +172,15 @@ func (p *LocalPathProvisioner) getRandomPathOnNode(node string) (string, error)
} }
c := p.config c := p.config
sharedFS, err := p.isSharedFilesystem()
if err != nil {
return "", err
}
if sharedFS {
// we are ignoring 'node' and returning shared FS path
return c.SharedFileSystemPath, nil
}
// we are working with local FS
npMap := c.NodePathMap[node] npMap := c.NodePathMap[node]
if npMap == nil { if npMap == nil {
npMap = c.NodePathMap[NodeDefaultNonListedNodes] npMap = c.NodePathMap[NodeDefaultNonListedNodes]
...@@ -189,8 +200,38 @@ func (p *LocalPathProvisioner) getRandomPathOnNode(node string) (string, error) ...@@ -189,8 +200,38 @@ func (p *LocalPathProvisioner) getRandomPathOnNode(node string) (string, error)
return path, nil return path, nil
} }
func (p *LocalPathProvisioner) isSharedFilesystem() (bool, error) {
p.configMutex.RLock()
defer p.configMutex.RUnlock()
if p.config == nil {
return false, fmt.Errorf("no valid config available")
}
c := p.config
if (c.SharedFileSystemPath != "") && (len(c.NodePathMap) != 0) {
return false, fmt.Errorf("both nodePathMap and sharedFileSystemPath are defined. Please make sure only one is in use")
}
if len(c.NodePathMap) != 0 {
return false, nil
}
if c.SharedFileSystemPath != "" {
return true, nil
}
return false, fmt.Errorf("both nodePathMap and sharedFileSystemPath are unconfigured")
}
func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v1.PersistentVolume, error) { func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v1.PersistentVolume, error) {
pvc := opts.PVC pvc := opts.PVC
node := opts.SelectedNode
sharedFS, err := p.isSharedFilesystem()
if err != nil {
return nil, err
}
if !sharedFS {
if pvc.Spec.Selector != nil { if pvc.Spec.Selector != nil {
return nil, fmt.Errorf("claim.Spec.Selector is not supported") return nil, fmt.Errorf("claim.Spec.Selector is not supported")
} }
...@@ -199,12 +240,17 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v ...@@ -199,12 +240,17 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v
return nil, fmt.Errorf("Only support ReadWriteOnce access mode") return nil, fmt.Errorf("Only support ReadWriteOnce access mode")
} }
} }
node := opts.SelectedNode if node == nil {
if opts.SelectedNode == nil {
return nil, fmt.Errorf("configuration error, no node was specified") return nil, fmt.Errorf("configuration error, no node was specified")
} }
}
basePath, err := p.getRandomPathOnNode(node.Name) nodeName := ""
if node != nil {
// This clause works only with sharedFS
nodeName = node.Name
}
basePath, err := p.getRandomPathOnNode(nodeName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -213,7 +259,11 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v ...@@ -213,7 +259,11 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v
folderName := strings.Join([]string{name, opts.PVC.Namespace, opts.PVC.Name}, "_") folderName := strings.Join([]string{name, opts.PVC.Namespace, opts.PVC.Name}, "_")
path := filepath.Join(basePath, folderName) path := filepath.Join(basePath, folderName)
logrus.Infof("Creating volume %v at %v:%v", name, node.Name, path) if nodeName == "" {
logrus.Infof("Creating volume %v at %v", name, path)
} else {
logrus.Infof("Creating volume %v at %v:%v", name, nodeName, path)
}
storage := pvc.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] storage := pvc.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)]
provisionCmd := []string{"/bin/sh", "/script/setup"} provisionCmd := []string{"/bin/sh", "/script/setup"}
...@@ -222,7 +272,7 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v ...@@ -222,7 +272,7 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v
Path: path, Path: path,
Mode: *pvc.Spec.VolumeMode, Mode: *pvc.Spec.VolumeMode,
SizeInBytes: storage.Value(), SizeInBytes: storage.Value(),
Node: node.Name, Node: nodeName,
}); err != nil { }); err != nil {
return nil, err return nil, err
} }
...@@ -246,24 +296,17 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v ...@@ -246,24 +296,17 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v
} }
} }
var nodeAffinity *v1.VolumeNodeAffinity
if sharedFS {
// If the same filesystem is mounted across all nodes, we don't need
// affinity, as path is accessible from any node
nodeAffinity = nil
} else {
valueNode, ok := node.GetLabels()[KeyNode] valueNode, ok := node.GetLabels()[KeyNode]
if !ok { if !ok {
valueNode = node.Name valueNode = nodeName
} }
nodeAffinity = &v1.VolumeNodeAffinity{
return &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: *opts.StorageClass.ReclaimPolicy,
AccessModes: pvc.Spec.AccessModes,
VolumeMode: &fs,
Capacity: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): pvc.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)],
},
PersistentVolumeSource: pvs,
NodeAffinity: &v1.VolumeNodeAffinity{
Required: &v1.NodeSelector{ Required: &v1.NodeSelector{
NodeSelectorTerms: []v1.NodeSelectorTerm{ NodeSelectorTerms: []v1.NodeSelectorTerm{
{ {
...@@ -279,7 +322,21 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v ...@@ -279,7 +322,21 @@ func (p *LocalPathProvisioner) Provision(opts pvController.ProvisionOptions) (*v
}, },
}, },
}, },
}
}
return &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
Spec: v1.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: *opts.StorageClass.ReclaimPolicy,
AccessModes: pvc.Spec.AccessModes,
VolumeMode: &fs,
Capacity: v1.ResourceList{
v1.ResourceName(v1.ResourceStorage): pvc.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)],
}, },
PersistentVolumeSource: pvs,
NodeAffinity: nodeAffinity,
}, },
}, nil }, nil
} }
...@@ -293,7 +350,11 @@ func (p *LocalPathProvisioner) Delete(pv *v1.PersistentVolume) (err error) { ...@@ -293,7 +350,11 @@ func (p *LocalPathProvisioner) Delete(pv *v1.PersistentVolume) (err error) {
return err return err
} }
if pv.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimRetain { if pv.Spec.PersistentVolumeReclaimPolicy != v1.PersistentVolumeReclaimRetain {
if node == "" {
logrus.Infof("Deleting volume %v at %v", pv.Name, path)
} else {
logrus.Infof("Deleting volume %v at %v:%v", pv.Name, node, path) logrus.Infof("Deleting volume %v at %v:%v", pv.Name, node, path)
}
storage := pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)] storage := pv.Spec.Capacity[v1.ResourceName(v1.ResourceStorage)]
cleanupCmd := []string{"/bin/sh", "/script/teardown"} cleanupCmd := []string{"/bin/sh", "/script/teardown"}
if err := p.createHelperPod(ActionTypeDelete, cleanupCmd, volumeOptions{ if err := p.createHelperPod(ActionTypeDelete, cleanupCmd, volumeOptions{
...@@ -326,6 +387,18 @@ func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume) (pat ...@@ -326,6 +387,18 @@ func (p *LocalPathProvisioner) getPathAndNodeForPV(pv *v1.PersistentVolume) (pat
return "", "", fmt.Errorf("no path set") return "", "", fmt.Errorf("no path set")
} }
sharedFS, err := p.isSharedFilesystem()
if err != nil {
return "", "", err
}
if sharedFS {
// We don't have affinity and can use any node
return path, "", nil
}
// Dealing with local filesystem
nodeAffinity := pv.Spec.NodeAffinity nodeAffinity := pv.Spec.NodeAffinity
if nodeAffinity == nil { if nodeAffinity == nil {
return "", "", fmt.Errorf("no NodeAffinity set") return "", "", fmt.Errorf("no NodeAffinity set")
...@@ -368,7 +441,11 @@ func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string, ...@@ -368,7 +441,11 @@ func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string,
defer func() { defer func() {
err = errors.Wrapf(err, "failed to %v volume %v", action, o.Name) err = errors.Wrapf(err, "failed to %v volume %v", action, o.Name)
}() }()
if o.Name == "" || o.Path == "" || o.Node == "" { sharedFS, err := p.isSharedFilesystem()
if err != nil {
return err
}
if o.Name == "" || o.Path == "" || (!sharedFS && o.Node == "") {
return fmt.Errorf("invalid empty name or path or node") return fmt.Errorf("invalid empty name or path or node")
} }
if !filepath.IsAbs(o.Path) { if !filepath.IsAbs(o.Path) {
...@@ -438,7 +515,9 @@ func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string, ...@@ -438,7 +515,9 @@ func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string,
helperPod.Name = helperPod.Name[:HelperPodNameMaxLength] helperPod.Name = helperPod.Name[:HelperPodNameMaxLength]
} }
helperPod.Namespace = p.namespace helperPod.Namespace = p.namespace
if o.Node != "" {
helperPod.Spec.NodeName = o.Node helperPod.Spec.NodeName = o.Node
}
helperPod.Spec.ServiceAccountName = p.serviceAccountName helperPod.Spec.ServiceAccountName = p.serviceAccountName
helperPod.Spec.RestartPolicy = v1.RestartPolicyNever helperPod.Spec.RestartPolicy = v1.RestartPolicyNever
helperPod.Spec.Tolerations = append(helperPod.Spec.Tolerations, lpvTolerations...) helperPod.Spec.Tolerations = append(helperPod.Spec.Tolerations, lpvTolerations...)
...@@ -478,7 +557,11 @@ func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string, ...@@ -478,7 +557,11 @@ func (p *LocalPathProvisioner) createHelperPod(action ActionType, cmd []string,
return fmt.Errorf("create process timeout after %v seconds", p.config.CmdTimeoutSeconds) return fmt.Errorf("create process timeout after %v seconds", p.config.CmdTimeoutSeconds)
} }
if o.Node == "" {
logrus.Infof("Volume %v has been %vd on %v", o.Name, action, o.Path)
} else {
logrus.Infof("Volume %v has been %vd on %v:%v", o.Name, action, o.Node, o.Path) logrus.Infof("Volume %v has been %vd on %v:%v", o.Name, action, o.Node, o.Path)
}
return nil return nil
} }
...@@ -534,6 +617,7 @@ func canonicalizeConfig(data *ConfigData) (cfg *Config, err error) { ...@@ -534,6 +617,7 @@ func canonicalizeConfig(data *ConfigData) (cfg *Config, err error) {
err = errors.Wrapf(err, "config canonicalization failed") err = errors.Wrapf(err, "config canonicalization failed")
}() }()
cfg = &Config{} cfg = &Config{}
cfg.SharedFileSystemPath = data.SharedFileSystemPath
cfg.NodePathMap = map[string]*NodePathMap{} cfg.NodePathMap = map[string]*NodePathMap{}
for _, n := range data.NodePathMap { for _, n := range data.NodePathMap {
if cfg.NodePathMap[n.Node] != nil { if cfg.NodePathMap[n.Node] != nil {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment