strongspace 0.2.0 → 0.3.5
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/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.
|