c66 0.1.0 → 0.1.96
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of c66 might be problematic. Click here for more details.
- checksums.yaml +15 -0
- data/.gitignore +14 -5
- data/Gemfile.lock +42 -0
- data/LICENSE.txt +1 -1
- data/README.md +138 -49
- data/lib/c66/commands/c66_toolbelt.rb +322 -65
- data/lib/c66/utils/version.rb +2 -1
- metadata +44 -27
- /data/bin/{c66.rb → c66} +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MDE0NGMzODMwZTIxZmJlZGNlNjljNDUyOGQxOWIzYmY1Y2Y5MjU1NA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzU2MDE3OWI5YzJmM2M1MTcxZTVhMTc2MDM0OGYzMzAyODJlZmE2Mw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZDFhMTM3YThjMGJiMzYxYzdlMThhOWQ1YzBhZTNkOTFlOTkxMDk3ODIxNGFi
|
10
|
+
MmQzYTdjN2Q5MzgyZTFjY2ZhYWI1YzY3MDQ4M2FkYjU3ZDA0MmEzMDMxNWYx
|
11
|
+
ZDY5MjM2MjU1YjMyNzZjMGFmMzEzMWMxYjdhNGJiMDM5NmY0MTc=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZmI3YWFiMjFjZGM3NjllOWE1ZDRiNTc4NzA5MThiOGUxMWZiNWVhMWJhZGIy
|
14
|
+
ZmNjYWRkNDhlNDdmMDhjYjlhNTcxMzg5ODUzMzY4NzYzZTFhYTcxZGNhNjli
|
15
|
+
MDc5ZTdkMzc1MTUxNzVmNTQwNmYxNmU2ZWY3NmY2MDhhNDg1NmY=
|
data/.gitignore
CHANGED
@@ -2,12 +2,8 @@
|
|
2
2
|
*.rbc
|
3
3
|
.bundle
|
4
4
|
.config
|
5
|
-
.yardoc
|
6
|
-
Gemfile.lock
|
7
|
-
InstalledFiles
|
8
|
-
_yardoc
|
9
5
|
coverage
|
10
|
-
|
6
|
+
InstalledFiles
|
11
7
|
lib/bundler/man
|
12
8
|
pkg
|
13
9
|
rdoc
|
@@ -15,3 +11,16 @@ spec/reports
|
|
15
11
|
test/tmp
|
16
12
|
test/version_tmp
|
17
13
|
tmp
|
14
|
+
.cloud66
|
15
|
+
|
16
|
+
# YARD artifacts
|
17
|
+
.yardoc
|
18
|
+
_yardoc
|
19
|
+
doc/
|
20
|
+
|
21
|
+
.ruby-gemset
|
22
|
+
.ruby-version
|
23
|
+
/dev.sh
|
24
|
+
/.DS_Store
|
25
|
+
|
26
|
+
/source.sh
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
c66 (0.1.94)
|
5
|
+
bundler (~> 1.3)
|
6
|
+
httparty (~> 0.11.0)
|
7
|
+
json (~> 1.7.7)
|
8
|
+
oauth2 (~> 0.9.2)
|
9
|
+
rake (~> 10.1.0)
|
10
|
+
thor (~> 0.18.1)
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
faraday (0.8.9)
|
16
|
+
multipart-post (~> 1.2.0)
|
17
|
+
httparty (0.11.0)
|
18
|
+
multi_json (~> 1.0)
|
19
|
+
multi_xml (>= 0.5.2)
|
20
|
+
httpauth (0.2.0)
|
21
|
+
json (1.7.7)
|
22
|
+
jwt (0.1.10)
|
23
|
+
multi_json (>= 1.5)
|
24
|
+
multi_json (1.8.4)
|
25
|
+
multi_xml (0.5.5)
|
26
|
+
multipart-post (1.2.0)
|
27
|
+
oauth2 (0.9.2)
|
28
|
+
faraday (~> 0.8)
|
29
|
+
httpauth (~> 0.2)
|
30
|
+
jwt (~> 0.1.4)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
multi_xml (~> 0.5)
|
33
|
+
rack (~> 1.2)
|
34
|
+
rack (1.5.2)
|
35
|
+
rake (10.1.1)
|
36
|
+
thor (0.18.1)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
c66!
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,111 +1,200 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Cloud 66 Toolbelt is a simple command-line tool for the awesome Cloud 66 customers. It allows you to deploy, modify settings and retrieve the current status of your Cloud 66 stacks, and much more!
|
1
|
+
<h1 class="doc-title">Cloud 66 Toolbelt</h1>
|
2
|
+
<p class="lead">Cloud 66 Toolbelt is a simple command-line tool for the awesome Cloud 66 customers. It allows you to deploy, modify settings and retrieve the current status of your Cloud 66 stacks, and much more!</p>
|
4
3
|
|
5
4
|
## Installation
|
6
5
|
|
7
6
|
You can install the Cloud 66 Toolbelt using [RubyGems](http://rubygems.org/):
|
7
|
+
<p>
|
8
|
+
<kbd>$ gem install c66</kbd>
|
9
|
+
</p>
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
## Usage
|
11
|
+
## Help
|
12
12
|
|
13
|
-
### Help
|
14
13
|
With c66 installed, you can display the help with one of the following instructions:
|
14
|
+
<p>
|
15
|
+
<kbd>$ c66 help</kbd>
|
16
|
+
</p>
|
17
|
+
|
18
|
+
or
|
15
19
|
|
16
|
-
|
20
|
+
<p>
|
21
|
+
<kbd>$ c66</kbd>
|
22
|
+
</p>
|
17
23
|
|
18
|
-
or
|
24
|
+
or for a specific command:
|
19
25
|
|
20
|
-
|
26
|
+
<p>
|
27
|
+
<kbd>$ c66 help <command></kbd>
|
28
|
+
</p>
|
21
29
|
|
22
|
-
|
30
|
+
## Initialize the Toolbelt
|
23
31
|
|
24
32
|
Firstly, to use the Toolbelt, you will need to initiate it using:
|
25
33
|
|
26
|
-
|
27
|
-
|
34
|
+
<p>
|
35
|
+
<kbd>$ c66 init</kbd>
|
36
|
+
</p>
|
37
|
+
|
28
38
|
Then visit the URL given once authorized, copy and paste the `authorization code` into the command-line interface.
|
29
|
-
|
30
39
|
You need to sign in and allow the Cloud 66 Toolbelt application to use your account to access to the authorization code.
|
31
40
|
|
32
|
-
Note
|
41
|
+
**Note**: This is a one-off task.
|
33
42
|
|
34
|
-
|
43
|
+
## List the Stacks
|
35
44
|
|
36
45
|
You can list all your stacks using:
|
37
46
|
|
38
|
-
|
47
|
+
<p>
|
48
|
+
<kbd>$ c66 list</kbd>
|
49
|
+
</p>
|
39
50
|
|
40
|
-
|
51
|
+
## Deploy a Stack
|
41
52
|
|
42
53
|
Deploy a stack using the command `deploy` with a stack UID (Unique Identifer):
|
43
54
|
|
44
|
-
|
45
|
-
|
55
|
+
<p>
|
56
|
+
<kbd>$ c66 deploy --stack <stack_UID></kbd>
|
57
|
+
</p>
|
58
|
+
|
46
59
|
or
|
47
60
|
|
48
|
-
|
49
|
-
|
61
|
+
<p>
|
62
|
+
<kbd>$ c66 deploy -s <stack_UID></kbd>
|
63
|
+
</p>
|
64
|
+
|
50
65
|
You can retrieve the UID of a stack using the `list` command.
|
51
|
-
|
52
66
|
Through the Cloud 66 interface, click on your stack, then click on the cog and select the stack information view to retrieve the UID:
|
53
|
-
|
54
67
|
![stack_uid](http://cdn.cloud66.com.s3.amazonaws.com/images/Toolbelt/exemple_stack_uid.PNG)
|
55
68
|
|
56
|
-
|
69
|
+
There is a command to save a default stack UID:
|
70
|
+
|
71
|
+
<p>
|
72
|
+
<kbd>$ c66 save --stack <stack_UID></kbd>
|
73
|
+
</p>
|
74
|
+
|
75
|
+
or
|
57
76
|
|
58
|
-
|
77
|
+
<p>
|
78
|
+
<kbd>$ c66 save -s <stack_UID></kbd>
|
79
|
+
</p>
|
59
80
|
|
81
|
+
**Note:** The stack is saved in your current folder (.cloud66/stack.json) and only one default stack will be saved per folder.
|
82
|
+
|
83
|
+
When your stack UID is saved, you are able to use other commands without specify the stack UID.
|
84
|
+
For instance, it allows you to deploy a stack without putting the stack UID every time:
|
85
|
+
|
86
|
+
<p>
|
87
|
+
<kbd>$ c66 deploy</kbd>
|
88
|
+
</p>
|
89
|
+
|
60
90
|
you can use a short-cut for this command:
|
61
91
|
|
62
|
-
|
92
|
+
<p>
|
93
|
+
<kbd>$ c66 d</kbd>
|
94
|
+
</p>
|
63
95
|
|
64
|
-
|
96
|
+
You can save multiple stack UID by giving an alias to a specific stack:
|
65
97
|
|
66
|
-
|
98
|
+
<p>
|
99
|
+
<kbd>$ c66 save --stack <stack_UID> --alias <stack_alias></kbd>
|
100
|
+
</p>
|
67
101
|
|
68
|
-
|
102
|
+
Then you can use commands and specific a stack's alias, like so:
|
69
103
|
|
70
|
-
|
104
|
+
<p>
|
105
|
+
<kbd>$ c66 deploy -s <stack_alias></kbd>
|
106
|
+
</p>
|
71
107
|
|
72
|
-
|
108
|
+
## Settings of a Stack
|
109
|
+
|
110
|
+
It is possible to retrieve the settings of a specified stack and to easily modify them:
|
73
111
|
|
74
|
-
|
112
|
+
To display the settings:
|
75
113
|
|
76
|
-
|
114
|
+
<p>
|
115
|
+
<kbd>$ c66 settings --stack <stack_UID></kbd>
|
116
|
+
</p>
|
117
|
+
|
118
|
+
or
|
77
119
|
|
78
|
-
|
120
|
+
<p>
|
121
|
+
<kbd>$ c66 settings -s <stack_UID></kbd>
|
122
|
+
</p>
|
123
|
+
|
124
|
+
If a default stack UID is saved:
|
79
125
|
|
126
|
+
<p>
|
127
|
+
<kbd>$ c66 settings</kbd>
|
128
|
+
</p>
|
129
|
+
|
80
130
|
To modify a setting:
|
81
131
|
|
82
|
-
|
132
|
+
<p>
|
133
|
+
<kbd>$ c66 set --stack <stack_UID> --setting_name <setting_name> --value <value></kbd>
|
134
|
+
</p>
|
135
|
+
|
136
|
+
or
|
137
|
+
|
138
|
+
<p>
|
139
|
+
<kbd>$ c66 set -s <stack_UID> -n <setting_name> -v <value></kbd>
|
140
|
+
</p>
|
141
|
+
|
142
|
+
If a default stack UID is saved:
|
83
143
|
|
144
|
+
<p>
|
145
|
+
<kbd>$ c66 set --setting_name <setting_name> --value <value></kbd>
|
146
|
+
</p>
|
147
|
+
|
84
148
|
or
|
85
149
|
|
86
|
-
|
150
|
+
<p>
|
151
|
+
<kbd>$ c66 set -n <setting_name> -v <value></kbd>
|
152
|
+
</p>
|
87
153
|
|
88
|
-
|
154
|
+
## Lease an IP address (version ≥ 0.1.91
|
89
155
|
|
90
|
-
|
156
|
+
You can allow an IP address to connect temporarily to the specific stack through ssh (22):
|
91
157
|
|
92
|
-
|
158
|
+
<p>
|
159
|
+
<kbd>$ c66 lease --stack <stack_UID> --ip-address <ip_address> --time-to-open <time_to_open></kbd>
|
160
|
+
</p>
|
93
161
|
|
94
|
-
|
162
|
+
or
|
95
163
|
|
164
|
+
<p>
|
165
|
+
<kbd>$ c66 lease -s <stack_UID> -i <ip_address> -t <time_to_open></kbd>
|
166
|
+
</p>
|
96
167
|
|
97
|
-
|
168
|
+
Options *ip-address* and *time-to-open* are optional.
|
169
|
+
By default:
|
98
170
|
|
99
|
-
|
171
|
+
- *ip-address* : your IP address
|
172
|
+
- *time-to-open* : 20 minutes
|
173
|
+
|
174
|
+
To allow your own IP address to connect temporarily to the specific stack:
|
100
175
|
|
101
|
-
|
176
|
+
<p>
|
177
|
+
<kbd>$ c66 lease --stack <stack_UID></kbd>
|
178
|
+
</p>
|
102
179
|
|
103
|
-
|
180
|
+
If a default stack UID is saved:
|
104
181
|
|
105
|
-
|
182
|
+
<p>
|
183
|
+
<kbd>$ c66 lease</kbd>
|
184
|
+
</p>
|
106
185
|
|
107
|
-
|
186
|
+
## Information of your toolbelt settings
|
108
187
|
|
109
|
-
|
188
|
+
At any time, you can see your toolbelt settings, it includes the version of the toolbelt but also some information about your saved stacks:
|
189
|
+
|
190
|
+
<p>
|
191
|
+
<kbd>$ c66 info</kbd>
|
192
|
+
</p>
|
110
193
|
|
111
|
-
|
194
|
+
## Contributing
|
195
|
+
|
196
|
+
1. Fork it
|
197
|
+
2. Create your feature branch `git checkout -b my-new-feature`
|
198
|
+
3. Commit your changes `git commit -am 'Add some feature'`
|
199
|
+
4. Push to the branch `git push origin my-new-feature`
|
200
|
+
5. Create new Pull Request
|
@@ -8,6 +8,7 @@ module C66
|
|
8
8
|
module Commands
|
9
9
|
|
10
10
|
CLIENT_NAME = 'c66'
|
11
|
+
CLIENT_FULLNAME = 'Cloud 66 Toolbelt'
|
11
12
|
|
12
13
|
STK_QUEUED = 0
|
13
14
|
STK_SUCCESS = 1
|
@@ -18,6 +19,8 @@ module C66
|
|
18
19
|
STK_DEPLOYING = 6
|
19
20
|
STK_TERMINAL_FAILURE = 7
|
20
21
|
|
22
|
+
FORBIDDEN_STACKS_ALIAS = ['params', 'toolbelt']
|
23
|
+
|
21
24
|
STATUS = {
|
22
25
|
STK_QUEUED => 'Pending analysis',
|
23
26
|
STK_SUCCESS => 'Deployed successfully',
|
@@ -30,16 +33,18 @@ module C66
|
|
30
33
|
}
|
31
34
|
|
32
35
|
VERSION_FILE = 'http://cdn.cloud66.com/config/cloud66_toolbelt.json'
|
33
|
-
BASE_URL = 'https://www.cloud66.com'
|
36
|
+
BASE_URL = ENV['C66_API_ENDPOINT'] || 'https://www.cloud66.com'
|
37
|
+
CLIENT_ID = ENV['C66_CLIENT_ID'] || '638412995ee3da6f67e24564ac297f9554ee253a8fe1502348c4d6e845bd9d0d'
|
38
|
+
CLIENT_SECRET = ENV['C66_CLIENT_SECRET'] || '961398353aa6e7f0f36dfcd83e447d748c54481b7a3b143e0119441516e8b91f'
|
34
39
|
|
35
40
|
class C66Toolbelt < Thor
|
36
41
|
no_commands {
|
37
42
|
def values
|
38
43
|
@values ||=
|
39
44
|
{ :base_url => "#{BASE_URL}/api/2",
|
40
|
-
:client_id =>
|
41
|
-
:client_secret =>
|
42
|
-
:scope => "public redeploy",
|
45
|
+
:client_id => CLIENT_ID,
|
46
|
+
:client_secret => CLIENT_SECRET,
|
47
|
+
:scope => "public redeploy admin users jobs",
|
43
48
|
:redirect_url => "urn:ietf:wg:oauth:2.0:oob",
|
44
49
|
:auth_url => "#{BASE_URL}/oauth/authorize",
|
45
50
|
:token_url => "#{BASE_URL}/oauth/token"
|
@@ -47,6 +52,7 @@ module C66
|
|
47
52
|
end
|
48
53
|
|
49
54
|
def base_url
|
55
|
+
load_params
|
50
56
|
values[:base_url]
|
51
57
|
end
|
52
58
|
|
@@ -74,8 +80,16 @@ module C66
|
|
74
80
|
File.join(c66_path, "params.json")
|
75
81
|
end
|
76
82
|
|
77
|
-
def stack_file
|
78
|
-
|
83
|
+
def stack_file(alias_name = nil)
|
84
|
+
if alias_name
|
85
|
+
if alias_name.match(/\w/)
|
86
|
+
File.join(stack_path, "#{alias_name}.json")
|
87
|
+
else
|
88
|
+
abort "#{alias_name} is an invalid alias."
|
89
|
+
end
|
90
|
+
else
|
91
|
+
File.join(stack_path, "stack.json")
|
92
|
+
end
|
79
93
|
end
|
80
94
|
|
81
95
|
def load_config
|
@@ -88,7 +102,7 @@ module C66
|
|
88
102
|
|
89
103
|
def save_config
|
90
104
|
if !File.directory?(c66_path)
|
91
|
-
Dir.
|
105
|
+
Dir.mkdir(c66_path)
|
92
106
|
end
|
93
107
|
|
94
108
|
File.open(config_file,"w") do |f|
|
@@ -96,28 +110,27 @@ module C66
|
|
96
110
|
end
|
97
111
|
end
|
98
112
|
|
99
|
-
def
|
100
|
-
if
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
113
|
+
def load_stack(alias_name)
|
114
|
+
if File.exists?(stack_file(alias_name))
|
115
|
+
if file = JSON.load(IO.read(stack_file(alias_name)))
|
116
|
+
if file.has_key? 'stack_id'
|
117
|
+
@stack = file['stack_id']
|
118
|
+
end
|
119
|
+
if file.has_key? 'stack_name' and !@stack.nil?
|
120
|
+
@stack_name = file['stack_name']
|
121
|
+
say "Stack #{@stack_name} loaded."
|
122
|
+
end
|
123
|
+
end
|
106
124
|
end
|
107
|
-
@stack = stack_id
|
108
|
-
say "Stack #{stack_id} saved to #{stack_file}"
|
109
125
|
end
|
110
126
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
else
|
119
|
-
say("No stack saved at #{stack_file}.")
|
120
|
-
end
|
127
|
+
def abort_no_stack
|
128
|
+
abort "No stack provided or saved, please use '--stack' or '-s' option. "\
|
129
|
+
"You can also use the 'save' method with '--stack' or '-s' option."
|
130
|
+
end
|
131
|
+
|
132
|
+
def abort_no_server
|
133
|
+
abort "Cannot find the given server name in the stack."
|
121
134
|
end
|
122
135
|
|
123
136
|
def load_params
|
@@ -130,25 +143,40 @@ module C66
|
|
130
143
|
if @params.has_key? 'base_url'
|
131
144
|
values[:base_url] = @params['base_url']
|
132
145
|
else
|
133
|
-
abort "Missing 'base_url' parameter in #{params_file}"
|
146
|
+
abort "Missing 'base_url' parameter in #{params_file}"
|
134
147
|
end
|
135
148
|
if @params.has_key? 'client_id'
|
136
149
|
values[:client_id] = @params['client_id']
|
137
150
|
else
|
138
|
-
abort "Missing 'client_id' parameter in #{params_file}"
|
151
|
+
abort "Missing 'client_id' parameter in #{params_file}"
|
139
152
|
end
|
140
153
|
if @params.has_key? 'client_secret'
|
141
154
|
values[:client_secret] = @params['client_secret']
|
142
155
|
else
|
143
|
-
abort "Missing 'client_secret' parameter in #{params_file}"
|
156
|
+
abort "Missing 'client_secret' parameter in #{params_file}"
|
144
157
|
end
|
145
|
-
say "Parameters loaded."
|
158
|
+
#say "Parameters loaded."
|
146
159
|
end
|
147
160
|
end
|
148
161
|
|
149
|
-
def get_stack(
|
150
|
-
|
151
|
-
|
162
|
+
def get_stack(stack_id_or_alias_name)
|
163
|
+
if stack_id_or_alias_name && !File.exist?(stack_file(stack_id_or_alias_name))
|
164
|
+
@stack=stack_id_or_alias_name
|
165
|
+
else
|
166
|
+
load_stack(stack_id_or_alias_name)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def get_server_by_name(stack_id_or_alias_name, server_name)
|
171
|
+
get_stack(stack_id_or_alias_name)
|
172
|
+
|
173
|
+
# get stack servers
|
174
|
+
response = token.get("#{base_url}/stacks/#{@stack}/servers.json")
|
175
|
+
servers = parse_response(response)['response']
|
176
|
+
server = servers.select { |s| s['name'].downcase == server_name.downcase }
|
177
|
+
|
178
|
+
return nil if server.empty?
|
179
|
+
return server.first
|
152
180
|
end
|
153
181
|
|
154
182
|
def client
|
@@ -173,33 +201,60 @@ module C66
|
|
173
201
|
end
|
174
202
|
end
|
175
203
|
|
176
|
-
def
|
204
|
+
def error_message(error)
|
205
|
+
begin
|
206
|
+
if !error.response.parsed.nil?
|
207
|
+
if (error.response.parsed.has_key? 'details')
|
208
|
+
say error.response.parsed['details']
|
209
|
+
else
|
210
|
+
say error.response.parsed['error_description']
|
211
|
+
end
|
212
|
+
end
|
213
|
+
rescue => e
|
214
|
+
abort e.message
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def get_version
|
177
219
|
begin
|
178
|
-
JSON.load(HTTParty.get(VERSION_FILE)).fetch("version")
|
220
|
+
JSON.load(HTTParty.get(VERSION_FILE).response.body).fetch("version")
|
179
221
|
rescue => e
|
180
|
-
|
222
|
+
say "Failed to retrieve the latest version of Cloud 66 Toolbelt, please contact us"
|
181
223
|
end
|
182
224
|
end
|
183
225
|
|
184
|
-
|
185
|
-
|
186
|
-
|
226
|
+
def display_info
|
227
|
+
say "#{CLIENT_FULLNAME} version #{C66::Utils::VERSION}\n\n"
|
228
|
+
end
|
229
|
+
|
230
|
+
def compare_versions
|
231
|
+
result = C66::Utils::VERSION <=> Gem::Version.new(get_version)
|
187
232
|
case result
|
188
233
|
when 0..1
|
189
|
-
|
190
|
-
|
191
|
-
|
234
|
+
#say "Version is up-to-date."
|
235
|
+
when -1
|
236
|
+
say "There is a new version of Cloud66 Toolbelt. Pease run \"gem update #{CLIENT_NAME}\".",:red
|
192
237
|
end
|
193
|
-
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def before_each_action
|
241
|
+
compare_versions
|
242
|
+
# pending_intercom_messages
|
243
|
+
end
|
194
244
|
}
|
195
245
|
|
196
|
-
package_name "
|
197
|
-
|
198
|
-
|
246
|
+
package_name "#{CLIENT_FULLNAME}: version #{C66::Utils::VERSION}\n"
|
247
|
+
|
248
|
+
default_task :default
|
199
249
|
|
200
|
-
|
201
|
-
|
250
|
+
desc "default", "hidden method", :hide => true
|
251
|
+
def default
|
252
|
+
before_each_action
|
253
|
+
help
|
254
|
+
end
|
202
255
|
|
256
|
+
desc "init", "Initialize the toolbelt"
|
257
|
+
map "d" => :deploy
|
203
258
|
long_desc <<-LONGDESC
|
204
259
|
Initialize Cloud 66 toolbelt
|
205
260
|
LONGDESC
|
@@ -226,63 +281,265 @@ module C66
|
|
226
281
|
|
227
282
|
desc "list", "Lists all the stacks"
|
228
283
|
def list
|
229
|
-
|
284
|
+
before_each_action
|
285
|
+
begin
|
286
|
+
response = parse_response(token.get("#{base_url}/stacks.json"))
|
230
287
|
|
231
|
-
|
232
|
-
|
233
|
-
|
288
|
+
if response['count'] != 0
|
289
|
+
response['response'].each do |stack|
|
290
|
+
say "#{stack['name']} (#{stack['uid']}) : #{stack['environment']} - #{STATUS[stack['status']]}"
|
291
|
+
end
|
292
|
+
else
|
293
|
+
say "No stacks found"
|
234
294
|
end
|
235
|
-
|
236
|
-
|
295
|
+
rescue OAuth2::Error => e
|
296
|
+
error_message(e)
|
237
297
|
end
|
238
298
|
end
|
239
299
|
|
240
300
|
desc "settings", "Get the list of settings for this stack"
|
241
301
|
option :stack, :aliases => "-s", :required => false
|
242
|
-
def settings
|
302
|
+
def settings
|
303
|
+
before_each_action
|
243
304
|
begin
|
244
305
|
get_stack(options[:stack])
|
245
|
-
|
306
|
+
abort_no_stack if @stack.nil?
|
246
307
|
response = token.get("#{base_url}/stacks/#{@stack}/settings.json")
|
247
308
|
settings = JSON.parse(response.body)['response']
|
309
|
+
number_settings = JSON.parse(response.body)['count']
|
310
|
+
stack_details = parse_response(token.get("#{base_url}/stacks/#{@stack}.json"))
|
311
|
+
stack_name = stack_details['response']['name']
|
248
312
|
|
249
313
|
abort "No settings found" if settings.nil?
|
250
|
-
|
314
|
+
say "Getting #{stack_name} settings:"
|
251
315
|
settings.each do |setting|
|
252
|
-
say "#{setting['key']}\t\t#{setting['value']}\t#{setting['readonly'] ? '(readonly)' : ''}\r\n"
|
316
|
+
say "#{setting['key'].ljust(20)}\t\t#{setting['value']}\t#{setting['readonly'] ? '(readonly)' : ''}\r\n"
|
253
317
|
end
|
254
318
|
rescue OAuth2::Error => e
|
255
|
-
|
319
|
+
error_message(e)
|
256
320
|
end
|
257
321
|
end
|
258
322
|
|
323
|
+
desc "ssh", "Start a SSH shell terminal with the given server"
|
324
|
+
option :stack, :aliases => "-s", :required => false
|
325
|
+
option :server_name, :aliases => "-n", :required => true
|
326
|
+
def ssh
|
327
|
+
before_each_action
|
328
|
+
begin
|
329
|
+
get_stack(options[:stack])
|
330
|
+
abort_no_stack if @stack.nil?
|
331
|
+
server = get_server_by_name(options[:stack], options[:server_name])
|
332
|
+
abort_no_server if server.nil?
|
333
|
+
say "Found server #{server['uid']} with name #{options[:server_name]}"
|
334
|
+
|
335
|
+
# get the SSH key
|
336
|
+
say "Requesting the SSH keys"
|
337
|
+
response = token.get("#{base_url}/servers/#{server['uid']}/ssh_private_key.json")
|
338
|
+
prv_key = parse_response(response)['response']['private_key']
|
339
|
+
|
340
|
+
say "Opening firewall temporarily for this IP address"
|
341
|
+
lease
|
342
|
+
|
343
|
+
path = File.join(Dir.home, '.ssh', "server_#{server['name'].downcase}")
|
344
|
+
|
345
|
+
# save it to user directory
|
346
|
+
File.open(path, 'w') do |file|
|
347
|
+
file.write(prv_key)
|
348
|
+
file.chmod(0600)
|
349
|
+
end
|
350
|
+
|
351
|
+
# let's do it
|
352
|
+
say "ssh '#{server['user_name']}'@'#{server['address']}' -i '#{path}'"
|
353
|
+
system "ssh '#{server['user_name']}'@'#{server['address']}' -i '#{path}'"
|
354
|
+
rescue OAuth2::Error => e
|
355
|
+
error_message(e)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
259
359
|
desc "set", "Set the value of a specific setting"
|
260
360
|
option :stack, :aliases => "-s", :required => false
|
261
361
|
option :setting_name, :aliases => "-n", :required => true
|
262
362
|
option :value, :aliases => "-v", :required => true
|
263
363
|
def set()
|
364
|
+
before_each_action
|
264
365
|
begin
|
265
366
|
get_stack(options[:stack])
|
266
|
-
|
367
|
+
abort_no_stack if @stack.nil?
|
368
|
+
stack_details = parse_response(token.get("#{base_url}/stacks/#{@stack}.json"))
|
369
|
+
stack_name = stack_details['response']['name']
|
267
370
|
response = token.post("#{base_url}/stacks/#{@stack}/setting.json", { :body => { :setting_name => options[:setting_name], :setting_value => options[:value] }})
|
268
|
-
say "
|
371
|
+
say "On #{stack_name}: applied value '#{options[:value]}' to setting '#{options[:setting_name]}'" if JSON.parse(response.body)['response']['ok']
|
269
372
|
rescue OAuth2::Error => e
|
270
|
-
|
373
|
+
error_message(e)
|
271
374
|
end
|
272
375
|
end
|
273
376
|
|
274
377
|
desc "deploy", "Deploy the given stack"
|
275
378
|
option :stack, :aliases => "-s", :required => false
|
276
|
-
def deploy
|
379
|
+
def deploy
|
380
|
+
before_each_action
|
277
381
|
begin
|
278
382
|
get_stack(options[:stack])
|
279
|
-
|
383
|
+
abort_no_stack if @stack.nil?
|
384
|
+
stack_details = parse_response(token.get("#{base_url}/stacks/#{@stack}.json"))
|
385
|
+
stack_name = stack_details['response']['name']
|
386
|
+
say stack_name+": "
|
280
387
|
response = token.post("#{base_url}/stacks/#{@stack}/redeploy.json", {})
|
281
388
|
say JSON.parse(response.body)['response']['message']
|
282
389
|
rescue OAuth2::Error => e
|
283
|
-
|
390
|
+
error_message(e)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
desc "restart", "Restart the given stack"
|
395
|
+
option :stack, :aliases => "-s", :required => false
|
396
|
+
option :target, :aliases => "-t", :required => false
|
397
|
+
def restart
|
398
|
+
before_each_action
|
399
|
+
begin
|
400
|
+
get_stack(options[:stack])
|
401
|
+
abort_no_stack if @stack.nil?
|
402
|
+
|
403
|
+
target_option = options[:target]
|
404
|
+
target = target_option.nil? ? 'web' : target_option.to_s
|
405
|
+
abort "Only 'web' target is currently supported" unless target == 'web'
|
406
|
+
|
407
|
+
stack_details = parse_response(token.get("#{base_url}/stacks/#{@stack}.json"))
|
408
|
+
stack_name = stack_details['response']['name']
|
409
|
+
say stack_name+": "
|
410
|
+
response = token.post("#{base_url}/stacks/#{@stack}/restart.json", {})
|
411
|
+
say JSON.parse(response.body)['response']['message']
|
412
|
+
|
413
|
+
rescue OAuth2::Error => e
|
414
|
+
error_message(e)
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
desc "save", "Save the given stack information in the current directory"
|
419
|
+
option :stack, :aliases => "-s", :required => true
|
420
|
+
option :alias, :aliases => "-a", :required => false
|
421
|
+
def save
|
422
|
+
before_each_action
|
423
|
+
begin
|
424
|
+
stack_details = parse_response(token.get("#{base_url}/stacks/#{options[:stack]}.json"))
|
425
|
+
stack_name = stack_details['response']['name']
|
426
|
+
if !File.directory?(stack_path)
|
427
|
+
Dir.mkdir(stack_path)
|
428
|
+
end
|
429
|
+
@stack_json = { :stack_id => options[:stack], :stack_name => stack_name}
|
430
|
+
if (!FORBIDDEN_STACKS_ALIAS.include? options[:alias])
|
431
|
+
File.open(stack_file(options[:alias]),"w") do |f|
|
432
|
+
f.write(@stack_json.to_json)
|
433
|
+
end
|
434
|
+
else
|
435
|
+
abort 'Stack alias "'+options[:alias]+'" is forbidden, please retry with another alias.'
|
436
|
+
end
|
437
|
+
@stack = options[:stack]
|
438
|
+
|
439
|
+
say "Linked stack #{stack_name} to #{stack_file(options[:alias])}.\n"
|
440
|
+
if !options[:alias]
|
441
|
+
say "You are now able to use other commands without specify the stack UID."
|
442
|
+
else
|
443
|
+
say "You are now able to use other commands and specific this stack's alias, like so: "\
|
444
|
+
"`c66 deploy -s #{options[:alias]}`"
|
445
|
+
end
|
446
|
+
rescue OAuth2::Error => e
|
447
|
+
error_message(e)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
desc "info", "#{CLIENT_FULLNAME} information"
|
452
|
+
def info
|
453
|
+
before_each_action
|
454
|
+
begin
|
455
|
+
say "#{CLIENT_FULLNAME} version #{C66::Utils::VERSION}\n\n"
|
456
|
+
Dir.glob("#{stack_path}/*.json") do |stack_file|
|
457
|
+
stack_alias = File.basename(stack_file, ".json")
|
458
|
+
if (!FORBIDDEN_STACKS_ALIAS.include? stack_alias)
|
459
|
+
load_stack(stack_alias)
|
460
|
+
if stack_alias == "stack"
|
461
|
+
say "Default stack: no alias"
|
462
|
+
else
|
463
|
+
say "Alias: #{stack_alias}"
|
464
|
+
end
|
465
|
+
stack_details = parse_response(token.get("#{base_url}/stacks/#{@stack}.json"))
|
466
|
+
say "Name: #{stack_details['response']['name']}"
|
467
|
+
say "UID: #{stack_details['response']['uid']}"
|
468
|
+
say "Environment: #{stack_details['response']['environment']}"
|
469
|
+
say "Status: #{STATUS[stack_details['response']['status']]}\n\n"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
rescue OAuth2::Error => e
|
473
|
+
puts "Didn't find any valid stacks, please use the 'save' method."
|
474
|
+
error_message(e)
|
284
475
|
end
|
285
476
|
end
|
477
|
+
|
478
|
+
desc "lease", "Allow an IP address to connect temporarily to the specified stack through the specified port - the default port is ssh (22)"
|
479
|
+
option :stack, :aliases => "-s", :required => false
|
480
|
+
option :ip_address, :aliases => "-i", :required => false
|
481
|
+
option :time_to_open, :aliases => "-t", :required => false, :default => 20
|
482
|
+
option :port, :aliases => "-p", :required => false, :default => 22
|
483
|
+
option :show_ip, :aliases => "-a", :required => false
|
484
|
+
def lease()
|
485
|
+
before_each_action
|
486
|
+
begin
|
487
|
+
abort "time_to_open value is invalid. The value must be an integer between 0 and 240 (~4 hours)." unless (0..240).include?(options[:time_to_open].to_i)
|
488
|
+
port = options.fetch(:port) { 22 }
|
489
|
+
abort "port value is invalid. The value must be a valid port." unless port.to_i > 0
|
490
|
+
get_stack(options[:stack])
|
491
|
+
abort_no_stack if @stack.nil?
|
492
|
+
response = token.post("#{base_url}/stacks/#{@stack}/lease.json", { :body => { :ip_address => options[:ip_address], :time_to_open => options[:time_to_open], :port => port }})
|
493
|
+
say JSON.parse(response.body)['response']['message'] if JSON.parse(response.body)['response']['ok']
|
494
|
+
|
495
|
+
if options[:show_ip]
|
496
|
+
server_groups = token.get("#{base_url}/stacks/#{@stack}/server_groups.json")
|
497
|
+
rails_server_group = JSON.parse(server_groups.body)['response'].find { |sg| sg['name'] == 'Rails Server' }
|
498
|
+
servers = token.get("#{base_url}/stacks/#{@stack}/server_groups/#{rails_server_group['id']}/servers.json")
|
499
|
+
server_ip_address = JSON.parse(servers.body)['response'][0]['address']
|
500
|
+
say "For reference, here's the IP address for your first Rails server: #{server_ip_address}"
|
501
|
+
end
|
502
|
+
rescue OAuth2::Error => e
|
503
|
+
error_message(e)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
desc "download_backup","Download a backup"
|
508
|
+
option :backup_id, :aliases => "-b", :required => true
|
509
|
+
def download_backup()
|
510
|
+
before_each_action
|
511
|
+
begin
|
512
|
+
next_extension = nil
|
513
|
+
downloaded_files = []
|
514
|
+
begin
|
515
|
+
response = parse_response(token.get("#{base_url}/backups/#{options[:backup_id]}/export/#{next_extension.nil? ? '' : next_extension }"))
|
516
|
+
file_name = response['response']['file_name']
|
517
|
+
unless file_name.nil?
|
518
|
+
File.open(file_name, "wb") do |f|
|
519
|
+
f.write HTTParty.get(response['response']['url']).parsed_response
|
520
|
+
end
|
521
|
+
downloaded_files << file_name
|
522
|
+
end
|
523
|
+
next_extension = response['response']['next_extension']
|
524
|
+
end while (!next_extension.nil?)
|
525
|
+
|
526
|
+
if downloaded_files.size > 0
|
527
|
+
if downloaded_files.size > 1
|
528
|
+
File.open("#{options[:backup_id]}.tar", "wb") do |output_f|
|
529
|
+
downloaded_files.sort.each {|f| output_f.write(File.open(f, 'r').read)}
|
530
|
+
end
|
531
|
+
downloaded_files.each {|f| File.delete f }
|
532
|
+
else
|
533
|
+
File.rename downloaded_files.first, "#{options[:backup_id]}.tar"
|
534
|
+
end
|
535
|
+
say "Your backup is downloaded : #{options[:backup_id]}.tar"
|
536
|
+
else
|
537
|
+
say "There is no file associated to #{options[:backup_id]}"
|
538
|
+
end
|
539
|
+
rescue OAuth2::Error => e
|
540
|
+
error_message(e)
|
541
|
+
end
|
542
|
+
end
|
286
543
|
end
|
287
544
|
end
|
288
545
|
end
|
data/lib/c66/utils/version.rb
CHANGED
metadata
CHANGED
@@ -1,96 +1,114 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: c66
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.96
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Cloud 66
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-01-16 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '1.3'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
25
27
|
- !ruby/object:Gem::Dependency
|
26
28
|
name: rake
|
27
|
-
requirement:
|
28
|
-
none: false
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
31
|
- - ~>
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: 10.1.0
|
33
34
|
type: :runtime
|
34
35
|
prerelease: false
|
35
|
-
version_requirements:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 10.1.0
|
36
41
|
- !ruby/object:Gem::Dependency
|
37
42
|
name: thor
|
38
|
-
requirement:
|
39
|
-
none: false
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
40
44
|
requirements:
|
41
45
|
- - ~>
|
42
46
|
- !ruby/object:Gem::Version
|
43
47
|
version: 0.18.1
|
44
48
|
type: :runtime
|
45
49
|
prerelease: false
|
46
|
-
version_requirements:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.18.1
|
47
55
|
- !ruby/object:Gem::Dependency
|
48
56
|
name: oauth2
|
49
|
-
requirement:
|
50
|
-
none: false
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
51
58
|
requirements:
|
52
59
|
- - ~>
|
53
60
|
- !ruby/object:Gem::Version
|
54
61
|
version: 0.9.2
|
55
62
|
type: :runtime
|
56
63
|
prerelease: false
|
57
|
-
version_requirements:
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.9.2
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: json
|
60
|
-
requirement:
|
61
|
-
none: false
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
62
72
|
requirements:
|
63
73
|
- - ~>
|
64
74
|
- !ruby/object:Gem::Version
|
65
75
|
version: 1.7.7
|
66
76
|
type: :runtime
|
67
77
|
prerelease: false
|
68
|
-
version_requirements:
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.7.7
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: httparty
|
71
|
-
requirement:
|
72
|
-
none: false
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
73
86
|
requirements:
|
74
87
|
- - ~>
|
75
88
|
- !ruby/object:Gem::Version
|
76
89
|
version: 0.11.0
|
77
90
|
type: :runtime
|
78
91
|
prerelease: false
|
79
|
-
version_requirements:
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.11.0
|
80
97
|
description: See https://www.cloud66.com for more info
|
81
98
|
email:
|
82
99
|
- hello@cloud66.com
|
83
100
|
executables:
|
84
|
-
- c66
|
101
|
+
- c66
|
85
102
|
extensions: []
|
86
103
|
extra_rdoc_files: []
|
87
104
|
files:
|
88
105
|
- .gitignore
|
89
106
|
- Gemfile
|
107
|
+
- Gemfile.lock
|
90
108
|
- LICENSE.txt
|
91
109
|
- README.md
|
92
110
|
- Rakefile
|
93
|
-
- bin/c66
|
111
|
+
- bin/c66
|
94
112
|
- c66.gemspec
|
95
113
|
- lib/c66.rb
|
96
114
|
- lib/c66/commands/c66_toolbelt.rb
|
@@ -98,26 +116,25 @@ files:
|
|
98
116
|
homepage: https://www.cloud66.com
|
99
117
|
licenses:
|
100
118
|
- MIT
|
119
|
+
metadata: {}
|
101
120
|
post_install_message:
|
102
121
|
rdoc_options: []
|
103
122
|
require_paths:
|
104
123
|
- lib
|
105
124
|
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
125
|
requirements:
|
108
126
|
- - ! '>='
|
109
127
|
- !ruby/object:Gem::Version
|
110
128
|
version: '0'
|
111
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
-
none: false
|
113
130
|
requirements:
|
114
131
|
- - ! '>='
|
115
132
|
- !ruby/object:Gem::Version
|
116
133
|
version: '0'
|
117
134
|
requirements: []
|
118
135
|
rubyforge_project:
|
119
|
-
rubygems_version: 1.
|
136
|
+
rubygems_version: 2.1.11
|
120
137
|
signing_key:
|
121
|
-
specification_version:
|
138
|
+
specification_version: 4
|
122
139
|
summary: Cloud 66 Toolbelt
|
123
140
|
test_files: []
|
/data/bin/{c66.rb → c66}
RENAMED
File without changes
|