cycle_chef_handler 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.autotest ADDED
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 1.2.0 / 2011-08-30
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,8 @@
1
+ .autotest
2
+ History.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/cycle_chef_handler
7
+ lib/cycle_chef_handler.rb
8
+ test/test_cycle_chef_handler.rb
data/README.txt ADDED
@@ -0,0 +1,86 @@
1
+ = cycle_chef_handler
2
+
3
+ * http://github.com/cyclecomputing/cycle_chef_handler
4
+ * http://www.cyclecomputing.com
5
+
6
+ == DESCRIPTION:
7
+
8
+ This extension of Chef::Handler creates reports in Condor class ad format and posts
9
+ them to an amqp-complient message broker. This report handler was created to produce
10
+ reports for the CycleServer Chef Dashboard available from Cycle Computing LLC.
11
+
12
+ == REQUIREMENTS:
13
+
14
+ * chef
15
+ * classad
16
+ * bunny
17
+
18
+ == INSTALL:
19
+
20
+ * sudo gem install cycle_chef_handler
21
+ * edit /etc/chef/client.rb on client nodes:
22
+
23
+ require 'cycle_chef_handler'
24
+
25
+ handler = CycleChefHandler.new(:amqp_config => {:host => 'my_amqp_hostname'})
26
+
27
+ report_handlers << handler
28
+ exception_handlers << handler
29
+
30
+ == ADVANCED USAGE:
31
+
32
+ The constructor takes a hash with the following keys:
33
+
34
+ :amqp_config
35
+ This key should point to a configuration hash suitable for Bunny.new(), including:
36
+
37
+ * :host Host name of amqp broker
38
+ * :port Port of amqp borker, default value = 5672
39
+ * :vhost Name of virtual host on amqp broker, default value = '/'
40
+ * :user User name on amqp broker, default value = 'guest'
41
+ * :pass Password for :user on amqp broker, default value = 'guest'
42
+ * :queue Queue name to be used to read report messages, default value = 'chef.converges'
43
+ * :exchange Exchange name to be used to post report messages, default value = 'chef.converges'
44
+
45
+ :extras
46
+ This optional key may be used to pass arbitrary key, value pairs to the chef report classad.
47
+ It may be used to tag chef clients to make it easier to slice and dice the report information.
48
+ I use it (along with the ec2_metadata gem) to add Amazon Web Services EC2 instance data to
49
+ the report.
50
+
51
+ :extras => {'InstanceId' => Ec2Metadata[:instance_id],
52
+ 'AvailabilityZone' => Ec2Metadata[:placement][:availability_zone],
53
+ 'PublicHostName' => Ec2Metadata[:public_hostname]}
54
+
55
+ :converge_index_file
56
+ This should point to a file where CycleChefHandler will keep track of the number of
57
+ converges that have been attempted. Its default value is /var/run/chef/converge_index.
58
+
59
+ :failed_converge_count_file
60
+ This should point to a file where CycleChefHandler will keep track of the number of
61
+ consecutive failed converges. Its default value is /var/run/chef/failed_converge_count.
62
+
63
+ == DEVELOPERS:
64
+
65
+ After checking out the source, run:
66
+
67
+ $ rake newb
68
+
69
+ This task will install any missing dependencies, run the tests/specs,
70
+ and generate the RDoc.
71
+
72
+ == LICENSE:
73
+
74
+ Copyright 2011 Cycle Computing LLC
75
+
76
+ Licensed under the Apache License, Version 2.0 (the "License");
77
+ you may not use this file except in compliance with the License.
78
+ You may obtain a copy of the License at
79
+
80
+ http://www.apache.org/licenses/LICENSE-2.0
81
+
82
+ Unless required by applicable law or agreed to in writing, software
83
+ distributed under the License is distributed on an "AS IS" BASIS,
84
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
85
+ See the License for the specific language governing permissions and
86
+ limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require 'fileutils'
6
+ require File.join(File.dirname(__FILE__), 'lib', 'cycle_chef_handler')
7
+
8
+ # copy README.rdoc to README.txt
9
+ FileUtils.cp File.join(File.dirname(__FILE__), 'README.rdoc'), File.join(File.dirname(__FILE__), 'README.txt')
10
+
11
+ # we don't use rubyforge
12
+ Hoe.plugins.delete :rubyforge
13
+
14
+ Hoe.spec 'cycle_chef_handler' do
15
+ developer('Chris Chalfant', 'chris.chalfant@cyclecomputing.com')
16
+ extra_deps << ['chef']
17
+ extra_deps << ['bunny']
18
+ extra_deps << ['classad']
19
+ end
20
+
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
@@ -0,0 +1,167 @@
1
+ # cycle_chef_handler.rb
2
+ #
3
+ # Report handler for chef clients to be used with CycleServer Chef Dashboard
4
+ #
5
+ # Author: Chris Chalfant (chris.chalfant@cyclecomputing.com)
6
+ #
7
+ # Copyright 2010 Cycle Computing LLC
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ require 'rubygems'
22
+ require 'chef'
23
+ require 'bunny'
24
+ require 'classad'
25
+ require 'fileutils'
26
+ require 'uri'
27
+
28
+ class CycleChefHandler < Chef::Handler
29
+ VERSION = '1.2.0'
30
+
31
+ def initialize(params)
32
+ defaults = {:queue => 'chef.converges',
33
+ :exchange => 'chef.converges'}
34
+
35
+ @amqp_config = defaults.merge(params[:amqp_config])
36
+ check_amqp_config
37
+
38
+ @extras = params[:extras]
39
+ @converge_index_file = params[:converge_index_file] || '/var/run/chef/converge_index'
40
+ @failed_converge_file = params[:failed_converge_count_file] || '/var/run/chef/failed_converge_count'
41
+ end
42
+
43
+ def check_amqp_config
44
+ [:host, :queue, :exchange].each do |i|
45
+ if not @amqp_config[i]
46
+ raise ArgumentError, ":amqp_config missing value for #{i}"
47
+ end
48
+ end
49
+ end
50
+
51
+ def report
52
+
53
+ ## Create and Post a classad
54
+ ad = create_ad
55
+ payload = "<classads>" + ad.to_xml + "</classads>"
56
+
57
+ begin
58
+
59
+ b = Bunny.new(@amqp_config)
60
+
61
+ b.start
62
+ e = b.exchange(@amqp_config[:exchange],
63
+ :type => :topic,
64
+ :durable => true,
65
+ :auto_delete => false)
66
+
67
+ # declare and bind a non-auto-delete queue here to make sure we don't
68
+ # lose any messages posted to an exchange w/o a bound queue
69
+ # make the queue non-durable so we can drop it with a broker reboot
70
+ q = b.queue(@amqp_config[:queue], :auto_delete => false)
71
+ q.bind(@amqp_config[:exchange], :key => @amqp_config[:queue])
72
+
73
+ e.publish(payload, :key => @amqp_config[:queue])
74
+
75
+ rescue Exception => e
76
+
77
+ # log any exceptions, but don't throw one.
78
+ trace = e.backtrace.join("\n")
79
+ Chef::Log.error("Failed to post converge history report: #{e.message} #{trace}")
80
+ return
81
+
82
+ ensure
83
+
84
+ b.stop
85
+
86
+ end
87
+
88
+ Chef::Log.info("Posted converge history report")
89
+
90
+ end
91
+
92
+ def create_ad
93
+ ad = ClassAd.new
94
+ ad['AdType'] = 'Chef.Host'
95
+ ad['ChefNode'] = Chef::Config[:node_name]
96
+ ad['ConvergeStartTime'] = start_time
97
+ ad['ConvergeEndTime'] = end_time
98
+ ad['ConvergeElapsedTime'] = RelativeTime.new(elapsed_time)
99
+
100
+ updated = []
101
+ if not updated_resources.nil?
102
+ updated = updated_resources.map {|x| x.to_s}
103
+ end
104
+
105
+ ad['UpdatedResources'] = updated
106
+ ad['UpdatedResourcesCount'] = updated.size
107
+ ad['ConvergeIndex'] = increment_count_file(@converge_index_file)
108
+ ad['ChefServerUrl'] = Chef::Config[:chef_server_url]
109
+ ad['ChefServerHostName'] = URI.parse(Chef::Config[:chef_server_url]).host
110
+ ad['ChefClientVersion'] = Chef::VERSION
111
+ ad['CycleChefHandlerVersion'] = CycleChefHandler::VERSION
112
+ ad['Success'] = success?
113
+
114
+ exception = nil
115
+ backtrace = nil
116
+ if failed?
117
+ exception = run_status.formatted_exception
118
+ backtrace = run_status.backtrace
119
+ ad['FailedConvergeCount'] = increment_count_file(@failed_converge_file)
120
+ else
121
+ clear_count_file(@failed_converge_file)
122
+ ad['FailedConvergeCount'] = 0
123
+ end
124
+
125
+ ad['Exception'] = exception
126
+ ad['Backtrace'] = backtrace
127
+
128
+ @extras.each do |k,v|
129
+ ad[k] = v
130
+ end
131
+
132
+ ad
133
+ end
134
+
135
+ def increment_count_file(count_file)
136
+ file_dir = File.dirname(count_file)
137
+ if not File.directory? file_dir
138
+ FileUtils.mkdir_p file_dir
139
+ end
140
+
141
+ count = nil
142
+ if File.exists? count_file
143
+ File.open(count_file) do |file|
144
+ count = file.readline.chomp.to_i
145
+ end
146
+ end
147
+
148
+ if count.nil?
149
+ count = 1
150
+ else
151
+ count += 1
152
+ end
153
+
154
+ File.open(count_file, "w") do |file|
155
+ file.puts(count)
156
+ end
157
+
158
+ count
159
+ end
160
+
161
+ def clear_count_file(count_file)
162
+ if File.exist? count_file
163
+ FileUtils.rm count_file
164
+ end
165
+ end
166
+
167
+ end
@@ -0,0 +1,27 @@
1
+ require "test/unit"
2
+ require "cycle_chef_handler"
3
+
4
+ class TestCycleChefHandler < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @index_file = File.join(File.dirname(__FILE__), 'index')
8
+ @handler = CycleChefHandler.new(:amqp_config => {:host=> 'h'},
9
+ :converge_index_file => @index_file )
10
+ end
11
+
12
+ def teardown
13
+ File.unlink @index_file if File.exist? @index_file
14
+ end
15
+
16
+ def test_increment
17
+ assert_equal(1, @handler.increment_count_file(@index_file))
18
+ assert_equal(2, @handler.increment_count_file(@index_file))
19
+ end
20
+
21
+ def test_reset
22
+ assert_equal(1, @handler.increment_count_file(@index_file))
23
+ assert_equal(2, @handler.increment_count_file(@index_file))
24
+ @handler.clear_count_file(@index_file)
25
+ assert_equal(1, @handler.increment_count_file(@index_file))
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cycle_chef_handler
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 2
9
+ - 0
10
+ version: 1.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Chris Chalfant
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-08-30 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: chef
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: bunny
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: classad
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: hoe
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 19
71
+ segments:
72
+ - 2
73
+ - 6
74
+ - 2
75
+ version: 2.6.2
76
+ type: :development
77
+ version_requirements: *id004
78
+ description: |-
79
+ This extension of Chef::Handler creates reports in Condor class ad format and posts
80
+ them to an amqp-complient message broker. This report handler was created to produce
81
+ reports for the CycleServer Chef Dashboard available from Cycle Computing LLC.
82
+ email:
83
+ - chris.chalfant@cyclecomputing.com
84
+ executables:
85
+ - cycle_chef_handler
86
+ extensions: []
87
+
88
+ extra_rdoc_files:
89
+ - History.txt
90
+ - Manifest.txt
91
+ - README.txt
92
+ files:
93
+ - .autotest
94
+ - History.txt
95
+ - Manifest.txt
96
+ - README.txt
97
+ - Rakefile
98
+ - bin/cycle_chef_handler
99
+ - lib/cycle_chef_handler.rb
100
+ - test/test_cycle_chef_handler.rb
101
+ homepage: http://github.com/cyclecomputing/cycle_chef_handler
102
+ licenses: []
103
+
104
+ post_install_message:
105
+ rdoc_options:
106
+ - --main
107
+ - README.txt
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 3
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ hash: 3
125
+ segments:
126
+ - 0
127
+ version: "0"
128
+ requirements: []
129
+
130
+ rubyforge_project: cycle_chef_handler
131
+ rubygems_version: 1.8.7
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: This extension of Chef::Handler creates reports in Condor class ad format and posts them to an amqp-complient message broker
135
+ test_files:
136
+ - test/test_cycle_chef_handler.rb