vpsmatrix 0.1.8 → 0.1.9
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.
- checksums.yaml +4 -4
- data/lib/vpsmatrix.rb +2 -0
- data/lib/vpsmatrix/config.rb +4 -5
- data/lib/vpsmatrix/helpers.rb +109 -0
- data/lib/vpsmatrix/starter.rb +137 -92
- data/lib/vpsmatrix/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54867d7225856e252da6399526ba5b786654ffbc
|
4
|
+
data.tar.gz: d414d15e0e2e1355c31bd1f4ff076a3a466c3e53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c23a6ae2568b00297addaa9f87fb865c7eadf0655c3fb65796b367b54f95d0887b108f6c779f5fdc6c10792d6865f5493ea5593c3be95c0e101a4c2f4f1d513d
|
7
|
+
data.tar.gz: 0ab2a5ff899c097f6c0a9c8435e5ab709afd9eac946d9bd1ddacba53d806e1d5477037a5d76c3030b461b7d9ca9b37e7b3e8d6fe8c54557f8865e9dcf80ea131
|
data/lib/vpsmatrix.rb
CHANGED
data/lib/vpsmatrix/config.rb
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
|
3
|
-
class
|
4
|
-
|
5
|
-
|
6
|
-
@file_path = "
|
3
|
+
class Conf
|
4
|
+
def initialize(home=nil)
|
5
|
+
@file_path = ".vpsx.yml"
|
6
|
+
@file_path = "#{ENV['HOME']}/.vpsx.yml" if home
|
7
7
|
unless File.exists? @file_path
|
8
|
-
Dir.mkdir "config" unless Dir.exists? "config"
|
9
8
|
File.open(@file_path, 'w') do |file|
|
10
9
|
file.write "comment: 'Config file for VPS Matrix services'"
|
11
10
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Helpers
|
2
|
+
# simple prompt with defined text
|
3
|
+
# return user's input
|
4
|
+
def prompt(default, *args)
|
5
|
+
print(*args)
|
6
|
+
result = gets.strip.gsub("\n", '')
|
7
|
+
return result.empty? ? default : result
|
8
|
+
end
|
9
|
+
|
10
|
+
# create put request, ssl and api_key optional
|
11
|
+
def send_put_request endpoint, params={}, api_key=nil, ssl=false
|
12
|
+
uri = URI.parse(endpoint)
|
13
|
+
|
14
|
+
Net::HTTP.start(uri.host, uri.port) do |http|
|
15
|
+
http.use_ssl = true if ssl
|
16
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
17
|
+
request['authorization'] = "Token token=#{api_key}" if api_key
|
18
|
+
request.set_form_data(params)
|
19
|
+
http.request request
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# create get request, ssl and api_key optional
|
24
|
+
def send_get_request endpoint, params={}, api_key=nil, ssl=false #https://api.vpsmatrix.net/uploads/get_file_list
|
25
|
+
uri = URI.parse(endpoint)
|
26
|
+
uri.query = URI.encode_www_form(params)
|
27
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
28
|
+
http.use_ssl = true if ssl
|
29
|
+
req = Net::HTTP::Get.new(uri.path)
|
30
|
+
req['authorization'] = "Token token=#{api_key}" if api_key
|
31
|
+
http.request(req)
|
32
|
+
end
|
33
|
+
|
34
|
+
# user can choose which VPS to use or create new one (get one from pool of prepared VPS)
|
35
|
+
def resolve_vps api_key
|
36
|
+
res = send_get_request "#{Vpsmatrix::API_TEST_SERVER}/vps/list_available", {}, api_key
|
37
|
+
|
38
|
+
if res.code == "200"
|
39
|
+
vps_list = JSON.parse res.body
|
40
|
+
vps_string = vps_list.map {|vps| "#{vps["id"]}: #{vps["hostname"]} at #{vps["ip"]}"}
|
41
|
+
vps_id = prompt nil, vps_string.join("\n") + "\n"
|
42
|
+
chosen_vps = vps_list.select {|vps| vps["id"].to_s == vps_id}.first
|
43
|
+
if chosen_vps.empty?
|
44
|
+
puts "No such vps exists. Use existing id please." # TODO let's user continue somehow (run prompt again?)
|
45
|
+
abort
|
46
|
+
else
|
47
|
+
# TODO is there more efficient way how to write to YML file? This just opens and closes file again and again. Maybe open it at beginning?
|
48
|
+
@app_config.write("host", chosen_vps["ip"])
|
49
|
+
@app_config.write("host_id", chosen_vps["id"])
|
50
|
+
end
|
51
|
+
#puts chosen_vps["hostname"]
|
52
|
+
else
|
53
|
+
puts "Check your api_key in ~/.vpsx.yml; call support"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# user may choose how to get files to VPS (git or directory upload)
|
58
|
+
def resolve_upload_strategy
|
59
|
+
# TODO add possibility to choose which remote to use
|
60
|
+
upload_strategy = prompt("1", "How you want to upload files? \n1: Git (origin remote will be used)\n2: Copy all files in folder [NOT IMPLEMENTED]\n")
|
61
|
+
if upload_strategy == "1"
|
62
|
+
puts "You have no git repository." && abort unless Dir.exist?(".git")
|
63
|
+
remote = `git remote get-url origin`.gsub("\n", '')
|
64
|
+
@app_config.write("upload_strategy", "git")
|
65
|
+
@app_config.write("git_url", remote)
|
66
|
+
puts "#{remote} will be used."
|
67
|
+
elsif upload_strategy == "2"
|
68
|
+
@app_config.write("upload_strategy", "stream")
|
69
|
+
puts "All files in this directory will be streamed to server."
|
70
|
+
else
|
71
|
+
puts "You chose invalid option!" && abort
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# choose which database will be used and where (same VPS, remote VPS, remote service)
|
76
|
+
def resolve_database
|
77
|
+
# let user choose where database is
|
78
|
+
## mysql is installed with root user without pass
|
79
|
+
# TODO add more database types as well 'postgres'
|
80
|
+
database = prompt("1", "Where database should be stored? \n1: Same VPS\n Other options not available now\n")
|
81
|
+
if database == "1"
|
82
|
+
@app_config.write("database", "current_vps")
|
83
|
+
else
|
84
|
+
puts "You chose invalid option!" && abort
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# choose domain which will be added to nginx
|
89
|
+
def resolve_domain
|
90
|
+
domain = prompt("example.com", "Add domain where app will run (will be used in nginx configuration)\n")
|
91
|
+
@app_config.write("domain", domain)
|
92
|
+
end
|
93
|
+
|
94
|
+
# will create user with app name on VPS; generate ssh key for him and possibly upload your pub key.
|
95
|
+
def create_app_user api_key
|
96
|
+
upload_ssh_key = prompt("Y", "Do you want to upload your public ssh key to app user on VPS? (Y/n)\n")
|
97
|
+
# TODO consider situation when there is no pub key
|
98
|
+
pub_ssh = upload_ssh_key == "Y" ? File.read("#{ENV['HOME']}/.ssh/id_rsa.pub") : ""
|
99
|
+
|
100
|
+
options = @app_config.content.merge({ssh_key: pub_ssh})
|
101
|
+
result = send_put_request "#{Vpsmatrix::API_TEST_SERVER}/vps/create_new_user", options, api_key
|
102
|
+
if result.code == "200"
|
103
|
+
result.body
|
104
|
+
else
|
105
|
+
puts "Check your api_key in ~/.vpsx.yml; call support" && abort
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/lib/vpsmatrix/starter.rb
CHANGED
@@ -1,65 +1,157 @@
|
|
1
1
|
require 'digest'
|
2
2
|
require 'net/http'
|
3
3
|
require 'uri'
|
4
|
+
require 'json'
|
4
5
|
require 'securerandom'
|
5
6
|
require_relative 'config'
|
6
7
|
require_relative 'upload_progress'
|
7
8
|
|
9
|
+
require_relative 'helpers'
|
10
|
+
include Helpers
|
11
|
+
|
8
12
|
class Starter
|
9
13
|
|
10
14
|
|
15
|
+
|
11
16
|
def self.start args
|
17
|
+
if ARGV[0]=~/^-/
|
18
|
+
switches = ARGV.shift
|
19
|
+
if switches == '-hv' || switches == '-vh'
|
20
|
+
puts "vpsx #{Vpsmatrix::VERSION}"
|
21
|
+
usage
|
22
|
+
elsif
|
23
|
+
switches == '-v'
|
24
|
+
puts "vpsx #{Vpsmatrix::VERSION}"
|
25
|
+
exit
|
26
|
+
else
|
27
|
+
usage
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
12
31
|
@environment = args.shift
|
13
32
|
@action = args.shift
|
14
33
|
|
15
|
-
environments = %w{demo prod}
|
16
|
-
fail "\nUnknown environment. Available environments: #{environments.join(', ')}" unless environments.include?(@environment)
|
17
|
-
actions = %w{deploy}
|
18
|
-
fail "\nUknown action. Available actions: #{actions.join(', ')}" unless actions.include?(@action)
|
19
|
-
|
34
|
+
#environments = %w{demo prod}
|
35
|
+
#fail "\nUnknown environment. Available environments: #{environments.join(', ')}" unless environments.include?(@environment)
|
36
|
+
#actions = %w{deploy init}
|
37
|
+
#fail "\nUknown action. Available actions: #{actions.join(', ')}" unless actions.include?(@action)
|
38
|
+
case @action
|
39
|
+
when "deploy"
|
40
|
+
Starter.new.send("#{@environment}_#{@action}")
|
41
|
+
when "config"
|
42
|
+
Starter.new.send(@action)
|
43
|
+
else
|
44
|
+
usage
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Login user; create if not existing; add api_key to ~/.vpsx.yml for future use
|
50
|
+
def login
|
51
|
+
# check ~/.vpsx.yml for api key
|
52
|
+
@config = Conf.new("home")
|
53
|
+
return @config.content['api_key'] if Conf.new("home").content['api_key']
|
54
|
+
|
55
|
+
puts "Getting api key"
|
56
|
+
email = prompt(nil, "Insert email: ")
|
57
|
+
p email
|
58
|
+
password = prompt(nil, "Insert password (provide new if new user): ")
|
59
|
+
res = send_put_request "#{API_TEST_SERVER}/login", {email: email, password: password}
|
60
|
+
json = JSON.parse(res.body)
|
61
|
+
case
|
62
|
+
when json["result"] == "ok"
|
63
|
+
# save api_key to ~/.vpsx.yml
|
64
|
+
puts json["api_key"]
|
65
|
+
@config.write 'api_key', json["api_key"]
|
66
|
+
@config.content['api_key']
|
67
|
+
when json["result"] == "new_account"
|
68
|
+
puts "Confirm your e-mail and run this script again"
|
69
|
+
# TODO find way how to get back after user confirmed mail (run login again?)
|
70
|
+
abort
|
71
|
+
else
|
72
|
+
puts "There is something very bad, call help."
|
73
|
+
abort
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Configure how app is
|
78
|
+
def config
|
79
|
+
@app_config = Conf.new
|
80
|
+
api_key = login
|
81
|
+
|
82
|
+
resolve_vps(api_key)
|
83
|
+
resolve_upload_strategy
|
84
|
+
|
85
|
+
app_name = `pwd`.split("/").last.gsub("\n", "")
|
86
|
+
@app_config.write("app_name", app_name)
|
87
|
+
## create service user
|
88
|
+
# API will check existing "service" user in VPS -> for communication between user's VPSs
|
89
|
+
# if not it will be created with ssh keys -> these keys will be saved to ~/.vpsx.yml (used for all other VPS)
|
90
|
+
# take private ssh key from existing server
|
91
|
+
|
92
|
+
# TODO check if user exists
|
93
|
+
ssh_key_for_git = create_app_user(api_key)
|
94
|
+
puts ssh_key_for_git
|
95
|
+
|
96
|
+
resolve_database
|
97
|
+
resolve_domain
|
98
|
+
|
99
|
+
## TODO solve this
|
100
|
+
## ask user for any ENV variables he may need? Like mailgun? mail server? redis? anything else?
|
101
|
+
# pass ENV variables to set settings of projects
|
20
102
|
end
|
21
103
|
|
22
|
-
#desc 'demo deploy', 'run demo deploy to deploy app to VPS Matrix demo server'
|
23
104
|
def prod_deploy
|
24
|
-
|
105
|
+
# TODO should be more sofisticated -> now in case of problems during .vpsx.yml creation there is no possibility to go back to questionnaire
|
106
|
+
# TODO do some checks of validity of .vpsx.yml !!!
|
107
|
+
return puts("There is no config file. Run vpsx config first.") && abort unless File.exist?(".vpsx.yml") # && is_valid?
|
108
|
+
|
109
|
+
@app_config = Conf.new
|
110
|
+
api_key = login # use api for all the rest of communication
|
111
|
+
|
112
|
+
# send to API and install on chosen VPS
|
113
|
+
puts 'Deploying app'
|
114
|
+
uri = URI.parse("#{Vpsmatrix::API_TEST_SERVER}/uploads/deploy_to_production")
|
115
|
+
|
116
|
+
Net::HTTP.start(uri.host, 3000, :read_timeout => 500) do |http|
|
117
|
+
req = Net::HTTP::Put.new(uri)
|
118
|
+
req.add_field("Content-Type","multipart/form-data;")
|
119
|
+
req.add_field('Transfer-Encoding', 'chunked')
|
120
|
+
req['authorization'] = "Token token=#{api_key}"
|
121
|
+
req.set_form_data(@app_config.content)
|
122
|
+
|
123
|
+
http.request req do |response|
|
124
|
+
puts ""
|
125
|
+
response.read_body do |chunk|
|
126
|
+
print chunk
|
127
|
+
end
|
128
|
+
if response.code != '200'
|
129
|
+
puts response.code
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
25
133
|
end
|
26
134
|
|
135
|
+
#desc 'demo deploy', 'run demo deploy to deploy app to VPS Matrix demo server'
|
27
136
|
def demo_deploy
|
28
137
|
|
29
|
-
unless
|
30
|
-
|
138
|
+
unless Conf.new.content['ssh_key']
|
139
|
+
Conf.new.write 'ssh_key', SecureRandom.hex
|
31
140
|
end
|
32
141
|
|
33
142
|
@app_name = Dir.pwd.split(File::SEPARATOR).last
|
34
|
-
unless
|
143
|
+
unless Conf.new.content['api_key'] && Conf.new.content['api_key'].length == 32
|
35
144
|
# ask for it to server
|
36
145
|
# TODO check if server returns api_key
|
37
146
|
api_key = send_get_request "https://api.vpsmatrix.net/uploads/get_api_key"
|
38
147
|
if api_key.response.code == '200'
|
39
|
-
|
148
|
+
Conf.new.write 'api_key', api_key.response.body
|
40
149
|
end
|
41
150
|
end
|
42
151
|
|
43
152
|
#register_email
|
44
153
|
read_files
|
45
154
|
stream_file
|
46
|
-
|
47
|
-
# https://api.vpsmatrix.net/uploads/get_new_files
|
48
|
-
|
49
|
-
# detect rails? DB in (pg, mysql, sqlite, nodb)?
|
50
|
-
# no? - do you wish us to check it?
|
51
|
-
|
52
|
-
# send SSH key and API KEY to API app
|
53
|
-
|
54
|
-
# -> OK
|
55
|
-
# upload app to API, use rsync or something easy
|
56
|
-
|
57
|
-
|
58
|
-
# -> return error message (no account, etc.)
|
59
|
-
|
60
|
-
# run deploy on API app
|
61
|
-
# receive DONE deploy -> show URL
|
62
|
-
|
63
155
|
end
|
64
156
|
|
65
157
|
def read_files
|
@@ -98,7 +190,7 @@ class Starter
|
|
98
190
|
# stream version
|
99
191
|
Net::HTTP.start(uri.host, uri.port, use_ssl: true, :read_timeout => 500) do |http|
|
100
192
|
req = Net::HTTP::Put.new(uri)
|
101
|
-
req.add_field("Content-Type","multipart/form-data; boundary=#{@multipart_boundary}; ssh_key=#{
|
193
|
+
req.add_field("Content-Type","multipart/form-data; boundary=#{@multipart_boundary}; ssh_key=#{Conf.new.content['ssh_key']}; api_key=#{Conf.new.content['api_key']}")
|
102
194
|
req.add_field('Transfer-Encoding', 'chunked')
|
103
195
|
req.basic_auth("test_app", "test_app")
|
104
196
|
File.open('tmp/files_to_send', 'rb') do |io|
|
@@ -121,29 +213,6 @@ class Starter
|
|
121
213
|
end
|
122
214
|
end
|
123
215
|
|
124
|
-
def send_put_request
|
125
|
-
uri = URI.parse("https://api.vpsmatrix.net/uploads/send_new_files")
|
126
|
-
|
127
|
-
# no stream version
|
128
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
129
|
-
request = Net::HTTP::Put.new(uri.request_uri)
|
130
|
-
request.basic_auth("test_app", "test_app")
|
131
|
-
request.set_form_data({"file" => File.read("tmp/files_to_send")})
|
132
|
-
http.request request
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def send_get_request endpoint, params={} #https://api.vpsmatrix.net/uploads/get_file_list
|
137
|
-
uri = URI.parse(endpoint)
|
138
|
-
uri.query = URI.encode_www_form(params)
|
139
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
140
|
-
http.use_ssl = true
|
141
|
-
req = Net::HTTP::Get.new(uri.path)
|
142
|
-
req.basic_auth("test_app", "test_app")
|
143
|
-
http.request(req)
|
144
|
-
#res = Net::HTTP.get_response(uri)
|
145
|
-
end
|
146
|
-
|
147
216
|
def read_dirs
|
148
217
|
working_dir = Dir.pwd
|
149
218
|
list_of_files = Dir.glob "#{working_dir}/**/*"
|
@@ -157,48 +226,24 @@ class Starter
|
|
157
226
|
dirs_string
|
158
227
|
end
|
159
228
|
|
160
|
-
|
161
|
-
def register_email
|
162
|
-
puts 'Thank you very much for using vpsmatrix. You are awesome!
|
163
|
-
|
164
|
-
We are just a month in this world and still working on
|
165
|
-
full implementation of CLI functionality. We wish deployment to be the
|
166
|
-
easiest step in development for everybody.
|
167
|
-
'
|
168
|
-
puts
|
169
|
-
print 'Do you want to help us improve our solution [y/n] '
|
170
|
-
|
171
|
-
reply=$stdin.gets.chop
|
172
|
-
|
173
|
-
if reply.downcase == 'y'
|
174
|
-
|
175
|
-
puts 'At this point we would love to get your email address so we can kindly
|
176
|
-
inform you when we are ready to present working functionality. And we are
|
177
|
-
eager to hear how you feel ideal deployment should look like
|
178
|
-
at ideas@vpsmatrix.com !'
|
179
|
-
|
229
|
+
def self.usage
|
180
230
|
puts
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
187
|
-
request = Net::HTTP::Post.new(uri)
|
188
|
-
request.set_form_data({"email" => email})
|
189
|
-
response = http.request(request)
|
190
|
-
puts response.body
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
puts 'Thank you very much. Speak to you soon!'
|
195
|
-
|
196
|
-
else
|
231
|
+
puts 'Usage:'
|
232
|
+
puts 'vpsx [-options] [environment action]'
|
233
|
+
puts
|
234
|
+
puts ' Available environments: demo'
|
235
|
+
puts ' Available actions: deploy'
|
197
236
|
puts
|
198
|
-
puts '
|
237
|
+
puts 'Options:'
|
238
|
+
puts ' -h print this help'
|
239
|
+
puts ' -v print version'
|
240
|
+
puts
|
241
|
+
puts 'Example:'
|
242
|
+
puts ' rails new fooapp'
|
243
|
+
puts ' cd fooapp'
|
244
|
+
puts ' rails g scaffold foo'
|
245
|
+
puts ' vpsx demo deploy'
|
246
|
+
exit
|
199
247
|
end
|
200
|
-
puts
|
201
|
-
|
202
248
|
|
203
|
-
end
|
204
249
|
end
|
data/lib/vpsmatrix/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vpsmatrix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mousse
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- bin/vpsx
|
53
53
|
- lib/vpsmatrix.rb
|
54
54
|
- lib/vpsmatrix/config.rb
|
55
|
+
- lib/vpsmatrix/helpers.rb
|
55
56
|
- lib/vpsmatrix/starter.rb
|
56
57
|
- lib/vpsmatrix/upload_progress.rb
|
57
58
|
- lib/vpsmatrix/version.rb
|