Hi all Thanks to everybody who replied. I agree that the best way would be to use an internal cfengine call to generate a random password, but as there doesn't seem to be an internal way of generating strings with alphanumeric and or punctuation symbols, I persued the external call.
On Wed, Jul 27, 2011 at 08:06:18PM +0200, phnakarin said: > I spotted errors on your code. For example, repair_failed and > promise_repaired are not allowed in commands stanza but classes body. > http://cfengine.com/manuals/cf3-reference.html#classes-in-_002a Mmm, I'm not sure that's the case - they seem to work fine in commands stanzas. Everything is a promise, including commands, so it seems reasonable (to me) to be able to set classes based on whether a promise was kept/repaired, even if it's a command promise. > Try this code if you don't mind. It should do what you want. I just > played around with classes Thank you! That gave me the crucial bit of logic. set $newpass if class "need_newpass" exists create class "need_newpass" if variable $newpass is not defined if the initial password check fails, then cancel class "need_newpass" It's still not close to perfect. It calls makepasswd every time cf-agent runs, which isn't efficient when under normal circumstances (after initial installation) the generated password will never get used. I'd prefer to delay the call to makepassword until after determining that a new password is needed, but I can't see a way to set a variable based on a class that doesn't exist at the start of the run - something like: vars set_new_mysql_password:: "newpass" string => execresult("/usr/bin/makepasswd --chars 12","noshell"); commands "/usr/bin/mysqladmin status" repair_failed => { "set_new_mysql_password" }; set_new_mysql_password:: "/do/the/mysql/fix/with $newpass" would be perfect. If I do that, though, $(newpass) is never instantiated. For posterity, here's the code I've finished up with, in case anybody wonders how it got solved. I've added some extra code to force the root password if the password in .my.cnf is neither correct nor null. This takes (at least) two cf-agent runs to repair - the first pass resets the password back to null, then next run will set a new password. It restarts the mysql daemon, so may well not be something to risk in production (for eg if somebody deletes .my.cnf on the mysql server, then as part of the password recovery mysql will restart at the next agent run ). bundle agent app_db_mysql_mycnf { vars: "mycnf" string => "root/.my.cnf"; "newpass" string => execresult("/usr/bin/makepasswd --chars 12","noshell"), policy => "constant", ifvarclass => "need_newpass"; # only set $(newpass) if class # need_newpass exists classes: "need_newpass" not => isvariable("newpass"); # create class need_newpass # if $(newpass) is not set commands: "/usr/bin/mysqladmin status" handle => "check_mysql_root_pwd", comment => "Check mysql root password", repair_failed => { "set_mysql_root_from_null", "need_newpass" }; set_mysql_root_from_null:: "/usr/bin/mysqladmin --password= password $(newpass)" handle => "set_mysql_root_from_null", comment => "If null, set Mysql root password to $(newpass)", promise_repaired => { "update_mycnf" }, repair_failed => { "force_mysql_root_pwd" }, cancel_repaired => { "need_newpass" }, # once the password has been set, cancel_notkept => { "need_newpass" }; # cancel the class so that subsequent # passes don't generate a new pwd force_mysql_root_pwd:: "/root/force_mysql_root_pwd.sh" handle => "force_mysql_root_pwd", comment => "Force the mysql root password to null."; # probably should put some error trapping in here files: "/$(mycnf)" handle => "my_cnf", comment => "Seed the my_cnf file", perms => mog("0600", "root", "root"), compare => "exists", copy_from => remote_cp("$(g.clientfiles)/common/$(mycnf)"); update_mycnf:: "/$(mycnf)" handle => "update_mycnf", comment => "Add the new password to my_cnf", perms => mog("0600", "root", "root"), edit_line => section_config("client","password","$(newpass)"); force_mysql_root_pwd:: "/root/force_mysql_root_pwd.sh" handle => "my_cnf", comment => "Copy the mysql root pwd force script", perms => mog("0700", "root", "root"), copy_from => remote_cp("$(g.clientfiles)/common/root/force_mysql_root_pwd.sh"); } bundle edit_line section_config(section,variable,setting) { delete_lines: "$(variable).*" select_region => INI_section("$(section)"); insert_lines: "$(variable)=$(setting)" select_region => INI_section("$(section)"); } force_mysql_root_pwd.sh is a simple shell script: -- #!/bin/sh TEMPFILE=`mktemp` echo "UPDATE mysql.user SET Password=PASSWORD('') WHERE User='root';" \ > $TEMPFILE echo "FLUSH PRIVILEGES;" >> $TEMPFILE chmod 644 $TEMPFILE /etc/init.d/mysql stop mysqld_safe --init-file=$TEMPFILE & sleep 5 /etc/init.d/mysql stop /etc/init.d/mysql start rm $TEMPFILE Cheers Simon _______________________________________________ Help-cfengine mailing list [email protected] https://cfengine.org/mailman/listinfo/help-cfengine
