gconf

214 views
Skip to first unread message

Gregory Matthews

unread,
Jan 7, 2013, 9:27:33 AM1/7/13
to help-c...@googlegroups.com
Has anyone written anything to deal with gconf settings? Just thought
I'd ask before re-inventing...

basically looking for the ability to detect settings of various types
and set them conditionally.

GREG
--
Greg Matthews 01235 778658
Scientific Computing Group Leader
Diamond Light Source Ltd. OXON UK

--
This e-mail and any attachments may contain confidential, copyright and or privileged material, and are for the use of the intended addressee only. If you are not the intended addressee or an authorised recipient of the addressee please notify us of receipt by returning the e-mail and do not use, copy, retain, distribute or disclose the information in or attached to the e-mail.
Any opinions expressed within this e-mail are those of the individual and not necessarily of Diamond Light Source Ltd.
Diamond Light Source Ltd. cannot guarantee that this e-mail or any attachments are free from viruses and we cannot accept liability for any damage which you may sustain as a result of software viruses which may be transmitted in or with the message.
Diamond Light Source Limited (company no. 4375679). Registered in England and Wales with its registered office at Diamond House, Harwell Science and Innovation Campus, Didcot, Oxfordshire, OX11 0DE, United Kingdom




Gregory Matthews

unread,
Jan 7, 2013, 12:52:49 PM1/7/13
to help-c...@googlegroups.com
On 07/01/13 14:27, Gregory Matthews wrote:
> Has anyone written anything to deal with gconf settings? Just thought
> I'd ask before re-inventing...

uh... found this:

https://cfengine.com/dev/issues/825

(which has an update related to gconf from Michael Pelletier)

which leads me to section 7.4.10 of the reference manual which doesn't
appear to have been written yet...

any clues appreciated. Implementing gconf edits using the gconftool-2
shell command is going to prove cumbersome to say the least.

G

Michael Pelletier

unread,
Jan 8, 2013, 3:48:23 PM1/8/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
Shauna Thomas' XML promise mechanisms - "edit_xml" - are documented here:


The documentation seems a little vague and to lack thorough and concrete examples, though that may be because I'm not really familiar with XML in general, and I haven't had time to really sit down and work out the proper syntax of edit_xml promises. Needless to say this is going to be our best bet for Gnome config management, rather than a whole bunch of gconftool commands promises.

If you come up with something that works, I'm sure zillions of people would love to see it. Thanks!

      -Michael Pelletier.

Michael Pelletier

unread,
Jan 11, 2013, 4:50:55 PM1/11/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
Greg,

Since dealing with Gnome is next on my checklist, I cracked open the edit_xml stuff a bit... Basically it works like an edit_line in a files promise:

bundle agent gconftest
{
   files:
     "/tmp/foo.xml"    # This is the XML file to be edited
        edit_xml => xml_set;
}

First, I called this bundle to create the new XML file:

bundle edit_xml xml_set
{
   insert_tree:
     "<Host name=\"cfe_host\"><Alias>cfe_alias</Alias></Host>";
}

It gripes about it, but it creates it like so:
-----
<?xml version="1.0"?>
<Host name="cfe_host"><Alias>cfe_alias</Alias></Host>
-----

Then I change the bundle to try out the set_attribute operation:

bundle edit_xml xml_set
{
   set_attribute:
     "attrib"
       attribute_value => "xyzzy",
       select_xpath => "/Host";
}

And the file changes to:

<Host name="cfe_host" attrib="xyzzy"><Alias>cfe_alias</Alias></Host>

That is, an "attribute" is a key-value pair that falls within the tag. The promise above set an "attrib" attribute in the /Host node with a value of "xyzzy."

Next, I changed the bundle to try out set_text:

bundle edit_xml xml_setattr
{
   set_text:
     "xyzzy"
       select_xpath => "/Host/Alias";
}

And you end up with this:

 <Host name="cfe_host" attrib="xyzzy"><Alias>xyzzy</Alias></Host>

So, with this basic outline, you can see how we need to approach the gconf file. First, of course, we need to use edit_defaults to set the maximum file size to 5M, since the XML file is 2M. For example, let's look at the /apps/gdm/simple-greeter/disable_user_list node in the %gconf-tree.xml file:

        <dir name="apps">
                <dir name="gdm">
                        <dir name="simple-greeter">
                                <entry name="disable_user_list" mtime="1357935465" type="bool" value="false">
                                </entry>
                        </dir>
                </dir>

