[Libguestfs] [PATCH 2/2] customize: add basic subscription-manager operations

Pino Toscano ptoscano at redhat.com
Fri Jul 17 13:31:19 UTC 2015


Add simple operations for RHEL guests using subscription-manager, so it
is possible to e.g. install software on them.
---
 builder/Makefile.am                |  1 +
 builder/virt-builder.pod           | 47 ++++++++++++++++++
 customize/Makefile.am              |  2 +
 customize/customize_run.ml         | 34 +++++++++++++
 customize/subscription_manager.ml  | 53 ++++++++++++++++++++
 customize/subscription_manager.mli | 34 +++++++++++++
 generator/customize.ml             | 99 ++++++++++++++++++++++++++++++++++++--
 po/POTFILES-ml                     |  1 +
 sysprep/Makefile.am                |  1 +
 9 files changed, 269 insertions(+), 3 deletions(-)
 create mode 100644 customize/subscription_manager.ml
 create mode 100644 customize/subscription_manager.mli

diff --git a/builder/Makefile.am b/builder/Makefile.am
index d69e25f..2413217 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -125,6 +125,7 @@ BOBJECTS = \
 	$(top_builddir)/customize/crypt.cmo \
 	$(top_builddir)/customize/password.cmo \
 	$(top_builddir)/customize/ssh_key.cmo \
+	$(top_builddir)/customize/subscription_manager.cmo \
 	$(top_builddir)/customize/customize_cmdline.cmo \
 	$(top_builddir)/customize/customize_run.cmo \
 	$(SOURCES_ML:.ml=.cmo)
diff --git a/builder/virt-builder.pod b/builder/virt-builder.pod
index 41cda1a..b4a341f 100644
--- a/builder/virt-builder.pod
+++ b/builder/virt-builder.pod
@@ -844,6 +844,53 @@ F<C:\Program Files\Red Hat\Firstboot\log.txt>.
 
 =back
 
+=head2 SUBSCRIPTION-MANAGER
+
+It is possible to automate the registration and attaching of the
+system using C<subscription-manager>.  This is typical on
+Red Hat Enterprise Linux guests.  There are few options which ease
+this process, avoid executing commands manually and exposing
+passwords on command line.
+
+I<--sm-register> starts the registration process, and requires
+I<--sm-credentials> to be specified; the format of the C<SELECTOR>
+of I<--sm-credentials> is one of the following formats:
+
+=over 4
+
+=item B<--sm-credentials> USER:file:FILENAME
+
+Read the password for the specified C<USER> from F<FILENAME>.
+
+=item B<--sm-credentials> USER:password:PASSWORD
+
+Use the literal string C<PASSWORD> for the specified C<USER>.
+
+=back
+
+I<--sm-attach> attaches the system to subscriptions; the format
+of its C<SELECTOR> is one of the following:
+
+=over 4
+
+=item B<--sm-attach> auto
+
+C<subscription-manager> attaches to the best-fitting subscriptions
+for the system.
+
+=item B<--sm-attach> file:FILENAME
+
+Read the pool ID from F<FILENAME>.
+
+=item B<--sm-attach> pool:POOL
+
+Use the literal string C<POOL> as pool ID.
+
+=back
+
+I<--sm-remove> removes all the subscriptions from the guest, while
+I<--sm-unregister> completely unregister the system.
+
 =head2 INSTALLATION PROCESS
 
 When you invoke virt-builder, installation proceeds as follows:
diff --git a/customize/Makefile.am b/customize/Makefile.am
index 8f0a2d8..1974b80 100644
--- a/customize/Makefile.am
+++ b/customize/Makefile.am
@@ -43,6 +43,7 @@ SOURCES_MLI = \
 	perl_edit.mli \
 	random_seed.mli \
 	ssh_key.mli \
+	subscription_manager.mli \
 	timezone.mli \
 	urandom.mli
 
@@ -57,6 +58,7 @@ SOURCES_ML = \
 	perl_edit.ml \
 	random_seed.ml \
 	ssh_key.ml \
+	subscription_manager.ml \
 	timezone.ml \
 	customize_cmdline.ml \
 	customize_run.ml \
diff --git a/customize/customize_run.ml b/customize/customize_run.ml
index d9547a0..bce0aca 100644
--- a/customize/customize_run.ml
+++ b/customize/customize_run.ml
@@ -249,6 +249,40 @@ exec >>%s 2>&1
       message (f_"Scrubbing: %s") path;
       g#scrub_file path
 
