vayacondios-server 0.1.2 → 0.1.6
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.
- data/Gemfile +1 -0
- data/app/http_shim.rb +1 -5
- data/lib/vayacondios-client.rb +2 -0
- data/lib/vayacondios-server.rb +1 -0
- data/lib/vayacondios/client/cube_client.rb +39 -0
- data/lib/vayacondios/client/itemset.rb +43 -28
- data/lib/vayacondios/client/notifier.rb +24 -1
- data/lib/vayacondios/client/zabbix_client.rb +148 -0
- data/lib/vayacondios/server/handlers/itemset_handler.rb +0 -1
- data/lib/vayacondios/server/model/itemset_document.rb +8 -4
- data/lib/vayacondios/server/rack/assume_json.rb +13 -0
- data/lib/vayacondios/server/rack/extract_methods.rb +11 -1
- data/lib/vayacondios/version.rb +1 -1
- data/pom.xml +97 -0
- data/scripts/hadoop_monitor/configurable.rb +1 -1
- data/scripts/hadoop_monitor/hadoop_attempt_scraper.rb +6 -3
- data/scripts/hadoop_monitor/hadoop_client.rb +20 -19
- data/scripts/hadoop_monitor/hadoop_monitor.rb +3 -3
- data/scripts/hadoop_monitor/hadoopable.rb +3 -3
- data/scripts/hadoop_monitor/machine_monitor.rb +2 -2
- data/spec/client/itemset_spec.rb +8 -8
- data/spec/server/itemset_spec.rb +4 -4
- data/src/main/java/com/infochimps/util/CurrentClass.java +26 -0
- data/src/main/java/com/infochimps/util/DebugUtil.java +38 -0
- data/src/main/java/com/infochimps/util/HttpHelper.java +112 -0
- data/src/main/java/com/infochimps/vayacondios/ItemSets.java +456 -0
- data/src/main/java/com/infochimps/vayacondios/Organization.java +49 -0
- data/src/main/java/com/infochimps/vayacondios/PathBuilder.java +13 -0
- data/src/main/java/com/infochimps/vayacondios/VCDIntegrationTest.java +68 -0
- data/src/main/java/com/infochimps/vayacondios/VayacondiosClient.java +88 -0
- data/vayacondios-client.gemspec +2 -2
- data/vayacondios-server.gemspec +4 -2
- metadata +37 -9
    
        data/Gemfile
    CHANGED
    
    
    
        data/app/http_shim.rb
    CHANGED
    
    | @@ -3,12 +3,8 @@ | |
| 3 3 | 
             
            require 'vayacondios-server'
         | 
| 4 4 |  | 
| 5 5 | 
             
            class HttpShim < Goliath::API
         | 
| 6 | 
            +
              use Vayacondios::Rack::AssumeJSON                                      # assume application/json content type
         | 
| 6 7 | 
             
              use Goliath::Rack::Tracer, 'X-Tracer'                                  # log trace statistics
         | 
| 7 | 
            -
              # /v1/infochimps/itemset/foo/1 -d '["foo","bar","baz"]'
         | 
| 8 | 
            -
              # use Vayacondios::Rack::Versionator
         | 
| 9 | 
            -
              # /v1/infochimps/itemset/foo/1 -d '{"items":["foo","bar","baz"]}' ... env[:vayacondios_version] = 1
         | 
| 10 | 
            -
              # post_process()
         | 
| 11 | 
            -
              # extract results = results[:results] from body for legacy
         | 
| 12 8 | 
             
              use Goliath::Rack::Params                                              # parse query string and message body into params hash
         | 
| 13 9 | 
             
              use Goliath::Rack::Validation::RequestMethod, %w[GET PUT PATCH DELETE] # only allow these methods
         | 
| 14 10 | 
             
              use Vayacondios::Rack::ExtractMethods                                  # interpolate GET, PUT into :create, :update, etc
         | 
    
        data/lib/vayacondios-client.rb
    CHANGED
    
    | @@ -16,5 +16,7 @@ require 'gorillib/string/constantize' | |
| 16 16 | 
             
            require 'gorillib/string/inflections'
         | 
| 17 17 |  | 
| 18 18 | 
             
            require 'vayacondios/client/http_client'
         | 
| 19 | 
            +
            require 'vayacondios/client/cube_client'
         | 
| 20 | 
            +
            require 'vayacondios/client/zabbix_client'
         | 
| 19 21 | 
             
            require 'vayacondios/client/notifier'
         | 