So based on what I figured out above, this presents a different situation than the examples here and in the docs - /apps/gdm/simple-greeter/disable_user_list isn't actually an XML path - we have a list of "dir" nodes with "name" attributes that work their way down to an "entry" node which has a "name" attribute of "disable_user_list." So the xpath is /gconf/dir/dir/dir/entry, in effect, which won't work well for select_xpath.

So, what I did instead is used "insert_tree" to just overwrite the whole tree in question:

bundle edit_xml do_gconf
{
  insert_tree:
    "<dir name=\"apps\">
                <dir name=\"gdm\">
                        <dir name=\"simple-greeter\">
                                <entry name=\"disable_user_list\" type=\"bool\" value=\"true\">
                                </entry>
                        </dir>
                </dir>
     </dir>"
    select_xpath => "/gconf";
}

I can't set the mtime attribute, since that wouldn't converge. And after an agent run, this tree turns up right at the end of the Gnome config file, replacing the other tree that used to be earlier in the file. Subsequent runs determine the promise has been kept, so nothing is done with the file. So, this means that the Gnome greeter's user list has been turned off. Success!! Hooray...ish.

It looks like we'd want a way to do a "select_attributes," as it were. Maybe this is already part of the XML Xpath specification? Wading through the XML Path Language doc here:


... it looks like we can do something like this:

"/gconf/dir[@name=apps]/dir[@name=gdm]/dir[@name=simple-greeter]/entry[@name=disable_user_list]"

And then use set_attribute edits to modify the "value" attribute of that node. Let me try that...

Okay, the XML library didn't complain about the select_xpath value, but it also didn't deal with the promise correctly either with or without quotes around the names in the path:

[root]# cf-agent -KIf ./gconf.cf
 !! The promised attribute (value) with value (false) was not set in /tmp/gconf.xml.defaults/%gconf-tree.xml
I: Report relates to a promise with handle ""
I: Made in version 'not specified' of './gconf.cf' near line 30
[root]#

It does, however, appear to be getting to the right node - if I change "false" to "true" in the promise it reports the promise as kept:

cf3>  !! The promised attribute to be set (value) with value (true) exists in /tmp/gconf.xml.defaults/%gconf-tree.xml (promise kept)

It just doesn't seem to be able to change it for some unknown reason. Verbose mode isn't any more informative, unfortunately. But in any case, we do seem to be well on the road to making promises Gnome configs. I'll start at "/gconf" and work my way down and see what I can figure out.

I noticed something potentially problematic, as well. I copied a fresh tree.xml file in place, and ran the promise on it, and instead of seeing one line change, I saw nearly 2,000 changes - the rewrite of the file is collapsing empty nodes and replacing &quot; with double quotes:

-                    <stringvalue></stringvalue>
+                   <stringvalue/>

-           if the &quot;vnc&quot; auth...
+           if the "vnc" auth...

Is this normal for XML?

     -Michael Pelletier.

Michael Pelletier

unread,
Jan 11, 2013, 5:03:46 PM1/11/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
I figured out what's going on with this error:

 !! The promised attribute (xyzzy) with value (false) was not set in /tmp/gconf.xml.defaults/%gconf-tree.xml

I can create a new attribute for a node, but I can't change an existing attribute for some reason.

-        <dir name="apps">
-                <dir name="gdm">
+        <dir name="apps" xyzzy="true">
+                <dir name="gdm" xyzzy="true">

But when I try to change the newly-inserted xyzzy attribute to "false," it throws the error.

This is what fails to modify the disable_user_list value:

bundle edit_xml xpath_test
{
   set_attribute:
     "xyzzy"
       attribute_value => "true",
       select_xpath => "/gconf/dir[@name=\"apps\"]/dir[@name=\"gdm\"]/dir[@name=\"simple-greeter\"]/entry[@name=\"disable_user_list\"]";
}

Having to escape the double quotes is a nuisance, but we can encapsulate that later.

     -Michael Pelletier

Michael Pelletier

unread,
Jan 11, 2013, 5:44:42 PM1/11/13
to help-c...@googlegroups.com
The error message I'm seeing when trying to change an attribute is coming from the post-update verification step, the final step in the procedure:

    //verify attribute was inserted
    if ((attr = XmlVerifyAttributeInNode(name, value, docnode, a, pp)) == NULL)
    {
        cfPS(cf_error, CF_INTERPT, "", pp, a,
             " !! The promised attribute (%s) with value (%s) was not set in %s",
             pp->promiser, a.xml.attribute_value, pp->this_server);
        return false;
    }

