flydata 0.0.1.nc1
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 +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
|