Initial Chef repository

This commit is contained in:
Greg Karékinian
2015-07-21 19:45:23 +02:00
parent 7e5401fc71
commit ee4079fa85
1151 changed files with 185163 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
#
# Copyright 2011, edelight GmbH
#
# Authors:
# Markus Korn <markus.korn@edelight.de>
# Seth Chisamore <schisamo@opscode.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if Chef::Config[:solo]
# add currrent dir to load path
$: << File.dirname(__FILE__)
# All chef/solr_query/* classes were removed in Chef 11; Load vendored copy
# that ships with this cookbook
$: << File.expand_path("vendor", File.dirname(__FILE__)) if Chef::VERSION.to_i >= 11
# Ensure the treetop gem is installed and available
begin
require 'treetop'
rescue LoadError
run_context = Chef::RunContext.new(Chef::Node.new, {}, Chef::EventDispatch::Dispatcher.new)
chef_gem = Chef::Resource::ChefGem.new("treetop", run_context)
chef_gem.version('>= 1.4')
chef_gem.run_action(:install)
end
require 'search/overrides'
require 'search/parser'
module Search; class Helper; end; end
# The search and data_bag related methods moved form `Chef::Mixin::Language`
# to `Chef::DSL::DataQuery` in Chef 11.
if Chef::VERSION.to_i >= 11
module Chef::DSL::DataQuery
def self.included(base)
base.send(:include, Search::Overrides)
end
end
Search::Helper.send(:include, Chef::DSL::DataQuery)
else
module Chef::Mixin::Language
def self.included(base)
base.send(:include, Search::Overrides)
end
end
Search::Helper.send(:include, Chef::Mixin::Language)
end
class Chef
class Search
class Query
def initialize(*args)
end
def search(*args, &block)
::Search::Helper.new.search(*args, &block)
end
end
end
end
end

View File

@@ -0,0 +1,100 @@
#
# Copyright 2011, edelight GmbH
#
# Authors:
# Markus Korn <markus.korn@edelight.de>
# Seth Chisamore <schisamo@opscode.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
module Search
module Overrides
# Overwrite the search method of recipes to operate locally by using
# data found in data_bags.
# Only very basic lucene syntax is supported and also sorting the result
# is not implemented, if this search method does not support a given query
# an exception is raised.
# This search() method returns a block iterator or an Array, depending
# on how this method is called.
def search(obj, query=nil, sort=nil, start=0, rows=1000, &block)
if !sort.nil?
raise "Sorting search results is not supported"
end
_query = Query.parse(query)
if _query.nil?
raise "Query #{query} is not supported"
end
_result = []
case obj
when :node
nodes = search_nodes(_query, start, rows, &block)
_result += nodes
when :role
roles = search_roles(_query, start, rows, &block)
_result += roles
else
bags = search_data_bag(_query, obj, start, rows, &block)
_result += bags
end
if block_given?
pos = 0
while (pos >= start and pos < (start + rows) and pos < _result.size)
yield _result[pos]
pos += 1
end
else
return _result.slice(start, rows)
end
end
def search_nodes(_query, start, rows, &block)
_result = []
node_path = Chef::Config[:nodes_path] || File.join(Chef::Config[:data_bag_path], "node")
Dir.glob(File.join(node_path, "*.json")).map do |f|
# parse and hashify the node
node = Chef::JSONCompat.from_json(IO.read(f))
if _query.match(node.to_hash)
_result << node
end
end
return _result
end
def search_roles(_query, start, rows, &block)
_result = []
Dir.glob(File.join(Chef::Config[:role_path], "*.json")).map do |f|
# parse and hashify the role
role = Chef::JSONCompat.from_json(IO.read(f))
if _query.match(role.to_hash)
_result << role
end
end
return _result
end
def search_data_bag(_query, bag_name, start, rows, &block)
_result = []
data_bag(bag_name.to_s).each do |bag_item_id|
bag_item = data_bag_item(bag_name.to_s, bag_item_id)
if _query.match(bag_item)
_result << bag_item
end
end
return _result
end
end
end

View File