When I set the action to warn_only, I get to this point successfully:

    if (a.transaction.action == cfa_warn)
    {
        cfPS(cf_error, CF_WARN, "", pp, a,
             " -> Need to set the promised attribute \"%s\" to %s - but only a warning was promised",
             pp->promiser, pp->this_server);
        return true;
    }

But it's this section, coming just after the above, is the crux of the problem:

    //set attribute in docnode
    cfPS(cf_verbose, CF_CHG, "", pp, a, " -> Setting attribute \"%s\" in %s", pp->promiser,
          pp->this_server);
    if ((attr = xmlNewProp(docnode, name, value)) == NULL)
    {
        cfPS(cf_verbose, CF_INTERPT, "", pp, a,
             " !! Attribute was not successfully set in XML document");
        return false;
    }

In verbose mode, I get:

cf3>  -> Setting attribute "xyzzy" in /tmp/gconf.xml.defaults/%gconf-tree.xml
cf3>  !! The promised attribute (xyzzy) with value (false) was not set in /tmp/gconf.xml.defaults/%gconf-tree.xml

So it appears that the "xmlNewProp" call is returning a non-NULL attribute handle, since I'm not getting the "not successfully set" message, but then the verification fails. Hmm...

         -Michael Pelletier.

Michael Pelletier

unread,
Jan 11, 2013, 6:44:15 PM1/11/13
to help-c...@googlegroups.com
Opened Redmine 2034 - https://cfengine.com/dev/issues/2034

    -Michael Pelletier.

Michael Pelletier

unread,
Jan 12, 2013, 5:57:30 PM1/12/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
I found Redmine 1800 addressing the problem of the non-CFEngine-ish reformatting of the entire XML file.

       -Michael Pelletier.

Michael Pelletier

unread,
Jan 13, 2013, 9:49:46 AM1/13/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
I wrote the following to convert a gconftool XML path into a CFEngine-usable xpath:

body common control
{
  bundlesequence => { "test" };
}

bundle agent test
{
  vars:
    # Gnome config path
    "path1" string => "/apps/gdm/simple-greeter/disable_user_list";

    # Separate path elements
    "list0" slist => splitstring("$(path1)", "/", 9999);

    # Map to gconf xpath elements
    "list3" slist => maplist("/dir[@name=\"$(this)\"]", "list0");

    # Eliminate split null from before first slash
    "list4" slist => grep(".*=\"[^\"].*", "list3");

    # Build the final Gconf path
    "path2" string => concat("/gconf", join("", "list4"));

  reports:
    cfengine::
      "Original config path: $(path1)";
      "Final xpath: $(path2)";
}

     -Michael Pelletier.

Michael Pelletier

unread,
Jan 13, 2013, 1:16:14 PM1/13/13
to help-c...@googlegroups.com
Here's the same thing parameterized via "useresult":

body common control
{
  bundlesequence => { "test" };
}

bundle agent test
{
  methods:
    "any" usebundle =>
              gnome_conf_to_xpath("/apps/gdm/simple-greeter/disable_user_list"),
          useresult => "disable_user_list_xpath";

  reports:
    cfengine::
      "XPath: $(disable_user_list_xpath[0])";
}

bundle agent gnome_conf_to_xpath(gconf_path)
{
  vars:
    # Separate path elements
    "elements" slist => splitstring("$(gconf_path)", "/", 9999);

    # Map to gconf xpath elements
    "elements_mapped" slist => maplist("/dir[@name=\"$(this)\"]", "elements");

    # Eliminate split null from before first slash
    "elements_final" slist => grep(".*=\"[^\"].*", "elements_mapped");

    # Build the final Gconf path
    "xpath" string => concat("/gconf", join("", "elements_final"));

  reports:
    cfengine::
      "$(xpath)" bundle_return_value_index => "0";
}

This is only good on CFEngine 3.4.0 and up, since that's when bundle_return_value_index was introduced. 

    -Michael Pelletier.

Michael Pelletier

unread,
Jan 13, 2013, 2:07:48 PM1/13/13
to help-c...@googlegroups.com
Whoops - I forgot that the last one has to be an "entry" node, not a "dir" node. Gotta fix that.

     -Michael Pelletier.

Michael Pelletier

unread,
Jan 13, 2013, 2:50:42 PM1/13/13
to help-c...@googlegroups.com
The following gives correct results in that the last element of the path is expressed as an "entry" attribute as required, rather than a "dir" attribute.

    -Michael Pelletier.

body common control
{
  bundlesequence => { "test" };
}

