Puppet
I hate cfengine. Puppet is an alternative software configuration manager that can help to centralize and standardize
configuration and distribute modifications on your systems. As of 2015 it is reasobaly popular and there are dozens book published about it.
From the point of view of software design Puppet is written in ruby and is a second generation CMS. That might mean that it is a better deal then cfengine:
- Written in Ruby
- It's
licensed under the GNU General Public License (GPL).
- Includes a configuration language to write manifests and modules, daemons to run the Puppet instructions
on managed systems and to coordinate machines that are using Puppet, and a
dashboard
to help visualize your systems and create reports.
- There is a derivative called Chief
so there is some intense competition and hopefully cross-pollination.
- Most puppet config files, while verbose, are not any harder to configure than something like
Nagios.
Such systems only make sense is you have dozens of hundreds similar systems and can exploit
this similarity using Puppet. For example a large HPC cluster.
Still the approach taken is pretty verbose. This problem with "too much typing" can be solved with
automatic tools. Here is an example specification of for a typical sudoer file:
class sudo {
package { ["sudo","audit-libs"]: ensure => latest }
file { "/etc/sudoers":
owner => root,
group => root,
mode => 440,
content => template("sudo/files/sudoers.erb"),
require => Package["sudo"],
}
}
With this level of verbosity automatic generation of such files using, say, Perl scripts is
the only viable solution.
Puppet is also able to collects facts from a managed systems using facter utility
The user and group types
In the absence of central registries such as LDAP, it is useful to be able to manage user accounts
on each of your machines. There are providers for all supported platforms; however, the available attributes
vary. On Linux, the useradd provider is the most common. It allows the management of all fields in
/etc/passwd, such as uid and shell, but also group memberships
group {
'ruser':
ensure => present,
gid => 4002,
}
user {
'joeuser':
uid => 332456,
gid => 10
home => '/home/bigdata'
managehome => true, # <- adds -m to useradd
shell => '/bin/bash',
groups => [ 'reseachers' ],
}
As with all resources, Puppet will not only make sure that the user and group exist, but also
fix any divergent properties such as the home directory.
The exec resource type
Puppet is not a specialized scripting engine, but instead a tool that allows you to model part of
your system state in a DSL and is capable of altering your system to meet the defined goal. This
is why you declare a user
and a group
, for example, instead of invoking
groupadd
and useradd
. Puppet also knows that on different platforms, other
commands are used for account management and that the arguments can be subtly different on some systems.
There are cases where you only need Puppet to invoke some exotic commands from very few places in
your manifest.
For such cases, Puppet provides the exec
resource type, which allows the execution of
custom commands in lieu of an abstract sync action. For example, it can be used to unpack a tarball
in the absence of a proper package:
exec {
'tar cjf /opt/packages/homebrewn-3.2.tar.bz2':
cwd => '/opt',
path => '/bin:/usr/bin',
creates => '/opt/homebrewn-3.2',
}
The creates
parameter is important for Puppet to tell whether the command
needs running — once the specified path exists, the resource counts as synced. For commands that
do not create a telltale file or directory, there are alternative parameters, onlyif
and
unless
, to allow Puppet to query the sync state:
exec {
'perl -MCPAN -e "install YAML"':
path => '/bin:/usr/bin',
unless => 'cpan -l | grep -qP ^YAML\\b'
}
The query command's exit code determines the state. In the case of unless
, the
exec
command runs if the query fails.
Finally, the exec
type resources are the second notable case of receivers for events
using notify
and subscribe
:
exec {
'apt-get update':
path => '/bin:/usr/bin',
subscribe =>
File['/etc/apt/sources.list.d/jenkins.list'],
refreshonly => true,
}
You can even chain multiple exec
resources in this fashion so that each invocation triggers
the next one. However, this is a bad practice and degrades Puppet to a (rather flawed) scripting engine.
The exec
resources should be avoided in favor of regular resources whenever possible. Some
resource types that are not part of the core are available as plugins from the Puppet Forge. You will
learn more about this topic in
Chapter 5, Extending Your Puppet Infrastructure with Modules.
Since exec
resources can be used to perform virtually any
operation, they are sometimes abused to stand in for more proper resource types. This is a typical
antipattern in Puppet manifests. It is safer to regard exec
resources as the last resort,
which are only to be used if all other alternatives have been exhausted.
Let's briefly discuss two more types that are supported out of the box. They allow the management
of cron jobs and mounted partitions and shares, respectively, which are frequent requirements in server
operation.
The cron resource type
A cron job mainly consists of a command and the recurring time and date at which to
run the command. Puppet models the command and each date particle as a property of a resource with the
cron
type:
cron {
'clean-files':
ensure => present,
user => 'root',
command => '/usr/local/bin/clean-files',
minute => '1',
hour => '3',
weekday => [ '2', '6' ],
environment => '[email protected]',
}
The environment
property allows you to specify one or more variable bindings for
cron
to add to the job.
The mount resource type
Finally, Puppet will manage all aspects about mountable filesystems for you-their basic
attributes such as the source device and mount point, the mount options, and the current state. A line
from the fstab
file translates quite literally to a Puppet manifest:
mount {
'/media/gluster-data':
ensure => 'mounted',
device => 'gluster01:/data',
fstype => 'glusterfs',
options => 'defaults,_netdev',
dump => 0,
pass => 0,
}
For this resource, Puppet will make sure that the filesystem is indeed mounted after the run.
Ensuring the unmounted
state is also possible, of course, but Puppet can also just
make sure the entry is present
in the fstab
file, or absent
from
the system altogether.
Built-in language
The whole paradigm is different from that of scripting languages. Whereas Ruby or Perl are imperative
languages, which are based around statements that will be evaluated in a strict order, the Puppet language
(DSL) is declarative: the manifest declares a set of resources that are expected to have certain properties.
So the manifest for /etc/sudoer file above ensures that the file /etc/sudoers is installed
from templates and after the installation has specified properties (ownership and permissions)
Variable assignment works just like in most scripting languages. Any variable name is always prefixed
with the $
sign:
$proxy_server = 'proxy.firma.net'
$mc_package = "https://${epel}/pkg/mc.rpm"
Like in Perl, Puppet performs variable value substitution in strings that are in double quotes, but
no interpolation at all in single-quoted strings.
Variables are useful to make your manifest more concise and comprehensible. They help you with the
overall goal of keeping your source code free from redundancy. An important distinction from variables
in imperative programming and scripting languages is the immutability
of variables in Puppet manifests. Once a value has been assigned, it cannot be overwritten.
Under specific circumstances, it is possible to amend values through concatenation. You might encounter
statements such as for $variable += 'value'
. This should be used with care, or avoided
altogether.
Variable types
There are three main variable types: strings, arrays, and hashes. Puppet 4 introduced a richer type
system. The three variable types work much like their respective counterparts in Perl:
$a_string = 'This is a string value'
$an_array = [ 'This', 'forms', 'an', 'array' ]
$a_hash = {
'subject' => 'Hashes',
'predicate' => 'are written',
'object' => 'like this',
'note' => 'not actual grammar!',
'also note' => [ 'nesting is',
{ 'allowed' => 'of course' } ],
}
Accessing the values is equally simple. Note that the hash syntax is similar to that of Ruby, not
Perl's:
$x = $a_string
$y = $an_array[1]
$z = $a_hash['object']
Strings can obviously be used as resource attribute values, but it's worth noting that a resource
title can also be a variable reference:
package {
$apache_package:
ensure => 'installed'
}
It's intuitively clear what a string value means in this context. But you can also pass arrays here
to declare a whole set of resources in one statement. The following manifest manages three packages,
making sure that they are all installed:
$packages = [ 'apache2',
'libapache2-mod-php5',
'libapache2-mod-passenger', ]
package {
$packages:
ensure => 'installed'
}
Control structures
The most common control element is the if/else
block. It is quite similar to its equivalent
in many programming languages:
if 'mail_lda' in $needed_services {
service { 'dovecot': enable => true }
} else {
service { 'dovecot': enable => false }
}
The Puppet has a case
statement, which is reminiscent of its counterpart in other
languages as well:
case $role {
'imap_server': {
package { 'dovecot': ensure => 'installed' }
service { 'dovecot': ensure => 'running' }
}
/_webserver$/: {
service { [ 'apache', 'ssh' ]: ensure => 'running' }
}
default: {
service { 'ssh': ensure => running }
}
}
A variation of the case
statement is the selector. It's an expression, not a statement,
and can be used in a fashion similar to the ternary if/else
operator found in C-like languages:
package {
'dovecot': ensure => $role ? {
'imap_server' => 'installed',
/desktop$/ => 'purged',
default => 'removed',
}
}
Regular expersssions
language used by Pupper is close to Perl, which simply its learning (after all Rubi is derivative
of perl). Puppet supports standard Ruby regular expressions, as defined at
http://www.ruby-doc.org/core/Regexp.html . The
regex operator works with a string on the left, and the regular expression on the right of the ~ operator.
$version_of_mc_istalled =~ /5.8.1/ #
$version_of_r_installed !~ /3.21/ #
Resources and properties
Each of the manifests you wrote in the previous section declared one respective resource. Resources
are the elementary building blocks of manifests. Each has a type (in this case, notify
and service
, respectively) and a name or title (Hello, world!
and puppet
).
Each resource is unique to a manifest and can be referenced by the combination of its type and name,
such as Service["puppet"]
. Finally, a resource also comprises a list of zero or more attributes.
An attribute is a key-value pair such as "enable => false"
.
Attribute names cannot be chosen arbitrarily. Each resource type supports a specific set of attributes.
Certain parameters are available for all resource types, and some names are just very common, such as
ensure
. The service type supports the ensure
property, which represents the
status of the managed process. Its enabled
property, on the other hand, relates to the
system boot configuration (with respect to the service in question).
Note that I have used the terms attribute, property, and parameter in a seemingly interchangeable
fashion. Don't be deceived-there are important distinctions. Property and parameter are the two different
kinds of attributes that Puppet uses. You have already seen two properties in action. Let's look at
a parameter:
service {
'puppet':
ensure => 'stopped',
enable => false,
provider => 'upstart',
}
The provider
parameter tells Puppet that it needs to interact with the upstart
subsystem to control its background service, as opposed to systemd
or init
.
If you don't specify this parameter, Puppet makes a well-educated guess. There is quite a multitude
of supported facilities to manage services on a system. You will learn more about providers and their
automatic choosing later.
The difference between parameters and properties is that the parameter merely indicates
how Puppet should manage the resource, not what a desired state is. Puppet will only
take action on property values. In this example, these are ensure => 'stopped'
and
enable => false
. For each such property, it will perform the following tasks:
- Test whether the resource is already in sync with the target state
- If the resource is not in sync, trigger a sync action
A property is considered to be in sync when the system entity that is managed by the given resource
(in this case, the upstart
service configuration for Puppet) is in the state that is described
by the property value in the manifest. In this example, the ensure
property will be in
sync only if the puppet
service is not running. The enable
property is in
sync if upstart
is not configured to launch Puppet at system start.
As a mnemonic concerning parameters versus properties, just remember that properties can be out of
sync, whereas parameters cannot.
Interpreting the output of the puppet apply command
As you have already witnessed, the output presented by Puppet is rather verbose. As you get more
experienced with the tool, you will quickly learn to spot the crucial pieces of information. Let's first
look at the informational messages though. Apply the service.pp
manifest once more:
Puppet took no particular action. You only get two timings-one from the compiling phase of
the manifest and the other from the catalog application phase. The catalog is a comprehensive representation
of a compiled manifest. Puppet bases all its efforts concerning the evaluation and syncing of resources
on the content of its current catalog.
Now, to quickly force Puppet to show you some more interesting output, pass it a one-line manifest
directly from the shell. Regular users of Ruby or Perl will recognize the call syntax:
Tip
I prefer double quotes in manifests that get passed as command-line arguments, because on the shell,
the manifest should be enclosed in single quotes as a whole, if at least for convenience.
You instructed Puppet to perform yet another change upon the Puppet service. The output reflects
the exact change that is performed. Let's analyze this log message:
- The
Notice:
keyword at the beginning of the line
represents the log level. Other levels include Warning
, Error
, and
Debug
.
- The property that changed is referenced with a whole path, starting
with
Stage[main]
. Stages are beyond the scope of this book, so you will always just
see the default of main
here.
- The next path element is
Main
, which is another default.
It denotes the class in which the resource was declared. You will learn about classes in
Chapter 4, Modularizing Manifests with Classes and Defined Types.
- Next is the resource. You already learned that
Service[puppet]
is its unique reference.
- Finally,
enable
is the name of the property in question.
When several properties are out of sync, there will usually be one line of output for each property
that gets synchronized.
- The rest of the log line indicates the type of change that Puppet
saw fit to apply. The wording depends on the nature of the property. It can be as simple as
created
for a resource that is newly added to the managed system, or a short phrase such as
changed false to true
.
Dry-testing your manifest
Another useful command-line switch for puppet apply
is the --noop
option.
It instructs Puppet to refrain from taking any action on unsynced resources. Instead, you only get log
output that indicates what will change without the switch. This is useful to determine whether a manifest
would possibly break anything on your system:
Note that the output format is the same as before, with a (noop
) marker trailing
the notice about the sync action. This log can be considered a preview of what will happen when the
manifest is applied.
As shown throughout all previous examples, you declare a resource using the resource type lowercase
and enclose the definition in curly brackets.
package { 'puppet':
ensure => present,
}
Once the resource has been given a unique title, it is possible to refer to that resource by name. This
is called a Resource Reference. In this chapter we're going to refer to specific resources quite often,
so let's describe how to do it. To create a resource reference, uppercase the first letter of the resource
type and enclose the title in square brackets. For example, when referring to the package resource created
above, you'd use Package['puppet']. Here an example which builds a service to run the puppet agent installed
above.
service { 'puppet':
ensure => running,
enabled => true,
require => Package['puppet'],
}
So remember: create a resource with the lowercase type, and refer to an existing resource with an
uppercase first letter.
Ordering Resources
In many situations some resources must be applied before others. For example, you cannot start a
service until after you install the package which contains the application. Here we will show you the
before and require metaparameters you can use to ensure the package is installed before the service
is started.
package { 'puppet':
ensure => present,
before => Service['puppet'],
}
service { 'puppet':
ensure => running,
enable => true,
require => Package['puppet'],
}
The before and require metaparameters are redundant in this case. Either one would work by itself. Use
the one which fits your manifest and is easiest to read. Belt and suspenders people like myself often
use both when possible.
Triggering Refresh Events
The before and require metaparameters ensure that dependencies are processed before resources that
require them. However, these parameters do not link or provide data to the other resource.
The notify and subscribe metaparameters operate in a similar manner, but will also send a refresh event
to the dependent resource if the dependency is changed. The dependent resource will take a resource-specific
action. For example, a service would restart after the configuration file has been changed.
Let's modify our previous policy to upgrade the Puppet package whenever a newer version is available.
package { 'puppet':
ensure => latest,
notify => Service['puppet'],
}
service { 'puppet':
ensure => running,
enable => true,
subscribe => Package['puppet'],
}
In this case, if a newer version of Puppet is available then the puppet package will be upgraded. Any
time the Puppet package is installed or upgraded, the puppet service will be restarted.
As before, the notify and subscribe metaparameters are redundant. Either one would send the refresh
event without the other. Belt and suspenders people like myself do both.
The refresh event means something special to Exec resources. If an Exec resource is created with the
attribute refreshonly set to true, then the Exec resource will not run unless it receives a refresh
event. In the following example, we will update the facts.yaml file for MCollective only after Puppet
has been upgraded.
Dependencies: Chaining Resources with Arrows
You can also order and related resources using Chaining Arrows. You put the required resource on
the left, and the dependent resource on the right, linked together with ->. For example, to install
puppet before starting the service you could express it like so.
Package['puppet'] -> Service['puppet']
You can use ~> to also send a refresh event, like notify does. For example, this will restart the Puppet
service after the Puppet package is upgraded.
Package['puppet'] ~> Service['puppet']
The chaining arrow syntax is harder to read than the metaparameters, and should be avoided when possible.
In particular, right to left relationships are harder to read and explicitly against the Puppet Style
Guide.
# Don't do this. Order it left -> right instead.
Service['puppet'] <~ Package['puppet']
Processing with Collectors
A collector is a grouping of many resources together. You can use Collectors to affect many resources
at once.
A Collector is declared by the capitalized type followed by <|, an optional attribute comparison, and
|>. Let's examine some collectors.
User <||> # every User
User <| groups == 'wheel' |> # Users in the wheel group declared in a manifest
Package <||> # every Package
Package <| tag == 'packages' |> # Packages tagged with 'packages' tag in a manifest
Service <||> # every Service
Service <| enabled == true |> # Services set to start at boot time in a manifest
# Search expressions may be grouped with parenthesis and combined
Service <| ( ensure == running ) or ( enabled == true ) |> # Services running OR set to start at boot
time
Service <| ( ensure == running ) and ( title != 'puppet' ) |> # Services other than Puppet set to be
running
I spent a while going over recipes, and comparing them to Puppet. For example, here's some code to
manage sudo for Chef. The Chef code was written by Chef's authors; the Puppet code was written by
myself. The Chef code is spread across 3 files.
# recipes/default.rb:
package "sudo" do
action :upgrade
end
template "/etc/sudoers" do
source "sudoers.erb"
mode 0440
owner "root"
group "root"
variables(
:sudoers_groups => node[:authorization][:sudo][:groups],
:sudoers_users => node[:authorization][:sudo][:users]
)
end
# attributes.rb:
authorization Mash.new unless attribute?("authorization")
authorization[:sudo] = Mash.new unless authorization.has_key?(:sudo)
unless authorization[:sudo].has_key?(:groups)
authorization[:sudo][:groups] = Array.new
end
unless authorization[:sudo].has_key?(:users)
authorization[:sudo][:users] = Array.new
end
# metadata.rb:
maintainer "Opscode, Inc."
maintainer_email "[email protected]"
license "Apache 2.0"
description "Installs and configures sudo"
version "0.7"
attribute "authorization",
:display_name => "Authorization",
:description => "Hash of Authorization attributes",
:type => "hash"
attribute "authorization/sudoers",
:display_name => "Authorization Sudoers",
:description => "Hash of Authorization/Sudoers attributes",
:type => "hash"
attribute "authorization/sudoers/users",
:display_name => "Sudo Users",
:description => "Users who are allowed sudo ALL",
:type => "array",
:default => ""
attribute "authorization/sudoers/groups",
:display_name => "Sudo Groups",
:description => "Groups who are allowed sudo ALL",
:type => "array",
:default => ""
Here's more or less the same thing for Puppet:
class sudo {
package { ["sudo","audit-libs"]: ensure => latest }
file { "/etc/sudoers":
owner => root,
group => root,
mode => 440,
content => template("sudo/files/sudoers.erb"),
require => Package["sudo"],
}
}
Both Chef and Puppet then take this information and output it through an ERB template, which is
an exercise for the reader, since it's basically the same for both.
There's a few things worth noting here. First of all, Puppet has zero metadata available. If you
want to set sudo-able groups, you need to know those variable names ahead of time and set them to
what you want. Both your template and whatever code sets your sudo-able groups must magically 'just
know' this information. Since the Puppet DSL is not even Ruby, you have *zero* ability to perform
any kind of metadata analysis on these attributes in order to make code more generic.
Chef gives you complete metadata about the variables it's using. This is powerful and indeed critical
in my imagined use domains for Chef (keep reading). That metadata comes at a cost of a lot of boilerplate
code, though. Chef comes with some rake tasks to generate some scaffolding. I'm always uncomfortable
with scaffolding like this; I think this kind of code generation is a bad way to do metaprogramming.
Chef spreads this information across 3 files, named a particular way. Puppet has a similar scheme
of magically named files, but it's basically just a folder structure, a file called init.pp, and
templates/source files. For a fairly simple task, Chef requires you to know a folder structure and
3 file names, and which data goes in which files. This is congruent with the Ruby world's (perhaps
specifically the rails/merb world's?) general practice of 'convention not configuration'. This is
in addition to all of the 'you just have to know' parts of the Chef system which are taken from Merb,
such as where models and controllers live, though you would not need to edit those save for pretty
advanced cases.
Lastly, Chef provides you with an actual data structure that is fed to the sudoers template. Puppet
simply uses available dynamically-scoped variables in its template files. This is *awful*, and a
big loss for puppet. I administrate Zimbra servers, for example, which require extra content in sudoers.
I cannot add this to the zimbra module unless the zimbra module were to be the one including the
sudo module. There are solutions to this, of course, but this is a really, really simple use case
and we're already
shaving yaks. Chef's method is undeniably superior.
All 3 of these are part of the same core difference between the two: Puppet is an application,
and Chef is a part of one.
Chef is a library to be used in a combined system of resource management in which the application
itself is aware of the hardware it's using. This allows certain kinds of applications to exist on
certain kinds of platforms (particularly EC2) that simply couldn't before--an application using this
system can declare a database just as well as it can declare an integer. That's fundamentally powerful,
awesome, amazing.
Puppet is an application which has an enormous built-in library of control methods for systems.
The puppet package manager, for example, supports multiple kinds of *nix, Solaris, HPUX, and so forth.
Chef cookbooks can certainly be written to do this, but I imagine by the time you supported everything
puppet does I don't think Chef would get a smiley-face sticker for being tiny and pure with extra
ruby sauce. Puppet's not a fundamental change, it's just a really nice workhorse.
I picked puppet for the project I'm working on now. It made sense for a lot of reasons.
Probably first and foremost, there are 3 other sysadmins working with
me, some split between this project and others. None of us are ruby programmers. We
don't write rake tasks like we configure Apache, we don't want to explain to new hires the difference
between a symbol or a variable, or where the default Merb configuration files, or 100 other ruby-isms.
Meanwhile, most puppet config, silly folder structure aside, is not any
harder to configure than something like Nagios. I think it would be a mistake for
an IT shop with a lot of existing systems running various old-fashioned stateful applications like
databases or LDAP to suddenly declare that sysadmins need to be Merb programmers.
Puppet's much deeper out-of-the-box support for a lot of systems provides
the kind of right-now real improvements that a lot of IT shops and random contractors desperately
need. System administration is depressingly rarely about being elegant or 'the best' and much more
frequently about being repeatable and reliable. It's just the nature of the business--if the systems
ran themselves, there would be no administrators.
Having a bunch of non-programmers become not just programmers but programmers specializing in
a tiny subset of the ruby world is a lot of yaks to shave for an organization. This is not some abstract
jab at my colleagues: I am most certainly not a Merb programmer, and even if I were, I have too many
database copies to make, SQL queries to run, mysterious performance problems to diagnose and deployments
to make to give this kind of development the attention it requires. How many system administrators
do you know that use the kind of TDD that Merb can provide for their bash scripts? What would make
one think that's going to happen with Chef?
The other big reason I picked Puppet is that it's got a sizable mailing list, a friendly and frequently
used google group for help, and remains in active development after a couple of years. I don't think
Reductive Labs is going away, and if it did, there have been a lot of contributors to the code base
over those 2 years.
It's worth noting, though, that the Chef guys come with an impressive set of resumes. It seems
to be somehow tied in with Engine Yard (several presentations about Chef include Ezra Zygmuntowicz
as a speaker). I worry, though, that they are working the typical valley business model, namely to
explode about a year after launch. Chef was released about 8 months before I write this. The organization
I am installing Puppet for does not have the Ruby talent base required to ensure that they can fix
bugs as required in the long term if Opscode goes away, or if they get hired on to Engine Yard and
they make Chef into the kind of competitive differentiation secret it could be.
Chef currently manages the EC2 version of Engine Yard, and that's just the kind of thing I cannot
imagine using puppet for: interact with a giant ruby application to manage itself. If you have a
lot of systems joining and leaving the resource pool as required, Chef's ability to add nodes dynamically
is going to save you. The ability to define resources programmatically is very powerful--one could
easily imagine reducing the number of web server threads if a system's CPU use goes over a certain
threshold, for example. I would not try that in puppet! But note that this is an application built
from scratch to expect such a command and control system to exist. If you're just managing a bunch
of LAMP stacks and samba servers, this is more power than you need. One of the Opscode founders has
some slides that talk about this kind of model.
And Chef is powerful for that model, sure, but is that even the model you want for your applications?
Applications should not have to worry about the hardware they use. Making an application's own hardware
use visible to itself encourages programmers to spend time thinking about issues they should be trying
their hardest to ignore. A better model is App Engine's, where the system just scales forever without
developer intervention. Even
Azure's
service configuration schema model is better, in which different application roles (web, proxy,
etc) are described as resources and given a dynamic instance count, and transparently scalable data
stores are available. The number of 'nodes' in the system is never an issue for either model.
Chef is what you'd use to build that auto-scaling backend. Engine Yard uses it for, well, Engine
Yard--scalable rails hosting, transparently sold as a service to folks who can then just blissfully
program in rails and never think about Chef. Very few organizations are making that infrastructure,
and most of them that are are shaving really big yaks and need to stop and use one of the available
clouds.
Meanwhile, a very many organizations are running 6 kinds of *nix to maintain tens of older applications
built on the POSIX or LAMP paradigms, or hosting virtual machines running applications made who knows
when. For these organizations, Puppet is probably the easiest thing that could work, and thus probably
the best option.
I'm sure there are sysadmins out there who think I'm completely wrong, and that you just can't
beat the elegance Chef provides. There are a lot of people better than me out there, and I'm sure
they have a point. But in my experience, bad system administration happens when sysadmins try and
do everything for themselves. For a given situation in system administration, it's highly unlikely
a sysadmin can do a better job than an available tool. Puppet's sizable default library is what most
organizations need, not the ability to write their own.
And all of the above aside, one thing is clear: there is little excuse for an organization with
3 or more *nix servers not to be using Puppet, Chef, cfengine, or *something*. I would argue that
about 80% of the virtualization push is dodging some of the core questions of system administration,
making systems movable to new resources indefinitely rather than making their configuration repeatable,
but that's a topic for another post. Especially since nobody got this far on this one anyway.
Adam Jacob
Hi John! Thanks for being passionate about my favorite space - configuration management. You
do great work, and I know your intent wasn't necessarily to sow discord - but I wanted to take
a moment to comment on a few of your points that I think are either wrong or missing some important
context.
1) Large installed base
Chef has somewhere in the neighborhood of ~1500 working installations. It's true that our early
adopters are primarily large web players like Wikia, Fotopedia, and 37signals. We also have a
growing number of people integrating Chef directly into their service offering - it's not just
Engine Yard, it's RightScale and others.
2) Large developer base
According to Ohloh, 39 developers have contributed to Puppet in the last 12 months, and 71
over the projects entire history.
Chef has been open source for a year. We just had our 100th CLA (contributor license
agreement, meaning they can contribute code). Over the course of the year, 52 different people
have contributed to Chef, including significant functionality (for the record, 5 of them work
for Opscode.) We're incredibly proud of the community of developers who have joined the project
in the last year, and the huge amount of quality code they produce.
3) Dedicated Configuration Language
To each their own, man. :) My preference for writing configuration management in a 3GL
was born out of frustration with doing the higher order systems integration tasks. By definition,
internal DSLs aren't meant to do that - when they start being broadly applicable, they loose the
benefits they gained from domain specificity. For me, the benefit of being able to leverage the
full power of a 3GL dramatically outweigh the learning curve, and I think a side-by-side
comparison of the two languages shows just how close you can get to never having to leave the
comfort of your DSL most of the time.
4) Robust Architecture
Chef is built to scale horizontally like a web application. It's a service oriented architecture,
built around REST and HTTP. Like cfengine, it pushes work to the edges,
rather then centralizing it. There are large (multi-thousand node) chef deployments, and larger
ones coming. Chef scales just fine.
5) Documentation
It's true, we've been focused pretty intently on refining Chef in tandem with our earlier adopters,
and that focus has had an impact on the clarity of our documentation. Rest assured, we're working
on it.
6) Language/Framework Neutral
I'm not sure where this comes from, other than we've had great adoption in the Ruby community.
People deploy and manage every imaginable software stack with Chef - Java, Perl, Ruby, PHP
- it's all being managed with Chef.
7) Multi-Platform
It's true that, at release a year ago, Chef didn't support many platforms. Since then, we've
been growing that support steadily - all the platforms you list run Chef just fine, with the exception
of AIX. We have native packages for Red Hat (community maintained by the always awesome
Matthew Kent!) and Ubuntu that ship regularly at every release. As for the Chef Server only running
on Ubuntu - that's just not true.
8) Doesn't re-invent the wheel
Again, to each their own. I think Chef's deterministic ordering, ease of integration, wider
range of actions, directly re-usable cookbooks, and lots of other things make it quite innovative.
I'm pleased to explain it to you over beer, on my dime. :)
9) Dependency Management
While I understand how you can think this would be true, it isn't. Chef does have dependency
management, and a more robust notification system then Puppet. Each resource is declarative and
idempotent. Within a recipe, resources are executed in the order they are written - meaning the
way you write it is the way it runs. This is frequently the way puppet manifests are written as
well. The difference being, there is no need to declare resource-level dependency relationships.
With Chef, you focus on recipe-level dependencies. "Apache should be working before I install
Tomcat". You can ensure that another recipe has been applied at any point, giving you great flexibility,
along with a high degree of encapsulation.
One added benefit of the way Chef works is that the system behaves the exact same way, every
time, given the same set of inputs. This greatly eases debugging of ordering issues, and results
in a system that is, in my opinion, significantly easier to reason about at scale (thousands of
resources under management).
10. Big Mindshare
There is a bit of survivor bias happening here. I meet people every day who are starting with,
or switching to, Chef. You don't, because, well - you don't use Chef.
* Conclusion
Thanks for taking the time to write about Puppet and Chef - I know your heart is in the right
place. Next time, come talk to us - we're pretty accessible guys, and I would be happy to provide
feedback and education about how Chef works. I won't even try and convince you to switch. :)
Best regards,
Adam
Puppet, Chef, cfengine, and Bcfg2 are all players in the configuration management space. If you're
looking for Linux automation solutions, or server configuration management tools, the two technologies
you're most likely to come across are Puppet and Opscode Chef. They are broadly similar in architecture
and solve the same kinds of problems. Puppet, from Reductive Labs, has been around longer, and has
a large user base. Chef, from Opscode, has learned some of the lessons from Puppet's development,
and has a high-profile client: EngineYard.You have an important choice to make: which system should
you invest in? When you build an automated infrastructure, you will likely be working with it for
some years. Once your infrastructure is already built, it's expensive to change technologies: Puppet
and Chef deployments are often large-scale, sometimes covering thousands of servers.
Chef vs. Puppet is an ongoing debate, but here are 10 advantages I believe Puppet has over Chef
today.
1. Larger installed base
Put simply, almost everyone is using Puppet rather than Chef. While Chef's web site lists
only a handful
of companies using it, Puppet's has
over
80 organisations including Google, Red Hat, Siemens, lots of big businesses worldwide, and several
major universities including Stanford and Harvard Law School.
This means Puppet is here to stay, and makes Puppet an easier sell. When people hear it's the
same technology Google use, they figure it works. Chef deployments don't have that advantage (yet).
Devops and sysadmins often look to their colleagues and counterparts in other companies for social
proof.
2. Larger developer base
Puppet is so widely used that lots of people develop for it. Puppet has many contributors to its
core source code, but it has also spawned a variety of support systems and third-party add-ons specifically
for Puppet, including Foreman. Popular
tools create their own ecosystems.
Chef's developer base is growing fast, but has some way to go to catch up to Puppet - and its
developers are necessarily less experienced at working on it, as it is a much younger project.
3. Choice of configuration languages
The
language
which Puppet uses to configure servers is designed specifically for the task: it is a domain
language optimised for the task of describing and linking resources such as users and files.
Chef uses an
extension of the Ruby language. Ruby is a good general-purpose programming language, but it is
not designed for configuration management - and learning Ruby is a lot harder than learning Puppet's
language.
Some people think that Chef's lack of a special-purpose language is an advantage. "You get the
power of Ruby for free," they argue. Unfortunately, there are many things about Ruby which aren't
so intuitive, especially for beginners, and there is a large and complex syntax that has to be mastered.
There is experimental support in Puppet for writing your manifests in a domain language embedded
in Ruby just like Chef's. So perhaps it would be better to say that Puppet gives you the choice of
using either its special-purpose language, or the general-purpose power of Ruby. I tend to agree
with
Chris Siebenmann that the problem with using general-purpose languages for configuration is that
they sacrifice clarity for power, and it's not a good trade.
4. Longer commercial track record
Puppet has been in commercial use for many years, and has been continually refined and improved.
It has been deployed into very large infrastructures (5,000+ machines) and the performance and scalability
lessons learned from these projects have fed back into Puppet's development.
Chef is still at an early stage of development. It's not mature enough for enterprise deployment,
in my view. It does not yet support as many operating systems as Puppet, so it may not even be an
option in your environment. Chef deployments do exist on multiple platforms, though, so check availability
for your OS.
5. Better documentation
Puppet has a large user-maintained wiki with hundreds of pages of
documentation
and comprehensive references for both the
language
and its
resource
types. In addition, it's actively discussed on several
mailing lists
and has a very popular
IRC
channel, so whatever your Puppet problem, it's easy to find the answer. (If you're getting started
with Puppet, you might like to check out my
Puppet tutorial
here.)
Chef's developers have understandably concentrated on getting it working, rather than writing
extensive documentation. While there are
Chef tutorials,
they're a little sketchy. There are bits and pieces scattered around, but it's hard to find the piece
of information you need.
6. Wider range of use cases
You can use both Chef and Puppet as a deployment tool. The Chef documentation seems largely aimed
at users deploying
Ruby on Rails applications, particularly in cloud environments - EngineYard is its main user
and that's what they do, and most of the tutorials have a similar focus. Chef's not limited to Rails,
but it's fair to say it's a major use case.
In contrast, Puppet is not associated with any particular language or web framework. Its users
manage Rails apps, but also PHP applications, Python and Django, Mac desktops, or
AIX mainframes running Oracle.
To make it clear, this is not a technical advantage of Puppet, but rather that its community,
documentation and usage have a broader base. Whatever you're trying to manage with Puppet, you're
likely to find that someone else has done the same and can help you.
7. More platform support
Puppet supports multiple platforms. Whether it's running on OS X or on Solaris, Puppet
knows the right package manager to use and the right commands to create resources. The Puppet server
can run on any platform which supports Ruby, and it can run on relatively old and out-of-date
OS and Ruby versions (an important consideration in many enterprise environments, which
tend to be conservative about upgrading software).
Chef supports fewer platforms than Puppet, largely because it depends on recent versions of both
Ruby and CouchDB. As with Puppet, though, the list of supported platforms is growing all the time.
Puppet and Chef can both deploy all domains of your infrastructure, provided it's on the supported
list.
8. Doesn't reinvent the wheel
Chef was strongly inspired by Puppet. It largely duplicates functionality which already existed
in Puppet - but it doesn't yet have all the capabilities of Puppet. If you're already using Puppet,
Chef doesn't really offer anything new which would make it worth switching.
Of course, Puppet itself reinvented a lot of functionality which was present in earlier generations
of config management software, such as cfengine. What goes around comes around.
9. Explicit dependency management
Some resources depend on other resources - things need to be done in a certain order for them
to work. Chef is like a shell script: things are done in the order they're written, and that's all.
But since there's no way to explicitly say that one resource depends on another, the ordering of
your resources in the code may be critical or it may not - there's no way for a reader to tell by
looking at the recipe. Consequently, refactoring and moving code around can be dangerous - just changing
the order of resources in a text file may stop things from working.
In Puppet, dependencies are always explicit, and you can reorder your resources freely in the
code without affecting the order of application. A resource in Puppet can 'listen' for changes to
things it depends on: if the Apache config changes, that can automatically trigger an Apache restart.
Conversely, resources can 'notify' other resources that may be interested in them. (Chef can do this
too, but you're not required to make these relationships explicit - and in my mind that's a bad thing,
though some people disagree. Andrew Clay Shafer has written thoughtfully on this distinction:
Puppet, Chef, Dependencies and Worldviews).
Chef fans counter that its behaviour is deterministic: the same changes will be applied in the
same order, every time. Steve Traugott and Lance Brown argue for the importance of this property
in a paper called
Why Order
Matters: Turing Equivalence in Automated Systems Administration.
10. Bigger mindshare
Though not a technical consideration, this is probably the most important. When you say 'configuration
management' to most people (at least people who know what you're talking about), the usual answer
is 'Puppet'. Puppet owns this space. I know there is a large and helpful community I can call on
for help, and even
books published on Puppet. Puppet is so widely adopted that virtually every problem you could
encounter has already been found and solved by someone.
Conclusion
Currently 'Chef vs. Puppet' is a rather unfair comparison. Many of the perceived disadvantages
of Chef that I've mentioned above are largely due to the fact that Chef is very new. Technically,
Puppet and Chef have similar capabilities, but Puppet has first mover advantage and has colonised
most corners of the configuration management world. One day Chef may catch up, but my recommendation
today is to go with Puppet.
Selected Comments
Julian Simpson:
Culture is an important reason as to why people gravitate to one tool or another. Chef will
draw in Ruby developers because it's not declarative, and because it's easy.
My experience is that most developers don't do declarative systems. Everyday languages are
imperative, and when you're a developer looking to get something deployed quickly, you're most
likely to pick the tool that suits your world view.
Systems Administrators tend to use more declarative tools (make, etc.)
Developers and Systems Administrators also have a divergent set of incentives. Developers are
generally rewarded for delivering systems quickly, and SA's are rewarded for stability. IMHO,
Chef is a tool to roll out something quickly, and Puppet is the one to manage the full lifecycle.
That's why I think Chef makes a good fit for cloud deployment because Vm instances have a short
lifespan.
I think it's still anybody's game. The opportunity for Chef is that the developer community
could build out an ecosystem very quickly.
vvuksan:
It seems to me that both system have quite a bit of support out there and it really comes down
to what you as the sysadmin/developer prefer.
I would also agree with ripienaar's tweet about disagreeing with point 6. Configuration management
systems are not really intended for deploying software but for making sure that systems conform
to a certain policy ie. webserver policy etc.
Nick Anderson:
I'm a SA and have worked closely with developers for years. It never ceased to
amaze me how differently we think. It does boil down to priorities, culture, and incentives as
Julian mentioned. I have not used Chef but I saw quite the stir the last time I mentioned puppet
Puppet Works Hard To Make Sure Nodes Are In Compliance.
I have used puppet both as a deployment tool and a configuration management tool. It really
can do both just fine as a deployment is essentially a configuration change. But I have found
it easier to use a tool like fabric
when I need to perform "actions" on a group of machines, especially when those actions are many
and very possibly one time. I have found it a bit daunting if you put too much into your configuration
management tool as over time it becomes a lot to sift through, and when its time to remove a configuration
you have to leave that part of the configuration there (the part that removes whatever it was).
Maybe I haven't looked around enough but I really want to see a puppet reporting tool. I know
bcfg2 has a decent one. I want to be able to know the current stats of my nodes, who is in compliance,
who isn't, when I last spoke with what node, last time nodex changed and what changed.
John Arundel:
It is hard to be objective - probably impossible. I'm sure I haven't been.
My background is that I've used Puppet for commercial sysadmin work for several years (basically
since it came out), and it currently manages many infrastructures for many of my clients (I'm
a freelancer). The biggest deployment I've worked on is probably 25-30 servers, and a comparable
number of desktops. Maybe 6,000 lines of manifest code (not counting templates).
When Chef was first announced, I set aside time to build a Chef server and try it out, with
a view to adopting it if it was superior to Puppet. I found it quite hard going (admittedly that
was early days for Chef), and I didn't find sufficient advantages for Chef to migrate any of my
clients to it. If a client asked for Chef specifically, I'd be quite happy to use it, but so far
no-one has.
So based on what I know, I use Puppet and that's what I recommend to others. I'm very interested
in hearing from anyone who knows different.
Anonymous
Readers, do you homework too and stop reading articles with the title 'versus', the hallmark of
propaganda. If you must read on, some specific points, with disclosure that I'm a Chef early adopter
with previous Puppet exposure.
#1, #2, #5, #7, #10: puppet is more mature than Chef
All software starts with a small install base, fewer adherents, etc. That doesn't make it more
suitable for your specific environment or taste in software development (configuration management
is development too). The answer here is to try both systems yourself and compare them - something
the author of this article seems to not have done yet. It's not just about the code, it's about the
software used to deploy it, the way it authenticates, etc. These things should also influence your
decision.
#9: Dependency management
"Chef has no support for specifying dependencies (ordering resources). Chef is like
a shell script: things are done in the order they're written, and that's all."
Chef's default behavior is to process resources in the order you write them. It has other dependency
features just like Puppet does - see below.
"A resource in Puppet can 'listen' for changes to things it depends on: if the Apache
config changes, that can automatically trigger an Apache restart. Conversely, resources can 'notify'
other resources that may be interested in them."
This has been possible in Chef for a long time. See this real world example:
http://gist.github.com/276246
http://wiki.opscode.com/display/chef/Resources - See the 'notifies' attribute in the Meta section.
#3 Dedicated configuration language
"Ruby is a good general-purpose programming language, but it is not designed for
configuration management - and learning Ruby is a lot harder than learning Puppet's language."
Sysadmins who can code can learn Ruby quickly, and there are plenty of resources on how to write
Ruby. While most of the time you can stick to the Chef style of Ruby, you have access to the power
of a mature programming language for free. If you think this language is easier, show why that would
be the case for someone who already knows at least one programming language.
I see nothing inherent in Puppet's language that makes it better suited to configuration management.
If you think there is, show some examples.
#6: Language/framework neutral
Straight up bullshit here. There is nothing in Chef specific to Ruby on Rails. All chef deployments
I know of (including our own) are used for deploying entire stacks of software totally unrelated
to Ruby or Rails, just like Puppet.
Conclusion: In the next installment, show more code examples and tell us why Chef didn't work
for you where Puppet did. Try both software packages the day before you write the article, not 6
months before. Assume your readers write code and already know that adopting less mature software
is more risky.
R.I.Pienaar:
I'd agree with almost everything above, this strikes me as mostly self promoting b/s written
with the express intend on driving traffic to a blog. Especially given the spammy nature of its
promotion.
As an aside, and I wouldn't want to distract from the fantasy here with actual facts, but Puppet
is getting native Ruby base DSL some time soon and so will please both sides of that particular
fence.
Puppet packages should be available for most major distros already. Just search for puppet
using your package manager of choice. For example, on Ubuntu 10.04 you'd want puppet
and puppet-common for the managed systems, and puppetmaster for
the central server (if you have multiple systems). You might also want the vim-puppet
package if you'll be writing Puppet manifests in Vim, or puppet-el if you want to write manifests
in GNU Emacs.When you're working with Puppet, you're working with resources. Users, packages,
files, services, etc. A resource describes something on your system. You can find the standard types
on the language resource guide
on Puppet Labs' site. Some resources are standard across all OSes (like files) others are OS-dependent
(like zfs and zone, which are Solaris-only).
For single systems, you'll usually use puppet to execute a manifest. Remember,
a manifest is a file containing a set of resources and instructions on how that resource should
be configured or manipulated.
Puppet also has a shell that you can use to execute Puppet commands and configure a local system.
The Resource Abstraction Layer Shell (ralsh) can list resources, and operate on
resources. Here's a simple example to verify whether a user exists on the system using ralsh:
ralsh user norm
If norm doesn't exist as a user account on the system yet, you'll see this:
user { 'norm':
ensure => 'absent'
}
This is Puppet providing the current system configuration, as expressed in the Puppet language.
This is how you'd write a manifest to remove the user norm from a system. What if we want
to add norm as a user with ralsh? Easy:
ralsh user norm
Ridiculously easy, isn't it? That will create norm with some sane defaults. Here's the
manifest that ralsh executes:
user { 'norm':
uid => '1001',
ensure => 'present',
gid => '1001',
home => '/home/norm',
shell => '/bin/sh'
}
You'd write that up as a manifest and run it using puppet on your local system.
What if we want to make norm's shell bash instead of sh? Let's look at that as a manifest:
user { 'norm':
uid => '1001',
ensure => 'present',
gid => '1001',
home => '/home/norm',
shell => '/bin/sh'
}
Copy that to a file, like norm.pp, and change the shell line to shell => '/bin/sh'.
Then run puppet norm.pp. Puppet will check the user, and make the changes necessary
so that the user conforms to the manifest.
So how is this easier than running the commands to create a new user on your system? On a single
system, it's not. What if you need to create the user on 20 systems, though? Much, much easier. And
this would work on Linux, Mac OS X, FreeBSD, and more.
This has been a pretty quick overview of how Puppet works on a single system. In the next tutorial,
we'll look at configuring Puppet to manage multiple systems and how to make changes across different
distros
Selected Comments
Paul Ivanov:
mudfly, the beauty of Puppet is that you build and manage system configurations, as Joe described,
which can then be realized by any machine running the puppet client (be it real or virtual).
Once you define the different configurations, you don't have to have a copy of the huge VM
images for each. In the most minimal extreme, you just need one VM that has a puppet client, and
now you can transform it into any of your configurations by changing e.g. its hostname or the
configuration provided by the puppetmaster.
It's also a lot more elegant to version control your configurations, since they are just small
text files, not the gigabytes of libraries and binaries which might even be identical from one
VM image to the next.
I tried to explain some of this
in the comments section here , that while virtual machines help you contain different
configurations, keeping track of the changes/differences between virtual machines becomes and
increasingly difficult proposition.
The Puppet way is to work on the configuration, instead of directly on the images - and have
the images conform to the configuration by running the puppet client. There are legitimate reasons
to keep around multiple images (it's faster to get up and running, disk space is cheap, etc),
but if you're using puppet, making changes to the images in "lock-step" as well as keeping track
of the resources in each image becomes a lot less painful.
April 28, 2009 | iTWire
UNIX system administrators normally use Perl, Python or shell scripts for their scripting needs;
Puppet is written in Ruby but one doesn't need to learn Ruby to use it. "You don't need to learn
Ruby to use Puppet. It's all under the covers. If you want to extend Puppet - it's quite easily extensible
- then yes, you're going to have to pick up some Ruby along the way," Turnbull clarifies.
"Our primary desire is to make it easier for sys admins to do things without every script. Luke's
very fond of saying SSH always isn't the solution. And he's quite right, because my big problem with
this is that I've worked in a number of different organisations where I've done exactly that - I've
written Perl or Python scripts or bash scripts, and numerous things, and every single organisation
almost certainly one starts from scratch.
"I have a collection of Perl and bash scripts to manage a whole lot of environments - well-maintained,
well documented. Sometimes I can't take them with me because of the organisation's IP. Puppet's an
attempt to get rid of that whole model. Instead of every shop having to start from scratch and writing
your provisioning script, or your management script, or your user management process, or setting
the root password on all of your hosts, you can do it through Puppet. It's one language, it's all
described the same way.
"There are a lot of systems administrators who don't do a lot of scripting, particularly people
who manage small- to medium-sized businesses. You may be the systems administrator but you're also
the accountant or operations manager. And you're not an IT expert - you just want a simple way of
saying, 'well, all my boxes should be up-to-date. All of my boxes need user Bob, because I'm user
Bob, and I need to assign all the boxes and they need to have the same password'.
"Puppet is designed to be a low level of entry for your average systems administrator. Other from
the domain specific language, they don't need to learn a new one, and the DSL's very simple. It contains
some programmatic concepts, like if else statements and case statements and things like that, but
broadly speaking, it's quite simple."
Turnbull says Puppet is fine for remote environments but the speed at which things get done will,
as always, depend on the available bandwidth. "A lot of ISPs use Puppet. There's nothing wrong with
having the master just sitting in Melbourne and connecting clients. We're not depending on how many
hops you have between you and your host. There'll be some performance issues. Puppet has an ability
to serve files out to hosts. If you're copying large amounts of files you can have a performance
hit there. There's also a lot of people who create a model of a centralised puppet master and child
masters, some kind of a distributed hierarchy."
I have been running my puppetmaster using the embedded WEBrick server for a while. I decided it
was time to migrate to something a little more robust – namely Apache and Passenger. I loosely followed
the documentation available on the Puppet
site, although that covers Passenger 3.0.x and I'm using 4.0.x, and the supplied Apache configuration
does not work. There were also a few other changes I had to make along the way to suit my configuration
requirements. My puppetmaster is running CentOS 6.4.
Related posts:
-
Adding Puppet DB to a CentOS 6.4-based puppetmaster
-
Implementing Git Dynamic Workflows with Puppet
-
Apache httpd: How to Use htpasswd to Password Protect Areas of your Site
-
Puppet Module: apache2: VirtualHost templates
-
Puppet Module: security::tcpwrappers with Hiera
Society
Groupthink :
Two Party System
as Polyarchy :
Corruption of Regulators :
Bureaucracies :
Understanding Micromanagers
and Control Freaks : Toxic Managers :
Harvard Mafia :
Diplomatic Communication
: Surviving a Bad Performance
Review : Insufficient Retirement Funds as
Immanent Problem of Neoliberal Regime : PseudoScience :
Who Rules America :
Neoliberalism
: The Iron
Law of Oligarchy :
Libertarian Philosophy
Quotes
War and Peace
: Skeptical
Finance : John
Kenneth Galbraith :Talleyrand :
Oscar Wilde :
Otto Von Bismarck :
Keynes :
George Carlin :
Skeptics :
Propaganda : SE
quotes : Language Design and Programming Quotes :
Random IT-related quotes :
Somerset Maugham :
Marcus Aurelius :
Kurt Vonnegut :
Eric Hoffer :
Winston Churchill :
Napoleon Bonaparte :
Ambrose Bierce :
Bernard Shaw :
Mark Twain Quotes
Bulletin:
Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient
markets hypothesis :
Political Skeptic Bulletin, 2013 :
Unemployment Bulletin, 2010 :
Vol 23, No.10
(October, 2011) An observation about corporate security departments :
Slightly Skeptical Euromaydan Chronicles, June 2014 :
Greenspan legacy bulletin, 2008 :
Vol 25, No.10 (October, 2013) Cryptolocker Trojan
(Win32/Crilock.A) :
Vol 25, No.08 (August, 2013) Cloud providers
as intelligence collection hubs :
Financial Humor Bulletin, 2010 :
Inequality Bulletin, 2009 :
Financial Humor Bulletin, 2008 :
Copyleft Problems
Bulletin, 2004 :
Financial Humor Bulletin, 2011 :
Energy Bulletin, 2010 :
Malware Protection Bulletin, 2010 : Vol 26,
No.1 (January, 2013) Object-Oriented Cult :
Political Skeptic Bulletin, 2011 :
Vol 23, No.11 (November, 2011) Softpanorama classification
of sysadmin horror stories : Vol 25, No.05
(May, 2013) Corporate bullshit as a communication method :
Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law
History:
Fifty glorious years (1950-2000):
the triumph of the US computer engineering :
Donald Knuth : TAoCP
and its Influence of Computer Science : Richard Stallman
: Linus Torvalds :
Larry Wall :
John K. Ousterhout :
CTSS : Multix OS Unix
History : Unix shell history :
VI editor :
History of pipes concept :
Solaris : MS DOS
: Programming Languages History :
PL/1 : Simula 67 :
C :
History of GCC development :
Scripting Languages :
Perl history :
OS History : Mail :
DNS : SSH
: CPU Instruction Sets :
SPARC systems 1987-2006 :
Norton Commander :
Norton Utilities :
Norton Ghost :
Frontpage history :
Malware Defense History :
GNU Screen :
OSS early history
Classic books:
The Peter
Principle : Parkinson
Law : 1984 :
The Mythical Man-Month :
How to Solve It by George Polya :
The Art of Computer Programming :
The Elements of Programming Style :
The Unix Hater’s Handbook :
The Jargon file :
The True Believer :
Programming Pearls :
The Good Soldier Svejk :
The Power Elite
Most popular humor pages:
Manifest of the Softpanorama IT Slacker Society :
Ten Commandments
of the IT Slackers Society : Computer Humor Collection
: BSD Logo Story :
The Cuckoo's Egg :
IT Slang : C++ Humor
: ARE YOU A BBS ADDICT? :
The Perl Purity Test :
Object oriented programmers of all nations
: Financial Humor :
Financial Humor Bulletin,
2008 : Financial
Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related
Humor : Programming Language Humor :
Goldman Sachs related humor :
Greenspan humor : C Humor :
Scripting Humor :
Real Programmers Humor :
Web Humor : GPL-related Humor
: OFM Humor :
Politically Incorrect Humor :
IDS Humor :
"Linux Sucks" Humor : Russian
Musical Humor : Best Russian Programmer
Humor : Microsoft plans to buy Catholic Church
: Richard Stallman Related Humor :
Admin Humor : Perl-related
Humor : Linus Torvalds Related
humor : PseudoScience Related Humor :
Networking Humor :
Shell Humor :
Financial Humor Bulletin,
2011 : Financial
Humor Bulletin, 2012 :
Financial Humor Bulletin,
2013 : Java Humor : Software
Engineering Humor : Sun Solaris Related Humor :
Education Humor : IBM
Humor : Assembler-related Humor :
VIM Humor : Computer
Viruses Humor : Bright tomorrow is rescheduled
to a day after tomorrow : Classic Computer
Humor
The Last but not Least Technology is dominated by
two types of people: those who understand what they do not manage and those who manage what they do not understand ~Archibald Putt.
Ph.D
Copyright © 1996-2021 by Softpanorama Society. www.softpanorama.org
was initially created as a service to the (now defunct) UN Sustainable Development Networking Programme (SDNP)
without any remuneration. This document is an industrial compilation designed and created exclusively
for educational use and is distributed under the Softpanorama Content License.
Original materials copyright belong
to respective owners. Quotes are made for educational purposes only
in compliance with the fair use doctrine.
FAIR USE NOTICE This site contains
copyrighted material the use of which has not always been specifically
authorized by the copyright owner. We are making such material available
to advance understanding of computer science, IT technology, economic, scientific, and social
issues. We believe this constitutes a 'fair use' of any such
copyrighted material as provided by section 107 of the US Copyright Law according to which
such material can be distributed without profit exclusively for research and educational purposes.
This is a Spartan WHYFF (We Help You For Free)
site written by people for whom English is not a native language. Grammar and spelling errors should
be expected. The site contain some broken links as it develops like a living tree...
Disclaimer:
The statements, views and opinions presented on this web page are those of the author (or
referenced source) and are
not endorsed by, nor do they necessarily reflect, the opinions of the Softpanorama society. We do not warrant the correctness
of the information provided or its fitness for any purpose. The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be
tracked by Google please disable Javascript for this site. This site is perfectly usable without
Javascript.
Last modified: March 12, 2019