lita-puppet 0.6.1 → 0.6.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 24922d792c78cac0dbc47d19319680e6d4aa8e65
4
- data.tar.gz: af23e3bb3dce2e5a053356a8ae03128b5d18b426
3
+ metadata.gz: 9d628affc13749d488e0425795d1c186529d6aa1
4
+ data.tar.gz: 9d6b10693e3ecccab9e6250b5a6dda87fc7abc25
5
5
  SHA512:
6
- metadata.gz: 3fa73002df79c370f7d4717d99a5b8784ab3a1fd4435e7ebf7e9d36f91e52aea1d2220dd50869ca3ad6d3d2089256f96b0525a2f3560f5a63dce0d0d398e3bee
7
- data.tar.gz: 969b0634bc6f682a5118b16a7c08c904deff71f2d640632964ae079c2ca61fccb5c2335baf599942a885a8d1c1df37276d6cc0dd22db83b38afb04e46b7bc7a7
6
+ metadata.gz: 33df42ee1cb7799138a0b829423cbe5d6316da8eff92f0c856695bf5143e8f4214f5ebab06291d9297e2524628ef6a09ae021a77fece2cd25b3696cbe29b2709
7
+ data.tar.gz: a7e34d69a70957729c495f40bef7d835d140a99a722bbdf57e16d192758f741d9a49a0a887b7727e458a4352b65f5e577f41a8860fe3195f3564dbf7a2b9b026
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ Documentation:
2
+ Exclude:
3
+ - lib/lita/handlers/puppet.rb
4
+
5
+ FileName:
6
+ Exclude:
7
+ - lib/lita-puppet.rb
8
+
9
+ Metrics/LineLength:
10
+ Max: 100
11
+
12
+ Metrics/AbcSize:
13
+ Max: 22
14
+
15
+ Metrics/MethodLength:
16
+ Max: 20
17
+
18
+ Metrics/ClassLength:
19
+ Max: 150
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.5
4
+ - 2.3.1
5
+ services:
6
+ - redis-server
7
+ cache: bundler
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # lita-puppet
2
2
 
