Showing posts with label rules. Show all posts
Showing posts with label rules. Show all posts

Thursday, March 19, 2009

Getting Started With CFEngine's cfagent.conf On Linux And Unix

Hey there,

It seems like a year since primary on-call duty came by and knocked me off my high horse. But, as they say, there's a reason we all fall down. It's so that we can learn how to deal with public humiliation, come to know the true meaning of pain and realize just how alone we are in this great big universe ;) It's either that or so we can learn to get back up again. The latter seems more like common sense, though. Does anyone reading this blog need to learn this lesson (after the first time)? Unless you prefer sitting, or spending your days sprawled-out face-down in the dirt, the odds are you've gotten back up before and you'll get back up again. Class dismissed ;)

Today, we're going to take a look at cfengine. It's a great (free) program that can be used for a wide variety of things (think Tripwire, Nagios, Jumpstart/Kickstart pre/post installation helper, etc). It's a decent product, that can be configured to run as simple or as complicated a setup as you prefer. So far, in my usage, I've come nowhere near the boundaries that cfengine can reach. I don't even know, for sure, what those boundaries are, since (as a side effect of not using it to its fullest potential) I've never fully tested its limitations.

That being what it is (and that is what it's being ;), today we're going to look at a skeleton of a configuration file for the cfagent program (part of cfengine, along with cfenvd, cfrun, etc). The cfagent program will allow you to hit the ground running and begin to see what cfengine can do for you. We're assuming that you've already installed cfengine, which you can download from cfengine.org or, if you're running a Linux distro, odds are there are packages available for your OS. That means that installation could just be a command away ("rpm -i cfengineXXXX.i386.rpm" or something like that). If you do need to build it from source, we'll be sure to address that in a future post on this blog. For now, we'll just assume it's already been installed, you can install it or you can find someone who'll install it for you. Whatever works for you. We'll wait ;)

For today we're going to go with a setup so basic, it may be of no use whatsoever. But, then, that's not the point :) The file we'll be using today (to control the actions of cfagent) is called cfagent.conf (Don't be fooled by the clever name ;) If we make a very simple configuration file, we could get away with this (running on a single server, just to keep things simple):

control:
any::
actionsequence = (
files
)

files:
any::
/bin/ls=0555 owner=root group=bin action=fixall


