knife-solo 0.0.3 → 0.0.4

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.
@@ -27,6 +27,8 @@ class Chef
27
27
 
28
28
  add_patches
29
29
 
30
+ check_chef_version
31
+
30
32
  logging_arg = "-l debug" if config[:verbosity] > 0
31
33
  stream_command <<-BASH
32
34
  sudo chef-solo -c #{chef_path}/solo.rb \
@@ -64,7 +66,6 @@ class Chef
64
66
  Array(Chef::Config.cookbook_path).first + "/chef_solo_patches/libraries"
65
67
  end
66
68
 
67
- # TODO (mat): Let rsync write to /var/chef-solo with sudo somehow
68
69
  def rsync_kitchen
69
70
  system %Q{rsync -rlP --rsh="ssh #{ssh_args}" --delete --exclude '.*' ./ :#{chef_path}}
70
71
  end
@@ -75,6 +76,14 @@ class Chef
75
76
  system %Q{rsync -rlP --rsh="ssh #{ssh_args}" #{patch} :#{patch_path}}
76
77
  end
77
78
  end
79
+
80
+ def check_chef_version
81
+ constraint = "~>0.10.4"
82
+ result = run_command <<-BASH
83
+ ruby -rubygems -e "gem 'chef', '#{constraint}'"
84
+ BASH
85
+ raise "The chef gem on #{host} is out of date. Please run `#{$0} prepare #{ssh_args}` to upgrade Chef to #{constraint}." unless result.success?
86
+ end
78
87
  end
79
88
  end
80
89
  end
@@ -16,11 +16,12 @@ class Chef
16
16
  mkdir name + "/site-cookbooks"
17
17
  mkdir name + "/cookbooks"
18
18
  File.open(name + "/solo.rb", 'w') do |f|
19
- f << <<-RUBY.gsub(/^\s+/, '')
19
+ f << <<-RUBY.gsub(/^ {12}/, '')
20
20
  file_cache_path "/tmp/chef-solo"
21
21
  data_bag_path "/tmp/chef-solo/data_bags"
22
22
  cookbook_path [ "/tmp/chef-solo/site-cookbooks",
23
23
  "/tmp/chef-solo/cookbooks" ]
24
+ role_path "/tmp/chef-solo/roles"
24
25
  RUBY
25
26
  end
26
27
  end
@@ -0,0 +1,211 @@
1
+ #
2
+ # Copyright 2011, edelight GmbH
3
+ #
4
+ # Authors:
5
+ # Markus Korn <markus.korn@edelight.de>
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
+
20
+ require 'treetop'
21
+ require 'chef/solr_query/query_transform'
22
+
23
+ # mock QueryTransform such that we can access the location of the lucene grammar
24
+ class Chef
25
+ class SolrQuery
26
+ class QueryTransform
27
+ def self.base_path
28
+ class_variable_get(:@@base_path)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def build_flat_hash(hsh, prefix="")
35
+ result = {}
36
+ hsh.each_pair do |key, value|
37
+ if value.kind_of?(Hash)
38
+ result.merge!(build_flat_hash(value, "#{prefix}#{key}_"))
39
+ else
40
+ result[prefix+key] = value
41
+ end
42
+ end
43
+ result
44
+ end
45
+
46
+ module Lucene
47
+
48
+ class Term < Treetop::Runtime::SyntaxNode
49
+ # compares a query value and a value, tailing '*'-wildcards are handled correctly.
50
+ # Value can either be a string or an array, all other objects are converted
51
+ # to a string and than checked.
52
+ def match( value )
53
+ if value.is_a?(Array)
54
+ value.any?{ |x| self.match(x) }
55
+ else
56
+ File.fnmatch(self.text_value, value.to_s)
57
+ end
58
+ end
59
+ end
60
+
61
+ class Field < Treetop::Runtime::SyntaxNode
62
+ # simple field -> value matches, supporting tailing '*'-wildcards in keys
63
+ # as well as in values
64
+ def match( item )
65
+ keys = self.elements[0].match(item)
66
+ if keys.nil?
67
+ false
68
+ else
69
+ keys.any?{ |key| self.elements[1].match(item[key]) }
70
+ end
71
+ end
72
+ end
73
+
74
+ # we don't support range matches
75
+ # range of integers would be easy to implement
76
+ # but string ranges are hard
77
+ class FiledRange < Treetop::Runtime::SyntaxNode
78
+ end
79
+
80
+ class InclFieldRange < FieldRange
81
+ end
82
+
83
+ class ExclFieldRange < FieldRange
84
+ end
85
+
86
+ class RangeValue < Treetop::Runtime::SyntaxNode
87
+ end
88
+
89
+ class FieldName < Treetop::Runtime::SyntaxNode
90
+ def match( item )
91
+ if self.text_value.count("_") > 0
92
+ item.merge!(build_flat_hash(item))
93
+ end
94
+ if self.text_value.end_with?("*")
95
+ part = self.text_value.chomp("*")
96
+ item.keys.collect{ |key| key.start_with?(part)? key: nil}.compact
97
+ else
98
+ if item.has_key?(self.text_value)
99
+ [self.text_value,]
100
+ else
101
+ nil
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ class Body < Treetop::Runtime::SyntaxNode
108
+ def match( item )
109
+ self.elements[0].match( item )
110
+ end
111
+ end
112
+
113
+ class Group < Treetop::Runtime::SyntaxNode
114
+ def match( item )
115
+ self.elements[0].match(item)
116
+ end
117
+ end
118
+
119
+ class BinaryOp < Treetop::Runtime::SyntaxNode
120
+ def match( item )
121
+ self.elements[1].match(
122
+ self.elements[0].match(item),
123
+ self.elements[2].match(item)
124
+ )
125
+ end
126
+ end
127
+
128
+ class OrOperator < Treetop::Runtime::SyntaxNode
129
+ def match( cond1, cond2 )
130
+ cond1 or cond2
131
+ end
132
+ end
133
+
134
+ class AndOperator < Treetop::Runtime::SyntaxNode
135
+ def match( cond1, cond2 )
136
+ cond1 and cond2
137
+ end
138
+ end
139
+
140
+ # we don't support fuzzy string matching
141
+ class FuzzyOp < Treetop::Runtime::SyntaxNode
142
+ end
143
+
144
+ class BoostOp < Treetop::Runtime::SyntaxNode
145
+ end
146
+
147
+ class FuzzyParam < Treetop::Runtime::SyntaxNode
148
+ end
149
+
150
+ class UnaryOp < Treetop::Runtime::SyntaxNode
151
+ def match( item )
152
+ self.elements[0].match(
153
+ self.elements[1].match(item)
154
+ )
155
+ end
156
+ end
157
+
158
+ class NotOperator < Treetop::Runtime::SyntaxNode
159
+ def match( cond )
160
+ not cond
161
+ end
162
+ end
163
+
164
+ class RequiredOperator < Treetop::Runtime::SyntaxNode
165
+ end
166
+
167
+ class ProhibitedOperator < Treetop::Runtime::SyntaxNode
168
+ end
169
+
170
+ class Phrase < Treetop::Runtime::SyntaxNode
171
+ # a quoted ::Term
172
+ def match( value )
173
+ self.elements[0].match(value)
174
+ end
175
+ end
176
+ end
177
+
178
+ class Query
179
+ # initialize the parser by using the grammar shipped with chef
180
+ @@grammar = File.join(Chef::SolrQuery::QueryTransform.base_path, "lucene.treetop")
181
+ Treetop.load(@@grammar)
182
+ @@parser = LuceneParser.new
183
+
184
+ def self.parse(data)
185
+ # parse the query into a query tree
186
+ if data.nil?
187
+ data = "*:*"
188
+ end
189
+ tree = @@parser.parse(data)
190
+ if tree.nil?
191
+ msg = "Parse error at offset: #{@@parser.index}\n"
192
+ msg += "Reason: #{@@parser.failure_reason}"
193
+ raise "Query #{data} is not supported: #{msg}"
194
+ end
195
+ self.clean_tree(tree)
196
+ tree
197
+ end
198
+
199
+ private
200
+
201
+ def self.clean_tree(root_node)
202
+ # remove all SyntaxNode elements from the tree, we don't need them as
203
+ # the related ruby class already knowns what to do.
204
+ return if root_node.elements.nil?
205
+ root_node.elements.delete_if do |node|
206
+ node.class.name == "Treetop::Runtime::SyntaxNode"
207
+ end
208
+ root_node.elements.each { |node| self.clean_tree(node) }
209
+ end
210
+ end
211
+
@@ -0,0 +1,81 @@
1
+ #
2
+ # Copyright 2011, edelight GmbH
3
+ #
4
+ # Authors:
5
+ # Markus Korn <markus.korn@edelight.de>
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
+
20
+ if Chef::Config[:solo]
21
+
22
+ if (defined? require_relative).nil?
23
+ # defenition of 'require_relative' for ruby < 1.9, found on stackoverflow.com
24
+ def require_relative(relative_feature)
25
+ c = caller.first
26
+ fail "Can't parse #{c}" unless c.rindex(/:\d+(:in `.*')?$/)
27
+ file = $`
28
+ if /\A\((.*)\)/ =~ file # eval, etc.
29
+ raise LoadError, "require_relative is called in #{$1}"
30
+ end
31
+ absolute = File.expand_path(relative_feature, File.dirname(file))
32
+ require absolute
33
+ end
34
+ end
35
+
36
+ require_relative 'parser.rb'
37
+
38
+ class Chef
39
+ class Recipe
40
+
41
+ # Overwrite the search method of recipes to operate locally by using
42
+ # data found in data_bags.
43
+ # Only very basic lucene syntax is supported and also sorting the result
44
+ # is not implemented, if this search method does not support a given query
45
+ # an exception is raised.
46
+ # This search() method returns a block iterator or an Array, depending
47
+ # on how this method is called.
48
+ def search(bag_name, query=nil, sort=nil, start=0, rows=1000, &block)
49
+ if !sort.nil?
50
+ raise "Sorting search results is not supported"
51
+ end
52
+ @_query = Query.parse(query)
53
+ if @_query.nil?
54
+ raise "Query #{query} is not supported"
55
+ end
56
+ if block_given?
57
+ pos = 0
58
+ else
59
+ result = []
60
+ end
61
+ data_bag(bag_name.to_s).each do |bag_item_id|
62
+ bag_item = data_bag_item(bag_name.to_s, bag_item_id)
63
+ if @_query.match(bag_item)
64
+ if block_given?
65
+ if (pos >= start and pos < (start + rows))
66
+ yield bag_item
67
+ end
68
+ pos += 1
69
+ else
70
+ result << bag_item
71
+ end
72
+ end
73
+ end
74
+ if !block_given?
75
+ return result.slice(start, rows)
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ end
@@ -30,7 +30,6 @@ class Chef
30
30
  @packages.join(' ')
31
31
  end
32
32
 
33
- # TODO (mat): integration test this, not a gem install
34
33
  def emerge_gem_install
35
34
  ui.msg("Installing required packages...")
36
35
  run_command("sudo USE='-test' ACCEPT_KEYWORDS='~amd64' emerge -u chef")
@@ -51,7 +50,6 @@ class Chef
51
50
  raise result.stderr unless result.success? || result.stdout.match(installed)
52
51
  end
53
52
 
54
- # TODO (mat): integration test this, will probably break without sudo
55
53
  def rpm_gem_install
56
54
  ui.msg("Installing required packages...")
57
55
  @packages = %w(ruby ruby-shadow gcc gcc-c++ ruby-devel wget rsync)
@@ -1,3 +1,5 @@
1
1
  module KnifeSolo
2
- VERSION = '0.0.3'
2
+ def self.version
3
+ '0.0.4'
4
+ end
3
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-solo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-08-01 00:00:00.000000000Z
12
+ date: 2011-10-07 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
16
- requirement: &70346489903680 !ruby/object:Gem::Requirement
16
+ requirement: &70138524107880 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70346489903680
24
+ version_requirements: *70138524107880
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: mocha
27
- requirement: &70346489903000 !ruby/object:Gem::Requirement
27
+ requirement: &70138524105520 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70346489903000
35
+ version_requirements: *70138524105520
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: virtualbox
38
- requirement: &70346489902460 !ruby/object:Gem::Requirement
38
+ requirement: &70138524103420 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70346489902460
46
+ version_requirements: *70138524103420
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: chef
49
- requirement: &70346489901760 !ruby/object:Gem::Requirement
49
+ requirement: &70138524099600 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 0.10.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70346489901760
57
+ version_requirements: *70138524099600
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: net-ssh
60
- requirement: &70346489901160 !ruby/object:Gem::Requirement
60
+ requirement: &70138524098780 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: 2.1.3
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *70346489901160
68
+ version_requirements: *70138524098780
69
69
  description: Handles bootstrapping, running chef solo, rsyncing cookbooks etc
70
70
  email: mat@schaffer.me
71
71
  executables: []
@@ -74,7 +74,8 @@ extra_rdoc_files: []
74
74
  files:
75
75
  - lib/chef/knife/cook.rb
76
76
  - lib/chef/knife/kitchen.rb
77
- - lib/chef/knife/patches/data_bags_patch.rb
77
+ - lib/chef/knife/patches/parser.rb
78
+ - lib/chef/knife/patches/search_patch.rb
78
79
  - lib/chef/knife/prepare.rb
79
80
  - lib/knife-solo/info.rb
80
81
  - lib/knife-solo/kitchen_command.rb
@@ -92,18 +93,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
92
93
  - - ! '>='
93
94
  - !ruby/object:Gem::Version
94
95
  version: '0'
95
- segments:
96
- - 0
97
- hash: -2883154116349428333
98
96
  required_rubygems_version: !ruby/object:Gem::Requirement
99
97
  none: false
100
98
  requirements:
101
99
  - - ! '>='
102
100
  - !ruby/object:Gem::Version
103
101
  version: '0'
104
- segments:
105
- - 0
106
- hash: -2883154116349428333
107
102
  requirements: []
108
103
  rubyforge_project: nowarning
109
104
  rubygems_version: 1.8.6
@@ -1,42 +0,0 @@
1
- # Taken from Vagrant's patch: https://gist.github.com/867960
2
- # based on Brian Akins's patch: http://lists.opscode.com/sympa/arc/chef/2011-02/msg00000.html
3
- if Chef::Config[:solo]
4
- class Chef
5
- module Mixin
6
- module Language
7
- def data_bag(bag)
8
- @solo_data_bags = {} if @solo_data_bags.nil?
9
- unless @solo_data_bags[bag]
10
- @solo_data_bags[bag] = {}
11
- data_bag_path = Chef::Config[:data_bag_path]
12
- Dir.glob(File.join(data_bag_path, bag, "*.json")).each do |f|
13
- item = JSON.parse(IO.read(f))
14
- @solo_data_bags[bag][item['id']] = item
15
- end
16
- end
17
- @solo_data_bags[bag].keys
18
- end
19
-
20
- def data_bag_item(bag, item)
21
- data_bag(bag) unless ( !@solo_data_bags.nil? && @solo_data_bags[bag])
22
- @solo_data_bags[bag][item]
23
- end
24
-
25
- end
26
- end
27
- end
28
-
29
- class Chef
30
- class Recipe
31
- def search(bag_name, query=nil)
32
- Chef::Log.warn("Simplistic search patch, ignoring query of %s" % [query]) unless query.nil?
33
- data_bag(bag_name.to_s).each do |bag_item_id|
34
- bag_item = data_bag_item(bag_name.to_s, bag_item_id)
35
- yield bag_item
36
- end
37
- end
38
-
39
- end
40
- end
41
-
42
- end