chef-zero 0.9

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.
Files changed (52) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +79 -0
  3. data/Rakefile +19 -0
  4. data/bin/chef-zero +40 -0
  5. data/lib/chef_zero.rb +5 -0
  6. data/lib/chef_zero/cookbook_data.rb +110 -0
  7. data/lib/chef_zero/data_normalizer.rb +129 -0
  8. data/lib/chef_zero/endpoints/actor_endpoint.rb +68 -0
  9. data/lib/chef_zero/endpoints/actors_endpoint.rb +32 -0
  10. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +21 -0
  11. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -0
  12. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +106 -0
  13. data/lib/chef_zero/endpoints/cookbooks_base.rb +59 -0
  14. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +12 -0
  15. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +50 -0
  16. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -0
  17. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +21 -0
  18. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -0
  19. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +114 -0
  20. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -0
  21. data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -0
  22. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -0
  23. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -0
  24. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +35 -0
  25. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -0
  26. data/lib/chef_zero/endpoints/node_endpoint.rb +17 -0
  27. data/lib/chef_zero/endpoints/not_found_endpoint.rb +9 -0
  28. data/lib/chef_zero/endpoints/principal_endpoint.rb +30 -0
  29. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +41 -0
  30. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +65 -0
  31. data/lib/chef_zero/endpoints/role_endpoint.rb +16 -0
  32. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -0
  33. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +22 -0
  34. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +44 -0
  35. data/lib/chef_zero/endpoints/search_endpoint.rb +139 -0
  36. data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -0
  37. data/lib/chef_zero/rest_base.rb +82 -0
  38. data/lib/chef_zero/rest_error_response.rb +11 -0
  39. data/lib/chef_zero/rest_request.rb +42 -0
  40. data/lib/chef_zero/router.rb +26 -0
  41. data/lib/chef_zero/server.rb +255 -0
  42. data/lib/chef_zero/solr/query/binary_operator.rb +53 -0
  43. data/lib/chef_zero/solr/query/phrase.rb +23 -0
  44. data/lib/chef_zero/solr/query/range_query.rb +34 -0
  45. data/lib/chef_zero/solr/query/regexpable_query.rb +29 -0
  46. data/lib/chef_zero/solr/query/subquery.rb +35 -0
  47. data/lib/chef_zero/solr/query/term.rb +45 -0
  48. data/lib/chef_zero/solr/query/unary_operator.rb +43 -0
  49. data/lib/chef_zero/solr/solr_doc.rb +62 -0
  50. data/lib/chef_zero/solr/solr_parser.rb +194 -0
  51. data/lib/chef_zero/version.rb +3 -0
  52. metadata +132 -0
