Beispiel #1
0
func (c *MountCommand) mountFolder(r req.MountFolder) error {
	warning, err := c.Klient.RemoteMountFolder(r)
	if err != nil {
		switch {
		case klientctlerrors.IsExistingMountErr(err):
			util.MustConfirm("This folder is already mounted. Remount? [Y|n]")

			// unmount using mount path
			//
			// TODO: Fix abstraction leak.
			if err := unmount(c.Klient.GetClient(), r.Name, r.LocalPath, c.Log); err != nil {
				c.printfln(defaultHealthChecker.CheckAllFailureOrMessagef(FailedToUnmount))
				return fmt.Errorf("Error unmounting (remounting). err:%s", err)
			}

			warning, err = c.Klient.RemoteMountFolder(r)
			if err != nil {
				c.printfln(defaultHealthChecker.CheckAllFailureOrMessagef(FailedToMount))
				return fmt.Errorf("Error mounting (remounting). err:%s", err)
			}

		case klientctlerrors.IsDialFailedErr(err):
			c.printfln(defaultHealthChecker.CheckAllFailureOrMessagef(FailedDialingRemote))
			return fmt.Errorf("Error dialing remote klient. err:%s", err)

		case klientctlerrors.IsMachineNotValidYetErr(err):
			c.printfln(defaultHealthChecker.CheckAllFailureOrMessagef(MachineNotValidYet))
			return fmt.Errorf("Machine is not valid yet. err:%s", err)

		case klientctlerrors.IsRemotePathNotExistErr(err):
			c.printfln(RemotePathDoesNotExist)
			return fmt.Errorf("Remote path does not exist. err:%s", err)

		case klientctlerrors.IsMachineActionLockedErr(err):
			c.printfln(MachineMountActionIsLocked, r.Name)
			return fmt.Errorf("Machine is locked. err:%s", err)

		default:
			// catch any remaining errors
			c.printfln(defaultHealthChecker.CheckAllFailureOrMessagef(FailedToMount))
			return fmt.Errorf("Error mounting directory. err:%s", err)
		}
	}

	// TODO: Remove this check? The above switch has a default case, this is useless,
	// right?
	//
	// catch errors other than klientctlerrors.IsExistingMountErr
	if err != nil {
		c.printfln(defaultHealthChecker.CheckAllFailureOrMessagef(FailedToMount))
		return fmt.Errorf("Error mounting directory. err:%s", err)
	}

	if warning != "" {
		c.printfln("Warning: %s\n", warning)
	}

	return nil
}
Beispiel #2
0
// callRemoteCache performs a Klient.RemoteCache request.
func (c *Command) callRemoteCache(r req.Cache, progressCb func(par *dnode.Partial)) error {
	if err := c.Klient.RemoteCache(r, progressCb); err != nil {
		// Because we have a progress bar in the UX currently, we need to add a
		// newline if there's an error.
		c.Stdout.Printlnf("")
		switch {
		case klientctlerrors.IsRemotePathNotExistErr(err):
			c.Stdout.Printlnf(errormessages.RemotePathDoesNotExist)
			return fmt.Errorf("Remote path does not exist. err:%s", err)
		case klientctlerrors.IsProcessError(err):
			c.Stdout.Printlnf(errormessages.RemoteProcessFailed, err)
			return err
		default:
			c.Stdout.Printlnf(
				c.HealthChecker.CheckAllFailureOrMessagef(errormessages.FailedPrefetchFolder),
			)
			return fmt.Errorf("remote.cacheFolder returned an error. err:%s", err)
		}
	}

	return nil
}
Beispiel #3
0
// smartOptions attempts to assign options based on the remote and local environment.
// Eg, if it's a small directory, pure fuse is used. Large directory, and
// onewaysync is used. Massive directory (too big for local system), and fuse is used.
func (c *MountCommand) smartOptions() (err error) {
	if c.hasFlaggedOpts() {
		c.Log.Debug("Mount has flagged options, not using SmartOptions.")
		return nil
	}

	c.Log.Debug("Mount has no flagged options, using SmartOptions.")

	if c.Options.Name == "" || c.Options.LocalPath == "" {
		c.printfln("Mount name and local path are required options.\n")
		c.Help()
		return errors.New("not enough arguments: missing Name or LocalPath")
	}

	// Repeat the message after every smart option return, if no errors.
	// Using a defer to avoid code reuse.
	defer func() {
		if err == nil {
			c.printfln("To manually specify mount options, see: kd mount --help\n")
		}
	}()

	remoteSize, err := c.Klient.RemoteGetPathSize(req.GetPathSizeOptions{
		Debug:      c.Options.Debug,
		Machine:    c.Options.Name,
		RemotePath: c.Options.RemotePath,
	})
	if err != nil {
		c.Log.Error("Unable to get remote path size. err:%s", err)
		if klientctlerrors.IsRemotePathNotExistErr(err) {
			c.printfln(errormessages.RemotePathDoesNotExist)
			return fmt.Errorf("remote path does not exist: %s", err)
		}
		return err
	}

	// Using parent since the given directory will not yet exist.
	localSize, err := getLocalDiskSize(filepath.Dir(c.Options.LocalPath))
	if err != nil {
		c.Log.Error("Unable to get local disk size. err:%s", err)
		return err
	}

	c.Log.Debug(
		"Deciding on smart options. RemotePathSize:%d, LocalDiskSize:%d",
		remoteSize, localSize,
	)

	// if the folder is larger than our specified largeFolderBytes, store isLargeFolder
	// for easy usage.
	isLargeFolder := remoteSize > largeFolderBytes

	// If the mounting the remote folder will take up more than 75% of
	// the local disk, use fuse not rsync, no matter what size the remote folder is.
	if remoteSize > uint64(float64(localSize)*0.75) {
		c.printfln("Remote folder will take more than 75%% of local disk space.")

		if isLargeFolder {
			// no options needed, fuse is default.
			c.printfln("Because of this, mounting via fuse.")
		} else {
			// if the remote folder is large, use fuse caching option.
			c.printfln("Because of this, mounting via fuse and prefetchall.")
			c.Options.PrefetchAll = true
		}

		// fuse is the default, so we don't need any values.
		return nil
	}

	if isLargeFolder {
		c.printfln("Remote folder is over 1Gb, mounting via oneway sync.")
		c.Options.OneWaySync = true
		return nil
	}

	c.printfln("Mounting via fuse.")

	return nil
}