+    | `SMAttach pool ->
+      (match pool with
+      | Subscription_manager.PoolAuto ->
+        message (f_"Attaching to compatible subscriptions");
+        let cmd = "subscription-manager attach --auto" in
+        do_run ~display:cmd cmd
+      | Subscription_manager.PoolId id ->
+        message (f_"Attaching to the pool %s") id;
+        let cmd = sprintf "subscription-manager attach --pool=%s" (quote id) in
+        do_run ~display:cmd cmd
+      )
+
+    | `SMRegister ->
+      message (f_"Registering with subscription-manager");
+      let creds =
+        match ops.flags.sm_credentials with
+        | None ->
+          error (f_"subscription-manager credentials required for --sm-register")
+        | Some c -> c in
+      let cmd = sprintf "subscription-manager register --username=%s --password=%s"
+                  (quote creds.Subscription_manager.sm_username)
+                  (quote creds.Subscription_manager.sm_password) in
+      do_run ~display:"subscription-manager register" cmd
+
+    | `SMRemove ->
+      message (f_"Removing all the subscriptions");
+      let cmd = "subscription-manager remove --all" in
+      do_run ~display:cmd cmd
+
+    | `SMUnregister ->
+      message (f_"Unregistering with subscription-manager");
+      let cmd = "subscription-manager unregister" in
+      do_run ~display:cmd cmd
+
     | `SSHInject (user, selector) ->
       (match g#inspect_get_type root with
       | "linux" | "freebsd" | "netbsd" | "openbsd" | "hurd" ->
diff --git a/customize/subscription_manager.ml b/customize/subscription_manager.ml
new file mode 100644
index 0000000..c9828d6
--- /dev/null
+++ b/customize/subscription_manager.ml
@@ -0,0 +1,53 @@
+(* virt-customize
+ * Copyright (C) 2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Common_gettext.Gettext
+open Common_utils
+
+type sm_credentials = {
+  sm_username : string;
+  sm_password : string;
+}
+
+type sm_pool =
+| PoolAuto
+| PoolId of string
+
+let rec parse_credentials_selector arg =
+  parse_credentials_selector_list arg (string_nsplit ":" arg)
+
+and parse_credentials_selector_list orig_arg = function
+  | [ username; "password"; password ] ->
+    { sm_username = username; sm_password = password }
+  | [ username; "file"; filename ] ->
+    { sm_username = username; sm_password = read_first_line_from_file filename }
+  | _ ->
+    error (f_"invalid sm-credentials selector '%s'; see the man page") orig_arg
+
+let rec parse_pool_selector arg =
+  parse_pool_selector_list arg (string_nsplit ":" arg)
+
+and parse_pool_selector_list orig_arg = function
+  | [ "auto" ] ->
+    PoolAuto
+  | [ "pool"; pool ] ->
+    PoolId pool
+  | [ "file"; filename ] ->
+    PoolId (read_first_line_from_file filename)
+  | _ ->
+    error (f_"invalid sm-attach selector '%s'; see the man page") orig_arg
diff --git a/customize/subscription_manager.mli b/customize/subscription_manager.mli
new file mode 100644
index 0000000..bb6b920
--- /dev/null
+++ b/customize/subscription_manager.mli
@@ -0,0 +1,34 @@
+(* virt-customize
+ * Copyright (C) 2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+type sm_credentials = {
+  sm_username : string;
+  sm_password : string;
+}
+
+type sm_pool =
+| PoolAuto                           (** Automatic entitlements. *)
+| PoolId of string                   (** Specific pool. *)
+
+val parse_credentials_selector : string -> sm_credentials
+(** Parse the selector field in --sm-credentials.  Exits if the format
+    is not valid. *)
+
+val parse_pool_selector : string -> sm_pool
+(** Parse the selector field in --sm-attach.  Exits if the format
+    is not valid. *)
diff --git a/generator/customize.ml b/generator/customize.ml
index f57aba6..2196e9e 100644
--- a/generator/customize.ml
+++ b/generator/customize.ml
@@ -44,6 +44,7 @@ and op_type =
 | UserPasswordSelector of string        (* user:selector *)
 | SSHKeySelector of string              (* user:selector *)
 | StringFn of (string * string)         (* string, function name *)
+| SMPoolSelector of string              (* pool selector *)
 
 let ops = [
   { op_name = "chmod";
@@ -327,6 +328,44 @@ It cannot delete directories, only regular files.
 =back";
   };
 
+  { op_name = "sm-attach";
+    op_type = SMPoolSelector "SELECTOR";
+    op_discrim = "`SMAttach";
+    op_shortdesc = "Attach to a subscription-manager pool";
+    op_pod_longdesc = "\
+Attach to a pool using C<subscription-manager>.
+
+See L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of
+the C<SELECTOR> field.";
+  };
+
+  { op_name = "sm-register";
+    op_type = Unit;
+    op_discrim = "`SMRegister";
+    op_shortdesc = "Register using subscription-manager";
+    op_pod_longdesc = "\
+Register the guest using C<subscription-manager>.
+
+This requires credentials being set using I<--sm-credentials>.";
+  };
+
+  { op_name = "sm-remove";
+    op_type = Unit;
+    op_discrim = "`SMRemove";
+    op_shortdesc = "Remove all the subscriptions";
+    op_pod_longdesc = "\
+Remove all the subscriptions from the guest using
+C<subscription-manager>.";
+  };
+
+  { op_name = "sm-unregister";
+    op_type = Unit;
+    op_discrim = "`SMUnregister";
+    op_shortdesc = "Unregister using subscription-manager";
+    op_pod_longdesc = "\
+Unregister the guest using C<subscription-manager>.";
+  };
+
   { op_name = "ssh-inject";
     op_type = SSHKeySelector "USER[:SELECTOR]";
     op_discrim = "`SSHInject";
@@ -428,6 +467,7 @@ type flag = {
 and flag_type =
 | FlagBool of bool                  (* boolean is the default value *)
 | FlagPasswordCrypto of string
+| FlagSMCredentials of string
 
 let flags = [
   { flag_name = "no-logfile";
@@ -477,6 +517,18 @@ Relabel files in the guest so that they have the correct SELinux label.
 
 You should only use this option for guests which support SELinux.";
   };
+
+  { flag_name = "sm-credentials";
+    flag_type = FlagSMCredentials "SELECTOR";
+    flag_ml_var = "sm_credentials";
+    flag_shortdesc = "credentials for subscription-manager";
+    flag_pod_longdesc = "\
+Set the credentials for C<subscription-manager>.
+
+See L<virt-builder(1)/SUBSCRIPTION-MANAGER> for the format of
+the C<SELECTOR> field.";
+  };
+
 ]
 
 let rec generate_customize_cmdline_mli () =
@@ -532,6 +584,8 @@ let rec argspec () =
       pr "  let %s = ref %b in\n" var default
     | { flag_type = FlagPasswordCrypto _; flag_ml_var = var } ->
       pr "  let %s = ref None in\n" var
+    | { flag_type = FlagSMCredentials _; flag_ml_var = var } ->
+      pr "  let %s = ref None in\n" var
   ) flags;
   pr "\
 
@@ -672,6 +726,18 @@ let rec argspec () =
       pr "      s_\"%s\" ^ \" \" ^ s_\"%s\"\n" v shortdesc;
       pr "    ),\n";
       pr "    Some %S, %S;\n" v longdesc
+    | { op_type = SMPoolSelector v; op_name = name; op_discrim = discrim;
+        op_shortdesc = shortdesc; op_pod_longdesc = longdesc } ->
+      pr "    (\n";
+      pr "      \"--%s\",\n" name;
+      pr "      Arg.String (\n";
+      pr "        fun s ->\n";
+      pr "          let sel = Subscription_manager.parse_pool_selector s in\n";
+      pr "          ops := %s sel :: !ops\n" discrim;
+      pr "      ),\n";
+      pr "      s_\"%s\" ^ \" \" ^ s_\"%s\"\n" v shortdesc;
+      pr "    ),\n";
+      pr "    Some %S, %S;\n" v longdesc
   ) ops;
 
   List.iter (
@@ -699,6 +765,19 @@ let rec argspec () =
       pr "      \"%s\" ^ \" \" ^ s_\"%s\"\n" v shortdesc;
       pr "    ),\n";
       pr "    Some %S, %S;\n" v longdesc
+    | { flag_type = FlagSMCredentials v; flag_ml_var = var;
+        flag_name = name; flag_shortdesc = shortdesc;
+        flag_pod_longdesc = longdesc } ->
+      pr "    (\n";
+      pr "      \"--%s\",\n" name;
+      pr "      Arg.String (\n";
+      pr "        fun s ->\n";
+      pr "          %s := Some (Subscription_manager.parse_credentials_selector s)\n"
+        var;
+      pr "      ),\n";
+      pr "      \"%s\" ^ \" \" ^ s_\"%s\"\n" v shortdesc;
+      pr "    ),\n";
+      pr "    Some %S, %S;\n" v longdesc
   ) flags;
 
   pr "  ]