And that's it. We're not going to get into specifics (like we'll only run this command on this set of servers, etc). The basic structure of our config file is pretty much this:

CONTROL:
CLASSES::
VARIABLE/FUNCTION = (
LIST OF FUNCTION OR FACILITY VALUES
)

FACILITY:
CLASSES::
OBJECT RULES


So, today, we'll just examine what those CAPITALIZED references mean. Obviously, they correspond to the contents of the cfagent.conf above :) It should be noted that all of the names we used in our sample configuration file are special to cfengine and don't require any specific definition by you. The only line where we really take any license is with the OBJECT RULES. More on that below!

CONTROL: This is a fundamental section in any cfagent.conf. Without this section, your cfagent run won't do anything! The colon at the end of the name "control:" indicates that the name is complete. This form can also be used to assign a value to a variable under a different context using a slightly different form (not to confuse... sorry; getting off track)

CLASSES:: This is sometimes known as "GROUPS::" although both will work at version 1.4 and above if I'm anywhere near correct. Hopefully you won't have to go back that far to get your setup working (They're on 3.x right now). The CLASSES:: variable ends with a double colon. Here we're not being as specific as we could be. We're setting the class "any" so that any defined class will match and cause cfagent to proceed deeper within the nest. "any" is pre-defined by cfagent and matches everything.

VARIABLE/FUNCTION In the CONTROL section, this generally defines the main flow of execution for the remainder of the configuration file. In this instance our variable is named "actionsequence." The "actionsequence" FUNCTION simply contains a list of the FACILITY's (pardon the improper spelling :) that we want to run through and in what order. If we had more than one, they would generally be listed one per line and executed from top to bottom. The FACILITY we chose to use is called "files"

FACILITY: As we noted just above, the FACILITY: "files" is the first FACILITY: executed by our CONTROL: section above. The "files" keyword (as also noted higher above) is special to cfagent and denotes files ;) That is to say that there are a lot of basic options you can choose from when you define your files and built-in actions that you can use simply by calling them within the configuration. The FACILITY: definition ends with a colon.

CLASSES:: This works the same as above. "any"-thing will match this!

OBJECT RULES This is where we set up what we want to do with our "files." We've only selected one rule, and it breaks down like this. In standard format (and this can get very complicated if you like) your rule definition would begin with the "name" of the file you wanted to act upon, followed by specific "attributes" of that file (if necessary/required) and the "action(s)" you intend to take upon it. So our RULE

/bin/ls=0555 owner=root group=bin action=fixall


could be picked apart like so:

file name = /bin/ls
file permissions = 0555
(Note that we took the liberty of jamming the file "name" and an "attribute" together here: /bin/ls=0555. This could also be written as: /bin/ls mode=0555)
file "attribute" owner = root
file "attribute" group = bin
file "action" = fixall
<-- Again, this action is built-in and instructs cfagent to fix any problems it finds with /bin/ls. Those problems would be defined as "attributes" of the actual file that differ from the "attributes" set for it in our cfagent.conf rule.


So if we did a:

host # ls -l /bin/ls
-rwxr-xr-x 1 root root 174432 Nov 8 14:21 /bin/ls


and then we ran:

host # cfagent -qv ( the -q option turns of host sleeping - also referred to as "splaying" (???) and the -v option is the expected "verbose")

it would find /bin/ls, note that the file mode was incorrect (0755 instead of 0555 and with the group root instead of bin) and fix that for us, so that our next ls would show the "corrected" file, like so:

host # ls -l /bin/ls
-r-xr-xr-x 1 root bin 174432 Nov 8 14:21 /bin/ls


And I think that's enough for today. You never realize how much there is to explain about something until you try to explain it. But, as they say, that's why we learn to fall down... Or am I mixing my metaphors again? ;)

Cheers,

, Mike




Discover the Free Ebook that shows you how to make 100% commissions on ClickBank!



Please note that this blog accepts comments via email only. See our Mission And Policy Statement for further details.

Sunday, June 1, 2008

Perl Script To Help Solve the "M I U" puzzle on Linux or Unix

Updated 6/02 - Blogspot bracket interpretation was showing the script incorrectly.

Hey There,

For this "Lazy Sunday" post, as promised, we're going to be taking a look, again, at formal systems and the "MI to MU" puzzle presented by Douglas R. Hofstadter in his book "Godel, Escher, Bach: An Eternal Golden Braid." And, also as promised, I've put together a Perl script to walk you through it, that should run on most Linux and Unix flavours (including Cygwin for Windows).

At the end of today's post, I've attached a simple Perl program that will let you attack this puzzle and solve it, while being certain that you're adhering to "the rules." I'm not a big fan of following the rules, in general (you can get a lot more done, and make significant breakthroughs, by ignoring convention ;), but a "formal system" can't exist without them.

Many of you may have already solved this puzzle on your own. If you'll permit me the opportunity to throw you a hint (assuming you haven't solved it yet), the answer is all in the way you perceive your boundaries, as laid out by the rules. The first time I tried to solve this I ended up with a few pieces of paper describing a decision-tree that I could barely comprehend (even though I'd written it ;). The third time I tried it, I realized that I was making assumptions, based on the "rules" presented, that were completely incorrect. In fact, by following the rules exactly (and removing any thought-prejudice I had with regards to what the rules made possible) I was able to solve it in the minimum number of steps.

Needless to say, this script isn't "perfect." For instance, I didn't bother to include extra code to do case-insensitive input matching and settled with creating a simple menu that only accepts the number of your selection as input (So, for instance, when you're presented with your options, you'll have to type 4 - rather than the first letter of the option - and if you're asked for string input, you'll need to enter "I" rather than "i", etc).

I spent most of my time writing this script trying to figure out how many different ways the puzzle could permutate and stray from the rules (and, of course, fixing those holes) rather than making it aesthetically pleasing. It will probably offend Perl purists, as well, since I wrote it as quickly as possible, with little regard for efficiency and elegance of the code ;)

