batali-infuse 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 17ef61f2e7578a35826f34fa210783553ca752dd
4
+ data.tar.gz: 5bfe4aef5b322a535359c459badd1a917c9be7ce
5
+ SHA512:
6
+ metadata.gz: 309df6df2f5637d9cf7d5e13e6142e512cf9352123ac74158211964f30756351d072f2c7bf0289286ac557ba3ba04f6ea8d91a8258ab61d4f3841754f7280d42
7
+ data.tar.gz: 474e691922cd655cee83842a0d5272e5e42686f75f5c9672cb8016a54574220028411dbf7c15eaa8c48a4ffd941eecb7172252d5f2088713850c5403fbb02b17
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # v0.2.0
2
+ * Rename to batali-infuse
3
+ * Add support for least impact resolution
4
+
5
+ # v0.1.0
6
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015 Chris Roberts
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Batali Infuse
2
+
3
+ Add an infusion of [Batali][1] to `chef-client`!
4
+
5
+ ## Infusing Batali
6
+
7
+ This gem infuses Batali into `chef-client` to perform cookbook
8
+ resolution locally on the node and request the solution set
9
+ from the Chef Server.
10
+
11
+ ## Origin of the infusion
12
+
13
+ There are some claims that the solver the Chef Server uses can
14
+ provide incorrect solutions. Though these are only claims, it
15
+ prompted the question:
16
+
17
+ > Can a client side solver be used to generate a solution?
18
+
19
+ As it turns out, it can!
20
+
21
+ ## Usage
22
+
23
+ ### Install
24
+
25
+ This only supports 12.2.x versions of Chef. If Chef is running via
26
+ the omnibus install the gem should be installed like so:
27
+
28
+ ```
29
+ $ /opt/chef/emebedded/bin/gem install batali-wedge --no-document
30
+ ```
31
+
32
+ If Chef is running via the system Ruby, just install the gem directly:
33
+
34
+ ```
35
+ $ gem install batali-wedge --no-document
36
+ ```
37
+
38
+ ### Enable
39
+
40
+ The infusion is enabled via the `client.rb` file. Add the following
41
+ line to the top of the file:
42
+
43
+ ```ruby
44
+ # /etc/chef/client.rb
45
+
46
+ require 'batali-infuse/sync'
47
+ ```
48
+
49
+ ### Least impact resolution
50
+
51
+ Batali includes a ["least impact"][2] feature when resolving cookbooks.
52
+ This feature can be enabled when resolving cookbooks on the local
53
+ node. The benefit of least impact updates is that nodes will not
54
+ automatically request the latest version of a cookbook available if
55
+ it has already been provisioned. Instead, it will use a "least impact"
56
+ approach when resolving cookbooks, and no update will occur if the
57
+ previous version is still available within the given constraints.
58
+
59
+ There are two ways the option can be enabled:
60
+
61
+ #### Node attribute
62
+
63
+ ```ruby
64
+ node.set[:batali][:least_impact] = true
65
+ ```
66
+
67
+ #### Chef configuration
68
+
69
+ ```ruby
70
+ # /etc/chef/client.rb
71
+ ...
72
+ batali_least_impact true
73
+ ```
74
+ _NOTE: Enabling via the configuration file will override a disabled setting within the node attributes_
75
+
76
+ # Info
77
+
78
+ ## Resolver
79
+
80
+ * Batali: https://github.com/hw-labs/batali
81
+ * Least impact updates: https://github.com/hw-labs/batali#least-impact-updates
82
+
83
+ ## General
84
+
85
+ * Repository: https://github.com/hw-labs/batali-infuse
86
+ * IRC: Freenode @ #heavywater
87
+
88
+ [1]: https://github.com/hw-labs/batali "Light weight cookbook resolver"
89
+ [2]: https://github.com/hw-labs/batali#least-impact-updates "Batali: Least impact updates"
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
2
+ require 'batali-infuse/version'
3
+ Gem::Specification.new do |s|
4
+ s.name = 'batali-infuse'
5
+ s.version = BataliInfuse::VERSION.version
6
+ s.summary = 'Batali infusion'
7
+ s.author = 'Chris Roberts'
8
+ s.email = 'code@chrisroberts.org'
9
+ s.homepage = 'https://github.com/hw-labs/batali-infuse'
10
+ s.description = 'Infuse the Batali resolver into Chef client'
11
+ s.require_path = 'lib'
12
+ s.license = 'Apache 2.0'
13
+ s.add_runtime_dependency 'batali', '>= 0.2.9', '< 1.0.0'
14
+ s.add_runtime_dependency 'chef', '~> 12.2.0'
15
+ s.files = Dir['{lib}/**/**/*'] + %w(batali-infuse.gemspec README.md CHANGELOG.md LICENSE)
16
+ end
@@ -0,0 +1,123 @@
1
+ require 'batali-infuse'
2
+
3
+ class Chef::PolicyBuilder::ExpandNodeObject
4
+
5
+ # Provide override to force Batali resolution
6
+ def sync_cookbooks
7
+ Chef::Log.debug("Synchronizing cookbooks")
8
+
9
+ begin
10
+ events.cookbook_resolution_start(@expanded_run_list_with_versions)
11
+ cookbook_hash = batali_cookbook_hash
12
+
13
+ rescue Exception => e
14
+ # TODO: wrap/munge exception to provide helpful error output
15
+ events.cookbook_resolution_failed(@expanded_run_list_with_versions, e)
16
+ raise
17
+ else
18
+ events.cookbook_resolution_complete(cookbook_hash)
19
+ end
20
+
21
+ synchronizer = Chef::CookbookSynchronizer.new(cookbook_hash, events)
22
+ if temporary_policy?
23
+ synchronizer.remove_obsoleted_files = false
24
+ end
25
+ synchronizer.sync_cookbooks
26
+
27
+ # register the file cache path in the cookbook path so that CookbookLoader actually picks up the synced cookbooks
28
+ Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")
29
+
30
+ cookbook_hash
31
+
32
+ end
33
+
34
+ # Generate expected cookbook version hash
35
+ #
36
+ # @return [Hash]
37
+ def batali_cookbook_hash
38
+ Chef::Log.warn 'Resolving cookbooks via Batali!'
39
+ system = batali_build_system
40
+ constraints = Smash[
41
+ api_service.get_rest("environments/#{node.chef_environment}").cookbook_versions.to_a
42
+ ]
43
+ @expanded_run_list_with_versions.each do |item|
44
+ c_name, c_version = item.split('@')
45
+ c_name = c_name.split('::').first
46
+ if(c_version)
47
+ constraints[c_name] = c_version
48
+ elsif(constraints[c_name].nil?)
49
+ constraints[c_name] = '> 0'
50
+ end
51
+ end
52
+ requirements = Grimoire::RequirementList.new(
53
+ :name => :batali_resolv,
54
+ :requirements => constraints.to_a
55
+ )
56
+ solver = Grimoire::Solver.new(
57
+ :requirements => requirements,
58
+ :system => system,
59
+ :score_keeper => batali_build_score_keeper
60
+ )
61
+ results = solver.generate!
62
+ solution = results.pop
63
+ solution_output = solution.units.sort_by(&:name).map{|u| "#{u.name}<#{u.version}>"}.join(', ')
64
+ node.set[:batali] ||= Mash.new
65
+ node.set[:batali][:last_resolution] = Mash[solution.units.map{|u| [u.name, u.version]}]
66
+ Chef::Log.warn "Batali cookbook resolution: #{solution_output}"
67
+ Hash[
68
+ solution.units.map do |unit|
69
+ [unit.name, api_service.get_rest("cookbooks/#{unit.name}/#{unit.version}")]
70
+ end
71
+ ]
72
+ end
73
+
74
+ # Build the base system for generating solution
75
+ #
76
+ # @return [Grimoire::System]
77
+ def batali_build_system
78
+ system = Grimoire::System.new
79
+ units = api_service.get_rest('cookbooks').map do |c_name, meta|
80
+ meta['versions'].map do |info|
81
+ "#{c_name}/#{info['version']}"
82
+ end
83
+ end.flatten.map do |ckbk|
84
+ Batali::Unit.new(
85
+ Smash.new(
86
+ :name => ckbk.split('/').first,
87
+ :version => ckbk.split('/').last,
88
+ :dependencies => api_service.get_rest("cookbooks/#{ckbk}").metadata.dependencies.to_a
89
+ )
90
+ )
91
+ end
92
+ system.add_unit(*units)
93
+ system
94
+ end
95
+
96
+ # Build score keeper if it is enabled via settings
97
+ #
98
+ # @return [Batali::ScoreKeeper]
99
+ def batali_build_score_keeper
100
+ if(batali_least_impact?)
101
+ Chef::Log.warn "Batali 'least impact resolution' is currently enabled!"
102
+ if(node[:batali] && node[:batali][:last_resolution])
103
+ Batali::ScoreKeeper.new(
104
+ :manifest => Batali::Manifest.new(
105
+ :cookbooks => node[:batali][:last_resolution].map{ |c_name, c_version|
106
+ Batali::Unit.new(
107
+ :name => c_name,
108
+ :version => c_version
109
+ )
110
+ }
111
+ )
112
+ )
113
+ end
114
+ end
115
+ end
116
+
117
+ # @return [TrueClass, FalseClass]
118
+ def batali_least_impact?
119
+ Chef::Config[:batali_least_impact] ||
120
+ (node[:batali] && node[:batali][:least_impact])
121
+ end
122
+
123
+ end
@@ -0,0 +1,3 @@
1
+ module BataliInfuse
2
+ VERSION = Gem::Version.new('0.2.0')
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'batali'
2
+ require 'batali-infuse/version'
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: batali-infuse
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Roberts
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: batali
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.9
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.2.9
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: chef
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 12.2.0
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 12.2.0
47
+ description: Infuse the Batali resolver into Chef client
48
+ email: code@chrisroberts.org
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - CHANGELOG.md
54
+ - LICENSE
55
+ - README.md
56
+ - batali-infuse.gemspec
57
+ - lib/batali-infuse.rb
58
+ - lib/batali-infuse/sync.rb
59
+ - lib/batali-infuse/version.rb
60
+ homepage: https://github.com/hw-labs/batali-infuse
61
+ licenses:
62
+ - Apache 2.0
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.2.2
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: Batali infusion
84
+ test_files: []
85
+ has_rdoc: