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

Richard W.M. Jones rjones at redhat.com
Fri Jul 17 15:01:19 UTC 2015


On Fri, Jul 17, 2015 at 03:31:19PM +0200, Pino Toscano wrote:
> 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)

ACK.

Don't know if you want to hold this to 1.31, or push it now.  It's up
to you really, since command line options aren't quite as rigid as
API.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/




More information about the Libguestfs mailing list