For a refresher on the rules of this puzzle, and examples of valid rule applications, check out yesterday's post regarding formal systems.

Here's hoping you enjoy a little brain-teaser as much as I do, and that this simple Perl script helps break you out of any "strange loops" you might have in your subconscious that prevent you from reaching the solution!

Cheers


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# mimu.pl - Solve the M I U formal system MI to MU puzzle by the rules
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

$start = "MI";
print "\nYour string is $start\n\n";

until ( $start eq "MU" ) {
if ( $start eq "M" ) {
print "\nYou Cannot Solve This\n";
print "Puzzle Within This Formal\n";
print "System From This Point On\n";
print "Try Again!\n\n";
exit;
}
print "Which rule to you want to apply?\n";
print "1. Add a U to end of string if string ends in I\n";
print "2. Duplicate a pattern following an M - Mx = Mxx\n";
print "3. Convert III to U\n";
print "4. Remove UU\n";
print "5. Quit\n";
print "?> ";
$response = <STDIN>;
if ( $response == 1 ) {
$test = $start;
$test =~ s/^.*(I)$/$1/;
if ( $test eq "I" ) {
$start = $start . "U";
print "\nYour string is now $start\n\n";
} else {
print "\nLast letter is not an I, cannot add U\n\n";
print "Your string is still $start\n\n";
}

} elsif ( $response == 2 ) {
print "\nWhat string do you want to duplicate?\n\n";
$response = <STDIN>;
chomp($response);
if ( $response =~ /^ * *$/ ) {
print "\nNo Input Received\n\n";
print "Your string is still $start\n\n";
next;
}
if ( $start =~ /^M$response.*$/ ) {
print "\nDuplicating $response\n\n";
$start =~ s/^(M)($response)(.*)$/$1$2$2$3/;
print "Your string is now $start\n\n";
} else {
print "\nThe string $response does not follow your M\n\n";
print "Your string is still $start\n\n";
}
} elsif ( $response == 3 ) {
undef @tripIs;
$string = $start;
$char = 'III';
$offset = 0;

$result = index($string, $char, $offset);
if ( $result == -1 ) {
print "\nCannot Find III in your string\n\n";
print "\nYour string is still $start\n\n";
next;
}

while ($result != -1) {
push(@tripIs, "$result");
$offset = $result + 1;
$result = index($string, $char, $offset);
}
print "\nFrom left to right, which offset\n";
print "of III would you like to replace?\n\n";
if ( defined @tripIs ) {
foreach $triplet (@tripIs) {
print "${triplet}: III\n";
$count++;
}
}
print "\n";
chomp($response = <STDIN>);
$temp = substr($string, $response, 3);
if ( $temp ne "III" ) {
print "\nCannot Find III At Index $response\n\n";
print "\nYour string is still $start\n\n";
} else {
substr($string, $response, 3) = 'U';
$start = $string;
print "\nYour string is now $start\n\n";
}
} elsif ( $response == 4 ) {
undef @doubleUs;
$string = $start;
$char = 'UU';
$offset = 0;

$result = index($string, $char, $offset);
if ( $result == -1 ) {
print "\nCannot Find UU in your string\n\n";
print "\nYour string is still $start\n\n";
next;
}

while ($result != -1) {
push(@doubleUs, "$result");
$offset = $result + 1;
$result = index($string, $char, $offset);
}
print "\nFrom left to right, which offset\n";
print "of UU would you like to remove?\n\n";
if ( defined @doubleUs ) {
foreach $doubleu (@doubleUs) {
print "${doubleu}: UU\n";
$count++;
}
}
print "\n";
chomp($response = <STDIN>);
$temp = substr($string, $response, 2);
if ( $temp ne "UU" ) {
print "\nCannot Find UU At Index $response\n\n";
print "\nYour string is still $start\n\n";
} else {
substr($string, $response, 2) = '';
$start = $string;
print "\nYour string is now $start\n\n";
}
} elsif ( $response ==5 ) {
print "\nYou quit with your string at $start\n\n";
exit;
} else {
print "WTF?\n";
print "\nYour string is still $start\n\n";
}
}
print "\nYour string is $start\n\n";
print "Puzzle Solved! Congrats\n\n";
exit;


, Mike

Saturday, May 31, 2008

Looking At Formal Systems On Linux and Unix

Hey There,

For today's post, we're going to put out a brain-teaser that won't get solved (at least on this blog) until tomorrow. It's based on a formal system (which is basically a set of rules, with specific applications, used as a method to solve an equation or problem) invented by Emil Post back in the 1920's and is most commonly referred to as a "post production system."

This basic formal system was re-popularized by Douglas R. Hofstadter in his book Godel, Escher, Bach: An Eternal Golden Braid" when he introduced the concept to folks, who weren't especially crazy about such abstract notions, by way of a little puzzle.

For today's post, we're going to reproduce (paraphrased, of course) that puzzle and let you see if you can solve it (or, if you can prove that it can't be solved, which is a possibility).

For tomorrow's post, we'll be putting up a script for Linux or Unix that will make this whole process much easier and will give you the option to "attack" this problem as quickly or slowly as you prefer. While the script will relieve you of the pleasure of completing this mental exercise (if it's at all possible to complete), it will either get you to the answer very quickly or make you wonder how long it might possibly take to solve. Considering the ingredients, that may turn out to be a huge chunk of your time ;)

And here we go. I hope you enjoy this puzzle as much as I did:

We begin with an absolute. You are starting out with a single string (which is absolutely defined, within the context of this formal system and puzzle, as a set of characters in a specific order - e.g. MI is not the same as IM). That absolute (or starting point) is simply "MI." (Note that all punctuation marks are "not" parts of the strings ;)

Give the string "MI," your goal will be to convert that string into the string "MU." Please note that, although a string like MIMUIM is a valid member of the M I U formal system, given the starting string of MI, you will never be able to have an M anywhere but in the first position. Sadly, this does not make finding the answer easy ;)

There are 4, and only 4, rules in this formal system, and you can only correctly solve the puzzle by applying any and/or all of them, one at a time, for as long as it takes to get you to "MU."

Rule 1: If your string ends with an "I", you can add a "U" to the end of it.

Ex: MI can become MIU.

Rule 2: If you have a string of the form "Mx," you can change that to "Mxx." Note here that the variable x can refer to a string (not necessarily just one character) and that only the letters M, I and U will ever exist in any string you produce by application of these rules. x is simply meant to be used as a variable notation.

Ex: MI can become MII
MIU can become MIUIU


The one thing to remember about this rule is that, once you've picked your character, or string, you can only duplicate it once per invocation of the rule. For instance, this is not acceptable:

Ex: MIU cannot become MIUIUII (duplicating "IU" and then duplicating the "I" before the "U," after the "I." You could do the following, however, in a number of steps:
MIU can become MIIUIU (by duplicating the "I" first, and then duplicating the "IU" from the resultant string)

Rule 3: If the substring "III" appears in your string, you can replace "III" with "U," but you may not do the opposite:

Ex: MIII can become MU
Ex: MU cannot become MIII


Rule 4: If "UU" occurs within your string (at any point), you can remove it from the string:

Ex: MIUUI can become MII

Using these 4 "rules of production" (or "rules of inference") can you take your initial string "MI" and change it to "MU"? Also, if it's not possible, is that provable? And, if it is possible, what's the fastest way to do it?

Have fun trying to figure it out. If you already own the aforementioned book, you may know the solution already (it's hidden somewhere in the approximately 700+ pages). Sometimes, though, your individual path to the solution will teach you a lot more than you'd learn by being told the answer :)

Enjoy,

, Mike