duostack 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/bin/.duostack-console-expect +2 -1
- data/bin/.duostack-expect +4 -0
- data/bin/bash/.duostack-console-expect +16 -5
- data/bin/bash/.duostack-expect +9 -0
- data/bin/duostack +160 -15
- metadata +7 -4
data/Rakefile
CHANGED
@@ -13,5 +13,5 @@ Jeweler::Tasks.new do |gem|
|
|
13
13
|
gem.authors = "Todd Eichel"
|
14
14
|
gem.require_paths = ['.'] # default is ["lib"] but we don't have that
|
15
15
|
|
16
|
-
gem.executables = ["duostack", ".duostack-console-expect"]
|
16
|
+
gem.executables = ["duostack", ".duostack-expect", ".duostack-console-expect"]
|
17
17
|
end
|
@@ -1,7 +1,18 @@
|
|
1
1
|
#!/usr/bin/env expect
|
2
|
-
set appname [lindex $argv 0]
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
set timeout 3600
|
4
|
+
|
5
|
+
set client [lindex $argv 0]
|
6
|
+
set type [lindex $argv 1]
|
7
|
+
set prompt [lindex $argv 2]
|
8
|
+
set command [lindex $argv 3]
|
9
|
+
set appname [lindex $argv 4]
|
10
|
+
|
11
|
+
spawn $client console $type --app $appname
|
12
|
+
expect $prompt
|
13
|
+
send "\r"
|
14
|
+
send -- "[read [open $command r]]"
|
15
|
+
send "\r"
|
16
|
+
expect $prompt
|
17
|
+
send "exit\r"
|
18
|
+
expect eof
|
data/bin/duostack
CHANGED
@@ -28,13 +28,14 @@ $client = File.basename(__FILE__)
|
|
28
28
|
module Duostack
|
29
29
|
class Client
|
30
30
|
|
31
|
-
VERSION = '0.
|
31
|
+
VERSION = '0.4.0'
|
32
32
|
DEPENDENCIES_LAST_MODIFIED = 1298683372
|
33
33
|
USER_AGENT = "duostack-#{VERSION}"
|
34
34
|
|
35
35
|
DEFAULTS = {
|
36
36
|
:credentials_location => '~/.duostack',
|
37
|
-
:remote_name => 'duostack'
|
37
|
+
:remote_name => 'duostack',
|
38
|
+
:console_type => 'app'
|
38
39
|
}
|
39
40
|
|
40
41
|
FLAGS = [ # app and remote get special handling
|
@@ -53,6 +54,7 @@ module Duostack
|
|
53
54
|
'billing_reset'
|
54
55
|
],
|
55
56
|
:app => [ # commands requiring an app to be specified (either by git inference or flag)
|
57
|
+
'info',
|
56
58
|
'logs',
|
57
59
|
'restart',
|
58
60
|
'ps',
|
@@ -68,6 +70,7 @@ module Duostack
|
|
68
70
|
:compound => [ # mult-part commands that expect subsequent arguments, must validate extra args on their own
|
69
71
|
'help',
|
70
72
|
'create',
|
73
|
+
'console',
|
71
74
|
'rake',
|
72
75
|
'config',
|
73
76
|
'env',
|
@@ -77,6 +80,28 @@ module Duostack
|
|
77
80
|
]
|
78
81
|
}
|
79
82
|
|
83
|
+
CONSOLES = {
|
84
|
+
:app => {
|
85
|
+
:target => 'cli-console@duostack.net',
|
86
|
+
:display_type => 'Ruby',
|
87
|
+
:display_name_suffix => '',
|
88
|
+
:prompt => '>> '
|
89
|
+
},
|
90
|
+
:mysql => {
|
91
|
+
:target => 'cli-dbconsole@duostack.net',
|
92
|
+
:display_type => 'database',
|
93
|
+
:display_name_suffix => ' (mysql)',
|
94
|
+
:prompt => 'mysql> '
|
95
|
+
},
|
96
|
+
:mongodb => {
|
97
|
+
:target => 'cli-dbconsole@duostack.net',
|
98
|
+
:display_type => 'database',
|
99
|
+
:display_name_suffix => ' (mongodb)',
|
100
|
+
:prompt => '> '
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
|
80
105
|
def initialize(args=[], client='duostack')
|
81
106
|
@args = args
|
82
107
|
@client = client
|
@@ -225,8 +250,15 @@ module Duostack
|
|
225
250
|
puts "First-time Duostack client setup"
|
226
251
|
print "Email: "
|
227
252
|
username = $stdin.gets.chomp
|
228
|
-
|
229
|
-
|
253
|
+
print "Password: "
|
254
|
+
begin
|
255
|
+
# http://stackoverflow.com/questions/133719/how-to-read-a-password-in-ruby
|
256
|
+
system "stty -echo"
|
257
|
+
password = $stdin.gets.chomp
|
258
|
+
puts '' # clears the line after
|
259
|
+
ensure
|
260
|
+
system "stty echo" # this is important
|
261
|
+
end
|
230
262
|
|
231
263
|
username = CGI::escape(username)
|
232
264
|
password = CGI::escape(password)
|
@@ -574,6 +606,11 @@ module Duostack
|
|
574
606
|
end
|
575
607
|
|
576
608
|
|
609
|
+
def info
|
610
|
+
puts api_get('get_info')
|
611
|
+
end
|
612
|
+
|
613
|
+
|
577
614
|
def logs
|
578
615
|
puts api_get('get_logs')
|
579
616
|
end
|
@@ -609,12 +646,65 @@ module Duostack
|
|
609
646
|
def console
|
610
647
|
# TODO: just use ruby expect lib
|
611
648
|
|
612
|
-
#
|
649
|
+
# get console and ensure it's valid
|
650
|
+
arg = (@args.shift || DEFAULTS[:console_type]).downcase
|
651
|
+
console = CONSOLES.fetch(arg.to_sym) do |invalid_type|
|
652
|
+
exit_with "invalid console type given ('#{invalid_type}'), try #{sentencize(CONSOLES.keys.collect { |k| k.to_s})}"
|
653
|
+
end
|
654
|
+
|
655
|
+
# take piped input first as command, fall back to using remaining command line args
|
656
|
+
if $stdin.tty?
|
657
|
+
console_command = @args.join(' ') unless @args.empty?
|
658
|
+
@args.clear
|
659
|
+
else
|
660
|
+
console_command = ''
|
661
|
+
$stdin.each_line { |line| console_command << line }
|
662
|
+
end
|
663
|
+
|
664
|
+
# we're finished processing args any remaning ones are invalid
|
665
|
+
unless @args.empty?
|
666
|
+
exit_with("unrecognized argument: '#{@args.first}', run '#{@client} help #{@command}' for usage")
|
667
|
+
end
|
668
|
+
|
669
|
+
# check for expect dependency
|
613
670
|
if `which expect`.empty?
|
614
671
|
exit_with "missing dependency, please install Expect (http://expect.sourceforge.net/)"
|
615
672
|
end
|
616
673
|
|
617
|
-
|
674
|
+
if console_command
|
675
|
+
|
676
|
+
# generate console command filename
|
677
|
+
timestamp = begin
|
678
|
+
t = Time.now
|
679
|
+
"#{t.to_i}.#{t.usec}"
|
680
|
+
end
|
681
|
+
console_command_file = File.join('/tmp', "ds-#{timestamp}.txt")
|
682
|
+
|
683
|
+
# write console command to file
|
684
|
+
file = File.new(console_command_file, 'w+')
|
685
|
+
file.chmod(0600)
|
686
|
+
file.write(console_command)
|
687
|
+
file.close
|
688
|
+
|
689
|
+
result = `#{$dir}/.duostack-console-expect '#{File.join($dir, $client)}' '#{arg}' '#{console[:prompt]}' '#{console_command_file}' '#{@app_name}'`
|
690
|
+
|
691
|
+
# clean up command file
|
692
|
+
File.delete(console_command_file)
|
693
|
+
|
694
|
+
# munge results
|
695
|
+
result = result.split("\r\n")
|
696
|
+
start = (result.index("#{console[:prompt]}") || 0) + 2
|
697
|
+
stop = (result.index("#{console[:prompt]}exit") || 0) - 1
|
698
|
+
result = result.slice(start..stop)
|
699
|
+
|
700
|
+
# clean up ruby return value marker
|
701
|
+
result[-1] = result[-1][3..-1] if arg == 'app'
|
702
|
+
|
703
|
+
puts result.join("\r\n")
|
704
|
+
|
705
|
+
else
|
706
|
+
exec("#{$dir}/.duostack-expect '#{console[:target]}' 'Connecting to #{console[:display_type]} console for ' '#{@app_name}#{console[:display_name_suffix]}'")
|
707
|
+
end
|
618
708
|
end
|
619
709
|
|
620
710
|
|
@@ -789,10 +879,12 @@ module Duostack
|
|
789
879
|
version Show version of this Duostack client
|
790
880
|
|
791
881
|
App Commands:
|
882
|
+
info Show app summary information
|
792
883
|
logs Retrieve server logs
|
793
884
|
restart Restart instances
|
794
885
|
ps List instances with current status
|
795
886
|
destroy Destroy Duostack App and associated data
|
887
|
+
console [<type> [command]] Connect to app or database console, run command
|
796
888
|
config [<name> [<setting>]] Show or set configuration options
|
797
889
|
env [<operation>] Manage environment variables
|
798
890
|
access [<operation>] Manage app collaborator access
|
@@ -800,7 +892,6 @@ module Duostack
|
|
800
892
|
instances [<operation>] Manage app instance count
|
801
893
|
|
802
894
|
App Commands - Ruby:
|
803
|
-
console Connect to IRB/Rails console
|
804
895
|
rake [<command>] Run a Rake command
|
805
896
|
|
806
897
|
EOF
|
@@ -856,12 +947,22 @@ module Duostack
|
|
856
947
|
EOF
|
857
948
|
end
|
858
949
|
|
950
|
+
def info
|
951
|
+
<<-EOF
|
952
|
+
|
953
|
+
Usage: #{$client} info
|
954
|
+
|
955
|
+
Retrieves a summary of app data, e.g. Git remote URL, instance count, etc.
|
956
|
+
|
957
|
+
EOF
|
958
|
+
end
|
959
|
+
|
859
960
|
def logs
|
860
961
|
<<-EOF
|
861
962
|
|
862
963
|
Usage: #{$client} logs
|
863
964
|
|
864
|
-
|
965
|
+
Retrieves aggregate logs from all of the app's instances.
|
865
966
|
|
866
967
|
EOF
|
867
968
|
end
|
@@ -888,7 +989,7 @@ module Duostack
|
|
888
989
|
|
889
990
|
Usage: #{$client} ps
|
890
991
|
|
891
|
-
|
992
|
+
Retrieves a listing of all of the app's instances with status information
|
892
993
|
(uptime) for each.
|
893
994
|
|
894
995
|
EOF
|
@@ -1039,7 +1140,7 @@ module Duostack
|
|
1039
1140
|
|
1040
1141
|
Any increment, decrement, or set command that would result in an invalid
|
1041
1142
|
instance count will be rejected with an error message. Instance counts must be
|
1042
|
-
greater than 0
|
1143
|
+
greater than 0.
|
1043
1144
|
|
1044
1145
|
EOF
|
1045
1146
|
end
|
@@ -1047,12 +1148,56 @@ module Duostack
|
|
1047
1148
|
def console
|
1048
1149
|
<<-EOF
|
1049
1150
|
|
1050
|
-
Usage:
|
1151
|
+
Usage:
|
1152
|
+
#{$client} console [<type> [<command>]]
|
1153
|
+
launches console session of <type> (defaults to
|
1154
|
+
'app' console), optionally runs specified
|
1155
|
+
<command> in console and prints the result
|
1156
|
+
|
1157
|
+
#{$client} console <type> <command> > <output-file>
|
1158
|
+
pipes the output from running <command> to the
|
1159
|
+
specified <output-file>
|
1160
|
+
|
1161
|
+
#{$client} console <type> < <input-file>
|
1162
|
+
pipes the contents of <input-file> into the
|
1163
|
+
specified console <type>, prints the result
|
1164
|
+
|
1165
|
+
Examples:
|
1166
|
+
#{$client} console same as running "#{$client} console app"
|
1167
|
+
#{$client} console app launches interactive app console (Ruby apps only)
|
1168
|
+
#{$client} console mysql launches interactive MySQL database console
|
1169
|
+
#{$client} console mongodb launches interactive MongoDB database console
|
1170
|
+
|
1171
|
+
#{$client} console app "puts('hello world')"
|
1172
|
+
#{$client} console mysql "SHOW TABLES;"
|
1173
|
+
runs the specified command and prints the result
|
1174
|
+
|
1175
|
+
#{$client} console mysql "SHOW TABLES;" > tables.txt
|
1176
|
+
runs "SHOW TABLES;" in the app's MySQL console,
|
1177
|
+
piping output into the file "tables.txt"
|
1178
|
+
|
1179
|
+
#{$client} console mysql < import.sql
|
1180
|
+
(EXPERIMENTAL) pipes the contents of "import.sql"
|
1181
|
+
into the app's MySQL console, printing the result
|
1182
|
+
|
1183
|
+
The "console" command can operate in three ways:
|
1184
|
+
|
1185
|
+
1. Launching an interactive console session with your app or one of its
|
1186
|
+
databases. If no argument is given, it connects to the app console itself
|
1187
|
+
(applicable only to Ruby apps). If a database name is given, connects to a
|
1188
|
+
database console session for that database. Valid database names are: mysql,
|
1189
|
+
mongodb.
|
1190
|
+
|
1191
|
+
You can use then use these interactive console sessions to make any action you
|
1192
|
+
would normally make in your app or database console.
|
1051
1193
|
|
1052
|
-
|
1053
|
-
|
1194
|
+
2. Running an ad-hoc command specified on the command line in the remaining
|
1195
|
+
arguments, and printing the result. You could also then pipe the output into an
|
1196
|
+
arbitrary file.
|
1054
1197
|
|
1055
|
-
|
1198
|
+
3. (EXPERIMENTAL) Sending the contents of a piped-in file to the specified (app
|
1199
|
+
or database) console. The resulting output will be collected and printed to your
|
1200
|
+
terminal.
|
1056
1201
|
|
1057
1202
|
EOF
|
1058
1203
|
end
|
@@ -1069,7 +1214,7 @@ module Duostack
|
|
1069
1214
|
Passing of environment variables if your rake task requires them is supported
|
1070
1215
|
(e.g. rake db:seed MODEL=Posts).
|
1071
1216
|
|
1072
|
-
Applicable only to Ruby
|
1217
|
+
Applicable only to Ruby apps.
|
1073
1218
|
|
1074
1219
|
EOF
|
1075
1220
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duostack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 4
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Todd Eichel
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-20 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -23,6 +23,7 @@ description: "Duostack command line client: create and manage Duostack apps"
|
|
23
23
|
email: todd@toddeichel.com
|
24
24
|
executables:
|
25
25
|
- duostack
|
26
|
+
- .duostack-expect
|
26
27
|
- .duostack-console-expect
|
27
28
|
extensions: []
|
28
29
|
|
@@ -31,7 +32,9 @@ extra_rdoc_files: []
|
|
31
32
|
files:
|
32
33
|
- Rakefile
|
33
34
|
- bin/.duostack-console-expect
|
35
|
+
- bin/.duostack-expect
|
34
36
|
- bin/bash/.duostack-console-expect
|
37
|
+
- bin/bash/.duostack-expect
|
35
38
|
- bin/duostack
|
36
39
|
- vendor/duostack-startcom.pem
|
37
40
|
has_rdoc: true
|