[ostree] admin: Add an "undeploy" command



commit 3d7bff2d4110b7e2cd8495c3870a523faa3e7224
Author: Colin Walters <walters verbum org>
Date:   Tue Jul 23 09:19:24 2013 -0400

    admin: Add an "undeploy" command
    
    Otherwise it's really easy to keep accumulating deployments.  Also, we
    may want to run this after rebooting, so we're back down to one
    operating system.

 Makefile-ostree.am                     |    1 +
 src/ostree/ot-admin-builtin-undeploy.c |  120 ++++++++++++++++++++++++++
 src/ostree/ot-admin-builtins.h         |    1 +
 src/ostree/ot-admin-deploy.c           |  146 ++++++++++++++++++--------------
 src/ostree/ot-admin-deploy.h           |    7 ++
 src/ostree/ot-builtin-admin.c          |    1 +
 tests/test-admin-deploy-1.sh           |   19 ++++-
 7 files changed, 231 insertions(+), 64 deletions(-)
---
diff --git a/Makefile-ostree.am b/Makefile-ostree.am
index 4c3ade9..949641e 100644
--- a/Makefile-ostree.am
+++ b/Makefile-ostree.am
@@ -48,6 +48,7 @@ ostree_SOURCES += \
        src/ostree/ot-admin-builtin-init-fs.c \
        src/ostree/ot-admin-builtin-diff.c \
        src/ostree/ot-admin-builtin-deploy.c \
+       src/ostree/ot-admin-builtin-undeploy.c \
        src/ostree/ot-admin-builtin-cleanup.c \
        src/ostree/ot-admin-builtin-os-init.c \
        src/ostree/ot-admin-builtin-status.c \
diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c
new file mode 100644
index 0000000..2922189
--- /dev/null
+++ b/src/ostree/ot-admin-builtin-undeploy.c
@@ -0,0 +1,120 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2012,2013 Colin Walters <walters verbum org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "ot-admin-builtins.h"
+#include "ot-admin-functions.h"
+#include "ot-admin-deploy.h"
+#include "ot-ordered-hash.h"
+#include "ostree.h"
+
+#include <stdlib.h>
+
+static GOptionEntry options[] = {
+  { NULL }
+};
+
+gboolean
+ot_admin_builtin_undeploy (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error)
+{
+  gboolean ret = FALSE;
+  __attribute__((unused)) GCancellable *cancellable = NULL;
+  GFile *sysroot = admin_opts->sysroot;
+  GOptionContext *context;
+  const char *deploy_index_str;
+  int deploy_index;
+  int current_bootversion;
+  gs_unref_ptrarray GPtrArray *current_deployments = NULL;
+  gs_unref_ptrarray GPtrArray *new_deployments = NULL;
+  gs_free char *revision = NULL;
+  gs_unref_object OtDeployment *booted_deployment = NULL;
+  gs_unref_object OtDeployment *target_deployment = NULL;
+
+  context = g_option_context_new ("INDEX - Delete deployment INDEX");
+
+  g_option_context_add_main_entries (context, options, NULL);
+
+  if (!g_option_context_parse (context, &argc, &argv, error))
+    goto out;
+
+  if (argc < 2)
+    {
+      ot_util_usage_error (context, "INDEX must be specified", error);
+      goto out;
+    }
+
+  deploy_index_str = argv[1];
+  deploy_index = atoi (deploy_index_str);
+
+  if (!ot_admin_list_deployments (sysroot, &current_bootversion, &current_deployments,
+                                  cancellable, error))
+    {
+      g_prefix_error (error, "While listing deployments: ");
+      goto out;
+    }
+
+  if (!ot_admin_find_booted_deployment (sysroot, current_deployments, &booted_deployment,
+                                        cancellable, error))
+    goto out;
+
+  if (deploy_index < 0)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                   "Invalid index %d", deploy_index);
+      goto out;
+    }
+  if (deploy_index >= current_deployments->len)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                   "Out of range index %d, expected < %d", deploy_index, current_deployments->len);
+      goto out;
+    }
+  
+  target_deployment = g_object_ref (current_deployments->pdata[deploy_index]);
+  if (target_deployment == booted_deployment)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                   "Cannot undeploy currently booted deployment %i", deploy_index);
+      goto out;
+    }
+  
+  g_ptr_array_remove_index (current_deployments, deploy_index);
+
+  if (!ot_admin_write_deployments (sysroot, current_bootversion,
+                                   current_bootversion ? 0 : 1, current_deployments,
+                                   cancellable, error))
+    goto out;
+
+  g_print ("Deleted deployment %s.%d\n", ot_deployment_get_csum (target_deployment),
+           ot_deployment_get_deployserial (target_deployment));
+  
+  if (!ot_admin_cleanup (sysroot, cancellable, error))
+    {
+      g_prefix_error (error, "Performing final cleanup: ");
+      goto out;
+    }
+
+  ret = TRUE;
+ out:
+  if (context)
+    g_option_context_free (context);
+  return ret;
+}
diff --git a/src/ostree/ot-admin-builtins.h b/src/ostree/ot-admin-builtins.h
index e6dc264..440ba0f 100644
--- a/src/ostree/ot-admin-builtins.h
+++ b/src/ostree/ot-admin-builtins.h
@@ -33,6 +33,7 @@ typedef struct {
 gboolean ot_admin_builtin_os_init (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
 gboolean ot_admin_builtin_install (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
 gboolean ot_admin_builtin_init_fs (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
+gboolean ot_admin_builtin_undeploy (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
 gboolean ot_admin_builtin_deploy (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
 gboolean ot_admin_builtin_cleanup (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
 gboolean ot_admin_builtin_status (int argc, char **argv, OtAdminBuiltinOpts *admin_opts, GError **error);
diff --git a/src/ostree/ot-admin-deploy.c b/src/ostree/ot-admin-deploy.c
index f77a73a..c7421b0 100644
--- a/src/ostree/ot-admin-deploy.c
+++ b/src/ostree/ot-admin-deploy.c
@@ -1000,6 +1000,86 @@ swap_bootloader (GFile          *sysroot,
 }
 
 gboolean
+ot_admin_write_deployments (GFile             *sysroot,
+                            int                current_bootversion,
+                            int                new_bootversion,
+                            GPtrArray         *new_deployments,
+                            GCancellable      *cancellable,
+                            GError           **error)
+{
+  gboolean ret = FALSE;
+  guint i;
+  gs_unref_object OtBootloader *bootloader = NULL;
+
+  bootloader = ot_admin_query_bootloader (sysroot);
+  if (!bootloader)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "No known bootloader configuration detected");
+      goto out;
+    }
+
+  if (current_bootversion == new_bootversion)
+    {
+      if (!full_system_sync (cancellable, error))
+        {
+          g_prefix_error (error, "Full sync: ");
+          goto out;
+        }
+
+      if (!swap_bootlinks (sysroot, current_bootversion,
+                           new_deployments,
+                           cancellable, error))
+        {
+          g_prefix_error (error, "Swapping current bootlinks: ");
+          goto out;
+        }
+    }
+  else
+    {
+      for (i = 0; i < new_deployments->len; i++)
+        {
+          OtDeployment *deployment = new_deployments->pdata[i];
+          if (!install_deployment_kernel (sysroot, new_bootversion, deployment,
+                                          cancellable, error))
+            {
+              g_prefix_error (error, "Installing kernel: ");
+              goto out;
+            }
+        }
+
+      /* Swap bootlinks for *new* version */
+      if (!swap_bootlinks (sysroot, new_bootversion, new_deployments,
+                           cancellable, error))
+        {
+          g_prefix_error (error, "Generating new bootlinks: ");
+          goto out;
+        }
+
+      if (!full_system_sync (cancellable, error))
+        {
+          g_prefix_error (error, "Full sync: ");
+          goto out;
+        }
+
+      if (!ot_bootloader_write_config (bootloader, new_bootversion,
+                                       cancellable, error))
+        goto out;
+
+      if (!swap_bootloader (sysroot, current_bootversion, new_bootversion,
+                            cancellable, error))
+        {
+          g_prefix_error (error, "Final bootloader swap: ");
+          goto out;
+        }
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+                            
+gboolean
 ot_admin_deploy (GFile             *sysroot,
                  int                current_bootversion,
                  GPtrArray         *current_deployments,
@@ -1019,7 +1099,6 @@ ot_admin_deploy (GFile             *sysroot,
   gboolean ret = FALSE;
   OtDeployment *new_deployment;
   gs_unref_object OtDeployment *merge_deployment = NULL;
-  gs_unref_object OtBootloader *bootloader = NULL;
   gs_unref_object GFile *rootfs = NULL;
   gs_unref_object OstreeRepo *repo = NULL;
   gs_unref_object GFile *commit_root = NULL;
@@ -1071,14 +1150,6 @@ ot_admin_deploy (GFile             *sysroot,
         goto out;
     }
 
-  bootloader = ot_admin_query_bootloader (sysroot);
-  if (!bootloader)
-    {
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-                   "No known bootloader configuration detected");
-      goto out;
-    }
-
   /* If we're booted into the OS into which we're deploying, then
    * merge the currently *booted* configuration, rather than the most
    * recently deployed.
@@ -1156,60 +1227,9 @@ ot_admin_deploy (GFile             *sysroot,
       ot_config_parser_set (bootconfig, "options", new_options);
     }
 
-  if (current_bootversion == new_bootversion)
-    {
-      if (!full_system_sync (cancellable, error))
-        {
-          g_prefix_error (error, "Full sync: ");
-          goto out;
-        }
-
-      if (!swap_bootlinks (sysroot, current_bootversion,
-                           new_deployments,
-                           cancellable, error))
-        {
-          g_prefix_error (error, "Swapping current bootlinks: ");
-          goto out;
-        }
-    }
-  else
-    {
-      for (i = 0; i < new_deployments->len; i++)
-        {
-          OtDeployment *deployment = new_deployments->pdata[i];
-          if (!install_deployment_kernel (sysroot, new_bootversion, deployment,
-                                          cancellable, error))
-            {
-              g_prefix_error (error, "Installing kernel: ");
-              goto out;
-            }
-        }
-
-      /* Swap bootlinks for *new* version */
-      if (!swap_bootlinks (sysroot, new_bootversion, new_deployments,
-                           cancellable, error))
-        {
-          g_prefix_error (error, "Generating new bootlinks: ");
-          goto out;
-        }
-
-      if (!full_system_sync (cancellable, error))
-        {
-          g_prefix_error (error, "Full sync: ");
-          goto out;
-        }
-
-      if (!ot_bootloader_write_config (bootloader, new_bootversion,
-                                       cancellable, error))
-        goto out;
-
-      if (!swap_bootloader (sysroot, current_bootversion, new_bootversion,
-                            cancellable, error))
-        {
-          g_prefix_error (error, "Final bootloader swap: ");
-          goto out;
-        }
-    }
+  if (!ot_admin_write_deployments (sysroot, current_bootversion, new_bootversion,
+                                   new_deployments, cancellable, error))
+    goto out;
 
   g_print ("Transaction complete, performing cleanup\n");
 
diff --git a/src/ostree/ot-admin-deploy.h b/src/ostree/ot-admin-deploy.h
index d5dfa83..ab9f1f5 100644
--- a/src/ostree/ot-admin-deploy.h
+++ b/src/ostree/ot-admin-deploy.h
@@ -29,6 +29,13 @@
 
 G_BEGIN_DECLS
 
+gboolean ot_admin_write_deployments (GFile             *sysroot,
+                                     int                current_bootversion,
+                                     int                new_bootversion,
+                                     GPtrArray         *new_deployments,
+                                     GCancellable      *cancellable,
+                                     GError           **error);
+
 gboolean ot_admin_deploy (GFile             *sysroot,
                           int                current_bootversion,
                           GPtrArray         *current_deployments,
diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c
index 4665680..c591c01 100644
--- a/src/ostree/ot-builtin-admin.c
+++ b/src/ostree/ot-builtin-admin.c
@@ -40,6 +40,7 @@ static OstreeAdminCommand admin_subcommands[] = {
   { "os-init", ot_admin_builtin_os_init },
   { "init-fs", ot_admin_builtin_init_fs },
   { "deploy", ot_admin_builtin_deploy },
+  { "undeploy", ot_admin_builtin_undeploy },
   { "upgrade", ot_admin_builtin_upgrade },
   { "cleanup", ot_admin_builtin_cleanup },
   { "status", ot_admin_builtin_status },
diff --git a/tests/test-admin-deploy-1.sh b/tests/test-admin-deploy-1.sh
index 32cca0c..0119586 100755
--- a/tests/test-admin-deploy-1.sh
+++ b/tests/test-admin-deploy-1.sh
@@ -27,7 +27,7 @@ setup_os_repository "archive-z2"
 
 echo "ok setup"
 
-echo "1..7"
+echo "1..8"
 
 ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime
 rev=$(ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime)
@@ -126,9 +126,26 @@ echo "ok upgrade bare"
 os_repository_new_commit
 ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
 ostree admin --sysroot=sysroot upgrade --os=testos
+origrev=${rev}
 rev=${newrev}
 newrev=$(ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime)
 assert_not_streq ${rev} ${newrev}
 assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS'
 
 echo "ok upgrade"
+
+assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS'
+assert_file_has_content sysroot/ostree/deploy/testos/deploy/${origrev}.4/etc/os-release 'NAME=TestOS'
+ostree admin --sysroot=sysroot undeploy 1
+assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS'
+assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${origrev}.4
+
+assert_file_has_content sysroot/ostree/deploy/testos/deploy/${origrev}.3/etc/os-release 'NAME=TestOS'
+ostree admin --sysroot=sysroot undeploy 3
+assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${origrev}.3
+
+assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-release 'NAME=TestOS'
+ostree admin --sysroot=sysroot undeploy 0
+assert_not_has_dir sysroot/ostree/deploy/testos/deploy/${newrev}.0
+
+echo "ok undeploy"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]