@@ -717,7 +796,8 @@ let rec argspec () =
     | { op_type = TargetLinks _; }
     | { op_type = PasswordSelector _; }
     | { op_type = UserPasswordSelector _; }
-    | { op_type = SSHKeySelector _; } -> ()
+    | { op_type = SSHKeySelector _; }
+    | { op_type = SMPoolSelector _; } -> ()
   ) ops;
 
 pr "    ] in
@@ -796,6 +876,10 @@ type ops = {
         discrim name v
     | { op_type = StringFn (v, _); op_discrim = discrim; op_name = name } ->
       pr "  | %s of string\n      (* --%s %s *)\n" discrim name v
+    | { op_type = SMPoolSelector v; op_discrim = discrim;
+        op_name = name } ->
+      pr "  | %s of Subscription_manager.sm_pool\n      (* --%s %s *)\n"
+        discrim name v
   ) ops;
   pr "]\n";
 
@@ -809,6 +893,10 @@ type ops = {
         flag_name = name } ->
       pr "  %s : Password.password_crypto option;\n      (* --%s %s *)\n"
         var name v
+    | { flag_type = FlagSMCredentials v; flag_ml_var = var;
+        flag_name = name } ->
+      pr "  %s : Subscription_manager.sm_credentials option;\n      (* --%s %s *)\n"
+        var name v
   ) flags;
   pr "}\n"
 
