.. -*- mode: rst -*- ganglia ======= Another interesting example of Genshi templating is to automatically generate ``gmond``/``gmetad`` configuration files. The idea is that each cluster is headless: it communicates with the rest of the cluster members on an isolated multicast IP address and port. Any of the cluster members is therefore isolated on that particular ip/port pair. Additionally, each ``gmond`` instance **also** listens on UDP. This allows for any of the cluster members to be polled for information on the entire cluster! The second part of the trick is in ``gmetad.conf``. Here, we dynamically generate a list of clusters (based on profiles names) and a list of members to poll (based on the clients in said profiles). As the number of profiles and client grows, this list will grow automatically as well. When a new host is added, ``gmetad`` will receive an updated configuration and act accordingly. There **is** one caveat though. The ``gmetad.conf`` parser is hard coded to read 16 arguments per ``data_source`` line. If you have more than 15 nodes in a cluster, you will see a warning in the logs. You can either ignore it, or truncate the list to the first 15 members. In our environment, a profile is a one to one match with the role of that particular host. You can also do this based on groups, or any other client property. Bundler/ganglia.xml ------------------- .. code-block:: xml Rules/services-ganglia.xml -------------------------- .. code-block:: xml Cfg/etc/ganglia/gmetad.conf/gmetad.conf.genshi ---------------------------------------------- .. code-block:: none {% python client_metadata = metadata.query.all() profile_array = {} seen = [] for item in client_metadata: if item.profile not in seen: seen.append(item.profile) profile_array[item.profile]=[] profile_array[item.profile].append(item.hostname) seen.sort() %}\ gridname "Our Grid" {% for profile in seen %} data_source "${profile}" \ {% for host in profile_array[profile] %}\ ${host} \ {% end %}\ {% end %} rrd_rootdir "/var/lib/ganglia/rrds" Cfg/etc/ganglia/gmond.conf/gmod.conf.genshi ------------------------------------------- .. code-block:: none {% python import random random.seed(metadata.profile) last_octet=random.randint(2,254) %}\ /* $$Id$$ $$HeadURL$$ */ /* This configuration is as close to 2.5.x default behavior as possible The values closely match ./gmond/metric.h definitions in 2.5.x */ globals { daemonize = yes setuid = yes user = nobody debug_level = 0 max_udp_msg_len = 1472 mute = no deaf = no host_dmax = 1800 /* 30 minutes */ cleanup_threshold = 604800 /*secs=1 week */ gexec = no send_metadata_interval = 0 } /* If a cluster attribute is specified, then all gmond hosts are wrapped inside * of a tag. If you do not specify a cluster tag, then all will * NOT be wrapped inside of a tag. */ cluster { name = "${metadata.profile}" owner = "user@company.net" latlong = "unspecified" url = "unspecified" } /* The host section describes attributes of the host, like the location */ host { location = "unspecified" } /* Feel free to specify as many udp_send_channels as you like. Gmond used to only support having a single channel */ udp_send_channel { host = ${metadata.hostname} port = 8649 } udp_send_channel { mcast_join = 239.2.11.${last_octet} port = 8649 ttl = 1 } /* You can specify as many udp_recv_channels as you like as well. */ udp_recv_channel { port = 8649 bind = ${metadata.hostname} } udp_recv_channel { mcast_join = 239.2.11.${last_octet} bind = 239.2.11.${last_octet} port = 8649 } /* You can specify as many tcp_accept_channels as you like to share an xml description of the state of the cluster */ tcp_accept_channel { port = 8649 } /* Each metrics module that is referenced by gmond must be specified and loaded. If the module has been statically linked with gmond, it does not require a load path. However all dynamically loadable modules must include a load path. */ modules { /* [snip] */