chef-zero 0.9

Sign up to get free protection for your applications and to get access to all the features.
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: []