jitendar-singh

Code Coverage

Mar 28th, 2022 (edited)
388
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 105.83 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html>
  3.     <head>
  4.         <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  5.         <title>cmd: Go Coverage Report</title>
  6.         <style>
  7.             body {
  8.                 background: black;
  9.                 color: rgb(80, 80, 80);
  10.             }
  11.             body, pre, #legend span {
  12.                 font-family: Menlo, monospace;
  13.                 font-weight: bold;
  14.             }
  15.             #topbar {
  16.                 background: black;
  17.                 position: fixed;
  18.                 top: 0; left: 0; right: 0;
  19.                 height: 42px;
  20.                 border-bottom: 1px solid rgb(80, 80, 80);
  21.             }
  22.             #content {
  23.                 margin-top: 50px;
  24.             }
  25.             #nav, #legend {
  26.                 float: left;
  27.                 margin-left: 10px;
  28.             }
  29.             #legend {
  30.                 margin-top: 12px;
  31.             }
  32.             #nav {
  33.                 margin-top: 10px;
  34.             }
  35.             #legend span {
  36.                 margin: 0 5px;
  37.             }
  38.             .cov0 { color: rgb(192, 0, 0) }
  39. .cov1 { color: rgb(128, 128, 128) }
  40. .cov2 { color: rgb(116, 140, 131) }
  41. .cov3 { color: rgb(104, 152, 134) }
  42. .cov4 { color: rgb(92, 164, 137) }
  43. .cov5 { color: rgb(80, 176, 140) }
  44. .cov6 { color: rgb(68, 188, 143) }
  45. .cov7 { color: rgb(56, 200, 146) }
  46. .cov8 { color: rgb(44, 212, 149) }
  47. .cov9 { color: rgb(32, 224, 152) }
  48. .cov10 { color: rgb(20, 236, 155) }
  49.  
  50.         </style>
  51.     </head>
  52.     <body>
  53.         <div id="topbar">
  54.             <div id="nav">
  55.                 <select id="files">
  56.                
  57.                 <option value="file0">github.com/openshift/csi-driver-shared-resource/cmd/main.go (11.5%)</option>
  58.                
  59.                 <option value="file1">github.com/openshift/csi-driver-shared-resource/pkg/config/config.go (100.0%)</option>
  60.                
  61.                 <option value="file2">github.com/openshift/csi-driver-shared-resource/pkg/config/manager.go (78.3%)</option>
  62.                
  63.                 <option value="file3">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/dpv.go (79.8%)</option>
  64.                
  65.                 <option value="file4">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/driver.go (69.0%)</option>
  66.                
  67.                 <option value="file5">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/file.go (0.0%)</option>
  68.                
  69.                 <option value="file6">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/identityserver.go (0.0%)</option>
  70.                
  71.                 <option value="file7">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/mount.go (42.9%)</option>
  72.                
  73.                 <option value="file8">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/nodeserver.go (67.9%)</option>
  74.                
  75.                 <option value="file9">github.com/openshift/csi-driver-shared-resource/pkg/csidriver/server.go (0.0%)</option>
  76.                
  77.                 <option value="file10">github.com/openshift/csi-driver-shared-resource/pkg/metrics/metrics.go (100.0%)</option>
  78.                
  79.                 <option value="file11">github.com/openshift/csi-driver-shared-resource/pkg/metrics/server.go (57.9%)</option>
  80.                
  81.                 </select>
  82.             </div>
  83.             <div id="legend">
  84.                 <span>not tracked</span>
  85.            
  86.                 <span class="cov0">not covered</span>
  87.                 <span class="cov8">covered</span>
  88.            
  89.             </div>
  90.         </div>
  91.         <div id="content">
  92.        
  93.         <pre class="file" id="file0" style="display: none">package main
  94.  
  95. import (
  96.         "flag"
  97.         "fmt"
  98.         "os"
  99.         "os/signal"
  100.         "syscall"
  101.         "time"
  102.  
  103.         "github.com/spf13/cobra"
  104.         "github.com/spf13/pflag"
  105.  
  106.         "k8s.io/client-go/kubernetes"
  107.         "k8s.io/klog/v2"
  108.         "k8s.io/utils/mount"
  109.  
  110.         sharev1clientset "github.com/openshift/client-go/sharedresource/clientset/versioned"
  111.         "github.com/openshift/csi-driver-shared-resource/pkg/cache"
  112.         "github.com/openshift/csi-driver-shared-resource/pkg/client"
  113.         "github.com/openshift/csi-driver-shared-resource/pkg/config"
  114.         "github.com/openshift/csi-driver-shared-resource/pkg/controller"
  115.         "github.com/openshift/csi-driver-shared-resource/pkg/csidriver"
  116.  
  117.         operatorv1 "github.com/openshift/api/operator/v1"
  118. )
  119.  
  120. var (
  121.         version string // driver version
  122.  
  123.         cfgFilePath       string // path to configuration file
  124.         endPoint          string // CSI driver API endpoint for Kubernetes kubelet
  125.         driverName        string // name of the CSI driver, registered in the cluster
  126.         nodeID            string // current Kubernetes node identifier
  127.         maxVolumesPerNode int64  // maximum amount of volumes per node, i.e. per driver instance
  128.  
  129.         shutdownSignals      = []os.Signal{os.Interrupt, syscall.SIGTERM}
  130.         onlyOneSignalHandler = make(chan struct{})
  131. )
  132.  
  133. var rootCmd = &amp;cobra.Command{
  134.         Use:     "csi-driver-shared-resource",
  135.         Version: "0.0.1",
  136.         Short:   "",
  137.         Long:    ``,
  138.         Run: func(cmd *cobra.Command, args []string) <span class="cov0" title="0">{
  139.                 var err error
  140.  
  141.                 cfgManager := config.NewManager(cfgFilePath)
  142.                 cfg, err := cfgManager.LoadConfig()
  143.                 if err != nil </span><span class="cov0" title="0">{
  144.                         fmt.Printf("Failed to load configuration file '%s': %s", cfgFilePath, err.Error())
  145.                         os.Exit(1)
  146.                 }</span>
  147.  
  148.                 <span class="cov0" title="0">if !cfg.RefreshResources </span><span class="cov0" title="0">{
  149.                         fmt.Println("Refresh-Resources disabled")
  150.  
  151.                 }</span>
  152.                 <span class="cov0" title="0">if kubeClient, err := loadKubernetesClientset(); err != nil </span><span class="cov0" title="0">{
  153.                         fmt.Printf("Failed to load Kubernetes API client: %s", err.Error())
  154.                         os.Exit(1)
  155.                 }</span> else<span class="cov0" title="0"> {
  156.                         client.SetClient(kubeClient)
  157.                 }</span>
  158.                 <span class="cov0" title="0">if shareClient, err := loadSharedresourceClientset(); err != nil </span><span class="cov0" title="0">{
  159.                         fmt.Printf("Failed to load SharedResource API client: %s", err.Error())
  160.                         os.Exit(1)
  161.                 }</span> else<span class="cov0" title="0"> {
  162.                         client.SetShareClient(shareClient)
  163.                 }</span>
  164.  
  165.                 <span class="cov0" title="0">driver, err := csidriver.NewCSIDriver(
  166.                         csidriver.DataRoot,
  167.                         csidriver.VolumeMapRoot,
  168.                         driverName,
  169.                         nodeID,
  170.                         endPoint,
  171.                         maxVolumesPerNode,
  172.                         version,
  173.                         mount.New(""),
  174.                 )
  175.                 if err != nil </span><span class="cov0" title="0">{
  176.                         fmt.Printf("Failed to initialize driver: %s", err.Error())
  177.                         os.Exit(1)
  178.                 }</span>
  179.  
  180.                 <span class="cov0" title="0">c, err := controller.NewController(cfg.GetShareRelistInterval(), cfg.RefreshResources)
  181.                 if err != nil </span><span class="cov0" title="0">{
  182.                         fmt.Printf("Failed to set up controller: %s", err.Error())
  183.                         os.Exit(1)
  184.                 }</span>
  185.                 <span class="cov0" title="0">prunerTicker := time.NewTicker(cfg.GetShareRelistInterval())
  186.                 prunerDone := make(chan struct{})
  187.                 go func() </span><span class="cov0" title="0">{
  188.                         for </span><span class="cov0" title="0">{
  189.                                 select </span>{
  190.                                 case &lt;-prunerDone:<span class="cov0" title="0">
  191.                                         return</span>
  192.                                 case &lt;-prunerTicker.C:<span class="cov0" title="0">
  193.                                         // remove any orphaned volume files on disk
  194.                                         driver.Prune(client.GetClient())
  195.                                         if cfg.RefreshResources </span><span class="cov0" title="0">{
  196.                                                 // in case we missed delete events, clean up unneeded secret/configmap informers
  197.                                                 c.PruneSecretInformers(cache.NamespacesWithSharedSecrets())
  198.                                                 c.PruneConfigMapInformers(cache.NamespacesWithSharedConfigMaps())
  199.                                         }</span>
  200.                                 }
  201.                         }
  202.                 }()
  203.  
  204.                 <span class="cov0" title="0">go runOperator(c, cfg)
  205.                 go watchForConfigChanges(cfgManager)
  206.                 driver.Run()
  207.                 prunerDone &lt;- struct{}{}</span>
  208.         },
  209. }
  210.  
  211. func main() <span class="cov0" title="0">{
  212.         if err := rootCmd.Execute(); err != nil </span><span class="cov0" title="0">{
  213.                 fmt.Println(err)
  214.                 os.Exit(1)
  215.         }</span>
  216. }
  217.  
  218. func init() <span class="cov8" title="1">{
  219.         klog.InitFlags(nil)
  220.         pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
  221.         cobra.OnInitialize()
  222.         rootCmd.Flags().AddGoFlagSet(flag.CommandLine)
  223.  
  224.         rootCmd.Flags().StringVar(&amp;cfgFilePath, "config", "/var/run/configmaps/config/config.yaml", "configuration file path")
  225.         rootCmd.Flags().StringVar(&amp;endPoint, "endpoint", "unix:///csi/csi.sock", "CSI endpoint")
  226.         rootCmd.Flags().StringVar(&amp;driverName, "drivername", string(operatorv1.SharedResourcesCSIDriver), "name of the driver")
  227.         rootCmd.Flags().StringVar(&amp;nodeID, "nodeid", "", "node id")
  228.         rootCmd.Flags().Int64Var(&amp;maxVolumesPerNode, "maxvolumespernode", 0, "limit of volumes per node")
  229. }</span>
  230.  
  231. // loadKubernetesClientset instantiate a clientset using local config.
  232. func loadKubernetesClientset() (kubernetes.Interface, error) <span class="cov0" title="0">{
  233.         kubeRestConfig, err := client.GetConfig()
  234.         if err != nil </span><span class="cov0" title="0">{
  235.                 return nil, err
  236.         }</span>
  237.         <span class="cov0" title="0">return kubernetes.NewForConfig(kubeRestConfig)</span>
  238. }
  239.  
  240. func loadSharedresourceClientset() (sharev1clientset.Interface, error) <span class="cov0" title="0">{
  241.         kubeRestConfig, err := client.GetConfig()
  242.         if err != nil </span><span class="cov0" title="0">{
  243.                 return nil, err
  244.         }</span>
  245.         <span class="cov0" title="0">return sharev1clientset.NewForConfig(kubeRestConfig)</span>
  246. }
  247.  
  248. // runOperator based on the informed configuration, it will spawn and run the Controller, until
  249. // trapping OS signals.
  250. func runOperator(c *controller.Controller, cfg *config.Config) <span class="cov0" title="0">{
  251.         stopCh := setupSignalHandler()
  252.         err := c.Run(stopCh)
  253.         if err != nil </span><span class="cov0" title="0">{
  254.                 fmt.Printf("Controller exited: %s", err.Error())
  255.                 os.Exit(1)
  256.         }</span>
  257. }
  258.  
  259. // watchForConfigChanges keeps checking if the informed configuration has changed, and in this case
  260. // makes the operator exit. The new configuration should take place upon new instance started.
  261. func watchForConfigChanges(mgr *config.Manager) <span class="cov0" title="0">{
  262.         for </span><span class="cov0" title="0">{
  263.                 if mgr.ConfigHasChanged() </span><span class="cov0" title="0">{
  264.                         fmt.Println("Configuration has changed on disk, restarting the operator!")
  265.                         os.Exit(0)
  266.                 }</span>
  267.                 <span class="cov0" title="0">time.Sleep(3 * time.Second)</span>
  268.         }
  269. }
  270.  
  271. // setupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
  272. // which is closed on one of these signals. If a second signal is caught, the program
  273. // is terminated with exit code 1.
  274. func setupSignalHandler() (stopCh &lt;-chan struct{}) <span class="cov0" title="0">{
  275.         close(onlyOneSignalHandler) // panics when called twice
  276.  
  277.         stop := make(chan struct{})
  278.         c := make(chan os.Signal, 2)
  279.         signal.Notify(c, shutdownSignals...)
  280.         go func() </span><span class="cov0" title="0">{
  281.                 &lt;-c
  282.                 close(stop)
  283.                 &lt;-c
  284.                 os.Exit(1) // second signal. Exit directly.
  285.         }</span>()
  286.  
  287.         <span class="cov0" title="0">return stop</span>
  288. }
  289. </pre>
  290.        
  291.         <pre class="file" id="file1" style="display: none">package config
  292.  
  293. import (
  294.         "time"
  295.  
  296.         "k8s.io/klog/v2"
  297. )
  298.  
  299. const DefaultResyncDuration = 10 * time.Minute
  300.  
  301. // Config configuration attributes.
  302. type Config struct {
  303.         // ShareRelistInterval interval to relist all "Share" object instances.
  304.         ShareRelistInterval string `yaml:"shareRelistInterval,omitempty"`
  305.         // RefreshResources toggles actively watching for resources, when disabled it will only read
  306.         // resources before mount.
  307.         RefreshResources bool `yaml:"refreshResources,omitempty"`
  308. }
  309.  
  310. var LoadedConfig Config
  311.  
  312. // GetShareRelistInterval returns the ShareRelistInterval value as duration. On error, default value
  313. // is employed instead.
  314. func (c *Config) GetShareRelistInterval() time.Duration <span class="cov8" title="1">{
  315.         resyncDuration, err := time.ParseDuration(c.ShareRelistInterval)
  316.         if err != nil </span><span class="cov8" title="1">{
  317.                 klog.Errorf("Error on parsing ShareRelistInterval '%s': %s", c.ShareRelistInterval, err)
  318.                 return DefaultResyncDuration
  319.         }</span>
  320.         <span class="cov8" title="1">return resyncDuration</span>
  321. }
  322.  
  323. // NewConfig returns a Config instance using the default attribute values.
  324. func NewConfig() Config <span class="cov8" title="1">{
  325.         return Config{
  326.                 ShareRelistInterval: DefaultResyncDuration.String(),
  327.                 RefreshResources:    true,
  328.         }
  329. }</span>
  330. </pre>
  331.        
  332.         <pre class="file" id="file2" style="display: none">package config
  333.  
  334. import (
  335.         "crypto/md5"
  336.         "encoding/hex"
  337.         "io/ioutil"
  338.         "os"
  339.  
  340.         "gopkg.in/yaml.v2"
  341.         "k8s.io/klog/v2"
  342. )
  343.  
  344. // Manager controls the configuration file loading, and can assert if it has changed on disk.
  345. type Manager struct {
  346.         cfgFilePath string // path to configuration file
  347.         md5sum      string // md5sum of the initial content
  348. }
  349.  
  350. // ConfigHasChanged checks the current configuration contents, comparing with that it has been
  351. // instantiated with.
  352. func (m *Manager) ConfigHasChanged() bool <span class="cov8" title="1">{
  353.         // given the md5sum is not yet set, the configuration payload won't be marked as changed
  354.         if m.md5sum == "" </span><span class="cov0" title="0">{
  355.                 return false
  356.         }</span>
  357.  
  358.         // reading the configration file payload again and comparing with the md5sum stored, when there
  359.         // are errors reading the file, it does not mark the configuration as changed
  360.         <span class="cov8" title="1">payload, err := ioutil.ReadFile(m.cfgFilePath)
  361.         if err != nil </span><span class="cov0" title="0">{
  362.                 klog.Errorf("Reading configuration-file '%s': '%#v'", m.cfgFilePath, err)
  363.                 return false
  364.         }</span>
  365.         <span class="cov8" title="1">sum := md5.Sum(payload)
  366.         return m.md5sum != hex.EncodeToString(sum[:])</span>
  367. }
  368.  
  369. // LoadConfig read the local configuration file, make sure the current contents are summed, so we can
  370. // assert if there are changes later on.
  371. func (m *Manager) LoadConfig() (*Config, error) <span class="cov8" title="1">{
  372.         cfg := NewConfig()
  373.  
  374.         if _, err := os.Stat(m.cfgFilePath); os.IsNotExist(err) </span><span class="cov8" title="1">{
  375.                 klog.Info("Configuration file is not found, using default values!")
  376.                 return &amp;cfg, nil
  377.         }</span>
  378.  
  379.         // in the case of issues to read the mounted file, and in case of errors marshaling to the
  380.         // destination struct, this method will surface those errors directly, and we may want to create
  381.         // means to differentiate the error scenarios
  382.         <span class="cov8" title="1">klog.Infof("Loading configuration-file '%s'", m.cfgFilePath)
  383.         payload, err := ioutil.ReadFile(m.cfgFilePath)
  384.         if err != nil </span><span class="cov0" title="0">{
  385.                 return nil, err
  386.         }</span>
  387.         <span class="cov8" title="1">sum := md5.Sum(payload)
  388.         m.md5sum = hex.EncodeToString(sum[:])
  389.  
  390.         // overwriting attributes found on the configuration file with the defaults
  391.         if err = yaml.Unmarshal(payload, &amp;cfg); err != nil </span><span class="cov0" title="0">{
  392.                 return nil, err
  393.         }</span>
  394.         <span class="cov8" title="1">LoadedConfig = cfg
  395.         return &amp;cfg, nil</span>
  396. }
  397.  
  398. // NewManager instantiate the manager.
  399. func NewManager(cfgFilePath string) *Manager <span class="cov8" title="1">{
  400.         return &amp;Manager{cfgFilePath: cfgFilePath}
  401. }</span>
  402. </pre>
  403.        
  404.         <pre class="file" id="file3" style="display: none">package csidriver
  405.  
  406. import (
  407.         "encoding/json"
  408.         "os"
  409.         "path/filepath"
  410.         "sync"
  411.  
  412.         "k8s.io/klog/v2"
  413.  
  414.         "github.com/openshift/csi-driver-shared-resource/pkg/consts"
  415. )
  416.  
  417. // NOTE / TODO: the fields in this struct need to start with a capital letter since we are
  418. // externalizing / storing to disk, unless there is someway to get the golang encoding
  419. // logic to use our getters/setters
  420. type driverVolume struct {
  421.         VolID               string     `json:"volID"`
  422.         VolName             string     `json:"volName"`
  423.         VolSize             int64      `json:"volSize"`
  424.         VolPathAnchorDir    string     `json:"volPathAnchorDir"`
  425.         VolPathBindMountDir string     `json:"volPathBindMountDir"`
  426.         VolAccessType       accessType `json:"volAccessType"`
  427.         TargetPath          string     `json:"targetPath"`
  428.         SharedDataKind      string     `json:"sharedDataKind"`
  429.         SharedDataId        string     `json:"sharedDataId"`
  430.         PodNamespace        string     `json:"podNamespace"`
  431.         PodName             string     `json:"podName"`
  432.         PodUID              string     `json:"podUID"`
  433.         PodSA               string     `json:"podSA"`
  434.         Refresh             bool       `json:"refresh"`
  435.         // dpv's can be accessed/modified by both the sharedSecret/SharedConfigMap events and the configmap/secret events; to prevent data races
  436.         // we serialize access to a given dpv with a per dpv mutex stored in this map; access to dpv fields should not
  437.         // be done directly, but only by each field's getter and setter.  Getters and setters then leverage the per dpv
  438.         // Lock objects stored in this map to prevent golang data races
  439.         Lock *sync.Mutex `json:"-"` // we do not want this persisted to and from disk, so use of `json:"-"`
  440. }
  441.  
  442. func CreateDV(volID string) *driverVolume <span class="cov8" title="1">{
  443.         dpv := &amp;driverVolume{VolID: volID, Lock: &amp;sync.Mutex{}}
  444.         setDPV(volID, dpv)
  445.         return dpv
  446. }</span>
  447.  
  448. func (dpv *driverVolume) GetVolID() string <span class="cov8" title="1">{
  449.         dpv.Lock.Lock()
  450.         defer dpv.Lock.Unlock()
  451.         return dpv.VolID
  452. }</span>
  453.  
  454. func (dpv *driverVolume) GetVolName() string <span class="cov0" title="0">{
  455.         dpv.Lock.Lock()
  456.         defer dpv.Lock.Unlock()
  457.         return dpv.VolName
  458. }</span>
  459.  
  460. func (dpv *driverVolume) GetVolSize() int64 <span class="cov0" title="0">{
  461.         dpv.Lock.Lock()
  462.         defer dpv.Lock.Unlock()
  463.         return dpv.VolSize
  464. }</span>
  465. func (dpv *driverVolume) GetVolPathAnchorDir() string <span class="cov8" title="1">{
  466.         dpv.Lock.Lock()
  467.         defer dpv.Lock.Unlock()
  468.         return dpv.VolPathAnchorDir
  469. }</span>
  470. func (dpv *driverVolume) GetVolPathBindMountDir() string <span class="cov0" title="0">{
  471.         dpv.Lock.Lock()
  472.         defer dpv.Lock.Unlock()
  473.         return dpv.VolPathBindMountDir
  474. }</span>
  475. func (dpv *driverVolume) GetVolAccessType() accessType <span class="cov0" title="0">{
  476.         dpv.Lock.Lock()
  477.         defer dpv.Lock.Unlock()
  478.         return dpv.VolAccessType
  479. }</span>
  480. func (dpv *driverVolume) GetTargetPath() string <span class="cov8" title="1">{
  481.         dpv.Lock.Lock()
  482.         defer dpv.Lock.Unlock()
  483.         return dpv.TargetPath
  484. }</span>
  485. func (dpv *driverVolume) GetSharedDataKind() consts.ResourceReferenceType <span class="cov8" title="1">{
  486.         dpv.Lock.Lock()
  487.         defer dpv.Lock.Unlock()
  488.         return consts.ResourceReferenceType(dpv.SharedDataKind)
  489. }</span>
  490. func (dpv *driverVolume) GetSharedDataId() string <span class="cov8" title="1">{
  491.         dpv.Lock.Lock()
  492.         defer dpv.Lock.Unlock()
  493.         return dpv.SharedDataId
  494. }</span>
  495. func (dpv *driverVolume) GetPodNamespace() string <span class="cov8" title="1">{
  496.         dpv.Lock.Lock()
  497.         defer dpv.Lock.Unlock()
  498.         return dpv.PodNamespace
  499. }</span>
  500. func (dpv *driverVolume) GetPodName() string <span class="cov8" title="1">{
  501.         dpv.Lock.Lock()
  502.         defer dpv.Lock.Unlock()
  503.         return dpv.PodName
  504. }</span>
  505. func (dpv *driverVolume) GetPodUID() string <span class="cov0" title="0">{
  506.         dpv.Lock.Lock()
  507.         defer dpv.Lock.Unlock()
  508.         return dpv.PodUID
  509. }</span>
  510. func (dpv *driverVolume) GetPodSA() string <span class="cov8" title="1">{
  511.         dpv.Lock.Lock()
  512.         defer dpv.Lock.Unlock()
  513.         return dpv.PodSA
  514. }</span>
  515. func (dpv *driverVolume) IsRefresh() bool <span class="cov8" title="1">{
  516.         dpv.Lock.Lock()
  517.         defer dpv.Lock.Unlock()
  518.         return dpv.Refresh
  519. }</span>
  520.  
  521. func (dpv *driverVolume) SetVolName(volName string) <span class="cov0" title="0">{
  522.         dpv.Lock.Lock()
  523.         defer dpv.Lock.Unlock()
  524.         dpv.VolName = volName
  525. }</span>
  526.  
  527. func (dpv *driverVolume) SetVolSize(size int64) <span class="cov8" title="1">{
  528.         dpv.Lock.Lock()
  529.         defer dpv.Lock.Unlock()
  530.         dpv.VolSize = size
  531. }</span>
  532. func (dpv *driverVolume) SetVolPathAnchorDir(path string) <span class="cov8" title="1">{
  533.         dpv.Lock.Lock()
  534.         defer dpv.Lock.Unlock()
  535.         dpv.VolPathAnchorDir = path
  536. }</span>
  537. func (dpv *driverVolume) SetVolPathBindMountDir(path string) <span class="cov8" title="1">{
  538.         dpv.Lock.Lock()
  539.         defer dpv.Lock.Unlock()
  540.         dpv.VolPathBindMountDir = path
  541. }</span>
  542. func (dpv *driverVolume) SetVolAccessType(at accessType) <span class="cov8" title="1">{
  543.         dpv.Lock.Lock()
  544.         defer dpv.Lock.Unlock()
  545.         dpv.VolAccessType = at
  546. }</span>
  547. func (dpv *driverVolume) SetTargetPath(path string) <span class="cov8" title="1">{
  548.         dpv.Lock.Lock()
  549.         defer dpv.Lock.Unlock()
  550.         dpv.TargetPath = path
  551. }</span>
  552. func (dpv *driverVolume) SetSharedDataKind(kind string) <span class="cov8" title="1">{
  553.         dpv.Lock.Lock()
  554.         defer dpv.Lock.Unlock()
  555.         dpv.SharedDataKind = kind
  556. }</span>
  557. func (dpv *driverVolume) SetSharedDataId(id string) <span class="cov8" title="1">{
  558.         dpv.Lock.Lock()
  559.         defer dpv.Lock.Unlock()
  560.         dpv.SharedDataId = id
  561. }</span>
  562. func (dpv *driverVolume) SetPodNamespace(namespace string) <span class="cov8" title="1">{
  563.         dpv.Lock.Lock()
  564.         defer dpv.Lock.Unlock()
  565.         dpv.PodNamespace = namespace
  566. }</span>
  567. func (dpv *driverVolume) SetPodName(name string) <span class="cov8" title="1">{
  568.         dpv.Lock.Lock()
  569.         defer dpv.Lock.Unlock()
  570.         dpv.PodName = name
  571. }</span>
  572. func (dpv *driverVolume) SetPodUID(uid string) <span class="cov8" title="1">{
  573.         dpv.Lock.Lock()
  574.         defer dpv.Lock.Unlock()
  575.         dpv.PodUID = uid
  576. }</span>
  577. func (dpv *driverVolume) SetPodSA(sa string) <span class="cov8" title="1">{
  578.         dpv.Lock.Lock()
  579.         defer dpv.Lock.Unlock()
  580.         dpv.PodSA = sa
  581. }</span>
  582. func (dpv *driverVolume) SetRefresh(refresh bool) <span class="cov8" title="1">{
  583.         dpv.Lock.Lock()
  584.         defer dpv.Lock.Unlock()
  585.         dpv.Refresh = refresh
  586. }</span>
  587.  
  588. func (dpv *driverVolume) StoreToDisk(volMapRoot string) error <span class="cov8" title="1">{
  589.         dpv.Lock.Lock()
  590.         defer dpv.Lock.Unlock()
  591.         klog.V(4).Infof("storeVolToDisk %s", dpv.VolID)
  592.         defer klog.V(4).Infof("storeVolToDisk exit %s", dpv.VolID)
  593.  
  594.         f, terr := os.Open(volMapRoot)
  595.         if terr != nil </span><span class="cov0" title="0">{
  596.                 // catch for unit tests
  597.                 return nil
  598.         }</span>
  599.         <span class="cov8" title="1">defer f.Close()
  600.  
  601.         filePath := filepath.Join(volMapRoot, dpv.VolID)
  602.         dataFile, err := os.Create(filePath)
  603.         if err != nil </span><span class="cov0" title="0">{
  604.                 return err
  605.         }</span>
  606.         <span class="cov8" title="1">defer dataFile.Close()
  607.  
  608.         dataEncoder := json.NewEncoder(dataFile)
  609.         return dataEncoder.Encode(dpv)</span>
  610. }
  611. </pre>
  612.        
  613.         <pre class="file" id="file4" style="display: none">/*
  614. Copyright 2017 The Kubernetes Authors.
  615.  
  616. Licensed under the Apache License, Version 2.0 (the "License");
  617. you may not use this file except in compliance with the License.
  618. You may obtain a copy of the License at
  619.  
  620.     http://www.apache.org/licenses/LICENSE-2.0
  621.  
  622. Unless required by applicable law or agreed to in writing, software
  623. distributed under the License is distributed on an "AS IS" BASIS,
  624. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  625. See the License for the specific language governing permissions and
  626. limitations under the License.
  627. */
  628.  
  629. package csidriver
  630.  
  631. import (
  632.         "context"
  633.         "encoding/json"
  634.         "errors"
  635.         "fmt"
  636.         "io"
  637.         "io/ioutil"
  638.         "k8s.io/utils/mount"
  639.         "os"
  640.         "path/filepath"
  641.         "strings"
  642.         "sync"
  643.  
  644.         corev1 "k8s.io/api/core/v1"
  645.         kerrors "k8s.io/apimachinery/pkg/api/errors"
  646.         metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  647.         "k8s.io/client-go/kubernetes"
  648.         "k8s.io/klog/v2"
  649.  
  650.         sharev1alpha1 "github.com/openshift/api/sharedresource/v1alpha1"
  651.         objcache "github.com/openshift/csi-driver-shared-resource/pkg/cache"
  652.         "github.com/openshift/csi-driver-shared-resource/pkg/client"
  653.         "github.com/openshift/csi-driver-shared-resource/pkg/config"
  654.         "github.com/openshift/csi-driver-shared-resource/pkg/consts"
  655. )
  656.  
  657. type driver struct {
  658.         name              string
  659.         nodeID            string
  660.         version           string
  661.         endpoint          string
  662.         ephemeral         bool
  663.         maxVolumesPerNode int64
  664.  
  665.         ids *identityServer
  666.         ns  *nodeServer
  667.  
  668.         root       string
  669.         volMapRoot string
  670.  
  671.         mounter mount.Interface
  672. }
  673.  
  674. var (
  675.         vendorVersion = "dev"
  676.  
  677.         volumes = sync.Map{}
  678. )
  679.  
  680. const (
  681.         // Directory where data for volumes are persisted.
  682.         // This is ephemeral to facilitate our per-pod, tmpfs,
  683.         // no bind mount, approach.
  684.         DataRoot = "/run/csi-data-dir"
  685.  
  686.         // Directory where we persist `volumes`
  687.         // This is a csidriver volume on the local node
  688.         // to maintain state across restarts of the DaemonSet
  689.         VolumeMapRoot = "/csi-volumes-map"
  690. )
  691.  
  692. func (d *driver) getVolume(name string) *driverVolume <span class="cov8" title="1">{
  693.         obj, loaded := volumes.Load(name)
  694.         if loaded </span><span class="cov8" title="1">{
  695.                 dv, _ := obj.(*driverVolume)
  696.                 return dv
  697.         }</span>
  698.         <span class="cov8" title="1">return nil</span>
  699. }
  700.  
  701. func setDPV(name string, dpv *driverVolume) <span class="cov8" title="1">{
  702.         if dpv.Lock == nil </span><span class="cov0" title="0">{
  703.                 dpv.Lock = &amp;sync.Mutex{}
  704.         }</span>
  705.         <span class="cov8" title="1">volumes.Store(name, dpv)</span>
  706. }
  707.  
  708. func remV(name string) <span class="cov8" title="1">{
  709.         volumes.Delete(name)
  710. }</span>
  711.  
  712. type CSIDriver interface {
  713.         createVolume(volID, targetPath string, refresh bool, volCtx map[string]string, cmShare *sharev1alpha1.SharedConfigMap, sShare *sharev1alpha1.SharedSecret, cap int64, volAccessType accessType) (*driverVolume, error)
  714.         getVolume(volID string) *driverVolume
  715.         deleteVolume(volID string) error
  716.         getVolumePath(volID string, volCtx map[string]string) (string, string)
  717.         mapVolumeToPod(dv *driverVolume) error
  718.         Run()
  719.         GetRoot() string
  720.         GetVolMapRoot() string
  721.         Prune(kubeClient kubernetes.Interface)
  722. }
  723.  
  724. // NewCSIDriver instantiate the CSIDriver with the driver details.  Optionally, a
  725. // Kubernetes Clientset can be informed to update (warm up) the object cache before creating the
  726. // volume (and it's data) for mounting on the incoming pod.
  727. func NewCSIDriver(root, volMapRoot, driverName, nodeID, endpoint string, maxVolumesPerNode int64, version string, mounter mount.Interface) (CSIDriver, error) <span class="cov8" title="1">{
  728.         if driverName == "" </span><span class="cov0" title="0">{
  729.                 return nil, errors.New("no driver name provided")
  730.         }</span>
  731.  
  732.         <span class="cov8" title="1">if nodeID == "" </span><span class="cov0" title="0">{
  733.                 return nil, errors.New("no node id provided")
  734.         }</span>
  735.  
  736.         <span class="cov8" title="1">if endpoint == "" </span><span class="cov0" title="0">{
  737.                 return nil, errors.New("no driver endpoint provided")
  738.         }</span>
  739.         <span class="cov8" title="1">if version != "" </span><span class="cov8" title="1">{
  740.                 vendorVersion = version
  741.         }</span>
  742.  
  743.         <span class="cov8" title="1">if err := os.MkdirAll(root, 0750); err != nil </span><span class="cov0" title="0">{
  744.                 return nil, fmt.Errorf("failed to create DataRoot: %v", err)
  745.         }</span>
  746.  
  747.         <span class="cov8" title="1">if err := os.MkdirAll(volMapRoot, 0750); err != nil </span><span class="cov0" title="0">{
  748.                 return nil, fmt.Errorf("failed to create VolMapRoot: %v", err)
  749.         }</span>
  750.  
  751.         <span class="cov8" title="1">klog.Infof("Driver: '%v', Version: '%s'", driverName, vendorVersion)
  752.         klog.Infof("EndPoint: '%s', NodeID: '%s'", endpoint, nodeID)
  753.  
  754.         if !config.LoadedConfig.RefreshResources </span><span class="cov8" title="1">{
  755.                 klog.Info("RefreshResources is disabled and CSIDriver will directly read Kubernetes corev1 resources!")
  756.         }</span>
  757.  
  758.         <span class="cov8" title="1">d := &amp;driver{
  759.                 name:              driverName,
  760.                 version:           vendorVersion,
  761.                 nodeID:            nodeID,
  762.                 endpoint:          endpoint,
  763.                 maxVolumesPerNode: maxVolumesPerNode,
  764.                 root:              root,
  765.                 volMapRoot:        volMapRoot,
  766.                 mounter:           mounter,
  767.         }
  768.  
  769.         if err := d.loadVolsFromDisk(); err != nil </span><span class="cov0" title="0">{
  770.                 return nil, fmt.Errorf("failed to load volume map on disk: %v", err)
  771.         }</span>
  772.  
  773.         <span class="cov8" title="1">return d, nil</span>
  774. }
  775.  
  776. func (d *driver) GetRoot() string <span class="cov0" title="0">{
  777.         return d.root
  778. }</span>
  779.  
  780. func (d *driver) GetVolMapRoot() string <span class="cov8" title="1">{
  781.         return d.volMapRoot
  782. }</span>
  783.  
  784. func (d *driver) Run() <span class="cov0" title="0">{
  785.         // Create GRPC servers
  786.         d.ids = NewIdentityServer(d.name, d.version)
  787.  
  788.         // the node-server will be on always-read-only mode when the object-cache is being populated
  789.         // directly
  790.         d.ns = NewNodeServer(d)
  791.  
  792.         s := NewNonBlockingGRPCServer()
  793.         s.Start(d.endpoint, d.ids, d.ns)
  794.         s.Wait()
  795. }</span>
  796.  
  797. // getVolumePath returns the canonical paths for csidriver volume
  798. func (d *driver) getVolumePath(volID string, volCtx map[string]string) (string, string) <span class="cov8" title="1">{
  799.         podNamespace, podName, podUID, podSA := getPodDetails(volCtx)
  800.         mountIDString := strings.Join([]string{podNamespace, podName, volID}, "-")
  801.         return mountIDString, filepath.Join(d.root, bindDir, volID, podNamespace, podName, podUID, podSA)
  802. }</span>
  803.  
  804. func commonRangerProceedFilter(dv *driverVolume, key interface{}) bool <span class="cov8" title="1">{
  805.         if dv == nil </span><span class="cov0" title="0">{
  806.                 return false
  807.         }</span>
  808.         <span class="cov8" title="1">compareKey := ""
  809.         // see if the shared item pertains to this volume
  810.         switch dv.GetSharedDataKind() </span>{
  811.         case consts.ResourceReferenceTypeSecret:<span class="cov8" title="1">
  812.                 sharedSecret := client.GetSharedSecret(dv.GetSharedDataId())
  813.                 if sharedSecret == nil </span><span class="cov0" title="0">{
  814.                         klog.V(6).Infof("commonRangerProceedFilter could not retrieve share %s for %s:%s:%s", dv.GetSharedDataId(), dv.GetPodNamespace(), dv.GetPodName(), dv.GetVolID())
  815.                         return false
  816.                 }</span>
  817.                 <span class="cov8" title="1">compareKey = objcache.BuildKey(sharedSecret.Spec.SecretRef.Namespace, sharedSecret.Spec.SecretRef.Name)</span>
  818.         case consts.ResourceReferenceTypeConfigMap:<span class="cov8" title="1">
  819.                 sharedConfigMap := client.GetSharedConfigMap(dv.GetSharedDataId())
  820.                 if sharedConfigMap == nil </span><span class="cov0" title="0">{
  821.                         klog.V(6).Infof("commonRangerProceedFilter could not retrieve share %s for %s:%s:%s", dv.GetSharedDataId(), dv.GetPodNamespace(), dv.GetPodName(), dv.GetVolID())
  822.                         return false
  823.                 }</span>
  824.                 <span class="cov8" title="1">compareKey = objcache.BuildKey(sharedConfigMap.Spec.ConfigMapRef.Namespace, sharedConfigMap.Spec.ConfigMapRef.Name)</span>
  825.         default:<span class="cov0" title="0">
  826.                 klog.Warningf("commonRangerProceedFilter unknown share type for %s:%s:%s: %s", dv.GetPodNamespace(), dv.GetPodName(), dv.GetVolID())
  827.                 return false</span>
  828.         }
  829.         <span class="cov8" title="1">keyStr := key.(string)
  830.         if keyStr != compareKey </span><span class="cov8" title="1">{
  831.                 klog.V(4).Infof("commonRangerProceedFilter skipping %s as it does not match %s for %s:%s:%s", keyStr, compareKey, dv.GetPodNamespace(), dv.GetPodName(), dv.GetVolID())
  832.                 return false
  833.         }</span>
  834.         <span class="cov8" title="1">return true</span>
  835. }
  836.  
  837. func commonUpsertRanger(dv *driverVolume, key, value interface{}) error <span class="cov8" title="1">{
  838.         proceed := commonRangerProceedFilter(dv, key)
  839.         if !proceed </span><span class="cov8" title="1">{
  840.                 return nil
  841.         }</span>
  842.  
  843.         <span class="cov8" title="1">payload, _ := value.(Payload)
  844.         klog.V(4).Infof("commonUpsertRanger key %s dv %#v", key, dv)
  845.         podPath := dv.GetTargetPath()
  846.         // So, what to do with error handling.  Errors with filesystem operations
  847.         // will almost always not be intermittent, but most likely the result of the
  848.         // host filesystem either being full or compromised in some long running fashion, so tight-loop retry, like we
  849.         // *could* do here as a result will typically prove fruitless.
  850.         // Then, the controller relist will result in going through the secrets/configmaps we share, so
  851.         // again, on the off chance the filesystem error is intermittent, or if an administrator has taken corrective
  852.         // action, writing the content will be retried.  And note, the relist interval is configurable (default 10 minutes)
  853.         // if users want more rapid retry...but by default, no tight loop more CPU intensive retry
  854.         // Lastly, with the understanding that an error log in the pod stdout may be missed, we will also generate a k8s
  855.         // event to facilitate exposure
  856.         // TODO: prometheus metrics/alerts may be desired here, though some due diligence on what k8s level metrics/alerts
  857.         // around host filesystem issues might already exist would be warranted with such an exploration/effort
  858.  
  859.         // Next, on an update we first nuke any existing directory and then recreate it to simplify handling the case where
  860.         // the keys in the secret/configmap have changed such that some keys have been removed, which would translate
  861.         // in files having to be removed. commonOSRemove will handle shares mounted off of shares.  And a reminder,
  862.         // currently this driver does not support overlaying over directories with files.  Either the directory in the
  863.         // container image must be empty, or the directory does not exist, and is created for the Pod's container as
  864.         // part of provisioning the container.
  865.         if err := commonOSRemove(podPath, fmt.Sprintf("commonUpsertRanger key %s volid %s share id %s pod name %s", key, dv.GetVolID(), dv.GetSharedDataId(), dv.GetPodName())); err != nil </span><span class="cov0" title="0">{
  866.                 return err
  867.         }</span>
  868.         <span class="cov8" title="1">if err := os.MkdirAll(podPath, os.ModePerm); err != nil </span><span class="cov0" title="0">{
  869.                 return err
  870.         }</span>
  871.         <span class="cov8" title="1">if payload.ByteData != nil </span><span class="cov8" title="1">{
  872.                 for dataKey, dataValue := range payload.ByteData </span><span class="cov8" title="1">{
  873.                         podFilePath := filepath.Join(podPath, dataKey)
  874.                         klog.V(4).Infof("commonUpsertRanger create/update file %s key %s volid %s share id %s pod name %s", podFilePath, key, dv.GetVolID(), dv.GetSharedDataId(), dv.GetPodName())
  875.                         if err := ioutil.WriteFile(podFilePath, dataValue, 0644); err != nil </span><span class="cov0" title="0">{
  876.                                 return err
  877.                         }</span>
  878.  
  879.                 }
  880.         }
  881.         <span class="cov8" title="1">if payload.StringData != nil </span><span class="cov8" title="1">{
  882.                 for dataKey, dataValue := range payload.StringData </span><span class="cov8" title="1">{
  883.                         podFilePath := filepath.Join(podPath, dataKey)
  884.                         klog.V(4).Infof("commonUpsertRanger create/update file %s key %s volid %s share id %s pod name %s", podFilePath, key, dv.GetVolID(), dv.GetSharedDataId(), dv.GetPodName())
  885.                         content := []byte(dataValue)
  886.                         if err := ioutil.WriteFile(podFilePath, content, 0644); err != nil </span><span class="cov0" title="0">{
  887.                                 return err
  888.                         }</span>
  889.                 }
  890.         }
  891.         <span class="cov8" title="1">klog.V(4).Infof("common upsert ranger returning key %s", key)
  892.         return nil</span>
  893. }
  894.  
  895. func commonOSRemove(dir, dbg string) error <span class="cov8" title="1">{
  896.         klog.V(4).Infof("commonOSRemove to delete %q dbg %s", dir, dbg)
  897.         defer klog.V(4).Infof("commonOSRemove completed delete attempt for dir %q", dir)
  898.         // we cannot do a os.RemoveAll on the mount point, so we remove all on each file system entity
  899.         // off of the potential mount point
  900.         return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error </span><span class="cov8" title="1">{
  901.                 if info == nil </span><span class="cov0" title="0">{
  902.                         return nil
  903.                 }</span>
  904.                 // since we do not support mounting on existing content, a dir can only mean a share
  905.                 // has been mounted as a separate dir in our share, so skip
  906.                 <span class="cov8" title="1">if info.IsDir() </span><span class="cov8" title="1">{
  907.                         return nil
  908.                 }</span>
  909.                 <span class="cov8" title="1">fileName := filepath.Join(dir, info.Name())
  910.                 klog.V(4).Infof("commonOSRemove going to delete file %s", fileName)
  911.                 return os.RemoveAll(fileName)</span>
  912.         })
  913.  
  914. }
  915.  
  916. func commonDeleteRanger(dv *driverVolume, key interface{}) bool <span class="cov8" title="1">{
  917.         proceed := commonRangerProceedFilter(dv, key)
  918.         if !proceed </span><span class="cov0" title="0">{
  919.                 // even though we are aborting, return true to continue to next entry in ranger list
  920.                 return true
  921.         }</span>
  922.         <span class="cov8" title="1">klog.V(4).Infof("common delete ranger key %s", key)
  923.         commonOSRemove(dv.GetTargetPath(), fmt.Sprintf("commonDeleteRanger %s", key))
  924.         klog.V(4).Infof("common delete ranger returning key %s", key)
  925.         return true</span>
  926. }
  927.  
  928. type innerShareDeleteRanger struct {
  929.         shareId string
  930. }
  931.  
  932. func (r *innerShareDeleteRanger) Range(key, value interface{}) bool <span class="cov8" title="1">{
  933.         targetPath := ""
  934.         volID := key.(string)
  935.         // painful debug has shown you cannot trust the value that comes in, you have to refetch,
  936.         // unless the map only has 1 entry in it
  937.         var dv *driverVolume
  938.         klog.V(4).Infof("innerShareDeleteRanger key %q\n incoming share id %s",
  939.                 key,
  940.                 r.shareId)
  941.         dvObj, ok := volumes.Load(key)
  942.         if !ok </span><span class="cov0" title="0">{
  943.                 klog.V(0).Infof("innerShareDeleteRanger how the hell can we not load key %s from the range list", key)
  944.                 // continue to the next entry, skip this one
  945.                 return true
  946.         }</span> else<span class="cov8" title="1"> {
  947.                 dv, _ = dvObj.(*driverVolume)
  948.         }</span>
  949.         <span class="cov8" title="1">if dv.GetVolID() == volID &amp;&amp; dv.GetSharedDataId() == r.shareId </span><span class="cov8" title="1">{
  950.                 klog.V(4).Infof("innerShareDeleteRanger shareid %s kind %s", r.shareId, dv.GetSharedDataKind())
  951.                 targetPath = dv.GetTargetPath()
  952.                 volID = dv.GetVolID()
  953.                 if len(volID) &gt; 0 &amp;&amp; len(targetPath) &gt; 0 </span><span class="cov8" title="1">{
  954.                         err := commonOSRemove(targetPath, fmt.Sprintf("innerShareDeleteRanger shareID id %s", r.shareId))
  955.                         if err != nil </span><span class="cov0" title="0">{
  956.                                 klog.Warningf("innerShareDeleteRanger %s vol %s target path %s delete error %s",
  957.                                         r.shareId, volID, targetPath, err.Error())
  958.                         }</span>
  959.                         // we just delete the associated data from the previously provisioned volume;
  960.                         // we don't delete the volume in case the share is added back
  961.                 }
  962.                 <span class="cov8" title="1">return false</span>
  963.         }
  964.         <span class="cov0" title="0">return true</span>
  965. }
  966.  
  967. func shareDeleteRanger(key interface{}) bool <span class="cov8" title="1">{
  968.         shareId := key.(string)
  969.         klog.V(4).Infof("shareDeleteRanger shareID id %s", shareId)
  970.         ranger := &amp;innerShareDeleteRanger{
  971.                 shareId: shareId,
  972.         }
  973.  
  974.         volumes.Range(ranger.Range)
  975.         klog.V(4).Infof("shareDeleteRanger returning share id %s", shareId)
  976.         return true
  977. }</span>
  978.  
  979. type innerShareUpdateRanger struct {
  980.         shareId   string
  981.         secret    bool
  982.         configmap bool
  983.  
  984.         oldTargetPath string
  985.         sharedItemKey string
  986.         volID         string
  987.  
  988.         sharedItem Payload
  989. }
  990.  
  991. func (r *innerShareUpdateRanger) Range(key, value interface{}) bool <span class="cov8" title="1">{
  992.         volID := key.(string)
  993.         // painful debug has shown you cannot trust the value that comes in, you have to refetch,
  994.         // unless the map only has 1 entry in it
  995.         var dv *driverVolume
  996.         klog.V(4).Infof("innerShareUpdateRanger key %q\n incoming share id %s",
  997.                 key,
  998.                 r.shareId)
  999.         dvObj, ok := volumes.Load(key)
  1000.         if !ok </span><span class="cov0" title="0">{
  1001.                 klog.V(0).Infof("innerShareUpdateRanger how the hell can we not load key %s from the range list", key)
  1002.                 // continue to the next entry, skip this one
  1003.                 return true
  1004.         }</span> else<span class="cov8" title="1"> {
  1005.                 dv, _ = dvObj.(*driverVolume)
  1006.         }</span>
  1007.         <span class="cov8" title="1">if dv.GetVolID() == volID &amp;&amp; dv.GetSharedDataId() == r.shareId </span><span class="cov8" title="1">{
  1008.                 klog.V(4).Infof("innerShareUpdateRanger MATCH inner ranger key %q\n dv vol id %s\n incoming share id %s\n dv share id %s", key, dv.GetVolID(), r.shareId, dv.GetSharedDataId())
  1009.                 a, err := client.ExecuteSAR(r.shareId, dv.GetPodNamespace(), dv.GetPodName(), dv.GetPodSA(), dv.GetSharedDataKind())
  1010.                 allowed := a &amp;&amp; err == nil
  1011.  
  1012.                 if allowed </span><span class="cov8" title="1">{
  1013.                         klog.V(0).Infof("innerShareUpdateRanger pod %s:%s has permissions for secretShare %s",
  1014.                                 dv.GetPodNamespace(), dv.GetPodName(), r.shareId)
  1015.                 }</span> else<span class="cov8" title="1"> {
  1016.                         klog.V(0).Infof("innerShareUpdateRanger pod %s:%s does not permission for secretShare %s",
  1017.                                 dv.GetPodNamespace(), dv.GetPodName(), r.shareId)
  1018.                 }</span>
  1019.  
  1020.                 <span class="cov8" title="1">switch </span>{
  1021.                 case r.secret:<span class="cov8" title="1">
  1022.                         sharedSecret := client.GetSharedSecret(r.shareId)
  1023.                         if sharedSecret == nil </span><span class="cov0" title="0">{
  1024.                                 klog.Warningf("innerShareUpdateRanger unexpected not found on sharedSecret lister refresh: %s", r.shareId)
  1025.                                 return false
  1026.                         }</span>
  1027.                         <span class="cov8" title="1">r.sharedItemKey = objcache.BuildKey(sharedSecret.Spec.SecretRef.Namespace, sharedSecret.Spec.SecretRef.Name)
  1028.                         secretObj := client.GetSecret(sharedSecret.Spec.SecretRef.Namespace, sharedSecret.Spec.SecretRef.Name)
  1029.                         if secretObj == nil </span><span class="cov0" title="0">{
  1030.                                 klog.Infof("innerShareUpdateRanger share %s could not retrieve shared item %s", r.shareId, r.sharedItemKey)
  1031.                                 return false
  1032.                         }</span>
  1033.                         <span class="cov8" title="1">r.sharedItem = Payload{
  1034.                                 ByteData:   secretObj.Data,
  1035.                                 StringData: secretObj.StringData,
  1036.                         }</span>
  1037.                 case r.configmap:<span class="cov8" title="1">
  1038.                         sharedConfigMap := client.GetSharedConfigMap(r.shareId)
  1039.                         if sharedConfigMap == nil </span><span class="cov0" title="0">{
  1040.                                 klog.Warningf("innerShareUpdateRanger unexpected not found on sharedConfigMap lister refresh: %s", r.shareId)
  1041.                                 return false
  1042.                         }</span>
  1043.                         <span class="cov8" title="1">r.sharedItemKey = objcache.BuildKey(sharedConfigMap.Spec.ConfigMapRef.Namespace, sharedConfigMap.Spec.ConfigMapRef.Name)
  1044.                         cmObj := client.GetConfigMap(sharedConfigMap.Spec.ConfigMapRef.Namespace, sharedConfigMap.Spec.ConfigMapRef.Name)
  1045.                         if cmObj == nil </span><span class="cov8" title="1">{
  1046.                                 klog.Infof("innerShareUpdateRanger share %s could not retrieve shared item %s", r.shareId, r.sharedItemKey)
  1047.                                 return false
  1048.                         }</span>
  1049.                         <span class="cov8" title="1">r.sharedItem = Payload{
  1050.                                 StringData: cmObj.Data,
  1051.                                 ByteData:   cmObj.BinaryData,
  1052.                         }</span>
  1053.                 }
  1054.  
  1055.                 <span class="cov8" title="1">r.oldTargetPath = dv.GetTargetPath()
  1056.                 r.volID = dv.GetVolID()
  1057.  
  1058.                 if !allowed </span><span class="cov8" title="1">{
  1059.                         err := commonOSRemove(r.oldTargetPath, "lostPermissions")
  1060.                         if err != nil </span><span class="cov0" title="0">{
  1061.                                 klog.Warningf("innerShareUpdateRanger %s target path %s delete error %s",
  1062.                                         key, r.oldTargetPath, err.Error())
  1063.                         }</span>
  1064.                         <span class="cov8" title="1">objcache.UnregisterSecretUpsertCallback(r.volID)
  1065.                         objcache.UnregisterSecretDeleteCallback(r.volID)
  1066.                         objcache.UnregisterConfigMapDeleteCallback(r.volID)
  1067.                         objcache.UnregisterConfigMapUpsertCallback(r.volID)
  1068.                         return false</span>
  1069.                 }
  1070.  
  1071.                 <span class="cov8" title="1">commonUpsertRanger(dv, r.sharedItemKey, r.sharedItem)</span>
  1072.  
  1073.         }
  1074.         <span class="cov8" title="1">klog.V(4).Infof("innerShareUpdateRanger NO MATCH inner ranger key %q\n dv vol id %s\n incoming share id %s\n dv share id %s", key, dv.GetVolID(), r.shareId, dv.GetSharedDataId())
  1075.         return true</span>
  1076. }
  1077.  
  1078. func shareUpdateRanger(key, value interface{}) bool <span class="cov8" title="1">{
  1079.         shareId := key.(string)
  1080.         _, sok := value.(*sharev1alpha1.SharedSecret)
  1081.         _, cmok := value.(*sharev1alpha1.SharedConfigMap)
  1082.         if !sok &amp;&amp; !cmok </span><span class="cov0" title="0">{
  1083.                 klog.Warningf("unknown shareUpdateRanger key %q object %#v", key, value)
  1084.                 return false
  1085.         }</span>
  1086.         <span class="cov8" title="1">klog.V(4).Infof("shareUpdateRanger key %s secret %v configmap %v", key, sok, cmok)
  1087.         rangerObj := &amp;innerShareUpdateRanger{
  1088.                 shareId:   shareId,
  1089.                 secret:    sok,
  1090.                 configmap: cmok,
  1091.         }
  1092.         volumes.Range(rangerObj.Range)
  1093.  
  1094.         klog.V(4).Infof("shareUpdateRanger key %s value %#v inner ranger %#v inner ranger", key, value, rangerObj)
  1095.         return true</span>
  1096. }
  1097.  
  1098. func mapBackingResourceToPod(dv *driverVolume) error <span class="cov8" title="1">{
  1099.         klog.V(4).Infof("mapBackingResourceToPod")
  1100.         switch dv.GetSharedDataKind() </span>{
  1101.         case consts.ResourceReferenceTypeConfigMap:<span class="cov8" title="1">
  1102.                 klog.V(4).Infof("mapBackingResourceToPod postlock %s configmap", dv.GetVolID())
  1103.                 upsertRangerCM := func(key, value interface{}) bool </span><span class="cov0" title="0">{
  1104.                         cm, _ := value.(*corev1.ConfigMap)
  1105.                         payload := Payload{
  1106.                                 StringData: cm.Data,
  1107.                                 ByteData:   cm.BinaryData,
  1108.                         }
  1109.                         err := commonUpsertRanger(dv, key, payload)
  1110.                         if err != nil </span><span class="cov0" title="0">{
  1111.                                 ProcessFileSystemError(cm, err)
  1112.                         }</span>
  1113.  
  1114.                         // we always return true in the golang ranger to still attempt additional items
  1115.                         // on the off chance the filesystem error received was intermittent and other items
  1116.                         // will succeed ... remember, the ranger predominantly deals with pushing secret/configmap
  1117.                         // updates to disk
  1118.                         <span class="cov0" title="0">return true</span>
  1119.                 }
  1120.                 // we call the upsert ranger inline in case there are filesystem problems initially, so
  1121.                 // we can return the error back to volume provisioning, where the kubelet will retry at
  1122.                 // a controlled frequency
  1123.                 <span class="cov8" title="1">sharedConfigMap := client.GetSharedConfigMap(dv.GetSharedDataId())
  1124.                 if sharedConfigMap == nil </span><span class="cov0" title="0">{
  1125.                         klog.V(4).Infof("mapBackingResourceToPod for pod volume %s:%s:%s share %s no longer exists", dv.GetPodNamespace(), dv.GetPodName(), dv.GetVolID(), dv.GetSharedDataId())
  1126.                         return nil
  1127.                 }</span>
  1128.                 <span class="cov8" title="1">cmNamespace := sharedConfigMap.Spec.ConfigMapRef.Namespace
  1129.                 cmName := sharedConfigMap.Spec.ConfigMapRef.Name
  1130.                 comboKey := objcache.BuildKey(cmNamespace, cmName)
  1131.                 cm := client.GetConfigMap(cmNamespace, cmName)
  1132.                 if cm != nil </span><span class="cov8" title="1">{
  1133.                         payload := Payload{
  1134.                                 StringData: cm.Data,
  1135.                                 ByteData:   cm.BinaryData,
  1136.                         }
  1137.  
  1138.                         upsertError := commonUpsertRanger(dv, comboKey, payload)
  1139.                         if upsertError != nil </span><span class="cov0" title="0">{
  1140.                                 ProcessFileSystemError(cm, upsertError)
  1141.                                 return upsertError
  1142.                         }</span>
  1143.                 }
  1144.                 <span class="cov8" title="1">if dv.IsRefresh() </span><span class="cov8" title="1">{
  1145.                         objcache.RegisterConfigMapUpsertCallback(dv.GetVolID(), comboKey, upsertRangerCM)
  1146.                 }</span>
  1147.                 <span class="cov8" title="1">deleteRangerCM := func(key, value interface{}) bool </span><span class="cov8" title="1">{
  1148.                         return commonDeleteRanger(dv, key)
  1149.                 }</span>
  1150.                 //we should register delete callbacks regardless of any per volume refresh setting to account for removed permissions
  1151.                 <span class="cov8" title="1">objcache.RegisterConfigMapDeleteCallback(dv.GetVolID(), deleteRangerCM)</span>
  1152.         case consts.ResourceReferenceTypeSecret:<span class="cov8" title="1">
  1153.                 klog.V(4).Infof("mapBackingResourceToPod postlock %s secret", dv.GetVolID())
  1154.                 upsertRangerSec := func(key, value interface{}) bool </span><span class="cov0" title="0">{
  1155.                         s, _ := value.(*corev1.Secret)
  1156.                         payload := Payload{
  1157.                                 ByteData: s.Data,
  1158.                         }
  1159.                         err := commonUpsertRanger(dv, key, payload)
  1160.                         if err != nil </span><span class="cov0" title="0">{
  1161.                                 ProcessFileSystemError(s, err)
  1162.                         }</span>
  1163.                         // we always return true in the golang ranger to still attempt additional items
  1164.                         // on the off chance the filesystem error received was intermittent and other items
  1165.                         // will succeed ... remember, the ranger predominantly deals with pushing secret/configmap
  1166.                         // updates to disk
  1167.                         <span class="cov0" title="0">return true</span>
  1168.                 }
  1169.                 // we call the upsert ranger inline in case there are filesystem problems initially,  so
  1170.                 // we can return the error back to volume provisioning, where the kubelet will retry at
  1171.                 // a controlled frequency
  1172.                 <span class="cov8" title="1">sharedSecret := client.GetSharedSecret(dv.GetSharedDataId())
  1173.                 sNamespace := sharedSecret.Spec.SecretRef.Namespace
  1174.                 sName := sharedSecret.Spec.SecretRef.Name
  1175.                 comboKey := objcache.BuildKey(sNamespace, sName)
  1176.                 s := client.GetSecret(sNamespace, sName)
  1177.                 if s != nil </span><span class="cov8" title="1">{
  1178.                         payload := Payload{
  1179.                                 ByteData: s.Data,
  1180.                         }
  1181.  
  1182.                         upsertError := commonUpsertRanger(dv, comboKey, payload)
  1183.                         if upsertError != nil </span><span class="cov0" title="0">{
  1184.                                 ProcessFileSystemError(s, upsertError)
  1185.                                 return upsertError
  1186.                         }</span>
  1187.                 }
  1188.                 <span class="cov8" title="1">if dv.IsRefresh() </span><span class="cov8" title="1">{
  1189.                         objcache.RegisterSecretUpsertCallback(dv.GetVolID(), comboKey, upsertRangerSec)
  1190.                 }</span>
  1191.                 <span class="cov8" title="1">deleteRangerSec := func(key, value interface{}) bool </span><span class="cov8" title="1">{
  1192.                         return commonDeleteRanger(dv, key)
  1193.                 }</span>
  1194.                 //we should register delete callbacks regardless of any per volume refresh setting to account for removed permissions
  1195.                 <span class="cov8" title="1">objcache.RegisterSecretDeleteCallback(dv.GetVolID(), deleteRangerSec)</span>
  1196.         default:<span class="cov0" title="0">
  1197.                 return fmt.Errorf("invalid share backing resource kind %s", dv.GetSharedDataKind())</span>
  1198.         }
  1199.         <span class="cov8" title="1">return nil</span>
  1200. }
  1201.  
  1202. func (d *driver) mapVolumeToPod(dv *driverVolume) error <span class="cov8" title="1">{
  1203.         klog.V(4).Infof("mapVolumeToPod calling mapBackingResourceToPod")
  1204.  
  1205.         err := mapBackingResourceToPod(dv)
  1206.         if err != nil </span><span class="cov0" title="0">{
  1207.                 return err
  1208.         }</span>
  1209.         <span class="cov8" title="1">d.registerRangers(dv)
  1210.  
  1211.         return nil</span>
  1212. }
  1213.  
  1214. func (d *driver) registerRangers(dv *driverVolume) <span class="cov8" title="1">{
  1215.         deleteRangerShare := func(key, value interface{}) bool </span><span class="cov8" title="1">{
  1216.                 return shareDeleteRanger(key)
  1217.         }</span>
  1218.         <span class="cov8" title="1">updateRangerShare := func(key, value interface{}) bool </span><span class="cov8" title="1">{
  1219.                 return shareUpdateRanger(key, value)
  1220.         }</span>
  1221.         <span class="cov8" title="1">switch dv.GetSharedDataKind() </span>{
  1222.         case consts.ResourceReferenceTypeSecret:<span class="cov8" title="1">
  1223.                 objcache.RegisterSharedSecretUpdateCallback(dv.GetVolID(), dv.GetSharedDataId(), updateRangerShare)
  1224.                 objcache.RegisteredSharedSecretDeleteCallback(dv.GetVolID(), deleteRangerShare)</span>
  1225.         case consts.ResourceReferenceTypeConfigMap:<span class="cov8" title="1">
  1226.                 objcache.RegisterSharedConfigMapUpdateCallback(dv.GetVolID(), dv.GetSharedDataId(), updateRangerShare)
  1227.                 objcache.RegisterSharedConfigMapDeleteCallback(dv.GetVolID(), deleteRangerShare)</span>
  1228.         }
  1229.  
  1230. }
  1231.  
  1232. // createVolume create the directory for the csidriver volume.
  1233. // It returns the volume path or err if one occurs.
  1234. func (d *driver) createVolume(volID, targetPath string, refresh bool, volCtx map[string]string, cmShare *sharev1alpha1.SharedConfigMap, sShare *sharev1alpha1.SharedSecret, cap int64, volAccessType accessType) (*driverVolume, error) <span class="cov8" title="1">{
  1235.         if cmShare != nil &amp;&amp; sShare != nil </span><span class="cov0" title="0">{
  1236.                 return nil, fmt.Errorf("cannot store both SharedConfigMap and SharedSecret in a volume")
  1237.         }</span>
  1238.         <span class="cov8" title="1">if cmShare == nil &amp;&amp; sShare == nil </span><span class="cov0" title="0">{
  1239.                 return nil, fmt.Errorf("have to provide either a SharedConfigMap or SharedSecret to a volume")
  1240.         }</span>
  1241.         <span class="cov8" title="1">dv := d.getVolume(volID)
  1242.         if dv != nil </span><span class="cov8" title="1">{
  1243.                 klog.V(0).Infof("createVolume: create call came in for volume %s that we have already created; returning previously created instance", volID)
  1244.                 return dv, nil
  1245.         }</span>
  1246.         <span class="cov8" title="1">anchorDir, bindDir := d.getVolumePath(volID, volCtx)
  1247.         switch volAccessType </span>{
  1248.         case mountAccess:<span class="cov8" title="1">
  1249.                 err := os.MkdirAll(anchorDir, 0777)
  1250.                 if err != nil </span><span class="cov0" title="0">{
  1251.                         return nil, err
  1252.                 }</span>
  1253.         default:<span class="cov8" title="1">
  1254.                 return nil, fmt.Errorf("unsupported access type %v", volAccessType)</span>
  1255.         }
  1256.  
  1257.         <span class="cov8" title="1">podNamespace, podName, podUID, podSA := getPodDetails(volCtx)
  1258.         vol := CreateDV(volID)
  1259.         vol.SetVolSize(cap)
  1260.         vol.SetVolPathAnchorDir(anchorDir)
  1261.         vol.SetVolPathBindMountDir(bindDir)
  1262.         vol.SetVolAccessType(volAccessType)
  1263.         vol.SetTargetPath(targetPath)
  1264.         vol.SetPodNamespace(podNamespace)
  1265.         vol.SetPodName(podName)
  1266.         vol.SetPodUID(podUID)
  1267.         vol.SetPodSA(podSA)
  1268.         vol.SetRefresh(refresh)
  1269.         switch </span>{
  1270.         case cmShare != nil:<span class="cov8" title="1">
  1271.                 vol.SetSharedDataKind(string(consts.ResourceReferenceTypeConfigMap))
  1272.                 vol.SetSharedDataId(cmShare.Name)</span>
  1273.         case sShare != nil:<span class="cov8" title="1">
  1274.                 vol.SetSharedDataKind(string(consts.ResourceReferenceTypeSecret))
  1275.                 vol.SetSharedDataId(sShare.Name)</span>
  1276.         }
  1277.  
  1278.         <span class="cov8" title="1">return vol, nil</span>
  1279. }
  1280.  
  1281. func isDirEmpty(name string) (bool, error) <span class="cov0" title="0">{
  1282.         f, err := os.Open(name)
  1283.         if err != nil </span><span class="cov0" title="0">{
  1284.                 klog.Warningf("error opening %s during empty check: %s", name, err.Error())
  1285.                 return false, err
  1286.         }</span>
  1287.         <span class="cov0" title="0">defer f.Close()
  1288.  
  1289.         _, err = f.Readdirnames(1) // Or f.Readdir(1)
  1290.         if err == io.EOF </span><span class="cov0" title="0">{
  1291.                 return true, nil
  1292.         }</span>
  1293.         <span class="cov0" title="0">return false, err</span> // Either not empty or error, suits both cases
  1294. }
  1295.  
  1296. func deleteIfEmpty(name string) <span class="cov0" title="0">{
  1297.         if empty, err := isDirEmpty(name); empty &amp;&amp; err == nil </span><span class="cov0" title="0">{
  1298.                 klog.V(4).Infof("deleteIfEmpty %s", name)
  1299.                 err = os.RemoveAll(name)
  1300.                 if err != nil </span><span class="cov0" title="0">{
  1301.                         klog.Warningf("error deleting %s: %s", name, err.Error())
  1302.                 }</span>
  1303.         }
  1304. }
  1305.  
  1306. func (d *driver) innerDeleteVolume(top string) <span class="cov0" title="0">{
  1307.         // reminder, path is filepath.Join(DataRoot, [anchor-dir | bind-dir], volID, podNamespace, podName, podUID, podSA)
  1308.         // delete SA dir
  1309.         klog.V(4).Infof("innerDeleteVolume %s", top)
  1310.         err := os.RemoveAll(top)
  1311.         if err != nil </span><span class="cov0" title="0">{
  1312.                 klog.Warningf("error deleting %s: %s", top, err.Error())
  1313.         }</span>
  1314.         <span class="cov0" title="0">currentLocation := top
  1315.         // we deleteIfEmpty on the remaining 4 levels
  1316.         for i := 0; i &lt; 4; i++ </span><span class="cov0" title="0">{
  1317.                 parentDir := filepath.Dir(currentLocation)
  1318.                 deleteIfEmpty(parentDir)
  1319.                 currentLocation = parentDir
  1320.         }</span>
  1321. }
  1322.  
  1323. // deleteVolume deletes the directory for the csidriver volume.
  1324. func (d *driver) deleteVolume(volID string) error <span class="cov8" title="1">{
  1325.         klog.V(4).Infof("deleting csidriver volume: %s", volID)
  1326.  
  1327.         if dv := d.getVolume(volID); dv != nil </span><span class="cov8" title="1">{
  1328.                 klog.V(4).Infof("found volume: %s", volID)
  1329.                 os.RemoveAll(dv.GetTargetPath())
  1330.                 remV(volID)
  1331.         }</span>
  1332.         <span class="cov8" title="1">objcache.UnregisterSecretUpsertCallback(volID)
  1333.         objcache.UnregisterSecretDeleteCallback(volID)
  1334.         objcache.UnregisterConfigMapUpsertCallback(volID)
  1335.         objcache.UnregisterConfigMapDeleteCallback(volID)
  1336.         objcache.UnregisterSharedConfigMapDeleteCallback(volID)
  1337.         objcache.UnregisterSharedConfigMapUpdateCallback(volID)
  1338.         objcache.UnregisterSharedSecretDeleteCallback(volID)
  1339.         objcache.UnregsiterSharedSecretsUpdateCallback(volID)
  1340.         return nil</span>
  1341. }
  1342.  
  1343. func (d *driver) loadVolsFromDisk() error <span class="cov8" title="1">{
  1344.         klog.V(2).Infof("loadVolsFromDisk")
  1345.         defer klog.V(2).Infof("loadVolsFromDisk exit")
  1346.         return filepath.Walk(d.volMapRoot, func(path string, info os.FileInfo, err error) error </span><span class="cov8" title="1">{
  1347.                 if info == nil </span><span class="cov0" title="0">{
  1348.                         return nil
  1349.                 }</span>
  1350.                 <span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
  1351.                         // continue to next file
  1352.                         return nil
  1353.                 }</span>
  1354.                 <span class="cov8" title="1">if info.IsDir() </span><span class="cov8" title="1">{
  1355.                         return nil
  1356.                 }</span>
  1357.                 <span class="cov0" title="0">fileName := filepath.Join(d.volMapRoot, info.Name())
  1358.                 dataFile, oerr := os.Open(fileName)
  1359.                 if oerr != nil </span><span class="cov0" title="0">{
  1360.                         klog.V(0).Infof("loadVolsFromDisk error opening file %s: %s", fileName, err.Error())
  1361.                         // continue to next file
  1362.                         return nil
  1363.                 }</span>
  1364.                 <span class="cov0" title="0">dataDecoder := json.NewDecoder(dataFile)
  1365.                 dv := &amp;driverVolume{}
  1366.                 err = dataDecoder.Decode(dv)
  1367.                 if err != nil </span><span class="cov0" title="0">{
  1368.                         klog.V(0).Infof("loadVolsFromDisk error decoding file %s: %s", fileName, err.Error())
  1369.                         // continue to next file
  1370.                         return nil
  1371.                 }</span>
  1372.                 <span class="cov0" title="0">if dv == nil </span><span class="cov0" title="0">{
  1373.                         klog.V(0).Infof("loadVolsFromDisk nil but no error for file %s", fileName)
  1374.                         // continue to next file
  1375.                         return nil
  1376.                 }</span>
  1377.                 <span class="cov0" title="0">dv.Lock = &amp;sync.Mutex{}
  1378.                 if filepath.Base(fileName) != dv.GetVolID() </span><span class="cov0" title="0">{
  1379.                         klog.Warningf("loadVolsFromDisk file %s had vol id %s - corrupted !!!", dv.GetVolID())
  1380.                         return nil
  1381.                 }</span>
  1382.                 <span class="cov0" title="0">klog.V(2).Infof("loadVolsFromDisk storing with key %s dv %#v", dv.GetVolID(), dv)
  1383.                 setDPV(dv.GetVolID(), dv)
  1384.                 d.registerRangers(dv)
  1385.  
  1386.                 return nil</span>
  1387.         })
  1388. }
  1389.  
  1390. // Prune inspects all the volumes stored on disk and checks if their associated pods still exists.  If not, the volume
  1391. // file in question is deleted from disk.
  1392. func (d *driver) Prune(kubeClient kubernetes.Interface) <span class="cov8" title="1">{
  1393.         filesToPrune := map[string]driverVolume{}
  1394.         filepath.Walk(d.volMapRoot, func(path string, info os.FileInfo, err error) error </span><span class="cov8" title="1">{
  1395.                 if info == nil </span><span class="cov0" title="0">{
  1396.                         return nil
  1397.                 }</span>
  1398.                 <span class="cov8" title="1">if err != nil </span><span class="cov0" title="0">{
  1399.                         // continue to next file
  1400.                         klog.V(5).Infof("Prune: for path %s given error %s", path, err.Error())
  1401.                         return nil
  1402.                 }</span>
  1403.                 <span class="cov8" title="1">if info.IsDir() </span><span class="cov8" title="1">{
  1404.                         return nil
  1405.                 }</span>
  1406.                 <span class="cov8" title="1">fileName := filepath.Join(d.volMapRoot, info.Name())
  1407.                 dataFile, oerr := os.Open(fileName)
  1408.                 if oerr != nil </span><span class="cov0" title="0">{
  1409.                         klog.V(0).Infof("loadVolsFromDisk error opening file %s: %s", fileName, err.Error())
  1410.                         // continue to next file
  1411.                         return nil
  1412.                 }</span>
  1413.                 <span class="cov8" title="1">dataDecoder := json.NewDecoder(dataFile)
  1414.                 dv := &amp;driverVolume{}
  1415.                 err = dataDecoder.Decode(dv)
  1416.                 if err != nil </span><span class="cov0" title="0">{
  1417.                         klog.V(0).Infof("loadVolsFromDisk error decoding file %s: %s", fileName, err.Error())
  1418.                         // continue to next file
  1419.                         return nil
  1420.                 }</span>
  1421.                 <span class="cov8" title="1">if dv == nil </span><span class="cov0" title="0">{
  1422.                         klog.V(0).Infof("loadVolsFromDisk nil but no error for file %s", fileName)
  1423.                         // continue to next file
  1424.                         return nil
  1425.                 }</span>
  1426.                 <span class="cov8" title="1">dv.Lock = &amp;sync.Mutex{}
  1427.                 _, err = kubeClient.CoreV1().Pods(dv.GetPodNamespace()).Get(context.TODO(), dv.GetPodName(), metav1.GetOptions{})
  1428.                 if err != nil &amp;&amp; kerrors.IsNotFound(err) </span><span class="cov8" title="1">{
  1429.                         klog.V(2).Infof("pruner: dv %q: %s", fileName, err.Error())
  1430.                         filesToPrune[fileName] = *dv
  1431.                 }</span>
  1432.                 <span class="cov8" title="1">return nil</span>
  1433.         })
  1434.         <span class="cov8" title="1">if len(filesToPrune) == 0 </span><span class="cov0" title="0">{
  1435.                 return
  1436.         }</span>
  1437.         // a bit paranoid, but not deleting files in the walk loop in case that can mess up filepath.Walk's iteration logic
  1438.         <span class="cov8" title="1">for file, dv := range filesToPrune </span><span class="cov8" title="1">{
  1439.                 err := os.Remove(file)
  1440.                 if err != nil </span><span class="cov0" title="0">{
  1441.                         klog.Warningf("pruner: unable to prune file %q: %s", file, err.Error())
  1442.                         continue</span>
  1443.                 }
  1444.                 <span class="cov8" title="1">klog.V(2).Infof("pruner: removed volume file %q with missing pod from disk", file)
  1445.                 if d.mounter != nil </span><span class="cov8" title="1">{
  1446.                         err = d.mounter.Unmount(dv.GetVolPathAnchorDir())
  1447.                         if err != nil </span><span class="cov0" title="0">{
  1448.                                 klog.Warningf("pruner: issue unmounting for volume %s mount id %s: %s", dv.GetVolID(), dv.GetVolPathAnchorDir(), err.Error())
  1449.                         }</span> else<span class="cov8" title="1"> {
  1450.                                 klog.V(2).Infof("pruner: successfully unmounted volume %s mount id %s", dv.GetVolID(), dv.GetVolPathAnchorDir())
  1451.                         }</span>
  1452.                 }
  1453.         }
  1454.  
  1455. }
  1456. </pre>
  1457.        
  1458.         <pre class="file" id="file5" style="display: none">package csidriver
  1459.  
  1460. import (
  1461.         "fmt"
  1462.  
  1463.         corev1 "k8s.io/api/core/v1"
  1464.         "k8s.io/apimachinery/pkg/runtime"
  1465.         "k8s.io/klog/v2"
  1466.  
  1467.         "github.com/openshift/csi-driver-shared-resource/pkg/client"
  1468. )
  1469.  
  1470. type Payload struct {
  1471.         StringData map[string]string
  1472.         ByteData   map[string][]byte
  1473. }
  1474.  
  1475. func ProcessFileSystemError(obj runtime.Object, err error) <span class="cov0" title="0">{
  1476.         msg := fmt.Sprintf("%s", err.Error())
  1477.         klog.Errorf(msg)
  1478.         client.GetRecorder().Eventf(obj, corev1.EventTypeWarning, "FileSystemError", msg)
  1479.  
  1480. }</span>
  1481. </pre>
  1482.        
  1483.         <pre class="file" id="file6" style="display: none">/*
  1484. Copyright 2017 The Kubernetes Authors.
  1485.  
  1486. Licensed under the Apache License, Version 2.0 (the "License");
  1487. you may not use this file except in compliance with the License.
  1488. You may obtain a copy of the License at
  1489.  
  1490.     http://www.apache.org/licenses/LICENSE-2.0
  1491.  
  1492. Unless required by applicable law or agreed to in writing, software
  1493. distributed under the License is distributed on an "AS IS" BASIS,
  1494. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1495. See the License for the specific language governing permissions and
  1496. limitations under the License.
  1497. */
  1498.  
  1499. package csidriver
  1500.  
  1501. import (
  1502.         "github.com/container-storage-interface/spec/lib/go/csi"
  1503.         "golang.org/x/net/context"
  1504.         "google.golang.org/grpc/codes"
  1505.         "google.golang.org/grpc/status"
  1506.  
  1507.         "k8s.io/klog/v2"
  1508. )
  1509.  
  1510. type identityServer struct {
  1511.         name    string
  1512.         version string
  1513. }
  1514.  
  1515. func NewIdentityServer(name, version string) *identityServer <span class="cov0" title="0">{
  1516.         return &amp;identityServer{
  1517.                 name:    name,
  1518.                 version: version,
  1519.         }
  1520. }</span>
  1521.  
  1522. func (ids *identityServer) GetPluginInfo(ctx context.Context, req *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) <span class="cov0" title="0">{
  1523.         klog.V(5).Infof("Using default GetPluginInfo")
  1524.  
  1525.         if ids.name == "" </span><span class="cov0" title="0">{
  1526.                 return nil, status.Error(codes.Unavailable, "Driver name not configured")
  1527.         }</span>
  1528.  
  1529.         <span class="cov0" title="0">if ids.version == "" </span><span class="cov0" title="0">{
  1530.                 return nil, status.Error(codes.Unavailable, "Driver is missing version")
  1531.         }</span>
  1532.  
  1533.         <span class="cov0" title="0">return &amp;csi.GetPluginInfoResponse{
  1534.                 Name:          ids.name,
  1535.                 VendorVersion: ids.version,
  1536.         }, nil</span>
  1537. }
  1538.  
  1539. func (ids *identityServer) Probe(ctx context.Context, req *csi.ProbeRequest) (*csi.ProbeResponse, error) <span class="cov0" title="0">{
  1540.         return &amp;csi.ProbeResponse{}, nil
  1541. }</span>
  1542.  
  1543. func (ids *identityServer) GetPluginCapabilities(ctx context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) <span class="cov0" title="0">{
  1544.         klog.V(5).Infof("Using default capabilities")
  1545.         return &amp;csi.GetPluginCapabilitiesResponse{
  1546.                 Capabilities: []*csi.PluginCapability{
  1547.                         // Even with the use of a DaemonSet so that this plugin runs on every node, this plugin does not
  1548.                         // guarantee that the *same* volume is present on all nodes; now, equivalent data could be present
  1549.                         // on different nodes via different volumes, as a function of different pods residing on different
  1550.                         // nodes have access to the same subset of shared configmpas/secrets, but that does not satisfy
  1551.                         // the definition around csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS
  1552.                         {
  1553.                                 Type: &amp;csi.PluginCapability_Service_{
  1554.                                         Service: &amp;csi.PluginCapability_Service{
  1555.                                                 Type: csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS,
  1556.                                         },
  1557.                                 },
  1558.                         },
  1559.                 },
  1560.         }, nil
  1561. }</span>
  1562. </pre>
  1563.        
  1564.         <pre class="file" id="file7" style="display: none">package csidriver
  1565.  
  1566. import (
  1567.         "fmt"
  1568.         "google.golang.org/grpc/codes"
  1569.         "google.golang.org/grpc/status"
  1570.  
  1571.         "k8s.io/utils/mount"
  1572. )
  1573.  
  1574. type FileSystemMounter interface {
  1575.         makeFSMounts(mountIDString, intermediateBindMountDir, kubeletTargetDir string, mounter mount.Interface) error
  1576.         removeFSMounts(mountIDString, intermediateBindMountDir, kubeletTargetDir string, mount mount.Interface) error
  1577. }
  1578.  
  1579. // ReadWriteMany high level details:
  1580. //
  1581. // This is our original landing spot wrt mounting the file system this driver manipulates
  1582. // to where the location the kubelet has allocated for the CSI volume in question.
  1583. //
  1584. // We go straight from our "identifier" string based on input from Jan to the kubelet's target directory.  No bind mounts.
  1585. // But this approach only works if the K8s CSIVolumenSource set readOnly to false.  If readOnly
  1586. // is set to true, the underlying mount mechanics between our call to m.mounter.Mount and what
  1587. // the kubelet does for the Pod results in the use of xfs for the filesystem and an inability for the
  1588. // Pod to read what we have mounted.
  1589. //
  1590. // Additional details:
  1591. //
  1592. // So our intent here is to have a separate tmpfs per pod; through experimentation
  1593. // and corroboration with OpenShift storage SMEs, a separate tmpfs per pod
  1594. // - ensures the kubelet will handle SELinux for us. It will relabel the volume in "the right way" just for the pod
  1595. // - otherwise, if pods share the same host dir, all sorts of warnings from the SMEs
  1596. // - and the obvious isolation between pods that implies
  1597. // We cannot do read-only on the mount since we have to copy the data after the mount, otherwise we get errors
  1598. // that the filesystem is readonly.
  1599. // However, we can restart this driver, leave up any live Pods with our volume, and then still update the content
  1600. // after this driver comes backup.
  1601. // The various bits that work in concert to achieve this
  1602. // - the use of emptyDir with a medium of Memory in this drivers Deployment is all that is needed to get tmpfs
  1603. // - do not use the "bind" option, that reuses existing dirs/filesystems vs. creating new tmpfs
  1604. // - without bind, we have to specify an fstype of tmpfs and path for the mount source, or we get errors on the
  1605. //   Mount about the fs not being  block access
  1606. // - that said,  testing confirmed using fstype of tmpfs on hostpath/xfs volumes still results in the target
  1607. //   being xfs and not tmpfs
  1608. // - with the lack of a bind option, and each pod getting its own tmpfs we have to copy the data from our emptydir
  1609. //   based location to the targetPath here ... that is handled in driver.go
  1610. type ReadWriteMany struct {
  1611. }
  1612.  
  1613. func (m *ReadWriteMany) makeFSMounts(mountIDString, intermediateBindMountDir, kubeletTargetDir string, mounter mount.Interface) error <span class="cov8" title="1">{
  1614.         options := []string{}
  1615.         if err := mounter.Mount(mountIDString, kubeletTargetDir, "tmpfs", options); err != nil </span><span class="cov0" title="0">{
  1616.                 return status.Error(codes.Internal, fmt.Sprintf("failed to mount device: %s at %s: %s",
  1617.                         mountIDString,
  1618.                         kubeletTargetDir,
  1619.                         err.Error()))
  1620.         }</span>
  1621.         <span class="cov8" title="1">return nil</span>
  1622. }
  1623.  
  1624. func (m *ReadWriteMany) removeFSMounts(mountIDString, intermediateBindMountDir, kubeletTargetDir string, mounter mount.Interface) error <span class="cov0" title="0">{
  1625.         // mount.CleanupMountPoint proved insufficient for us, as it always considered our mountIDString here "not a mount", even
  1626.         // though we would rsh into the driver container/pod and manually run 'umount'.  If we did not do this, then
  1627.         // the termination of pods using our CSI driver could hang.  So we just directly call Unmount from out mounter.
  1628.         if err := mounter.Unmount(mountIDString); err != nil </span><span class="cov0" title="0">{
  1629.                 return status.Error(codes.Internal, fmt.Sprintf("failed to umount device: %s at %s and %s: %s",
  1630.                         mountIDString,
  1631.                         intermediateBindMountDir,
  1632.                         kubeletTargetDir,
  1633.                         err.Error()))
  1634.         }</span>
  1635.         <span class="cov0" title="0">return nil</span>
  1636. }
  1637. </pre>
  1638.        
  1639.         <pre class="file" id="file8" style="display: none">/*
  1640. Copyright 2017 The Kubernetes Authors.
  1641.  
  1642. Licensed under the Apache License, Version 2.0 (the "License");
  1643. you may not use this file except in compliance with the License.
  1644. You may obtain a copy of the License at
  1645.  
  1646.     http://www.apache.org/licenses/LICENSE-2.0
  1647.  
  1648. Unless required by applicable law or agreed to in writing, software
  1649. distributed under the License is distributed on an "AS IS" BASIS,
  1650. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1651. See the License for the specific language governing permissions and
  1652. limitations under the License.
  1653. */
  1654.  
  1655. package csidriver
  1656.  
  1657. import (
  1658.         "fmt"
  1659.         "os"
  1660.         "path/filepath"
  1661.         "strconv"
  1662.         "strings"
  1663.  
  1664.         "github.com/container-storage-interface/spec/lib/go/csi"
  1665.         sharev1alpha1 "github.com/openshift/api/sharedresource/v1alpha1"
  1666.         "github.com/openshift/csi-driver-shared-resource/pkg/client"
  1667.         "github.com/openshift/csi-driver-shared-resource/pkg/consts"
  1668.         "github.com/openshift/csi-driver-shared-resource/pkg/metrics"
  1669.         "golang.org/x/net/context"
  1670.         "google.golang.org/grpc/codes"
  1671.         "google.golang.org/grpc/status"
  1672.  
  1673.         "k8s.io/klog/v2"
  1674.         "k8s.io/utils/mount"
  1675. )
  1676.  
  1677. var (
  1678.         listers client.Listers
  1679. )
  1680.  
  1681. type nodeServer struct {
  1682.         nodeID            string
  1683.         maxVolumesPerNode int64
  1684.         d                 CSIDriver
  1685.         readWriteMounter  FileSystemMounter
  1686.         mounter           mount.Interface
  1687. }
  1688.  
  1689. func NewNodeServer(d *driver) *nodeServer <span class="cov0" title="0">{
  1690.         return &amp;nodeServer{
  1691.                 nodeID:            d.nodeID,
  1692.                 maxVolumesPerNode: d.maxVolumesPerNode,
  1693.                 d:                 d,
  1694.                 mounter:           mount.New(""),
  1695.                 readWriteMounter:  &amp;ReadWriteMany{},
  1696.         }
  1697. }</span>
  1698.  
  1699. func getPodDetails(volumeContext map[string]string) (string, string, string, string) <span class="cov8" title="1">{
  1700.         podName, _ := volumeContext[CSIPodName]
  1701.         podNamespace, _ := volumeContext[CSIPodNamespace]
  1702.         podSA, _ := volumeContext[CSIPodSA]
  1703.         podUID, _ := volumeContext[CSIPodUID]
  1704.         return podNamespace, podName, podUID, podSA
  1705.  
  1706. }</span>
  1707.  
  1708. func (ns *nodeServer) validateShare(req *csi.NodePublishVolumeRequest) (*sharev1alpha1.SharedConfigMap, *sharev1alpha1.SharedSecret, error) <span class="cov8" title="1">{
  1709.         configMapShareName, cmok := req.GetVolumeContext()[SharedConfigMapShareKey]
  1710.         secretShareName, sok := req.GetVolumeContext()[SharedSecretShareKey]
  1711.         if (!cmok &amp;&amp; !sok) || (len(strings.TrimSpace(configMapShareName)) == 0 &amp;&amp; len(strings.TrimSpace(secretShareName)) == 0) </span><span class="cov8" title="1">{
  1712.                 return nil, nil, status.Errorf(codes.InvalidArgument,
  1713.                         "the csi driver reference is missing the volumeAttribute %q and %q", SharedSecretShareKey, SharedConfigMapShareKey)
  1714.         }</span>
  1715.         <span class="cov8" title="1">if (cmok &amp;&amp; sok) || (len(strings.TrimSpace(configMapShareName)) &gt; 0 &amp;&amp; len(strings.TrimSpace(secretShareName)) &gt; 0) </span><span class="cov8" title="1">{
  1716.                 return nil, nil, status.Errorf(codes.InvalidArgument,
  1717.                         "a single volume cannot support both a SharedConfigMap reference %q and SharedSecret reference %q",
  1718.                         configMapShareName, secretShareName)
  1719.         }</span>
  1720.  
  1721.         <span class="cov8" title="1">var cmShare *sharev1alpha1.SharedConfigMap
  1722.         var sShare *sharev1alpha1.SharedSecret
  1723.         var err error
  1724.         allowed := false
  1725.         if len(configMapShareName) &gt; 0 </span><span class="cov8" title="1">{
  1726.                 cmShare, err = client.GetListers().SharedConfigMaps.Get(configMapShareName)
  1727.                 if err != nil </span><span class="cov0" title="0">{
  1728.                         return nil, nil, status.Errorf(codes.InvalidArgument,
  1729.                                 "the csi driver volumeAttribute %q reference had an error: %s", configMapShareName, err.Error())
  1730.                 }</span>
  1731.         }
  1732.         <span class="cov8" title="1">if len(secretShareName) &gt; 0 </span><span class="cov8" title="1">{
  1733.                 sShare, err = client.GetListers().SharedSecrets.Get(secretShareName)
  1734.                 if err != nil </span><span class="cov0" title="0">{
  1735.                         return nil, nil, status.Errorf(codes.InvalidArgument,
  1736.                                 "the csi driver volumeAttribute %q reference had an error: %s", secretShareName, err.Error())
  1737.                 }</span>
  1738.         }
  1739.  
  1740.         <span class="cov8" title="1">if sShare == nil &amp;&amp; cmShare == nil </span><span class="cov0" title="0">{
  1741.                 return nil, nil, status.Errorf(codes.InvalidArgument,
  1742.                         "volumeAttributes did not reference a valid SharedSecret or SharedConfigMap")
  1743.         }</span>
  1744.  
  1745.         <span class="cov8" title="1">podNamespace, podName, _, podSA := getPodDetails(req.GetVolumeContext())
  1746.         shareName := ""
  1747.         kind := consts.ResourceReferenceTypeConfigMap
  1748.         if cmShare != nil </span><span class="cov8" title="1">{
  1749.                 if len(strings.TrimSpace(cmShare.Spec.ConfigMapRef.Namespace)) == 0 </span><span class="cov8" title="1">{
  1750.                         return nil, nil, status.Errorf(codes.InvalidArgument,
  1751.                                 "the SharedConfigMap %q backing resource namespace needs to be set", configMapShareName)
  1752.                 }</span>
  1753.                 <span class="cov8" title="1">if len(strings.TrimSpace(cmShare.Spec.ConfigMapRef.Name)) == 0 </span><span class="cov8" title="1">{
  1754.                         return nil, nil, status.Errorf(codes.InvalidArgument,
  1755.                                 "the SharedConfigMap %q backing resource name needs to be set", configMapShareName)
  1756.                 }</span>
  1757.                 <span class="cov8" title="1">shareName = configMapShareName</span>
  1758.         }
  1759.         <span class="cov8" title="1">if sShare != nil </span><span class="cov8" title="1">{
  1760.                 kind = consts.ResourceReferenceTypeSecret
  1761.                 if len(strings.TrimSpace(sShare.Spec.SecretRef.Namespace)) == 0 </span><span class="cov8" title="1">{
  1762.                         return nil, nil, status.Errorf(codes.InvalidArgument,
  1763.                                 "the SharedSecret %q backing resource namespace needs to be set", secretShareName)
  1764.                 }</span>
  1765.                 <span class="cov8" title="1">if len(strings.TrimSpace(sShare.Spec.SecretRef.Name)) == 0 </span><span class="cov8" title="1">{
  1766.                         return nil, nil, status.Errorf(codes.InvalidArgument,
  1767.                                 "the SharedSecret %q backing resource name needs to be set", secretShareName)
  1768.                 }</span>
  1769.                 <span class="cov8" title="1">shareName = secretShareName</span>
  1770.         }
  1771.  
  1772.         <span class="cov8" title="1">allowed, err = client.ExecuteSAR(shareName, podNamespace, podName, podSA, kind)
  1773.         if allowed </span><span class="cov8" title="1">{
  1774.                 return cmShare, sShare, nil
  1775.         }</span>
  1776.         <span class="cov8" title="1">return nil, nil, err</span>
  1777. }
  1778.  
  1779. // validateVolumeContext return values:
  1780. func (ns *nodeServer) validateVolumeContext(req *csi.NodePublishVolumeRequest) error <span class="cov8" title="1">{
  1781.  
  1782.         podNamespace, podName, podUID, podSA := getPodDetails(req.GetVolumeContext())
  1783.         klog.V(4).Infof("NodePublishVolume pod %s ns %s sa %s uid %s",
  1784.                 podName,
  1785.                 podNamespace,
  1786.                 podSA,
  1787.                 podUID)
  1788.  
  1789.         if len(podName) == 0 || len(podNamespace) == 0 || len(podUID) == 0 || len(podSA) == 0 </span><span class="cov8" title="1">{
  1790.                 return status.Error(codes.InvalidArgument,
  1791.                         fmt.Sprintf("Volume attributes missing required set for pod: namespace: %s name: %s uid: %s, sa: %s",
  1792.                                 podNamespace, podName, podUID, podSA))
  1793.         }</span>
  1794.         <span class="cov8" title="1">ephemeralVolume := req.GetVolumeContext()[CSIEphemeral] == "true" ||
  1795.                 req.GetVolumeContext()[CSIEphemeral] == "" // Kubernetes 1.15 doesn't have csi.storage.k8s.io/ephemeral.
  1796.  
  1797.         if !ephemeralVolume </span><span class="cov8" title="1">{
  1798.                 return status.Error(codes.InvalidArgument, "Non-ephemeral request made")
  1799.         }</span>
  1800.  
  1801.         <span class="cov8" title="1">if req.GetVolumeCapability().GetMount() == nil </span><span class="cov8" title="1">{
  1802.                 return status.Error(codes.InvalidArgument, "only support mount access type")
  1803.         }</span>
  1804.         <span class="cov8" title="1">return nil</span>
  1805. }
  1806.  
  1807. func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) <span class="cov8" title="1">{
  1808.         var kubeletTargetPath string
  1809.  
  1810.         // Check arguments
  1811.         if req.GetVolumeCapability() == nil </span><span class="cov8" title="1">{
  1812.                 return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request")
  1813.         }</span>
  1814.         <span class="cov8" title="1">if len(req.GetVolumeId()) == 0 </span><span class="cov8" title="1">{
  1815.                 return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
  1816.         }</span>
  1817.         <span class="cov8" title="1">if len(req.GetTargetPath()) == 0 </span><span class="cov8" title="1">{
  1818.                 return nil, status.Error(codes.InvalidArgument, "Target path missing in request")
  1819.         }</span>
  1820.         <span class="cov8" title="1">if req.VolumeContext == nil || len(req.GetVolumeContext()) == 0 </span><span class="cov8" title="1">{
  1821.                 return nil, status.Error(codes.InvalidArgument, "Volume attributes missing in request")
  1822.         }</span>
  1823.  
  1824.         <span class="cov8" title="1">err := ns.validateVolumeContext(req)
  1825.         if err != nil </span><span class="cov8" title="1">{
  1826.                 return nil, err
  1827.         }</span>
  1828.  
  1829.         <span class="cov8" title="1">cmShare, sShare, err := ns.validateShare(req)
  1830.         if err != nil </span><span class="cov8" title="1">{
  1831.                 return nil, err
  1832.         }</span>
  1833.  
  1834.         <span class="cov8" title="1">kubeletTargetPath = req.GetTargetPath()
  1835.         if !req.GetReadonly() </span><span class="cov8" title="1">{
  1836.                 return nil, status.Error(codes.InvalidArgument, "The Shared Resource CSI driver requires all volume requests to set read-only to 'true'")
  1837.         }</span>
  1838.         <span class="cov8" title="1">attrib := req.GetVolumeContext()
  1839.         refresh := true
  1840.         refreshStr, rok := attrib[RefreshResource]
  1841.         if rok </span><span class="cov8" title="1">{
  1842.                 r, e := strconv.ParseBool(refreshStr)
  1843.                 if e == nil </span><span class="cov8" title="1">{
  1844.                         refresh = r
  1845.                 }</span>
  1846.         }
  1847.  
  1848.         <span class="cov8" title="1">vol, err := ns.d.createVolume(req.GetVolumeId(), kubeletTargetPath, refresh, req.GetVolumeContext(), cmShare, sShare, maxStorageCapacity, mountAccess)
  1849.         if err != nil &amp;&amp; !os.IsExist(err) </span><span class="cov0" title="0">{
  1850.                 klog.Error("ephemeral mode failed to create volume: ", err)
  1851.                 return nil, status.Error(codes.Internal, err.Error())
  1852.         }</span>
  1853.         <span class="cov8" title="1">klog.V(4).Infof("NodePublishVolume created volume: %s", kubeletTargetPath)
  1854.  
  1855.         notMnt, err := mount.IsNotMountPoint(ns.mounter, kubeletTargetPath)
  1856.  
  1857.         if err != nil </span><span class="cov0" title="0">{
  1858.                 if os.IsNotExist(err) </span><span class="cov0" title="0">{
  1859.                         if err = os.MkdirAll(kubeletTargetPath, 0750); err != nil </span><span class="cov0" title="0">{
  1860.                                 return nil, status.Error(codes.Internal, err.Error())
  1861.                         }</span>
  1862.                         <span class="cov0" title="0">notMnt = true</span>
  1863.                 } else<span class="cov0" title="0"> {
  1864.                         return nil, status.Error(codes.Internal, err.Error())
  1865.                 }</span>
  1866.         }
  1867.  
  1868.         // this means the mount.Mounter call has already happened
  1869.         <span class="cov8" title="1">if !notMnt </span><span class="cov0" title="0">{
  1870.                 return &amp;csi.NodePublishVolumeResponse{}, nil
  1871.         }</span>
  1872.  
  1873.         <span class="cov8" title="1">fsType := req.GetVolumeCapability().GetMount().GetFsType()
  1874.  
  1875.         deviceId := ""
  1876.         if req.GetPublishContext() != nil </span><span class="cov0" title="0">{
  1877.                 deviceId = req.GetPublishContext()[deviceID]
  1878.         }</span>
  1879.  
  1880.         <span class="cov8" title="1">volumeId := req.GetVolumeId()
  1881.         mountFlags := req.GetVolumeCapability().GetMount().GetMountFlags()
  1882.  
  1883.         klog.V(4).Infof("NodePublishVolume %v\nfstype %v\ndevice %v\nvolumeId %v\nattributes %v\nmountflags %v\n",
  1884.                 kubeletTargetPath, fsType, deviceId, volumeId, attrib, mountFlags)
  1885.  
  1886.         mountIDString, bindDir := ns.d.getVolumePath(req.GetVolumeId(), req.GetVolumeContext())
  1887.         if err := ns.readWriteMounter.makeFSMounts(mountIDString, bindDir, kubeletTargetPath, ns.mounter); err != nil </span><span class="cov0" title="0">{
  1888.                 return nil, err
  1889.         }</span>
  1890.  
  1891.         // here is what initiates that necessary copy now with *NOT* using bind on the mount so each pod gets its own tmpfs
  1892.         <span class="cov8" title="1">if err := ns.d.mapVolumeToPod(vol); err != nil </span><span class="cov0" title="0">{
  1893.                 metrics.IncMountCounters(false)
  1894.                 return nil, status.Error(codes.Internal, fmt.Sprintf("failed to populate mount device: %s at %s: %s",
  1895.                         bindDir,
  1896.                         kubeletTargetPath,
  1897.                         err.Error()))
  1898.         }</span>
  1899.  
  1900.         <span class="cov8" title="1">if err := vol.StoreToDisk(ns.d.GetVolMapRoot()); err != nil </span><span class="cov0" title="0">{
  1901.                 metrics.IncMountCounters(false)
  1902.                 klog.Errorf("failed to persist driver volume metadata to disk: %s", err.Error())
  1903.                 return nil, status.Error(codes.Internal, err.Error())
  1904.         }</span>
  1905.  
  1906.         <span class="cov8" title="1">metrics.IncMountCounters(true)
  1907.         return &amp;csi.NodePublishVolumeResponse{}, nil</span>
  1908. }
  1909.  
  1910. func (ns *nodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) <span class="cov0" title="0">{
  1911.  
  1912.         // Check arguments
  1913.         if len(req.GetVolumeId()) == 0 </span><span class="cov0" title="0">{
  1914.                 return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
  1915.         }</span>
  1916.         <span class="cov0" title="0">if len(req.GetTargetPath()) == 0 </span><span class="cov0" title="0">{
  1917.                 return nil, status.Error(codes.InvalidArgument, "Target path missing in request")
  1918.         }</span>
  1919.         <span class="cov0" title="0">targetPath := req.GetTargetPath()
  1920.         volumeID := req.GetVolumeId()
  1921.  
  1922.         dv := ns.d.getVolume(volumeID)
  1923.         if dv == nil </span><span class="cov0" title="0">{
  1924.                 return nil, status.Error(codes.Internal, fmt.Sprintf("unpublish volume %s already gone", volumeID))
  1925.         }</span>
  1926.         <span class="cov0" title="0">if err := ns.readWriteMounter.removeFSMounts(dv.GetVolPathAnchorDir(), dv.GetVolPathBindMountDir(), targetPath, ns.mounter); err != nil </span><span class="cov0" title="0">{
  1927.                 return nil, status.Error(codes.Internal, fmt.Sprintf("error removing %s: %s", targetPath, err.Error()))
  1928.  
  1929.         }</span>
  1930.  
  1931.         <span class="cov0" title="0">klog.V(4).Infof("volume %s at path %s has been unpublished.", volumeID, targetPath)
  1932.  
  1933.         if err := ns.d.deleteVolume(volumeID); err != nil &amp;&amp; !os.IsNotExist(err) </span><span class="cov0" title="0">{
  1934.                 return nil, status.Error(codes.Internal, fmt.Sprintf("failed to delete volume: %s", err))
  1935.         }</span>
  1936.  
  1937.         <span class="cov0" title="0">filePath := filepath.Join(ns.d.GetVolMapRoot(), dv.GetVolID())
  1938.         if err := os.Remove(filePath); err != nil </span><span class="cov0" title="0">{
  1939.                 klog.Errorf("failed to persist driver volume metadata to disk: %s", err.Error())
  1940.                 return nil, status.Error(codes.Internal, err.Error())
  1941.         }</span>
  1942.         <span class="cov0" title="0">return &amp;csi.NodeUnpublishVolumeResponse{}, nil</span>
  1943. }
  1944.  
  1945. func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) <span class="cov0" title="0">{
  1946.         return nil, status.Error(codes.Unimplemented, "")
  1947. }</span>
  1948.  
  1949. func (ns *nodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) <span class="cov0" title="0">{
  1950.         return nil, status.Error(codes.Unimplemented, "")
  1951. }</span>
  1952.  
  1953. func (ns *nodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) <span class="cov0" title="0">{
  1954.  
  1955.         topology := &amp;csi.Topology{
  1956.                 Segments: map[string]string{TopologyKeyNode: ns.nodeID},
  1957.         }
  1958.  
  1959.         return &amp;csi.NodeGetInfoResponse{
  1960.                 NodeId:             ns.nodeID,
  1961.                 MaxVolumesPerNode:  ns.maxVolumesPerNode,
  1962.                 AccessibleTopology: topology,
  1963.         }, nil
  1964. }</span>
  1965.  
  1966. func (ns *nodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) <span class="cov0" title="0">{
  1967.  
  1968.         return &amp;csi.NodeGetCapabilitiesResponse{
  1969.                 Capabilities: []*csi.NodeServiceCapability{},
  1970.         }, nil
  1971. }</span>
  1972.  
  1973. func (ns *nodeServer) NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) <span class="cov0" title="0">{
  1974.         return nil, status.Error(codes.Unimplemented, "")
  1975. }</span>
  1976.  
  1977. // NodeExpandVolume is only implemented so the driver can be used for e2e testing.
  1978. func (ns *nodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) <span class="cov0" title="0">{
  1979.         return nil, status.Error(codes.Unimplemented, "")
  1980. }</span>
  1981. </pre>
  1982.        
  1983.         <pre class="file" id="file9" style="display: none">/*
  1984. Copyright 2019 The Kubernetes Authors.
  1985.  
  1986. Licensed under the Apache License, Version 2.0 (the "License");
  1987. you may not use this file except in compliance with the License.
  1988. You may obtain a copy of the License at
  1989.  
  1990.     http://www.apache.org/licenses/LICENSE-2.0
  1991.  
  1992. Unless required by applicable law or agreed to in writing, software
  1993. distributed under the License is distributed on an "AS IS" BASIS,
  1994. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  1995. See the License for the specific language governing permissions and
  1996. limitations under the License.
  1997. */
  1998.  
  1999. package csidriver
  2000.  
  2001. import (
  2002.         "fmt"
  2003.         "net"
  2004.         "os"
  2005.         "strings"
  2006.         "sync"
  2007.  
  2008.         "golang.org/x/net/context"
  2009.         "google.golang.org/grpc"
  2010.  
  2011.         "github.com/container-storage-interface/spec/lib/go/csi"
  2012.         "github.com/kubernetes-csi/csi-lib-utils/protosanitizer"
  2013.  
  2014.         "k8s.io/klog/v2"
  2015. )
  2016.  
  2017. func NewNonBlockingGRPCServer() *nonBlockingGRPCServer <span class="cov0" title="0">{
  2018.         return &amp;nonBlockingGRPCServer{}
  2019. }</span>
  2020.  
  2021. // NonBlocking server
  2022. type nonBlockingGRPCServer struct {
  2023.         wg     sync.WaitGroup
  2024.         server *grpc.Server
  2025. }
  2026.  
  2027. func (s *nonBlockingGRPCServer) Start(endpoint string, ids csi.IdentityServer, ns csi.NodeServer) <span class="cov0" title="0">{
  2028.  
  2029.         s.wg.Add(1)
  2030.  
  2031.         go s.serve(endpoint, ids, ns)
  2032.  
  2033.         return
  2034. }</span>
  2035.  
  2036. func (s *nonBlockingGRPCServer) Wait() <span class="cov0" title="0">{
  2037.         s.wg.Wait()
  2038. }</span>
  2039.  
  2040. func (s *nonBlockingGRPCServer) Stop() <span class="cov0" title="0">{
  2041.         s.server.GracefulStop()
  2042. }</span>
  2043.  
  2044. func (s *nonBlockingGRPCServer) ForceStop() <span class="cov0" title="0">{
  2045.         s.server.Stop()
  2046. }</span>
  2047.  
  2048. func (s *nonBlockingGRPCServer) serve(endpoint string, ids csi.IdentityServer, ns csi.NodeServer) <span class="cov0" title="0">{
  2049.  
  2050.         proto, addr, err := parseEndpoint(endpoint)
  2051.         if err != nil </span><span class="cov0" title="0">{
  2052.                 klog.Fatal(err.Error())
  2053.         }</span>
  2054.  
  2055.         <span class="cov0" title="0">if proto == "unix" </span><span class="cov0" title="0">{
  2056.                 addr = "/" + addr
  2057.                 if err := os.Remove(addr); err != nil &amp;&amp; !os.IsNotExist(err) </span><span class="cov0" title="0">{ //nolint: vetshadow
  2058.                         klog.Fatalf("Failed to remove %s, error: %s", addr, err.Error())
  2059.                 }</span>
  2060.         }
  2061.  
  2062.         <span class="cov0" title="0">listener, err := net.Listen(proto, addr)
  2063.         if err != nil </span><span class="cov0" title="0">{
  2064.                 klog.Fatalf("Failed to listen: %v", err)
  2065.         }</span>
  2066.  
  2067.         <span class="cov0" title="0">opts := []grpc.ServerOption{
  2068.                 grpc.UnaryInterceptor(logGRPC),
  2069.         }
  2070.         server := grpc.NewServer(opts...)
  2071.         s.server = server
  2072.  
  2073.         if ids != nil </span><span class="cov0" title="0">{
  2074.                 csi.RegisterIdentityServer(server, ids)
  2075.         }</span>
  2076.         <span class="cov0" title="0">if ns != nil </span><span class="cov0" title="0">{
  2077.                 csi.RegisterNodeServer(server, ns)
  2078.         }</span>
  2079.  
  2080.         <span class="cov0" title="0">klog.Infof("Listening for connections on address: %#v", listener.Addr())
  2081.  
  2082.         server.Serve(listener)</span>
  2083.  
  2084. }
  2085.  
  2086. func parseEndpoint(ep string) (string, string, error) <span class="cov0" title="0">{
  2087.         if strings.HasPrefix(strings.ToLower(ep), "unix://") || strings.HasPrefix(strings.ToLower(ep), "tcp://") </span><span class="cov0" title="0">{
  2088.                 s := strings.SplitN(ep, "://", 2)
  2089.                 if s[1] != "" </span><span class="cov0" title="0">{
  2090.                         return s[0], s[1], nil
  2091.                 }</span>
  2092.         }
  2093.         <span class="cov0" title="0">return "", "", fmt.Errorf("Invalid endpoint: %v", ep)</span>
  2094. }
  2095.  
  2096. func logGRPC(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) <span class="cov0" title="0">{
  2097.         klog.V(3).Infof("GRPC call: %s", info.FullMethod)
  2098.         klog.V(5).Infof("GRPC request: %+v", protosanitizer.StripSecrets(req))
  2099.         resp, err := handler(ctx, req)
  2100.         if err != nil </span><span class="cov0" title="0">{
  2101.                 klog.Errorf("GRPC error: %v", err)
  2102.         }</span> else<span class="cov0" title="0"> {
  2103.                 klog.V(5).Infof("GRPC response: %+v", protosanitizer.StripSecrets(resp))
  2104.         }</span>
  2105.         <span class="cov0" title="0">return resp, err</span>
  2106. }
  2107. </pre>
  2108.        
  2109.         <pre class="file" id="file10" style="display: none">package metrics
  2110.  
  2111. import (
  2112.         "github.com/prometheus/client_golang/prometheus"
  2113. )
  2114.  
  2115. const (
  2116.         separator = "_"
  2117.  
  2118.         sharesSubsystem = "openshift_csi_share"
  2119.  
  2120.         mount                 = "mount"
  2121.         mountCountName        = sharesSubsystem + separator + mount + separator + "requests_total"
  2122.         mountFailureCountName = sharesSubsystem + separator + mount + separator + "failures_total"
  2123.  
  2124.         MetricsPort = 6000
  2125. )
  2126.  
  2127. var (
  2128.         mountCounter, failedMountCounter = createMountCounters()
  2129. )
  2130.  
  2131. func createMountCounters() (prometheus.Counter, prometheus.Counter) <span class="cov8" title="1">{
  2132.         return prometheus.NewCounter(prometheus.CounterOpts{
  2133.                         Name: mountCountName,
  2134.                         Help: "Counts share volume mount attempts.",
  2135.                 }),
  2136.                 prometheus.NewCounter(prometheus.CounterOpts{
  2137.                         Name: mountFailureCountName,
  2138.                         Help: "Counts failed share volume mount attempts.",
  2139.                 })
  2140. }</span>
  2141.  
  2142. func init() <span class="cov8" title="1">{
  2143.         prometheus.MustRegister(mountCounter)
  2144.         prometheus.MustRegister(failedMountCounter)
  2145. }</span>
  2146.  
  2147. func IncMountCounters(succeeded bool) <span class="cov8" title="1">{
  2148.         if !succeeded </span><span class="cov8" title="1">{
  2149.                 failedMountCounter.Inc()
  2150.         }</span>
  2151.         <span class="cov8" title="1">mountCounter.Inc()</span>
  2152. }
  2153. </pre>
  2154.        
  2155.         <pre class="file" id="file11" style="display: none">package metrics
  2156.  
  2157. import (
  2158.         "context"
  2159.         "errors"
  2160.         "fmt"
  2161.         "net/http"
  2162.         "time"
  2163.  
  2164.         "github.com/prometheus/client_golang/prometheus/promhttp"
  2165.         "k8s.io/klog/v2"
  2166. )
  2167.  
  2168. var (
  2169.         // these files are mounted from the openshift secret
  2170.         // shared-resource-csi-driver-node-metrics-serving-cert
  2171.         // by the csi-driver-shared-resource-operator
  2172.         tlsCRT = "/etc/secrets/tls.crt"
  2173.         tlsKey = "/etc/secrets/tls.key"
  2174. )
  2175.  
  2176. // BuildServer creates the http.Server struct
  2177. func BuildServer(port int) (*http.Server, error) <span class="cov8" title="1">{
  2178.         if port &lt;= 0 </span><span class="cov0" title="0">{
  2179.                 klog.Error("invalid port for metric server")
  2180.                 return nil, errors.New("invalid port for metrics server")
  2181.         }</span>
  2182.  
  2183.         <span class="cov8" title="1">bindAddr := fmt.Sprintf(":%d", port)
  2184.         router := http.NewServeMux()
  2185.         router.Handle("/metrics", promhttp.Handler())
  2186.         srv := &amp;http.Server{
  2187.                 Addr:    bindAddr,
  2188.                 Handler: router,
  2189.         }
  2190.  
  2191.         return srv, nil</span>
  2192. }
  2193.  
  2194. // StopServer stops the metrics server
  2195. func StopServer(srv *http.Server) <span class="cov0" title="0">{
  2196.         ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  2197.         defer cancel()
  2198.         if err := srv.Shutdown(ctx); err != nil </span><span class="cov0" title="0">{
  2199.                 klog.Warningf("Problem shutting down HTTP server: %v", err)
  2200.         }</span>
  2201. }
  2202.  
  2203. // RunServer starts the metrics server.
  2204. func RunServer(srv *http.Server, stopCh &lt;-chan struct{}) <span class="cov8" title="1">{
  2205.         go func() </span><span class="cov8" title="1">{
  2206.                 err := srv.ListenAndServeTLS(tlsCRT, tlsKey)
  2207.                 if err != nil &amp;&amp; err != http.ErrServerClosed </span><span class="cov0" title="0">{
  2208.                         klog.Errorf("error starting metrics server: %v", err)
  2209.                 }</span>
  2210.         }()
  2211.         <span class="cov8" title="1">&lt;-stopCh
  2212.         if err := srv.Close(); err != nil </span><span class="cov0" title="0">{
  2213.                 klog.Errorf("error closing metrics server: %v", err)
  2214.         }</span>
  2215. }
  2216. </pre>
  2217.        
  2218.         </div>
  2219.     </body>
  2220.     <script>
  2221.     (function() {
  2222.         var files = document.getElementById('files');
  2223.         var visible;
  2224.         files.addEventListener('change', onChange, false);
  2225.         function select(part) {
  2226.             if (visible)
  2227.                 visible.style.display = 'none';
  2228.             visible = document.getElementById(part);
  2229.             if (!visible)
  2230.                 return;
  2231.             files.value = part;
  2232.             visible.style.display = 'block';
  2233.             location.hash = part;
  2234.         }
  2235.         function onChange() {
  2236.             select(files.value);
  2237.             window.scrollTo(0, 0);
  2238.         }
  2239.         if (location.hash != "") {
  2240.             select(location.hash.substr(1));
  2241.         }
  2242.         if (!visible) {
  2243.             select("file0");
  2244.         }
  2245.     })();
  2246.     </script>
  2247. </html>
  2248.  
Add Comment
Please, Sign In to add comment