flydata 0.0.1.nc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +49 -0
- data/.rspec +1 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +67 -0
- data/Rakefile +34 -0
- data/VERSION +1 -0
- data/bin/flydata +11 -0
- data/flydata.gemspec +106 -0
- data/lib/flydata.rb +16 -0
- data/lib/flydata/api/base.rb +16 -0
- data/lib/flydata/api/data_entry.rb +11 -0
- data/lib/flydata/api/data_port.rb +15 -0
- data/lib/flydata/api_client.rb +57 -0
- data/lib/flydata/cli.rb +41 -0
- data/lib/flydata/command/base.rb +35 -0
- data/lib/flydata/command/crontab.rb +9 -0
- data/lib/flydata/command/login.rb +39 -0
- data/lib/flydata/command/restart.rb +10 -0
- data/lib/flydata/command/routine.rb +29 -0
- data/lib/flydata/command/sender.rb +92 -0
- data/lib/flydata/command/setlogdel.rb +73 -0
- data/lib/flydata/command/setup.rb +101 -0
- data/lib/flydata/command/start.rb +10 -0
- data/lib/flydata/command/stop.rb +10 -0
- data/lib/flydata/credentials.rb +52 -0
- data/lib/flydata/cron.rb +88 -0
- data/lib/flydata/flydata_crontab.sh +116 -0
- data/lib/flydata/helpers.rb +20 -0
- data/lib/flydata/log_monitor.rb +93 -0
- data/lib/flydata/proxy.rb +16 -0
- data/spec/flydata/api/data_entry_spec.rb +17 -0
- data/spec/flydata/command/sender_spec.rb +37 -0
- data/spec/flydata_spec.rb +4 -0
- data/spec/spec_helper.rb +12 -0
- metadata +291 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Command
|
3
|
+
class Base
|
4
|
+
def initialize
|
5
|
+
@api_client = ApiClient.instance
|
6
|
+
end
|
7
|
+
def flydata; @api_client end
|
8
|
+
|
9
|
+
# retrieve models on servers
|
10
|
+
def retrieve_data_entries
|
11
|
+
data_entries = flydata.get('/data_entries')
|
12
|
+
unless flydata.response.code == 200
|
13
|
+
raise "Failed to retrieve data_entries"
|
14
|
+
end
|
15
|
+
data_entries
|
16
|
+
end
|
17
|
+
|
18
|
+
# print console
|
19
|
+
def newline; puts end
|
20
|
+
def ask_yes_no(message)
|
21
|
+
loop do
|
22
|
+
ans = ask("#{message} (yes/no): ")
|
23
|
+
if ans.size > 0
|
24
|
+
case ans[0].downcase
|
25
|
+
when 'y'; return true
|
26
|
+
when 'n'; return false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
say(" ! Please answer y[es] or n[o]")
|
30
|
+
newline
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Command
|
3
|
+
class Login < Base
|
4
|
+
LOGIN_TRIAL_TIMES=3
|
5
|
+
def run
|
6
|
+
ret = login(LOGIN_TRIAL_TIMES)
|
7
|
+
raise "Login failed #{LOGIN_TRIAL_TIMES} times." unless ret
|
8
|
+
ret
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def login(times=3)
|
13
|
+
1.upto(times) do |i|
|
14
|
+
begin
|
15
|
+
return true if login_once
|
16
|
+
rescue Exception => e
|
17
|
+
puts e
|
18
|
+
end
|
19
|
+
end
|
20
|
+
false
|
21
|
+
end
|
22
|
+
def login_once
|
23
|
+
# Ask login info
|
24
|
+
email = ask("FlyData Email: ")
|
25
|
+
password = ask("FlyData password: ") {|q| q.echo = false}
|
26
|
+
flydata.credentials = Flydata::Credentials.new(email, password)
|
27
|
+
# Auth request
|
28
|
+
flydata.post('/users/sign_in')
|
29
|
+
if flydata.response.code == 201 # 201: Created
|
30
|
+
say("Login succeeded!")
|
31
|
+
flydata.credentials.authenticate!
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
say("Login failed!")
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Command
|
3
|
+
class Routine < Base
|
4
|
+
def run
|
5
|
+
print "#{Time.now} "
|
6
|
+
unless flydata.credentials.authenticated?
|
7
|
+
raise "Authentication error. Please login."
|
8
|
+
end
|
9
|
+
log_paths = retrieve_log_paths
|
10
|
+
log_paths and log_paths.size() > 0 and log_paths.each { |path|
|
11
|
+
if File.exist?(path) and File.writable?(path)
|
12
|
+
puts "Start - #{path}. "
|
13
|
+
Flydata::LogMonitor.new(path).setup.rotate
|
14
|
+
else
|
15
|
+
puts "Skip - #{path}. System cannot access this path."
|
16
|
+
end
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def retrieve_log_paths
|
22
|
+
data_entries = retrieve_data_entries
|
23
|
+
data_entries.map {|e|
|
24
|
+
e['log_path'] if e['log_deletion']
|
25
|
+
}.compact
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Command
|
3
|
+
class Sender < Base
|
4
|
+
FLYDATA_HOME=Flydata::HOME_DIR
|
5
|
+
def start
|
6
|
+
if process_exist?
|
7
|
+
say("Process exist. Please stop process first.")
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
11
|
+
retry_count = 10
|
12
|
+
1.upto(retry_count) do |i|
|
13
|
+
break if server_ready?
|
14
|
+
say("Waiting server side active... (#{i}/#{retry_count})")
|
15
|
+
sleep 30
|
16
|
+
end
|
17
|
+
|
18
|
+
say('Starting sender process.')
|
19
|
+
Dir.chdir(FLYDATA_HOME){
|
20
|
+
system("fluentd -d #{FLYDATA_HOME}/flydata.pid -l #{FLYDATA_HOME}/flydata.log -c #{FLYDATA_HOME}/flydata.conf")
|
21
|
+
}
|
22
|
+
|
23
|
+
sleep 5
|
24
|
+
|
25
|
+
data_port = flydata.data_port.get
|
26
|
+
data_port_id = data_port['id']
|
27
|
+
|
28
|
+
retry_count = 10
|
29
|
+
ready = false
|
30
|
+
1.upto(retry_count) do |i|
|
31
|
+
ready ||= client_ready?
|
32
|
+
if ready and uploaded_successfully?(data_port_id)
|
33
|
+
say('Done.')
|
34
|
+
say("Go to your Dashboard! http://#{Flydata::FLYDATA_API_HOST}")
|
35
|
+
return true
|
36
|
+
end
|
37
|
+
say("Waiting client side active... (#{i}/#{retry_count})")
|
38
|
+
sleep 30
|
39
|
+
end
|
40
|
+
|
41
|
+
say('Something wrong..')
|
42
|
+
false
|
43
|
+
end
|
44
|
+
def stop
|
45
|
+
unless process_exist?
|
46
|
+
say("Process doesn't exist.")
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
|
50
|
+
say('Stopping sender process.')
|
51
|
+
if system("kill `cat #{FLYDATA_HOME}/flydata.pid`")
|
52
|
+
say('Done.')
|
53
|
+
return true
|
54
|
+
else
|
55
|
+
say('Something wrong..')
|
56
|
+
end
|
57
|
+
false
|
58
|
+
end
|
59
|
+
def restart
|
60
|
+
if process_exist?
|
61
|
+
say('Restarting sender process.')
|
62
|
+
if system("kill -HUP `cat #{FLYDATA_HOME}/flydata.pid`")
|
63
|
+
say('Done.')
|
64
|
+
return true
|
65
|
+
else
|
66
|
+
say('Something wrong..')
|
67
|
+
end
|
68
|
+
else
|
69
|
+
say("Process doesn't exist.")
|
70
|
+
start
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def server_ready?
|
76
|
+
data_port = flydata.data_port.get
|
77
|
+
data_port['server_status'] == 'active'
|
78
|
+
end
|
79
|
+
def client_ready?
|
80
|
+
process_exist?
|
81
|
+
end
|
82
|
+
def process_exist?
|
83
|
+
process_count = `ps aux|grep -v grep|grep "\\.flydata/flydata\\.conf"|grep fluentd|wc -l`.to_i
|
84
|
+
process_count > 0
|
85
|
+
end
|
86
|
+
def uploaded_successfully?(data_port_id)
|
87
|
+
res = flydata.get("/data_ports/#{data_port_id}/tail.json")
|
88
|
+
res and res['logs'] and res['logs'].size > 0
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Command
|
3
|
+
class Setlogdel < Base
|
4
|
+
def run
|
5
|
+
Flydata::Command::Login.new.run unless flydata.credentials.authenticated?
|
6
|
+
# Choose target data_entry
|
7
|
+
data_entry = choose_data_entry
|
8
|
+
return unless data_entry
|
9
|
+
# Confirm and update
|
10
|
+
if confirm_setting data_entry
|
11
|
+
set_log_deletion data_entry
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def choose_data_entry
|
17
|
+
data_entries = retrieve_data_entries
|
18
|
+
if data_entries.size < 1
|
19
|
+
puts("There are no registered entries.")
|
20
|
+
puts("You need to create a data entry by flydata setup command.")
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
choices = data_entries.map {|e|
|
24
|
+
"#{e['name']}\t#{e['log_path']}\t -- Log deletion:#{boolToOnOff e['log_deletion']}"
|
25
|
+
}
|
26
|
+
choices << "Cancel"
|
27
|
+
|
28
|
+
choice = nil
|
29
|
+
say('Please select your log path for setting log deletion.')
|
30
|
+
newline
|
31
|
+
choose do |menu|
|
32
|
+
menu.index = :letter
|
33
|
+
menu.index_suffix = ") "
|
34
|
+
menu.prompt = "Select item to change log deletion setting: "
|
35
|
+
menu.choices(*choices) {|item| choice = item.split(' ')[0]}
|
36
|
+
end
|
37
|
+
newline
|
38
|
+
data_entries.select{|e| e['log_path'] == choice}.first
|
39
|
+
end
|
40
|
+
def confirm_setting(data_entry)
|
41
|
+
cur_flag = data_entry['log_deletion']
|
42
|
+
loop do
|
43
|
+
say "Target log path: #{data_entry['log_path']}"
|
44
|
+
say "Now changing log deletion setting: #{boolToOnOff cur_flag} -> #{boolToOnOff !cur_flag}"
|
45
|
+
ans = ask "Are you sure? (yes/no): "
|
46
|
+
if ans.size > 0
|
47
|
+
case ans[0].downcase
|
48
|
+
when 'y'; return true
|
49
|
+
when 'n'; return false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
say " ! Please answer y[es] or n[o]"
|
53
|
+
newline
|
54
|
+
end
|
55
|
+
end
|
56
|
+
def boolToOnOff(bool)
|
57
|
+
bool ? 'ON' : 'OFF'
|
58
|
+
end
|
59
|
+
def set_log_deletion(data_entry)
|
60
|
+
param = {
|
61
|
+
:data_entry => {
|
62
|
+
'log_deletion' => !data_entry['log_deletion']
|
63
|
+
}
|
64
|
+
}
|
65
|
+
url = "/data_entries/#{data_entry['id']}"
|
66
|
+
ret = flydata.put(url, param)
|
67
|
+
raise 'Failed to update the log deletion setting.' unless ret['success']
|
68
|
+
Flydata::Command::Crontab.new.run if !data_entry['log_deletion']
|
69
|
+
puts "Update succeeded!"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Flydata
|
2
|
+
module Command
|
3
|
+
class Setup < Base
|
4
|
+
LOG_PATH_EXAMPLES=
|
5
|
+
%w(/var/log/httpd/access_log /var/log/apache2/access.log
|
6
|
+
/var/log/httpd-access.log /var/log/apache2/access_log
|
7
|
+
/var/log/messages /var/log/maillog /var/log/mysql/error.log
|
8
|
+
/home/*/deploy/shared/log/*.log)
|
9
|
+
OTHER = '-- None of above --'
|
10
|
+
|
11
|
+
# readline settings for asking log path
|
12
|
+
Readline.completion_append_character = "/"
|
13
|
+
Readline.completion_proc = Proc.new do |str|
|
14
|
+
Dir[str+'*'].grep( /^#{Regexp.escape(str)}/ )
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
# login
|
19
|
+
Flydata::Command::Login.new.run unless flydata.credentials.authenticated?
|
20
|
+
|
21
|
+
# choose entries
|
22
|
+
unless shown = show_registered_entries and not more_entry?
|
23
|
+
begin
|
24
|
+
show_registered_entries unless shown
|
25
|
+
shown = false
|
26
|
+
path = choose_log_path_from_examples
|
27
|
+
case path
|
28
|
+
when OTHER; ask_log_path
|
29
|
+
else; create_log_entry(path, ask_log_deletion)
|
30
|
+
end
|
31
|
+
newline
|
32
|
+
end while more_entry?
|
33
|
+
end
|
34
|
+
|
35
|
+
# start client process
|
36
|
+
Flydata::Command::Sender.new.restart
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def show_registered_entries
|
41
|
+
data_entries = retrieve_data_entries
|
42
|
+
@last_fetched_entries = data_entries
|
43
|
+
if data_entries and data_entries.size > 0
|
44
|
+
puts('Registered entries. ')
|
45
|
+
data_entries.each { |data_entry|
|
46
|
+
say(" - #{data_entry['name']}\t#{data_entry['log_path']}")
|
47
|
+
}
|
48
|
+
true
|
49
|
+
else
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
def choose_log_path_from_examples
|
54
|
+
candidates = (`ls #{LOG_PATH_EXAMPLES.join(' ')} 2>/dev/null`).split(/\s+/)
|
55
|
+
candidates = candidates.find_all{|path| File.readable?(path)}
|
56
|
+
if @last_fetched_entries
|
57
|
+
candidates = candidates - @last_fetched_entries.map{|v| v['log_path']}
|
58
|
+
end
|
59
|
+
return OTHER unless candidates.size > 0
|
60
|
+
candidates << OTHER
|
61
|
+
choice = nil
|
62
|
+
say('Please select your log path for sending FlyData')
|
63
|
+
newline
|
64
|
+
choose do |menu|
|
65
|
+
menu.index = :letter
|
66
|
+
menu.index_suffix = ") "
|
67
|
+
menu.prompt = "Your log path: "
|
68
|
+
menu.choices(*candidates) {|item| choice = item}
|
69
|
+
end
|
70
|
+
newline
|
71
|
+
choice
|
72
|
+
end
|
73
|
+
def ask_log_path
|
74
|
+
path = nil
|
75
|
+
loop do
|
76
|
+
path = Readline.readline("Enter the absolute path of your log (return to cancel): ")
|
77
|
+
return if path.empty?
|
78
|
+
break if FileTest.file?(path) and FileTest.readable?(path)
|
79
|
+
say(" ! #{path} is not a readable file!")
|
80
|
+
newline
|
81
|
+
end
|
82
|
+
create_log_entry(path, ask_log_deletion)
|
83
|
+
end
|
84
|
+
def ask_log_deletion
|
85
|
+
say("** Log deletion setting **")
|
86
|
+
say("Flydata has a log deletion feature that flydata will delete old log archives uploaded by flydata automatically.")
|
87
|
+
say("Flydata will delete logs whose last modified timestamp is 7 days ago.")
|
88
|
+
ask_yes_no("Set auto log deletion mode?")
|
89
|
+
end
|
90
|
+
def create_log_entry(path, log_deletion)
|
91
|
+
data_port = flydata.data_port.get
|
92
|
+
flydata.data_entry.create(data_port_id: data_port['id'], log_path: path, log_deletion: log_deletion)
|
93
|
+
Flydata::Command::Crontab.new.run if log_deletion
|
94
|
+
say("Process successfuly!") if flydata.response.code == 200
|
95
|
+
end
|
96
|
+
def more_entry?
|
97
|
+
ask_yes_no("Do you want to add more log path?")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Flydata
|
2
|
+
class Credentials
|
3
|
+
include Helpers
|
4
|
+
attr_reader :user, :password
|
5
|
+
def initialize(user=nil, password=nil)
|
6
|
+
read_credentials
|
7
|
+
if user && password
|
8
|
+
@user = user
|
9
|
+
@password = password
|
10
|
+
elsif !(@authenticated)
|
11
|
+
@user = ENV['FLYDATA_LOGIN']
|
12
|
+
@password = ENV['FLYDATA_PASSWORD']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
def authenticate!
|
16
|
+
@authenticated = true
|
17
|
+
write_credentials
|
18
|
+
end
|
19
|
+
def authenticated?
|
20
|
+
@authenticated
|
21
|
+
end
|
22
|
+
def write_credentials
|
23
|
+
dir = File.dirname(credentials_file)
|
24
|
+
FileUtils.mkdir_p(dir)
|
25
|
+
File.delete(credentials_file) if FileTest.exists?(credentials_file)
|
26
|
+
File.open(credentials_file, 'w', 0400) do |out|
|
27
|
+
out.puts @user
|
28
|
+
out.puts encode(@password)
|
29
|
+
end
|
30
|
+
FileUtils.chmod(0700, dir)
|
31
|
+
end
|
32
|
+
def read_credentials
|
33
|
+
if FileTest.exist?(credentials_file)
|
34
|
+
File.open(credentials_file, 'r') do |f|
|
35
|
+
@user = f.gets.chomp
|
36
|
+
@password = decode(f.gets.chomp)
|
37
|
+
@authenticated = true if @user and @password
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
private
|
42
|
+
def credentials_file
|
43
|
+
File.join(home_directory, '.flydata', 'credentials')
|
44
|
+
end
|
45
|
+
def encode(str)
|
46
|
+
str.unpack('H*') # want to change more complecated? still useful for shoulder hacking.
|
47
|
+
end
|
48
|
+
def decode(str)
|
49
|
+
[str].pack('H*')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|