bundle agent test
{
  methods:
    "any" usebundle => gnome_conf_to_xpath("/apps/gdm/simple-greeter/disable_user_list"),
          useresult => "disable_user_list_xpath";

  reports:
    cfengine::
      "XPath: $(disable_user_list_xpath[0])";
}

bundle agent gnome_conf_to_xpath(gconf_path)
{
  vars:
    # Separate the path elements
    "dirname" string => dirname("$(gconf_path)");
       "dirs"  slist => splitstring("$(dirname)", "/", 9999);
      "entry"  slist => splitstring("$(gconf_path)", "$(dirname)/", 2);

    # Map to gconf XML path elements
     "dirs_mapped" slist => maplist("/dir[@name=\"$(this)\"]", "dirs");
    "entry_mapped" slist => maplist("/entry[@name=\"$(this)\"]", "entry");

    # Eliminate split null from beginning of line
     "dirs_final" slist => grep(".*=\"[^\"].*", "dirs_mapped");
    "entry_final" slist => grep(".*=\"[^\"].*", "entry_mapped");

    # Build the final Gconf path
    "xpath" string => concat("/gconf", join("", "dirs_final"), "$(entry_final)");

Michael Pelletier

unread,
Jan 15, 2013, 12:28:15 PM1/15/13
to help-c...@googlegroups.com
An interesting thing I found about the approach used by edit_xml is that it's tied to a files promise, and you can't use a GConf "config source" for that - you need to give it the actual XML config file.

By default, the gconftool-2 will add new config values in a directory-structured path in the config source, so you'd get a file named something like this:

/etc/gconf/gconf.xml.mandatory/app/gdm/simple-greeter/%gconf.xml

And then that file would contain an xpath of /gconf/entry[@name="enable_user_list"]

The /etc/gconf/gconf.xml.mandatory/%gconf-tree.xml file appears to take precedence over these values.

So when updating a Gnome config value, we'd need to do something like the following:
  1. If the directory-based config exists for the dirname() of the desired config path:
    1. Use the %gconf.xml file to add or update the value.
    2. Remove any corresponding entry from the %gconf-tree.xml file.
  2. If the directory-based config does not exist::
    1. If the %gconf-tree.xml file exists:
      1. Use %gconf-tree.xml to add or update the value.
    2. If the %gconf-tree.xml file does not exist:
      1. Create the directory-based %gconf.xml file mode 644. (default for goconftool-2)
      2. Add the value to that file.
This would work properly with both the defaults, which comes with a gconf-tree.xml file, and the mandatory components which start out with an empty directory which gconftool-2 populates with directory-based configs.

We'd also want to check the config source path name given to the method - if it's a directory, we'd do the above, but if it doesn't exist or is a file name, then we'd operate directly on the specified file instead.

     -Michael Pelletier.

Michael Pelletier

unread,
Jan 16, 2013, 10:20:50 PM1/16/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
Here's what I've put together for Gnome configuration with edit_xml over the last few evenings, let me know what you think...


# Example:
# "sec_gnome_disable_login_user_list" -> { "DISA_GSCRHEL5" }
# usebundle => gconf("/etc/gconf/gconf.xml.defaults",
# "/apps/gdm/simple-greeter/disable_user_list", "true", "bool");

The actual test agent bundle is not set up, as you can see, but I'm planning to run some preliminary tests tomorrow. It looks like this could also work on Solaris Gnome as well as Linux, provided the CFEngine is built with libxml2.

      -Michael Peleltier.

Nick Anderson

unread,
Jan 16, 2013, 10:30:59 PM1/16/13
to Michael Pelletier, help-c...@googlegroups.com, greg.m...@diamond.ac.uk

Nice! Can't wait to try it. years ago I had a python script that ran on user logins to default gconf settings for the session. This would have been much better.

--
Sent from Kaiten Mail. Please excuse my brevity.

Gregory Matthews

unread,
Jan 17, 2013, 6:28:00 AM1/17/13
to Michael Pelletier, help-c...@googlegroups.com
On 17/01/13 03:20, Michael Pelletier wrote:
> Here's what I've put together for Gnome configuration with edit_xml over
> the last few evenings, let me know what you think...
>
> https://github.com/mvpel/design-center/blob/master/sketches/mvpel/gconfsketch.cf

groovy! looking forward to trying this out!

GREG

>
>
> # Example:
> # "sec_gnome_disable_login_user_list" -> { "DISA_GSCRHEL5" }
> # usebundle => gconf("/etc/gconf/gconf.xml.defaults",
> # "/apps/gdm/simple-greeter/disable_user_list", "true", "bool");
>
> The actual test agent bundle is not set up, as you can see, but I'm
> planning to run some preliminary tests tomorrow. It looks like this
> could also work on Solaris Gnome as well as Linux, provided the CFEngine
> is built with libxml2.
>
> -Michael Peleltier.


Michael Pelletier

unread,
Jan 17, 2013, 12:31:15 PM1/17/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
Flag on the play...

We can't use it as is on Solaris 9 with gconftool-2 2.1.0, at least, since the instead of a "value" attribute in the <entry> node, it creates a "type" attribute and then a "<stringvalue>" node which contains the value as text:

<entry name="foo" type="string"><stringvalue>testing123</stringvalue></entry>

The 2.1.0 version doesn't recognize the "value" attribute at all - if you put it in the tag, it just reverts to the default value specified in the schema.

Unfortunately, this is also making me wonder if it might not be better to use a combination of execresult and commands with gconftool-2 - direct updates to the files outside of gconftool-2 could get overwritten if the gconf daemon is running and has a different in-memory picture of the XML tree. It would also be possible to leave the XML file in an inconsistent state - some <entry> nodes on Solaris refer to schemas, so they shouldn't be deleted entirely as my promise kit does - it would need to use "delete_attribute" instead. And there's the question of locking, and so on.

*sigh*

So I think we'll need to develop something else to accept a proper "xml:" config source path (don't want to use the default path since that would not necessarily be convergent), and then run gconftool-2 in an execresult() to get the current value, set a class based on whether that matches what's specified, and then if a change is required we get the type for the value with gconftool-2 --get-type, then run gconftool-2 --set. The drawback, of course, is we'd need at least one execution of gconftool-2 for each value promised in order to verify the promises, so we'd want to set some sort of persistence value to keep it from running a bunch child processes every five minutes. Not sure if we should handle that in the bundle or in whatever uses the bundle - probably the latter, though.

