rclone

package
v0.4.53 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package rclone talks to the rclone daemon this distribution already installs.

The installer puts rclone on every box and runs it as a service:

ExecStart=/usr/bin/rclone rcd --rc-addr unix:///var/run/rclone/rclone.sock --rc-no-auth

which means S3, SFTP, FTP, the retries, the resume after a broken connection and the incremental comparison are already here, already running, and already driven over an API. None of that is worth writing again in Go.

Two things about that daemon are worth knowing before trusting it with credentials. It listens with --rc-no-auth, so any local process can read and write every remote it holds; that is already true of the cloud drives CasaOS stores there today. And it is pinned at v1.61.1, which is old but long predates every backend used here.

Index

Constants

View Source
const DestinationPrefix = "casaos-backup-"

DestinationPrefix marks a remote as one of ours.

Backup destinations live in rclone's own config, next to the cloud drives CasaOS mounts -- which is deliberate: the credentials then sit where this project already keeps credentials of exactly that kind, rather than in a second store invented for the purpose. The prefix is what tells the two apart, and it is readable in `rclone config` by anyone wondering what CasaOS put there.

View Source
const RawSuffix = "-raw"

RawSuffix marks the remote underneath an encrypted destination: the bucket or the server itself, which holds only ciphertext and is never listed as a destination in its own right. A name ending in it is refused, so the two can always be told apart.

View Source
const SocketPath = "/var/run/rclone/rclone.sock"

SocketPath is where the unit file puts the daemon's socket.

Variables

View Source
var ErrDaemonUnreachable = errors.New("the rclone daemon is not answering on " + SocketPath)

ErrDaemonUnreachable is returned when the socket is not there or not answering. It is worth its own error: it means rclone is not running, which is a different problem from a destination being misconfigured, and the two get different advice.

Functions

func Destination

func Destination(name, remotePath string) string

Destination turns a destination name and a path inside it into the `remote:path` rclone expects.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client drives the rclone daemon over its unix socket.

func NewClient

func NewClient() *Client

NewClient returns a client bound to the daemon's socket.

The timeout here covers control calls only -- listing remotes, creating one, checking one answers. A transfer is started as a job and polled, so no copy ever has to finish inside one request.

func (*Client) CheckDestination

func (c *Client) CheckDestination(name string) (DestinationSpace, error)

CheckDestination asks a destination whether it is reachable, and what it can say about its space.

Worth doing at the moment somebody configures a destination rather than at the moment a backup runs: a typo in a bucket name found at 3am by a scheduled job nobody is watching is a backup that never existed.

func (*Client) CopyDirectory

func (c *Client) CopyDirectory(ctx context.Context, source, destinationName, destinationPath string) error

CopyDirectory copies a folder and everything under it, and blocks until it is done.

This is rclone's `copy`, not `sync`: it adds and updates, and never deletes anything at the destination. A backup that deletes is a backup that can destroy the previous one when the source is wrong -- an app whose folder was unmounted at the moment of the run looks exactly like an app whose files were all deleted.

func (*Client) CopyFile

func (c *Client) CopyFile(ctx context.Context, source, destinationName, destinationPath string) error

CopyFile copies a single file.

rclone addresses a file as a folder plus a name, on both sides, which is why this takes the whole path and splits it: handing `/etc/app/php.ini` to the directory call above would copy `/etc/app` entire.

func (*Client) CreateDestination

func (c *Client) CreateDestination(name, backend string, parameters map[string]string) error

CreateDestination adds or replaces a backup destination.

`backend` is an rclone backend name -- "s3", "sftp", "ftp" -- and `parameters` are that backend's own options. Neither is interpreted here: rclone validates them, rclone knows what each backend needs, and a list of required fields maintained on this side would go stale the first time rclone gained an option.

func (*Client) CreateEncryptedDestination added in v0.4.44

func (c *Client) CreateEncryptedDestination(name, backend string, parameters map[string]string, password string) error

CreateEncryptedDestination makes a destination whose contents -- names and bytes both -- are encrypted before they leave this box.

Two remotes: the backend itself under the raw name, and rclone's crypt backend on top of it under the destination's name. Everything else in this package talks to the top one and never knows the difference; a bucket at a provider holds ciphertext it cannot read. The password is obscured by rclone into its config the way it obscures every password it keeps, and is not readable back through this API.

func (*Client) DeleteDestination

func (c *Client) DeleteDestination(name string) error

DeleteDestination forgets a destination and its credentials. Whatever was already copied to it stays where it is: this removes the way in, not the backup.

func (*Client) Destinations

func (c *Client) Destinations() ([]string, error)

Destinations lists the remotes this project put there, by their short name -- the prefix is an implementation detail and does not belong in an interface.

func (*Client) Fetch added in v0.4.41

func (c *Client) Fetch(ctx context.Context, destinationName, remotePath string) ([]byte, error)

Fetch reads one file held at a destination.

rclone's API has no "read this file" call; the file is copied into a folder of ours and read from there. Small files only -- a manifest, a compose file -- which is all a restore needs to read before it starts copying.

func (*Client) JobStatus

func (c *Client) JobStatus(id int64) (JobStatus, error)

JobStatus asks after one job.

func (*Client) Purge

func (c *Client) Purge(ctx context.Context, destinationName, remotePath string) error

Purge deletes one run and everything under it.

The only call in this package that removes anything, kept separate from the copies for that reason: nothing that copies can reach it by accident.

func (*Client) RestoreDirectory added in v0.4.41

func (c *Client) RestoreDirectory(ctx context.Context, destinationName, remotePath, hostPath string) error

RestoreDirectory makes hostPath hold what the destination holds under remotePath.

sync/sync rather than sync/copy: a restore means "as it was", and a file that appeared in that folder after the backup was taken is not part of "as it was". This is the one call in the package that deletes something on this host, and it deletes exactly what a restore is asked to undo.

func (*Client) RestoreFile added in v0.4.41

func (c *Client) RestoreFile(ctx context.Context, destinationName, remotePath, hostPath string) error

RestoreFile puts one file from the destination at hostPath.

func (*Client) Runs

func (c *Client) Runs(destinationName, appPath string) ([]string, error)

Runs lists the runs an app has at a destination, by their stamp.

Directories only, one level down: the layout puts every run of an app in its own folder under the app's, and nothing else lives there.

func (*Client) StopJob

func (c *Client) StopJob(id int64) error

StopJob asks the daemon to abandon a job.

type DestinationSpace

type DestinationSpace struct {
	// Used and Free are bytes, and either may be absent: plenty of backends,
	// object stores especially, have no answer to "how much room is left", and
	// inventing one would be worse than saying nothing.
	Used  *int64 `json:"used,omitempty"`
	Free  *int64 `json:"free,omitempty"`
	Total *int64 `json:"total,omitempty"`
}

DestinationSpace is what a destination says about itself when asked.

type JobStatus

type JobStatus struct {
	ID       int64   `json:"id"`
	Finished bool    `json:"finished"`
	Success  bool    `json:"success"`
	Error    string  `json:"error"`
	Duration float64 `json:"duration"`
}

JobStatus is what the daemon says about a job.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL