Where I am working at the moment, we have to manage the Linux portion of our server farm which is just over 300 Linux servers. This includes mostly HP Proliants, followed by IBM 3850s, some IBM blades, VMware ESX, and some KVM for our internal management servers.
We looked at cobbler but the problem there was that cobbler is very RHEL/Red Hat specific. We need to support RHEL and SLES at the least, and Ubuntu is next.
We did consider puppet, however later decided against it as it depends on Ruby, which means that an upgrade of Ruby, could potentially break our management system.
Hotwire is what we use (developed internally, but is open-source), and have done so for the last few years. It firstly inventories the systems that are going to be built, which means inventorying the data-center, rack, hardware, operating system, network, etc, and secondly perform the rapid build & deploy. Once the system is built, hotwire's auto-inventory keeps the inventory in-sync, while cfengine maintains them. Hotwire knows about the server hardware by talking to the SMBIOS/DMI data in the Bios via python-dmidecode.
The bonus points are that it is combines the inventory and build process into one, so there's less to manage, and the live-inventory feature is great as we know if something is not quite right.
The disadvantages are that the user-interface still needs polishing, and there are bugs here and there, but development is still hot, and bugs reported are fixed relatively fast.
We use cfengine because other than it, and puppet, there is nothing else. It actually is a good tool, but "good" only as a function of how good your policies are - if you set dangerous policies, then a small mistake can cause alot of damage. For example, by policy, we don't "modify" files, we either replace them, or we don't. Also all files replaced have a header that makes any person editing it know that it will be replaced the next time it runs (it is run via cron hourly).
The configuration and all files pushed out by cfengine to the servers are also kept in a SCM, and using post-commit hooks, where possible, we check the syntax and if that fails, then the commit is rejected. This is easy for nice applications such as Apache, but not so easy for most enterprise applications.