strongspace 0.2.0 → 0.3.5
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/as_installed/ss +6 -1
- data/bin/as_installed/strongspace +5 -1
- data/lib/strongspace/client.rb +9 -0
- data/lib/strongspace/command.rb +8 -1
- data/lib/strongspace/commands/auth.rb +16 -8
- data/lib/strongspace/commands/files.rb +22 -0
- data/lib/strongspace/commands/keys.rb +4 -4
- data/lib/strongspace/commands/spaces.rb +5 -9
- data/lib/strongspace/helpers.rb +54 -7
- data/lib/strongspace/version.rb +1 -1
- data/spec/client_spec.rb +2 -2
- metadata +33 -46
data/bin/as_installed/ss
CHANGED
data/lib/strongspace/client.rb
CHANGED
@@ -62,8 +62,13 @@ class Strongspace::Client
|
|
62
62
|
doc = delete("/api/v1/files/#{escape(path[1..-1])}")
|
63
63
|
end
|
64
64
|
|
65
|
+
def size(path)
|
66
|
+
doc = JSON.parse get("/api/v1/files/#{escape(path[1..-1])}?op=size")
|
67
|
+
end
|
68
|
+
|
65
69
|
def spaces
|
66
70
|
doc = JSON.parse get('/api/v1/spaces')
|
71
|
+
doc["spaces"]
|
67
72
|
end
|
68
73
|
|
69
74
|
def delete_space(space_name)
|
@@ -91,6 +96,10 @@ class Strongspace::Client
|
|
91
96
|
doc = JSON.parse post("/api/v1/spaces/#{escape(space_name)}/snapshots", :name => snapshot_name)
|
92
97
|
end
|
93
98
|
|
99
|
+
def filesystem
|
100
|
+
doc = JSON.parse get("/api/v1/filesystem").to_s
|
101
|
+
doc["filesystem"]
|
102
|
+
end
|
94
103
|
|
95
104
|
# Get the list of ssh public keys for the current user.
|
96
105
|
def keys
|
data/lib/strongspace/command.rb
CHANGED
@@ -19,8 +19,15 @@ module Strongspace
|
|
19
19
|
run_internal(command, args.dup)
|
20
20
|
rescue InvalidCommand
|
21
21
|
error "Unknown command. Run 'strongspace help' for usage information."
|
22
|
+
rescue Strongspace::Exceptions::InvalidCredentials
|
23
|
+
if retries < 1
|
24
|
+
STDERR.puts "Authentication failure"
|
25
|
+
run(command, args, retries+1)
|
26
|
+
else
|
27
|
+
error "! Authentication failure"
|
28
|
+
end
|
22
29
|
rescue RestClient::Unauthorized
|
23
|
-
if retries <
|
30
|
+
if retries < 1
|
24
31
|
STDERR.puts "Authentication failure"
|
25
32
|
run(command, args, retries+1)
|
26
33
|
else
|
@@ -27,9 +27,9 @@ module Strongspace::Command
|
|
27
27
|
|
28
28
|
def authorize!
|
29
29
|
@credentials = [args.first, args[1]]
|
30
|
-
r = Strongspace::Client.auth(@credentials[0], @credentials[1])
|
30
|
+
r = Strongspace::Client.auth(@credentials[0], @credentials[1], host)
|
31
31
|
if r
|
32
|
-
@credentials[0] =
|
32
|
+
@credentials[0] = r['username']
|
33
33
|
@credentials[1] = r['api_token']
|
34
34
|
write_credentials
|
35
35
|
return true
|
@@ -58,10 +58,6 @@ module Strongspace::Command
|
|
58
58
|
@credentials[1]
|
59
59
|
end
|
60
60
|
|
61
|
-
def credentials_file
|
62
|
-
"#{credentials_folder}/credentials"
|
63
|
-
end
|
64
|
-
|
65
61
|
def get_credentials # :nodoc:
|
66
62
|
return if @credentials
|
67
63
|
unless @credentials = read_credentials
|
@@ -84,6 +80,10 @@ module Strongspace::Command
|
|
84
80
|
end
|
85
81
|
|
86
82
|
def ask_for_credentials
|
83
|
+
if ENV["STRONGSPACE_DISPLAY"] == "silent"
|
84
|
+
return [nil, nil]
|
85
|
+
end
|
86
|
+
|
87
87
|
puts "Enter your Strongspace credentials."
|
88
88
|
|
89
89
|
print "Username or Email: "
|
@@ -92,13 +92,14 @@ module Strongspace::Command
|
|
92
92
|
print "Password: "
|
93
93
|
password = running_on_windows? ? ask_for_password_on_windows : ask_for_password
|
94
94
|
|
95
|
-
|
95
|
+
r = Strongspace::Client.auth(user, password, host)
|
96
|
+
[r['username'], r['api_token']]
|
96
97
|
end
|
97
98
|
|
98
99
|
def valid_saved_credentials?
|
99
100
|
if File.exists?(credentials_file)
|
100
101
|
credentials = read_credentials
|
101
|
-
r = Strongspace::Client.auth(credentials[0], credentials[1])
|
102
|
+
r = Strongspace::Client.auth(credentials[0], credentials[1], host)
|
102
103
|
return !r.blank?
|
103
104
|
end
|
104
105
|
return false
|
@@ -131,6 +132,13 @@ module Strongspace::Command
|
|
131
132
|
end
|
132
133
|
|
133
134
|
def save_credentials
|
135
|
+
|
136
|
+
if args[0] and args[1]
|
137
|
+
@credentials = []
|
138
|
+
@credentials[0] = args[0]
|
139
|
+
@credentials[1] = args[1]
|
140
|
+
end
|
141
|
+
|
134
142
|
begin
|
135
143
|
write_credentials
|
136
144
|
command = 'auth:check'
|
@@ -55,4 +55,26 @@ module Strongspace::Command
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
class Quota < Base
|
59
|
+
def index
|
60
|
+
|
61
|
+
f = strongspace.filesystem
|
62
|
+
display "#{strongspace.username}:"
|
63
|
+
display " Quota: #{f["quota_gib"]} GiB"
|
64
|
+
display " Used: #{f["used_gib"]} GiB"
|
65
|
+
display " Available: #{f["avail_gib"]} GiB"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Size < Base
|
70
|
+
def index
|
71
|
+
if args.length != 1
|
72
|
+
error "please supply a remote path"
|
73
|
+
end
|
74
|
+
|
75
|
+
r = strongspace.size(args[0])
|
76
|
+
puts r
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
58
80
|
end
|
@@ -30,9 +30,9 @@ module Strongspace::Command
|
|
30
30
|
end
|
31
31
|
|
32
32
|
|
33
|
-
if !File.exist? "#{credentials_folder}/#{
|
34
|
-
`/usr/bin/ssh-keygen -f #{credentials_folder}/#{
|
35
|
-
args[0] = "#{credentials_folder}/#{
|
33
|
+
if !File.exist? "#{credentials_folder}/#{computername}.rsa"
|
34
|
+
`/usr/bin/ssh-keygen -f \"#{credentials_folder}/#{computername}.rsa\" -b 2048 -C \" Strongspace App - #{computername}\" -q -N ""` unless File.exist? "#{credentials_folder}/#{computername}.rsa"
|
35
|
+
args[0] = "#{credentials_folder}/#{computername}.rsa.pub"
|
36
36
|
begin
|
37
37
|
add
|
38
38
|
rescue RestClient::Conflict => e # Swallow errors if the key already exists on Strongspace
|
@@ -62,7 +62,7 @@ module Strongspace::Command
|
|
62
62
|
def valid_key_gui?
|
63
63
|
return unless running_on_a_mac? and File.exist? "#{support_directory}/ssh"
|
64
64
|
|
65
|
-
ret = `ssh -o PreferredAuthentications=publickey -i "#{support_directory}/ssh/#{
|
65
|
+
ret = `ssh -o PreferredAuthentications=publickey -i "#{support_directory}/ssh/#{computername}.rsa" #{strongspace.username}@#{strongspace.username}.strongspace.com 2>&1`
|
66
66
|
|
67
67
|
if ret.include? "Strongspace"
|
68
68
|
display "Valid key installed"
|
@@ -63,7 +63,7 @@ module Strongspace::Command
|
|
63
63
|
while (!success and (retries < 5)) do
|
64
64
|
begin
|
65
65
|
create_snapshot
|
66
|
-
thin_snapshots
|
66
|
+
#thin_snapshots
|
67
67
|
rescue SocketError => e
|
68
68
|
sleep(10)
|
69
69
|
retries = retries + 1
|
@@ -86,17 +86,11 @@ module Strongspace::Command
|
|
86
86
|
|
87
87
|
keeplist = []
|
88
88
|
|
89
|
-
if snapshots.count < 24
|
90
|
-
return
|
91
|
-
end
|
92
|
-
|
93
89
|
snapshots.each do |s|
|
94
|
-
|
95
|
-
if Time.parse(s['created_at']) > (Time.now - 3600*24)
|
90
|
+
if DateTime.parse(s['created_at']).to_local_time > (Time.now - 3600*24)
|
96
91
|
keeplist << s
|
97
92
|
next
|
98
93
|
end
|
99
|
-
|
100
94
|
end
|
101
95
|
|
102
96
|
(snapshots - keeplist).each do |k|
|
@@ -141,6 +135,8 @@ module Strongspace::Command
|
|
141
135
|
<string>#{log_file}</string>
|
142
136
|
<key>EnvironmentVariables</key>
|
143
137
|
<dict>
|
138
|
+
<key>STRONGSPACE_DISPLAY</key>
|
139
|
+
<string>logging</string>
|
144
140
|
<key>GEM_PATH</key>
|
145
141
|
<string>#{support_directory}/gems</string>
|
146
142
|
<key>GEM_HOME</key>
|
@@ -187,7 +183,6 @@ module Strongspace::Command
|
|
187
183
|
CronEdit::Crontab.Remove "strongspace-snapshots-#{space_name}"
|
188
184
|
end
|
189
185
|
|
190
|
-
display "Unscheduled snapshotting of #{space_name}"
|
191
186
|
end
|
192
187
|
|
193
188
|
|
@@ -202,3 +197,4 @@ module Strongspace::Command
|
|
202
197
|
|
203
198
|
end
|
204
199
|
end
|
200
|
+
|
data/lib/strongspace/helpers.rb
CHANGED
@@ -38,22 +38,38 @@ module Strongspace
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def gui_ssh_key
|
41
|
-
"#{credentials_folder}/#{
|
41
|
+
"#{credentials_folder}/#{computername}.rsa"
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
45
|
-
|
44
|
+
def computername
|
45
|
+
n = File.read(credentials_file).split("\n")[2]
|
46
46
|
|
47
|
-
if
|
48
|
-
@
|
47
|
+
if n.blank?
|
48
|
+
@computername ||= `system_profiler SPSoftwareDataType | grep "Computer Name"`.split(":").last.gsub(/[[:punct:][:cntrl:]]/, '')
|
49
|
+
|
50
|
+
if @computername.include?(".local")
|
51
|
+
@computername = @computername.split(".")[0]
|
52
|
+
end
|
53
|
+
|
54
|
+
File.open(credentials_file, 'a') do |f|
|
55
|
+
f.puts @computername
|
56
|
+
end
|
57
|
+
|
58
|
+
else
|
59
|
+
@computername = n.strip
|
49
60
|
end
|
50
|
-
|
61
|
+
|
62
|
+
return @computername
|
51
63
|
end
|
52
64
|
|
53
65
|
def credentials_folder
|
54
66
|
"#{support_directory}/credentials"
|
55
67
|
end
|
56
68
|
|
69
|
+
def credentials_file
|
70
|
+
"#{credentials_folder}/credentials"
|
71
|
+
end
|
72
|
+
|
57
73
|
def pids_folder
|
58
74
|
"#{support_directory}/pids"
|
59
75
|
end
|
@@ -95,6 +111,34 @@ module Strongspace
|
|
95
111
|
return nil
|
96
112
|
end
|
97
113
|
|
114
|
+
def kill_via_pidfile(name)
|
115
|
+
existing_pid = pid_from_pid_file(name)
|
116
|
+
|
117
|
+
if not existing_pid
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
|
121
|
+
begin
|
122
|
+
# This process is running, Kill 0 is a no-op that only works
|
123
|
+
# if the process exists
|
124
|
+
Process.kill(9, existing_pid)
|
125
|
+
return true
|
126
|
+
rescue Errno::EPERM
|
127
|
+
error "No longer have permissions to check this PID"
|
128
|
+
return
|
129
|
+
rescue Errno::ESRCH
|
130
|
+
# Cleanup orphaned pid file and continue on as normal
|
131
|
+
File.unlink(pid_file_path(name))
|
132
|
+
return
|
133
|
+
rescue
|
134
|
+
error "Unable to determine status for #{existing_pid} : #{$!}"
|
135
|
+
return
|
136
|
+
end
|
137
|
+
|
138
|
+
File.unlink(pid_file_path(name))
|
139
|
+
return false
|
140
|
+
end
|
141
|
+
|
98
142
|
def process_running?(name)
|
99
143
|
existing_pid = pid_from_pid_file(name)
|
100
144
|
|
@@ -117,7 +161,7 @@ module Strongspace
|
|
117
161
|
end
|
118
162
|
|
119
163
|
return false
|
120
|
-
|
164
|
+
end
|
121
165
|
|
122
166
|
def create_pid_file(name, pid)
|
123
167
|
|
@@ -143,6 +187,9 @@ module Strongspace
|
|
143
187
|
end
|
144
188
|
|
145
189
|
def display(msg, newline=true)
|
190
|
+
if ENV["STRONGSPACE_DISPLAY"] == "silent"
|
191
|
+
return
|
192
|
+
end
|
146
193
|
if newline
|
147
194
|
puts(msg)
|
148
195
|
else
|
data/lib/strongspace/version.rb
CHANGED
data/spec/client_spec.rb
CHANGED
@@ -16,13 +16,13 @@ describe Strongspace::Client do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should return an API key hash for auth" do
|
19
|
-
api_token = { "api_key" => "abc" }
|
19
|
+
api_token = { "api_key" => "abc", "username" => "foo/token" }
|
20
20
|
stub_request(:get, "https://foo:bar@www.strongspace.com/api/v1/api_token").to_return(:body => api_token.to_json)
|
21
21
|
Strongspace::Client.auth("foo", "bar").should == api_token
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should fail auth gracefully with a bad password" do
|
25
|
-
api_token = { "api_key" => "abc" }
|
25
|
+
api_token = { "api_key" => "abc", "username" => "foo/token" }
|
26
26
|
stub_request(:get, "https://foo:bar@www.strongspace.com/api/v1/api_token").to_return(:body => api_token.to_json)
|
27
27
|
lambda {Strongspace::Client.auth("foo", "ba3r")}.should raise_error(WebMock::NetConnectNotAllowedError)
|
28
28
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strongspace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 25
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 3
|
9
|
+
- 5
|
10
|
+
version: 0.3.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Strongspace
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-02-14 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -60,24 +60,10 @@ dependencies:
|
|
60
60
|
version: "0"
|
61
61
|
type: :development
|
62
62
|
version_requirements: *id003
|
63
|
-
- !ruby/object:Gem::Dependency
|
64
|
-
name: autotest-fsevent
|
65
|
-
prerelease: false
|
66
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
|
-
requirements:
|
69
|
-
- - ">="
|
70
|
-
- !ruby/object:Gem::Version
|
71
|
-
hash: 3
|
72
|
-
segments:
|
73
|
-
- 0
|
74
|
-
version: "0"
|
75
|
-
type: :development
|
76
|
-
version_requirements: *id004
|
77
63
|
- !ruby/object:Gem::Dependency
|
78
64
|
name: rspec
|
79
65
|
prerelease: false
|
80
|
-
requirement: &
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
81
67
|
none: false
|
82
68
|
requirements:
|
83
69
|
- - ~>
|
@@ -89,11 +75,11 @@ dependencies:
|
|
89
75
|
- 0
|
90
76
|
version: 1.3.0
|
91
77
|
type: :development
|
92
|
-
version_requirements: *
|
78
|
+
version_requirements: *id004
|
93
79
|
- !ruby/object:Gem::Dependency
|
94
80
|
name: webmock
|
95
81
|
prerelease: false
|
96
|
-
requirement: &
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
97
83
|
none: false
|
98
84
|
requirements:
|
99
85
|
- - ~>
|
@@ -105,11 +91,11 @@ dependencies:
|
|
105
91
|
- 0
|
106
92
|
version: 1.5.0
|
107
93
|
type: :development
|
108
|
-
version_requirements: *
|
94
|
+
version_requirements: *id005
|
109
95
|
- !ruby/object:Gem::Dependency
|
110
|
-
name:
|
96
|
+
name: sinatra
|
111
97
|
prerelease: false
|
112
|
-
requirement: &
|
98
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
113
99
|
none: false
|
114
100
|
requirements:
|
115
101
|
- - ">="
|
@@ -119,11 +105,11 @@ dependencies:
|
|
119
105
|
- 0
|
120
106
|
version: "0"
|
121
107
|
type: :development
|
122
|
-
version_requirements: *
|
108
|
+
version_requirements: *id006
|
123
109
|
- !ruby/object:Gem::Dependency
|
124
|
-
name: sinatra
|
110
|
+
name: sinatra-reloader
|
125
111
|
prerelease: false
|
126
|
-
requirement: &
|
112
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
127
113
|
none: false
|
128
114
|
requirements:
|
129
115
|
- - ">="
|
@@ -133,25 +119,26 @@ dependencies:
|
|
133
119
|
- 0
|
134
120
|
version: "0"
|
135
121
|
type: :development
|
136
|
-
version_requirements: *
|
122
|
+
version_requirements: *id007
|
137
123
|
- !ruby/object:Gem::Dependency
|
138
|
-
name:
|
124
|
+
name: hoptoad_notifier
|
139
125
|
prerelease: false
|
140
|
-
requirement: &
|
126
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
141
127
|
none: false
|
142
128
|
requirements:
|
143
|
-
- -
|
129
|
+
- - ~>
|
144
130
|
- !ruby/object:Gem::Version
|
145
|
-
hash:
|
131
|
+
hash: 11
|
146
132
|
segments:
|
147
|
-
-
|
148
|
-
|
133
|
+
- 2
|
134
|
+
- 4
|
135
|
+
version: "2.4"
|
149
136
|
type: :development
|
150
|
-
version_requirements: *
|
137
|
+
version_requirements: *id008
|
151
138
|
- !ruby/object:Gem::Dependency
|
152
139
|
name: open4
|
153
140
|
prerelease: false
|
154
|
-
requirement: &
|
141
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
155
142
|
none: false
|
156
143
|
requirements:
|
157
144
|
- - ">="
|
@@ -161,11 +148,11 @@ dependencies:
|
|
161
148
|
- 0
|
162
149
|
version: "0"
|
163
150
|
type: :runtime
|
164
|
-
version_requirements: *
|
151
|
+
version_requirements: *id009
|
165
152
|
- !ruby/object:Gem::Dependency
|
166
153
|
name: cronedit
|
167
154
|
prerelease: false
|
168
|
-
requirement: &
|
155
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
169
156
|
none: false
|
170
157
|
requirements:
|
171
158
|
- - ">="
|
@@ -175,11 +162,11 @@ dependencies:
|
|
175
162
|
- 0
|
176
163
|
version: "0"
|
177
164
|
type: :runtime
|
178
|
-
version_requirements: *
|
165
|
+
version_requirements: *id010
|
179
166
|
- !ruby/object:Gem::Dependency
|
180
167
|
name: rest-client
|
181
168
|
prerelease: false
|
182
|
-
requirement: &
|
169
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
183
170
|
none: false
|
184
171
|
requirements:
|
185
172
|
- - "="
|
@@ -191,11 +178,11 @@ dependencies:
|
|
191
178
|
- 1
|
192
179
|
version: 1.6.1
|
193
180
|
type: :runtime
|
194
|
-
version_requirements: *
|
181
|
+
version_requirements: *id011
|
195
182
|
- !ruby/object:Gem::Dependency
|
196
183
|
name: json_pure
|
197
184
|
prerelease: false
|
198
|
-
requirement: &
|
185
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
199
186
|
none: false
|
200
187
|
requirements:
|
201
188
|
- - <
|
@@ -207,7 +194,7 @@ dependencies:
|
|
207
194
|
- 0
|
208
195
|
version: 1.5.0
|
209
196
|
type: :runtime
|
210
|
-
version_requirements: *
|
197
|
+
version_requirements: *id012
|
211
198
|
description: Client library and command line tool for Strongspace.
|
212
199
|
email: support@strongspace.com
|
213
200
|
executables:
|
@@ -272,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
272
259
|
requirements: []
|
273
260
|
|
274
261
|
rubyforge_project:
|
275
|
-
rubygems_version: 1.
|
262
|
+
rubygems_version: 1.5.0
|
276
263
|
signing_key:
|
277
264
|
specification_version: 3
|
278
265
|
summary: Client library and CLI for Strongspace.
|