@@ -822,7 +910,7 @@ let generate_customize_synopsis_pod () =
         n, sprintf "[--%s]" n
       | { op_type = String v | StringPair v | StringList v | TargetLinks v
             | PasswordSelector v | UserPasswordSelector v | SSHKeySelector v
-            | StringFn (v, _);
+            | StringFn (v, _) | SMPoolSelector v;
           op_name = n } ->
         n, sprintf "[--%s %s]" n v
     ) ops @
@@ -832,6 +920,8 @@ let generate_customize_synopsis_pod () =
           n, sprintf "[--%s]" n
         | { flag_type = FlagPasswordCrypto v; flag_name = n } ->
           n, sprintf "[--%s %s]" n v
+        | { flag_type = FlagSMCredentials v; flag_name = n } ->
+          n, sprintf "[--%s %s]" n v
       ) flags in
 
   (* Print the option names in the synopsis, line-wrapped. *)
@@ -863,7 +953,7 @@ let generate_customize_options_pod () =
         n, sprintf "B<--%s>" n, ld
       | { op_type = String v | StringPair v | StringList v | TargetLinks v
             | PasswordSelector v | UserPasswordSelector v | SSHKeySelector v
-            | StringFn (v, _);
+            | StringFn (v, _) | SMPoolSelector v;
           op_name = n; op_pod_longdesc = ld } ->
         n, sprintf "B<--%s> %s" n v, ld
     ) ops @
@@ -874,6 +964,9 @@ let generate_customize_options_pod () =
         | { flag_type = FlagPasswordCrypto v;
             flag_name = n; flag_pod_longdesc = ld } ->
           n, sprintf "B<--%s> %s" n v, ld
+        | { flag_type = FlagSMCredentials v;
+            flag_name = n; flag_pod_longdesc = ld } ->
+          n, sprintf "B<--%s> %s" n v, ld
       ) flags in
   let cmp (arg1, _, _) (arg2, _, _) =
     compare (String.lowercase arg1) (String.lowercase arg2)
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index cddd02f..bfed0cf 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -23,6 +23,7 @@ customize/password.ml
 customize/perl_edit.ml
 customize/random_seed.ml
 customize/ssh_key.ml
+customize/subscription_manager.ml
 customize/timezone.ml
 customize/urandom.ml
 dib/cmdline.ml
diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am
index c1d1245..9424c40 100644
--- a/sysprep/Makefile.am
+++ b/sysprep/Makefile.am
@@ -119,6 +119,7 @@ BOBJECTS = \
 	$(top_builddir)/customize/firstboot.cmo \
 	$(top_builddir)/customize/perl_edit.cmo \
 	$(top_builddir)/customize/ssh_key.cmo \
+	$(top_builddir)/customize/subscription_manager.cmo \
 	$(top_builddir)/customize/customize_cmdline.cmo \
 	$(top_builddir)/customize/customize_run.cmo \
 	$(SOURCES_ML:.ml=.cmo)
-- 
2.1.0




More information about the Libguestfs mailing list