| 20 22 | 
             
            require 'vayacondios/client/configliere'
         | 
    
        data/lib/vayacondios-server.rb
    CHANGED
    
    | @@ -22,6 +22,7 @@ require 'vayacondios/server/handlers/config_handler' | |
| 22 22 | 
             
            require 'vayacondios/server/handlers/event_handler'
         | 
| 23 23 | 
             
            require 'vayacondios/server/handlers/itemset_handler'
         | 
| 24 24 |  | 
| 25 | 
            +
            require 'vayacondios/server/rack/assume_json'
         | 
| 25 26 | 
             
            require 'vayacondios/server/rack/extract_methods'
         | 
| 26 27 | 
             
            require 'vayacondios/server/rack/path'
         | 
| 27 28 | 
             
            require 'vayacondios/server/rack/path_validation'
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            class Vayacondios
         | 
| 2 | 
            +
              class CubeClient
         | 
| 3 | 
            +
                include Gorillib::Model
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                field :host,         String,  :default => 'localhost'
         | 
| 6 | 
            +
                field :port,         Integer, :default => 6000
         | 
| 7 | 
            +
                
         | 
| 8 | 
            +
                class Error < StandardError; end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def uri
         | 
| 11 | 
            +
                  return @uri if @uri
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  uri_str  = "http://#{host}:#{port}/1.0"
         | 
| 14 | 
            +
                  @uri ||= URI(uri_str)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                def event(topic, document = {})
         | 
| 18 | 
            +
                  request(:post, File.join(uri.path, 'event'), MultiJson.dump(document))
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
              private
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                def request(method, path, document=nil)
         | 
| 24 | 
            +
                  http    = Net::HTTP.new(uri.host, uri.port)
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  params  = [method.to_sym, path]
         | 
| 27 | 
            +
                  params += [document, {'Content-Type' => 'application/json'}] unless document.nil?
         | 
| 28 | 
            +
                  
         | 
| 29 | 
            +
                  response = http.send *params
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  if Net::HTTPSuccess === response
         | 
| 32 | 
            +
                    MultiJson.load(response.body) rescue response.body
         | 
| 33 | 
            +
                  else
         | 
| 34 | 
            +
                    raise Error.new("Error (#{response.code}) while #{method.to_s == 'get' ? 'fetching' : 'inserting'} document: " + response.body)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
              
         | 
| @@ -4,42 +4,29 @@ require 'multi_json' | |
| 4 4 | 
             
            class Vayacondios
         | 
| 5 5 | 
             
              class Client
         | 
| 6 6 | 
             
                class ItemSet
         | 
| 7 | 
            -
                  def initialize host, port, organization, topic, id
         | 
| 8 | 
            -
                    @host | 
| 9 | 
            -
                    @port | 
| 10 | 
            -
             | 
| 11 | 
            -
                    @ | 
| 7 | 
            +
                  def initialize host, port, organization=nil, topic=nil, id=nil
         | 
| 8 | 
            +
                    @host         = host
         | 
| 9 | 
            +
                    @port         = port
         | 
| 10 | 
            +
                    @organization = organization
         | 
| 11 | 
            +
                    @topic        = topic
         | 
| 12 | 
            +
                    @id           = id
         | 
| 12 13 | 
             
                  end
         | 
| 13 14 |  | 
| 14 | 
            -
                   | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
                    when :fetch  then
         | 
| 18 | 
            -
                      req = Net::HTTP::Get.new(@path)
         | 
| 19 | 
            -
                    when :create then
         | 
| 20 | 
            -
                      (req = Net::HTTP::Put.new(@path)).body = MultiJson.encode(ary)
         | 
| 21 | 
            -
                    when :update then
         | 
| 22 | 
            -
                      (req = Net::HTTP::Put.new(@path, {"x-method" => "PATCH"})).body = MultiJson.encode(ary)
         | 
| 23 | 
            -
                    when :remove then
         | 
| 24 | 
            -
                      (req = Net::HTTP::Delete.new(@path)).body = MultiJson.encode(ary)
         | 
| 25 | 
            -
                    end
         | 
| 26 | 
            -
                    req
         | 
| 15 | 
            +
                  def fetch organization=nil, topic=nil, id=nil
         | 
| 16 | 
            +
                    resp = execute_request(_req(:fetch, nil, organization, topic, id)) and
         | 
| 17 | 
            +
                      resp["contents"]
         | 
| 27 18 | 
             
                  end
         | 
