diff --git a/apt/README.md b/apt/README.md index 76c276abf..331e50fb2 100644 --- a/apt/README.md +++ b/apt/README.md @@ -8,20 +8,17 @@ Recipes default ------- - The default recipe runs apt-get update during the Compile Phase of the Chef run to ensure that the system's package cache is updated with the latest. It is recommended that this recipe appear first in a node's run list (directly or through a role) to ensure that when installing packages, Chef will be able to download the latest version available on the remote APT repository. This recipe also sets up a local cache directory for preseeding packages. cacher ------ +Installs the apt-cacher package and service so the system can provide APT caching. You can check the usage report at http://{hostname}:3142/report. The cacher recipe includes the `cacher-client` recipe, so it helps seed itself. -Installs the apt-cacher package and service so the system can be an APT cache. - -proxy ------ - -Installs the apt-proxy package and service so the system can be an APT proxy. +cacher-client +------------- +Configures the node to use the apt-cacher server as a client. Resources/Providers =================== @@ -42,6 +39,8 @@ Put `recipe[apt]` first in the run list. If you have other recipes that you want The above will run during execution phase since it is a normal template resource, and should appear before other package resources that need the sources in the template. +Put `recipe[apt::cacher]` in the run_list for a server to provide APT caching and add `recipe[apt::cacher-client]` on the rest of the Debian-based nodes to take advantage of the caching server. + An example of The LWRP `apt_repository` `add` action: apt_repository "zenoss" do @@ -51,18 +50,6 @@ An example of The LWRP `apt_repository` `add` action: action :add end -An example of `apt_repository` using a signing key: - - apt_repository "hardy-rsyslog-ppa" do - uri "http://ppa.launchpad.net/a.bono/rsyslog/ubuntu" - distribution "hardy" - components ["main"] - keyserver "keyserver.ubuntu.com" - key "C0061A4A" - action :add - notifies :run, "execute[apt-get update]", :immediately - end - and the `remove` action: apt_repository "zenoss" do diff --git a/apt/metadata.rb b/apt/metadata.rb index 67ae37ffd..951cb16d9 100644 --- a/apt/metadata.rb +++ b/apt/metadata.rb @@ -3,10 +3,10 @@ license "Apache 2.0" description "Configures apt and apt services and an LWRP for managing apt repositories" long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version "1.0.0" +version "1.1.0" recipe "apt", "Runs apt-get update during compile phase and sets up preseed directories" recipe "apt::cacher", "Set up an APT cache" -recipe "apt::proxy", "Set up an APT proxy" +recipe "apt::cacher-client", "Client for the apt::cacher server" %w{ ubuntu debian }.each do |os| supports os diff --git a/apt/recipes/cacher-client.rb b/apt/recipes/cacher-client.rb new file mode 100644 index 000000000..b173b8b2a --- /dev/null +++ b/apt/recipes/cacher-client.rb @@ -0,0 +1,37 @@ +# +# Cookbook Name:: apt +# Recipe:: cacher-client +# +# Copyright 2011, Opscode, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +servers = search(:node, 'recipes:apt\:\:cacher') || [] +if servers.length > 0 + Chef::Log.info("apt-cacher server found on #{servers[0]}.") + proxy = "Acquire::http::Proxy \"http://#{servers[0].ipaddress}:3142\";" + file "/etc/apt/apt.conf.d/01proxy" do + owner "root" + group "root" + mode "0644" + content proxy + action :create + end +else + Chef::Log.info("No apt-cacher server found.") + file "/etc/apt/apt.conf.d/01proxy" do + action :delete + only_if {File.exists?("/etc/apt/apt.conf.d/01proxy")} + end +end diff --git a/apt/recipes/cacher.rb b/apt/recipes/cacher.rb index f6fed5805..3d4a086f3 100644 --- a/apt/recipes/cacher.rb +++ b/apt/recipes/cacher.rb @@ -2,7 +2,7 @@ # Cookbook Name:: apt # Recipe:: cacher # -# Copyright 2008-2009, Opscode, Inc. +# Copyright 2008-2011, Opscode, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -40,3 +40,6 @@ mode 0644 notifies :restart, resources(:service => "apt-cacher") end + +#this will help seed the proxy +include_recipe "apt::cacher-client" diff --git a/one-shot/README.md b/one-shot/README.md new file mode 100644 index 000000000..715a50e46 --- /dev/null +++ b/one-shot/README.md @@ -0,0 +1,71 @@ +Description +=========== +This cookbook provides a framework for making single-use, one-shot recipes. By including the `one-shot` recipe in the node's run_list, on the next chef-client run the contents of the `one-shot::one-shot` recipe will be called. This is parameterized as an attribute, so you can change these out by setting the `["one_shot"]["recipe"]` to include different recipes. The file `roles/one-shot.rb` is included so you can simply change the role instead of changing the source directly. + +Requirements +============ +Written with Chef 0.9.12. + +Testing +------- +Tested on Ubuntu 10.04 and 10.10 and tested with Chef 0.9.12. + +Attributes +========== +The attribute is set in `attributes/default.rb` and can be set via the `roles/one-shot.rb` Role as well (or you could edit the `default.rb` recipe directly). + +* `["one_shot"]["recipe"]` - Default is `one-shot::one-shot`, but may be set to alternate recipes so you may have multiple recipes to use, depending on this attribute. + +Roles +===== +one-shot +-------- +This role is provided by the `roles/one-shot.rb` for setting the `["one_shot"]["recipe"]` attribute. + + knife role from file cookbooks/one-shot/roles/one-shot.rb + knife node run_list add YOURNODE 'role[one-shot]' + + +Recipes +======= +Default +------- +The default recipe includes the recipe referred to by the `["one_shot"]["recipe"]` attribute, executing it and then removing the `oneshot` recipe from the node's run_list. + +One-Shot +-------- +This is an example implementation of a one-shot recipe, it may be copied or modified as necessary. Access to additional recipes are made through the `["one_shot"]["recipe"]` attribute. This recipe is accessed by the `attributes/default.rb`. + +Two-Shot +-------- +This is an example implementation of a one-shot recipe, it may be copied or modified as necessary. Access to additional recipes are made through the `["one_shot"]["recipe"]` attribute. This recipe is accessed by the `roles/one-shot.rb` Role. + +Usage +===== +Add the `one-shot` recipe to a node's run_list. Next chef-client run, that node will execute the recipe designated by the `["one_shot"]["recipe"]` attribute, then remove itself from the node's run_list. The attribute may be set with a Role or directly in the source of the cookbook. You can update the `one-shot` Role with any changes for future runs, then add the `one-shot` recipe back to the run_list again. It could definitely be used within another Role and applied to a series of nodes if needed. + + knife node run_list add YOURNODE 'recipe[one-shot]' + +optional + + knife role from file cookbooks/one-shot/roles/one-shot.rb + knife node run_list add YOURNODE 'role[one-shot]' + + +License and Author +================== +Author:: Matt Ray + +Copyright:: 2011 Opscode, Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/apt/recipes/proxy.rb b/one-shot/attributes/default.rb similarity index 57% rename from apt/recipes/proxy.rb rename to one-shot/attributes/default.rb index b843fa106..810a99512 100644 --- a/apt/recipes/proxy.rb +++ b/one-shot/attributes/default.rb @@ -1,8 +1,9 @@ # -# Cookbook Name:: apt -# Recipe:: proxy +# Author:: Matt Ray +# Cookbook Name:: zenoss +# Attributes:: default # -# Copyright 2008-2009, Opscode, Inc. +# Copyright 2011 Opscode, Inc # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,19 +17,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -package "apt-proxy" do - action :install -end -service "apt-proxy" do - supports :restart => true, :status => false - action [ :enable, :start ] -end - -cookbook_file "/etc/apt-proxy/apt-proxy-v2.conf" do - source "apt-proxy-v2.conf" - owner "root" - group "root" - mode 0644 - notifies :restart, resources(:service => "apt-proxy") -end +#additional one-shots can be added by changing the name of the recipe +default[:one_shot][:recipe] = "one-shot::one-shot" diff --git a/one-shot/metadata.json b/one-shot/metadata.json new file mode 100644 index 000000000..318df625a --- /dev/null +++ b/one-shot/metadata.json @@ -0,0 +1,31 @@ +{ + "long_description": "", + "recipes": { + "one-shot::one-shot": "The recipe to be executed a single time.", + "default": "Includes the `one-shot` recipe and removes itself from the run_list." + }, + "attributes": { + }, + "providing": { + }, + "dependencies": { + }, + "maintainer": "Opscode, Inc.", + "replacing": { + }, + "maintainer_email": "matt@opscode.com", + "groupings": { + }, + "platforms": { + }, + "license": "Apache 2.0", + "version": "0.1.0", + "recommendations": { + }, + "suggestions": { + }, + "name": "one-shot", + "description": "Runs the contents of the one-shot.rb and removes it from the run_list", + "conflicting": { + } +} \ No newline at end of file diff --git a/one-shot/metadata.rb b/one-shot/metadata.rb new file mode 100644 index 000000000..8b92171dd --- /dev/null +++ b/one-shot/metadata.rb @@ -0,0 +1,7 @@ +maintainer "Opscode, Inc." +maintainer_email "matt@opscode.com" +license "Apache 2.0" +description "Runs the contents of the one-shot.rb and removes it from the run_list" +version "0.1" +recipe "one-shot::one-shot", "The recipe to be executed a single time." +recipe "default", "Includes the `one-shot` recipe and removes itself from the run_list." diff --git a/one-shot/recipes/default.rb b/one-shot/recipes/default.rb new file mode 100644 index 000000000..f8666c706 --- /dev/null +++ b/one-shot/recipes/default.rb @@ -0,0 +1,31 @@ +# +# Author:: Matt Ray +# Cookbook Name:: one-shot +# Recipe:: default +# +# Copyright 2011, Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +oneshot = node["one_shot"]["recipe"] + +include_recipe oneshot + +ruby_block "remove one-shot recipe #{oneshot}" do + block do + Chef::Log.info("One-Shot recipe #{oneshot} executed and removed from run_list") + node.run_list.remove("recipe[one-shot]") if node.run_list.include?("recipe[one-shot]") + end + action :create +end diff --git a/one-shot/recipes/one-shot.rb b/one-shot/recipes/one-shot.rb new file mode 100644 index 000000000..8b89ef500 --- /dev/null +++ b/one-shot/recipes/one-shot.rb @@ -0,0 +1,21 @@ +# +# Author:: Matt Ray +# Cookbook Name:: one-shot +# Recipe:: one-shot +# +# Copyright 2011, Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Chef::Log.info("one-shot::one-shot called and executed!") diff --git a/one-shot/recipes/two-shot.rb b/one-shot/recipes/two-shot.rb new file mode 100644 index 000000000..faf73b8a7 --- /dev/null +++ b/one-shot/recipes/two-shot.rb @@ -0,0 +1,21 @@ +# +# Author:: Matt Ray +# Cookbook Name:: one-shot +# Recipe:: two-shot +# +# Copyright 2011, Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +Chef::Log.info("one-shot::two-shot called and executed!") diff --git a/one-shot/roles/one-shot.rb b/one-shot/roles/one-shot.rb new file mode 100644 index 000000000..6dd33b816 --- /dev/null +++ b/one-shot/roles/one-shot.rb @@ -0,0 +1,7 @@ +name "one-shot" +description "One-Shot attribute for selecting recipe" +override_attributes( + "one_shot" => { + "recipe" => "one-shot::two-shot" + } + ) diff --git a/zenoss/README.md b/zenoss/README.md new file mode 100644 index 000000000..4cb53a394 --- /dev/null +++ b/zenoss/README.md @@ -0,0 +1,161 @@ +Description +=========== +WORK IN PROGRESS, TODO.txt covers planned features + +Installs and configures a Zenoss server with the `zenoss::server` recipe. Devices can be added to the Zenoss server by using the `zenoss::client` recipe and utilizing Chef roles to map to Zenoss Device Classes, Locations and Groups. LWRPs are available for installing ZenPacks, zenpatches, loading devices and users and running zendmd commands. + +Requirements +============ +Written with Chef 0.9.12 and uses fairly recent search capabilities of roles. + +The example roles in the `zenoss/roles` directory should be loaded for use, refer to the Roles subsection. + +Testing +------- +Tested on Ubuntu 10.04 and 10.10 and tested with Chef 0.9.12. + +Attributes +========== +Attributes under the `zenoss` namespace. + +* `["zenoss"]["device"]["device_class"]` - Device Class for the device, "/Discovered" is the default and may be overwritten at the Role or Node. +* `["zenoss"]["device"]["location"]` - Location for the device, may be set at the Role or Node. +* `["zenoss"]["device"]["modeler_plugins"]` - Modeler Plugins used by the device, may be set at the Role or Node. +* `["zenoss"]["device"]["properties"]` - Configuration Properties used by the device, may be set at the Role or Node. +* `["zenoss"]["device"]["templates"]` - Monitoring Templates used by the device, may be set at the Role or Node. +* `["zenoss"]["server"]["admin_password"]` - Password for the `admin` account, default is `chefzenoss` +* `["zenoss"]["server"]["installed_zenpacks"]` - Hash of ZenPacks and their versions, defaults are `"ZenPacks.zenoss.LinuxMonitor" => "1.1.5", "ZenPacks.community.MySQLSSH" => "0.4"` +* `["zenoss"]["server"]["zenhome"]` - Directory of the Zenoss server installation, default is `/usr/local/zenoss/zenoss` +* `["zenoss"]["server"]["zenoss_pubkey"]` - Public key for the `zenoss` user used for monitoring. Set on the server automatically if it does not exist. +* `["zenoss"]["server"]["zenpatches"]` - Hash of patches and the tickets providing the patches, defaults are `"23716" => "http://dev.zenoss.com/trac/ticket/7485", "23833" => "http://dev.zenoss.com/trac/ticket/6959"` + +Resources/Providers +=================== +zenbatchload +------------ +This LWRP builds a list of devices, their Device Classes, Systems, Groups, Locations and their properties and populates the `zenoss::server` with them. + +zendmd +------ +This LWRP takes a command to be executed by the `zendmd` command on the Zenoss server. Examples include setting passwords and other changes to the Zope object database. + +zenpack +------- +Installs ZenPacks on the `zenoss::server` for use for extending the base functionality. + +zenpatch +-------- +Installs patches on the `zenoss::server` based on the number referenced in the ticket. + +Recipes +======= +Default +------- +The default recipe passes through to `zenoss::client`. + +Client +------ +The client includes the `openssh` recipe and adds the device to the Zenoss server for monitoring. + +Server +------ +The server includes the `openssh` and `apt` recipes. The server recipe installs Zenoss from the .deb stack installer via the `apt` cookbook, handling and configuring all the dependencies. + +The recipe does the following: + +1. Installs Zenoss. +2. Applies post-3.0.3 patches from closed tickets. +3. Starts server. +4. Sets the `admin` password. +5. Adds any other users to the proper Zenoss roles. +6. Creates a `zenoss` user for running Zenoss and monitoring clients via SSH. +7. Installs ZenPacks required for monitoring. +8. Creates Device Classes, Groups and Locations based on Chef roles containing custom settings. +9. Adds Systems to the server based on which recipes are used within Chef. +10. Adds itself to be monitored. +11. Searches for members of the `sysadmins` group by searching through `users` data bag and adds them to the server. +12. Finds all nodes implementing `zenoss::client` and adds them for monitoring and places them in the proper Device Classes, Groups, Systems and Locations and any node-specific settings as well. + +Data Bags +========= +Create a `users` data bag that will contain the users that will be able to log into the Zenoss server (members of the 'sysadmin' group). The admin user is automatically provided. Zenoss-specific information is stored in the `zenoss` hash. Passwords may be set or left out. Multiple roles may be set; the choices with Zenoss Core are Manager, ZenManager, ZenUser or empty. Users may belong to User Groups within Zenoss (listing them here will create them). Example user data bag item: + + { + "id": "zenossadmin", + "groups": "sysadmin", + "zenoss": { + "password": "abc", + "roles": ["Manager", "ZenUser"], + "user_groups": ["managers"], + "pager": "zpager@example.com", + "email": "zemail@example.com" + } + } + +Two example data bags are provided and may be loaded like this: + + knife data bag create users + knife data bag from file users cookbooks/zenoss/data_bags/Zenoss_User.json + knife data bag from file users cookbooks/zenoss/data_bags/Zenoss_Readonly_User.json + +Roles +===== +This cookbook provides a number of example roles for mapping attributes to Zenoss' Device Classes, Groups and Locations. There is also a role called "ZenossServer" that may be used to configure the Zenoss server for convenience. These roles may be loaded like this: + + knife role from file cookbooks/zenoss/roles/Class_Server-SSH-Linux.rb + +Device Class Roles +------------------ +* Roles intended to map to Device Classes set the attribute `[:zenoss][:device][:device_class]`. This is an override_attribute on the role. +* Roles may set default attributes for `[:zenoss][:device][:modeler_plugins]`, `[:zenoss][:device][:templates]` and `[:zenoss][:device][:properties]` to be applied to the Device Class. +* The `name` for the role is unused by Zenoss. +* Nodes may only belong to a single Device Class, nodes that belong to multiple Device Class roles will have non-determinant membership in a single Device Class. + +Location Roles +-------------- +* Roles intended to map to Locations set the attribute `[:zenoss][:device][:location]`. This is an override_attribute on the role. +* Location roles may set the have `[:zenoss][:device][:address]` attribute for the Google map address. If you are using a newline, make sure it is entered as `\\n` in the role. This is an override_attribute on the role. +* The `name` and the `description` for the role map to the name and description of the Location. +* Nodes may only belong to a single Location, nodes that belong to multiple Location roles will have non-determinant membership in a single Location. + +Group Roles +----------- +* The roles in organization will populate the Groups on the Zenoss server. +* The Device Class and Location roles will not be added to Groups. + +Usage +===== +For a Zenoss server add the following recipe to the run_list: + + recipe[zenoss::server] + +This will allow device nodes to search for the server by this role. Devices are currently added by their external IP addresses, which is effective in hybrid clouds but you may want to modify this for environments in a single platform (ie. EC2-only). Check the `providers/zenbatchload.rb` for this setting. Running `chef-client --log_level debug` on the server node will show the calls for zendmd and zenbatchload commands. + +To register a device for monitoring with Zenoss on a client node: + + include_recipe "zenoss::client" + +Any Properties that need to be set are exposed as attributes on the node and the Roles used by this cookbook. + +Zenoss has the concept of Devices, which belong to a single Device Class and Location. Chef nodes implementing the `zenoss::client` recipe become Zenoss Devices and the Device Class and Location roles may be used for placing in the proper organizers. Zenoss also has Groups and Systems which are essentially ways of tagging and organizing devices (and devices may belong to multiple Groups and Systems). Searches for nodes that belong to other roles will populate the Groups. Searches for nodes applying recipes are used to populate the Systems. + +If you are monitoring devices running on Amazon's EC2 with Zenoss, you will need to allow ICMP ping from your Zenoss server. + +License and Author +================== +Author:: Matt Ray + +Copyright:: 2010, Zenoss, Inc +Copyright:: 2010, 2011 Opscode, Inc + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/zenoss/TODO.txt b/zenoss/TODO.txt new file mode 100644 index 000000000..467b971ad --- /dev/null +++ b/zenoss/TODO.txt @@ -0,0 +1,91 @@ +0.1 +mostly documentation +zenoss::client depends on openssh + +0.2 +zenoss::server installs itself via apt + +0.3 +$ZENHOME is an attribute +zenoss_zenpack LWRP with :install :remove +install linux monitor ZenPack +zenoss_zendmd LWRP with :run +sets the admin password via attribute + +0.4 +checks for already installed zenpacks, apt repos +hash of installed_zenpacks as key->package, value->version: server attribute +single attributes/default.rb file since there's no differentiation +zenoss::server generate SSH keys for the zenoss user and writes it to an attribute +zenoss::client get the SSH keys via the attribute writes it to /home/zenoss/.ssh/authorized_keys + +0.5 +LWRP for 3.0.3 zenpatches (http://dev.zenoss.com/trac/report/6 is the basis) +Roles will be used for Device Classes, Groups and Locations +Recipes will be used for Systems +server will insert devices +devices get added to zenoss::server that implement the zenoss::client recipe +zenoss::clients will have attributes for any particular properties they need set + +0.6 +check search in client.rb to negate use of [0] +in metadata.rb, you should add recipes http://wiki.opscode.com/display/chef/Metadata#Metadata-recipe +move restart to server.rb for zenpack installation +skips new install wizard +create a random admin password (in mysql cookbook) +user manage_home true +document use of external IP addresses +include the search zenpack +zendmd use debug for commands +load_current_resource for zenpack installation +zenoss::client server move self to /Server/SSH/Linux instead of /Server/Linux +monitoring server should have a default role ('monitoring' is used in Nagios) +document enabling ping through the security group in EC2 +add additional users via zendmd (extend zendmd LWRP for user-management) +use the "sysadmins" data bag to populate the users +provide example data_bag files for loading users + +0.7 *CURRENT* +CentOS 5.5 via yum +yum::repo +add a repo to /etc/yum/sources.list.d/ or whatever + +0.8 +notify zendmd at end of run to load everything (before zenbatchload) +optimize creation of device classes, systems and groups by using hashes instead of individual calls or by comparing against previous values +diff previous zenbatchload run +clients request specific ZenPacks (or Device Class roles?) +AWS ZenPack and Role for Device Class + + +BACKLOG: +Chef Client ZenPack +configure mail settings +sysadmin_email - default notification email. +sysadmin_sms_email - default notification sms. +encrypted data bags for storing passwords +nodes not in "production" environment could map to other production states ("preproduction", "decommissioned", etc.") +make zenoss server receive syslog +install nagios plugins +templates for the configuration? (http://community.zenoss.org/docs/DOC-8511) +other configuration/tuning options exposed as attributes? +configure zope.conf +distributed collectors +disable some of the daemons that are unused +other types of things to monitor could be added by search (ie. apache::server or mysql::server) +anything useful for the zLink? +LDAP logins +snmpd cookbook +ERB template for monitoring via Zenoss that exposes the basics in a secure fashion +change default community string to "cookbook" + + +CHEF SERVER ZENPACK +list of managed nodes +link back to Chef server/platform in zLink +zlinked and any stats available +any reports +AMQP message queue event listener +anything worth pushing to the Chef Server with Knife? +is there any additional monitoring data available from Chef Server worth exposing + diff --git a/zenoss/attributes/default.rb b/zenoss/attributes/default.rb new file mode 100644 index 000000000..092a44fc8 --- /dev/null +++ b/zenoss/attributes/default.rb @@ -0,0 +1,46 @@ +# +# Author:: Matt Ray +# Cookbook Name:: zenoss +# Attributes:: default +# +# Copyright 2010, Zenoss, Inc +# Copyright 2010, 2011 Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +::Chef::Node.send(:include, Opscode::OpenSSL::Password) + +set_unless[:zenoss][:server][:admin_password] = secure_password + +default[:zenoss][:device][:device_class] = "/Discovered" #overwritten by roles or on nodes +default[:zenoss][:device][:location] = "" #overwritten by roles or on nodes +default[:zenoss][:device][:modeler_plugins] = [] #overwritten by roles or on nodes +default[:zenoss][:device][:properties] = {} #overwritten by roles or on nodes +default[:zenoss][:device][:templates] = [] #overwritten by roles or on nodes +default[:zenoss][:server][:version] = "3.0.3-0" +default[:zenoss][:server][:zenhome] = "/usr/local/zenoss/zenoss" #RPM is different +default[:zenoss][:server][:zenoss_pubkey] = "" #gets set in the server recipe, read by clients + +#it might matter that these get ordered eventually +default[:zenoss][:server][:installed_zenpacks] = { + "ZenPacks.zenoss.DeviceSearch" => "1.0.0", + "ZenPacks.zenoss.LinuxMonitor" => "1.1.5", + "ZenPacks.community.MySQLSSH" => "0.4", +} + +#it might matter that these get ordered eventually as well +default[:zenoss][:server][:zenpatches] = { + "23716" => "http://dev.zenoss.com/trac/ticket/7485", + "23833" => "http://dev.zenoss.com/trac/ticket/6959", +} diff --git a/zenoss/data_bags/Zenoss_Readonly_User.json b/zenoss/data_bags/Zenoss_Readonly_User.json new file mode 100644 index 000000000..43157f27a --- /dev/null +++ b/zenoss/data_bags/Zenoss_Readonly_User.json @@ -0,0 +1,8 @@ +{ + "id": "readonly", + "groups": "sysadmin", + "zenoss": { + "password": "readonly", + "roles": ["ZenUser"] + } +} diff --git a/zenoss/data_bags/Zenoss_User.json b/zenoss/data_bags/Zenoss_User.json new file mode 100644 index 000000000..cc7d23dcc --- /dev/null +++ b/zenoss/data_bags/Zenoss_User.json @@ -0,0 +1,11 @@ +{ + "id": "zenossadmin", + "groups": "sysadmin", + "zenoss": { + "password": "abc", + "roles": ["Manager","ZenUser"], + "user_groups": ["sysadmin"], + "pager": "zenossadmin_pager@example.com", + "email": "zenossadmin@example.com" + } +} diff --git a/zenoss/metadata.rb b/zenoss/metadata.rb new file mode 100644 index 000000000..13dff2eaf --- /dev/null +++ b/zenoss/metadata.rb @@ -0,0 +1,71 @@ +maintainer "Opscode, Inc." +maintainer_email "matt@opscode.com" +license "Apache 2.0" +description "Installs and configures Zenoss and registers nodes as devices" +version "0.6.1" +depends "apt", ">> 0.9" +depends "openssh" +depends "openssl" +recipe "zenoss", "Defaults to the client recipe." +recipe "zenoss::client", "Includes the `openssh` recipe and adds the device to the Zenoss server for monitoring." +recipe "zenoss::server", "Installs Zenoss, handling and configuring all the dependencies while adding Device Classes, Groups, Systems and Locations. All nodes using the `zenoss::client` recipe are added for monitoring." + + +#start with just the .deb, perhaps switch to stack installer and/or .rpm +%w{ debian ubuntu }.each do |os| + supports os +end + +attribute "zenoss/device/device_class", + :display_name => "Device Class for the node.", + :description => "Device Class for the node. May be overridden by the Role.", + :default => "/Discovered" + +attribute "zenoss/device/location", + :display_name => "Location for the node.", + :description => "Location for the node. May be overridden by the Role." + +attribute "zenoss/device/modeler_plugins", + :display_name => "List of modeler plugins for the node.", + :description => "List of modeler plugins for the node. Node takes precendence over the Role if set.", + :type => "array" + +attribute "zenoss/device/properties", + :display_name => "Hash of configuration properties for the node.", + :description => "Hash of configuration properties for the node. Node takes precendence over the Role if set.", + :type => "hash" + +attribute "zenoss/device/templates", + :display_name => "List of templates for the node.", + :description => "List of templates for the node. Node takes precendence over the Role if set.", + :type => "array" + +attribute "zenoss/server/admin_password", + :display_name => "Zenoss Admin Password", + :description => "Randomly generated password for the admin user", + :default => "randomly generated" + +attribute "zenoss/server/version", + :display_name => "Zenoss Version", + :default => "3.0.3-0" + +attribute "zenoss/server/zenhome", + :display_name => "Environment variable $ZENHOME", + :description => "$ZENHOME environment variable, directory where Zenoss is installed.", + :default => "/usr/local/zenoss/zenoss" + +attribute "zenoss/server/zenoss_pubkey", + :display_name => "zenoss user's public key", + :description => "zenoss user's public key on the server for use with SSH monitoring.", + :type => "string" + +attribute "zenoss/server/installed_zenpacks", + :display_name => "Hash of ZenPacks to install.", + :description => "Hash of ZenPacks to install. Key/value of Name/Version.", + :type => "hash" + +attribute "zenoss/server/zenpatches", + :display_name => "zenpatch patches", + :description => "Hash of patches to install with zenpatch. Key/value of patch number/ticket url", + :type => "hash" + diff --git a/zenoss/providers/zenbatchload.rb b/zenoss/providers/zenbatchload.rb new file mode 100644 index 000000000..ba75216bf --- /dev/null +++ b/zenoss/providers/zenbatchload.rb @@ -0,0 +1,75 @@ +#loads the hash into a file for zenbatchload and loads it +action :run do + devices = new_resource.devices + locations = new_resource.locations + groups = new_resource.groups + batch = "" + #sort the hash and construct the batchload file + devices.keys.sort!.each do |dclass| + batch += "#{dclass}\n" + devices[dclass].sort_by {|n| n.ipaddress}.each do |device| + #set for hybrid clouds + if device.attribute["cloud"] and device.attribute["cloud"]["public_ips"] + batch += "#{device.cloud.public_ips[0]} " + else + batch += "#{device.ipaddress} " + end + #set the ID to the ec2 public name or fqdn + if device.attribute["ec2"] + batch += "setTitle='#{device["ec2"]["public_hostname"]}', " + else + batch += "setTitle='#{device["fqdn"]}', " + end + #set the Location & Groups + devlocation = "" + devgroups = "setGroups=[[" + device.roles.each do |role| + if locations.member?(role) + devlocation = "setLocation='#{role}', " + elsif groups.member?(role) + devgroups += "'#{role}'," + end + #ignore deviceclass roles + end + devgroups += "]], " + batch += "#{devlocation}#{devgroups}" + #set the Systems + devsystems = "setSystems=[[" + systems = device.run_list.expand.recipes + systems.collect! {|sys| sys.gsub('::', '/')} + systems.each {|sys| devsystems += "'#{sys}',"} + devsystems += "]], " + batch += "#{devsystems}" + #only use device.attribute["zenoss"]["device"].current_normal for node-specific templates, modeler_plugins and properties + if node.attribute["zenoss"] and node.attribute["zenoss"]["device"] and node.attribute["zenoss"]["device"].current_normal + if node.attribute["zenoss"]["device"].current_normal["modeler_plugins"] + plugins = node.attribute["zenoss"]["device"].current_normal["modeler_plugins"] + batch += "zCollectorPlugins=#{plugins}, " + end + if node.attribute["zenoss"]["device"].current_normal["templates"] + templates = node.attribute["zenoss"]["device"].current_normal["templates"] + batch += "zDeviceTemplates=#{templates}, " + end + if node.attribute["zenoss"]["device"].current_normal["properties"] + node.attribute["zenoss"]["device"].current_normal["properties"].each {|k, v| batch += "#{k}='#{v}', " } + end + end + batch += "\n" + end + end + Chef::Log.debug batch + #write the content to a temp file + file "/tmp/chefzenbatch.batch" do + owner "zenoss" + mode "0600" + content batch + action :create + end + #run the command as the zenoss user + execute "zenbatchload" do + user "zenoss" + command "#{node[:zenoss][:server][:zenhome]}/bin/zenbatchload /tmp/chefzenbatch.batch" + action :run + end +end + diff --git a/zenoss/providers/zendmd.rb b/zenoss/providers/zendmd.rb new file mode 100644 index 000000000..93ae43af7 --- /dev/null +++ b/zenoss/providers/zendmd.rb @@ -0,0 +1,123 @@ +#runs a command via zendmd +action :run do + Chef::Log.info "zenoss_zendmd:#{new_resource.name}\n" + Chef::Log.debug "#{new_resource.command}\n" + #write the content to a temp file + dmdscript = "#{rand(1000000)}.dmd" + file "/tmp/#{dmdscript}" do + backup false + owner "zenoss" + mode "0600" + content new_resource.command + action :create + end + #run the command as the zenoss user + execute "zendmd" do + user "zenoss" + command "#{node[:zenoss][:server][:zenhome]}/bin/zendmd --commit --script=#{dmdscript}" + action :run + end + #remove the temp file + file "/tmp/#{dmdscript}" do + action :delete + end +end + +#based on Device Class roles +action :deviceclass do + dclass = new_resource.name + command = "dmd.Devices.createOrganizer('#{dclass}')\n" + dmdpath = "dmd.Devices"+dclass.gsub('/', '.') + command += "#{dmdpath}.description='#{new_resource.description}'\n" + plugins = new_resource.modeler_plugins + if plugins and (plugins.length > 0) + pluginscommand = "#{dmdpath}.setZenProperty('zCollectorPlugins', (" + plugins.each {|p| pluginscommand += "'#{p}',"} + pluginscommand += "))\n" + command += pluginscommand + end + templates = new_resource.templates + if templates and (templates.length > 0) + templatescommand = "#{dmdpath}.setZenProperty('zDeviceTemplates', [" + templates.each {|t| templatescommand += "'#{t}',"} + templatescommand += "])\n" + command += templatescommand + end + properties = new_resource.properties + if properties + properties.each {|p, v| command += "#{dmdpath}.setZenProperty('#{p}','#{v}')\n"} + end + zenoss_zendmd "Setting Device Class #{dclass}" do + command command + action :run + end +end + +#based on Location roles +action :location do + location = new_resource.location + command = "dmd.Locations.createOrganizer('#{location}')\n" + dmdpath = "dmd.Locations" + location.gsub('/', '.') + command += "#{dmdpath}.name='#{new_resource.name}'\n" + command += "#{dmdpath}.description='#{new_resource.description}'\n" + command += "#{dmdpath}.address='#{new_resource.address}'\n" + zenoss_zendmd "Setting Location #{location}" do + command command + action :run + end +end + +#all non Device Class or Location roles +action :group do + name = new_resource.name + command = "dmd.Groups.createOrganizer('#{name}')\n" + command += "dmd.Groups.#{name}.description='#{new_resource.description}'\n" + zenoss_zendmd "Setting Group #{name}" do + command command + action :run + end +end + +#based on recipes used by nodes +action :system do + name = new_resource.name + command = "dmd.Systems.createOrganizer('#{name}')\n" + zenoss_zendmd "Setting System #{name}" do + command command + action :run + end +end + +action :users do + command = "" + new_resource.users.each do |user| + userid = user.id + if user.has_key?("zenoss") + password = user['zenoss']['password'] + pager = user['zenoss']['pager'] + email = user['zenoss']['email'] + roles = user['zenoss']['roles'] + user_groups = user['zenoss']['user_groups'] + end + command += "dmd.ZenUsers.manage_addUser('#{userid}'" + command += ", '#{password}'" if password + command += ", email='#{email}'" if email + command += ", pager='#{pager}'" if pager + if roles and (roles.length > 0) + command += ", roles=(" + roles.each {|r| command += "'#{r}',"} + command += ")" + end + command += ")\n" + if user_groups and (user_groups.length > 0) + user_groups.each {|g| command += "dmd.ZenUsers.manage_addGroup('#{g}')\n"} + command += "dmd.ZenUsers.manage_addUsersToGroups('#{userid}', (" + user_groups.each {|g| command += "'#{g}',"} + command += "))\n" + end + end + zenoss_zendmd "Creating users and user groups" do + command command + action :run + end +end diff --git a/zenoss/providers/zenpack.rb b/zenoss/providers/zenpack.rb new file mode 100644 index 000000000..170a2a56f --- /dev/null +++ b/zenoss/providers/zenpack.rb @@ -0,0 +1,65 @@ +# +# Author:: Matt Ray +# Cookbook Name:: zenoss +# Provider:: zenpack +# +# Copyright 2010, 2011 Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/mixin/shell_out' +require 'chef/mixin/language' +include Chef::Mixin::ShellOut + +action :install do + unless @zenpack.exists + zpfile = "#{new_resource.package}-#{new_resource.version}-#{new_resource.py_version}.egg" + Chef::Log.info "Installing the #{zpfile} ZenPack." + #download the ZenPack + remote_file "/tmp/#{zpfile}" do + source "http://dev.zenoss.com/zenpacks/#{zpfile}" + mode "0644" + action :create + end + #install the ZenPack + execute "zenpack --install" do + user "zenoss" + cwd "/tmp" + command "#{node[:zenoss][:server][:zenhome]}/bin/zenpack --install=#{zpfile}" + action :run + end + new_resource.updated_by_last_action(true) + end +end + +action :remove do + if @zenpack.exists + Chef::Log.info "Removing the #{new_resource.package} ZenPack." + execute "zenpack --remove" do + user "zenoss" + command "#{node[:zenoss][:server][:zenhome]}/bin/zenpack --remove=#{new_resource.package}" + action :run + end + new_resource.updated_by_last_action(true) + end +end + +#check if the zenpack is already installed +def load_current_resource + @zenpack = Chef::Resource::ZenossZenpack.new(new_resource.package) + Chef::Log.debug("Checking for ZenPack #{new_resource.name}") + zp = shell_out("sudo -u zenoss #{node[:zenoss][:server][:zenhome]}/bin/zenpack --list") + exists = zp.stdout.include?(new_resource.package) + @zenpack.exists(exists) +end diff --git a/zenoss/providers/zenpatch.rb b/zenoss/providers/zenpatch.rb new file mode 100644 index 000000000..0c1a3da3c --- /dev/null +++ b/zenoss/providers/zenpatch.rb @@ -0,0 +1,13 @@ +action :install do + patch = new_resource.svnpatch + #check if the patch is already applied + unless ::File.exists?("#{node[:zenoss][:server][:zenhome]}/Products/r#{patch}.patch") + Chef::Log.info "Applying patch #{patch} from ticket #{new_resource.ticket}." + #apply the patch + execute "#{node[:zenoss][:server][:zenhome]}/bin/zenpatch #{patch}" do + user "zenoss" + action :run + end + end +end + diff --git a/zenoss/recipes/client.rb b/zenoss/recipes/client.rb new file mode 100644 index 000000000..4b9cd2d61 --- /dev/null +++ b/zenoss/recipes/client.rb @@ -0,0 +1,60 @@ +# +# Author:: Matt Ray +# Cookbook Name:: zenoss +# Recipe:: client +# +# Copyright 2010, Zenoss, Inc +# Copyright 2010, Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "openssh" + +#create a 'zenoss' user for monitoring +user "zenoss" do + comment "Zenoss monitoring account" + home "/home/zenoss" + supports :manage_home => true + shell "/bin/bash" + action :create +end + +#create a home directory for them +directory "/home/zenoss/.ssh" do + owner "zenoss" + group "zenoss" + mode "0755" + recursive true + action :create +end + +#get the zenoss user public key via search +server = search(:node, 'recipes:zenoss\:\:server') || [] +if server.length > 0 + zenoss = server[0]["zenoss"] + if zenoss["server"] and zenoss["server"]["zenoss_pubkey"] + pubkey = zenoss["server"]["zenoss_pubkey"] + file "/home/zenoss/.ssh/authorized_keys" do + backup false + owner "zenoss" + mode "0600" + content pubkey + action :create + end + else + Chef::Log.info("No Zenoss server found, device is unmonitored.") + end +else + Chef::Log.info("No Zenoss server found, device is unmonitored.") +end diff --git a/zenoss/recipes/default.rb b/zenoss/recipes/default.rb new file mode 100644 index 000000000..92a1fe3cf --- /dev/null +++ b/zenoss/recipes/default.rb @@ -0,0 +1,21 @@ +# +# Author:: Matt Ray +# Cookbook Name:: zenoss +# Recipe:: default +# +# Copyright 2010, Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "zenoss::client" diff --git a/zenoss/recipes/server.rb b/zenoss/recipes/server.rb new file mode 100644 index 000000000..b9cd89698 --- /dev/null +++ b/zenoss/recipes/server.rb @@ -0,0 +1,195 @@ +# +# Author:: Matt Ray +# Cookbook Name:: zenoss +# Recipe:: server +# +# Copyright 2010, Zenoss, Inc +# Copyright 2010, 2011 Opscode, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include_recipe "openssh" +include_recipe "apt" + +# Zenoss apt repository +apt_repository "zenoss" do + uri "http://dev.zenoss.org/deb" + distribution "main" + components ["stable"] + action :add +end + +#Debian/Ubuntu specific required packages +packages = %w{ttf-liberation ttf-linux-libertine} +packages.each do |pkg| + apt_package pkg do + action :install + end +end + +#Zenoss hasn't signed their repository http://dev.zenoss.org/trac/ticket/7421 +apt_package "zenoss-stack" do + version node["zenoss"]["server"]["version"] + options "--allow-unauthenticated" + action :install +end + +#apply post 3.0.3 patches from http://dev.zenoss.com/trac/report/6 marked 'closed' +node["zenoss"]["server"]["zenpatches"].each do |patch, url| + zenoss_zenpatch patch do + ticket url + action :install + end +end + +#the Zenoss installer puts the service in place, just start it +service "zenoss" do + case node["platform"] + when "debian", "ubuntu" + service_name "zenoss-stack" + action [ :start ] + else + #need to have mysql restart too + service_name "zenoss" + end +end + +#skip the new install Wizard. +zenoss_zendmd "skip setup wizard" do + command "dmd._rq = True" + action :run +end + +#use zendmd to set the admin password +zenoss_zendmd "set admin pass" do + command "app.acl_users.userManager.updateUserPassword('admin', '#{node[:zenoss][:server][:admin_password]}')" + action :run +end + +#search the 'users' databag and pull out sysadmins for users and groups +zenoss_zendmd "add users" do + users search(:users, 'groups:sysadmin') || [] + action :users +end + +#put public key in an attribute +ruby_block "zenoss public key" do + block do + pubkey = IO.read("/home/zenoss/.ssh/id_dsa.pub") + node.set["zenoss"]["server"]["zenoss_pubkey"] = pubkey + node.save + #write out the authorized_keys for the zenoss user + ak = File.new("/home/zenoss/.ssh/authorized_keys", "w+") + ak.puts pubkey + ak.chown(File.stat("/home/zenoss/.ssh/id_dsa.pub").uid,File.stat("/home/zenoss/.ssh/id_dsa.pub").gid) + end + action :nothing +end + +#generate SSH key for the zenoss user +execute "ssh-keygen -q -t dsa -f /home/zenoss/.ssh/id_dsa -N \"\" " do + user "zenoss" + action :run + not_if {File.exists?("/home/zenoss/.ssh/id_dsa.pub")} + notifies :create, resources(:ruby_block => "zenoss public key"), :immediate +end + +#this list should get appended by other recipes +node["zenoss"]["server"]["installed_zenpacks"].each do |package, zpversion| + zenoss_zenpack "#{package}" do + version zpversion + action :install + notifies :restart, resources(:service => "zenoss"), :immediate + end +end + +#find the roles and push their settings in via zendmd +deviceclasslist = [] +locationlist = [] +grouplist = [] +search(:role, "*:*").each do |role| + if role.override_attributes["zenoss"] and role.override_attributes["zenoss"]["device"] + if role.override_attributes["zenoss"]["device"]["device_class"] + #add the role as a Device Class + deviceclasslist.push(role.name) + zenoss_zendmd role.override_attributes["zenoss"]["device"]["device_class"] do + description role.description + modeler_plugins role.default_attributes["zenoss"]["device"]["modeler_plugins"] + templates role.default_attributes["zenoss"]["device"]["templates"] + properties role.default_attributes["zenoss"]["device"]["properties"] + action :deviceclass + end + elsif role.override_attributes["zenoss"]["device"]["location"] + #add the role as a Location + locationlist.push(role.name) + zenoss_zendmd role.name do + location role.override_attributes["zenoss"]["device"]["location"] + description role.description + address role.override_attributes["zenoss"]["device"]["address"] + action :location + end + end + else + #create Groups for the rest of the roles + grouplist.push(role.name) + zenoss_zendmd role.name do + description role.description + action :group + end + end +end + +#move the localhost to SSH monitoring since we're not using SNMP +zenoss_zendmd "move Zenoss server" do + batch = "dmd.Devices.moveDevices('/Server/SSH/Linux/MySQL', '#{node[:fqdn]}')\n" + batch += "dev = dmd.Devices.findDevice('#{node[:fqdn]}')\n" + batch += "dev.setManageIp('#{node[:ipaddress]}')" + command batch + action :run +end + +#all nodes (for now, until pick a role or other flag to standardize on) +nodes = search(:node, 'zenoss:device*') +#find the recipes and create Systems for them +systems = [] +nodes.each {|node| systems.push(node.run_list.expand.recipes)} +systems.flatten! +systems.uniq! +#make suborganizers with recipes +systems.collect! {|sys| sys.gsub('::', '/')} +systems.each do |system| + zenoss_zendmd system do + action :system + end +end +#using the nodes list, write out a zenbatchload +#find all the device classes and the devices each one has. +devices = {} +nodes.each do |node| + if node.attribute["zenoss"] and node.attribute["zenoss"]["device"] + dclass = node.attribute["zenoss"]["device"]["device_class"] + if devices.has_key?(dclass) + devices[dclass].push(node) + else + devices[dclass] = [node] + end + end +end +zenoss_zenbatchload devices do + locations locationlist + groups grouplist + action :run +end + +#keep the previous zenbatchload run, diff it against the new list and only load the results of the diff. diff --git a/zenoss/resources/zenbatchload.rb b/zenoss/resources/zenbatchload.rb new file mode 100644 index 000000000..10e3656d3 --- /dev/null +++ b/zenoss/resources/zenbatchload.rb @@ -0,0 +1,5 @@ +actions :run + +attribute :devices, :kind_of => Hash, :default => {}, :name_attribute => true +attribute :locations, :kind_of => Array, :default => [] +attribute :groups, :kind_of => Array, :default => [] diff --git a/zenoss/resources/zendmd.rb b/zenoss/resources/zendmd.rb new file mode 100644 index 000000000..cbb7fba4d --- /dev/null +++ b/zenoss/resources/zendmd.rb @@ -0,0 +1,11 @@ +actions :run, :deviceclass, :group, :system, :location, :users + +attribute :name, :kind_of => String, :name_attribute => true +attribute :command, :kind_of => String #command to run via zendmd +attribute :description, :kind_of => String +attribute :modeler_plugins, :kind_of => Array, :default => [] +attribute :templates, :kind_of => Array, :default => [] +attribute :properties, :kind_of => Hash, :default => {} +attribute :location, :kind_of => String +attribute :address, :kind_of => String +attribute :users, :kind_of => Array, :default => [] diff --git a/zenoss/resources/zenpack.rb b/zenoss/resources/zenpack.rb new file mode 100644 index 000000000..2f363e372 --- /dev/null +++ b/zenoss/resources/zenpack.rb @@ -0,0 +1,7 @@ +actions :install, :remove + +#package name of the zenpack +attribute :package, :kind_of => String, :name_attribute => true +attribute :version, :kind_of => String +attribute :py_version, :kind_of =>String, :default => "py2.6" +attribute :exists, :default => false diff --git a/zenoss/resources/zenpatch.rb b/zenoss/resources/zenpatch.rb new file mode 100644 index 000000000..098e26236 --- /dev/null +++ b/zenoss/resources/zenpatch.rb @@ -0,0 +1,4 @@ +actions :install + +attribute :svnpatch, :kind_of => String, :name_attribute => true +attribute :ticket, :kind_of => String diff --git a/zenoss/roles/Class_Server-SSH-Linux-MySQL.rb b/zenoss/roles/Class_Server-SSH-Linux-MySQL.rb new file mode 100644 index 000000000..3c549250d --- /dev/null +++ b/zenoss/roles/Class_Server-SSH-Linux-MySQL.rb @@ -0,0 +1,38 @@ +name "ServerSSHLinuxMySQL" +description "Linux & MySQL monitoring via SSH" +default_attributes( + "zenoss" => { + "device" => { + "properties" => { + "zCommandUsername" => "zenoss", + "zKeyPath" => "/home/zenoss/.ssh/id_dsa", + "zMySqlPassword" => "zenoss", + "zMySqlUsername" => "zenoss" + } + # "modeler_plugins" => [ + # "zenoss.cmd.uname", + # "zenoss.cmd.uname_a", + # "zenoss.cmd.df", + # "zenoss.cmd.linux.cpuinfo", + # "zenoss.cmd.linux.memory", + # "zenoss.cmd.linux.ifconfig", + # "zenoss.cmd.linux.netstat_an", + # "zenoss.cmd.linux.netstat_rn", + # ], + # "templates" => ['Device'] + } + } + ) + +override_attributes( + "zenoss" => { + "device" => { + "device_class" => "/Server/SSH/Linux/MySQL" + } + } + ) + +#this could change to zenoss::client_mysqlssh or something eventually +run_list( + "recipe[zenoss::client]" + ) diff --git a/zenoss/roles/Class_Server-SSH-Linux.rb b/zenoss/roles/Class_Server-SSH-Linux.rb new file mode 100644 index 000000000..d96f20151 --- /dev/null +++ b/zenoss/roles/Class_Server-SSH-Linux.rb @@ -0,0 +1,24 @@ +name "ServerSSHLinux" +description "Linux monitoring via SSH" +#use the default modeler_plugins and templates for the device class +default_attributes( + "zenoss" => { + "device" => { + "properties" => { + "zCommandUsername" => "zenoss", + "zKeyPath" => "/home/zenoss/.ssh/id_dsa" + } + } + } + ) + +override_attributes( + "zenoss" => { + "device" => { + "device_class" => "/Server/SSH/Linux", + } + } + ) +run_list( + "recipe[zenoss::client]" + ) diff --git a/zenoss/roles/Location_Austin.rb b/zenoss/roles/Location_Austin.rb new file mode 100644 index 000000000..16dd56a04 --- /dev/null +++ b/zenoss/roles/Location_Austin.rb @@ -0,0 +1,10 @@ +name "Austin" +description "Opscode Austin" +override_attributes( + "zenoss" => { + "device" => { + "address" => "1005 W 38th Street\\nAustin, TX 78705", + "location" => "/Austin" + } + } + ) diff --git a/zenoss/roles/Location_Seattle.rb b/zenoss/roles/Location_Seattle.rb new file mode 100644 index 000000000..d9f1d0575 --- /dev/null +++ b/zenoss/roles/Location_Seattle.rb @@ -0,0 +1,10 @@ +name "Seattle" +description "Opscode HQ" +override_attributes( + "zenoss" => { + "device" => { + "address" => "1008 Western Ave\\nSeattle WA 98104", + "location" => "/Seattle" + } + } + ) diff --git a/zenoss/roles/ZenossServer.rb b/zenoss/roles/ZenossServer.rb new file mode 100644 index 000000000..f6b29541b --- /dev/null +++ b/zenoss/roles/ZenossServer.rb @@ -0,0 +1,28 @@ +name "ZenossServer" +description "Role to use as basis for configuring Zenoss Server" +#a number of server attributes are available for customization +#you may want to set the [:zenoss][:server][:admin_password] +default_attributes( + "zenoss" => { + "device" => { + "properties" => { + "zCommandUsername" => "zenoss", + "zKeyPath" => "/home/zenoss/.ssh/id_dsa", + "zMySqlPassword" => "zenoss", + "zMySqlUsername" => "zenoss" + } + } + } + ) + +override_attributes( + "zenoss" => { + "device" => { + "device_class" => "/Server/SSH/Linux/MySQL" + } + } + ) + +run_list( + "recipe[zenoss::server]" + )