qtc-sdk 0.3.1 → 0.4.0
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/.gitignore +18 -18
- data/Changelog.md +23 -18
- data/Gemfile +4 -4
- data/LICENSE.txt +22 -22
- data/README.md +44 -44
- data/Rakefile +1 -1
- data/bin/qtc-cli +13 -13
- data/lib/qtc-sdk.rb +1 -1
- data/lib/qtc/cli/commands.rb +15 -15
- data/lib/qtc/cli/common.rb +146 -146
- data/lib/qtc/cli/eds/base.rb +27 -27
- data/lib/qtc/cli/eds/commands.rb +20 -20
- data/lib/qtc/cli/eds/instances.rb +30 -30
- data/lib/qtc/cli/mar/apps.rb +116 -116
- data/lib/qtc/cli/mar/base.rb +60 -60
- data/lib/qtc/cli/mar/commands.rb +266 -221
- data/lib/qtc/cli/mar/debug.rb +88 -88
- data/lib/qtc/cli/mar/domains.rb +35 -35
- data/lib/qtc/cli/mar/env.rb +38 -38
- data/lib/qtc/cli/mar/repository.rb +24 -24
- data/lib/qtc/cli/mar/slugs.rb +80 -0
- data/lib/qtc/cli/mar/ssl_certificates.rb +40 -40
- data/lib/qtc/cli/mar/stack.rb +29 -29
- data/lib/qtc/cli/mdb/base.rb +47 -47
- data/lib/qtc/cli/mdb/commands.rb +43 -43
- data/lib/qtc/cli/mdb/instances.rb +79 -79
- data/lib/qtc/cli/platform/clouds.rb +33 -33
- data/lib/qtc/cli/platform/commands.rb +132 -132
- data/lib/qtc/cli/platform/datacenters.rb +23 -23
- data/lib/qtc/cli/platform/ssh_keys.rb +41 -41
- data/lib/qtc/cli/platform/user.rb +25 -25
- data/lib/qtc/cli/platform/vpn.rb +93 -93
- data/lib/qtc/client.rb +170 -170
- data/lib/qtc/eds/client.rb +116 -116
- data/lib/qtc/eds/collection.rb +124 -124
- data/lib/qtc/eds/user_collection.rb +13 -13
- data/lib/qtc/eds/usergroup_collection.rb +41 -41
- data/lib/qtc/errors.rb +13 -13
- data/lib/qtc/version.rb +3 -3
- data/qtc-sdk.gemspec +28 -28
- data/spec/unit/qtc/client_spec.rb +147 -147
- metadata +4 -3
data/lib/qtc/cli/mar/debug.rb
CHANGED
@@ -1,88 +1,88 @@
|
|
1
|
-
require_relative 'base'
|
2
|
-
require 'open3'
|
3
|
-
|
4
|
-
module Qtc
|
5
|
-
module Cli
|
6
|
-
class Mar::Debug < Mar::Base
|
7
|
-
|
8
|
-
def local_debug(commands, options)
|
9
|
-
app_home = File.realpath('.')
|
10
|
-
docker_id = nil
|
11
|
-
stack = options.stack || 'cedar-14'
|
12
|
-
puts "-----> Starting to build MAR app locally"
|
13
|
-
|
14
|
-
if options.clean == true && File.exists?("#{app_home}/slug.tgz")
|
15
|
-
File.delete("#{app_home}/slug.tgz")
|
16
|
-
end
|
17
|
-
|
18
|
-
unless File.exists?("#{app_home}/slug.tgz")
|
19
|
-
docker_id = build_slug(app_home, stack)
|
20
|
-
else
|
21
|
-
puts " Existing slug.tgz found, build not needed."
|
22
|
-
end
|
23
|
-
puts "-----> Starting app container"
|
24
|
-
run_opts = [
|
25
|
-
'-e PORT=5000',
|
26
|
-
"-e STACK=#{stack}",
|
27
|
-
'-e SLUG_URL=file:///tmp/fake_slug.tgz',
|
28
|
-
'-p 5000',
|
29
|
-
"-v #{app_home}/slug.tgz:/tmp/fake_slug.tgz"
|
30
|
-
]
|
31
|
-
if File.exists?("#{app_home}/.env")
|
32
|
-
run_opts << "--env-file=#{app_home}/.env"
|
33
|
-
end
|
34
|
-
if commands.size == 0
|
35
|
-
cmd = 'start web'
|
36
|
-
else
|
37
|
-
cmd = commands.join(" ")
|
38
|
-
end
|
39
|
-
|
40
|
-
exec("docker run -it #{run_opts.join(" ")} qtcs/slugrunner:#{stack} #{cmd}")
|
41
|
-
end
|
42
|
-
|
43
|
-
def local_build_slug(options)
|
44
|
-
stack = options.stack || 'cedar-14'
|
45
|
-
app_home = File.realpath('.')
|
46
|
-
puts "-----> Starting to build MAR app locally"
|
47
|
-
build_slug(app_home, stack)
|
48
|
-
end
|
49
|
-
|
50
|
-
def build_slug(app_home, stack)
|
51
|
-
docker_id = nil
|
52
|
-
run_opts = ''
|
53
|
-
if File.exists?("#{app_home}/.env")
|
54
|
-
run_opts << "--env-file=#{app_home}/.env"
|
55
|
-
end
|
56
|
-
Open3.popen3("docker run -d #{run_opts} -v #{app_home}:/tmp/gitrepo:r qtcs/slugbuilder:#{stack}") {|stdin, stdout, stderr, wait_thr|
|
57
|
-
docker_id = stdout.gets
|
58
|
-
if docker_id
|
59
|
-
docker_id.strip!
|
60
|
-
else
|
61
|
-
puts stderr.gets
|
62
|
-
end
|
63
|
-
exit_status = wait_thr.value
|
64
|
-
unless exit_status.success?
|
65
|
-
raise "ERROR: build failed to start"
|
66
|
-
end
|
67
|
-
}
|
68
|
-
Open3.popen2('docker', 'attach', docker_id){|stdin, stdout, wait_thr|
|
69
|
-
stdin.close
|
70
|
-
while line = stdout.gets
|
71
|
-
puts line
|
72
|
-
end
|
73
|
-
exit_status = wait_thr.value
|
74
|
-
unless exit_status.success?
|
75
|
-
raise "ERROR: build failed to complete"
|
76
|
-
end
|
77
|
-
}
|
78
|
-
puts "-----> Extracting slug from build image to ./slug.tgz"
|
79
|
-
system("docker cp #{docker_id}:/tmp/slug.tgz . > /dev/null")
|
80
|
-
|
81
|
-
docker_id
|
82
|
-
rescue => exc
|
83
|
-
system("docker rm -f #{docker_id}") if docker_id
|
84
|
-
raise exc
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
1
|
+
require_relative 'base'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
module Qtc
|
5
|
+
module Cli
|
6
|
+
class Mar::Debug < Mar::Base
|
7
|
+
|
8
|
+
def local_debug(commands, options)
|
9
|
+
app_home = File.realpath('.')
|
10
|
+
docker_id = nil
|
11
|
+
stack = options.stack || 'cedar-14'
|
12
|
+
puts "-----> Starting to build MAR app locally"
|
13
|
+
|
14
|
+
if options.clean == true && File.exists?("#{app_home}/slug.tgz")
|
15
|
+
File.delete("#{app_home}/slug.tgz")
|
16
|
+
end
|
17
|
+
|
18
|
+
unless File.exists?("#{app_home}/slug.tgz")
|
19
|
+
docker_id = build_slug(app_home, stack)
|
20
|
+
else
|
21
|
+
puts " Existing slug.tgz found, build not needed."
|
22
|
+
end
|
23
|
+
puts "-----> Starting app container"
|
24
|
+
run_opts = [
|
25
|
+
'-e PORT=5000',
|
26
|
+
"-e STACK=#{stack}",
|
27
|
+
'-e SLUG_URL=file:///tmp/fake_slug.tgz',
|
28
|
+
'-p 5000',
|
29
|
+
"-v #{app_home}/slug.tgz:/tmp/fake_slug.tgz"
|
30
|
+
]
|
31
|
+
if File.exists?("#{app_home}/.env")
|
32
|
+
run_opts << "--env-file=#{app_home}/.env"
|
33
|
+
end
|
34
|
+
if commands.size == 0
|
35
|
+
cmd = 'start web'
|
36
|
+
else
|
37
|
+
cmd = commands.join(" ")
|
38
|
+
end
|
39
|
+
|
40
|
+
exec("docker run -it #{run_opts.join(" ")} qtcs/slugrunner:#{stack} #{cmd}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def local_build_slug(options)
|
44
|
+
stack = options.stack || 'cedar-14'
|
45
|
+
app_home = File.realpath('.')
|
46
|
+
puts "-----> Starting to build MAR app locally"
|
47
|
+
build_slug(app_home, stack)
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_slug(app_home, stack)
|
51
|
+
docker_id = nil
|
52
|
+
run_opts = ''
|
53
|
+
if File.exists?("#{app_home}/.env")
|
54
|
+
run_opts << "--env-file=#{app_home}/.env"
|
55
|
+
end
|
56
|
+
Open3.popen3("docker run -d #{run_opts} -v #{app_home}:/tmp/gitrepo:r qtcs/slugbuilder:#{stack}") {|stdin, stdout, stderr, wait_thr|
|
57
|
+
docker_id = stdout.gets
|
58
|
+
if docker_id
|
59
|
+
docker_id.strip!
|
60
|
+
else
|
61
|
+
puts stderr.gets
|
62
|
+
end
|
63
|
+
exit_status = wait_thr.value
|
64
|
+
unless exit_status.success?
|
65
|
+
raise "ERROR: build failed to start"
|
66
|
+
end
|
67
|
+
}
|
68
|
+
Open3.popen2('docker', 'attach', docker_id){|stdin, stdout, wait_thr|
|
69
|
+
stdin.close
|
70
|
+
while line = stdout.gets
|
71
|
+
puts line
|
72
|
+
end
|
73
|
+
exit_status = wait_thr.value
|
74
|
+
unless exit_status.success?
|
75
|
+
raise "ERROR: build failed to complete"
|
76
|
+
end
|
77
|
+
}
|
78
|
+
puts "-----> Extracting slug from build image to ./slug.tgz"
|
79
|
+
system("docker cp #{docker_id}:/tmp/slug.tgz . > /dev/null")
|
80
|
+
|
81
|
+
docker_id
|
82
|
+
rescue => exc
|
83
|
+
system("docker rm -f #{docker_id}") if docker_id
|
84
|
+
raise exc
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/qtc/cli/mar/domains.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
|
-
require_relative 'base'
|
2
|
-
|
3
|
-
module Qtc
|
4
|
-
module Cli
|
5
|
-
class Mar::Domains < Mar::Base
|
6
|
-
|
7
|
-
def list(options)
|
8
|
-
instance_id = resolve_instance_id(options)
|
9
|
-
instance_data = instance_info(instance_id)
|
10
|
-
if instance_data
|
11
|
-
result = client.get("/apps/#{instance_id}/domains", nil, {'Authorization' => "Bearer #{current_cloud_token}"})
|
12
|
-
result['results'].each do |r|
|
13
|
-
print color("* #{r['name']}", :bold)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def create(name, options)
|
19
|
-
instance_id = resolve_instance_id(options)
|
20
|
-
instance_data = instance_info(instance_id)
|
21
|
-
if instance_data
|
22
|
-
client.post("/apps/#{instance_id}/domains", {name: name}, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def destroy(name, options)
|
27
|
-
instance_id = resolve_instance_id(options)
|
28
|
-
instance_data = instance_info(instance_id)
|
29
|
-
if instance_data
|
30
|
-
client.delete("/apps/#{instance_id}/domains/#{name}", nil, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Qtc
|
4
|
+
module Cli
|
5
|
+
class Mar::Domains < Mar::Base
|
6
|
+
|
7
|
+
def list(options)
|
8
|
+
instance_id = resolve_instance_id(options)
|
9
|
+
instance_data = instance_info(instance_id)
|
10
|
+
if instance_data
|
11
|
+
result = client.get("/apps/#{instance_id}/domains", nil, {'Authorization' => "Bearer #{current_cloud_token}"})
|
12
|
+
result['results'].each do |r|
|
13
|
+
print color("* #{r['name']}", :bold)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create(name, options)
|
19
|
+
instance_id = resolve_instance_id(options)
|
20
|
+
instance_data = instance_info(instance_id)
|
21
|
+
if instance_data
|
22
|
+
client.post("/apps/#{instance_id}/domains", {name: name}, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def destroy(name, options)
|
27
|
+
instance_id = resolve_instance_id(options)
|
28
|
+
instance_data = instance_info(instance_id)
|
29
|
+
if instance_data
|
30
|
+
client.delete("/apps/#{instance_id}/domains/#{name}", nil, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/qtc/cli/mar/env.rb
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
require_relative 'base'
|
2
|
-
|
3
|
-
module Qtc
|
4
|
-
module Cli
|
5
|
-
class Mar::Env < Mar::Base
|
6
|
-
|
7
|
-
def set(vars, options)
|
8
|
-
instance_id = resolve_instance_id(options)
|
9
|
-
env_vars = {}
|
10
|
-
vars.each do |type|
|
11
|
-
arr = type.strip.split('=', 2)
|
12
|
-
if arr[0]
|
13
|
-
if arr[1].nil? || arr[1] == ''
|
14
|
-
env_vars[arr[0]] = nil
|
15
|
-
else
|
16
|
-
env_vars[arr[0]] = arr[1]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
instance_data = instance_info(instance_id)
|
21
|
-
if instance_data
|
22
|
-
client.put("/apps/#{instance_id}/env_vars", env_vars, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def show(options)
|
27
|
-
instance_id = resolve_instance_id(options)
|
28
|
-
instance_data = instance_info(instance_id)
|
29
|
-
if instance_data
|
30
|
-
env_vars = client.get("/apps/#{instance_id}/env_vars", {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
31
|
-
env_vars.each do |key, value|
|
32
|
-
puts "#{key}=#{value}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Qtc
|
4
|
+
module Cli
|
5
|
+
class Mar::Env < Mar::Base
|
6
|
+
|
7
|
+
def set(vars, options)
|
8
|
+
instance_id = resolve_instance_id(options)
|
9
|
+
env_vars = {}
|
10
|
+
vars.each do |type|
|
11
|
+
arr = type.strip.split('=', 2)
|
12
|
+
if arr[0]
|
13
|
+
if arr[1].nil? || arr[1] == ''
|
14
|
+
env_vars[arr[0]] = nil
|
15
|
+
else
|
16
|
+
env_vars[arr[0]] = arr[1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
instance_data = instance_info(instance_id)
|
21
|
+
if instance_data
|
22
|
+
client.put("/apps/#{instance_id}/env_vars", env_vars, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def show(options)
|
27
|
+
instance_id = resolve_instance_id(options)
|
28
|
+
instance_data = instance_info(instance_id)
|
29
|
+
if instance_data
|
30
|
+
env_vars = client.get("/apps/#{instance_id}/env_vars", {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
31
|
+
env_vars.each do |key, value|
|
32
|
+
puts "#{key}=#{value}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -1,24 +1,24 @@
|
|
1
|
-
require_relative 'base'
|
2
|
-
|
3
|
-
module Qtc
|
4
|
-
module Cli
|
5
|
-
class Mar::Repository < Mar::Base
|
6
|
-
|
7
|
-
def purge_cache(options)
|
8
|
-
instance_id = resolve_instance_id(options)
|
9
|
-
instance_data = instance_info(instance_id)
|
10
|
-
if instance_data
|
11
|
-
client.delete("/apps/#{instance_id}/build_cache", nil, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def reset(options)
|
16
|
-
instance_id = resolve_instance_id(options)
|
17
|
-
instance_data = instance_info(instance_id)
|
18
|
-
if instance_data
|
19
|
-
client.delete("/apps/#{instance_id}/repository", nil, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Qtc
|
4
|
+
module Cli
|
5
|
+
class Mar::Repository < Mar::Base
|
6
|
+
|
7
|
+
def purge_cache(options)
|
8
|
+
instance_id = resolve_instance_id(options)
|
9
|
+
instance_data = instance_info(instance_id)
|
10
|
+
if instance_data
|
11
|
+
client.delete("/apps/#{instance_id}/build_cache", nil, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset(options)
|
16
|
+
instance_id = resolve_instance_id(options)
|
17
|
+
instance_data = instance_info(instance_id)
|
18
|
+
if instance_data
|
19
|
+
client.delete("/apps/#{instance_id}/repository", nil, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'httpclient'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
module Qtc
|
9
|
+
module Cli
|
10
|
+
class Mar::Slugs < Mar::Base
|
11
|
+
|
12
|
+
def list(options)
|
13
|
+
instance_id = resolve_instance_id(options)
|
14
|
+
slugs = client.get("/apps/#{instance_id}/slugs/", {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
15
|
+
if slugs && slugs['results'].size > 0
|
16
|
+
template = "%-20.20s %-30.30s %-30.30s"
|
17
|
+
puts template % ["TAG", "CREATED", "DEPLOYED"]
|
18
|
+
slugs['results'].each do |slug|
|
19
|
+
puts template % [slug['tag'], slug['createdAt'], slug['deployedAt']]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove(slug_id, options)
|
25
|
+
instance_id = resolve_instance_id(options)
|
26
|
+
client.delete("/apps/#{instance_id}/slugs/#{slug_id}", {}, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
27
|
+
end
|
28
|
+
|
29
|
+
def upload(options)
|
30
|
+
instance_id = resolve_instance_id(options)
|
31
|
+
|
32
|
+
slug = create_slug(instance_id, options)
|
33
|
+
upload_uri = URI(slug['blob']['url'])
|
34
|
+
puts "Starting slug upload, if your slug is large this may take a while"
|
35
|
+
# todo Would be nice to have some sort of progress indication...
|
36
|
+
begin
|
37
|
+
open(File.new(options.slug), 'rb') do |io|
|
38
|
+
aws_client = Net::HTTP.new(upload_uri.host)
|
39
|
+
req = Net::HTTP::Put.new(upload_uri.request_uri)
|
40
|
+
req.content_length = io.size
|
41
|
+
req.body_stream = io
|
42
|
+
req['Content-Type'] = 'application/octet-stream'
|
43
|
+
|
44
|
+
aws_client.request(req)
|
45
|
+
end
|
46
|
+
rescue => exc
|
47
|
+
puts "Slug upload failed:#{exc.to_s}"
|
48
|
+
raise StandardError "Slug upload failed!"
|
49
|
+
end
|
50
|
+
puts "Slug uploaded successfully, you may now deploy it using commit tag: #{slug['tag']}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def deploy(slug_id, options)
|
54
|
+
instance_id = resolve_instance_id(options)
|
55
|
+
client.post("/apps/#{instance_id}/slugs/#{slug_id}/deploy", {}, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
56
|
+
end
|
57
|
+
|
58
|
+
def create_slug(instance_id, options)
|
59
|
+
process_types = resolve_proc_types(options)
|
60
|
+
data = {
|
61
|
+
tag: options.tag,
|
62
|
+
process_types: process_types
|
63
|
+
}
|
64
|
+
client.post("/apps/#{instance_id}/slugs", data, {}, {'Authorization' => "Bearer #{current_cloud_token}"})
|
65
|
+
end
|
66
|
+
|
67
|
+
def resolve_proc_types(options)
|
68
|
+
if options.procfile
|
69
|
+
procfile_hash = {}
|
70
|
+
procfile = YAML.load(File.read(options.procfile), :encoding => 'utf-8')
|
71
|
+
procfile_hash.merge!(procfile) if procfile
|
72
|
+
procfile_hash
|
73
|
+
else
|
74
|
+
raise StandardError 'Procfile must be given'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|