github.com/AbhinandanKurakure/podman/v3@v3.4.10/test/testvol/main.go (about) 1 package main 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "sync" 8 "time" 9 10 "github.com/docker/go-plugins-helpers/volume" 11 "github.com/pkg/errors" 12 "github.com/sirupsen/logrus" 13 "github.com/spf13/cobra" 14 ) 15 16 var rootCmd = &cobra.Command{ 17 Use: "testvol", 18 Short: "testvol - volume plugin for Podman", 19 Long: `Creates simple directory volumes using the Volume Plugin API for testing volume plugin functionality`, 20 RunE: func(cmd *cobra.Command, args []string) error { 21 return startServer(config.sockName) 22 }, 23 PersistentPreRunE: before, 24 } 25 26 // Configuration for the volume plugin 27 type cliConfig struct { 28 logLevel string 29 sockName string 30 path string 31 } 32 33 // Default configuration is stored here. Will be overwritten by flags. 34 var config cliConfig = cliConfig{ 35 logLevel: "error", 36 sockName: "test-volume-plugin", 37 } 38 39 func init() { 40 rootCmd.Flags().StringVar(&config.sockName, "sock-name", config.sockName, "Name of unix socket for plugin") 41 rootCmd.Flags().StringVar(&config.path, "path", "", "Path to initialize state and mount points") 42 rootCmd.PersistentFlags().StringVar(&config.logLevel, "log-level", config.logLevel, "Log messages including and over the specified level: debug, info, warn, error, fatal, panic") 43 } 44 45 func before(cmd *cobra.Command, args []string) error { 46 if config.logLevel == "" { 47 config.logLevel = "error" 48 } 49 50 level, err := logrus.ParseLevel(config.logLevel) 51 if err != nil { 52 return err 53 } 54 55 logrus.SetLevel(level) 56 57 return nil 58 } 59 60 func main() { 61 if err := rootCmd.Execute(); err != nil { 62 logrus.Errorf("Error running volume plugin: %v", err) 63 os.Exit(1) 64 } 65 66 os.Exit(0) 67 } 68 69 // startServer runs the HTTP server and responds to requests 70 func startServer(socketPath string) error { 71 logrus.Debugf("Starting server...") 72 73 if config.path == "" { 74 path, err := ioutil.TempDir("", "test_volume_plugin") 75 if err != nil { 76 return errors.Wrapf(err, "error getting directory for plugin") 77 } 78 config.path = path 79 } else { 80 pathStat, err := os.Stat(config.path) 81 if err != nil { 82 return errors.Wrapf(err, "unable to access requested plugin state directory") 83 } 84 if !pathStat.IsDir() { 85 return errors.Errorf("cannot use %v as plugin state dir as it is not a directory", config.path) 86 } 87 } 88 89 handle, err := makeDirDriver(config.path) 90 if err != nil { 91 return errors.Wrapf(err, "error making volume driver") 92 } 93 logrus.Infof("Using %s for volume path", config.path) 94 95 server := volume.NewHandler(handle) 96 if err := server.ServeUnix(socketPath, 0); err != nil { 97 return errors.Wrapf(err, "error starting server") 98 } 99 return nil 100 } 101 102 // DirDriver is a trivial volume driver implementation. 103 // the volumes field maps name to volume 104 type DirDriver struct { 105 lock sync.Mutex 106 volumesPath string 107 volumes map[string]*dirVol 108 } 109 110 type dirVol struct { 111 name string 112 path string 113 options map[string]string 114 mounts map[string]bool 115 createTime time.Time 116 } 117 118 // Make a new DirDriver. 119 func makeDirDriver(path string) (volume.Driver, error) { 120 drv := new(DirDriver) 121 drv.volumesPath = path 122 drv.volumes = make(map[string]*dirVol) 123 124 return drv, nil 125 } 126 127 // Capabilities returns the capabilities of the driver. 128 func (d *DirDriver) Capabilities() *volume.CapabilitiesResponse { 129 logrus.Infof("Hit Capabilities() endpoint") 130 131 return &volume.CapabilitiesResponse{ 132 volume.Capability{ 133 "local", 134 }, 135 } 136 } 137 138 // Create creates a volume. 139 func (d *DirDriver) Create(opts *volume.CreateRequest) error { 140 d.lock.Lock() 141 defer d.lock.Unlock() 142 143 logrus.Infof("Hit Create() endpoint") 144 145 if _, exists := d.volumes[opts.Name]; exists { 146 return errors.Errorf("volume with name %s already exists", opts.Name) 147 } 148 149 newVol := new(dirVol) 150 newVol.name = opts.Name 151 newVol.mounts = make(map[string]bool) 152 newVol.options = make(map[string]string) 153 newVol.createTime = time.Now() 154 for k, v := range opts.Options { 155 newVol.options[k] = v 156 } 157 158 volPath := filepath.Join(d.volumesPath, opts.Name) 159 if err := os.Mkdir(volPath, 0755); err != nil { 160 return errors.Wrapf(err, "error making volume directory") 161 } 162 newVol.path = volPath 163 164 d.volumes[opts.Name] = newVol 165 166 logrus.Debugf("Made volume with name %s and path %s", newVol.name, newVol.path) 167 168 return nil 169 } 170 171 // List lists all volumes available. 172 func (d *DirDriver) List() (*volume.ListResponse, error) { 173 d.lock.Lock() 174 defer d.lock.Unlock() 175 176 logrus.Infof("Hit List() endpoint") 177 178 vols := new(volume.ListResponse) 179 vols.Volumes = []*volume.Volume{} 180 181 for _, vol := range d.volumes { 182 newVol := new(volume.Volume) 183 newVol.Name = vol.name 184 newVol.Mountpoint = vol.path 185 newVol.CreatedAt = vol.createTime.String() 186 vols.Volumes = append(vols.Volumes, newVol) 187 logrus.Debugf("Adding volume %s to list response", newVol.Name) 188 } 189 190 return vols, nil 191 } 192 193 // Get retrieves a single volume. 194 func (d *DirDriver) Get(req *volume.GetRequest) (*volume.GetResponse, error) { 195 d.lock.Lock() 196 defer d.lock.Unlock() 197 198 logrus.Infof("Hit Get() endpoint") 199 200 vol, exists := d.volumes[req.Name] 201 if !exists { 202 logrus.Debugf("Did not find volume %s", req.Name) 203 return nil, errors.Errorf("no volume with name %s found", req.Name) 204 } 205 206 logrus.Debugf("Found volume %s", req.Name) 207 208 resp := new(volume.GetResponse) 209 resp.Volume = new(volume.Volume) 210 resp.Volume.Name = vol.name 211 resp.Volume.Mountpoint = vol.path 212 resp.Volume.CreatedAt = vol.createTime.String() 213 214 return resp, nil 215 } 216 217 // Remove removes a single volume. 218 func (d *DirDriver) Remove(req *volume.RemoveRequest) error { 219 d.lock.Lock() 220 defer d.lock.Unlock() 221 222 logrus.Infof("Hit Remove() endpoint") 223 224 vol, exists := d.volumes[req.Name] 225 if !exists { 226 logrus.Debugf("Did not find volume %s", req.Name) 227 return errors.Errorf("no volume with name %s found", req.Name) 228 } 229 logrus.Debugf("Found volume %s", req.Name) 230 231 if len(vol.mounts) > 0 { 232 logrus.Debugf("Cannot remove %s, is mounted", req.Name) 233 return errors.Errorf("volume %s is mounted and cannot be removed", req.Name) 234 } 235 236 delete(d.volumes, req.Name) 237 238 if err := os.RemoveAll(vol.path); err != nil { 239 return errors.Wrapf(err, "error removing mountpoint of volume %s", req.Name) 240 } 241 242 logrus.Debugf("Removed volume %s", req.Name) 243 244 return nil 245 } 246 247 // Path returns the path a single volume is mounted at. 248 func (d *DirDriver) Path(req *volume.PathRequest) (*volume.PathResponse, error) { 249 d.lock.Lock() 250 defer d.lock.Unlock() 251 252 logrus.Infof("Hit Path() endpoint") 253 254 // TODO: Should we return error if not mounted? 255 256 vol, exists := d.volumes[req.Name] 257 if !exists { 258 logrus.Debugf("Cannot locate volume %s", req.Name) 259 return nil, errors.Errorf("no volume with name %s found", req.Name) 260 } 261 262 return &volume.PathResponse{ 263 vol.path, 264 }, nil 265 } 266 267 // Mount mounts the volume. 268 func (d *DirDriver) Mount(req *volume.MountRequest) (*volume.MountResponse, error) { 269 d.lock.Lock() 270 defer d.lock.Unlock() 271 272 logrus.Infof("Hit Mount() endpoint") 273 274 vol, exists := d.volumes[req.Name] 275 if !exists { 276 logrus.Debugf("Cannot locate volume %s", req.Name) 277 return nil, errors.Errorf("no volume with name %s found", req.Name) 278 } 279 280 vol.mounts[req.ID] = true 281 282 return &volume.MountResponse{ 283 vol.path, 284 }, nil 285 } 286 287 // Unmount unmounts the volume. 288 func (d *DirDriver) Unmount(req *volume.UnmountRequest) error { 289 d.lock.Lock() 290 defer d.lock.Unlock() 291 292 logrus.Infof("Hit Unmount() endpoint") 293 294 vol, exists := d.volumes[req.Name] 295 if !exists { 296 logrus.Debugf("Cannot locate volume %s", req.Name) 297 return errors.Errorf("no volume with name %s found", req.Name) 298 } 299 300 mount := vol.mounts[req.ID] 301 if !mount { 302 logrus.Debugf("Volume %s is not mounted by %s", req.Name, req.ID) 303 return errors.Errorf("volume %s is not mounted by %s", req.Name, req.ID) 304 } 305 306 delete(vol.mounts, req.ID) 307 308 return nil 309 }