| 28 19 |  | 
| 29 | 
            -
                  def  | 
| 30 | 
            -
                    execute_request(_req(: | 
| 20 | 
            +
                  def update ary, organization=nil, topic=nil, id=nil
         | 
| 21 | 
            +
                    execute_request(_req(:update, ary, organization, topic, id))
         | 
| 31 22 | 
             
                  end
         | 
| 32 23 |  | 
| 33 | 
            -
                  def  | 
| 34 | 
            -
                    execute_request(_req(: | 
| 24 | 
            +
                  def create ary, organization=nil, topic=nil, id=nil
         | 
| 25 | 
            +
                    execute_request(_req(:create, ary, organization, topic, id))
         | 
| 35 26 | 
             
                  end
         | 
| 36 27 |  | 
| 37 | 
            -
                  def  | 
| 38 | 
            -
                    execute_request(_req(: | 
| 39 | 
            -
                  end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                  def remove ary
         | 
| 42 | 
            -
                    execute_request(_req(:remove, ary))
         | 
| 28 | 
            +
                  def remove ary, organization=nil, topic=nil, id=nil
         | 
| 29 | 
            +
                    execute_request(_req(:remove, ary, organization, topic, id))
         | 
| 43 30 | 
             
                  end
         | 
| 44 31 |  | 
| 45 32 |  | 
| @@ -52,6 +39,34 @@ class Vayacondios | |
| 52 39 | 
             
                    result = MultiJson.decode(resp) unless resp.nil? or resp.empty?
         | 
| 53 40 | 
             
                    (result.respond_to?(:has_key?) and result.has_key? "error") ? nil : result
         | 
| 54 41 | 
             
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def path organization, topic, id
         | 
| 44 | 
            +
                    if ((the_organization = (organization || @organization)).nil? ||
         | 
| 45 | 
            +
                        (the_topic        = (topic        || @topic       )).nil? ||
         | 
| 46 | 
            +
                        (the_id           = (id           || @id          )).nil?)
         | 
| 47 | 
            +
                      raise ArgumentError.new("must provide organization, topic, and id!")
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    ['/v1', the_organization, 'itemset', the_topic, the_id].join("/")
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  # This is the only private method that is tested.
         | 
| 54 | 
            +
                  def _req type, ary=nil, organization=nil, topic=nil, id=nil
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    the_path = path(organization, topic, id)
         | 
| 57 | 
            +
                    headers = {"content-type" => "application/json"}
         | 
| 58 | 
            +
                    headers.merge!("x-method" => "PATCH") if type == :update
         | 
| 59 | 
            +
             
         | 
| 60 | 
            +
                    case type
         | 
| 61 | 
            +
                    when :fetch  then Net::HTTP::Get
         | 
| 62 | 
            +
                    when :create then Net::HTTP::Put
         | 
| 63 | 
            +
                    when :update then Net::HTTP::Put
         | 
| 64 | 
            +
                    when :remove then Net::HTTP::Delete
         | 
| 65 | 
            +
                    else         raise ArgumentError.new("invalid type: #{type}")
         | 
| 66 | 
            +
                    end.new(the_path, headers).tap do |req|
         | 
| 67 | 
            +
                      req.body = MultiJson.encode(contents: ary) unless type == :fetch
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  end
         | 
| 55 70 | 
             
                end
         | 
| 56 71 | 
             
              end
         | 
| 57 72 | 
             
            end
         | 
| @@ -56,11 +56,34 @@ class Vayacondios | |
| 56 56 | 
             
                end
         | 
| 57 57 | 
             
              end
         | 
| 58 58 |  | 
| 59 | 
            +
              class CubeNotifier < Notifier
         | 
| 60 | 
            +
                def initialize(options={})
         | 
| 61 | 
            +
                  @client = Vayacondios::CubeClient.receive(options)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                def notify topic, cargo={}
         | 
| 64 | 
            +
                  prepped = prepare(cargo)
         | 
| 65 | 
            +
                  client.event(topic, prepped)
         | 
| 66 | 
            +
                  nil
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              class ZabbixNotifier < Notifier
         | 
| 71 | 
            +
                def initialize options={}
         | 
| 72 | 
            +
                  @client = Vayacondios::ZabbixClient.receive(options)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
                def notify(topic, cargo={})
         | 
| 75 | 
            +
                  prepped = prepare(cargo)
         | 
| 76 | 
            +
                  client.insert(topic, prepped)
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
              
         | 
| 59 80 | 
             
              class NotifierFactory
         | 
| 60 81 | 
             
                def self.receive(attrs = {})
         | 
| 61 82 | 
             
                  type = attrs[:type]
         | 
| 62 83 | 
             
                  case type
         | 
| 63 84 | 
             
                  when 'http'        then HttpNotifier.new(attrs)
         | 
| 85 | 
            +
                  when 'cube'        then CubeNotifier.new(attrs)
         | 
| 86 | 
            +
                  when 'zabbix'      then ZabbixNotifier.new(attrs)
         | 
| 64 87 | 
             
                  when 'log'         then LogNotifier.new(attrs)
         | 
| 65 88 | 
             
                  when 'none','null' then NullNotifier.new(attrs)
         | 
| 66 89 | 
             
                  else
         | 
| @@ -80,7 +103,7 @@ class Vayacondios | |
| 80 103 | 
             
                def self.included klass
         | 
| 81 104 | 
             
                  if klass.ancestors.include? Gorillib::Model
         | 
| 82 105 | 
             
                    klass.class_eval do
         | 
| 83 | 
            -
                      field :notifier, Vayacondios::NotifierFactory, default: Vayacondios.default_notifier
         | 
| 106 | 
            +
                      field :notifier, Vayacondios::NotifierFactory, default: Vayacondios.default_notifier, :doc => "Notifier used to notify out of band data"
         | 
| 84 107 |  | 
| 85 108 | 
             
                      def receive_notifier params
         | 
| 86 109 | 
             
                        params.merge!(log: try(:log)) if params[:type] == 'log'
         | 
| @@ -0,0 +1,148 @@ | |
| 1 | 
            +
            require 'socket'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Vayacondios
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              # Used for sending events to a Zabbix server.
         | 
| 6 | 
            +
              #
         | 
| 7 | 
            +
              # An 'event' from Vayacondios' perspective is an arbitrary Hash.
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              # An 'event' from Zabbix's perspective is a tuple of values:
         | 
| 10 | 
            +
              #
         | 
| 11 | 
            +
              # * time
         | 
| 12 | 
            +
              # * host
         | 
| 13 | 
            +
              # * key
         | 
| 14 | 
            +
              # * value
         | 
| 15 | 
            +
              #
         | 
| 16 | 
            +
              # This client will accept a Vayacondios event and internally
         | 
| 17 | 
            +
              # translate it into a set of Zabbix events.
         | 
| 18 | 
            +
              #
         | 
| 19 | 
            +
              # @example A CPU monitoring notification
         | 
| 20 | 
            +
              #
         | 
| 21 | 
            +
              #   notify "foo-server.example.com", cpu: {
         | 
| 22 | 
            +
              #     util: {
         | 
| 23 | 
            +
              #       user: 0.20,
         | 
| 24 | 
            +
              #       idle: 0.70,
         | 
| 25 | 
            +
              #       sys:  0.10
         | 
| 26 | 
            +
              #     },
         | 
| 27 | 
            +
              #     load: 1.3
         | 
| 28 | 
            +
              #   }
         | 
| 29 | 
            +
              #
         | 
| 30 | 
            +
              # would get turned into the following events when written to Zabbix:
         | 
| 31 | 
            +
              #
         | 
| 32 | 
            +
              # @example The CPU monitoring notification translated to Zabbix events
         | 
| 33 | 
            +
              #
         | 
| 34 | 
            +
              # [
         | 
| 35 | 
            +
              #   { host: "foo-server.example.com", key: "cpu.util.user", value: 0.20 }
         | 
| 36 | 
            +
              #   { host: "foo-server.example.com", key: "cpu.util.idle", value: 0.70 },
         | 
| 37 | 
            +
              #   { host: "foo-server.example.com", key: "cpu.util.sys",  value: 0.10 },
         | 
| 38 | 
            +
              #   { host: "foo-server.example.com", key: "cpu.load",      value: 1.3  }
         | 
| 39 | 
            +
              # ]
         | 
| 40 | 
            +
              #
         | 
| 41 | 
            +
              # Zabbix will interpret the time as the time it receives each event.
         | 
| 42 | 
            +
              #
         | 
| 43 | 
            +
              # The following links provide details on the protocol used by Zabbix
         | 
| 44 | 
            +
              # to receive events:
         | 
| 45 | 
            +
              #
         | 
| 46 | 
            +
              # * https://www.zabbix.com/forum/showthread.php?t=20047&highlight=sender
         | 
| 47 | 
            +
              # * https://gist.github.com/1170577
         | 
| 48 | 
            +
              # * http://spin.atomicobject.com/2012/10/30/collecting-metrics-from-ruby-processes-using-zabbix-trappers/?utm_source=rubyflow&utm_medium=ao&utm_campaign=collecting-metrics-zabix
         | 
| 49 | 
            +
              class ZabbixClient
         | 
| 50 | 
            +
                include Gorillib::Builder
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                attr_accessor :socket
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                field :host, String,  :default => 'localhost', :doc => "Host for the Zabbix server"
         | 
| 55 | 
            +
                field :port, Integer, :default => 10051,       :doc => "Port for the Zabbix server"
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                # Insert events to a Zabbix server.
         | 
| 58 | 
            +
                #
         | 
| 59 | 
            +
                # The `topic` will be used as the name of the Zabbix host to
         | 
| 60 | 
            +
                # associate event data to.
         | 
| 61 | 
            +
                #
         | 
| 62 | 
            +
                # As per the documentation for the [Zabbix sender
         | 
| 63 | 
            +
                # protocol](https://www.zabbix.com/wiki/doc/tech/proto/zabbixsenderprotocol),
         | 
| 64 | 
            +
                # a new TCP connection will be created for each event.
         | 
| 65 | 
            +
                #
         | 
| 66 | 
            +
                # @param [String] topic
         | 
| 67 | 
            +
                # @param [Hash] cargo
         | 
| 68 | 
            +
                # Array<Hash>] text
         | 
| 69 | 
            +
                def insert topic, cargo={}
         | 
| 70 | 
            +
                  self.socket = TCPSocket.new(host, port)
         | 
| 71 | 
            +
                  send_request(topic, cargo)
         | 
| 72 | 
            +
                  handle_response
         | 
| 73 | 
            +
                  self.socket.close
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                private
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                # :nodoc
         | 
| 79 | 
            +
                def send_request topic, cargo
         | 
| 80 | 
            +
                  socket.write(payload(topic, cargo))
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                # :nodoc
         | 
| 84 | 
            +
                def handle_response
         | 
| 85 | 
            +
                  header = socket.recv(5)
         | 
| 86 | 
            +
                  if header == "ZBXD\1"
         | 
| 87 | 
            +
                    data_header = socket.recv(8)
         | 
| 88 | 
            +
                    length      = data_header[0,4].unpack("i")[0]
         | 
| 89 | 
            +
                    response    = MultiJson.load(socket.recv(length))
         | 
| 90 | 
            +
                    puts response["info"]
         | 
| 91 | 
            +
                  else
         | 
| 92 | 
            +
                    puts "Invalid response: #{header}"
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                # :nodoc
         | 
| 97 | 
            +
                def payload topic, cargo={}
         | 
| 98 | 
            +
                  body = body_for(topic, cargo)
         | 
| 99 | 
            +
                  header_for(body) + body
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                # :nodoc
         | 
| 103 | 
            +
                def body_for topic, cargo={}
         | 
| 104 | 
            +
                  MultiJson.dump({request: "sender data", data: zabbix_events_from(topic, cargo) })
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                # :nodoc
         | 
| 108 | 
            +
                def header_for body
         | 
| 109 | 
            +
                  length = body.bytesize
         | 
| 110 | 
            +
                  "ZBXD\1".encode("ascii") + [length].pack("i") + "\x00\x00\x00\x00"
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                # :nodoc
         | 
| 114 | 
            +
                def zabbix_events_from topic, cargo, scope=''
         | 
| 115 | 
            +
                  events = []
         | 
| 116 | 
            +
                  case cargo
         | 
| 117 | 
            +
                  when Hash
         | 
| 118 | 
            +
                    cargo.each_pair do |key, value|
         | 
| 119 | 
            +
                      events += zabbix_events_from(topic, value, new_scope(scope, key))
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
                  when Array
         | 
| 122 | 
            +
                    cargo.each_with_index do |item, index|
         | 
| 123 | 
            +
                      events += zabbix_events_from(topic, item, new_scope(scope, index))
         | 
| 124 | 
            +
                    end
         | 
| 125 | 
            +
                  else
         | 
| 126 | 
            +
                    events << event_body(topic, scope, cargo)
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
                  events
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                # :nodoc
         | 
| 132 | 
            +
                def new_scope(current_scope, new_scope)
         | 
| 133 | 
            +
                  [current_scope, new_scope].map(&:to_s).reject(&:empty?).join('.')
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                # :nodoc
         | 
| 137 | 
            +
                def event_body topic, scope, cargo
         | 
| 138 | 
            +
                  value = case cargo
         | 
| 139 | 
            +
                  when Hash  then cargo[:value]
         | 
| 140 | 
            +
                  when Array then cargo.first
         | 
| 141 | 
            +
                  else cargo
         | 
| 142 | 
            +
                  end
         | 
| 143 | 
            +
                  { host: topic, key: scope, value: value }
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
                
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
            end
         | 
| 148 | 
            +
             | 
| @@ -10,7 +10,7 @@ require 'vayacondios/server/model/document' | |
| 10 10 | 
             
            # work while Goliath is in a streaming context.
         | 
| 11 11 |  | 
| 12 12 | 
             
            class Vayacondios::ItemsetDocument < Vayacondios::Document
         | 
| 13 | 
            -
              attr_reader :organization, :topic, : | 
| 13 | 
            +
              attr_reader :organization, :topic, :id
         | 
| 14 14 |  | 
| 15 15 | 
             
              def initialize(mongodb, options = {})
         | 
| 16 16 | 
             
                super options
         | 
| @@ -33,13 +33,17 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document | |
| 33 33 | 
             
                self.new(mongodb, options).find
         | 
| 34 34 | 
             
              end
         | 
| 35 35 |  | 
| 36 | 
            +
              def body
         | 
| 37 | 
            +
                {contents: @body}
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 36 40 | 
             
              def find
         | 
| 37 41 | 
             
                result = @collection.find_one({_id: @id})
         | 
| 38 42 |  | 
| 39 43 | 
             
                if result
         | 
| 40 44 | 
             
                  result.delete("_id")
         | 
| 41 45 | 
             
                  @body = result["d"]
         | 
| 42 | 
            -
                  self | 
| 46 | 
            +
                  self
         | 
| 43 47 | 
             
                else
         | 
| 44 48 | 
             
                  nil
         | 
| 45 49 | 
             
                end
         | 
| @@ -48,7 +52,7 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document | |
| 48 52 | 
             
              def update(document)
         | 
| 49 53 | 
             
                raise Vayacondios::Error::BadRequest.new unless document.is_a?(Hash)
         | 
| 50 54 |  | 
| 51 | 
            -
                @body = document['contents'] | 
| 55 | 
            +
                @body = document['contents']
         | 
| 52 56 |  | 
| 53 57 |  | 
| 54 58 | 
             
                @collection.update({:_id => @id}, {:_id => @id, 'd' => @body }, {upsert: true})
         | 
| @@ -61,7 +65,7 @@ class Vayacondios::ItemsetDocument < Vayacondios::Document | |
| 61 65 |  | 
| 62 66 | 
             
                # Merge ourselves
         | 
| 63 67 | 
             
                if @body
         | 
| 64 | 
            -
                  @body = body + document['contents']
         | 
| 68 | 
            +
                  @body = @body + document['contents']
         | 
| 65 69 | 
             
                else
         | 
| 66 70 | 
             
                  @body = document['contents']
         | 
| 67 71 | 
             
                end
         | 
| @@ -12,7 +12,17 @@ class Vayacondios | |
| 12 12 | 
             
                    return unless env['REQUEST_METHOD']
         | 
| 13 13 | 
             
                    case env['REQUEST_METHOD'].upcase
         | 
| 14 14 | 
             
                    when 'PUT'    then
         | 
| 15 | 
            -
                       | 
| 15 | 
            +
                      if env.has_key? 'HTTP_X_METHOD'
         | 
| 16 | 
            +
                        if env['HTTP_X_METHOD'].upcase == 'PATCH'
         | 
| 17 | 
            +
                          :patch
         | 
| 18 | 
            +
                        elsif env['HTTP_X_METHOD'].upcase == 'DELETE'
         | 
| 19 | 
            +
                          :delete
         | 
| 20 | 
            +
                        else
         | 
| 21 | 
            +
                          :update
         | 
| 22 | 
            +
                        end
         | 
| 23 | 
            +
                      else
         | 
| 24 | 
            +
                        :update
         | 
| 25 | 
            +
                      end
         | 
| 16 26 | 
             
                    when 'GET'    then :show
         | 
| 17 27 | 
             
                    when 'POST'   then :create
         | 
| 18 28 | 
             
                    when 'PATCH'  then :patch
         |