1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2019 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * This is a Bacula plugin for backup/restore Docker using native tools.
21  *
22  * Author: Radosław Korzeniewski, MMXIX
23  * radoslaw@korzeniewski.net, radekk@inteos.pl
24  * Inteos Sp. z o.o. http://www.inteos.pl/
25  */
26 
27 #ifndef _DKCOMMCTX_H_
28 #define _DKCOMMCTX_H_
29 
30 #include "pluglib.h"
31 #include "lib/ini.h"
32 #include "lib/bregex.h"
33 
34 #define USE_CMD_PARSER
35 #include "fd_common.h"
36 #include "dkinfo.h"
37 
38 /* Plugin compile time variables */
39 #ifndef DOCKER_CMD
40 #ifndef HAVE_WIN32
41 #define DOCKER_CMD                  "/usr/bin/docker"
42 #else
43 #define DOCKER_CMD                  "C:/Program Files/Docker/Docker/resources/bin/docker.exe"
44 #endif
45 #endif
46 
47 #ifndef WORKDIR
48 #define WORKDIR                     "/opt/bacula/working"
49 #endif
50 
51 #define BACULATARIMAGE              "baculatar:" DOCKER_TAR_IMAGE
52 
53 #define BACULACONTAINERFOUT         "fout"
54 #define BACULACONTAINERFIN          "fin"
55 #define BACULACONTAINERERRLOG       "docker.err"
56 #define BACULACONTAINERARCHLOG      "docker.log"
57 
58 /*
59  * Supported backup modes
60  */
61 typedef enum {
62    DKPAUSE,
63    DKNOPAUSE,
64 } DOCKER_BACKUP_MODE_T;
65 
66 /*
67  * The list of restore options saved to the RestoreObject.
68  */
69 static struct ini_items plugin_items_dump[] = {
70 //  name                         handler             comment                                      required  default
71    {"container_create",          ini_store_bool,     "Create container on restore",                      0, "*Yes*"},
72    {"container_run",             ini_store_bool,     "Run container on restore",                         0, "*No*"},
73    {"container_imageid",         ini_store_bool,     "Use Image Id for container creation/start",        0, "*No*"},
74    {"container_defaultnames",    ini_store_bool,     "Use default docker Names on container creation",   0, "*No*"},
75    {"docker_host",               ini_store_str,      "Use defined docker host to restore",                0, "*local*"},
76    {"timeout",                   ini_store_int32,    "Timeout connecting to volume container",           0, "*30*"},
77    {NULL, NULL, NULL, 0, NULL}
78 };
79 
80 /*
81  * This is a low-level communication class which handles command tools execution.
82  */
83 class DKCOMMCTX: public SMARTALLOC {
84  public:
85    char *command;
86 
87    alist *get_all_containers(bpContext *ctx);
88    alist *get_all_images(bpContext *ctx);
89    alist *get_all_volumes(bpContext *ctx);
90    void release_all_dkinfo_list(alist **list);
91    void release_all_pm_list(alist **list);
92    void set_all_to_backup(bpContext *ctx);
93    void set_all_containers_to_backup(bpContext *ctx);
94    void set_all_images_to_backup(bpContext *ctx);
95    void set_all_volumes_to_backup(bpContext *ctx);
96 
get_first_to_backup(bpContext * ctx)97    inline DKINFO *get_first_to_backup(bpContext *ctx) { return (DKINFO*)objs_to_backup->first(); };
get_next_to_backup(bpContext * ctx)98    inline DKINFO *get_next_to_backup(bpContext *ctx) { return (DKINFO*)objs_to_backup->next(); };
finish_backup_list(bpContext * ctx)99    inline void finish_backup_list(bpContext *ctx) { objs_to_backup->last(); };
100 
101    bRC container_commit(bpContext *ctx, DKINFO *dkinfo, int jobid);
102    bRC delete_container_commit(bpContext *ctx, DKINFO *dkinfo, int jobid);
103    bRC image_save(bpContext *ctx, DKID *dkid);
104    bRC backup_docker(bpContext *ctx, DKINFO *dkinfo, int jobid);
105    bRC restore_docker(bpContext *ctx, DKINFO *dkinfo, int jobid);
106    bRC docker_tag(bpContext* ctx, DKID &dkid, POOLMEM *tag);
107    bRC docker_create_run_container(bpContext* ctx, DKINFO *dkinfo);
108    bRC wait_for_restore(bpContext *ctx, DKID &dkid);
109    void update_vols_mounts(bpContext* ctx, DKINFO *container, DKVOLS *volume);
110 
111    int32_t read_data(bpContext *ctx, POOLMEM *buf, int32_t len);
112    int32_t read_output(bpContext *ctx, POOL_MEM &out);
113    int32_t write_data(bpContext *ctx, POOLMEM *buf, int32_t len);
114    void terminate(bpContext *ctx);
get_backend_pid()115    inline int get_backend_pid() { if (bpipe){ return bpipe->worker_pid; } return -1;};
116 
117    bRC parse_parameters(bpContext *ctx, char *argk, char *argv);
118    bRC parse_restoreobj(bpContext *ctx, restore_object_pkt *rop);
119    bRC prepare_bejob(bpContext *ctx, bool estimate);
120    bRC prepare_restore(bpContext *ctx);
121    bRC prepare_working_volume(bpContext* ctx, int jobid);
122    void clean_working_volume(bpContext* ctx);
render_working_volume_filename(POOL_MEM & buf,const char * fname)123    inline void render_working_volume_filename(POOL_MEM &buf, const char *fname)
124       { Mmsg(buf, "%s/%s", workingvolume, fname); };
125    void setworkingdir(char *workdir);
126 
is_open()127    inline bool is_open() { return bpipe != NULL; };
is_closed()128    inline bool is_closed() { return bpipe == NULL; };
is_error()129    inline bool is_error() { return f_error || f_fatal; };
set_error()130    inline void set_error() { f_error = true; };
is_fatal()131    inline bool is_fatal() { return f_fatal || (f_error && abort_on_error); };
is_eod()132    inline bool is_eod() { return f_eod; };
clear_eod()133    inline void clear_eod() { f_eod = false; };
set_eod()134    inline void set_eod() { f_eod = true; };
set_abort_on_error()135    inline void set_abort_on_error() { abort_on_error = true; };
clear_abort_on_error()136    inline void clear_abort_on_error() { abort_on_error = false; };
is_abort_on_error()137    inline bool is_abort_on_error() { return abort_on_error; };
is_all_vols_to_backup()138    inline bool is_all_vols_to_backup() { return all_vols_to_backup; };
is_remote_docker()139    inline bool is_remote_docker() { return param_docker_host != NULL; };
timeout()140    inline int32_t timeout() { return param_timeout; };
141 
142    DKCOMMCTX(const char *cmd);
143    ~DKCOMMCTX();
144 
145  private:
146    BPIPE *bpipe;                          /* this is our bpipe to communicate with command tools */
147    alist *param_include_container;        /* the include parameter list which filter what container name to backup as regex */
148    alist *param_include_image;            /* the include parameter list which filter what image name to backup as regex */
149    alist *param_exclude_container;        /* the exclude parameter list which filter what container name to exclude from backup */
150    alist *param_exclude_image;            /* the exclude parameter list which filter what image name to exclude from backup */
151    alist *param_container;                /* the container parameter list which filter what container name or id to backup */
152    alist *param_image;                    /* the image parameter list which filter what image name or id to backup */
153    alist *param_volume;                   /* the volume parameter list which filter what volume name to backup */
154    DOCKER_BACKUP_MODE_T param_mode;       /* the mode parameter which is used with docker commit, default is pause */
155    bool param_container_create;           /* the restore parameter for container creation */
156    bool param_container_run;              /* the restore parameter for container creation and execution */
157    bool param_container_imageid;          /* the restore parameter for setting imageid during container creation/run */
158    bool param_container_defaultnames;     /* the restore parameter for setting default docker names on container creation */
159    POOLMEM *param_docker_host;            /* use defined docker host to docker operations */
160    int32_t param_timeout;                 /* a timeout opening container communication pipe, the default is 30 */
161    regex_t preg;                          /* this is a regex context for include/exclude */
162    bool abort_on_error;                   /* abort on error flag */
163    alist *all_containers;                 /* the list of all containers defined on Docker */
164    alist *all_images;                     /* the list of all docker images defined on Docker */
165    alist *all_volumes;                    /* the list of all docker volumes defined on Docker */
166    alist *objs_to_backup;                 /* the list of all docker objects selected to backup or filtered */
167    bool all_to_backup;                    /* if true use all_containers list to backup or containers_to_backup list when false */
168    bool all_vols_to_backup;               /* if true use all volumes for container to backup */
169    bool f_eod;                            /* the command tool signaled EOD */
170    bool f_error;                          /* the plugin signaled an error */
171    bool f_fatal;                          /* the plugin signaled a fatal error */
172    ConfigFile *ini;                       /* restore object config parser */
173    POOLMEM *workingvolume;                /* */
174    POOLMEM *workingdir;                   /* runtime working directory from file daemon */
175 
176    bool execute_command(bpContext *ctx, POOLMEM *args);
177    bool execute_command(bpContext *ctx, const char *args);
178    bool execute_command(bpContext *ctx, POOL_MEM &args);
179    void parse_parameters(bpContext *ctx, ini_items &item);
180    bool render_param(bpContext *ctx, POOLMEM **param, const char *pname, const char *fmt, const char *name, char *value);
181    bool render_param(bpContext *ctx, POOLMEM **param, const char *pname, const char *fmt, const char *name, int value);
182    bool render_param(bpContext *ctx, POOLMEM **param, const char *pname, const char *name, char *value);
183    bool render_param(bpContext *ctx, bool *param, const char *pname, const char *name, bool value);
184    bool render_param(bpContext *ctx, int32_t *param, const char *pname, const char *name, int32_t value);
185    bool add_param_str(bpContext *ctx, alist **list, const char *pname, const char *name, char *value);
186    bool parse_param(bpContext *ctx, POOLMEM **param, const char *pname, const char *name, char *value);
187    bool parse_param(bpContext *ctx, bool *param, const char *pname, const char *name, char *value);
188    bool parse_param(bpContext *ctx, int32_t *param, const char *pname, const char *name, char *value);
189    bool parse_param(bpContext *ctx, DOCKER_BACKUP_MODE_T *param, const char *pname, const char *name, char *value);
190 
191    void filter_param_to_backup(bpContext *ctx, alist *params, alist *dklist, bool estimate);
192    void filter_incex_to_backup(bpContext *ctx, alist *params_include, alist *params_exclude, alist *dklist);
193    void add_container_volumes_to_backup(bpContext *ctx);
194    void select_container_vols(bpContext *ctx);
195    alist *get_all_list_from_docker(bpContext* ctx, const char *cmd, int cols, alist **dklist, DKINFO_OBJ_t type);
196    void setup_dkinfo(bpContext* ctx, DKINFO_OBJ_t type, char *paramtab[], DKINFO *dkinfo);
197    void setup_container_dkinfo(bpContext* ctx, char *paramtab[], DKINFO *dkinfo);
198    void setup_image_dkinfo(bpContext* ctx, char *paramtab[], DKINFO *dkinfo);
199    void setup_volume_dkinfo(bpContext* ctx, char *paramtab[], DKINFO *dkinfo);
200    bRC run_container_volume_cmd(bpContext* ctx, const char *cmd, POOLMEM *volname, int jobid);
201    bRC run_container_volume_save(bpContext* ctx, POOLMEM *volname, int jobid);
202    bRC run_container_volume_load(bpContext* ctx, POOLMEM *volname, int jobid);
203    bool check_for_docker_errors(bpContext* ctx, char *buf);
render_imagesave_name(POOL_MEM & out,DKINFO * dkinfo,int jobid)204    inline void render_imagesave_name(POOL_MEM &out, DKINFO *dkinfo, int jobid)
205       { Mmsg(out, "%s/%s/%d:backup", dkinfo->get_container_names(),
206             dkinfo->get_container_id()->digest_short(), jobid); };
207    void dump_robjdebug(bpContext *ctx, restore_object_pkt *rop);
208 };
209 
210 #endif   /* _DKCOMMCTX_H_ */