[lxc-devel] [PATCH] snapshots: move snapshot directory (v5)

S.Çağlar Onur caglar at 10ur.org
Fri May 30 03:57:14 UTC 2014


On Wed, May 28, 2014 at 8:32 PM, S.Çağlar Onur <caglar at 10ur.org> wrote:
> Hi Serge,
>
> On Tue, May 27, 2014 at 5:24 PM, Serge Hallyn <serge.hallyn at ubuntu.com> wrote:
>> Originally we kept snapshots under /var/lib/lxcsnaps.  If a
>> separate btrfs is mounted at /var/lib/lxc, then we can't
>> make btrfs snapshots under /var/lib/lxcsnaps.
>>
>> This patch moves the default directory to /var/lib/lxc/c/snaps.
>> If /var/lib/lxcsnaps already exists, then we continue to use that.
>>
>> add c->destroy_with_snapshots() and c->snapshot_destroy_all()
>> API methods.  c->snashot_destroy_all() can be triggered from
>> lxc-snapshot using '-d ALL'.  There is no command to call
>> c->destroy_with_snapshots(c) as of yet.
>>
>> lxclock: use ".$lxcname" for container lock files
>> that way we can use /run/lock/lxc/$lxcpath/$lxcname/snaps as a
>> directory when locking snapshots without having to worry about
>> /run/lock//lxc/$lxcpath/$lxcname being a file.
>>
>> destroy: split off a container_destroy
>> container_destroy() doesn't check for snapshots, so snapshot_rename can
>> use it.  api_destroy() now does check for snapshots (previously it only
>> checked for fs - i.e. overlayfs/aufs - snapshots).
>>
>> Add destroy to the manpage, as it was previously undocumented.
>>
>> Update snapshot testcase accordingly.
>>
>> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
>
> This version is not cleanly getting applied on top of current master
> so I ended up modifying the patch locally. I might have introduced a
> problem or two while doing that cause my tests started to fail with
> this. Unfortunately I haven't been able to find some time to debug it
> further. Will try again and catch you on irc tomorrow.

So I found why my tests are failing and my first reaction was blaming
the Go bindings but then I realized that python bindings are also not
working. Somehow this patch is causing create to fail and I'm not
seeing how. Please see below, same thing happens with Go (a file named
as template argument appears in the directory but nothing else
happens) but lxc-create works just fine.

[caglar at qop:~/t] pwd
/home/caglar/t
[caglar at qop:~/t] sudo lxc-ls
[caglar at qop:~/t] ls
[caglar at qop:~/t] sudo python3
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lxc
>>> c = lxc.Container("r")
>>> c.create("ubuntu")
True
>>>
[caglar at qop:~/t] cat ubuntu
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.hwaddr = 00:16:3e:e6:0b:a0
[caglar at qop:~/t] sudo lxc-ls
[caglar at qop:~/t]
[caglar at qop:~/t] sudo lxc-create -n r -t ubuntu
Checking cache download in /var/cache/lxc/trusty/rootfs-amd64 ...
Copy /var/cache/lxc/trusty/rootfs-amd64 to /var/lib/lxc/r/rootfs ...
Copying rootfs to /var/lib/lxc/r/rootfs ...
Generating locales...
  en_US.UTF-8... up-to-date
Generation complete.
Creating SSH2 RSA key; this may take some time ...
Creating SSH2 DSA key; this may take some time ...
Creating SSH2 ECDSA key; this may take some time ...
Creating SSH2 ED25519 key; this may take some time ...
update-rc.d: warning: default stop runlevel arguments (0 1 6) do not
match ssh Default-Stop values (none)
invoke-rc.d: policy-rc.d denied execution of start.

Current default time zone: 'America/New_York'
Local time is now:      Thu May 29 23:53:56 EDT 2014.
Universal Time is now:  Fri May 30 03:53:56 UTC 2014.


##
# The default user is 'ubuntu' with password 'ubuntu'!
# Use the 'sudo' command to run tasks as root in the container.
##


