batali-infuse 0.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.
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: