comrad 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66c6919f9e828f044c58110f1f249c397bf8b30f
4
- data.tar.gz: bfe6cea60a7b4284a42f4cfff6e46684da3520ff
3
+ metadata.gz: f8a7c8c56e6699348b75573ab291f298b1b40267
4
+ data.tar.gz: 4f27ebddb71d6bad85cc9ea6ec947bc1b1f524b5
5
5
  SHA512:
6
- metadata.gz: 8a3c112332856871089428d59ea4ad98f0ba0f8c5b7e155552c8854961e74b62849a3d66f0e59f88c207b1083565f6252c989854b2d5f91bbc230b9d039dd715
7
- data.tar.gz: 2b8c623f22b0d0ea2fd7ac9611a5c2625bb6f7612d1cb8632d0320006fc68d9937f4ea3c93a8bb2aafedb79cac9d908f7dbe250ac0d62f23e5b204ec43bd0d36
6
+ metadata.gz: 7807998016b768f385925a846ad053eb41be367dadb1400936ae5a7eb1746d79f1ecbc129ddf98696071f5a7fc63ccd18b05c6510065a4b25558a240ac576daf
7
+ data.tar.gz: a90d91f1dd5542dbd01c964a87305b87949ae2d277dd60500ce778df73a33a2b315d7d7a0518ecb58e5f04799d859ce449308d89e9bb3af1bbca37e390005f0e
@@ -1,7 +1,11 @@
1
1
  language: ruby
2
+ cache:
3
+ - bundler
4
+ install:
5
+ - bundle install
2
6
  rvm:
3
- - 2.1.5
4
- - 2.2.0
7
+ - 2.1.6
8
+ - 2.2.2
5
9
  script:
6
10
  - bundle exec rake test
7
11
 
data/Gemfile CHANGED
@@ -1,10 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'chef', '>= 11.0'
4
- gem 'ridley', '~> 4.1'
5
- gem 'rest-client', '~> 1.7.0'
6
-
7
- group :test do
8
- gem 'rubocop', '~> 0.30.0'
9
- gem 'rake', '~> 10.4'
10
- end
3
+ gemspec
data/README.md CHANGED
@@ -1,2 +1,6 @@
1
- # Comrad
1
+ Comrad
2
+ ======
3
+ [![Build Status](https://travis-ci.org/tas50/Comrad.svg)](https://travis-ci.org/tas50/Comrad)
4
+
2
5
  Application to sync changes from git to Chef Server via Jenkins
6
+
data/bin/comrad CHANGED
@@ -20,6 +20,6 @@
20
20
  # load the libs
21
21
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
22
22
 
23
- require 'application'
23
+ require 'comrad'
24
24
 
25
- Comrad::Application.new.run
25
+ Comrad.run
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'comrad'
3
- s.version = '0.0.3'
3
+ s.version = '0.1.0'
4
4
  s.date = Date.today.to_s
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.extra_rdoc_files = ['README.md', 'LICENSE']
@@ -14,13 +14,13 @@ Gem::Specification.new do |s|
14
14
  s.required_ruby_version = '>= 1.9.3'
15
15
  s.add_dependency 'rest-client', '~> 1.7.0'
16
16
  s.add_dependency 'chef', '>= 11.0'
17
- s.add_dependency 'ridley', '~> 4.0'
17
+ s.add_dependency 'slack-post', '~> 0.3'
18
18
  s.add_development_dependency 'rake', '~> 10.0'
19
19
  s.add_development_dependency 'rubocop', '~> 0.30.0'
20
20
 
21
21
  s.files = `git ls-files -z`.split("\x0")
22
- s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ s.executables = s.name
23
23
  s.require_paths = ['lib']
24
24
  s.extra_rdoc_files = ['README.md']
25
- s.rdoc_options = ['--line-numbers', '--inline-source', '--title', 'reagan', '--main', 'README.md']
25
+ s.rdoc_options = ['--line-numbers', '--inline-source', '--title', 'comrad', '--main', 'README.md']
26
26
  end
@@ -1,5 +1,6 @@
1
1
  slack:
2
2
  webhook_url: 1234abcde1234abcde
3
+ channel: '#general'
3
4
  jenkins:
4
5
  workspace_dir: '/home/jenkins/workspace/chef-repo/'
5
6
  chef:
@@ -0,0 +1,54 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Tim Smith (<tim@cozy.co>)
4
+ # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ require 'pp'
19
+
20
+ require 'core_ext/string'
21
+
22
+ require 'comrad/config'
23
+ require 'comrad/changeset'
24
+ require 'comrad/chef'
25
+ require 'comrad/notifier'
26
+
27
+ # Your rad comrade - Sync changes from git to Chef Server via Jenkins
28
+ module Comrad
29
+ module_function
30
+
31
+ # Evaluate the current build for chef object changes,
32
+ # use knife to upload changed objects to the Chef server,
33
+ # send a notification to slack.
34
+ def self::run
35
+ if Config.config['flags']['print_config']
36
+ 'Current config file / CLI flag values'.marquee
37
+ Config.print
38
+ exit
39
+ end
40
+
41
+ if Changeset.empty?
42
+ 'No objects to test. Exiting'.to_green
43
+ exit
44
+ end
45
+
46
+ 'The following chef objects will be changed'.marquee
47
+ pp Changeset.changes
48
+
49
+ 'Making Chef Changes'.marquee
50
+ Chef.process_changes
51
+
52
+ Notifier.notify_changes
53
+ end
54
+ end
@@ -16,82 +16,72 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- begin
20
- require 'json'
21
- require 'rest_client'
22
- require 'uri'
23
- rescue LoadError => e
24
- raise "Missing gem or lib #{e}"
25
- end
19
+ require 'json'
20
+ require 'rest_client'
26
21
 
27
22
  module Comrad
28
23
  # interacts with jenkins API to determine changes files
29
24
  # parses changed files to determine relevant files that will
30
25
  # need to be uploaded to chef server
31
- class Change < Application
32
- attr_accessor :changes
33
- def initialize(config)
34
- @config = config
35
- @protocol = URI(@config['jenkins']['url']).scheme
36
- @jenkins_host = URI(@config['jenkins']['url']).host
37
- @username = @config['jenkins']['username']
38
- @password = @config['jenkins']['password']
39
- @job_name = @config['jenkins']['job_name']
40
- @jenkins_workspace_path = @config['jenkins']['workspace_dir']
41
- @build_num = ENV['BUILD_NUMBER']
26
+ class Changeset
27
+ # Return a hash of all changed objects
28
+ def self::changes
29
+ @changes ||= create_change_hash(changed_files_array)
30
+ end
42
31
 
43
- @build_data = query_build_data
44
- @changes = create_change_hash(changed_files_array)
32
+ # True if there are no changed objects
33
+ def self::empty?
34
+ changes == empty_chef_object_hash
35
+ end
36
+
37
+ # Return a hash of all Jenkins details for this build
38
+ def self::build_data
39
+ @build_data ||= fetch_build_data
45
40
  end
46
41
 
47
42
  # fetch build data using Jenkins API
48
- def query_build_data
49
- conn = RestClient::Resource.new("#{@protocol}://#{@jenkins_host}/job/#{@job_name}/#{@build_num}/api/json?", @username, @password)
43
+ def self::fetch_build_data
44
+ j = Config.config['jenkins']
45
+ url = j['url'] + '/job/' + j['job_name'] + '/' + ENV['BUILD_NUMBER'] + '/api/json?'
46
+ conn = RestClient::Resource.new(url, j['username'], j['password'])
50
47
  JSON.parse(conn.get)
51
48
  end
52
49
 
53
50
  # parse jenkins build data to determine unique list of all files that have changed accross multiple commits
54
- def changed_files_array
51
+ def self::changed_files_array
55
52
  changed_files = []
56
-
57
- @build_data['changeSet']['items'].each do |change|
53
+ build_data['changeSet']['items'].each do |change|
58
54
  changed_files.concat(change['affectedPaths'])
59
55
  end
60
-
61
56
  changed_files.uniq
62
57
  end
63
58
 
64
- # create the empty hash that stores the changed objects
65
- def empty_chef_object_hash
66
- objects = {}
67
- objects['environments'] = {}
68
- objects['roles'] = {}
69
- objects['data_bags'] = {}
70
- objects['cookbooks'] = {}
71
-
72
- objects
59
+ def self::empty_chef_object_hash
60
+ {
61
+ 'environments' => {},
62
+ 'roles' => {},
63
+ 'data_bags' => {},
64
+ 'cookbooks' => {}
65
+ }
73
66
  end
74
67
 
75
68
  # return an action based on the status of the object in the workspace
76
- def action(file)
77
- ::File.exist?(::File.join(@jenkins_workspace_path, file)) ? 'update' : 'delete'
78
- end
79
-
80
- def print
69
+ def self::action(file)
70
+ ::File.exist?(::File.join(Config.config['jenkins']['workspace_dir'], file)) ? 'update' : 'delete'
81
71
  end
82
72
 
83
73
  # takes an array of files that have changes and returns hash of chef objects and an action to take on the object
84
- def create_change_hash(files_array)
74
+ def self::create_change_hash(files_array)
85
75
  objects = empty_chef_object_hash
86
76
  files_array.each do |file|
77
+ split_file = file.split('/')
87
78
  case
88
79
  when file.match(/^[cookbook|roles|environments]/)
89
- split_file = file.split('/')
80
+ # "cookbooks"=>{"some-cookbook"=>"update"}
90
81
  objects[split_file[0]][split_file[1]] = action(split_file[0..1].join('/'))
91
82
  when file.match(/^data_bags/)
92
- split_file = file.split('/')
93
- objects[split_file[0]][split_file[1]] = {} unless objects[split_file[0]].key?(split_file[1])
94
- objects[split_file[0]][split_file[1]][split_file[2]] = action(split_file[0..2].join('/'))
83
+ # "data_bags"=>{"some_dbag/some_item.json"=>"update"}
84
+ objects[split_file[0]][split_file[1..2].join('/')] = action(split_file[0..2].join('/'))
95
85
  end
96
86
  end
97
87
  objects
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Tim Smith (<tim@cozy.co>)
4
+ # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ module Comrad
20
+ # uploads / removes objects that changed from the chef server
21
+ class Chef
22
+ # Given an +item+ of +item_class+, return a knife command that performs +action+
23
+ def self::knife_command(item_class, item, action)
24
+ item_path = {
25
+ cookbooks: item,
26
+ data_bags: "data_bags/#{item}",
27
+ environments: "environments/#{item}",
28
+ roles: "roles/#{item}"
29
+ }
30
+ # Special case: if we're deleting a data_bag, we want
31
+ # "bag_name item_name" without the '.json' rather than the path to the item.
32
+ item_path[:data_bags] = item.split('/').join(' ').chomp('.json') if action == 'delete'
33
+
34
+ knife_action = { delete: 'delete', update: 'from file' }
35
+ # Special case: we call 'upload' instead of 'from file' for updated cookbooks
36
+ knife_action[:update] = 'upload' if item_class == 'cookbooks'
37
+
38
+ 'knife %s %s %s' % [ # rubocop:disable FormatString
39
+ item_class.chomp('s'), # cookbook, data_bag, environment, role
40
+ knife_action[action.to_sym], # 'upload', 'delete' or 'from file'
41
+ item_path[item_class.to_sym] # cookbookname, environments/foo.json, 'dbag bagitem', etc.
42
+ ]
43
+ end
44
+
45
+ # run the provided knife command
46
+ def self::excute_knife_cmd(cmd)
47
+ if Config.config['flags']['dryrun']
48
+ puts "I would be running '#{cmd}'"
49
+ else
50
+ puts "Live mode is not implemented. Not performing '#{cmd}'"
51
+ end
52
+ end
53
+
54
+ # perform the appropriate knife action for each item in the +changeset+
55
+ def self::process_changes
56
+ Changeset.changes.each_pair do |item_class, action_pairs|
57
+ next if action_pairs.empty?
58
+ action_pairs.each_pair do |item, action|
59
+ excute_knife_cmd(knife_command(item_class, item, action))
60
+ end
61
+ end
62
+ end
63
+ end # Chef class
64
+ end # Comrad Module
@@ -16,25 +16,34 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- begin
20
- require 'yaml'
21
- require 'optparse'
22
- rescue LoadError => e
23
- raise "Missing gem or lib #{e}"
24
- end
19
+ require 'yaml'
20
+ require 'optparse'
25
21
 
26
22
  module Comrad
27
23
  # builds a single config from passed flags, yaml config, and knife.rb
28
24
  class Config
29
- attr_accessor :settings
30
- def initialize
31
- @flags = parse_flags
32
- @config_file = load_file
33
- @settings = merge_configs
25
+ # return the fully-evaluated configuration hash
26
+ def self::config
27
+ @flags ||= parse_flags
28
+ @config ||= merge_configs(load_file(@flags[:config]), @flags)
29
+ end
30
+
31
+ # pretty print the config hash
32
+ def self::print(hash = config, spaces = 0)
33
+ hash.each do |k, v|
34
+ spaces.times { print ' ' }
35
+ print k.to_s + ': '
36
+ if v.class == Hash
37
+ print "\n"
38
+ print_config(v, spaces + 2)
39
+ else
40
+ puts v
41
+ end
42
+ end
34
43
  end
35
44
 
36
45
  # make sure the BUILD_NUMBER Jenkins variable exists. If not force help
37
- def check_jenkins_env_variable
46
+ def self::check_jenkins_env_variable
38
47
  if ENV['BUILD_NUMBER'].nil?
39
48
  puts "Jenkins set BUILD_NUMBER environmental variable not set. Cannot continue.\n\n"
40
49
  ARGV[0] = '-h'
@@ -42,14 +51,14 @@ module Comrad
42
51
  end
43
52
 
44
53
  # grabs the flags passed in via command line
45
- def parse_flags
54
+ def self::parse_flags
46
55
  check_jenkins_env_variable
47
56
 
48
57
  flags = { config: '/etc/comrad.yml', print_config: false, quiet: false }
49
58
  OptionParser.new do |opts|
50
59
  opts.banner = 'Usage: comrad [options]'
51
60
 
52
- opts.on('-p', '--print', 'Print the config options that will be used') do |config|
61
+ opts.on('-p', '--print', 'Print the config options that would be used, and then exit') do |config|
53
62
  flags[:print_config] = config
54
63
  end
55
64
 
@@ -79,42 +88,27 @@ module Comrad
79
88
  end
80
89
 
81
90
  # loads the comrad.yml config file from /etc/comrad.yml or the passed location
82
- def load_file
83
- config = YAML.load_file(@flags[:config])
91
+ def self::load_file(file_path)
92
+ config = YAML.load_file(file_path)
84
93
  if config == false
85
94
  puts "ERROR: Comrad config at #{@flags[:config]} does not contain any configuration data"
86
95
  exit 1
87
96
  end
88
97
  config
89
98
  rescue Errno::ENOENT
90
- puts "ERROR: Cannot load Comrad config file at #{@flags[:config]}"
99
+ puts "ERROR: Cannot load Comrad config file at #{file_path}"
91
100
  exit 1
92
101
  rescue Psych::SyntaxError
93
- puts "ERROR: Syntax error in Comrad config file at #{@flags[:config]}"
102
+ puts "ERROR: Syntax error in Comrad config file at #{file_path}"
94
103
  exit 1
95
104
  end
96
105
 
97
106
  # join the config file with the passed flags into a single object
98
- def merge_configs
99
- config = @config_file
107
+ def self::merge_configs(file_config, flags_config)
108
+ config = file_config.dup
100
109
  config['flags'] = {}
101
- @flags.each { |k, v| config['flags'][k.to_s] = v }
110
+ flags_config.each { |k, v| config['flags'][k.to_s] = v }
102
111
  config
103
112
  end
104
-
105
- # pretty print the config hash
106
- def print(hash = nil, spaces = 0)
107
- hash = @settings if hash.nil?
108
- hash.each do |k, v|
109
- spaces.times { print ' ' }
110
- print k.to_s + ': '
111
- if v.class == Hash
112
- print "\n"
113
- print_config(v, spaces + 2)
114
- else
115
- puts v
116
- end
117
- end
118
- end
119
113
  end
120
114
  end
@@ -0,0 +1,62 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Tim Smith (<tim@cozy.co>)
4
+ # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'slack/post'
20
+
21
+ module Comrad
22
+ # send notifications to slack
23
+ class Notifier
24
+ def self::configure
25
+ Slack::Post.configure(
26
+ webhook_url: Config.config['slack']['webhook_url'],
27
+ username: 'comrad',
28
+ channel: Config.config['slack']['channel']
29
+ )
30
+ @configured = true
31
+ end
32
+
33
+ # Post a Slack notification containing details of the changes
34
+ def self::notify_changes
35
+ unless Config.config['flags']['quiet']
36
+ configure unless @configured
37
+ Slack::Post.post_with_attachments(
38
+ 'Comrad action for chef repo <%s|Build #%s>' % [ # rubocop:disable FormatString
39
+ Changeset.build_data['url'],
40
+ Changeset.build_data['number']],
41
+ changeset_attachment)
42
+ end
43
+ end
44
+
45
+ # Generate a Slack message attachment that contains changeset details
46
+ def self::changeset_attachment
47
+ attach = { fallback: '', color: '#36a64f', fields: [] }
48
+
49
+ Changeset.changes.each_pair do |item_class, action_pairs|
50
+ next if action_pairs.empty?
51
+ text = ''
52
+ action_pairs.each_pair do |item, action|
53
+ text << "#{action} #{item}\n"
54
+ end
55
+ attach[:fallback] << "#{item_class}:\n#{text}"
56
+ attach[:fields] << { title: item_class, value: text, short: false }
57
+ end
58
+
59
+ [attach]
60
+ end
61
+ end
62
+ end
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: comrad
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Smith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-22 00:00:00.000000000 Z
11
+ date: 2015-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '11.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: ridley
42
+ name: slack-post
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: '4.0'
47
+ version: '0.3'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: '4.0'
54
+ version: '0.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -98,12 +98,12 @@ files:
98
98
  - bin/comrad
99
99
  - comrad.gemspec
100
100
  - comrad.yml.EXAMPLE
101
- - lib/application.rb
102
- - lib/change.rb
103
- - lib/chef.rb
104
- - lib/config.rb
105
- - lib/slack.rb
106
- - lib/string.rb
101
+ - lib/comrad.rb
102
+ - lib/comrad/changeset.rb
103
+ - lib/comrad/chef.rb
104
+ - lib/comrad/config.rb
105
+ - lib/comrad/notifier.rb
106
+ - lib/core_ext/string.rb
107
107
  homepage: http://www.github.com/tas50/Comrad
108
108
  licenses:
109
109
  - Apache-2.0
@@ -113,7 +113,7 @@ rdoc_options:
113
113
  - --line-numbers
114
114
  - --inline-source
115
115
  - --title
116
- - reagan
116
+ - comrad
117
117
  - --main
118
118
  - README.md
119
119
  require_paths:
@@ -1,66 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Tim Smith (<tim@cozy.co>)
4
- # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- module Comrad
20
- # the main class for the comrad app. gets called by the comrad bin
21
- class Application
22
- require 'config'
23
- require 'change'
24
- require 'chef'
25
- require 'string'
26
- require 'slack'
27
-
28
- def initialize
29
- @config_obj = Comrad::Config.new
30
- @config = @config_obj.settings
31
- @changes = Comrad::Change.new(@config).changes
32
- end
33
-
34
- # exit with a friendly message if nothing we test has been changed
35
- def check_empty_update
36
- objects_updated = false
37
- %w(cookbooks roles environments data_bags).each do |object|
38
- objects_updated = true unless @changes[object].empty?
39
- end
40
-
41
- ('No objects to test. Exiting'.to_green && exit) unless objects_updated
42
- end
43
-
44
- # check and see if the -p flag was passed and if so print the config hash
45
- def check_print_config
46
- if @config['flags']['print_config']
47
- 'Current config file / CLI flag values'.marquee
48
- @config_obj.print
49
- exit
50
- end
51
- end
52
-
53
- # run tests on each changed cookbook
54
- def run
55
- check_print_config
56
- ('No objects updated by this commit. Exiting'.to_green && exit) if check_empty_update
57
-
58
- # print objects that will be uploaded
59
- 'The following chef objects will be changed'.marquee
60
- puts @changes
61
-
62
- 'Making Chef Changes'.marquee
63
- Comrad::Chef.new(@config, @changes).run
64
- end
65
- end
66
- end
@@ -1,94 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Tim Smith (<tim@cozy.co>)
4
- # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- begin
20
- require 'ridley'
21
- rescue LoadError => e
22
- raise "Missing gem or lib #{e}"
23
- end
24
-
25
- module Comrad
26
- # uploads / removes objects that changed from the chef server
27
- class Chef < Application
28
- def initialize(config, changes)
29
- @config = config
30
- @changes = changes
31
- @slack = Comrad::Slack.new(config)
32
- end
33
-
34
- # builds a string of what the action is / would be depending on dry run or not
35
- def action_string(action, trailing_text)
36
- string = @config['flags']['dryrun'] ? " - I would #{action} " : " - #{action.capitalize.chomp('e')}ing "
37
- string + trailing_text
38
- end
39
-
40
- # a really horrible method to build knife commands based on item / action / item type (cookbook/role/environment/data_bag)
41
- def build_knife_cmd(type, action, item1, item2 = nil)
42
- if type == 'data_bags'
43
- action == 'delete' ? "knife data bag delete #{item1} #{item2}" : "knife data bag from file #{item1} data_bags/#{item1}/#{item2}"
44
- elsif action == 'delete'
45
- "knife #{type.chomp('s')} delete #{item1} #{item2}"
46
- elsif type == 'cookbooks'
47
- "knife cookbook #{action == 'update' ? 'upload' : 'delete'} #{item1}"
48
- else
49
- "knife #{type.chomp('s')} from file #{type}/#{item1}"
50
- end
51
- end
52
-
53
- # run the provided knife command
54
- def excute_knife_cmd(cmd)
55
- if @config['flags']['dryrun']
56
- @slack.slack_put(" - I would be running #{cmd}")
57
- else
58
- @slack.slack_put(' - Non-dry mode is not implemented. Doing nothing')
59
- end
60
- end
61
-
62
- # main method of the class. Iterates over the changes passed in and kicks off actions / slack messaging
63
- def take_actions
64
- @changes.each_pair do |type, name|
65
- next if name.empty?
66
- case
67
- when type.match(/^['environments|roles']/)
68
- name.each_pair do |item, action|
69
- @slack.slack_put(action_string(action, "#{item}"))
70
- excute_knife_cmd(build_knife_cmd(type, action, item))
71
- end
72
- when type == 'cookbooks'
73
- name.each_pair do |item, action|
74
- @slack.slack_put(action_string(action, "#{item}"))
75
- excute_knife_cmd(build_knife_cmd(type, action, item))
76
- end
77
- when type == 'data_bags'
78
- name.each_pair do |bag, item|
79
- item.each_pair do |bag_item_name, action|
80
- @slack.slack_put(action_string(action, "#{bag}::#{bag_item_name} data bag item"))
81
- excute_knife_cmd(build_knife_cmd(type, action, bag, bag_item_name))
82
- end
83
- end
84
- end
85
- end
86
- end
87
-
88
- # called by application to perform actions
89
- def run
90
- @slack.slack_put("Comrad action for chef repo build # #{ENV['BUILD_NUMBER']}:")
91
- take_actions
92
- end
93
- end # Chef class
94
- end # Comrad Module
@@ -1,46 +0,0 @@
1
- # encoding: UTF-8
2
- #
3
- # Author:: Tim Smith (<tim@cozy.co>)
4
- # Copyright:: Copyright (c) 2014-2015 Tim Smith
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
-
19
- require 'rest-client'
20
- require 'json'
21
-
22
- # base module
23
- module Comrad
24
- # send notifications to slack
25
- class Slack
26
- def initialize(config)
27
- @config = config
28
- @url = config['slack']['webhook_url']
29
- end
30
-
31
- def slack_put(text)
32
- puts text
33
- post(text) unless @config['flags']['quiet']
34
- end
35
-
36
- def post(text)
37
- RestClient.post @url, create_message(text).to_json
38
- end
39
-
40
- def create_message(text)
41
- message = {}
42
- message['text'] = text
43
- message
44
- end
45
- end
46
- end