>> ---
>>  doc/lxc-snapshot.sgml.in |  13 +++
>>  src/lxc/bdev.c           |   6 +-
>>  src/lxc/lxc_snapshot.c   |  11 ++-
>>  src/lxc/lxccontainer.c   | 217 ++++++++++++++++++++++++++++++++++++++---------
>>  src/lxc/lxccontainer.h   |  24 +++++-
>>  src/lxc/lxclock.c        |  10 +--
>>  src/lxc/utils.c          |  39 +++++++--
>>  src/lxc/utils.h          |   2 +-
>>  src/tests/snapshot.c     |  29 ++-----
>>  9 files changed, 271 insertions(+), 80 deletions(-)
>>
>> diff --git a/doc/lxc-snapshot.sgml.in b/doc/lxc-snapshot.sgml.in
>> index 4b70279..029534e 100644
>> --- a/doc/lxc-snapshot.sgml.in
>> +++ b/doc/lxc-snapshot.sgml.in
>> @@ -55,6 +55,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>>      <cmdsynopsis>
>>        <command>lxc-snapshot</command>
>>        <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
>> +      <arg choice="req">-d, -destroy <replaceable>snapshot-name</replaceable></arg>
>> +    </cmdsynopsis>
>> +    <cmdsynopsis>
>> +      <command>lxc-snapshot</command>
>> +      <arg choice="req">-n, --name <replaceable>name</replaceable></arg>
>>        <arg choice="req">-L, --list </arg>
>>        <arg choice="opt">-C, --showcomments </arg>
>>      </cmdsynopsis>
>> @@ -92,6 +97,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>>           </varlistentry>
>>
>>           <varlistentry>
>> +           <term> <option>-d,--destroy snapshot-name</option> </term>
>> +          <listitem>
>> +           <para> Destroy the named snapshot.  If the named snapshot is ALL, then all snapshots
>> +           will be destroyed.</para>
>> +          </listitem>
>> +         </varlistentry>
>> +
>> +         <varlistentry>
>>             <term> <option>-L,--list </option> </term>
>>            <listitem>
>>             <para> List existing snapshots. </para>
>> diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c
>> index 751fa9f..efdbecc 100644
>> --- a/src/lxc/bdev.c
>> +++ b/src/lxc/bdev.c
>> @@ -482,7 +482,7 @@ static int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna
>>
>>  static int dir_destroy(struct bdev *orig)
>>  {
>> -       if (lxc_rmdir_onedev(orig->src) < 0)
>> +       if (lxc_rmdir_onedev(orig->src, NULL) < 0)
>>                 return -1;
>>         return 0;
>>  }
>> @@ -2073,7 +2073,7 @@ static int overlayfs_destroy(struct bdev *orig)
>>         if (!upper)
>>                 return -22;
>>         upper++;
>> -       return lxc_rmdir_onedev(upper);
>> +       return lxc_rmdir_onedev(upper, NULL);
>>  }
>>
>>  /*
>> @@ -2350,7 +2350,7 @@ static int aufs_destroy(struct bdev *orig)
>>         if (!upper)
>>                 return -22;
>>         upper++;
>> -       return lxc_rmdir_onedev(upper);
>> +       return lxc_rmdir_onedev(upper, NULL);
>>  }
>>
>>  /*
>> diff --git a/src/lxc/lxc_snapshot.c b/src/lxc/lxc_snapshot.c
>> index 1f8fdaf..58288e0 100644
>> --- a/src/lxc/lxc_snapshot.c
>> +++ b/src/lxc/lxc_snapshot.c
>> @@ -112,7 +112,13 @@ static int do_restore_snapshots(struct lxc_container *c)
>>
>>  static int do_destroy_snapshots(struct lxc_container *c)
>>  {
>> -       if (c->snapshot_destroy(c, snapshot))
>> +       bool bret;
>> +       if (strcmp(snapshot, "ALL") == 0)
>> +               bret = c->snapshot_destroy_all(c);
>> +       else
>> +               bret = c->snapshot_destroy(c, snapshot);
>> +
>> +       if (bret)
>>                 return 0;
>>
>>         ERROR("Error destroying snapshot %s", snapshot);
>> @@ -154,7 +160,8 @@ Options :\n\
>>    -C, --showcomments  show snapshot comments in list\n\
>>    -c, --comment=file  add file as a comment\n\
>>    -r, --restore=name  restore snapshot name, i.e. 'snap0'\n\
>> -  -d, --destroy=name  destroy snapshot name, i.e. 'snap0'\n",
>> +  -d, --destroy=name  destroy snapshot name, i.e. 'snap0'\n\
>> +                      use ALL to destroy all snapshots\n",
>>         .options  = my_longopts,
>>         .parser   = my_parser,
>>         .checker  = NULL,
>> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
>> index fdac433..b0003d1 100644
>> --- a/src/lxc/lxccontainer.c
>> +++ b/src/lxc/lxccontainer.c
>> @@ -1203,6 +1203,8 @@ static void lxcapi_clear_config(struct lxc_container *c)
>>  }
>>
>>  static bool lxcapi_destroy(struct lxc_container *c);
>> +static bool container_destroy(struct lxc_container *c);
>> +static bool get_snappath_dir(struct lxc_container *c, char *snappath);
>>  /*
>>   * lxcapi_create:
>>   * create a container with the given parameters.
>> @@ -1344,7 +1346,7 @@ out_unlock:
>>                 remove_partial(c, partial_fd);
>>  out:
>>         if (!ret && c)
>> -               lxcapi_destroy(c);
>> +               container_destroy(c);
>>  free_tpath:
>>         if (tpath)
>>                 free(tpath);
>> @@ -1950,7 +1952,7 @@ out:
>>         fclose(f);
>>  }
>>
>> -static bool has_snapshots(struct lxc_container *c)
>> +static bool has_fs_snapshots(struct lxc_container *c)
>>  {
>>         char path[MAXPATHLEN];
>>         int ret, v;
>> @@ -1974,10 +1976,38 @@ out:
>>         return bret;
>>  }
>>
>> +static bool has_snapshots(struct lxc_container *c)
>> +{
>> +       char path[MAXPATHLEN];
>> +       struct dirent dirent, *direntp;
>> +       int count=0;
>> +       DIR *dir;
>> +
>> +       if (!get_snappath_dir(c, path))
>> +               return false;
>> +       dir = opendir(path);
>> +       if (!dir)
>> +               return false;
>> +       while (!readdir_r(dir, &dirent, &direntp)) {
>> +               if (!direntp)
>> +                       break;
>> +
>> +               if (!strcmp(direntp->d_name, "."))
>> +                       continue;
>> +
>> +               if (!strcmp(direntp->d_name, ".."))
>> +                       continue;
>> +               count++;
>> +               break;
>> +       }
>> +       closedir(dir);
>> +       return count > 0;
>> +}
>> +
>>  static int lxc_rmdir_onedev_wrapper(void *data)
>>  {
>>         char *arg = (char *) data;
>> -       return lxc_rmdir_onedev(arg);
>> +       return lxc_rmdir_onedev(arg, "snaps");
>>  }
>>
>>  static int do_bdev_destroy(struct lxc_conf *conf)
>> @@ -2012,8 +2042,7 @@ static int bdev_destroy_wrapper(void *data)
>>         return do_bdev_destroy(conf);
>>  }
>>
>> -// do we want the api to support --force, or leave that to the caller?
>> -static bool lxcapi_destroy(struct lxc_container *c)
>> +static bool container_destroy(struct lxc_container *c)
>>  {
>>         bool bret = false;
>>         int ret;
>> @@ -2030,11 +2059,6 @@ static bool lxcapi_destroy(struct lxc_container *c)
>>                 goto out;
>>         }
>>
>> -       if (c->lxc_conf && has_snapshots(c)) {
>> -               ERROR("container %s has dependent snapshots", c->name);
>> -               goto out;
>> -       }
>> -
>>         if (c->lxc_conf && c->lxc_conf->rootfs.path && c->lxc_conf->rootfs.mount) {
>>                 if (am_unpriv())
>>                         ret = userns_exec_1(c->lxc_conf, bdev_destroy_wrapper, c->lxc_conf);
>> @@ -2054,7 +2078,7 @@ static bool lxcapi_destroy(struct lxc_container *c)
>>         if (am_unpriv())
>>                 ret = userns_exec_1(c->lxc_conf, lxc_rmdir_onedev_wrapper, path);
>>         else
>> -               ret = lxc_rmdir_onedev(path);
>> +               ret = lxc_rmdir_onedev(path, "snaps");
>>         if (ret < 0) {
>>                 ERROR("Error destroying container directory for %s", c->name);
>>                 goto out;
>> @@ -2066,6 +2090,37 @@ out:
>>         return bret;
>>  }
>>
>> +static bool lxcapi_destroy(struct lxc_container *c)
>> +{
>> +       if (!c || !lxcapi_is_defined(c))
>> +               return false;
>> +       if (has_snapshots(c)) {
>> +               ERROR("Container %s has snapshots;  not removing", c->name);
>> +               return false;
>> +       }
>> +
>> +       if (has_fs_snapshots(c)) {
>> +               ERROR("container %s has snapshots on its rootfs", c->name);
>> +               return false;
>> +       }
>> +
>> +       return container_destroy(c);
>> +}
>> +
>> +static bool lxcapi_snapshot_destroy_all(struct lxc_container *c);
>> +
>> +static bool lxcapi_destroy_with_snapshots(struct lxc_container *c)
>> +{
>> +       if (!c || !lxcapi_is_defined(c))
>> +               return false;
>> +       if (!lxcapi_snapshot_destroy_all(c)) {
>> +               ERROR("Error deleting all snapshots");
>> +               return false;
>> +       }
>> +       return lxcapi_destroy(c);
>> +}
>> +
>> +
>>  static bool set_config_item_locked(struct lxc_container *c, const char *key, const char *v)
>>  {
>>         struct lxc_config_t *config;
>> @@ -2780,6 +2835,10 @@ static bool lxcapi_rename(struct lxc_container *c, const char *newname)
>>         if (!c || !c->name || !c->config_path || !c->lxc_conf)
>>                 return false;
>>
>> +       if (has_fs_snapshots(c) || has_snapshots(c)) {
>> +               ERROR("Renaming a container with snapshots is not supported");
>> +               return false;
>> +       }
>>         bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
>>         if (!bdev) {
>>                 ERROR("Failed to find original backing store type");
>> @@ -2796,7 +2855,7 @@ static bool lxcapi_rename(struct lxc_container *c, const char *newname)
>>         if (newc && lxcapi_is_defined(newc))
>>                 lxc_container_put(newc);
>>
>> -       if (!lxcapi_destroy(c)) {
>> +       if (!container_destroy(c)) {
>>                 ERROR("Could not destroy existing container %s", c->name);
>>                 return false;
>>         }
>> @@ -2846,16 +2905,42 @@ static int get_next_index(const char *lxcpath, char *cname)
>>         }
>>  }
>>
>> +static bool get_snappath_dir(struct lxc_container *c, char *snappath)
>> +{
>> +       int ret;
>> +       /*
>> +        * If the old style snapshot path exists, use it
>> +        * /var/lib/lxc -> /var/lib/lxcsnaps
>> +        */
>> +       ret = snprintf(snappath, MAXPATHLEN, "%ssnaps", c->config_path);
>> +       if (ret < 0 || ret >= MAXPATHLEN)
>> +               return false;
>> +       if (dir_exists(snappath)) {
>> +               ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
>> +               if (ret < 0 || ret >= MAXPATHLEN)
>> +                       return false;
>> +               return true;
>> +       }
>> +
>> +       /*
>> +        * Use the new style path
>> +        * /var/lib/lxc -> /var/lib/lxc + c->name + /snaps + \0
>> +        */
>> +       ret = snprintf(snappath, MAXPATHLEN, "%s/%s/snaps", c->config_path, c->name);
>> +       if (ret < 0 || ret >= MAXPATHLEN)
>> +               return false;
>> +       return true;
>> +}
>> +
>>  static int lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
>>  {
>>         int i, flags, ret;
>>         struct lxc_container *c2;
>>         char snappath[MAXPATHLEN], newname[20];
>>
>> -       // /var/lib/lxc -> /var/lib/lxcsnaps \0
>> -       ret = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
>> -       if (ret < 0 || ret >= MAXPATHLEN)
>> +       if (!get_snappath_dir(c, snappath)) {
>>                 return -1;
>> +       }
>>         i = get_next_index(snappath, c->name);
>>
>>         if (mkdir_p(snappath, 0755) < 0) {
>> @@ -2989,7 +3074,7 @@ static char *get_timestamp(char* snappath, char *name)
>>  static int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **ret_snaps)
>>  {
>>         char snappath[MAXPATHLEN], path2[MAXPATHLEN];
>> -       int dirlen, count = 0, ret;
>> +       int count = 0, ret;
>>         struct dirent dirent, *direntp;
>>         struct lxc_snapshot *snaps =NULL, *nsnaps;
>>         DIR *dir;
>> @@ -2997,9 +3082,7 @@ static int lxcapi_snapshot_list(struct lxc_container *c, struct lxc_snapshot **r
>>         if (!c || !lxcapi_is_defined(c))
>>                 return -1;
>>
>> -       // snappath is ${lxcpath}snaps/${lxcname}/
>> -       dirlen = snprintf(snappath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
>> -       if (dirlen < 0 || dirlen >= MAXPATHLEN) {
>> +       if (!get_snappath_dir(c, snappath)) {
>>                 ERROR("path name too long");
>>                 return -1;
>>         }
>> @@ -3067,7 +3150,7 @@ out_free:
>>  static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapname, const char *newname)
>>  {
>>         char clonelxcpath[MAXPATHLEN];
>> -       int flags = 0,ret;
>> +       int flags = 0;
>>         struct lxc_container *snap, *rest;
>>         struct bdev *bdev;
>>         bool b = false;
>> @@ -3075,6 +3158,11 @@ static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam
>>         if (!c || !c->name || !c->config_path)
>>                 return false;
>>
>> +       if (has_fs_snapshots(c)) {
>> +               ERROR("container rootfs has dependent snapshots");
>> +               return false;
>> +       }
>> +
>>         bdev = bdev_init(c->lxc_conf, c->lxc_conf->rootfs.path, c->lxc_conf->rootfs.mount, NULL);
>>         if (!bdev) {
>>                 ERROR("Failed to find original backing store type");
>> @@ -3084,14 +3172,13 @@ static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam
>>         if (!newname)
>>                 newname = c->name;
>>         if (strcmp(c->name, newname) == 0) {
>> -               if (!lxcapi_destroy(c)) {
>> +               if (!container_destroy(c)) {
>>                         ERROR("Could not destroy existing container %s", newname);
>>                         bdev_put(bdev);
>>                         return false;
>>                 }
>>         }
>> -       ret = snprintf(clonelxcpath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
>> -       if (ret < 0 || ret >= MAXPATHLEN) {
>> +       if (!get_snappath_dir(c, clonelxcpath)) {
>>                 bdev_put(bdev);
>>                 return false;
>>         }
>> @@ -3118,21 +3205,13 @@ static bool lxcapi_snapshot_restore(struct lxc_container *c, const char *snapnam
>>         return b;
>>  }
>>
>> -static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
>> +static bool do_snapshot_destroy(const char *snapname, const char *clonelxcpath)
>>  {
>> -       int ret;
>> -       char clonelxcpath[MAXPATHLEN];
>>         struct lxc_container *snap = NULL;
>> -
>> -       if (!c || !c->name || !c->config_path)
>> -               return false;
>> -
>> -       ret = snprintf(clonelxcpath, MAXPATHLEN, "%ssnaps/%s", c->config_path, c->name);
>> -       if (ret < 0 || ret >= MAXPATHLEN)
>> -               goto err;
>> +       bool bret = false;
>>
>>         snap = lxc_container_new(snapname, clonelxcpath);
>> -       if (!snap || !lxcapi_is_defined(snap)) {
>> +       if (!snap) {
>>                 ERROR("Could not find snapshot %s", snapname);
>>                 goto err;
>>         }
>> @@ -3141,13 +3220,70 @@ static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapnam
>>                 ERROR("Could not destroy snapshot %s", snapname);
>>                 goto err;
>>         }
>> -       lxc_container_put(snap);
>> +       bret = true;
>>
>> -       return true;
>>  err:
>>         if (snap)
>>                 lxc_container_put(snap);
>> -       return false;
>> +       return bret;
>> +}
>> +
>> +static bool remove_all_snapshots(const char *path)
>> +{
>> +       DIR *dir;
>> +       struct dirent dirent, *direntp;
>> +       bool bret = true;
>> +
>> +       dir = opendir(path);
>> +       if (!dir) {
>> +               SYSERROR("opendir on snapshot path %s", path);
>> +               return false;
>> +       }
>> +       while (!readdir_r(dir, &dirent, &direntp)) {
>> +               if (!direntp)
>> +                       break;
>> +               if (!strcmp(direntp->d_name, "."))
>> +                       continue;
>> +               if (!strcmp(direntp->d_name, ".."))
>> +                       continue;
>> +               if (!do_snapshot_destroy(direntp->d_name, path)) {
>> +                       bret = false;
>> +                       continue;
>> +               }
>> +       }
>> +
>> +       closedir(dir);
>> +
>> +       if (rmdir(path))
>> +               SYSERROR("Error removing directory %s", path);
>> +
>> +       return bret;
>> +}
>> +
>> +static bool lxcapi_snapshot_destroy(struct lxc_container *c, const char *snapname)
>> +{
>> +       char clonelxcpath[MAXPATHLEN];
>> +
>> +       if (!c || !c->name || !c->config_path || !snapname)
>> +               return false;
>> +
>> +       if (!get_snappath_dir(c, clonelxcpath))
>> +               return false;
>> +
>> +       return do_snapshot_destroy(snapname, clonelxcpath);
>> +}
>> +
>> +static bool lxcapi_snapshot_destroy_all(struct lxc_container *c)
>> +{
>> +       char clonelxcpath[MAXPATHLEN];
>> +
>> +       if (!c || !c->name || !c->config_path)
>> +               return false;
>> +
>> +       if (!get_snappath_dir(c, clonelxcpath))
>> +               return false;
>> +
>> +       return remove_all_snapshots(clonelxcpath);
>>  }
>>
>>  static bool lxcapi_may_control(struct lxc_container *c)
>> @@ -3307,6 +3443,9 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
>>  {
>>         struct lxc_container *c;
>>
>> +       if (!name)
>> +               return NULL;
>> +
>>         c = malloc(sizeof(*c));
>>         if (!c) {
>>                 fprintf(stderr, "failed to malloc lxc_container\n");
>> @@ -3353,7 +3492,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
>>
>>         if (ongoing_create(c) == 2) {
>>                 ERROR("Error: %s creation was not completed", c->name);
>> -               lxcapi_destroy(c);
>> +               container_destroy(c);
>>                 lxcapi_clear_config(c);
>>         }
>>         c->daemonize = true;
>> @@ -3378,6 +3517,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
>>         c->wait = lxcapi_wait;
>>         c->set_config_item = lxcapi_set_config_item;
>>         c->destroy = lxcapi_destroy;
>> +       c->destroy_with_snapshots = lxcapi_destroy_with_snapshots;
>>         c->rename = lxcapi_rename;
>>         c->save_config = lxcapi_save_config;
>>         c->get_keys = lxcapi_get_keys;
>> @@ -3403,6 +3543,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath
>>         c->snapshot_list = lxcapi_snapshot_list;
>>         c->snapshot_restore = lxcapi_snapshot_restore;
>>         c->snapshot_destroy = lxcapi_snapshot_destroy;
>> +       c->snapshot_destroy_all = lxcapi_snapshot_destroy_all;
>>         c->may_control = lxcapi_may_control;
>>         c->add_device_node = lxcapi_add_device_node;
>>         c->remove_device_node = lxcapi_remove_device_node;
>> diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
>> index 1d0628a..5085c43 100644
>> --- a/src/lxc/lxccontainer.h
>> +++ b/src/lxc/lxccontainer.h
>> @@ -286,6 +286,17 @@ struct lxc_container {
>>         bool (*destroy)(struct lxc_container *c);
>>
>>         /*!
>> +        * \brief Delete the container and all its snapshots.
>> +        *
>> +        * \param c Container.
>> +        *
>> +        * \return \c true on success, else \c false.
>> +        *
>> +        * \note Container must be stopped.
>> +        */
>> +       bool (*destroy_with_snapshots)(struct lxc_container *c);
>> +
>> +       /*!
>>          * \brief Save configuaration to a file.
>>          *
>>          * \param c Container.
>> @@ -649,7 +660,7 @@ struct lxc_container {
>>          * \brief Create a container snapshot.
>>          *
>>          * Assuming default paths, snapshots will be created as
>> -        * \c /var/lib/lxcsnaps/\<c\>/snap\<n\>
>> +        * \c /var/lib/lxc/\<c\>/snaps/snap\<n\>
>>          * where \c \<c\> represents the container name and \c \<n\>
>>          * represents the zero-based snapshot number.
>>          *
>> @@ -691,7 +702,7 @@ struct lxc_container {
>>          *  fail if the  snapshot is overlay-based, since the snapshots
>>          *  will pin the original container.
>>          * \note As an example, if the container exists as \c /var/lib/lxc/c1, snapname might be \c 'snap0'
>> -        *  (representing \c /var/lib/lxcsnaps/c1/snap0). If \p newname is \p c2,
>> +        *  (representing \c /var/lib/lxc/c1/snaps/snap0). If \p newname is \p c2,
>>          *  then \c snap0 will be copied to \c /var/lib/lxc/c2.
>>          */
>>         bool (*snapshot_restore)(struct lxc_container *c, const char *snapname, const char *newname);
>> @@ -707,6 +718,15 @@ struct lxc_container {
>>         bool (*snapshot_destroy)(struct lxc_container *c, const char *snapname);
>>
>>         /*!
>> +        * \brief Destroy all the container's snapshot.
>> +        *
>> +        * \param c Container.
>> +        *
>> +        * \return \c true on success, else \c false.
>> +        */
>> +       bool (*snapshot_destroy_all)(struct lxc_container *c);
>> +
>> +       /*!
>>          * \brief Determine if the caller may control the container.
>>          *
>>          * \param c Container.
>> diff --git a/src/lxc/lxclock.c b/src/lxc/lxclock.c
>> index 1d62729..9d1c6f4 100644
>> --- a/src/lxc/lxclock.c
>> +++ b/src/lxc/lxclock.c
>> @@ -108,8 +108,8 @@ static char *lxclock_name(const char *p, const char *n)
>>          * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root
>>          */
>>
>> -       /* length of "/lock/lxc/" + $lxcpath + "/" + $lxcname + '\0' */
>> -       len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 2;
>> +       /* length of "/lock/lxc/" + $lxcpath + "/" + "." + $lxcname + '\0' */
>> +       len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 3;
>>         rundir = get_rundir();
>>         if (!rundir)
>>                 return NULL;
>> @@ -129,7 +129,7 @@ static char *lxclock_name(const char *p, const char *n)
>>         ret = mkdir_p(dest, 0755);
>>         if (ret < 0) {
>>                 /* fall back to "/tmp/" $(id -u) "/lxc/" $lxcpath / $lxcname + '\0' */
>> -               int l2 = 33 + strlen(n) + strlen(p);
>> +               int l2 = 34 + strlen(n) + strlen(p);
>>                 if (l2 > len) {
>>                         char *d;
>>                         d = realloc(dest, l2);
>> @@ -147,9 +147,9 @@ static char *lxclock_name(const char *p, const char *n)
>>                         free(rundir);
>>                         return NULL;
>>                 }
>> -               ret = snprintf(dest, len, "/tmp/%d/lxc/%s/%s", geteuid(), p, n);
>> +               ret = snprintf(dest, len, "/tmp/%d/lxc/%s/.%s", geteuid(), p, n);
>>         } else
>> -               ret = snprintf(dest, len, "%s/lock/lxc/%s/%s", rundir, p, n);
>> +               ret = snprintf(dest, len, "%s/lock/lxc/%s/.%s", rundir, p, n);
>>
>>         free(rundir);
>>
>> diff --git a/src/lxc/utils.c b/src/lxc/utils.c
>> index b076ce7..738bf5e 100644
>> --- a/src/lxc/utils.c
>> +++ b/src/lxc/utils.c
>> @@ -46,12 +46,14 @@
>>
>>  lxc_log_define(lxc_utils, lxc);
>>
>> -static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
>> +static int _recursive_rmdir_onedev(char *dirname, dev_t pdev,
>> +                                  const char *exclude, int level)
>>  {
>>         struct dirent dirent, *direntp;
>>         DIR *dir;
>>         int ret, failed=0;
>>         char pathname[MAXPATHLEN];
>> +       bool hadexclude = false;
>>
>>         dir = opendir(dirname);
>>         if (!dir) {
>> @@ -76,6 +78,29 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
>>                         failed=1;
>>                         continue;
>>                 }
>> +
>> +               if (!level && exclude && !strcmp(direntp->d_name, exclude)) {
>> +                       ret = rmdir(pathname);
>> +                       if (ret < 0) {
>> +                               switch(errno) {
>> +                               case ENOTEMPTY:
>> +                                       INFO("Not deleting snapshots");
>> +                                       hadexclude = true;
>> +                                       break;
>> +                               case ENOTDIR:
>> +                                       ret = unlink(pathname);
>> +                                       if (ret)
>> +                                               INFO("%s: failed to remove %s", __func__, pathname);
>> +                                       break;
>> +                               default:
>> +                                       SYSERROR("%s: failed to rmdir %s", __func__, pathname);
>> +                                       failed = 1;
>> +                                       break;
>> +                               }
>> +                       }
>> +                       continue;
>> +               }
>> +
>>                 ret = lstat(pathname, &mystat);
>>                 if (ret) {
>>                         ERROR("%s: failed to stat %s", __func__, pathname);
>> @@ -85,7 +110,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
>>                 if (mystat.st_dev != pdev)
>>                         continue;
>>                 if (S_ISDIR(mystat.st_mode)) {
>> -                       if (_recursive_rmdir_onedev(pathname, pdev) < 0)
>> +                       if (_recursive_rmdir_onedev(pathname, pdev, exclude, level+1) < 0)
>>                                 failed=1;
>>                 } else {
>>                         if (unlink(pathname) < 0) {
>> @@ -96,8 +121,10 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
>>         }
>>
>>         if (rmdir(dirname) < 0) {
>> -               ERROR("%s: failed to delete %s", __func__, dirname);
>> -               failed=1;
>> +               if (!hadexclude) {
>> +                       ERROR("%s: failed to delete %s", __func__, dirname);
>> +                       failed=1;
>> +               }
>>         }
>>
>>         ret = closedir(dir);
>> @@ -110,7 +137,7 @@ static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
>>  }
>>
>>  /* returns 0 on success, -1 if there were any failures */
>> -extern int lxc_rmdir_onedev(char *path)
>> +extern int lxc_rmdir_onedev(char *path, const char *exclude)
>>  {
>>         struct stat mystat;
>>
>> @@ -119,7 +146,7 @@ extern int lxc_rmdir_onedev(char *path)
>>                 return -1;
>>         }
>>
>> -       return _recursive_rmdir_onedev(path, mystat.st_dev);
>> +       return _recursive_rmdir_onedev(path, mystat.st_dev, exclude, 0);
>>  }
>>
>>  static int mount_fs(const char *source, const char *target, const char *type)
>> diff --git a/src/lxc/utils.h b/src/lxc/utils.h
>> index 691e56c..8516fcf 100644
>> --- a/src/lxc/utils.h
>> +++ b/src/lxc/utils.h
>> @@ -34,7 +34,7 @@
>>  #include "config.h"
>>
>>  /* returns 1 on success, 0 if there were any failures */
>> -extern int lxc_rmdir_onedev(char *path);
>> +extern int lxc_rmdir_onedev(char *path, const char *exclude);
>>  extern void lxc_setup_fs(void);
>>  extern int get_u16(unsigned short *val, const char *arg, int base);
>>  extern int mkdir_p(const char *dir, mode_t mode);
>> diff --git a/src/tests/snapshot.c b/src/tests/snapshot.c
>> index 09cee1a..21acd3e 100644
>> --- a/src/tests/snapshot.c
>> +++ b/src/tests/snapshot.c
>> @@ -32,28 +32,21 @@
>>  static void try_to_remove(void)
>>  {
>>         struct lxc_container *c;
>> -       char snappath[1024];
>>         c = lxc_container_new(RESTNAME, NULL);
>>         if (c) {
>> -               if (c->is_defined(c))
>> -                       c->destroy(c);
>> -               lxc_container_put(c);
>> -       }
>> -       snprintf(snappath, 1024, "%ssnaps/%s", lxc_get_global_config_item("lxc.lxcpath"), MYNAME);
>> -       c = lxc_container_new("snap0", snappath);
>> -       if (c) {
>> +               c->snapshot_destroy_all(c);
>>                 if (c->is_defined(c))
>>                         c->destroy(c);
>>                 lxc_container_put(c);
>>         }
>>         c = lxc_container_new(MYNAME2, NULL);
>>         if (c) {
>> -               if (c->is_defined(c))
>> -                       c->destroy(c);
>> +               c->destroy_with_snapshots(c);
>>                 lxc_container_put(c);
>>         }
>>         c = lxc_container_new(MYNAME, NULL);
>>         if (c) {
>> +               c->snapshot_destroy_all(c);
>>                 if (c->is_defined(c))
>>                         c->destroy(c);
>>                 lxc_container_put(c);
>> @@ -77,7 +70,7 @@ int main(int argc, char *argv[])
>>
>>         if (c->is_defined(c)) {
>>                 fprintf(stderr, "%d: %s thought it was defined\n", __LINE__, MYNAME);
>> -               (void) c->destroy(c);
>> +               (void) c->destroy_with_snapshots(c);
>>         }
>>         if (!c->set_config_item(c, "lxc.network.type", "empty")) {
>>                 fprintf(stderr, "%s: %d: failed to set network type\n", __FILE__, __LINE__);
>> @@ -95,11 +88,11 @@ int main(int argc, char *argv[])
>>                 goto err;
>>         }
>>
>> -       // rootfs should be ${lxcpath}snaps/${lxcname}/snap0/rootfs
>> +       // rootfs should be ${lxcpath}${lxcname}/snaps/snap0/rootfs
>>         struct stat sb;
>>         int ret;
>>         char path[1024];
>> -       snprintf(path, 1024, "%ssnaps/%s/snap0/rootfs", lxc_get_global_config_item("lxc.lxcpath"), MYNAME);
>> +       snprintf(path, 1024, "%s/%s/snaps/snap0/rootfs", lxc_get_global_config_item("lxc.lxcpath"), MYNAME);
>>         ret = stat(path, &sb);
>>         if (ret != 0) {
>>                 fprintf(stderr, "%s: %d: snapshot was not actually created\n", __FILE__, __LINE__);
>> @@ -169,17 +162,7 @@ int main(int argc, char *argv[])
>>                 goto err;
>>         }
>>
>> -       if (!c2->destroy(c2)) {
>> -               fprintf(stderr, "%s: %d: failed to destroy container\n", __FILE__, __LINE__);
>> -               goto err;
>> -       }
>> -
>>  good:
>> -       if (!c->destroy(c)) {
>> -               fprintf(stderr, "%s: %d: failed to destroy container\n", __FILE__, __LINE__);
>> -               goto err;
>> -       }
>> -
>>         lxc_container_put(c);
>>         try_to_remove();
>>
>> --
>> 2.0.0.rc0
>>
>> _______________________________________________
>> lxc-devel mailing list
>> lxc-devel at lists.linuxcontainers.org
>> http://lists.linuxcontainers.org/listinfo/lxc-devel
>
>
>
> --
> S.Çağlar Onur <caglar at 10ur.org>



-- 
S.Çağlar Onur <caglar at 10ur.org>


More information about the lxc-devel mailing list