コード例 #1
0
ファイル: vfs_storage.go プロジェクト: PaulCharlton/convoy
func Init(root string, config map[string]string) (convoydriver.ConvoyDriver, error) {
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
	} else {
		if err := util.MkdirIfNotExists(root); err != nil {
			return nil, err
		}

		path := config[VFS_PATH]
		if path == "" {
			return nil, fmt.Errorf("VFS driver base path unspecified")
		}
		if err := util.MkdirIfNotExists(path); err != nil {
			return nil, err
		}

		dev = &Device{
			Root: root,
			Path: path,
		}

		if _, exists := config[VFS_DEFAULT_VOLUME_SIZE]; !exists {
			config[VFS_DEFAULT_VOLUME_SIZE] = DEFAULT_VOLUME_SIZE
		}
		volumeSize, err := util.ParseSize(config[VFS_DEFAULT_VOLUME_SIZE])
		if err != nil || volumeSize == 0 {
			return nil, fmt.Errorf("Illegal default volume size specified")
		}
		dev.DefaultVolumeSize = volumeSize
	}

	// For upgrade case
	if dev.DefaultVolumeSize == 0 {
		dev.DefaultVolumeSize, err = util.ParseSize(DEFAULT_VOLUME_SIZE)
		if err != nil || dev.DefaultVolumeSize == 0 {
			return nil, fmt.Errorf("Illegal default volume size specified")
		}
	}

	if err := util.ObjectSave(dev); err != nil {
		return nil, err
	}
	d := &Driver{
		mutex:  &sync.RWMutex{},
		Device: *dev,
	}

	return d, nil
}
コード例 #2
0
ファイル: vfs_storage.go プロジェクト: PaulCharlton/convoy
func (d *Driver) CreateSnapshot(id, volumeID string) error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	volume := d.blankVolume(volumeID)
	if err := util.ObjectLoad(volume); err != nil {
		return err
	}
	if _, exists := volume.Snapshots[id]; exists {
		return fmt.Errorf("Snapshot %v already exists for volume %v", id, volumeID)
	}
	snapFile := d.getSnapshotFilePath(id, volumeID)
	if err := util.MkdirIfNotExists(filepath.Dir(snapFile)); err != nil {
		return err
	}
	if err := util.CompressDir(volume.Path, snapFile); err != nil {
		return err
	}
	volume.Snapshots[id] = Snapshot{
		UUID:       id,
		VolumeUUID: volumeID,
		FilePath:   snapFile,
	}
	return util.ObjectSave(volume)
}
コード例 #3
0
ファイル: daemon.go プロジェクト: PaulCharlton/convoy
func daemonEnvironmentSetup(c *cli.Context) error {
	var err error

	root := c.String("root")
	if root == "" {
		return fmt.Errorf("Have to specific root directory")
	}
	if err := util.MkdirIfNotExists(root); err != nil {
		return fmt.Errorf("Invalid root directory:", err)
	}

	lockPath := filepath.Join(root, LOCKFILE)
	if lockFile, err = util.LockFile(lockPath); err != nil {
		return fmt.Errorf("Failed to lock the file at %v: %v", lockPath, err.Error())
	}

	logrus.SetLevel(logrus.DebugLevel)
	logName := c.String("log")
	if logName != "" {
		logFile, err := os.OpenFile(logName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
		if err != nil {
			return err
		}
		logrus.SetFormatter(&logrus.JSONFormatter{})
		logrus.SetOutput(logFile)
	} else {
		logrus.SetOutput(os.Stdout)
	}

	return nil
}
コード例 #4
0
ファイル: vfs_storage.go プロジェクト: alwang1234/convoy
func (d *Driver) CreateSnapshot(req Request) error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	id := req.Name
	volumeID, err := util.GetFieldFromOpts(OPT_VOLUME_NAME, req.Options)
	if err != nil {
		return err
	}

	volume := d.blankVolume(volumeID)
	if err := util.ObjectLoad(volume); err != nil {
		return err
	}
	if _, exists := volume.Snapshots[id]; exists {
		return fmt.Errorf("Snapshot %v already exists for volume %v", id, volumeID)
	}
	snapFile := d.getSnapshotFilePath(id, volumeID)
	if err := util.MkdirIfNotExists(filepath.Dir(snapFile)); err != nil {
		return err
	}
	if err := util.CompressDir(volume.Path, snapFile); err != nil {
		return err
	}
	volume.Snapshots[id] = Snapshot{
		Name:        id,
		CreatedTime: util.Now(),
		VolumeUUID:  volumeID,
		FilePath:    snapFile,
	}
	return util.ObjectSave(volume)
}
コード例 #5
0
ファイル: vfs_storage.go プロジェクト: PaulCharlton/convoy
func (d *Driver) CreateVolume(id string, opts map[string]string) error {
	d.mutex.Lock()
	defer d.mutex.Unlock()

	backupURL := opts[convoydriver.OPT_BACKUP_URL]
	if backupURL != "" {
		objVolume, err := objectstore.LoadVolume(backupURL)
		if err != nil {
			return err
		}
		if objVolume.Driver != d.Name() {
			return fmt.Errorf("Cannot restore backup of %v to %v", objVolume.Driver, d.Name())
		}
	}

	volumeName := opts[convoydriver.OPT_VOLUME_NAME]
	if volumeName == "" {
		volumeName = "volume-" + id[:8]
	}

	volume := d.blankVolume(id)
	exists, err := util.ObjectExists(volume)
	if err != nil {
		return err
	}
	if exists {
		return fmt.Errorf("volume %v already exists", id)
	}

	volume.PrepareForVM, err = strconv.ParseBool(opts[convoydriver.OPT_PREPARE_FOR_VM])
	if err != nil {
		return err
	}
	if volume.PrepareForVM {
		volume.Size, err = d.getSize(opts, d.DefaultVolumeSize)
		if err != nil {
			return err
		}
	}

	volumePath := filepath.Join(d.Path, volumeName)
	if err := util.MkdirIfNotExists(volumePath); err != nil {
		return err
	}
	volume.Path = volumePath
	volume.Snapshots = make(map[string]Snapshot)

	if backupURL != "" {
		file, err := objectstore.RestoreSingleFileBackup(backupURL, volumePath)
		if err != nil {
			return err
		}
		// file would be removed after this because it's under volumePath
		if err := util.DecompressDir(file, volumePath); err != nil {
			return err
		}
	}
	return util.ObjectSave(volume)
}
コード例 #6
0
ファイル: ebs.go プロジェクト: PaulCharlton/convoy
func Init(root string, config map[string]string) (convoydriver.ConvoyDriver, error) {
	ebsService, err := NewEBSService()
	if err != nil {
		return nil, err
	}
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
	} else {
		if err := util.MkdirIfNotExists(root); err != nil {
			return nil, err
		}

		if config[EBS_DEFAULT_VOLUME_SIZE] == "" {
			config[EBS_DEFAULT_VOLUME_SIZE] = DEFAULT_VOLUME_SIZE
		}
		size, err := util.ParseSize(config[EBS_DEFAULT_VOLUME_SIZE])
		if err != nil {
			return nil, err
		}
		if config[EBS_DEFAULT_VOLUME_TYPE] == "" {
			config[EBS_DEFAULT_VOLUME_TYPE] = DEFAULT_VOLUME_TYPE
		}
		volumeType := config[EBS_DEFAULT_VOLUME_TYPE]
		if err := checkVolumeType(volumeType); err != nil {
			return nil, err
		}
		dev = &Device{
			Root:              root,
			DefaultVolumeSize: size,
			DefaultVolumeType: volumeType,
		}
		if err := util.ObjectSave(dev); err != nil {
			return nil, err
		}
	}
	d := &Driver{
		mutex:      &sync.RWMutex{},
		ebsService: ebsService,
		Device:     *dev,
	}
	if err := d.remountVolumes(); err != nil {
		return nil, err
	}

	return d, nil
}
コード例 #7
0
ファイル: devmapper.go プロジェクト: ppawiggers/convoy
func (d *Driver) getVolumeMountPoint(volumeUUID, specifiedPoint string) (string, error) {
	var dir string
	if specifiedPoint != "" {
		dir = specifiedPoint
	} else {
		dir = filepath.Join(d.Root, MOUNTS_DIR, volumeUUID)
	}
	if err := util.MkdirIfNotExists(dir); err != nil {
		return "", err
	}
	return dir, nil
}
コード例 #8
0
ファイル: vfs_storage.go プロジェクト: versus/convoy
func Init(root string, config map[string]string) (convoydriver.ConvoyDriver, error) {
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
	} else {
		if err := util.MkdirIfNotExists(root); err != nil {
			return nil, err
		}

		path := config[VFS_PATH]
		if path == "" {
			return nil, fmt.Errorf("VFS driver base path unspecified")
		}
		if err := util.MkdirIfNotExists(path); err != nil {
			return nil, err
		}
		dev = &Device{
			Root: root,
			Path: path,
		}
		if err := util.ObjectSave(dev); err != nil {
			return nil, err
		}
	}
	d := &Driver{
		mutex:  &sync.RWMutex{},
		Device: *dev,
	}

	return d, nil
}
コード例 #9
0
ファイル: glusterfs.go プロジェクト: alwang1234/convoy
func Init(root string, config map[string]string) (ConvoyDriver, error) {
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
	} else {
		if err := util.MkdirIfNotExists(root); err != nil {
			return nil, err
		}

		serverList := config[GLUSTERFS_SERVERS]
		if serverList == "" {
			return nil, fmt.Errorf("Missing required parameter: %v", GLUSTERFS_SERVERS)
		}

		servers := strings.Split(serverList, ",")
		for _, server := range servers {
			if !util.ValidNetworkAddr(server) {
				return nil, fmt.Errorf("Invalid or unsolvable address: %v", server)
			}
		}

		defaultVolumePool := config[GLUSTERFS_DEFAULT_VOLUME_POOL]
		if defaultVolumePool == "" {
			return nil, fmt.Errorf("Missing required parameter: %v", GLUSTERFS_DEFAULT_VOLUME_POOL)
		}

		if _, exists := config[GLUSTERFS_DEFAULT_VOLUME_SIZE]; !exists {
			config[GLUSTERFS_DEFAULT_VOLUME_SIZE] = DEFAULT_VOLUME_SIZE
		}
		volumeSize, err := util.ParseSize(config[GLUSTERFS_DEFAULT_VOLUME_SIZE])
		if err != nil || volumeSize == 0 {
			return nil, fmt.Errorf("Illegal default volume size specified")
		}
		dev.DefaultVolumeSize = volumeSize

		dev = &Device{
			Root:              root,
			Servers:           servers,
			DefaultVolumePool: defaultVolumePool,
		}
	}

	// For upgrade case
	if dev.DefaultVolumeSize == 0 {
		dev.DefaultVolumeSize, err = util.ParseSize(DEFAULT_VOLUME_SIZE)
		if err != nil || dev.DefaultVolumeSize == 0 {
			return nil, fmt.Errorf("Illegal default volume size specified")
		}
	}

	d := &Driver{
		mutex:    &sync.RWMutex{},
		gVolumes: map[string]*GlusterFSVolume{},
		Device:   *dev,
	}
	gVolume := &GlusterFSVolume{
		UUID:       dev.DefaultVolumePool,
		Servers:    dev.Servers,
		configPath: d.Root,
	}
	// We would always mount the default volume pool
	// TODO: Also need to mount any existing volume's pool
	if _, err := util.VolumeMount(gVolume, "", true); err != nil {
		return nil, err
	}
	d.gVolumes[d.DefaultVolumePool] = gVolume

	if err := util.ObjectSave(dev); err != nil {
		return nil, err
	}
	return d, nil
}
コード例 #10
0
ファイル: devmapper.go プロジェクト: ppawiggers/convoy
func Init(root string, config map[string]string) (convoydriver.ConvoyDriver, error) {
	devicemapper.LogInitVerbose(1)
	devicemapper.LogInit(&DMLogger{})

	if err := checkEnvironment(); err != nil {
		return nil, err
	}

	if err := util.MkdirIfNotExists(root); err != nil {
		return nil, err
	}
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
		d := &Driver{
			Mutex:  &sync.Mutex{},
			Device: *dev,
		}
		if err := d.activatePool(); err != nil {
			return nil, err
		}
		if err := d.remountVolumes(); err != nil {
			return nil, err
		}
		return d, nil
	}

	dev, err = verifyConfig(config)
	if err != nil {
		return nil, err
	}

	dev.Root = root

	dataDev, err := os.Open(dev.DataDevice)
	if err != nil {
		return nil, err
	}
	defer dataDev.Close()

	metadataDev, err := os.Open(dev.MetadataDevice)
	if err != nil {
		return nil, err
	}
	defer metadataDev.Close()

	thinpSize, err := devicemapper.GetBlockDeviceSize(dataDev)
	if err != nil {
		return nil, err
	}
	dev.ThinpoolSize = int64(thinpSize)
	dev.LastDevID = 0

	if err = createPool(filepath.Base(dev.ThinpoolDevice), dataDev, metadataDev, uint32(dev.ThinpoolBlockSize)); err != nil {
		return nil, err
	}

	if err = util.ObjectSave(dev); err != nil {
		return nil, err
	}
	d := &Driver{
		Mutex:  &sync.Mutex{},
		Device: *dev,
	}
	return d, nil
}
コード例 #11
0
ファイル: daemon.go プロジェクト: PaulCharlton/convoy
// Start the daemon
func Start(sockFile string, c *cli.Context) error {
	var err error

	if err = daemonEnvironmentSetup(c); err != nil {
		return err
	}
	defer environmentCleanup()

	root := c.String("root")
	s := &daemon{
		ConvoyDrivers: make(map[string]convoydriver.ConvoyDriver),
	}
	config := &daemonConfig{
		Root: root,
	}
	exists, err := util.ObjectExists(config)
	if err != nil {
		return err
	}
	if exists {
		log.Debug("Found existing config. Ignoring command line opts, loading config from ", root)
		if err := util.ObjectLoad(config); err != nil {
			return err
		}
	} else {
		fd := c.String("mnt-ns")
		if fd != "" {
			if _, err := os.Stat(fd); err != nil {
				return fmt.Errorf("Cannot find mount namespace fd %v", fd)
			}
			config.MountNamespaceFD = fd
		}

		driverList := c.StringSlice("drivers")
		if len(driverList) == 0 {
			return fmt.Errorf("Missing or invalid parameters")
		}
		log.Debug("Creating config at ", root)

		config.DriverList = driverList
		config.DefaultDriver = driverList[0]
	}

	s.daemonConfig = *config

	if err := util.InitMountNamespace(s.MountNamespaceFD); err != nil {
		return err
	}
	// driverOpts would be ignored by Convoy Drivers if config already exists
	driverOpts := util.SliceToMap(c.StringSlice("driver-opts"))
	if err := s.initDrivers(driverOpts); err != nil {
		return err
	}
	if err := s.finializeInitialization(); err != nil {
		return err
	}
	if err := util.ObjectSave(config); err != nil {
		return err
	}

	s.Router = createRouter(s)

	if err := util.MkdirIfNotExists(filepath.Dir(sockFile)); err != nil {
		return err
	}
	// This should be safe because lock file prevent starting daemon twice
	if _, err := os.Stat(sockFile); err == nil {
		log.Warnf("Remove previous sockfile at %v", sockFile)
		if err := os.Remove(sockFile); err != nil {
			return err
		}
	}

	l, err := net.Listen("unix", sockFile)
	if err != nil {
		fmt.Println("listen err", err)
		return err
	}
	defer l.Close()

	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		sig := <-sigs
		fmt.Printf("Caught signal %s: shutting down.\n", sig)
		done <- true
	}()

	go func() {
		err = http.Serve(l, s.Router)
		if err != nil {
			log.Error("http server error", err.Error())
		}
		done <- true
	}()

	<-done
	return nil
}
コード例 #12
0
ファイル: longhorn.go プロジェクト: srenkens/convoy
func Init(root string, config map[string]string) (convoydriver.ConvoyDriver, error) {
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
		dev.RancherURL = override(dev.RancherURL, config[LH_RANCHER_URL])
		dev.RancherAccessKey = override(dev.RancherAccessKey, config[LH_RANCHER_ACCESS_KEY])
		dev.RancherSecretKey = override(dev.RancherSecretKey, config[LH_RANCHER_SECRET_KEY])
	} else {
		if err := util.MkdirIfNotExists(root); err != nil {
			return nil, err
		}

		url := config[LH_RANCHER_URL]
		accessKey := config[LH_RANCHER_ACCESS_KEY]
		secretKey := config[LH_RANCHER_SECRET_KEY]

		if url == "" || accessKey == "" || secretKey == "" {
			return nil, fmt.Errorf("Missing required parameter. lh.rancherurl or lh.rancheraccesskey or lh.ranchersecretkey")
		}

		if _, exists := config[LH_DEFAULT_VOLUME_SIZE]; !exists {
			config[LH_DEFAULT_VOLUME_SIZE] = DEFAULT_VOLUME_SIZE
		}
		volumeSize, err := util.ParseSize(config[LH_DEFAULT_VOLUME_SIZE])
		if err != nil || volumeSize == 0 {
			return nil, fmt.Errorf("Illegal default volume size specified")
		}

		dev = &Device{
			Root:              root,
			RancherURL:        url,
			RancherAccessKey:  accessKey,
			RancherSecretKey:  secretKey,
			DefaultVolumeSize: volumeSize,
		}
	}

	containerName := config[LH_CONTAINER_NAME]
	if containerName == "" {
		handler := metadata.NewClient(RANCHER_METADATA_URL)
		container, err := handler.GetSelfContainer()
		if err != nil {
			return nil, err
		}
		containerName = container.UUID
	}

	log.Debugf("Try to connect to Rancher server at %s [%s:%s]", dev.RancherURL, dev.RancherAccessKey, dev.RancherSecretKey)
	client, err := rancherClient.NewRancherClient(&rancherClient.ClientOpts{
		Url:       dev.RancherURL,
		AccessKey: dev.RancherAccessKey,
		SecretKey: dev.RancherSecretKey,
	})
	if err != nil {
		return nil, fmt.Errorf("Failed to establish connection to Rancher server")
	}

	if err := util.ObjectSave(dev); err != nil {
		return nil, err
	}
	d := &Driver{
		client:        client,
		containerName: containerName,
		Device:        *dev,
	}

	return d, nil
}
コード例 #13
0
ファイル: daemon.go プロジェクト: versus/convoy
// Start the daemon
func Start(sockFile string, c *cli.Context) error {
	var err error

	if err = daemonEnvironmentSetup(c); err != nil {
		return err
	}
	defer environmentCleanup()

	root := c.String("root")
	s := &daemon{
		ConvoyDrivers: make(map[string]convoydriver.ConvoyDriver),
	}
	config := &daemonConfig{
		Root: root,
	}
	exists, err := util.ObjectExists(config)
	if err != nil {
		return err
	}
	driverOpts := util.SliceToMap(c.StringSlice("driver-opts"))
	if exists {
		log.Debug("Found existing config. Ignoring command line opts, loading config from ", root)
		if err := util.ObjectLoad(config); err != nil {
			return err
		}
	} else {
		driverList := c.StringSlice("drivers")
		if len(driverList) == 0 || driverOpts == nil {
			return fmt.Errorf("Missing or invalid parameters")
		}
		log.Debug("Creating config at ", root)

		config.DriverList = driverList
		config.DefaultDriver = driverList[0]
	}
	s.daemonConfig = *config

	if err := s.initDrivers(driverOpts); err != nil {
		return err
	}
	if err := s.finializeInitialization(); err != nil {
		return err
	}
	if err := util.ObjectSave(config); err != nil {
		return err
	}

	s.Router = createRouter(s)

	if err := util.MkdirIfNotExists(filepath.Dir(sockFile)); err != nil {
		return err
	}

	l, err := net.Listen("unix", sockFile)
	if err != nil {
		fmt.Println("listen err", err)
		return err
	}
	defer l.Close()

	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sigs, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		sig := <-sigs
		fmt.Printf("Caught signal %s: shutting down.\n", sig)
		done <- true
	}()

	go func() {
		err = http.Serve(l, s.Router)
		if err != nil {
			log.Error("http server error", err.Error())
		}
		done <- true
	}()

	<-done
	return nil
}
コード例 #14
0
ファイル: glusterfs.go プロジェクト: willbryant/convoy
func Init(root string, config map[string]string) (convoydriver.ConvoyDriver, error) {
	dev := &Device{
		Root: root,
	}
	exists, err := util.ObjectExists(dev)
	if err != nil {
		return nil, err
	}
	if exists {
		if err := util.ObjectLoad(dev); err != nil {
			return nil, err
		}
	} else {
		if err := util.MkdirIfNotExists(root); err != nil {
			return nil, err
		}

		stack := config[GLUSTERFS_RANCHER_STACK]
		if stack == "" {
			return nil, fmt.Errorf("Missing required parameter: %v", GLUSTERFS_RANCHER_STACK)
		}
		service := config[GLUSTERFS_RANCHER_GLUSTER_SERVICE]
		if service == "" {
			return nil, fmt.Errorf("Missing required parameter: %v", GLUSTERFS_RANCHER_GLUSTER_SERVICE)
		}
		defaultVolumePool := config[GLUSTERFS_DEFAULT_VOLUME_POOL]
		if defaultVolumePool == "" {
			return nil, fmt.Errorf("Missing required parameter: %v", GLUSTERFS_DEFAULT_VOLUME_POOL)
		}

		dev = &Device{
			Root:              root,
			RancherStack:      stack,
			RancherService:    service,
			DefaultVolumePool: defaultVolumePool,
		}
	}

	serverIPs, err := rancher.GetIPsForServiceInStack(dev.RancherService, dev.RancherStack)
	if err != nil {
		return nil, err
	}

	d := &Driver{
		mutex:    &sync.RWMutex{},
		gVolumes: map[string]*GlusterFSVolume{},
		Device:   *dev,
	}
	gVolume := &GlusterFSVolume{
		UUID:       dev.DefaultVolumePool,
		ServerIPs:  serverIPs,
		configPath: d.Root,
	}
	// We would always mount the default volume pool
	// TODO: Also need to mount any existing volume's pool
	if _, err := util.VolumeMount(gVolume, "", true); err != nil {
		return nil, err
	}
	d.gVolumes[d.DefaultVolumePool] = gVolume

	if err := util.ObjectSave(dev); err != nil {
		return nil, err
	}
	return d, nil
}