@@ -0,0 +1,222 @@
#
# Copyright 2011, edelight GmbH
#
# Authors:
# Markus Korn <markus.korn@edelight.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/solr_query/query_transform'
# mock QueryTransform such that we can access the location of the lucene grammar
class Chef
class SolrQuery
class QueryTransform
def self.base_path
class_variable_get(:@@base_path)
end
end
end
end
def build_flat_hash(hsh, prefix="")
result = {}
hsh.each_pair do |key, value|
if value.kind_of?(Hash)
result.merge!(build_flat_hash(value, "#{prefix}#{key}_"))
else
result[prefix+key] = value
end
end
result
end
module Lucene
class Term < Treetop::Runtime::SyntaxNode
# compares a query value and a value, tailing '*'-wildcards are handled correctly.
# Value can either be a string or an array, all other objects are converted
# to a string and than checked.
def match( value )
if value.is_a?(Array)
value.any?{ |x| self.match(x) }
else
File.fnmatch(self.text_value, value.to_s)
end
end
end
class Field < Treetop::Runtime::SyntaxNode
# simple field -> value matches, supporting tailing '*'-wildcards in keys
# as well as in values
def match( item )
keys = self.elements[0].match(item)
if keys.nil?
false
else
keys.any?{ |key| self.elements[1].match(item[key]) }
end
end
end
# we don't support range matches
# range of integers would be easy to implement
# but string ranges are hard
class FiledRange < Treetop::Runtime::SyntaxNode
end
# we handle '[* TO *]' as a special case since it is common in
# cookbooks for matching the existence of keys
class InclFieldRange
def match(item)
field = self.elements[0].text_value
range_start = self.elements[1].transform
range_end = self.elements[2].transform
if range_start == "*" and range_end == "*"
!!item[field]
else
raise "Ranges not really supported yet"
end
end
end
class ExclFieldRange < FieldRange
end
class RangeValue < Treetop::Runtime::SyntaxNode
end
class FieldName < Treetop::Runtime::SyntaxNode
def match( item )
if self.text_value.count("_") > 0
item.merge!(build_flat_hash(item))
end
if self.text_value.end_with?("*")
part = self.text_value.chomp("*")
item.keys.collect{ |key| key.start_with?(part)? key: nil}.compact
else
if item.has_key?(self.text_value)
[self.text_value,]
else
nil
end
end
end
end
class Body < Treetop::Runtime::SyntaxNode
def match( item )
self.elements[0].match( item )
end
end
class Group < Treetop::Runtime::SyntaxNode
def match( item )
self.elements[0].match(item)
end
end
class BinaryOp < Treetop::Runtime::SyntaxNode
def match( item )
self.elements[1].match(
self.elements[0].match(item),
self.elements[2].match(item)
)
end
end
class OrOperator < Treetop::Runtime::SyntaxNode
def match( cond1, cond2 )
cond1 or cond2
end
end
class AndOperator < Treetop::Runtime::SyntaxNode
def match( cond1, cond2 )
cond1 and cond2
end
end
# we don't support fuzzy string matching
class FuzzyOp < Treetop::Runtime::SyntaxNode
end
class BoostOp < Treetop::Runtime::SyntaxNode
end
class FuzzyParam < Treetop::Runtime::SyntaxNode
end
class UnaryOp < Treetop::Runtime::SyntaxNode
def match( item )
self.elements[0].match(
self.elements[1].match(item)
)
end
end
class NotOperator < Treetop::Runtime::SyntaxNode
def match( cond )
not cond
end
end
class RequiredOperator < Treetop::Runtime::SyntaxNode
end
class ProhibitedOperator < Treetop::Runtime::SyntaxNode
end
class Phrase < Treetop::Runtime::SyntaxNode
# a quoted ::Term
def match( value )
self.elements[0].match(value)
end
end
end
class Query
# initialize the parser by using the grammar shipped with chef
@@grammar = File.join(Chef::SolrQuery::QueryTransform.base_path, "lucene.treetop")
Treetop.load(@@grammar)
@@parser = LuceneParser.new
def self.parse(data)
# parse the query into a query tree
if data.nil?
data = "*:*"
end
tree = @@parser.parse(data)
if tree.nil?
msg = "Parse error at offset: #{@@parser.index}\n"
msg += "Reason: #{@@parser.failure_reason}"
raise "Query #{data} is not supported: #{msg}"
end
self.clean_tree(tree)
tree
end
private
def self.clean_tree(root_node)
# remove all SyntaxNode elements from the tree, we don't need them as
# the related ruby class already knowns what to do.
return if root_node.elements.nil?
root_node.elements.delete_if do |node|
node.class.name == "Treetop::Runtime::SyntaxNode"
end
root_node.elements.each { |node| self.clean_tree(node) }
end
end

View File

