cryptic-hoffa 0.0.16
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/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +1 -0
- data/RBPKG +5 -0
- data/README.md +22 -0
- data/Rakefile +1 -0
- data/bin/dev-glu-tunnel.sh +5 -0
- data/bin/highway-from-sql +76 -0
- data/bin/hoffa +195 -0
- data/bin/prod-glu-tunnel.sh +5 -0
- data/binstubs/.gitkeep +0 -0
- data/cassandra_migrations/20131024000000_create_keyspace_Cryptic_down.cql.erb +1 -0
- data/cassandra_migrations/20131024000000_create_keyspace_Cryptic_up.cql.erb +2 -0
- data/cassandra_migrations/20131025000000_create_table_overlay_actions_down.cql.erb +3 -0
- data/cassandra_migrations/20131025000000_create_table_overlay_actions_up.cql.erb +15 -0
- data/cassandra_migrations/20131114488001_create_client_survey_user_site_tables_down.cql.erb +9 -0
- data/cassandra_migrations/20131114488001_create_client_survey_user_site_tables_up.cql.erb +94 -0
- data/cassandra_migrations/20131206944013_create_table_cryptic_place_marker_down.cql.erb +3 -0
- data/cassandra_migrations/20131206944013_create_table_cryptic_place_marker_up.cql.erb +10 -0
- data/cassandra_migrations/20140115150807_add_place_marker_to_place_markers_down.cql +3 -0
- data/cassandra_migrations/20140115150807_add_place_marker_to_place_markers_up.cql +3 -0
- data/cassandra_migrations/20140116281758_repartition_place_markers_table_down.cql +10 -0
- data/cassandra_migrations/20140116281758_repartition_place_markers_table_up.cql +10 -0
- data/cryptic-hoffa.gemspec +34 -0
- data/database.yml +13 -0
- data/jenkins.recipe +67 -0
- data/lib/cryptic/hoffa.rb +183 -0
- data/lib/cryptic/hoffa/version.rb +6 -0
- data/vendor/.gitkeep +0 -0
- metadata +240 -0
data/.gitignore
ADDED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.9.3-p327
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Copyright (c) 2013 OL2, Inc. All Rights Reserved.
|
data/RBPKG
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Cryptic::Hoffa
|
|
2
|
+
|
|
3
|
+
Cryptic Highway is OnLive's Cassandra series reader/writer code. The
|
|
4
|
+
cryptic-highway gem is the "public" part, in that it could be made
|
|
5
|
+
open-source without a problem.
|
|
6
|
+
|
|
7
|
+
Other parts of our code are very OnLive-specific, such as reading
|
|
8
|
+
messages from OMQ and our specific user sites. This code lives in the
|
|
9
|
+
cryptic-hoffa gem.
|
|
10
|
+
|
|
11
|
+
This gem currently includes two programs:
|
|
12
|
+
|
|
13
|
+
* hoffa - an OMQ reader that writes into Cassandra
|
|
14
|
+
* highway-from-sql - an ActiveRecord-based SQL reader that writes into Cassandra
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
"gem install cryptic-hoffa", if you have gems.onlive.com set up as a gem server.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
(To be added)
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2013-2014 OL2, Inc. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
require "trollop"
|
|
6
|
+
require "yaml"
|
|
7
|
+
require "active_record"
|
|
8
|
+
require "erubis"
|
|
9
|
+
|
|
10
|
+
require "cryptic/highway"
|
|
11
|
+
require "cryptic/hoffa"
|
|
12
|
+
|
|
13
|
+
opts = Trollop::options do
|
|
14
|
+
banner <<BANNER
|
|
15
|
+
Highway-from-sql is a tool to move database information from SQL DBs into Cassandra.
|
|
16
|
+
Its database.yml file must include a "sql_db" database connection in standard ActiveRecord format
|
|
17
|
+
|
|
18
|
+
Specific options:
|
|
19
|
+
BANNER
|
|
20
|
+
opt :db_file, "Database YAML file", :default => "database.yml", :type => String
|
|
21
|
+
opt :site, "User site", :required => true, :type => String
|
|
22
|
+
opt :cass_host, "Cassandra host(s)", :type => :strings, :default => [ "localhost" ]
|
|
23
|
+
opt :cass_key, "Name for Cass keyspace", :type => String, :default => "cryptic"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
SITE = opts[:site]
|
|
27
|
+
|
|
28
|
+
raise "Wrong args!" if ARGV.size > 0
|
|
29
|
+
|
|
30
|
+
Cryptic.redirect_user_sites! [opts[:site]]
|
|
31
|
+
site_port = Cryptic.redirected_database_port_for_user_site opts[:site]
|
|
32
|
+
|
|
33
|
+
eruby = Erubis::Eruby.new File.read(opts[:db_file])
|
|
34
|
+
eruby_string = eruby.evaluate :site => SITE, :site_port => site_port
|
|
35
|
+
db_yml = YAML.load eruby_string
|
|
36
|
+
|
|
37
|
+
STDERR.puts "Connecting with DB options: #{db_yml["sql_db"].inspect}"
|
|
38
|
+
ActiveRecord::Base.establish_connection db_yml["sql_db"]
|
|
39
|
+
|
|
40
|
+
class ClientSurveyUSBDevice < ActiveRecord::Base
|
|
41
|
+
self.table_name = "client_survey_usb_device"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ramp = Cryptic::Highway::Ramp.new("client_survey_usb_device") do
|
|
45
|
+
hosts opts[:cass_host]
|
|
46
|
+
keyspace opts[:cass_key]
|
|
47
|
+
site opts[:site]
|
|
48
|
+
marker_name "client_survey_usb_device-#{opts[:site]}"
|
|
49
|
+
to_update do |place_marker|
|
|
50
|
+
STDERR.puts "Updating forward from #{place_marker.inspect}!"
|
|
51
|
+
sql_query = <<-QUERY
|
|
52
|
+
SELECT client_survey_timestamp, u.* FROM client_survey_usb_device u
|
|
53
|
+
JOIN client_survey cs ON cs.client_survey_id = u.client_survey_id
|
|
54
|
+
WHERE client_survey_timestamp >= '2014-01-14 00:00:00'
|
|
55
|
+
#{ place_marker.nil? ? "" : "AND client_survey_timestamp >= '#{place_marker}'" }
|
|
56
|
+
LIMIT #{ db_yml["block_size"] || 100 }
|
|
57
|
+
QUERY
|
|
58
|
+
STDERR.puts "Query: #{sql_query}"
|
|
59
|
+
objs = ClientSurveyUSBDevice.find_by_sql sql_query
|
|
60
|
+
STDERR.puts "Query returned #{objs.size} records!"
|
|
61
|
+
|
|
62
|
+
data = objs.map do |o|
|
|
63
|
+
item = o.attributes
|
|
64
|
+
item["timestamp"] = item.delete "client_survey_timestamp"
|
|
65
|
+
item
|
|
66
|
+
end
|
|
67
|
+
ramp.insert_rows data
|
|
68
|
+
|
|
69
|
+
STDERR.puts "New last marker: #{objs.last["client_survey_timestamp"].to_s.inspect}"
|
|
70
|
+
objs.last["client_survey_timestamp"].to_s
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
ramp.update_until_done
|
|
75
|
+
|
|
76
|
+
puts "Highway: Finished. Exiting."
|
data/bin/hoffa
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "trollop"
|
|
4
|
+
require "cryptic/highway"
|
|
5
|
+
require "cryptic/highway/utils"
|
|
6
|
+
require "cryptic/hoffa"
|
|
7
|
+
require "rubyglu"
|
|
8
|
+
|
|
9
|
+
require "logger"
|
|
10
|
+
ERR_LOG = Logger.new STDERR
|
|
11
|
+
ERR_LOG.level = Logger::INFO
|
|
12
|
+
OUT_LOG = Logger.new STDOUT
|
|
13
|
+
OUT_LOG.level = Logger::INFO
|
|
14
|
+
|
|
15
|
+
# Make a fake logger object that just passes all operations to both log objects
|
|
16
|
+
BOTH_LOGS = Cryptic::Highway::Utils::MultiDispatcher.new(ERR_LOG, OUT_LOG)
|
|
17
|
+
|
|
18
|
+
BOTH_LOGS.info "Started hoffa with arguments: #{ARGV.inspect}"
|
|
19
|
+
|
|
20
|
+
opts = Trollop::options do
|
|
21
|
+
banner <<-BANNER
|
|
22
|
+
Read JSON messages from OMQ (GLU), insert them into Cassandra.
|
|
23
|
+
BANNER
|
|
24
|
+
opt :omq_host, "OMQ broker hostname", :type => String
|
|
25
|
+
opt :omq_host_site, "OMQ site of specified host", :type => String
|
|
26
|
+
opt :omq_port, "OMQ broker port", :type => Integer
|
|
27
|
+
opt :omq_debug, "OMQ debug mode"
|
|
28
|
+
opt :cass_host, "Cassandra host", :type => :strings, :default => [ "localhost" ]
|
|
29
|
+
#opt :cass_port, "Cassandra port", :type => Integer, :default => 9042
|
|
30
|
+
|
|
31
|
+
opt :cass_table, "Name for Cass table/CF", :type => String, :required => true
|
|
32
|
+
opt :cass_key, "Name for Cass keyspace", :type => String, :default => "Cryptic"
|
|
33
|
+
|
|
34
|
+
opt :duplication,"Number of times to duplicate each site.", :type => Integer, :default => 1
|
|
35
|
+
|
|
36
|
+
opt :user_sites, "OnLive User site(s) for reading data, comma-separated.", :type => String
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if opts[:user_sites] && (opts[:omq_host] || opts[:omq_port])
|
|
40
|
+
ERR_LOG.error <<-ERR_STRING
|
|
41
|
+
Can't specify user site(s) with individual host/port for OMQ!
|
|
42
|
+
Sites: #{opts[:user_sites].inspect}
|
|
43
|
+
Host: #{opts[:omq_host]}
|
|
44
|
+
Port: #{opts[:omq_port]}"
|
|
45
|
+
ERR_STRING
|
|
46
|
+
raise "Can't specify user site(s) with individual host/port for OMQ!"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Doing a kill -9 on this should kill the parent and all children, but nobody else.
|
|
50
|
+
Process.setpgrp
|
|
51
|
+
|
|
52
|
+
if opts[:user_sites]
|
|
53
|
+
if sites == "query"
|
|
54
|
+
sites = Cryptic.user_sites
|
|
55
|
+
else
|
|
56
|
+
sites = opts[:user_sites].split ","
|
|
57
|
+
end
|
|
58
|
+
omq_brokers = sites.map { |s| ["omq://omq.#{s}.onlive.net:61618", s] }
|
|
59
|
+
else
|
|
60
|
+
# Use omq_host and omq_port, defaulting to localhost:61618
|
|
61
|
+
omq_brokers = [["omq://#{opts[:omq_host] || "localhost"}:#{opts[:omq_port] || 61618}", opts[:omq_host_site]]]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
BOTH_LOGS.warn "(Re)starting Hoffa."
|
|
65
|
+
|
|
66
|
+
broker_list = omq_brokers.flat_map { |broker| (1..opts[:duplication]).map { |i| broker + [ i ] } }
|
|
67
|
+
|
|
68
|
+
opts[:slots] = ARGV.length > 0 ? ARGV : [ "*" ]
|
|
69
|
+
puts "Connecting to OMQ broker(s): #{broker_list.inspect}"
|
|
70
|
+
|
|
71
|
+
processes = []
|
|
72
|
+
|
|
73
|
+
# Create a new process, return the pid.
|
|
74
|
+
def new_process(omq_broker, user_site, dup_num, opts = {})
|
|
75
|
+
fork do
|
|
76
|
+
$0 = "Hoffa worker (ruby), Site: #{user_site || "none"} Dup Num: #{dup_num || "none"}"
|
|
77
|
+
Process.setrlimit :RSS, 10_000_000 # This should be way higher than needed
|
|
78
|
+
|
|
79
|
+
consecutive_failures = 0
|
|
80
|
+
loop do
|
|
81
|
+
# Re-instantiate Cassandra connection in each process and after OMQ errors.
|
|
82
|
+
# This works around problems with down nodes not always being marked up
|
|
83
|
+
# again after Cassandra recovery. We want to prevent cases where we keep
|
|
84
|
+
# looping and keep failing... Also, for the same reason, don't share
|
|
85
|
+
# the connection between processes.
|
|
86
|
+
ramp = Cryptic::Highway::Ramp.new(opts[:cass_table]) do
|
|
87
|
+
hosts opts[:cass_host]
|
|
88
|
+
keyspace opts[:cass_key]
|
|
89
|
+
site user_site
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
GLU::services do
|
|
94
|
+
debug_mode if opts[:omq_debug]
|
|
95
|
+
use_broker omq_broker
|
|
96
|
+
use_name "ruby_omq_tail"
|
|
97
|
+
no_clear
|
|
98
|
+
|
|
99
|
+
consumer opts[:slots] do |message|
|
|
100
|
+
if message.type == 'Log'
|
|
101
|
+
puts "#{message[:timestamp]} LOG-#{message[:level]}(#{message[:componentName]}.#{message[:componentVersion]}) " +
|
|
102
|
+
"#{message[:sourceFileName]}@#{message[:sourceHostName]}: #{message[:message]}"
|
|
103
|
+
elsif not message.name.nil?
|
|
104
|
+
data = message.message_parameters
|
|
105
|
+
sentTo = message.headers["sentTo"]
|
|
106
|
+
|
|
107
|
+
puts "Data to insert: #{sentTo} / #{data.inspect}" # In case of error on insert, put it in the logfile
|
|
108
|
+
|
|
109
|
+
actions = data['actions']
|
|
110
|
+
base = {
|
|
111
|
+
"userSessionKey" => data["userSessionKey"],
|
|
112
|
+
"appSessionId" => data["appSessionId"],
|
|
113
|
+
"topic" => sentTo,
|
|
114
|
+
"sequenceNum" => message.headers["sequenceNum"],
|
|
115
|
+
}
|
|
116
|
+
rows = actions.map { |action| action.merge base }
|
|
117
|
+
|
|
118
|
+
ramp.insert_rows rows
|
|
119
|
+
consecutive_failures = 0 # Reset number of consecutive failures
|
|
120
|
+
else
|
|
121
|
+
BOTH_LOGS.warn "Nil name on message? #{message.inspect}"
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
rescue
|
|
126
|
+
# One more failure since the last success
|
|
127
|
+
consecutive_failures += 1
|
|
128
|
+
|
|
129
|
+
is_in_maint = Cryptic.sites_in_maintenance & [ user_site ]
|
|
130
|
+
maint_msg = is_in_maint ? "(In maint)" : "(Not in maint)"
|
|
131
|
+
|
|
132
|
+
OUT_LOG.error "Error caused GLU exit: #{$!.class} / #{$!.message}!"
|
|
133
|
+
ERR_LOG.error <<-ERROR_MESSAGE
|
|
134
|
+
#{maint_msg} Error caused GLU exit: #{$!.class} / #{$!.message}
|
|
135
|
+
#{$!.backtrace.join(" \n")}
|
|
136
|
+
ERROR_MESSAGE
|
|
137
|
+
puts "#{maint_msg} Error caused GLU exit: #{$!.class}: #{$!.message}"
|
|
138
|
+
|
|
139
|
+
if consecutive_failures >= 10
|
|
140
|
+
# That's nearly a minute of consecutive failure, or maybe
|
|
141
|
+
# even longer. Kill the process, in case something is
|
|
142
|
+
# royally and globally screwed. It may just be that
|
|
143
|
+
# Cassandra or OMQ is down, in which case this restarting is
|
|
144
|
+
# fine too.
|
|
145
|
+
exit! # Always use "exit!" at end of a forked Ruby process
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
BOTH_LOGS.warn "#{maint_msg} Looping after 5 second delay (60 in maint)..."
|
|
149
|
+
puts "#{maint_msg} Looping after 5 second delay (60 in maint)..."
|
|
150
|
+
sleep is_in_maint ? 60.0 : 5.0
|
|
151
|
+
end
|
|
152
|
+
end # loop do
|
|
153
|
+
end # fork
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
broker_list.each do |omq_broker, user_site, dup_num|
|
|
157
|
+
pid = new_process omq_broker, user_site, dup_num, opts
|
|
158
|
+
processes << { pid: pid, omq_broker: omq_broker, site: user_site, dup_num: dup_num }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
$0 = "Hoffa master (ruby), Sites: #{opts[:user_sites].inspect}"
|
|
162
|
+
|
|
163
|
+
Signal.trap("TERM") do
|
|
164
|
+
processes.each { |process| `kill -TERM #{process[:pid]}` }
|
|
165
|
+
shutdown()
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
loop do
|
|
169
|
+
|
|
170
|
+
# Default: reap children every 5 seconds, check for data every 1 minute.
|
|
171
|
+
# That means 12 5-second iterations.
|
|
172
|
+
12.times do
|
|
173
|
+
tries = 0
|
|
174
|
+
pid, status = Process.waitpid2 0, Process::WNOHANG # Did any child die?
|
|
175
|
+
|
|
176
|
+
# Reap child processes until nobody dies, or up to 10
|
|
177
|
+
while pid != nil && tries < 10
|
|
178
|
+
# Find the descriptor for the dead child process
|
|
179
|
+
proc = processes.detect { |p| p[:pid] == pid }
|
|
180
|
+
|
|
181
|
+
processes -= [ proc ]
|
|
182
|
+
pid = new_process proc[:omq_broker], proc[:site], opts
|
|
183
|
+
processes << { pid: pid, omq_broker: proc[:omq_broker], site: proc[:site] }
|
|
184
|
+
tries += 1
|
|
185
|
+
pid, status = Process.waitpid2 0, Process::WNOHANG # Did any child die?
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
sleep 5 # Reap children and check data no more often than this
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# TODO: check if process is writing, somehow, and restart if not.
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
ERR_LOG.error "Finished! Shouldn't get here."
|
|
195
|
+
raise "Finished! Shouldn't get here."
|
data/binstubs/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DROP KEYSPACE "cryptic";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- Create table for purchase-flow analytics and other actions in the overlay.
|
|
2
|
+
|
|
3
|
+
use "cryptic";
|
|
4
|
+
|
|
5
|
+
CREATE TABLE overlay_actions (
|
|
6
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
7
|
+
"topic" varchar, // OMQ topic
|
|
8
|
+
"name" text, // overlay action name
|
|
9
|
+
"timestamp" bigint, // nanosec since the epoch
|
|
10
|
+
"sequenceNum" int,
|
|
11
|
+
"appSessionId" varchar,
|
|
12
|
+
"userSessionKey" varchar,
|
|
13
|
+
"actionKey" varchar,
|
|
14
|
+
"tags" map<text,text>,
|
|
15
|
+
PRIMARY KEY ("partition_key", "topic", "actionKey"));
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
-- Create tables for user-site client_survey data
|
|
2
|
+
|
|
3
|
+
use "cryptic";
|
|
4
|
+
|
|
5
|
+
CREATE TABLE client_survey (
|
|
6
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
7
|
+
"client_survey_id" varchar,
|
|
8
|
+
"client_survey_timestamp" bigint,
|
|
9
|
+
"user_id" varchar,
|
|
10
|
+
"user_session_key" varchar,
|
|
11
|
+
"aero" boolean,
|
|
12
|
+
"audio_driver" blob,
|
|
13
|
+
"client_version" varchar,
|
|
14
|
+
"decode_time" float,
|
|
15
|
+
"input_keyboard" boolean,
|
|
16
|
+
"input_mouse" boolean,
|
|
17
|
+
"operating_system" varchar,
|
|
18
|
+
"operating_system_build" int,
|
|
19
|
+
"operating_system_build_str" varchar,
|
|
20
|
+
"pixel_shader_version" float,
|
|
21
|
+
"processor_cores" int,
|
|
22
|
+
"processor_current_frequency" int,
|
|
23
|
+
"processor_details" varchar,
|
|
24
|
+
"processor_features" varchar,
|
|
25
|
+
"processor_frequency" int,
|
|
26
|
+
"processor_name" varchar,
|
|
27
|
+
"processor_vendor" varchar,
|
|
28
|
+
"system_page_used" int,
|
|
29
|
+
"system_ram" int,
|
|
30
|
+
"system_ram_available" int,
|
|
31
|
+
"video_card" varchar,
|
|
32
|
+
"video_card_driver" varchar,
|
|
33
|
+
"video_memory" varchar,
|
|
34
|
+
"video_modes" varchar,
|
|
35
|
+
"client_survey_auto_id" bigint,
|
|
36
|
+
PRIMARY KEY ("partition_key","client_survey_id"));
|
|
37
|
+
|
|
38
|
+
CREATE TABLE client_survey_monitor (
|
|
39
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
40
|
+
"client_survey_monitor_id" bigint,
|
|
41
|
+
"client_survey_id" varchar,
|
|
42
|
+
"timestamp" bigint,
|
|
43
|
+
"edid" blob,
|
|
44
|
+
"monitor_name" blob,
|
|
45
|
+
"manufacture_date" blob,
|
|
46
|
+
"horizontal_cm" int,
|
|
47
|
+
"vertical_cm" int,
|
|
48
|
+
"name" blob,
|
|
49
|
+
"primary" boolean,
|
|
50
|
+
"refresh_rate" int,
|
|
51
|
+
"resolution" blob,
|
|
52
|
+
PRIMARY KEY ("partition_key","client_survey_monitor_id"));
|
|
53
|
+
|
|
54
|
+
CREATE TABLE client_survey_usb_device (
|
|
55
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
56
|
+
"client_survey_usb_device_id" bigint,
|
|
57
|
+
"timestamp" bigint,
|
|
58
|
+
"client_survey_id" varchar,
|
|
59
|
+
"client_survey_usb_device_type_id" int,
|
|
60
|
+
"name" blob, // overlay action name
|
|
61
|
+
PRIMARY KEY ("partition_key","client_survey_usb_device_id"));
|
|
62
|
+
|
|
63
|
+
CREATE TABLE network_test_result (
|
|
64
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
65
|
+
"network_test_result_id" bigint,
|
|
66
|
+
"test_timestamp" timeuuid,
|
|
67
|
+
"user_session_key" varchar,
|
|
68
|
+
"user_id" varchar,
|
|
69
|
+
"bandwidth" bigint,
|
|
70
|
+
"connection" varchar,
|
|
71
|
+
"decode_time" double,
|
|
72
|
+
"jitter" double,
|
|
73
|
+
"latency" double,
|
|
74
|
+
"machine_power_save_possible" boolean,
|
|
75
|
+
"packet_loss" double,
|
|
76
|
+
"error" blob,
|
|
77
|
+
PRIMARY KEY ("partition_key","network_test_result_id"));
|
|
78
|
+
|
|
79
|
+
CREATE TABLE spi_profile_log (
|
|
80
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
81
|
+
"id" bigint,
|
|
82
|
+
"timestamp" bigint,
|
|
83
|
+
"hw_id" varchar,
|
|
84
|
+
"hw_id_type" varchar,
|
|
85
|
+
"device_type" varchar,
|
|
86
|
+
"slice_id" varchar,
|
|
87
|
+
"session_key" varchar,
|
|
88
|
+
"user_id" varchar,
|
|
89
|
+
"connection_type" varchar,
|
|
90
|
+
"tested_rate_kbps" int,
|
|
91
|
+
"desired_rate_kbps" int,
|
|
92
|
+
"decode_time_ms" bigint,
|
|
93
|
+
"computer_speed" varchar,
|
|
94
|
+
PRIMARY KEY ("partition_key","id"));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- Create tables for place markers for Cryptic Highway and other Cryptic scripts and processes
|
|
2
|
+
|
|
3
|
+
use "cryptic";
|
|
4
|
+
|
|
5
|
+
CREATE TABLE "place_markers" (
|
|
6
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
7
|
+
"marker_type" varchar,
|
|
8
|
+
"timestamp" bigint,
|
|
9
|
+
"notes" varchar,
|
|
10
|
+
PRIMARY KEY ("partition_key","marker_type","timestamp"));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
use "cryptic";
|
|
2
|
+
|
|
3
|
+
DROP TABLE place_markers;
|
|
4
|
+
|
|
5
|
+
CREATE TABLE "place_markers" (
|
|
6
|
+
"partition_key" varchar, // Partition by site and time bucket
|
|
7
|
+
"marker_type" varchar,
|
|
8
|
+
"timestamp" bigint,
|
|
9
|
+
"notes" varchar,
|
|
10
|
+
PRIMARY KEY ("partition_key","marker_type","timestamp"));
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'cryptic/hoffa/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "cryptic-hoffa"
|
|
8
|
+
spec.version = Cryptic::Hoffa::VERSION
|
|
9
|
+
spec.authors = ["Noah Gibbs"]
|
|
10
|
+
spec.email = ["noah@onlive.com"]
|
|
11
|
+
spec.description = %q{Gateway OMQ data to Cassandra}
|
|
12
|
+
spec.summary = %q{Gateway OMQ data to Cassandra}
|
|
13
|
+
spec.homepage = ""
|
|
14
|
+
spec.license = "Proprietary"
|
|
15
|
+
|
|
16
|
+
spec.files = (File.exist?("MANIFEST") ? File.read("MANIFEST") : `git ls-files`).split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
|
22
|
+
spec.add_development_dependency "rake"
|
|
23
|
+
spec.add_development_dependency "cassandra_migrate"
|
|
24
|
+
|
|
25
|
+
spec.add_runtime_dependency "trollop"
|
|
26
|
+
spec.add_runtime_dependency "cryptic-highway"
|
|
27
|
+
spec.add_runtime_dependency "rubyglu"
|
|
28
|
+
spec.add_runtime_dependency "multi_json"
|
|
29
|
+
spec.add_runtime_dependency "erubis"
|
|
30
|
+
|
|
31
|
+
# For Highway-from-SQL and querying user sites
|
|
32
|
+
spec.add_runtime_dependency "activerecord"
|
|
33
|
+
spec.add_runtime_dependency "mysql2"
|
|
34
|
+
end
|
data/database.yml
ADDED
data/jenkins.recipe
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Jenkins recipe to build rpm via rbpkgbuild
|
|
3
|
+
|
|
4
|
+
### SETUP ENVIRONMENT ###
|
|
5
|
+
: ${RVM_SH_PATH:=/etc/profile.d/rvm.sh}
|
|
6
|
+
. $RVM_SH_PATH
|
|
7
|
+
progname=$(basename $0)
|
|
8
|
+
|
|
9
|
+
# Should this use the specific ruby version specified?
|
|
10
|
+
cd $WORKSPACE
|
|
11
|
+
rvm use 1.9.3-p392
|
|
12
|
+
|
|
13
|
+
log() {
|
|
14
|
+
echo "$progname: ""$@"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
err() {
|
|
18
|
+
log "$@" >&2
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
### UPDATE TAGS ###
|
|
22
|
+
git fetch --tags
|
|
23
|
+
|
|
24
|
+
### INSTALL GEMS ###
|
|
25
|
+
rm -rf .bundle
|
|
26
|
+
rm -rf Gemfile.lock
|
|
27
|
+
rm -rf vendor/bundle
|
|
28
|
+
cp -r bin bindir # bin gets replaced with stubs by rbpkgbuild
|
|
29
|
+
echo "Do bundle install --path=vendor/bundle"
|
|
30
|
+
bundle install --path=vendor/bundle
|
|
31
|
+
|
|
32
|
+
### RUN TESTS ###
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### CREATE MANIFEST ###
|
|
36
|
+
echo "Creating MANIFEST for deployment"
|
|
37
|
+
git ls-files > MANIFEST
|
|
38
|
+
|
|
39
|
+
### CREATE RPM ###
|
|
40
|
+
log "Creating rpm with rbpkgbuild"
|
|
41
|
+
/usr/local/bin/rbpkgbuild
|
|
42
|
+
if [ $? -ne 0 ]; then
|
|
43
|
+
err "Error creating rpms"
|
|
44
|
+
exit 2
|
|
45
|
+
else
|
|
46
|
+
log "rpmpkgbuild completed without error."
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
### PUBLISH RPM ###
|
|
50
|
+
# Define RPM destinations
|
|
51
|
+
EL5REPO='mm-apt.mmm.onlive.net::incoming-rpm/integration/'
|
|
52
|
+
EL6REPO='mm-apt.mmm.onlive.net::incoming-rpm/integration6/'
|
|
53
|
+
|
|
54
|
+
# Push rpms to repo
|
|
55
|
+
## depending on build server, el5 or el6 rpms are generated
|
|
56
|
+
log "Publishing rpms to mm-apt via rsync"
|
|
57
|
+
rsync *el6*.rpm $EL6REPO || rsync *el5*.rpm $EL5REPO
|
|
58
|
+
if [ $? -ne 0 ]; then
|
|
59
|
+
err "Error pushing rpm to repo"
|
|
60
|
+
exit 3
|
|
61
|
+
else
|
|
62
|
+
log "Publishing completed without error."
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
### END ###
|
|
66
|
+
log "Congratulations! We made it to the end of the jenkins recipe."
|
|
67
|
+
exit 0
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Copyright (C) 2013-2015 OL2, Inc. All Rights Reserved.
|
|
2
|
+
|
|
3
|
+
require "cryptic/hoffa/version"
|
|
4
|
+
require "mysql2"
|
|
5
|
+
|
|
6
|
+
# This allows redirecting user sites and querying them.
|
|
7
|
+
# You can pass the following options into the
|
|
8
|
+
# various methods:
|
|
9
|
+
#
|
|
10
|
+
# :master_site - the site ID (aav, mca, etc.) of the master site
|
|
11
|
+
# :grok_master - the URL of the Grok master host
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
module Cryptic
|
|
15
|
+
extend self
|
|
16
|
+
|
|
17
|
+
BASE_PORT=28808
|
|
18
|
+
DEFAULT_OPTIONS = {
|
|
19
|
+
:host => "127.0.0.1",
|
|
20
|
+
:port => 3306,
|
|
21
|
+
:username => "analytics",
|
|
22
|
+
:password => "5parklin3",
|
|
23
|
+
:secure_auth => false,
|
|
24
|
+
:database => "analytics",
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
def user_sites(master_options = {})
|
|
28
|
+
return @user_sites.keys if @user_sites
|
|
29
|
+
conn = slave_connection master_options
|
|
30
|
+
# @user_sites maps site name to grok-master DB ID in the etl_control table. This ensures consistent local port mappings.
|
|
31
|
+
@user_sites = {}
|
|
32
|
+
conn.query("SELECT id, site FROM etl_control WHERE level = 'user' AND status = 'up'").each { |row| @user_sites[row["site"]] = row["id"] }
|
|
33
|
+
@user_sites.keys
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def master_site(options = {})
|
|
37
|
+
return ENV['CRYPTIC_MASTER_SITE'] if ENV['CRYPTIC_MASTER_SITE']
|
|
38
|
+
return options[:master_site] if options[:master_site]
|
|
39
|
+
|
|
40
|
+
reference_site = options[:grok_master] || `hostname -f`.chomp
|
|
41
|
+
onlive_user_site = reference_site.split(".")[1]
|
|
42
|
+
if onlive_user_site && (onlive_user_site =~ /^[A-Za-z]{3}$/ || onlive_user_site == "prod")
|
|
43
|
+
nil # Use local
|
|
44
|
+
else
|
|
45
|
+
"aav"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def master_host(options = {})
|
|
51
|
+
if options[:grok_master]
|
|
52
|
+
options[:grok_master]
|
|
53
|
+
else
|
|
54
|
+
site = master_site(options)
|
|
55
|
+
|
|
56
|
+
site ? "grok-master.#{site}.onlive.net" : "grok-master"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def slave_host(options = {})
|
|
61
|
+
if options[:grok_slave]
|
|
62
|
+
options[:grok_slave]
|
|
63
|
+
else
|
|
64
|
+
site = master_site(options) # There's not a separate "slave site" - just master & slave in the same master site.
|
|
65
|
+
|
|
66
|
+
site ? "grokdbro.#{site}.onlive.net" : "grokdbro"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def master_connection(options = {})
|
|
71
|
+
@master_conn ||= Mysql2::Client.new(DEFAULT_OPTIONS.merge(:host => master_host(options)).merge(options))
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def slave_connection(options = {})
|
|
75
|
+
@master_conn ||= Mysql2::Client.new(DEFAULT_OPTIONS.merge(:host => slave_host(options)).merge(options))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def dont_redirect_user_sites!(master_options = {})
|
|
79
|
+
@already_redirected_user_sites = true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def redirect_user_sites!(sites = nil, master_options = {})
|
|
83
|
+
return if @already_redirected_user_sites
|
|
84
|
+
@already_redirected_user_sites = true
|
|
85
|
+
|
|
86
|
+
sites = user_sites(master_options) unless sites
|
|
87
|
+
|
|
88
|
+
user = `whoami`.chomp
|
|
89
|
+
sites.each do |site|
|
|
90
|
+
local_port = redirected_database_port_for_user_site(site, master_options)
|
|
91
|
+
process = `pgrep -f #{local_port}`
|
|
92
|
+
|
|
93
|
+
# TODO: use slaves where available (currently not for user sites)
|
|
94
|
+
hostname = "grok.#{site}"
|
|
95
|
+
|
|
96
|
+
ms = master_site(master_options)
|
|
97
|
+
master_domain = ms ? "#{ms}.onlive.net" : ""
|
|
98
|
+
|
|
99
|
+
cmd = "ssh -Nf -L#{local_port}:#{hostname}:3306 -o \"StrictHostKeyChecking no\" #{user}@shell.#{master_domain}"
|
|
100
|
+
if process && !process.strip.empty? # Redirection already active
|
|
101
|
+
process.strip.split("\n").each do |p|
|
|
102
|
+
pid = p.to_i
|
|
103
|
+
cur_cmd = `ps -p #{pid}`.split("\n")[1].split(/\s+/, 4)[3]
|
|
104
|
+
|
|
105
|
+
# If this same command was issued then we're already redirecting the site to the right port number.
|
|
106
|
+
# But the double-quotes go away in the ps output.
|
|
107
|
+
if cur_cmd != cmd.gsub('"', "")
|
|
108
|
+
Process.kill("INT", pid)
|
|
109
|
+
STDERR.puts "Remapping port #{local_port} for site #{site}. Command: #{cmd} / Old Command: #{cur_cmd}"
|
|
110
|
+
system(cmd) || raise("Failed port-map for site #{site}, port #{local_port}!")
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
else
|
|
114
|
+
STDERR.puts "Mapping port #{local_port} for site #{site}. Command: #{cmd}"
|
|
115
|
+
system(cmd) || raise("Failed port-map for site #{site}, port #{local_port}!")
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def redirected_database_port_for_user_site(site, master_options = {})
|
|
121
|
+
user_sites(master_options) unless @user_sites
|
|
122
|
+
index = @user_sites[site]
|
|
123
|
+
raise "No index for site #{site.inspect}!" unless index
|
|
124
|
+
BASE_PORT + index
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def user_site_connection(site = nil, master_options = {})
|
|
128
|
+
@user_site_connections ||= {}
|
|
129
|
+
return @user_site_connections[site] if @user_site_connections[site]
|
|
130
|
+
|
|
131
|
+
local_port = redirected_database_port_for_user_site(site)
|
|
132
|
+
|
|
133
|
+
@user_site_connections[site] = Mysql2::Client.new DEFAULT_OPTIONS.merge(:port => local_port)
|
|
134
|
+
@user_site_connections[site]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Default timeout for queries: 10 minutes
|
|
138
|
+
SELECT_TIMEOUT = 600
|
|
139
|
+
|
|
140
|
+
def query_on_user_sites(query, sites = nil, master_options = {}, &block)
|
|
141
|
+
redirect_user_sites!(sites, master_options)
|
|
142
|
+
|
|
143
|
+
sites = user_sites(master_options) unless sites
|
|
144
|
+
conns = sites.map { |site| user_site_connection(site, master_options) }
|
|
145
|
+
|
|
146
|
+
results = {}
|
|
147
|
+
threads = []
|
|
148
|
+
sites.zip(conns).each do |site, conn|
|
|
149
|
+
t = nil
|
|
150
|
+
begin
|
|
151
|
+
t = Thread.new do
|
|
152
|
+
# Global Interpreter Lock means we don't need to synchronize this
|
|
153
|
+
results[site] = conn.query(query)
|
|
154
|
+
block.call(results[site]) if block
|
|
155
|
+
end
|
|
156
|
+
rescue
|
|
157
|
+
STDERR.puts "Errors on query for site #{site}:\n#{query}\n\n"
|
|
158
|
+
STDERR.puts "Backtrace:\n#{$!.backtrace.join("\n")}\n"
|
|
159
|
+
end
|
|
160
|
+
threads.push(t)
|
|
161
|
+
end
|
|
162
|
+
threads.each(&:join)
|
|
163
|
+
|
|
164
|
+
results
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# TODO: figure out how to do this outside prod
|
|
168
|
+
def sites_in_maintenance
|
|
169
|
+
begin
|
|
170
|
+
stat = `curl http://mastermon.mca.onlive.net/glustats/glustats.json 2>/dev/null`
|
|
171
|
+
glustat = JSON.parse(stat)
|
|
172
|
+
sites = glustat.keys
|
|
173
|
+
sites = sites.select do |site|
|
|
174
|
+
glustat[site].is_a?(Hash) && glustat[site]["drain_state"] == "drain"
|
|
175
|
+
end
|
|
176
|
+
return sites
|
|
177
|
+
rescue
|
|
178
|
+
STDERR.puts "Error querying sites in maint: #{$!.message}\n#{$!.backtrace.join "\n"}"
|
|
179
|
+
return []
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
end
|
data/vendor/.gitkeep
ADDED
|
File without changes
|
metadata
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cryptic-hoffa
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.16
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Noah Gibbs
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2015-02-04 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: bundler
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '1.3'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.3'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: rake
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
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
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: cassandra_migrate
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: trollop
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ! '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
type: :runtime
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ! '>='
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
78
|
+
- !ruby/object:Gem::Dependency
|
|
79
|
+
name: cryptic-highway
|
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
|
81
|
+
none: false
|
|
82
|
+
requirements:
|
|
83
|
+
- - ! '>='
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '0'
|
|
86
|
+
type: :runtime
|
|
87
|
+
prerelease: false
|
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
89
|
+
none: false
|
|
90
|
+
requirements:
|
|
91
|
+
- - ! '>='
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
- !ruby/object:Gem::Dependency
|
|
95
|
+
name: rubyglu
|
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
|
97
|
+
none: false
|
|
98
|
+
requirements:
|
|
99
|
+
- - ! '>='
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
type: :runtime
|
|
103
|
+
prerelease: false
|
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
105
|
+
none: false
|
|
106
|
+
requirements:
|
|
107
|
+
- - ! '>='
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: multi_json
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
none: false
|
|
114
|
+
requirements:
|
|
115
|
+
- - ! '>='
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :runtime
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
none: false
|
|
122
|
+
requirements:
|
|
123
|
+
- - ! '>='
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '0'
|
|
126
|
+
- !ruby/object:Gem::Dependency
|
|
127
|
+
name: erubis
|
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
|
129
|
+
none: false
|
|
130
|
+
requirements:
|
|
131
|
+
- - ! '>='
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: '0'
|
|
134
|
+
type: :runtime
|
|
135
|
+
prerelease: false
|
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
137
|
+
none: false
|
|
138
|
+
requirements:
|
|
139
|
+
- - ! '>='
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: '0'
|
|
142
|
+
- !ruby/object:Gem::Dependency
|
|
143
|
+
name: activerecord
|
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
|
145
|
+
none: false
|
|
146
|
+
requirements:
|
|
147
|
+
- - ! '>='
|
|
148
|
+
- !ruby/object:Gem::Version
|
|
149
|
+
version: '0'
|
|
150
|
+
type: :runtime
|
|
151
|
+
prerelease: false
|
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
153
|
+
none: false
|
|
154
|
+
requirements:
|
|
155
|
+
- - ! '>='
|
|
156
|
+
- !ruby/object:Gem::Version
|
|
157
|
+
version: '0'
|
|
158
|
+
- !ruby/object:Gem::Dependency
|
|
159
|
+
name: mysql2
|
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
|
161
|
+
none: false
|
|
162
|
+
requirements:
|
|
163
|
+
- - ! '>='
|
|
164
|
+
- !ruby/object:Gem::Version
|
|
165
|
+
version: '0'
|
|
166
|
+
type: :runtime
|
|
167
|
+
prerelease: false
|
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
169
|
+
none: false
|
|
170
|
+
requirements:
|
|
171
|
+
- - ! '>='
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: '0'
|
|
174
|
+
description: Gateway OMQ data to Cassandra
|
|
175
|
+
email:
|
|
176
|
+
- noah@onlive.com
|
|
177
|
+
executables:
|
|
178
|
+
- dev-glu-tunnel.sh
|
|
179
|
+
- highway-from-sql
|
|
180
|
+
- hoffa
|
|
181
|
+
- prod-glu-tunnel.sh
|
|
182
|
+
extensions: []
|
|
183
|
+
extra_rdoc_files: []
|
|
184
|
+
files:
|
|
185
|
+
- .gitignore
|
|
186
|
+
- .ruby-version
|
|
187
|
+
- Gemfile
|
|
188
|
+
- LICENSE.txt
|
|
189
|
+
- RBPKG
|
|
190
|
+
- README.md
|
|
191
|
+
- Rakefile
|
|
192
|
+
- bin/dev-glu-tunnel.sh
|
|
193
|
+
- bin/highway-from-sql
|
|
194
|
+
- bin/hoffa
|
|
195
|
+
- bin/prod-glu-tunnel.sh
|
|
196
|
+
- binstubs/.gitkeep
|
|
197
|
+
- cassandra_migrations/20131024000000_create_keyspace_Cryptic_down.cql.erb
|
|
198
|
+
- cassandra_migrations/20131024000000_create_keyspace_Cryptic_up.cql.erb
|
|
199
|
+
- cassandra_migrations/20131025000000_create_table_overlay_actions_down.cql.erb
|
|
200
|
+
- cassandra_migrations/20131025000000_create_table_overlay_actions_up.cql.erb
|
|
201
|
+
- cassandra_migrations/20131114488001_create_client_survey_user_site_tables_down.cql.erb
|
|
202
|
+
- cassandra_migrations/20131114488001_create_client_survey_user_site_tables_up.cql.erb
|
|
203
|
+
- cassandra_migrations/20131206944013_create_table_cryptic_place_marker_down.cql.erb
|
|
204
|
+
- cassandra_migrations/20131206944013_create_table_cryptic_place_marker_up.cql.erb
|
|
205
|
+
- cassandra_migrations/20140115150807_add_place_marker_to_place_markers_down.cql
|
|
206
|
+
- cassandra_migrations/20140115150807_add_place_marker_to_place_markers_up.cql
|
|
207
|
+
- cassandra_migrations/20140116281758_repartition_place_markers_table_down.cql
|
|
208
|
+
- cassandra_migrations/20140116281758_repartition_place_markers_table_up.cql
|
|
209
|
+
- cryptic-hoffa.gemspec
|
|
210
|
+
- database.yml
|
|
211
|
+
- jenkins.recipe
|
|
212
|
+
- lib/cryptic/hoffa.rb
|
|
213
|
+
- lib/cryptic/hoffa/version.rb
|
|
214
|
+
- vendor/.gitkeep
|
|
215
|
+
homepage: ''
|
|
216
|
+
licenses:
|
|
217
|
+
- Proprietary
|
|
218
|
+
post_install_message:
|
|
219
|
+
rdoc_options: []
|
|
220
|
+
require_paths:
|
|
221
|
+
- lib
|
|
222
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
223
|
+
none: false
|
|
224
|
+
requirements:
|
|
225
|
+
- - ! '>='
|
|
226
|
+
- !ruby/object:Gem::Version
|
|
227
|
+
version: '0'
|
|
228
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
|
+
none: false
|
|
230
|
+
requirements:
|
|
231
|
+
- - ! '>='
|
|
232
|
+
- !ruby/object:Gem::Version
|
|
233
|
+
version: '0'
|
|
234
|
+
requirements: []
|
|
235
|
+
rubyforge_project:
|
|
236
|
+
rubygems_version: 1.8.23
|
|
237
|
+
signing_key:
|
|
238
|
+
specification_version: 3
|
|
239
|
+
summary: Gateway OMQ data to Cassandra
|
|
240
|
+
test_files: []
|