I finally got my cfengine configs all objectified and separated into service-based configurations. But there are still many things that cfe can''t or won''t do very well, so I''m looking for a replacement. What about puppet? I am looking for something that I can use to manage services and applications, not hosts and files. It seems like puppet may have inherited some of cfe''s design limitations in this regard; but because puppet is much more extensible I may be able to make it do what I want it to. So here are my questions: can puppet... Do a find/replace within a flat file and trigger an action if the change was successful? Can it do that on a file and trigger an action if the changed file is different from the file that already exists on the system? I manage a variety of Linux and FreeBSD hosts, how smart is puppet about the differences between these systems? For instance, can I tell it to "install a file to the ''bin'' directory" or do I first have to do some kind of "if system=freebsd; bin=/usr/local/bin; elsif system...." With cfe I check out my configuration from an svn repository and cfe executes that configuration on each host; I would want to do something similar with puppet but I''m not sure how the client/server architecture would work in this way. My ultimate goal is to be able to assign a service to a host and let puppet build and install the application auto-magically. (I know this is Luke''s stated goal for puppet, but I wondering how well it works in practice; and if anybody has done any work to make it os independent.) -- -- Perfection is just a word I use occasionally with mustard. --Atom Powers--
On Wed, Mar 07, 2007 at 06:12:49PM -0800, Atom Powers wrote:> I finally got my cfengine configs all objectified and separated into > service-based configurations. But there are still many things that cfe > can''t or won''t do very well, so I''m looking for a replacement. What > about puppet? > > I am looking for something that I can use to manage services and > applications, not hosts and files.You''ve come to the right place!> So here are my questions: can puppet... > Do a find/replace within a flat file and trigger an action if the > change was successful?You can''t do find and replace at the moment without writing an extension. The main reason being that it''d be preferable to write a native puppet type that has an understanding of what the configuration changes mean on some level. Eg: So instead of talking of adding a line to a file, you could mean "enabling a service in rc.conf" for a NetBSD system, or adding a configuration element to a java property file. This sometimes then gets abstracted into various providers. Eg: you can specify that you want to install a certain package, and puppet will figure out how to do it based on what it knows about the platform it''s running on.> Can it do that on a file and trigger an action if the changed file is > different from the file that already exists on the system?With the caveats specified above, you can have another object (B) subscribe to another object (A), so that when A changes, B is refreshed. That might mean re-starting a service, or running a command, for example.> I manage a variety of Linux and FreeBSD hosts, how smart is puppet > about the differences between these systems? For instance, can I tell > it to "install a file to the ''bin'' directory" or do I first have to do > some kind of "if system=freebsd; bin=/usr/local/bin; elsif system...."If you need to do somethign that low level, you could use conditionals based on the operating system fact: case $operatingsystem { CentOS: { $bindir = "/usr/bin" } FreeBSD: { $bindir = "/usr/local/bin" } } exec { "/bin/echo > /dev/tty ''$bindir''": } Personally, I just prefer to create a package, add that to a repository and say: package { magicthing: ensure => present }> > With cfe I check out my configuration from an svn repository and cfe > executes that configuration on each host; I would want to do something > similar with puppet but I''m not sure how the client/server > architecture would work in this way.You''d check out your configuration onto the puppet master server, and then let puppetmasterd serve the compiled configuration to each client.> My ultimate goal is to be able to assign a service to a host and let > puppet build and install the application auto-magically. (I know this > is Luke''s stated goal for puppet, but I wondering how well it works in > practice; and if anybody has done any work to make it os independent.)I''ve done this at work to build an application tower from a base kickstart install to a production-ready server, and it works beautifully. We''ve not had to make it os-indepedent, but I don''t think that it''d be too hard. If you''ve alredy got the other infrastucture in place (eg: a build system for packages) then that''s half of the battle already won. -- Ceri Storey <cez@necrofish.org.uk> ''What I really want is "apt-get smite"'' --Rob Partington http://unix.culti.st/
On Thu, Mar 08, 2007 at 10:02:06PM +0000, Ceri Storey wrote:> You can''t do find and replace at the moment without writing an > extension.Either that, or some shell nastiness. There are a few examples on the wiki (when Luke vanquishes the evil demons of Trac crashyness), and some in PRMweb: http://prmweb.hezmatt.org/ . -- Ceri Storey <cez@necrofish.org.uk> ''What I really want is "apt-get smite"'' --Rob Partington http://unix.culti.st/
On 3/8/07, Ceri Storey <cez@necrofish.org.uk> wrote:> On Wed, Mar 07, 2007 at 06:12:49PM -0800, Atom Powers wrote: > > > So here are my questions: can puppet... > > Do a find/replace within a flat file and trigger an action if the > > change was successful? > > You can''t do find and replace at the moment without writing an > extension. The main reason being that it''d be preferable to write a > native puppet type that has an understanding of what the configuration > changes mean on some level. Eg: So instead of talking of adding a line > to a file, you could mean "enabling a service in rc.conf" for a NetBSD > system, or adding a configuration element to a java property file. >That''s great. But I don''t see the puppet types to do any of that. These are things that you can''t do with templating and you shouldn''t do by keeping multiple versions of the same file. I need a type that will: Given "file", "setting", and "value", 1. search "file" for instances of "setting =" (or "setting:" for groups and aliases) 2. add "setting = value" if "setting =" doesn''t exist. 3. correct "value" if "setting =" exists but has the incorrect "value" Which is pretty universal to most config files (with some obvious exceptions) and seems to me to be a pretty basic requirement of a configuration manager. ( I think it would need to be able to work on blocks of data to, but I''m not sure how that would work and it isn''t a pressing need for me right now. ) I''m sure I could write the types myself (as soon as I learn Ruby) but I''m surprised such a thing doesn''t already exist. In addition to the basic "setting = value" type, I would need types for: syslog crontab inetd passwd and probably several others> > > > With cfe I check out my configuration from an svn repository and cfe > > executes that configuration on each host; I would want to do something > > similar with puppet but I''m not sure how the client/server > > architecture would work in this way. > > You''d check out your configuration onto the puppet master server, and > then let puppetmasterd serve the compiled configuration to each client. >What if the puppet master is down or unavailable? Would all the puppet hosts stop updating? I really like the peer model, where each host checks out and enforces the configuration for itself. It''s distributed, so the number of hosts you are working with really doesn''t matter, and you are not relying on the availability of any single server to keep all the other systems correct. Central logging should be a different service separate from enforcing the configuration. -- -- Perfection is just a word I use occasionally with mustard. --Atom Powers--
On Fri, Mar 09, 2007 at 09:33:32AM -0800, Atom Powers wrote:> I''m sure I could write the types myself (as soon as I learn Ruby) but prised > I''m sursuch a thing doesn''t already exist.It''s mostly a case of people having time to do it, really.> In addition to the basic "setting = value" type, I would need types for:> crontabAlready present. > passwd There''s a user type, which would suffice.> and probably several others > You''d check out your configuration onto the > puppet master server, and > then let puppetmasterd serve the compiled > configuration to each client. > > What if the puppet master is down or unavailable? Would all the puppet hosts > stop updating?Well, if the master isn''t there to serve the configuration, how is a client to know that the configuration is updated?> I really like the peer model, where each host checks out and enforces the > configuration for itself.I''d call that the "smart client" model myself. Or do you mean it''s a mesh model, where each client copies configuration from it''s peers?> It''s distributed, so the number of hosts you are working with really doesn''t > matter, and you are not relying on the availability of any single server to > keep all the other systems correct. Central logging should be a different > service separate from enforcing the configuration.Maybe so, but all puppet really provides are deltas to the configuration, in a sense. So if the puppetmaster fails, the machines will, of course, still work. I do see your point, though. Having no single point of failure would be nice, but with a pure peer to peer model you''d then need a decent trust verification mechanism on top of that to verify that the configuration is authentic and trusted. It''s also harder to ensure that all clients are in sync, unless, as you say, you''ve got decent logging in place. Admittedly, most of that is my own opinion :) Currently, the way that the server operates is to compile a configuration tailored for each individudal client, hence each client doesn''t have knowledge of how it''s neighbours should be configured. Admittedly, a dump of the full configuration would be useful for replication. Cheers! -- Ceri Storey <cez@necrofish.org.uk> ''What I really want is "apt-get smite"'' --Rob Partington http://unix.culti.st/
Let me describe what I''m trying to do here in a little more detail. Here''s my vision: 1. I assign a service to a host (such as "mail relay", "imap server", "staff web server", "students'' web server", "ldap server", "ldap-client", "samba PDC", "samba BDC", etc). 2. next time the configuration management app runs it applies a manifest to the host based on the services assigned to that host. Obviously a single host can have multiple services. 3. the manifest installs the applications and configures the system to use that application, without clobbering the configuration of the other services on that host. 3a. this usually means adding service enabling lines to rc.conf, creating users, setting file acls, creating syslog.conf and newsyslog.conf entries, installing configuration files, modifying those configuration files depending on what subnet this host is on, and making adjustments to configuration files depending on how this particular instance of this service is defined. So although, in the end, I really don''t want to muck around with such low-level stuff as "add ''setting = value'' to file-X", I need to be able to do that in order to write the service manifests in the first place and maintain them afterwards. I imagine, and hope, that these service manifests can be made general and specific enough to share with other people. When configuring a host is as simple as assigning a service to it, yet powerful enough that you can choose exactly how that service is configured, maybe my "job security" will disappear and I can retire happy. On 3/9/07, Atom Powers <atom.powers@gmail.com> wrote:> I need a type that will: > Given "file", "setting", and "value", > 1. search "file" for instances of "setting =" (or "setting:" for > groups and aliases) > 2. add "setting = value" if "setting =" doesn''t exist. > 3. correct "value" if "setting =" exists but has the incorrect "value" > > Which is pretty universal to most config files (with some obvious > exceptions) and seems to me to be a pretty basic requirement of a > configuration manager. ( I think it would need to be able to work on > blocks of data to, but I''m not sure how that would work and it isn''t a > pressing need for me right now. ) > > I''m sure I could write the types myself (as soon as I learn Ruby) but > I''m surprised such a thing doesn''t already exist. > > In addition to the basic "setting = value" type, I would need types for: > syslog > crontab > inetd > passwd > and probably several others >-- -- Perfection is just a word I use occasionally with mustard. --Atom Powers--
On Mar 9, 2007, at 12:03 PM, Atom Powers wrote:> 3a. this usually means adding service enabling lines to rc.conf, > creating users, setting file acls, creating syslog.conf and > newsyslog.conf entries, installing configuration files, modifying > those configuration files depending on what subnet this host is on, > and making adjustments to configuration files depending on how this > particular instance of this service is defined.Very few of these should actually be modeled as simple ''set value X to Y''. Modifications to rc.conf should be considered "enabling" the service, which the service should directly support. Creation of users and file acls should be treated as separate resources. Modification of syslog.conf should be treated as a separate resource, also -- some kind of logging resource or something. As to modifying your configuration files per subnet or whatever, yeah, there are definitely cases where you''ll need to do that. However, I think you''ll find that the vast majority of times where that''s necessary, Puppet''s templating is perfectly sufficient. No, I don''t all claim it''s perfect, and yes, it definitely requires remodeling how you manage systems, but it ends up being a more sensible model for most cases, and it even draws out better tools. For instance, standard syslog is pretty tough to manage at all, using Puppet or not, but if you switch to syslog-ng, it''d be very easy to write a Puppet type that knows how to manage that, because it''s just a more manageable configuration file.> I imagine, and hope, that these service manifests can be made general > and specific enough to share with other people. When configuring a > host is as simple as assigning a service to it, yet powerful enough > that you can choose exactly how that service is configured, maybe my > "job security" will disappear and I can retire happy.Many people are using Puppet in the exact way you describe, although I''m sorry to say if you get to this point you''ll become a dreaded "expert", and your services will be in more demand than ever. :) -- Charm is a way of getting the answer yes without asking a clear question. -- Albert Camus --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
On Mar 9, 2007, at 11:33 AM, Atom Powers wrote:> That''s great. But I don''t see the puppet types to do any of that. > These are things that you can''t do with templating and you shouldn''t > do by keeping multiple versions of the same file. > > I need a type that will: > Given "file", "setting", and "value", > 1. search "file" for instances of "setting =" (or "setting:" for > groups and aliases) > 2. add "setting = value" if "setting =" doesn''t exist. > 3. correct "value" if "setting =" exists but has the incorrect "value"You don''t actually care about that, you only think you do because the stupid software you''re using forces you to think about things this way. You want a specific behaviour, from one or more resources. This behaviour is determined by one or more configuration files. You need the configuration files to contain the necessary information to result in the behaviour you want. Everything else is green-field and can be done however makes the most sense. The majority of the work involved in managing systems involves one or more instances of a common resource type, like packages, users, groups, hosts (as in /etc/hosts), interfaces, mount points, etc. The majority of what''s left are per-service configuration files with little or no modeling. Whatever''s left is going to be difficult no matter what you do. For instance, take the postfix configuration file main.conf. There''s no real model to it; it''s a list of a whole bunch of parameters, probably in a specific order. This is always going to be difficult to manage, but you''re never going to have that many varieties of this file, at least in basic form. Templates are perfectly sufficient for this case. If you don''t want to use templates because you only care about one or two lines (which, IMO, is pretty dangerous) then you can easily hack it using exec. But you have to realize that that''s a hack, and while Puppet will allow you those hacks, it will never encourage promotion of hacks to first-class types. For another example, you can consider your entire apache configuration to be one, nasty, monolithic configuration file, but that will make it essentially impossible to manage. If you instead remodel it, like Debian has done for apache2, you can think of parts of it as resources -- modules, virtual hosts, and maybe a few others -- and model them easily that way. The rest of it becomes *much* smaller and now either doesn''t need to be managed, because you can use the default configuration, or can be managed easily using templates.> > I''m sure I could write the types myself (as soon as I learn Ruby) but > I''m surprised such a thing doesn''t already exist.It does, just not using the model you''ve provided.> In addition to the basic "setting = value" type, I would need types > for: > syslog > crontab > inetd > passwd > and probably several othersI''ve got cron and user management, and I, too, am surprised no one has asked for inetd support.> What if the puppet master is down or unavailable? Would all the puppet > hosts stop updating?If you run with a central master, yes. Of course, Puppet is just xmlrpc over https, so you can easily provide load-balancing and failover.> I really like the peer model, where each host checks out and enforces > the configuration for itself. It''s distributed, so the number of hosts > you are working with really doesn''t matter, and you are not relying on > the availability of any single server to keep all the other systems > correct. Central logging should be a different service separate from > enforcing the configuration.You can use Puppet this way; just use the ''puppet'' executable instead of ''puppetd''. Of course, then every host will have a copy of every other host''s configuration, and you won''t be able to do any extra- informative processing on the server (which, admittedly, is still experimental, but will be very important in the future of Puppet). -- True Terror is to wake up one morning and discover that your high school class is running the country. -- Kurt Vonnegut --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Friday 09 March 2007 19:03, Atom Powers wrote:> Let me describe what I''m trying to do here in a little more detail. > Here''s my vision: > > 1. I assign a service to a host (such as "mail relay", "imap server", > "staff web server", "students'' web server", "ldap server", > "ldap-client", "samba PDC", "samba BDC", etc).Realize these "services" as classes. See https://reductivelabs.com/trac/puppet/wiki/LanguageStructures#ServerClasses> 2. next time the configuration management app runs it applies a > manifest to the host based on the services assigned to that host. > Obviously a single host can have multiple services.Read all about puppetd at https://reductivelabs.com/trac/puppet/wiki/PuppetExecutables#puppetd and the configuration reference of at http://reductivelabs.com/projects/puppet/reference/configref.html> 3. the manifest installs the applications and configures the system to > use that application, without clobbering the configuration of the > other services on that host.That currently - and in the foreseeable future - hinges on the aptness of the manifest writer.> 3a. this usually means adding service enabling lines to rc.conf, > creating users, setting file acls, creating syslog.conf and > newsyslog.conf entries, installing configuration files, modifying > those configuration files depending on what subnet this host is on, > and making adjustments to configuration files depending on how this > particular instance of this service is defined.http://reductivelabs.com/projects/puppet/reference/typedocs.html describes the basic building blocks puppet provides. Group these within components (https://reductivelabs.com/trac/puppet/wiki/LanguageStructures#Components) to create blocks of increasing complexity. Read https://reductivelabs.com/trac/puppet/wiki/LanguageStructures#Classesvs.Components to understand the difference between classes and components.> So although, in the end, I really don''t want to muck around with such > low-level stuff as "add ''setting = value'' to file-X", I need to be > able to do that in order to write the service manifests in the first > place and maintain them afterwards.You can use recipies like https://reductivelabs.com/trac/puppet/wiki/SimpleTextRecipes for many non-natively supported formats. Often software provides ways to add/modify configuration by dropping configuration snippets into a specific directory. These mechanisms enable easier management by puppet. As already mentioned, native support of individual configuration formats depends on creating implementations which can handle the subtleties of the respective format. See http://mail.madstop.com/pipermail/puppet-dev/2007-February/003075.html for an example doing that for mysql''s server configuration.> I imagine, and hope, that these service manifests can be made general > and specific enough to share with other people. When configuring a > host is as simple as assigning a service to it, yet powerful enough > that you can choose exactly how that service is configured, maybe my > "job security" will disappear and I can retire happy.Welcome to the club :) For preliminary work on implementing really redistributable modules see David Lutterkort''s patches described at http://reductivelabs.com/trac/puppet/wiki/ModuleOrganisation and sent for discussion in the thread starting at http://mail.madstop.com/pipermail/puppet-dev/2007-March/003182.html Regards, David - -- - - hallo... wie gehts heute? - - *hust* gut *rotz* *keuch* - - gott sei dank kommunizieren wir über ein septisches medium ;) -- Matthias Leeb, Uni f. angewandte Kunst, 2005-02-15 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFF8aeW/Pp1N6Uzh0URAoXuAJ4ihzdTp4qgJcgDC9GB0r8UB16xVgCfYJwM 8FFjcz8NSSRr64vhG9Sc26U=52tt -----END PGP SIGNATURE-----
On Mar 7, 2007, at 8:12 PM, Atom Powers wrote:> > I manage a variety of Linux and FreeBSD hosts, how smart is puppet > about the differences between these systems? For instance, can I tell > it to "install a file to the ''bin'' directory" or do I first have to do > some kind of "if system=freebsd; bin=/usr/local/bin; elsif system...."Puppet''s resources are built to be os-independent. The resources usually have different providers for different operating systems or applications; e.g., there are providers for 18 different package managers, and Puppet''s pretty good about choosing the correct package manager for your particular OS. Beyond resources, though, Puppet doesn''t have any extra OS knowledge, but it does make it pretty easy to specify this kind of thing. E.g., there''s a "selector" structure for this kind of decision: $bin = $operatingsystem ? { freebsd => "/usr/local/bin", default => "/usr/bin" } I''d be surprised if you needed to do this, though. If you''re installing files into the bin directory, you should either use a package, or you should have a separate bin directory you can manage entirely and consistently. The problems you *will* run into, though, are things like service names. The ssh service is named differently on almost every platform in the world, somehow. Puppet allows every resource to have both a name (used on the individual platform) and a title (used to refer to the resource), so you can easily specify relationships using the title and not have to use variables or repeating case statements: file { "/etc/ssh": source => "...", recurse => true, notify => Service[ssh] } service { ssh: name => $operatingsystem ? { debian => sshd, solaris => openssh, default => ssh }, ensure => running } You put your complicated os-independence selector in one place, and then you pick a second name that you then use everywhere else in your configuration. Enjoy doing that with cfengine. :)> My ultimate goal is to be able to assign a service to a host and let > puppet build and install the application auto-magically. (I know this > is Luke''s stated goal for puppet, but I wondering how well it works in > practice; and if anybody has done any work to make it os independent.)Considering that I developed Puppet after years of using Cfengine, I expect you''ll find os-independence drastically easier with Puppet than with Cfengine. Most resources are already os-independent, and for those cases where you need more, Puppet does what it can to help. -- Life is too short for traffic. --Dan Bellack --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
On 3/9/07, Luke Kanies <luke@madstop.com> wrote:> On Mar 9, 2007, at 11:33 AM, Atom Powers wrote: > > That''s great. But I don''t see the puppet types to do any of that. > > These are things that you can''t do with templating and you shouldn''t > > do by keeping multiple versions of the same file. > > > > I need a type that will: > > Given "file", "setting", and "value", > > 1. search "file" for instances of "setting =" (or "setting:" for > > groups and aliases) > > 2. add "setting = value" if "setting =" doesn''t exist. > > 3. correct "value" if "setting =" exists but has the incorrect "value" > > You don''t actually care about that, you only think you do because the > stupid software you''re using forces you to think about things this way.Your right, I don''t care about that. But right now I don''t know any other way to do it.> You want a specific behaviour, from one or more resources. This > behaviour is determined by one or more configuration files. You need > the configuration files to contain the necessary information to > result in the behaviour you want. Everything else is green-field and > can be done however makes the most sense.Snakes live in green fields. I want my hosts to be paved and fenced, with nothing I don''t know about hiding in the grass. That means I need the configuration files to contain what is necessary and ONLY what is necessary.> The majority of the work involved in managing systems involves one or > more instances of a common resource type, like packages, users, > groups, hosts (as in /etc/hosts), interfaces, mount points, etc. The > majority of what''s left are per-service configuration files with > little or no modeling. Whatever''s left is going to be difficult no > matter what you do. > > For instance, take the postfix configuration file main.conf. There''s > no real model to it; it''s a list of a whole bunch of parameters, > probably in a specific order. This is always going to be difficult > to manage, but you''re never going to have that many varieties of this > file, at least in basic form. Templates are perfectly sufficient for > this case. If you don''t want to use templates because you only care > about one or two lines (which, IMO, is pretty dangerous) then you can > easily hack it using exec. But you have to realize that that''s a > hack, and while Puppet will allow you those hacks, it will never > encourage promotion of hacks to first-class types.I currently have two varieties of my postfix main.cf file, one for mx relays and one for the imap server. Pretty soon I''m going to have two more varieties for a new subdomain. Each one has only two or three lines different but templating should be the correct answer to this problem, even if I have to rewrite the template and all the manifests every time I need to keep different values a new setting. Here''s a couple of example of when templating may be insufficient for the task: In order to make sure I don''t have any unknown and unwanted services enabled I constantly rebuild the rc.conf file. I start with a template of universal settings, add network interface configuration, then in each services manifest add a line or few to enable that service. The file can be very short or very long depending on how many services are enabled on that host. I have one openldap master server and many slave servers. The configuration is almost exactly the same for all slave servers, but the master server has a few key differences. I currently send a template out to all the slave servers, making a single adjustment to one line in the file; but the master server needs about five lines added and ten lines removed. I could template those changes, but then the slave servers are reconfiguring a lot more of the file than is really necessary. Even with a template I would need to manage blocks of data, with specific edits within each block. My syslog is built similarly to my rc.conf, except that some services share the same log facility, so I can''t just build the file and append lines for each service. I need to be able to modify a line after it was added in order to enable different kinds of logging.> For another example, you can consider your entire apache > configuration to be one, nasty, monolithic configuration file, but > that will make it essentially impossible to manage. If you instead > remodel it, like Debian has done for apache2, you can think of parts > of it as resources -- modules, virtual hosts, and maybe a few others > -- and model them easily that way. The rest of it becomes *much* > smaller and now either doesn''t need to be managed, because you can > use the default configuration, or can be managed easily using templates.My apache config is realized very similarly to my rc.conf: I have a template and then I append various "include" lines for the specific web services. There can be 0 or more includes.> > > > I''m sure I could write the types myself (as soon as I learn Ruby) but > > I''m surprised such a thing doesn''t already exist. > > It does, just not using the model you''ve provided.Then I need to learn new models.> > In addition to the basic "setting = value" type, I would need types > > for: > > syslog > > crontab > > inetd > > passwd > > and probably several others > > I''ve got cron and user management, and I, too, am surprised no one > has asked for inetd support.Doesn''t cron, and wouldn''t most other types use a "setting = value" find/replace/edit mechanism internally? Wouldn''t it be easier to create new types if a common "setting=value: find/replace/edit" method wan available? As we said before, I really don''t want to use that method, but I don''t see a way around it right now. But of course I am still learning about the templating engine; so if what I describe above is possible ... then nevermind. But I need to find out if it is possible, or if there is a better way, before I commit too much energy into puppet or any other tool. My dream is to get to the point where, even if a service goes down at 2am, I can get a full nights sleep. That probably means having a configuration engine smart enough to recognize when a service goes down and be able to reconfigure another host to take over serving that service, and reconfigure the network so that it recognizes that the service has moved. -- -- Perfection is just a word I use occasionally with mustard. --Atom Powers--
On Mar 9, 2007, at 1:24 PM, Atom Powers wrote:>> >> You don''t actually care about that, you only think you do because the >> stupid software you''re using forces you to think about things this >> way. > > Your right, I don''t care about that. But right now I don''t know any > other way to do it.Hopefully we can help with that. :)>> You want a specific behaviour, from one or more resources. This >> behaviour is determined by one or more configuration files. You need >> the configuration files to contain the necessary information to >> result in the behaviour you want. Everything else is green-field and >> can be done however makes the most sense. > > Snakes live in green fields. I want my hosts to be paved and fenced, > with nothing I don''t know about hiding in the grass. That means I need > the configuration files to contain what is necessary and ONLY what is > necessary.At least you have the opportunity for that paving and fencing. My point is that it''s limiting to focus on the configuration files, and if you focus instead on behaviour, then your life will be easier. Of course you''ll still want full control, I''d expect that.> I currently have two varieties of my postfix main.cf file, one for mx > relays and one for the imap server. Pretty soon I''m going to have two > more varieties for a new subdomain. Each one has only two or three > lines different but templating should be the correct answer to this > problem, even if I have to rewrite the template and all the manifests > every time I need to keep different values a new setting. > > Here''s a couple of example of when templating may be insufficient > for the task: > > In order to make sure I don''t have any unknown and unwanted services > enabled I constantly rebuild the rc.conf file. I start with a template > of universal settings, add network interface configuration, then in > each services manifest add a line or few to enable that service. The > file can be very short or very long depending on how many services are > enabled on that host.rc.conf is a great example of an unmanageable file. It has too many types of information for too many applications, and it''s a shell script instead of a data file so you can never depend on parsing it. If your goal is to manage rc.conf, I highly recommend reorganizing it into multiple, separate files, and then file a bug against your distribution because that file is so unmanageable. I expect you''re using FreeBSD, and if so, I think you can expect many situations like this, where most of the world has chosen a far more manageable solution but FreeBSD has stuck with a solution that''s easier for one person managing a single machine, at the cost of being able to manage many machines easily.> I have one openldap master server and many slave servers. The > configuration is almost exactly the same for all slave servers, but > the master server has a few key differences. I currently send a > template out to all the slave servers, making a single adjustment to > one line in the file; but the master server needs about five lines > added and ten lines removed. I could template those changes, but then > the slave servers are reconfiguring a lot more of the file than is > really necessary. Even with a template I would need to manage blocks > of data, with specific edits within each block.That''s all pretty easy, still, I''d think. And again, if you''re talking about configuring rc.conf, the problem here is that you''ve chosen a platform that starts out difficult to manage. That''s clearly your decision, but it does mean you''re always going to struggle to automate your systems. If you either picked a more manageable platform, or just gave up on using the standard file organization and rewrote things to be more manageable, you''d be better off.> My syslog is built similarly to my rc.conf, except that some services > share the same log facility, so I can''t just build the file and append > lines for each service. I need to be able to modify a line after it > was added in order to enable different kinds of logging.That''s a question of remodeling the configuration file. I don''t think anyone is doing this yet in Puppet, but it shouldn''t be too difficult to come up with a decent model. I still recommend syslog- ng over normal syslog, but you''ll still need to spend some extra effort on the config file.> My apache config is realized very similarly to my rc.conf: I have a > template and then I append various "include" lines for the specific > web services. There can be 0 or more includes.I highly recommend looking into how Debian does it. It doesn''t require you to recompile Apache or anything, it''s just how you organize the configuration file, and it''s much easier to manage.>> I''ve got cron and user management, and I, too, am surprised no one >> has asked for inetd support. > > Doesn''t cron, and wouldn''t most other types use a "setting = value" > find/replace/edit mechanism internally? Wouldn''t it be easier to > create new types if a common "setting=value: find/replace/edit" method > wan available?Cron doesn''t use that kind of format internally, and it''s painfully difficult to manage, unfortunately. It might be easier to add new types if there were a simple base class available, but far more configuration files have a unique format than you would like to believe. Even for those that do have a common format, they often support a huge number of parameters, and the entire file counts as one record, rather than the file being semantically separate records, like cron tabs are.> As we said before, I really don''t want to use that method, but I don''t > see a way around it right now. But of course I am still learning about > the templating engine; so if what I describe above is possible ... > then nevermind. But I need to find out if it is possible, or if there > is a better way, before I commit too much energy into puppet or any > other tool.I''m assuming it''s not an option to switch to a sysV-style platform, or something like Solaris that''s actually trying to make the platform more manageable. Assuming that, you''re always going to have trouble unless you''re willing to pretty much entirely rethink these important configuration files. E.g., if you take all of the data out of rc.conf and put application-specific data into separate files, restricting rc.conf to just loading those files, then your life will be easier and Puppet''s templating will trivially do what you want. If you don''t want to do that, though, then it''s going to be pretty difficult.> My dream is to get to the point where, even if a service goes down at > 2am, I can get a full nights sleep. That probably means having a > configuration engine smart enough to recognize when a service goes > down and be able to reconfigure another host to take over serving that > service, and reconfigure the network so that it recognizes that the > service has moved.Many share that dream, but it''s far beyond the scope of any existing set of tools, much less a single tool like Puppet. If I had many full-time developers working on this space, I''d hope I could realistically attack that problem in 5 years or so. Until then, we''re stuck with humans doing most of the work, still, but hopefully with Puppet you can focus on the problem and not worry so much about how to get the bits to the disks. -- The first time I see a jogger smiling, I''ll consider it. --Joan Rivers --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
On 3/11/07, Luke Kanies <luke@madstop.com> wrote:> On Mar 9, 2007, at 1:24 PM, Atom Powers wrote: > > > > In order to make sure I don''t have any unknown and unwanted services > > enabled I constantly rebuild the rc.conf file. I start with a template > > of universal settings, add network interface configuration, then in > > each services manifest add a line or few to enable that service. The > > file can be very short or very long depending on how many services are > > enabled on that host. > > rc.conf is a great example of an unmanageable file. It has too many > types of information for too many applications, and it''s a shell > script instead of a data file so you can never depend on parsing it. > If your goal is to manage rc.conf, I highly recommend reorganizing it > into multiple, separate files, and then file a bug against your > distribution because that file is so unmanageable. I expect you''re > using FreeBSD, and if so, I think you can expect many situations like > this, where most of the world has chosen a far more manageable > solution but FreeBSD has stuck with a solution that''s easier for one > person managing a single machine, at the cost of being able to manage > many machines easily.You are thinking of the rc.d script. And I think you misunderstand the rc.d framework, which is much more manageable than the init.d framework. rc.conf has, only, un-ordered setting=value pairs, like "ntpd_enable=yes" and "ntpd_conf=/usr/local/etc/ntp.conf" When rc.d starts a service via an /etc/rc.d script it reads rc.conf for the settings that affect the application execution environment. So all your application start/stop/restart settings are in one place, you only have to manage one file and you don''t have to manage any of the scripting that is inside the service start script. The structure and purpose of rc.conf is a design decision, not a bug. I fail to see how managing setting=value pairs in rc.conf is technically more difficult than managing application specific configuration scripts; and perhaps more to the point, how applications configuration scripts make a system easier to manage than rc.conf. Especially when System-V run scripts must be ordered; rc.d scrips manage the ordering automatically with "provide" and "require" lines in each script. Unless by "a far more manageable solution" you are talking about OS X''s launchd or Solaris'' smf framework. But Linux doesn''t have those and the distinction there really isn''t in BSD style vs System-V style. I would love to have something like those to play with but OS X has made some very bizarre design decisions and OpenSolaris just doesn''t have the application support I need. ( If I recall, RedHat has another kind of process manager, but it still uses the init.d framework.)> > I have one openldap master server and many slave servers. The > > configuration is almost exactly the same for all slave servers, but > > the master server has a few key differences. I currently send a > > template out to all the slave servers, making a single adjustment to > > one line in the file; but the master server needs about five lines > > added and ten lines removed. I could template those changes, but then > > the slave servers are reconfiguring a lot more of the file than is > > really necessary. Even with a template I would need to manage blocks > > of data, with specific edits within each block. > > That''s all pretty easy, still, I''d think. And again, if you''re > talking about configuring rc.conf, the problem here is that you''ve > chosen a platform that starts out difficult to manage. That''s > clearly your decision, but it does mean you''re always going to > struggle to automate your systems. If you either picked a more > manageable platform, or just gave up on using the standard file > organization and rewrote things to be more manageable, you''d be > better off.I find it almost ironic that you should accuse FreeBSD of being a platform that is difficult to manage; my biggest complaint about System-V is that it is more difficult to manage than BSD. This begs the question: if BSD is so hard to manage, how come I have been able to be so successful when using an arguably broken tool, cfengine, while my Linux administrators are still doing everything by hand? This is starting to sound more like a philosophical argument than a technical one.> > My syslog is built similarly to my rc.conf, except that some services > > share the same log facility, so I can''t just build the file and append > > lines for each service. I need to be able to modify a line after it > > was added in order to enable different kinds of logging. > > That''s a question of remodeling the configuration file. I don''t > think anyone is doing this yet in Puppet, but it shouldn''t be too > difficult to come up with a decent model. I still recommend syslog- > ng over normal syslog, but you''ll still need to spend some extra > effort on the config file.The only config file that I can think of where order matters is the Apache config. Almost all others: rc.conf, syslog.conf, newsyslog.conf, main.cf, etc are all un-ordered. The configuration elements can exist in any order as long as they exist. So the question is not "how to order the file" but "how to recognize configuration elements." That is something I expect my tools to be able to do; so it sounds to me like I need to file a bug with my tool designers.> > > > Doesn''t cron, and wouldn''t most other types use a "setting = value" > > find/replace/edit mechanism internally? Wouldn''t it be easier to > > create new types if a common "setting=value: find/replace/edit" method > > wan available? > > Cron doesn''t use that kind of format internally, and it''s painfully > difficult to manage, unfortunately. It might be easier to add new > types if there were a simple base class available, but far more > configuration files have a unique format than you would like to > believe. Even for those that do have a common format, they often > support a huge number of parameters, and the entire file counts as > one record, rather than the file being semantically separate records, > like cron tabs are.That would probably be true for php conf/include files or any executable configuration files, and for parts of config files that are split across several lines (blocks of data) but for the most part, at least in my experience, each line is a semantically separate configuration element. But then, most of what I do is in FreeBSD, System-V may very well do some weird stuff with it''s configuration files.> > As we said before, I really don''t want to use that method, but I don''t > > see a way around it right now. But of course I am still learning about > > the templating engine; so if what I describe above is possible ... > > then nevermind. But I need to find out if it is possible, or if there > > is a better way, before I commit too much energy into puppet or any > > other tool. > > I''m assuming it''s not an option to switch to a sysV-style platform, > or something like Solaris that''s actually trying to make the platform > more manageable. Assuming that, you''re always going to have trouble > unless you''re willing to pretty much entirely rethink these important > configuration files. E.g., if you take all of the data out of > rc.conf and put application-specific data into separate files, > restricting rc.conf to just loading those files, then your life will > be easier and Puppet''s templating will trivially do what you want. > If you don''t want to do that, though, then it''s going to be pretty > difficult.In order to be manageable a system must be predictable and understandable, Linux and especially Solaris, have a long way to go. I have had a lot of success in making FreeBSD manageable on a large scale across many hosts. If, as it appears, you are taking the position that System-V can be managed in the right way and BSD can not then you are doing puppet an extreme disservice. System-V and BSD are different, but it is a philosophical difference, not a technical one.> > My dream is to get to the point where, even if a service goes down at > > 2am, I can get a full nights sleep. That probably means having a > > configuration engine smart enough to recognize when a service goes > > down and be able to reconfigure another host to take over serving that > > service, and reconfigure the network so that it recognizes that the > > service has moved. > > Many share that dream, but it''s far beyond the scope of any existing > set of tools, much less a single tool like Puppet. If I had many > full-time developers working on this space, I''d hope I could > realistically attack that problem in 5 years or so. Until then, > we''re stuck with humans doing most of the work, still, but hopefully > with Puppet you can focus on the problem and not worry so much about > how to get the bits to the disks. >I''m actually not that far away from this goal, but I have run into some problems that can''t be solved with cfengine. I still hope that puppet can solve these problems, and I am more than willing to do the design and development work to make it happen. But if your philosophy is that System-V is right and all others are "difficult to manage" then I need to find some other tools. I am also sensing that we are both very stubborn people. So let''s leave this conversation alone for a while while I try and understand puppet''s design philosophy and you consider why managing service configurations in rc.conf is not something puppet should do. -- -- Perfection is just a word I use occasionally with mustard. --Atom Powers--
(I''m about to catch a plane, so this''ll be a short initial reply.)> I find it almost ironic that you should accuse FreeBSD of being a > platform that is difficult to manage; my biggest complaint about > System-V is that it is more difficult to manage than BSD. > > This begs the question: if BSD is so hard to manage, how come I have > been able to be so successful when using an arguably broken tool, > cfengine, while my Linux administrators are still doing everything by > hand? This is starting to sound more like a philosophical argument > than a technical one.Much of my definition of manageability derives from whether semantically distinct information is in separate files. If you''re configuring multiple services with a single file, it''s going to be more difficult to manage than one file per semantically distinct resource. It''s true that I find FreeBSD infuriatingly difficult to automate, but I don''t know FreeBSD very well. My personal experience has been that FreeBSD is often chosen by those sysadmins who are very good at interacting directly with computers, but I have not seen anyone succeed at putting a software proxy between them and FreeBSD. Clearly I''m not going to say it''s not possible, but based on my attempts to do things like write providers for FreeBSD''s packaging system, I wouldn''t want to be responsible for that proxy. I''d love to have someone who really cared about FreeBSD spend some time on Puppet, because it''s different enough that it needs to be treated pretty specially in most cases. That does result in a negative prejudice on my part, because it makes it very difficult for me to provide good support for the *BSDs, but I hope that my prejudice is based on experience, not philosophy. I''ll respond to the rest of the email once I''m settled into my hotel room (probably tomorrow). -- "They called me mad, and I called them mad, and damn them, they outvoted me." -- Nathaniel Lee, on being consigned to a mental institution, circa 17th c. --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com
Hi, I think the whole argumet about managebility comes to this. Which is easier to automate? File copiing/deleting/linking or file editing? I would say the first. 2007/3/11, Atom Powers <atom.powers@gmail.com>:> On 3/11/07, Luke Kanies <luke@madstop.com> wrote: > > On Mar 9, 2007, at 1:24 PM, Atom Powers wrote:> You are thinking of the rc.d script. And I think you misunderstand the > rc.d framework, which is much more manageable than the init.d > framework.I think you are looking at managability from completly different angle. I maybe agree that for a person administrator is more mamageble if everithing related to services is in one file. There is fewer files to edit and therefore easier to find the right one. Now, if you want to automate and simplify config management I would say it is easier to move/copy files around. I would emphasis two points 1. we want to abstract different parts of the system. The contents of rc.conf file is not important, what is important is what services are running on the system. 2. we want to separate configuration of different parts of the system, so we can treat them independently. Different parts of the system should be orthogonal to each other. That means that they should interact as little as possible. So monolithic file managing many different services does not fit in this model well. So let us say we want to have apache server and postfix running on a host. If you look at sysv system the files needed to run apache are completly different than for postfix. So if you want apache and postfix on one host, you just copy files for apache and postfix over. They won''t interact. Whereas if you use rc.d as in FreeBSD both apache and postfix use the same file(rc.conf), so thay have to edit it. Now it is way easier to automate file copiing than file editing I would say. I think in that respect sysv is easier to mantain than rc.d.> > rc.conf has, only, un-ordered setting=value pairs, like > "ntpd_enable=yes" and "ntpd_conf=/usr/local/etc/ntp.conf" When rc.d > starts a service via an /etc/rc.d script it reads rc.conf for the > settings that affect the application execution environment. > So all your application start/stop/restart settings are in one place, > you only have to manage one file and you don''t have to manage any of > the scripting that is inside the service start script.Sysv used in modern linux also have separate files for configuration (/etc/sysconfig/*).> > The structure and purpose of rc.conf is a design decision, not a bug. > I fail to see how managing setting=value pairs in rc.conf is > technically more difficult than managing application specific > configuration scripts;File editing is more difficult and error prone than linking/moving/copiing/deleting files.> and perhaps more to the point, how applications > configuration scripts make a system easier to manage than rc.conf.Maybe not from the point of a human beeing, but defenitely from a point of automation tool. In automation you want configuration of different services to be orthogonal to each other as much as possible. Monolithic files make it difficult.> Especially when System-V run scripts must be ordered; rc.d scrips > manage the ordering automatically with "provide" and "require" lines > in each script.There are some enhancements of sysv in gentoo and suse, which manage order with provide and require as in rc.d. I don''t know about other distros. Anyway order is usually defined by the distro so there is no need for admin to change it. I hope this would help, to see things from a different angle. Martin
On 3/12/07, Martin Vuk <mrcin.vuk@gmail.com> wrote:> 2007/3/11, Atom Powers <atom.powers@gmail.com>: > > On 3/11/07, Luke Kanies <luke@madstop.com> wrote: > > > On Mar 9, 2007, at 1:24 PM, Atom Powers wrote: > > > You are thinking of the rc.d script. And I think you misunderstand the > > rc.d framework, which is much more manageable than the init.d > > framework. > I think you are looking at managability from completly different > angle. I maybe agree that for a person administrator is more mamageble > if everithing related to services is in one file. There is fewer files > to edit and therefore easier to find the right one. Now, if you want > to automate and simplify config management I would say it is easier to > move/copy files around. I would emphasis two points > 1. we want to abstract different parts of the system. The contents of > rc.conf file is not important, what is important is what services are > running on the system.Very True.> 2. we want to separate configuration of different parts of the system, > so we can treat them independently. Different parts of the system > should be orthogonal to each other. That means that they should > interact as little as possible. So monolithic file managing many > different services does not fit in this model well.RE "orthogonal", I don''t think that word means what you think it means. I see your point, and I don''t disagree.> Sysv used in modern linux also have separate files for configuration > (/etc/sysconfig/*).I see the advantages of that method, but I smell complexity. (I''m allergic to complexity.) I can''t quite put my finger on where it is though...> > > > The structure and purpose of rc.conf is a design decision, not a bug. > > I fail to see how managing setting=value pairs in rc.conf is > > technically more difficult than managing application specific > > configuration scripts; > File editing is more difficult and error prone than > linking/moving/copiing/deleting files.It doesn''t have to be. The hard part is parsing the file, and the service managers (rc.d/init.d) seem to be able to do that without trouble, why can''t we? Sure, parsing and editing files is hard, but just because it''s hard doesn''t mean it''s wrong.> > and perhaps more to the point, how applications > > configuration scripts make a system easier to manage than rc.conf. > Maybe not from the point of a human beeing, but defenitely from a > point of automation tool. In automation you want configuration of > different services to be orthogonal to each other as much as possible. > Monolithic files make it difficult.As I stated in one of my previous messages, my ultimate goal is to "train" the systems to manage themselves, to be able to start/stop/install/reinstall/ and even reconfigure themselves based on changing conditions in the network. That may well be an impossible goal, but I''m stubborn. In my mind I need the ability to modify files in-place in order to achieve that goal; the alternative is to create so many versions of the same file, or templates so complex as to be worse than the problem I''m trying to solve. Let''s take an example, SpamAssassin. I can do some statistical analysis on incoming messages and identify the checks that hit most often for spam and least often for ham. With in-place file edits I could take those statistics a step further and automatically change the weight of the checks to match the current trends. You could do something similar with firewall rules, identifying and blocking problematic hosts. Or your reporting tools might discover that the samba service on a host is having a known kind of network problem and modify the "socket options" on only that host. A similar argument can be made for many kinds of problems for many services. Yes, I am a long way away from that goal, but every step in that direction now is a step I don''t have to take later. -- -- Perfection is just a word I use occasionally with mustard. --Atom Powers--
On Mar 12, 2007, at 4:10 PM, Atom Powers wrote:> On 3/12/07, Martin Vuk <mrcin.vuk@gmail.com> wrote: > >> 2. we want to separate configuration of different parts of the >> system, >> so we can treat them independently. Different parts of the system >> should be orthogonal to each other. That means that they should >> interact as little as possible. So monolithic file managing many >> different services does not fit in this model well. > > RE "orthogonal", I don''t think that word means what you think it > means. > I see your point, and I don''t disagree.You''re both right. Orthogonal''s literal definition is "at right angles", but is also used in math to describe two variables that can''t affect each other.>> Sysv used in modern linux also have separate files for configuration >> (/etc/sysconfig/*). > > I see the advantages of that method, but I smell complexity. (I''m > allergic to complexity.) > I can''t quite put my finger on where it is though...There are different kinds of complexity. rc.conf''s simplicity is that everything is in one place, but its complexity is that it''s essentially impossible for a computer to know what a given setting will affect. This is why I often talk about "teaching" Puppet how to manage a given application or file -- it''s often very difficult to use a computer to manage something that is otherwise very easy for a human, and it often includes some weird twists or rethinking of the problem, and sometimes results in a system that''s easier for computers but possibly harder for humans.>> File editing is more difficult and error prone than >> linking/moving/copiing/deleting files. > > It doesn''t have to be. The hard part is parsing the file, and the > service managers (rc.d/init.d) seem to be able to do that without > trouble, why can''t we? Sure, parsing and editing files is hard, but > just because it''s hard doesn''t mean it''s wrong.Parsing the file is trivial; parsing the semantics is essentially impossible without knowing beforehand every parameter that can appear in the file and which services each parameter affects.>> Maybe not from the point of a human beeing, but defenitely from a >> point of automation tool. In automation you want configuration of >> different services to be orthogonal to each other as much as >> possible. >> Monolithic files make it difficult. > > As I stated in one of my previous messages, my ultimate goal is to > "train" the systems to manage themselves, to be able to > start/stop/install/reinstall/ and even reconfigure themselves based on > changing conditions in the network. That may well be an impossible > goal, but I''m stubborn. In my mind I need the ability to modify files > in-place in order to achieve that goal; the alternative is to create > so many versions of the same file, or templates so complex as to be > worse than the problem I''m trying to solve.I think that your goal is laudible, if disappointingly far off, and I agree that it requires modification of files on disk, but I recommend questioning your assumption. Specifically, I''ve provided a fourth option (beyond modifying the file in place, having many versions, or using complex templates): Split the file into semantically separate (and thus orthogonal) files, one per service, and just have rc.conf read in all of those files. Now, suddenly, parsing is still trivial, but so are the semantics -- if it''s in /etc/rc.conf.d/apache2, then I know it''s going to affect apache2. You can generate the entire file each time, rather than having to generate pieces and edit those pieces in, which is *far* easier. It''s true that you can''t actually guarantee orthogonality here, because different services could use the same parameter and thus have a collision, but that''d be a problem Puppet couldn''t fix. As a simple exercise, try writing a parser, in whatever language you want, capable of managing this file each way: Every parameter in the same file, and parameters split out into per-service files. The second is trivial, the first is quite complicated.> Let''s take an example, SpamAssassin. I can do some statistical > analysis on incoming messages and identify the checks that hit most > often for spam and least often for ham. With in-place file edits I > could take those statistics a step further and automatically change > the weight of the checks to match the current trends. > > You could do something similar with firewall rules, identifying and > blocking problematic hosts. > > Or your reporting tools might discover that the samba service on a > host is having a known kind of network problem and modify the "socket > options" on only that host. A similar argument can be made for many > kinds of problems for many services. > > Yes, I am a long way away from that goal, but every step in that > direction now is a step I don''t have to take later.Ah, now you''re talking something very different -- using feedback mechanisms to affect configurations. You have to separate the modification mechanism from the feedback mechanism, and envision a decoupled flow of information. Puppet can very successfully be used to make those edits, but you''ll need another subsystem capable of automatically determining what the edits should be, and then probably yet another subsystem collecting the base data and feeding it to the determination engine. This is definitely my long term goal -- lots of feedback systems eventually empowering the stupid computers to make some decisions for themselves -- and I''d love to work with you to accomplish those things. I think it''s impossible to accomplish these goals without separating capabilities through a simple, decoupled interface, though, which means we can focus just on editing the files here, and focus elsewhere on how to determine what edits to make. -- If all the world''s a stage, I want to operate the trap door. -- Paul Beatty --------------------------------------------------------------------- Luke Kanies | http://reductivelabs.com | http://madstop.com