@@ -0,0 +1,29 @@
1
+ module ChefZero
2
+ module Solr
3
+ module Query
4
+ class RegexpableQuery
5
+ def initialize(regexp_string, literal_string)
6
+ @regexp_string = regexp_string
7
+ # Surround the regexp with word boundaries
8
+ @regexp = Regexp.new("(^|#{NON_WORD_CHARACTER})#{regexp_string}($|#{NON_WORD_CHARACTER})", true)
9
+ @literal_string = literal_string
10
+ end
11
+
12
+ attr_reader :literal_string
13
+ attr_reader :regexp_string
14
+ attr_reader :regexp
15
+
16
+ def matches_doc?(doc)
17
+ value = doc[DEFAULT_FIELD]
18
+ return value ? matches_values?([value]) : false
19
+ end
20
+ def matches_values?(values)
21
+ values.any? { |value| !@regexp.match(value).nil? }
22
+ end
23
+
24
+ WORD_CHARACTER = "[A-Za-z0-9@._':]"
25
+ NON_WORD_CHARACTER = "[^A-Za-z0-9@._':]"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,35 @@
1
+ module ChefZero
2
+ module Solr
3
+ module Query
4
+ class Subquery
5
+ def initialize(subquery)
6
+ @subquery = subquery
7
+ end
8
+
9
+ def to_s
10
+ "(#{@subquery})"
11
+ end
12
+
13
+ def literal_string
14
+ subquery.literal_string
15
+ end
16
+
17
+ def regexp
18
+ subquery.regexp
19
+ end
20
+
21
+ def regexp_string
22
+ subquery.regexp_string
23
+ end
24
+
25
+ def matches_doc?(doc)
26
+ subquery.matches_doc?(doc)
27
+ end
28
+
29
+ def matches_values?(values)
30
+ subquery.matches_values?(values)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ require 'chef_zero/solr/query/regexpable_query'
2
+
3
+ module ChefZero
4
+ module Solr
5
+ module Query
6
+ class Term < RegexpableQuery
7
+ def initialize(term)
8
+ # Get rid of escape characters, turn * and ? into .* and . for regex, and
9
+ # escape everything that needs escaping
10
+ literal_string = ""
11
+ regexp_string = ""
12
+ index = 0
13
+ while index < term.length
14
+ if term[index] == '*'
15
+ regexp_string << "#{WORD_CHARACTER}*"
16
+ literal_string = nil
17
+ index += 1
18
+ elsif term[index] == '?'
19
+ regexp_string << WORD_CHARACTER
20
+ literal_string = nil
21
+ index += 1
22
+ elsif term[index] == '~'
23
+ raise "~ unsupported"
24
+ else
25
+ if term[index] == '\\'
26
+ index = index+1
27
+ if index >= term.length
28
+ raise "Backslash at end of string '#{term}'"
29
+ end
30
+ end
31
+ literal_string << term[index] if literal_string
32
+ regexp_string << Regexp.escape(term[index])
33
+ index += 1
34
+ end
35
+ end
36
+ super(regexp_string, literal_string)
37
+ end
38
+
39
+ def to_s
40
+ "Term(#{regexp_string})"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ module ChefZero
2
+ module Solr
3
+ module Query
4
+ class UnaryOperator
5
+ def initialize(operator, operand)
6
+ @operator = operator
7
+ @operand = operand
8
+ end
9
+
10
+ def to_s
11
+ "#{operator} #{operand}"
12
+ end
13
+
14
+ attr_reader :operator
15
+ attr_reader :operand
16
+
17
+ def matches_doc?(doc)
18
+ case @operator
19
+ when '-'
20
+ when 'NOT'
21
+ !operand.matches_doc?(doc)
22
+ when '+'
23
+ # TODO This operator uses relevance to eliminate other, unrelated
24
+ # expressions. +a OR b means "if it has b but not a, don't return it"
25
+ raise "+ not supported yet, because it is hard."
26
+ end
27
+ end
28
+
29
+ def matches_values?(values)
30
+ case @operator
31
+ when '-'
32
+ when 'NOT'
33
+ !operand.matches_values?(values)
34
+ when '+'
35
+ # TODO This operator uses relevance to eliminate other, unrelated
36
+ # expressions. +a OR b means "if it has b but not a, don't return it"
37
+ raise "+ not supported yet, because it is hard."
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,62 @@
1
+ module ChefZero
2
+ module Solr
3
+ # This does what expander does, flattening the json doc into keys and values
4
+ # so that solr can search them.
5
+ class SolrDoc
6
+ def initialize(json, id)
7
+ @json = json
8
+ @id = id
9
+ end
10
+
11
+ def [](key)
12
+ values = matching_values { |match_key| match_key == key }
13
+ values[0]
14
+ end
15
+
16
+ def matching_values(&block)
17
+ result = {}
18
+ key_values(nil, @json) do |key, value|
19
+ if block.call(key)
20
+ if result.has_key?(key)
21
+ result[key] << value.to_s
22
+ else
23
+ result[key] = value.to_s.clone
24
+ end
25
+ end
26
+ end
27
+ # Handle manufactured value(s)
28
+ if block.call('X_CHEF_id_CHEF_X')
29
+ if result.has_key?('X_CHEF_id_CHEF_X')
30
+ result['X_CHEF_id_CHEF_X'] << @id.to_s
31
+ else
32
+ result['X_CHEF_id_CHEF_X'] = @id.to_s.clone
33
+ end
34
+ end
35
+
36
+ result.values
37
+ end
38
+
39
+ private
40
+
41
+ def key_values(key_so_far, value, &block)
42
+ if value.is_a?(Hash)
43
+ value.each_pair do |child_key, child_value|
44
+ block.call(child_key, child_value.to_s)
45
+ if key_so_far
46
+ new_key = "#{key_so_far}_#{child_key}"
47
+ key_values(new_key, child_value, &block)
48
+ else
49
+ key_values(child_key, child_value, &block) if child_value.is_a?(Hash) || child_value.is_a?(Array)
50
+ end
51
+ end
52
+ elsif value.is_a?(Array)
53
+ value.each do |child_value|
54
+ key_values(key_so_far, child_value, &block)
55
+ end
56
+ else
57
+ block.call(key_so_far || 'text', value.to_s)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,194 @@
1
+ require 'chef_zero/solr/query/binary_operator'
2
+ require 'chef_zero/solr/query/unary_operator'
3
+ require 'chef_zero/solr/query/term'
4
+ require 'chef_zero/solr/query/phrase'
5
+ require 'chef_zero/solr/query/range_query'
6
+ require 'chef_zero/solr/query/subquery'
7
+
8
+ module ChefZero
9
+ module Solr
10
+ class SolrParser
11
+ def initialize(query_string)
12
+ @query_string = query_string
13
+ @index = 0
14
+ end
15
+
16
+ def parse
17
+ read_expression
18
+ end
19
+
20
+ #
21
+ # Tokenization
22
+ #
23
+ def peek_token
24
+ @next_token ||= parse_token
25
+ end
26
+
27
+ def next_token
28
+ result = peek_token
29
+ @next_token = nil
30
+ result
31
+ end
32
+
33
+ def parse_token
34
+ # Skip whitespace
35
+ skip_whitespace
36
+ return nil if eof?
37
+
38
+ # Operators
39
+ operator = peek_operator_token
40
+ if operator
41
+ @index+=operator.length
42
+ operator
43
+ else
44
+ # Everything that isn't whitespace or an operator, is part of a term
45
+ # (characters plus backslashed escaped characters)
46
+ start_index = @index
47
+ begin
48
+ if @query_string[@index] == '\\'
49
+ @index+=1
50
+ end
51
+ @index+=1 if !eof?
52
+ end until eof? || @query_string[@index] =~ /\s/ || peek_operator_token
53
+ @query_string[start_index..@index-1]
54
+ end
55
+ end
56
+
57
+ def skip_whitespace
58
+ if @query_string[@index] =~ /\s/
59
+ whitespace = /\s+/.match(@query_string, @index)
60
+ @index += whitespace[0].length
61
+ end
62
+ end
63
+
64
+ def peek_operator_token
65
+ if ['"', '+', '-', '!', '(', ')', '{', '}', '[', ']', '^', ':'].include?(@query_string[@index])
66
+ return @query_string[@index]
67
+ else
68
+ result = @query_string[@index..@index+1]
69
+ if ['&&', '||'].include?(result)
70
+ return result
71
+ end
72
+ end
73
+ nil
74
+ end
75
+
76
+ def eof?
77
+ !@next_token && @index >= @query_string.length
78
+ end
79
+
80
+ # Parse tree creation
81
+ def read_expression
82
+ result = read_single_expression
83
+ # Expression is over when we hit a close paren or eof
84
+ # (peek_token has the side effect of skipping whitespace for us, so we
85
+ # really know if we're at eof or not)
86
+ until peek_token == ')' || eof?
87
+ operator = peek_token
88
+ if binary_operator?(operator)
89
+ next_token
90
+ else
91
+ # If 2 terms are next to each other, the default operator is OR
92
+ operator = 'OR'
93
+ end
94
+ next_expression = read_single_expression
95
+
96
+ # Build the operator, taking precedence into account
97
+ if result.is_a?(Query::BinaryOperator) &&
98
+ binary_operator_precedence(operator) > binary_operator_precedence(result.operator)
99
+ # a+b*c -> a+(b*c)
100
+ new_right = Query::BinaryOperator.new(result.right, operator, next_expression)
101
+ result = Query::BinaryOperator.new(result.left, result.operator, new_right)
102
+ else
103
+ # a*b+c -> (a*b)+c
104
+ result = Query::BinaryOperator.new(result, operator, next_expression)
105
+ end
106
+ end
107
+ result
108
+ end
109
+
110
+ def parse_error(token, str)
111
+ error = "Error on token '#{token}' at #{@index} of '#{@query_string}': #{str}"
112
+ puts error
113
+ raise error
114
+ end
115
+
116
+ def read_single_expression
117
+ token = next_token
118
+ # If EOF, we have a problem Houston
119
+ if !token
120
+ parse_error(nil, "Expected expression!")
121
+
122
+ # If it's an unary operand, build that
123
+ elsif unary_operator?(token)
124
+ operand = read_single_expression
125
+ # TODO We rely on all unary operators having higher precedence than all
126
+ # binary operators. Check if this is the case.
127
+ Query::UnaryOperator.new(token, operand)
128
+
129
+ # If it's the start of a phrase, read the terms in the phrase
130
+ elsif token == '"'
131
+ # Read terms until close "
132
+ phrase_terms = []
133
+ until (term = next_token) == '"'
134
+ phrase_terms << Query::Term.new(term)
135
+ end
136
+ Query::Phrase.new(phrase_terms)
137
+
138
+ # If it's the start of a range query, build that
139
+ elsif token == '{' || token == '['
140
+ left = next_token
141
+ parse_error(left, "Expected left term in range query") if !left
142
+ to = next_token
143
+ parse_error(left, "Expected TO in range query") if to != "TO"
144
+ right = next_token
145
+ parse_error(right, "Expected left term in range query") if !right
146
+ end_range = next_token
147
+ parse_error(right, "Expected end range '#{expected_end_range}") if !['{', '['].include?(end_range)
148
+ Query::RangeQuery.new(left, right, token == '[', end_range == ']')
149
+
150
+ elsif token == '('
151
+ subquery = read_expression
152
+ close_paren = next_token
153
+ parse_error(close_paren, "Expected ')'") if close_paren != ')'
154
+ Query::Subquery.new(subquery)
155
+
156
+ # If it's the end of a closure, raise an exception
157
+ elsif ['}',']',')'].include?(token)
158
+ parse_error(token, "Unexpected end paren")
159
+
160
+ # If it's a binary operator, raise an exception
161
+ elsif binary_operator?(token)
162
+ parse_error(token, "Unexpected binary operator")
163
+
164
+ # Otherwise it's a term.
165
+ else
166
+ Query::Term.new(token)
167
+ end
168
+ end
169
+
170
+ def unary_operator?(token)
171
+ [ 'NOT', '+', '-' ].include?(token)
172
+ end
173
+
174
+ def binary_operator?(token)
175
+ [ 'AND', 'OR', '^', ':'].include?(token)
176
+ end
177
+
178
+ def binary_operator_precedence(token)
179
+ case token
180
+ when '^'
181
+ 4
182
+ when ':'
183
+ 3
184
+ when 'AND'
185
+ 2
186
+ when 'OR'
187
+ 1
188
+ end
189
+ end
190
+
191
+ DEFAULT_FIELD = 'text'
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,3 @@
1
+ module ChefZero
2
+ VERSION = '0.9'
3
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef-zero
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.9'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - John Keiser
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chef
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: thin
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Self-contained, easy-setup, fast-start in-memory Chef server for testing
47
+ and solo setup purposes
48
+ email: jkeiser@opscode.com
49
+ executables:
50
+ - chef-zero
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - README.rdoc
54
+ - LICENSE
55
+ files:
56
+ - LICENSE
57
+ - README.rdoc
58
+ - Rakefile
59
+ - lib/chef_zero/cookbook_data.rb
60
+ - lib/chef_zero/data_normalizer.rb
61
+ - lib/chef_zero/endpoints/actor_endpoint.rb
62
+ - lib/chef_zero/endpoints/actors_endpoint.rb
63
+ - lib/chef_zero/endpoints/authenticate_user_endpoint.rb
64
+ - lib/chef_zero/endpoints/cookbook_endpoint.rb
65
+ - lib/chef_zero/endpoints/cookbook_version_endpoint.rb
66
+ - lib/chef_zero/endpoints/cookbooks_base.rb
67
+ - lib/chef_zero/endpoints/cookbooks_endpoint.rb
68
+ - lib/chef_zero/endpoints/data_bag_endpoint.rb
69
+ - lib/chef_zero/endpoints/data_bag_item_endpoint.rb
70
+ - lib/chef_zero/endpoints/data_bags_endpoint.rb
71
+ - lib/chef_zero/endpoints/environment_cookbook_endpoint.rb
72
+ - lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb
73
+ - lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb
74
+ - lib/chef_zero/endpoints/environment_endpoint.rb
75
+ - lib/chef_zero/endpoints/environment_nodes_endpoint.rb
76
+ - lib/chef_zero/endpoints/environment_recipes_endpoint.rb
77
+ - lib/chef_zero/endpoints/environment_role_endpoint.rb
78
+ - lib/chef_zero/endpoints/file_store_file_endpoint.rb
79
+ - lib/chef_zero/endpoints/node_endpoint.rb
80
+ - lib/chef_zero/endpoints/not_found_endpoint.rb
81
+ - lib/chef_zero/endpoints/principal_endpoint.rb
82
+ - lib/chef_zero/endpoints/rest_list_endpoint.rb
83
+ - lib/chef_zero/endpoints/rest_object_endpoint.rb
84
+ - lib/chef_zero/endpoints/role_endpoint.rb
85
+ - lib/chef_zero/endpoints/role_environments_endpoint.rb
86
+ - lib/chef_zero/endpoints/sandbox_endpoint.rb
87
+ - lib/chef_zero/endpoints/sandboxes_endpoint.rb
88
+ - lib/chef_zero/endpoints/search_endpoint.rb
89
+ - lib/chef_zero/endpoints/searches_endpoint.rb
90
+ - lib/chef_zero/rest_base.rb
91
+ - lib/chef_zero/rest_error_response.rb
92
+ - lib/chef_zero/rest_request.rb
93
+ - lib/chef_zero/router.rb
94
+ - lib/chef_zero/server.rb
95
+ - lib/chef_zero/solr/query/binary_operator.rb
96
+ - lib/chef_zero/solr/query/phrase.rb
97
+ - lib/chef_zero/solr/query/range_query.rb
98
+ - lib/chef_zero/solr/query/regexpable_query.rb
99
+ - lib/chef_zero/solr/query/subquery.rb
100
+ - lib/chef_zero/solr/query/term.rb
101
+ - lib/chef_zero/solr/query/unary_operator.rb
102
+ - lib/chef_zero/solr/solr_doc.rb
103
+ - lib/chef_zero/solr/solr_parser.rb
104
+ - lib/chef_zero/version.rb
105
+ - lib/chef_zero.rb
106
+ - bin/chef-zero
107
+ homepage: http://www.opscode.com
108
+ licenses: []
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 1.8.23
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: Self-contained, easy-setup, fast-start in-memory Chef server for testing
131
+ and solo setup purposes
132
+ test_files: []