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  }