diff --git a/main.go b/main.go index e56a255..9b6852c 100644 --- a/main.go +++ b/main.go @@ -17,6 +17,7 @@ import ( "github.com/bytesizedhosting/bcd/plugins/plexrequests" "github.com/bytesizedhosting/bcd/plugins/proxy" "github.com/bytesizedhosting/bcd/plugins/rocketchat" + "github.com/Dedsec1/bcd/plugins/rclone" "github.com/bytesizedhosting/bcd/plugins/rtorrent" "github.com/bytesizedhosting/bcd/plugins/sickrage" "github.com/bytesizedhosting/bcd/plugins/sonarr" @@ -67,6 +68,13 @@ func startApp(config *core.MainConfig) { } else { engine.Activate(plex) } + + rclone, err := rclone.New(dockerClient) + if err != nil { + log.Infoln("Could not enable plugin: ", err) + } else { + engine.Activate(rclone) + } rocketchat, err := rocketchat.New(dockerClient) if err != nil { diff --git a/plugins/rclone/data/manifest.yml b/plugins/rclone/data/manifest.yml new file mode 100644 index 0000000..743b085 --- /dev/null +++ b/plugins/rclone/data/manifest.yml @@ -0,0 +1,41 @@ +exposed_methods: +- Install +- Restart +- Stop +- Start +method_options: + Install: + - default_vault: /home/bytesized/rclone + hint: "" + name: config_folder + type: string + - default_value: /home/bytesized/rclone/data + hint: "" + name: data_folder + type: string + Restart: + - default_value: "" + hint: "" + name: rclone-bcd + type: string + Start: + - default_value: "" + hint: "" + name: rclone-bcd + type: string + Stop: + - default_value: "" + hint: "" + name: rclone-bcd + type: string +name: Rclone +rpc_name: RcloneRPC +show_options: +- username +- password +- web_port +- config_folder +- data_folder +version: 1 +web_url_format: http://##ip##:##web_port##/ +description: "Data synchronization and back-up tool build on bitorrent technology" diff --git a/plugins/rclone/rclone.go b/plugins/rclone/rclone.go new file mode 100644 index 0000000..127dccb --- /dev/null +++ b/plugins/rclone/rclone.go @@ -0,0 +1,89 @@ +package Rclone + +import ( + log "github.com/Sirupsen/logrus" + "github.com/fsouza/go-dockerclient" + "github.com/bytesizedhosting/bcd/plugins" + "net/rpc" + "os" +) + +type Rclone struct { + plugins.Base + imageName string +} + +func New(client *docker.Client) (*Rclone, error) { + manifest, err := plugins.LoadManifest("Rclone") + + if err != nil { + return nil, err + } + + return &Rclone{Base: plugins.Base{DockerClient: client, Name: "Rclone", Version: 1, Manifest: manifest}, imageName: "bytesized/rclone"}, nil +} + +func (self *Rclone) RegisterRPC(server *rpc.Server) { + rpc := plugins.NewBaseRPC(self) + server.Register(&RcloneRPC{base: self, BaseRPC: *rpc}) +} + +type RcloneOpts struct { + plugins.BaseOpts +} + +func (self *Rclone) Install(opts *RcloneOpts) error { + var err error + + err = opts.SetDefault(self.Name) + if err != nil { + return err + } + + log.WithFields(log.Fields{ + "plugin": self.Name, + "datafolder": opts.DataFolder, + "configfolder": opts.ConfigFolder, + "media_folder": opts.MediaFolder, + }).Debug("Rclone options") + + err = os.MkdirAll(opts.ConfigFolder, 0755) + if err != nil { + return err + } + + log.Debugln("Pulling docker image", self.imageName) + err = self.DockerClient.PullImage(docker.PullImageOptions{Repository: self.imageName}, docker.AuthConfiguration{}) + if err != nil { + return err + } + + portBindings := map[docker.Port][]docker.PortBinding{ + "8989/tcp": []docker.PortBinding{docker.PortBinding{HostPort: opts.WebPort}}, + } + + hostConfig := docker.HostConfig{ + PortBindings: portBindings, + Binds: plugins.DefaultBindings(opts), + } + + conf := docker.Config{Env: []string{"PUID=" + opts.User.Uid}, Image: self.imageName} + + log.Debugln("Creating docker container") + c, err := self.DockerClient.CreateContainer(docker.CreateContainerOptions{Config: &conf, HostConfig: &hostConfig, Name: "bytesized_rclone_" + opts.WebPort}) + + if err != nil { + return err + } + + log.Debugln("Starting docker container") + + err = self.DockerClient.StartContainer(c.ID, nil) + if err != nil { + return err + } + + opts.ContainerId = c.ID + + return nil +} diff --git a/plugins/rclone/rpc_proxy.go b/plugins/rclone/rpc_proxy.go new file mode 100644 index 0000000..c5c62f4 --- /dev/null +++ b/plugins/rclone/rpc_proxy.go @@ -0,0 +1,118 @@ +package Rclone + +import ( + log "github.com/Sirupsen/logrus" + "github.com/fsouza/go-dockerclient" + "os" +) + +func NewRcloneRPC(parent appPlugin) *RcloneRPC { + return &RcloneRPC{parent} +} + +type RcloneRPC struct { + base appPlugin +} + +type ActionOpts struct { + ContainerId string `json:"container_id"` + DeleteFolders []string `json:"delete_folders"` +} + +func (self *RcloneRPC) Start(opts *RcloneOpts, success *bool) error { + containerId := opts.ContainerId + log.WithFields(log.Fields{ + "container_id": containerId, + "name": self.base.GetName(), + }).Info("Starting container") + + err := self.base.Start(&AppConfig{ContainerId: containerId}) + + if err != nil { + return err + } + *success = true + + log.WithFields(log.Fields{ + "container_id": containerId, + "name": self.base.GetName(), + }).Info("Container started") + + return nil +} + +func (self *RcloneRPC) Status(opts *RcloneOpts, state *docker.State) error { + containerId := opts.ContainerId + s, err := self.base.Status(&AppConfig{ContainerId: containerId}) + if err != nil { + return err + } + + *state = *s + return nil +} + +func (self *RcloneRPC) Stop(opts *RcloneOpts, success *bool) error { + containerId := opts.ContainerId + log.WithFields(log.Fields{ + "container_id": containerId, + "name": self.base.GetName(), + }).Info("Stopping container") + + err := self.base.Stop(&AppConfig{ContainerId: containerId}) + + if err != nil { + return err + } + *success = true + + log.WithFields(log.Fields{ + "container_id": containerId, + "name": self.base.GetName(), + }).Info("Container stopped") + + return nil +} +func (self *RcloneRPC) Restart(opts *RcloneOpts, success *bool) error { + containerId := opts.ContainerId + err := self.base.Restart(&AppConfig{ContainerId: containerId}) + + if err != nil { + return err + } + *success = true + + return nil +} +func (self *RcloneRPC) Uninstall(opts *RcloneOpts, success *bool) error { + containerId := opts.ContainerId + + log.WithFields(log.Fields{ + "container_id": containerId, + "name": self.base.GetName(), + }).Info("Removing container") + + err := self.base.Uninstall(&AppConfig{ContainerId: containerId}) + + if err != nil { + return err + } + *success = true + + if len(opts.DeleteFolders) > 0 { + for _, folder := range opts.DeleteFolders { + log.WithFields(log.Fields{"folder": folder}).Info("Removing folder") + err := os.RemoveAll(folder) + if err != nil { + log.Infof("Could not delete folder '%s': '%s'", folder, err) + } + } + } + + log.WithFields(log.Fields{ + "container_id": containerId, + "name": self.base.GetName(), + }).Info("Container removed") + + return nil +}