3
+ [![Build Status](https://img.shields.io/travis/knuedge/lita-puppet/master.svg)](https://travis-ci.org/knuedge/lita-puppet)
4
+ [![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://tldrlegal.com/license/mit-license)
5
+ [![RubyGems :: RMuh Gem Version](http://img.shields.io/gem/v/lita-puppet.svg)](https://rubygems.org/gems/lita-puppet)
6
+ [![Code Climate](https://img.shields.io/codeclimate/github/knuedge/lita-puppet.svg)](https://codeclimate.com/github/knuedge/lita-puppet)
7
+
3
8
  A [Lita](https://www.lita.io/) handler plugin for some basic [Puppet](https://puppet.com/) operations.
4
9
 
5
10
  ## Installation
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new(:rubocop)
5
7
 
6
- task default: :spec
8
+ task default: [:spec, :rubocop]
data/lib/lita-puppet.rb CHANGED
@@ -1,18 +1,18 @@
1
- require "lita"
1
+ require 'lita'
2
2
  require 'rye'
3
3
  require 'timeout'
4
4
  require 'puppetdb'
5
5
 
6
6
  Lita.load_locales Dir[File.expand_path(
7
- File.join("..", "..", "locales", "*.yml"), __FILE__
7
+ File.join('..', '..', 'locales', '*.yml'), __FILE__
8
8
  )]
9
9
 
10
- require 'utils/puppetdb'
11
- require 'utils/ssh'
12
- require 'utils/text'
13
- require "lita/handlers/puppet"
10
+ require 'utils/lita_puppet/puppetdb'
11
+ require 'utils/lita_puppet/ssh'
12
+ require 'utils/lita_puppet/text'
13
+ require 'lita/handlers/puppet'
14
14
 
15
15
  Lita::Handlers::Puppet.template_root File.expand_path(
16
- File.join("..", "..", "templates"),
17
- __FILE__
16
+ File.join('..', '..', 'templates'),
17
+ __FILE__
18
18
  )
@@ -3,225 +3,185 @@ module Lita
3
3
  class Puppet < Handler
4
4
  namespace 'Puppet'
5
5
  config :master_hostname, required: true, type: String
6
- config :ssh_user, required: false, type: String
7
- config :control_repo_path, required: false, type: String
6
+ config :ssh_user, required: false, type: String, default: 'lita'
7
+ config :control_repo_path, required: false, type: String, default: '/opt/puppet/control'
8
8
  config :puppetdb_url, required: false, type: String
9
9
 
10
10
  route(
11
11
  /(puppet|pp)(\s+agent)?\s+(run)(\s+on)?\s+(\S+)/i,
12
12
  :puppet_agent_run,
13
13
  command: true,
14
- help: {
15
- "puppet agent run on <host>" => "Run the puppet agent on <host>."
16
- }
14
+ help: { t('help.puppet_agent_run.syntax') => t('help.puppet_agent_run.desc') }
17
15
  )
18
16
 
19
17
  route(
20
18
  /(puppet|pp)\s+(cert)\s+(clean)\s+(\S+)/i,
21
19
  :cert_clean,
22
20
  command: true,
23
- help: {
24
- "puppet cert clean <host>" => "Remove all traces of the SSL cert for <host> on the Puppet Master."
25
- }
21
+ help: { t('help.cert_clean.syntax') => t('help.cert_clean.desc') }
26
22
  )
27
23
 
28
24
  route(
29
25
  /(puppet|pp)\s+(catalog|node)\s+(\S+)\s+(profiles)/i,
30
26
  :node_profiles,
31
27
  command: true,
32
- help: {
33
- "puppet catalog <host> profiles" => "Query PuppetDB to get a list of all roles and profiles applied to <host>."
34
- }
28
+ help: { t('help.node_profiles.syntax') => t('help.node_profiles.desc') }
35
29
  )
36
30
 
37
31
  route(
38
32
  /(puppet|pp)\s+(class)\s+(nodes)\s+(\S+)/i,
39
33
  :nodes_with_class,
40
34
  command: true,
41
- help: {
42
- "puppet class nodes <class>" => "Query PuppetDB to get a list of all nodes containing a class."
43
- }
35
+ help: { t('help.nodes_with_class.syntax') => t('help.nodes_with_class.desc') }
44
36
  )
45
37
 
46
38
  route(
47
39
  /(puppet|pp)\s+(r10k|deploy)(\s+(\S+)(\s+(\S+))?)?/i,
48
40
  :r10k_deploy,
49
41
  command: true,
50
- help: {
51
- "puppet r10k [env [module]]" => "Deploy the latest puppet code on the puppet master via r10k, optionally specifying an environment, and possibly a module."
52
- }
42
+ help: { t('help.r10k_deploy.syntax') => t('help.r10k_deploy.desc') }
53
43
  )
54
44
 
55
- include ::Utils::PuppetDB
56
- include ::Utils::SSH
57
- include ::Utils::Text
45
+ include ::Utils::LitaPuppet::PuppetDB
46
+ include ::Utils::LitaPuppet::SSH
47
+ include ::Utils::LitaPuppet::Text
58
48
 
59
49
  def cert_clean(response)
60
50
  cert = response.matches[0][3]
61
- user = config.ssh_user || 'lita'
62
- username = friendly_name(response.user.name)
63
51
 
64
- response.reply("#{username}, working on that `puppet cert clean`. I'll get right back to you.")
52
+ response.reply_with_mention(t('replies.cert_clean.working'))
65
53
 
66
- result = over_ssh(host: config.master_hostname, user: user, timeout: 120) do |server|
67
- server.cd '/tmp'
68
- # Need to use sudo
69
- server.enable_sudo
70
- # scary...
71
- server.disable_safe_mode
72
-
73
- server.execute "puppet cert clean #{cert} 2>&1"
74
- end
54
+ result = cert_clean_result(config.master_hostname, config.ssh_user, cert)
75
55
 
76
56
  if result[:exception]
77
- response.reply "#{username}, your `puppet cert clean` didn't seem to work... ;-("
78
- response.reply as_code(result[:exception].message)
79
- return false
57
+ fail_message t('replies.cert_clean.failure'), result[:exception].message
58
+ else
59
+ success_message(
60
+ t('replies.cert_clean.success'),
61
+ (result[:stdout] + result[:stderr]).join("\n")
62
+ )
80
63
  end
81
-
82
- # build a reply
83
- response.reply("#{username}, your `puppet cert clean` is all done!")
84
- reply_content = [result[:stdout].join("\n"), result[:stderr].join("\n")].join("\n")
85
- response.reply as_code(reply_content)
86
64
  end
87
65
 
88
66
  def puppet_agent_run(response)
89
67
  host = response.matches[0][4]
90
- user = config.ssh_user || 'lita'
91
- username = friendly_name(response.user.name)
92
68
 
93
- response.reply("#{username}, I'll run puppet right away. Give me a sec and I'll let you know how it goes.")
69
+ response.reply_with_mention(t('replies.puppet_agent_run.working'))
94
70
 
95
- result = over_ssh(host: host, user: user) do |server|
96
- server.cd '/tmp'
97
-
98
- # Need to use sudo from here on
99
- server.enable_sudo
100
-
101
- # scary...
102
- server.disable_safe_mode
103
-
104
- # build up the command
105
- command = 'puppet agent'
106
- command << ' --onetime --verbose --no-daemonize'
107
- command << ' --no-usecacheonfailure'
108
- command << ' --no-splay --show_diff 2>&1'
109
-
110
- server.execute command
111
- end
71
+ result = simple_ssh_command(host, config.ssh_user, agent_command)
112
72
 
113
73
  # build a reply
114
- if !result[:exception]
115
- response.reply "#{username}, that puppet run is complete! It exited with status #{result[:exit_status]}."
116
- # Send the standard out, but strip off the bash color code stuff...
117
- response.reply as_code(result[:stdout].join("\n"))
74
+ if result[:exception]
75
+ fail_message t('replies.puppet_agent_run.failure'), result[:exception].message
118
76
  else
119
- response.reply "#{username}, your puppet run is done, but didn't seem to work... I think it may have timed out."
120
- response.reply as_code(result[:exception].message)
77
+ success_message(
78
+ t('replies.puppet_agent_run.success', status: result[:exit_status]),
79
+ result[:stdout].join("\n")
80
+ )
121
81
  end
122
82
  end
123
83
 
124
84
  def node_profiles(response)
125
85
  host = response.matches[0][2]
126
86
  url = config.puppetdb_url
127
- username = friendly_name(response.user.name)
128
87
 
129
88
  unless url
130
- cant_reply = "#{username}, I would do that, but I don't know how to connect to PuppetDB."
131
- cant_reply << "Edit my config and add `config.handlers.puppet.puppetdb_url`."
132
- response.reply(cant_reply)
89
+ response.reply(t('replies.node_profiles.notconf'))
133
90
  return false
134
91
  end
135
92
 
136
- response.reply("#{username}, let me see what I can find in PuppetDB for you.")
93
+ response.reply_with_mention(t('replies.node_profiles.working'))
137
94
 
138
95
  profiles = node_roles_and_profiles(url, host)
96
+
139
97
  if profiles.is_a? String
140
- response.reply("Hmmm, that didn't work. Here's what PuppetDB responded with: '#{profiles}'")
141
- return false
98
+ fail_message t('replies.node_profiles.failure', error: profiles)
142
99
  else
143
- response.reply("Here are the profiles and roles for #{host}:")
144
- response.reply as_code(profiles.join("\n"))
100
+ success_message t('replies.node_profiles.success', host: host), profiles.join("\n")
145
101
  end
146
102
  end
147
103
 
148
104
  def nodes_with_class(response)
149
105
  puppet_class = response.matches[0][3]
150
106
  url = config.puppetdb_url
151
- username = friendly_name(response.user.name)
152
107
 
153
108
  unless url
154
- cant_reply = "#{username}, I would do that, but I don't know how to connect to PuppetDB."
155
- cant_reply << "Edit my config and add `config.handlers.puppet.puppetdb_url`."
156
- response.reply(cant_reply)
109
+ response.reply(t('replies.nodes_with_class.notconf'))
157
110
  return false
158
111
  end
159
112
 
160
- response.reply("#{username}, let me see what I can find in PuppetDB for you.")
161
-
162
- search = class_camel(puppet_class)
163
- puppet_classes = class_nodes(url, search)
113
+ response.reply_with_mention(t('replies.nodes_with_class.working'))
114
+
115
+ puppet_classes = class_nodes(url, class_camel(puppet_class))
164
116
  if puppet_classes.empty?
165
- response.reply("There are no nodes with #{puppet_class} class, are you sure its a valid class?")
166
- return false
117
+ fail_message t('replies.nodes_with_class.failure', pclass: puppet_class)
167
118
  else
168
- response.reply("Here are all the nodes with class #{puppet_class}:")
169
- response.reply as_code(puppet_classes.join("\n"))
119
+ success_message(
120
+ t('replies.nodes_with_class.success', pclass: puppet_class),
121
+ puppet_classes.join("\n")
122
+ )
170
123
  end
171
124
  end
172
125
 
173
-
126
+ # rubocop:disable Metrics/AbcSize
174
127
  def r10k_deploy(response)
175
128
  environment = response.matches[0][3]
176
129
  mod = response.matches[0][5]
177
- control_repo = config.control_repo_path || '/opt/puppet/control'
178
- user = config.ssh_user || 'lita'
179
- username = friendly_name(response.user.name)
130
+ user = config.ssh_user
180
131
 
181
- response.reply("#{username}, I'll get right on that. Give me a moment and I'll let you know how it went.")
132
+ response.reply_with_mention(t('replies.r10k_deploy.working'))
182
133
 
183
- result1 = over_ssh(host: config.master_hostname, user: user, timeout: 120) do |server|
184
- # Need to use sudo
185
- server.enable_sudo
186
- server[control_repo].git :pull
187
- end
134
+ result1 = r10k_git_result(config.master_hostname, user, config.control_repo_path)
188
135
 
189
136
  if result1[:exception]
190
- response.reply "#{username}, your r10k run didn't seem to work. Looks like there was a problem with Git:"
191
- response.reply as_code(result1[:exception].message)
137
+ fail_message t('replies.r10k_deploy.gitfail'), result1[:exception].message
192
138
  return false
193
139
  end
194
140
 
195
- result2 = over_ssh(host: config.master_hostname, user: user) do |server|
141
+ result2 = simple_ssh_command(config.master_hostname, user, r10k_command(environment, mod))
142
+
143
+ if result2[:exception]
144
+ fail_message t('replies.r10k_deploy.pupfail'), result2[:exception].message
145
+ else
146
+ success_message(
147
+ t('replies.r10k_deploy.success'),
148
+ [result1[:stdout].join("\n"), result2[:stderr].join("\n")].join("\n")
149
+ )
150
+ end
151
+ end
152
+
153
+ private
154
+
155
+ def fail_message(message, data = nil)
156
+ response.reply_with_mention(message)
157
+ response.reply(as_code(data)) if data
158
+ end
159
+
160
+ alias success_message fail_message
161
+
162
+ def simple_ssh_command(host, user, command, timeout = 300)
163
+ over_ssh(host: host, user: user, timeout: timeout) do |server|
164
+ server.cd '/tmp'
196
165
  # Need to use sudo
197
166
  server.enable_sudo
198
167
  # scary...
199
168
  server.disable_safe_mode
200
169
 
201
- command = "r10k deploy"
202
- if environment && mod
203
- command << ' module'
204
- command << " -e #{environment}"
205
- command << " #{mod}"
206
- command << " -v"
207
- else
208
- command << " environment"
209
- command << " #{environment}" if environment
210
- command << ' -pv'
211
- end
212
170
  server.execute command
213
171
  end
172
+ end
214
173
 
215
- if result2[:exception]
216
- response.reply "#{username}, your r10k run didn't seem to work... Maybe it timed out?"
217
- response.reply as_code(result2[:exception].message)
218
- return false
219
- end
174
+ def cert_clean_result(host, user, cert)
175
+ cmd = "puppet cert clean #{cert} 2>&1"
176
+ simple_ssh_command(host, user, cmd, 120)
177
+ end
220
178
 
221
- # build a reply
222
- response.reply("#{username}, your r10k deployment is done!")
223
- reply_content = [result1[:stdout].join("\n"), result2[:stderr].join("\n")].join("\n")
224
- response.reply as_code(reply_content)
179
+ def r10k_git_result(host, user, repo_location)
180
+ over_ssh(host: host, user: user, timeout: 120) do |server|
181
+ # Need to use sudo
182
+ server.enable_sudo
183
+ server[repo_location].git :pull
184
+ end
225
185
  end
226
186
 
227
187
  Lita.register_handler(self)
@@ -0,0 +1,39 @@
1
+ module Utils
2
+ module LitaPuppet
3
+ # Utility methods for working with PuppetDB
4
+ module PuppetDB
5
+ def dbquery(url, q)
6
+ # TODO: validate incoming query structure
7
+ client = ::PuppetDB::Client.new(server: url)
8
+ client.request(*q)
9
+ end
10
+
11
+ def node_roles_and_profiles(url, nodename)
12
+ # TODO: validate url and nodename
13
+ ::PuppetDB::Client.new(server: url) # this is weird but required
14
+ d = ::PuppetDB::Client.get("/catalogs/#{nodename}")
15
+ return d['error'] if d['error']
16
+
17
+ tags = []
18
+ d['data']['resources'].each { |r| tags.concat(r['tags']) }
19
+
20
+ # return all the tags related to profile:: or role::
21
+ tags.sort.uniq.select { |t| t.match(/^(profile|role)::/) }
22
+ end
23
+
24
+ def class_nodes(url, classname)
25
+ client = ::PuppetDB::Client.new(server: url)
26
+ q = client.request(
27
+ 'resources',
28
+ [
29
+ :and,
30
+ [:'=', 'type', 'Class'],
31
+ [:'=', 'title', classname.to_s]
32
+ ]
33
+ )
34
+
35
+ q.data.map { |node| node['certname'] }
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ module Utils
2
+ module LitaPuppet
3
+ # Utility methods for doing things over SSH
4
+ module SSH
5
+ # Intelligently do some things over SSH
6
+ def over_ssh(opts = {})
7
+ raise 'MissingSSHHost' unless opts[:host]
8
+ raise 'MissingSSHUser' unless opts[:user]
9
+ opts[:timeout] ||= 300 # default to a 5 minute timeout
10
+
11
+ remote = Rye::Box.new(
12
+ opts[:host],
13
+ user: opts[:user],
14
+ auth_methods: ['publickey'],
15
+ password_prompt: false,
16
+ error: STDOUT # send STDERR to STDOUT for things that actually print
17
+ )
18
+
19
+ exception = nil
20
+
21
+ # Getting serious about not crashing Lita...
22
+ output = begin
23
+ # pass our host back to the user to work with
24
+ Timeout.timeout(opts[:timeout]) { yield remote }
25
+ rescue Rye::Err, StandardError => e
26
+ exception = e
27
+ ensure
28
+ remote.disconnect
29
+ end
30
+
31
+ calculate_result(output, exception)
32
+ end
33
+
34
+ def calculate_result(output, exception)
35
+ result = {}
36
+ if exception
37
+ result[:exception] = exception
38
+ else
39
+ result[:exit_status] = output.exit_status
40
+ result[:stdout] = output.stdout
41
+ result[:stderr] = output.stderr
42
+ end
43
+ result
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ module Utils
2
+ module LitaPuppet
3
+ # Utility methods for manipulating text
4
+ module Text
5
+ # Strip off bad characters
6
+ def sanitze_for_chat(text)
7
+ # Remove bash colorings
8
+ text.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]/, '')
9
+ end
10
+
11
+ # camel case puppet classes
12
+ def class_camel(text)
13
+ text.split('::').map(&:capitalize).join('::')
14
+ end
15
+
16
+ # Format some text as code
17
+ # Note that this is HipChat specific for the moment
18
+ # TODO: Make this *not* HipChat specific
19
+ def as_code(text)
20
+ '/code ' + sanitze_for_chat(text)
21
+ end
22
+
23
+ def r10k_command(environment, mod)
24
+ command = 'r10k deploy'
25
+ if environment && mod
26
+ command << " module -e #{environment} #{mod} -v"
27
+ else
28
+ command << ' environment'
29
+ command << " #{environment}" if environment
30
+ command << ' -pv'
31
+ end
32
+ end
33
+
34
+ def agent_command
35
+ command = 'puppet agent'
36
+ command << ' --onetime --verbose --no-daemonize'
37
+ command << ' --no-usecacheonfailure'
38
+ command << ' --no-splay --show_diff 2>&1'
39
+ end
40
+ end
41
+ end
42
+ end
data/lita-puppet.gemspec CHANGED
@@ -1,26 +1,29 @@
1
1
  Gem::Specification.new do |spec|
2
- spec.name = "lita-puppet"
3
- spec.version = "0.6.1"
4
- spec.authors = ["Daniel Schaaff", "Jonathan Gnagy"].sort
5
- spec.email = ["jgnagy@knuedge.com"]
6
- spec.description = "Some basic Puppet interactions for Lita"
7
- spec.summary = "Allow the Lita bot to handle requests for puppet tasks"
8
- spec.homepage = "https://github.com/knuedge/lita-puppet"
2
+ spec.name = 'lita-puppet'
3
+ spec.version = '0.6.2'
4
+ spec.authors = ['Daniel Schaaff', 'Jonathan Gnagy'].sort
5
+ spec.email = ['jgnagy@knuedge.com']
6
+ spec.description = 'Some basic Puppet interactions for Lita'
7
+ spec.summary = 'Allow the Lita bot to handle requests for puppet tasks'
8
+ spec.homepage = 'https://github.com/knuedge/lita-puppet'
9
9
  spec.license = 'MIT'
10
- spec.metadata = { "lita_plugin_type" => "handler" }
10
+ spec.metadata = { 'lita_plugin_type' => 'handler' }
11
11
 
12
- spec.files = `git ls-files`.split($/)
12
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
13
13
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
14
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
- spec.require_paths = ["lib"]
15
+ spec.require_paths = ['lib']
16
16
 
17
- spec.add_runtime_dependency "lita", "~> 4.7"
18
- spec.add_runtime_dependency "rye"
19
- spec.add_runtime_dependency "puppetdb-ruby"
17
+ spec.add_runtime_dependency 'lita', '~> 4.7'
18
+ spec.add_runtime_dependency 'rye'
19
+ spec.add_runtime_dependency 'puppetdb-ruby'
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
22
- spec.add_development_dependency "pry-byebug"
23
- spec.add_development_dependency "rake"
24
- spec.add_development_dependency "rack-test"
25
- spec.add_development_dependency "rspec", "~> 3.0"
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'pry-byebug'
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rack-test'
25
+ spec.add_development_dependency 'rspec', '~> 3.0'
26
+ spec.add_development_dependency 'simplecov'
27
+ spec.add_development_dependency 'coveralls'
28
+ spec.add_development_dependency 'rubocop'
26
29
  end
data/locales/en.yml CHANGED
@@ -2,3 +2,43 @@ en:
2
2
  lita:
3
3
  handlers:
4
4
  puppet:
5
+ help:
6
+ puppet_agent_run:
7
+ syntax: puppet agent run on <host>
8
+ desc: Run the puppet agent on <host>.
9
+ cert_clean:
10
+ syntax: puppet cert clean <host>
11
+ desc: Remove all traces of the SSL cert for <host> on the Puppet Master.
12
+ node_profiles:
13
+ syntax: puppet catalog <host> profiles
14
+ desc: Query PuppetDB to get a list of all roles and profiles applied to <host>.
15
+ nodes_with_class:
16
+ syntax: puppet class nodes <class>
17
+ desc: Query PuppetDB to get a list of all nodes containing a class.
18
+ r10k_deploy:
19
+ syntax: puppet r10k [env [module]]
20
+ desc: Deploy the latest puppet code on the puppet master via r10k, optionally specifying an environment, and possibly a module.
21
+ replies:
22
+ cert_clean:
23
+ working: "working on that `puppet cert clean`. I'll get right back to you."
24
+ failure: "your `puppet cert clean` didn't seem to work... ;-("
25
+ success: "your `puppet cert clean` is all done!"
26
+ puppet_agent_run:
27
+ working: "I'll run puppet right away. Give me a sec and I'll let you know how it goes."
28
+ failure: "your puppet run is done, but didn't seem to work... I think it may have timed out."
29
+ success: "that puppet run is complete! It exited with status %{status}."
30
+ node_profiles:
31
+ notconf: "I would do that, but I don't know how to connect to PuppetDB. Edit my config and add `config.handlers.puppet.puppetdb_url`."
32
+ working: "let me see what I can find in PuppetDB for you."
33
+ failure: "Hmmm, that didn't work. Here's what PuppetDB responded with: '%{error}'"
34
+ success: "Here are the profiles and roles for %{host}:"
35
+ nodes_with_class:
36
+ notconf: "I would do that, but I don't know how to connect to PuppetDB. Edit my config and add `config.handlers.puppet.puppetdb_url`."
37
+ working: "let me see what I can find in PuppetDB for you."
38
+ failure: "There are no nodes with %{pclass} class, are you sure it's a valid class?"
39
+ success: "Here are all the nodes with class %{pclass}:"
40
+ r10k_deploy:
41
+ working: "I'll get right on that. Give me a moment and I'll let you know how it went."
42
+ gitfail: "your r10k run didn't seem to work. Looks like there was a problem with Git:"
43
+ pupfail: "your r10k run didn't seem to work. Here's what went wrong:"
44
+ success: "your r10k deployment is done!"
@@ -1,4 +1,23 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
3
  describe Lita::Handlers::Puppet, lita_handler: true do
4
+ it 'routes agent run commands properly' do
5
+ is_expected.to route_command('puppet agent run on foo').to(:puppet_agent_run)
6
+ end
7
+
8
+ it 'routes cert clean commands properly' do
9
+ is_expected.to route_command('puppet cert clean foo').to(:cert_clean)
10
+ end
11
+
12
+ it 'routes catalog profiles commands properly' do
13
+ is_expected.to route_command('puppet catalog foo profiles').to(:node_profiles)
14
+ end
15
+
16
+ it 'routes class nodes commands properly' do
17
+ is_expected.to route_command('puppet class nodes foo').to(:nodes_with_class)
18
+ end
19
+
20
+ it 'routes r10k commands properly' do
21
+ is_expected.to route_command('puppet r10k').to(:r10k_deploy)
22
+ end
4
23
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,12 @@
1
- require "lita-puppet"
2
- require "lita/rspec"
1
+ require 'simplecov'
2
+ # require 'coveralls'
3
+ SimpleCov.formatters = [
4
+ SimpleCov::Formatter::HTMLFormatter
5
+ ]
6
+ SimpleCov.start { add_filter '/spec/' }
7
+
8
+ require 'lita-puppet'
9
+ require 'lita/rspec'
3
10
 
4
11
  # A compatibility mode is provided for older plugins upgrading from Lita 3. Since this plugin
5
12
  # was generated with Lita 4, the compatibility mode should be left disabled.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-puppet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schaaff
@@ -123,6 +123,48 @@ dependencies:
123
123
  - - "~>"
124
124
  - !ruby/object:Gem::Version
125
125
  version: '3.0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: simplecov
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: coveralls
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: rubocop
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
126
168
  description: Some basic Puppet interactions for Lita
127
169
  email:
128
170
  - jgnagy@knuedge.com
@@ -131,6 +173,8 @@ extensions: []
131
173
  extra_rdoc_files: []
132
174
  files:
133
175
  - ".gitignore"
176
+ - ".rubocop.yml"
177
+ - ".travis.yml"
134
178
  - CONTRIBUTING.md
135
179
  - Gemfile
136
180
  - LICENSE
@@ -138,9 +182,9 @@ files:
138
182
  - Rakefile
139
183
  - lib/lita-puppet.rb
140
184
  - lib/lita/handlers/puppet.rb
141
- - lib/utils/puppetdb.rb
142
- - lib/utils/ssh.rb
143
- - lib/utils/text.rb
185
+ - lib/utils/lita_puppet/puppetdb.rb
186
+ - lib/utils/lita_puppet/ssh.rb
187
+ - lib/utils/lita_puppet/text.rb
144
188
  - lita-puppet.gemspec
145
189
  - locales/en.yml
146
190
  - spec/lita/handlers/puppet_spec.rb
@@ -1,31 +0,0 @@
1
- module Utils
2
- # Utility methods for working with PuppetDB
3
- module PuppetDB
4
- def dbquery(url, q)
5
- # TODO: validate incoming query structure
6
- client = ::PuppetDB::Client.new(server: url)
7
- client.request *q
8
- end
9
-
10
- def node_roles_and_profiles(url, nodename)
11
- # TODO: validate url and nodename
12
- ::PuppetDB::Client.new(server: url) # this is weird but required
13
- d = ::PuppetDB::Client.get("/catalogs/#{nodename}")
14
- return d["error"] if d['error']
15
-
16
- tags = []
17
- d["data"]["resources"].each {|r| tags.concat(r['tags'])}
18
-
19
- # return all the tags related to profile:: or role::
20
- tags.sort.uniq.select {|t| t.match /^(profile|role)::/ }
21
- end
22
-
23
- def class_nodes(url, classname)
24
- client = ::PuppetDB::Client.new(server: url)
25
- q = client.request('resources',[:and,[:'=','type', 'Class'],[:'=','title',"#{classname}"]])
26
-
27
- q.data.map { |node| node['certname'] }
28
- end
29
-
30
- end
31
- end
data/lib/utils/ssh.rb DELETED
@@ -1,46 +0,0 @@
1
- module Utils
2
- # Utility methods for doing things over SSH
3
- module SSH
4
- # Intelligently do some things over SSH
5
- def over_ssh(opts = {})
6
- result = {}
7
- fail "MissingSSHHost" unless opts[:host]
8
- fail "MissingSSHUser" unless opts[:user]
9
- opts[:timeout] ||= 300 # default to a 5 minute timeout
10
-
11
- remote = Rye::Box.new(
12
- opts[:host],
13
- user: opts[:user],
14
- auth_methods: ['publickey'],
15
- password_prompt: false,
16
- error: STDOUT # send STDERR to STDOUT for things that actually print
17
- )
18
-
19
- exception = nil
20
-
21
- # Getting serious about not crashing Lita...
22
- output = begin
23
- Timeout::timeout(opts[:timeout]) do
24
- yield remote # pass our host back to the user to work with
25
- end
26
- rescue Rye::Err => e
27
- exception = e
28
- rescue StandardError => e
29
- exception = e
30
- rescue Exception => e
31
- exception = e
32
- ensure
33
- remote.disconnect
34
- end
35
-
36
- if exception
37
- result[:exception] = exception
38
- else
39
- result[:exit_status] = output.exit_status
40
- result[:stdout] = output.stdout
41
- result[:stderr] = output.stderr
42
- end
43
- return result
44
- end
45
- end
46
- end
data/lib/utils/text.rb DELETED
@@ -1,28 +0,0 @@
1
- module Utils
2
- # Utility methods for manipulating text
3
- module Text
4
- # Try to make names more friendly
5
- def friendly_name(long_name)
6
- long_name.split(/\s/).first
7
- end
8
-
9
- # Strip off bad characters
10
- def sanitze_for_chat(text)
11
- # Remove bash colorings
12
- text.gsub(/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]/, '')
13
- end
14
-
15
- # camel case puppet classes
16
- def class_camel(text)
17
- text.split('::').map(&:capitalize).join('::')
18
- end
19
-
20
- # Format some text as code
21
- # Note that this is HipChat specific for the moment
22
- # TODO: Make this *not* HipChat specific
23
- def as_code(text)
24
- "/code " + sanitze_for_chat(text)
25
- end
26
- end
27
-
28
- end