But regardless, it's been a very good learning experience with respect to edit_xml promises and CFEngine coding design, and uncovered a bug to boot.

             -Michael Pelletier.

Michael Pelletier

unread,
Jan 17, 2013, 5:22:39 PM1/17/13
to help-c...@googlegroups.com, greg.m...@diamond.ac.uk
Here's work-in-progress using gconftool-2 instead of edit_xml, which minimizes the number of executions and avoids spawning any shells:


It got a little silly with the variable/class dependencies needed to avoid unnecessary runs, but it does converge on the third iteration thankfully. I realized we need both a "set" and "unset" functionality, but it should be fairly straightforward to convert this one bundle to support it. One nice thing is that it sets the type automatically by running gconftool-2 --get-type.

If anyone can suggest improvements, I'd appreciate it. I don't use any implicit looping, and I'm wondering if that might help reduce the complexity any.

      -Michael Pelletier.

$       cat ~/.gconf/apps/gdm/simple-greeter/*
<?xml version="1.0"?>
<gconf>
        <entry name="disable_user_list" mtime="1358458694" type="bool" value="false">
        </entry>
</gconf>
$
$ /var/cfengine/bin/cf-agent -KIf ./gconfsketch2.cf
 -> Executing '/usr/bin/gconftool-2 --config-source=xml:readwrite:/home/pelletm/.gconf --type 'bool' --set '/apps/gdm/simple-greeter/disable_user_list' 'true'' ... (no timeout)
 -> Completed execution of /usr/bin/gconftool-2 --config-source=xml:readwrite:/home/pelletm/.gconf --type 'bool' --set '/apps/gdm/simple-greeter/disable_user_list' 'true'
 !! Method invoked repairs
$
$       cat ~/.gconf/apps/gdm/simple-greeter/*
<?xml version="1.0"?>
<gconf>
        <entry name="disable_user_list" mtime="1358458715" type="bool" value="true">
        </entry>
</gconf>
$
$ time /var/cfengine/bin/cf-agent -KIf ./gconf-tool.cf

real    0m0.24s
user    0m0.06s
sys     0m0.02s
$

Gregory Matthews

unread,
Jan 21, 2013, 6:51:51 AM1/21/13
to Michael Pelletier, help-c...@googlegroups.com
On 17/01/13 22:22, Michael Pelletier wrote:
> Here's work-in-progress using gconftool-2 instead of edit_xml, which
> minimizes the number of executions and avoids spawning any shells:
>
> https://github.com/mvpel/design-center/blob/master/sketches/mvpel/gconf-tool.cf

I get a 404 for that link (but its the coolest 404 page I've seen!)

G
Reply all
Reply to author
Forward
0 new messages