@@ -0,0 +1,150 @@
#
# Author:: Seth Falcon (<seth@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
grammar Lucene
rule body
(expression / space)* <Body>
end
rule expression
operation / group / field / field_range / term / string
end
rule term
keyword valid_letter+ <Term> / !keyword !"?" valid_letter <Term>
end
rule field
field_name ":" (term/string/group) <Field>
end
rule field_range
field_name ":" "[" range_value " TO " range_value "]" <InclFieldRange>
/
field_name ":" "{" range_value " TO " range_value "}" <ExclFieldRange>
end
rule field_name
!keyword valid_letter+ <FieldName>
end
rule range_value
valid_letter+ <RangeValue> / "*" <RangeValue>
end
rule group
space? '(' body ')' space? <Group>
end
rule operation
binary_op / unary_op / fuzzy_op / boost_op
end
rule unary_op
not_op / required_op / prohibited_op
end
rule binary_op
(group / field / field_range / term) space? boolean_operator space+ body <BinaryOp>
end
rule boolean_operator
and_operator / or_operator
end
rule and_operator
'AND' <AndOperator> / '&&' <AndOperator>
end
rule or_operator
'OR' <OrOperator> / '||' <OrOperator>
end
rule not_op
not_operator space (group / field / field_range / term / string) <UnaryOp>
/
bang_operator space? (group / field / field_range / term / string) <UnaryOp>
end
rule not_operator
'NOT' <NotOperator>
end
rule bang_operator
'!' <NotOperator>
end
rule required_op
!valid_letter required_operator (term/string) <UnaryOp>
/
required_operator (term/string) <UnaryOp>
end
rule required_operator
'+' <RequiredOperator>
end
rule prohibited_op
!valid_letter prohibited_operator (field/field_range/term/string) <UnaryOp>
end
rule prohibited_operator
'-' <ProhibitedOperator>
end
rule boost_op
(term/string) '^' fuzzy_param <BoostOp>
end
rule fuzzy_op
(term/string) '~' fuzzy_param? (space / !valid_letter) <FuzzyOp>
end
rule fuzzy_param
[0-9] '.'? [0-9] <FuzzyParam> / [0-9]+ <FuzzyParam>
end
rule string
'"' term (space term)* '"' <Phrase>
end
rule keyword
'AND' / 'OR' / 'NOT'
end
rule valid_letter
start_letter+ ([a-zA-Z0-9@*?_.-] / '\\' special_char)*
end
rule start_letter
[a-zA-Z0-9@._*] / '\\' special_char
end
rule end_letter
[a-zA-Z0-9*?_.] / '\\' special_char
end
rule special_char
[-+&|!(){}\[\]^"~*?:\\]
end
rule space
[\s]+
end
end

View File

@@ -0,0 +1,285 @@
#
# Author:: Seth Falcon (<seth@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'treetop'
module Lucene
SEP = "__=__"
class Term < Treetop::Runtime::SyntaxNode
def to_array
"T:#{self.text_value}"
end
def transform
self.text_value
end
end
class Field < Treetop::Runtime::SyntaxNode
def to_array
field = self.elements[0].text_value
term = self.elements[1].to_array
"(F:#{field} #{term})"
end
def transform
field = self.elements[0].text_value
term = self.elements[1]
if term.is_a? Phrase
str = term.transform
# remove quotes
str = str[1 ... (str.length - 1)]
"content:\"#{field}#{SEP}#{str}\""
else
"content:#{field}#{SEP}#{term.transform}"
end
end
end
class FieldRange < Treetop::Runtime::SyntaxNode
def to_array
field = self.elements[0].text_value
range_start = self.elements[1].to_array
range_end = self.elements[2].to_array
"(FR:#{field} #{left}#{range_start}#{right} #{left}#{range_end}#{right})"
end
def transform
field = self.elements[0].text_value
range_start = self.elements[1].transform
range_end = self.elements[2].transform
# FIXME: handle special cases for missing start/end
if ("*" == range_start && "*" == range_end)
"content:#{field}#{SEP}*"
elsif "*" == range_end
"content:#{left}#{field}#{SEP}#{range_start} TO #{field}#{SEP}\\ufff0#{right}"
elsif "*" == range_start
"content:#{left}#{field}#{SEP} TO #{field}#{SEP}#{range_end}#{right}"
else
"content:#{left}#{field}#{SEP}#{range_start} TO #{field}#{SEP}#{range_end}#{right}"
end
end
end
class InclFieldRange < FieldRange
def left
"["
end
def right
"]"
end
end
class ExclFieldRange < FieldRange
def left
"{"
end
def right
"}"
end
end
class RangeValue < Treetop::Runtime::SyntaxNode
def to_array
self.text_value
end
def transform
to_array
end
end
class FieldName < Treetop::Runtime::SyntaxNode
def to_array
self.text_value
end
def transform
to_array
end
end
class Body < Treetop::Runtime::SyntaxNode
def to_array
self.elements.map { |x| x.to_array }.join(" ")
end
def transform
self.elements.map { |x| x.transform }.join(" ")
end
end
class Group < Treetop::Runtime::SyntaxNode
def to_array
"(" + self.elements[0].to_array + ")"
end
def transform
"(" + self.elements[0].transform + ")"
end
end
class BinaryOp < Treetop::Runtime::SyntaxNode
def to_array
op = self.elements[1].to_array
a = self.elements[0].to_array
b = self.elements[2].to_array
"(#{op} #{a} #{b})"
end
def transform
op = self.elements[1].transform
a = self.elements[0].transform
b = self.elements[2].transform
"#{a} #{op} #{b}"
end
end
class AndOperator < Treetop::Runtime::SyntaxNode
def to_array
"OP:AND"
end
def transform
"AND"
end
end
class OrOperator < Treetop::Runtime::SyntaxNode
def to_array
"OP:OR"
end
def transform
"OR"
end
end
class FuzzyOp < Treetop::Runtime::SyntaxNode
def to_array
a = self.elements[0].to_array
param = self.elements[1]
if param
"(OP:~ #{a} #{param.to_array})"
else
"(OP:~ #{a})"
end
end
def transform
a = self.elements[0].transform
param = self.elements[1]
if param
"#{a}~#{param.transform}"
else
"#{a}~"
end
end
end
class BoostOp < Treetop::Runtime::SyntaxNode
def to_array
a = self.elements[0].to_array
param = self.elements[1]
"(OP:^ #{a} #{param.to_array})"
end
def transform
a = self.elements[0].transform
param = self.elements[1]
"#{a}^#{param.transform}"
end
end
class FuzzyParam < Treetop::Runtime::SyntaxNode
def to_array
self.text_value
end
def transform
self.text_value
end
end
class UnaryOp < Treetop::Runtime::SyntaxNode
def to_array
op = self.elements[0].to_array
a = self.elements[1].to_array
"(#{op} #{a})"
end
def transform
op = self.elements[0].transform
a = self.elements[1].transform
spc = case op
when "+", "-"
""
else
" "
end
"#{op}#{spc}#{a}"
end
end
class NotOperator < Treetop::Runtime::SyntaxNode
def to_array
"OP:NOT"
end
def transform
"NOT"
end
end
class RequiredOperator < Treetop::Runtime::SyntaxNode
def to_array
"OP:+"
end
def transform
"+"
end
end
class ProhibitedOperator < Treetop::Runtime::SyntaxNode
def to_array
"OP:-"
end
def transform
"-"
end
end
class Phrase < Treetop::Runtime::SyntaxNode
def to_array
"STR:#{self.text_value}"
end
def transform
"#{self.text_value}"
end
end
end

View File

@@ -0,0 +1,65 @@
#
# Author:: Seth Falcon (<seth@opscode.com>)
# Copyright:: Copyright (c) 2010-2011 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'treetop'
require 'chef/solr_query/lucene_nodes'
class Chef
class Exceptions
class QueryParseError < StandardError
end
end
end
class Chef
class SolrQuery
class QueryTransform
@@base_path = File.expand_path(File.dirname(__FILE__))
Treetop.load(File.join(@@base_path, 'lucene.treetop'))
@@parser = LuceneParser.new
def self.parse(data)
tree = @@parser.parse(data)
msg = "Parse error at offset: #{@@parser.index}\n"
msg += "Reason: #{@@parser.failure_reason}"
raise Chef::Exceptions::QueryParseError, msg if tree.nil?
self.clean_tree(tree)
tree.to_array
end
def self.transform(data)
return "*:*" if data == "*:*"
tree = @@parser.parse(data)
msg = "Parse error at offset: #{@@parser.index}\n"
msg += "Reason: #{@@parser.failure_reason}"
raise Chef::Exceptions::QueryParseError, msg if tree.nil?
self.clean_tree(tree)
tree.transform
end
private
def self.clean_tree(root_node)
return if root_node.elements.nil?
root_node.elements.delete_if do |node|
node.class.name == "Treetop::Runtime::SyntaxNode"
end
root_node.elements.each { |node| self.clean_tree(node) }
end
end
end
end