kontena-cli 0.8.4 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/bin/kontena +4 -0
- data/lib/kontena/cli/app_command.rb +2 -0
- data/lib/kontena/cli/apps/build_command.rb +26 -0
- data/lib/kontena/cli/apps/common.rb +41 -12
- data/lib/kontena/cli/apps/deploy_command.rb +31 -13
- data/lib/kontena/cli/apps/docker_helper.rb +34 -0
- data/lib/kontena/cli/apps/init_command.rb +130 -10
- data/lib/kontena/cli/apps/list_command.rb +4 -2
- data/lib/kontena/cli/apps/logs_command.rb +4 -2
- data/lib/kontena/cli/apps/remove_command.rb +4 -2
- data/lib/kontena/cli/apps/start_command.rb +4 -2
- data/lib/kontena/cli/apps/stop_command.rb +4 -2
- data/lib/kontena/cli/common.rb +3 -3
- data/lib/kontena/cli/container_command.rb +3 -0
- data/lib/kontena/cli/containers/inspect_command.rb +16 -0
- data/lib/kontena/cli/deploy_command.rb +3 -0
- data/lib/kontena/cli/etcd/get_command.rb +21 -0
- data/lib/kontena/cli/etcd/list_command.rb +26 -0
- data/lib/kontena/cli/etcd/mkdir_command.rb +17 -0
- data/lib/kontena/cli/etcd/remove_command.rb +21 -0
- data/lib/kontena/cli/etcd/set_command.rb +18 -0
- data/lib/kontena/cli/etcd_command.rb +17 -0
- data/lib/kontena/cli/grid_command.rb +2 -0
- data/lib/kontena/cli/grids/logs_command.rb +71 -0
- data/lib/kontena/cli/master/aws/create_command.rb +33 -0
- data/lib/kontena/cli/master/aws_command.rb +8 -0
- data/lib/kontena/cli/master/azure/create_command.rb +33 -0
- data/lib/kontena/cli/master/azure_command.rb +13 -0
- data/lib/kontena/cli/master/digital_ocean/create_command.rb +30 -0
- data/lib/kontena/cli/master/digital_ocean_command.rb +13 -0
- data/lib/kontena/cli/master/vagrant/create_command.rb +19 -0
- data/lib/kontena/cli/master/vagrant/restart_command.rb +20 -0
- data/lib/kontena/cli/master/vagrant/ssh_command.rb +15 -0
- data/lib/kontena/cli/master/vagrant/start_command.rb +20 -0
- data/lib/kontena/cli/master/vagrant/stop_command.rb +20 -0
- data/lib/kontena/cli/master/vagrant/terminate_command.rb +13 -0
- data/lib/kontena/cli/master/vagrant_command.rb +23 -0
- data/lib/kontena/cli/master_command.rb +15 -0
- data/lib/kontena/cli/node_command.rb +4 -0
- data/lib/kontena/cli/nodes/aws/create_command.rb +39 -0
- data/lib/kontena/cli/nodes/aws/restart_command.rb +28 -0
- data/lib/kontena/cli/nodes/aws/terminate_command.rb +20 -0
- data/lib/kontena/cli/nodes/aws_command.rb +15 -0
- data/lib/kontena/cli/nodes/azure/create_command.rb +39 -0
- data/lib/kontena/cli/nodes/azure/restart_command.rb +31 -0
- data/lib/kontena/cli/nodes/azure/terminate_command.rb +20 -0
- data/lib/kontena/cli/nodes/azure_command.rb +15 -0
- data/lib/kontena/cli/nodes/digital_ocean/create_command.rb +1 -1
- data/lib/kontena/cli/nodes/vagrant/create_command.rb +1 -1
- data/lib/kontena/cli/service_command.rb +4 -0
- data/lib/kontena/cli/services/add_env_command.rb +18 -0
- data/lib/kontena/cli/services/create_command.rb +8 -0
- data/lib/kontena/cli/services/remove_env_command.rb +17 -0
- data/lib/kontena/cli/services/services_helper.rb +20 -1
- data/lib/kontena/cli/services/update_command.rb +10 -0
- data/lib/kontena/client.rb +22 -1
- data/lib/kontena/machine/aws.rb +13 -0
- data/lib/kontena/machine/aws/cloudinit.yml +66 -0
- data/lib/kontena/machine/aws/cloudinit_master.yml +105 -0
- data/lib/kontena/machine/aws/master_provisioner.rb +161 -0
- data/lib/kontena/machine/aws/node_destroyer.rb +39 -0
- data/lib/kontena/machine/aws/node_provisioner.rb +168 -0
- data/lib/kontena/machine/azure.rb +13 -0
- data/lib/kontena/machine/azure/cloudinit.yml +59 -0
- data/lib/kontena/machine/azure/cloudinit_master.yml +105 -0
- data/lib/kontena/machine/azure/logger.rb +27 -0
- data/lib/kontena/machine/azure/master_provisioner.rb +126 -0
- data/lib/kontena/machine/azure/node_destroyer.rb +53 -0
- data/lib/kontena/machine/azure/node_provisioner.rb +128 -0
- data/lib/kontena/machine/digital_ocean.rb +1 -0
- data/lib/kontena/machine/digital_ocean/cloudinit.yml +1 -0
- data/lib/kontena/machine/digital_ocean/cloudinit_master.yml +105 -0
- data/lib/kontena/machine/digital_ocean/master_provisioner.rb +94 -0
- data/lib/kontena/machine/digital_ocean/node_provisioner.rb +8 -1
- data/lib/kontena/machine/vagrant.rb +2 -0
- data/lib/kontena/machine/vagrant/Vagrantfile.master.rb.erb +101 -0
- data/lib/kontena/machine/vagrant/{Vagrantfile.coreos.rb.erb → Vagrantfile.node.rb.erb} +0 -0
- data/lib/kontena/machine/vagrant/cloudinit.yml +2 -1
- data/lib/kontena/machine/vagrant/master_destroyer.rb +37 -0
- data/lib/kontena/machine/vagrant/master_provisioner.rb +75 -0
- data/lib/kontena/machine/vagrant/node_destroyer.rb +4 -0
- data/lib/kontena/machine/vagrant/node_provisioner.rb +1 -1
- data/lib/kontena/scripts/completer +29 -3
- data/spec/kontena/cli/app/common_spec.rb +61 -0
- data/spec/kontena/cli/app/deploy_command_spec.rb +25 -6
- data/spec/kontena/cli/app/docker_helper_spec.rb +32 -0
- data/spec/kontena/cli/common_spec.rb +53 -0
- metadata +61 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5495634079f9438b5489ef1b059675ecd1b1816e
|
4
|
+
data.tar.gz: 2f2d23237da702fe1dd1919a83621d004d129d9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e44eaeae82ce15d7e09cb238cca449c8d7cfcf9ce666018dc8daa89aceb5a8ddc00a5077d5dbfe81aaae71a7ccb61f4e410054bc2f59dcbe13ed94ff6eacae08
|
7
|
+
data.tar.gz: 1a0ac1c623f49eb325c31d41cc108d0fabcce469848cca141b3b280827b6919f3f26a2456f4addac0ad378d74db41ed2ec47a86d67d62f5ad58018af620b95bd
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.9.0
|
data/bin/kontena
CHANGED
@@ -24,6 +24,7 @@ require 'kontena/cli/forgot_password_command'
|
|
24
24
|
require 'kontena/cli/reset_password_command'
|
25
25
|
require 'kontena/cli/container_command'
|
26
26
|
require 'kontena/cli/grid_command'
|
27
|
+
require 'kontena/cli/master_command'
|
27
28
|
require 'kontena/cli/node_command'
|
28
29
|
require 'kontena/cli/service_command'
|
29
30
|
require 'kontena/cli/vpn_command'
|
@@ -31,6 +32,7 @@ require 'kontena/cli/registry_command'
|
|
31
32
|
require 'kontena/cli/external_registry_command'
|
32
33
|
require 'kontena/cli/deploy_command'
|
33
34
|
require 'kontena/cli/app_command'
|
35
|
+
require 'kontena/cli/etcd_command'
|
34
36
|
require 'kontena/cli/version_command'
|
35
37
|
|
36
38
|
class MainCommand < Clamp::Command
|
@@ -41,9 +43,11 @@ class MainCommand < Clamp::Command
|
|
41
43
|
subcommand "service", "Service specific commands", Kontena::Cli::ServiceCommand
|
42
44
|
subcommand "deploy", "Create and deploy multiple services from YAML file", Kontena::Cli::DeployCommand
|
43
45
|
subcommand "node", "Node specific commands", Kontena::Cli::NodeCommand
|
46
|
+
subcommand "master", "Master specific commands", Kontena::Cli::MasterCommand
|
44
47
|
subcommand "vpn", "VPN specific commands", Kontena::Cli::VpnCommand
|
45
48
|
subcommand "registry", "Registry specific commands", Kontena::Cli::RegistryCommand
|
46
49
|
subcommand "container", "Container specific commands", Kontena::Cli::ContainerCommand
|
50
|
+
subcommand "etcd", "Etcd specific commands", Kontena::Cli::EtcdCommand
|
47
51
|
subcommand "external-registry", "External registry specific commands", Kontena::Cli::ExternalRegistryCommand
|
48
52
|
subcommand "register", "Register Kontena Account", Kontena::Cli::RegisterCommand
|
49
53
|
subcommand "login", "Login to Kontena Master", Kontena::Cli::LoginCommand
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'apps/init_command'
|
2
|
+
require_relative 'apps/build_command'
|
2
3
|
require_relative 'apps/deploy_command'
|
3
4
|
require_relative 'apps/start_command'
|
4
5
|
require_relative 'apps/stop_command'
|
@@ -9,6 +10,7 @@ require_relative 'apps/logs_command'
|
|
9
10
|
class Kontena::Cli::AppCommand < Clamp::Command
|
10
11
|
|
11
12
|
subcommand "init", "Init Kontena application", Kontena::Cli::Apps::InitCommand
|
13
|
+
subcommand "build", "Build Kontena services", Kontena::Cli::Apps::BuildCommand
|
12
14
|
subcommand "deploy", "Deploy Kontena services", Kontena::Cli::Apps::DeployCommand
|
13
15
|
subcommand "start", "Start services", Kontena::Cli::Apps::StartCommand
|
14
16
|
subcommand "stop", "Stop services", Kontena::Cli::Apps::StopCommand
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative 'common'
|
3
|
+
require_relative 'docker_helper'
|
4
|
+
|
5
|
+
module Kontena::Cli::Apps
|
6
|
+
class BuildCommand < Clamp::Command
|
7
|
+
include Kontena::Cli::Common
|
8
|
+
include Common
|
9
|
+
include DockerHelper
|
10
|
+
|
11
|
+
option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
|
12
|
+
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
13
|
+
parameter "[SERVICE] ...", "Services to start"
|
14
|
+
|
15
|
+
attr_reader :services, :service_prefix
|
16
|
+
|
17
|
+
def execute
|
18
|
+
require_config_file(filename)
|
19
|
+
@service_prefix = project_name || current_dir
|
20
|
+
dir = Dir.getwd
|
21
|
+
@services = load_services(filename, service_list, service_prefix)
|
22
|
+
Dir.chdir(dir)
|
23
|
+
process_docker_images(services, true) if dockerfile_exist?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -4,12 +4,12 @@ module Kontena::Cli::Apps
|
|
4
4
|
module Common
|
5
5
|
include Kontena::Cli::Services::ServicesHelper
|
6
6
|
|
7
|
-
def
|
8
|
-
@service_prefix = project_name || current_dir
|
9
|
-
|
7
|
+
def require_config_file(filename)
|
10
8
|
abort("File #{filename} does not exist") unless File.exists?(filename)
|
11
|
-
|
9
|
+
end
|
12
10
|
|
11
|
+
def load_services(filename, service_list, prefix)
|
12
|
+
services = parse_services(filename, nil, prefix)
|
13
13
|
services.delete_if { |name, service| !service_list.include?(name)} unless service_list.empty?
|
14
14
|
services
|
15
15
|
end
|
@@ -32,18 +32,17 @@ module Kontena::Cli::Apps
|
|
32
32
|
get_service(token, prefixed_name(name)) rescue false
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
services = YAML.load(File.read(file) % {
|
35
|
+
def parse_services(file, name = nil, prefix='')
|
36
|
+
services = YAML.load(File.read(File.expand_path(file)) % {project: prefix})
|
37
|
+
Dir.chdir(File.dirname(File.expand_path(file)))
|
37
38
|
services.each do |name, options|
|
39
|
+
normalize_env_vars(options)
|
38
40
|
if options.has_key?('extends')
|
39
|
-
|
41
|
+
extension_file = options['extends']['file']
|
42
|
+
service_name = options['extends']['service']
|
40
43
|
options.delete('extends')
|
41
|
-
services[name] =
|
42
|
-
end
|
43
|
-
if options.has_key?('build')
|
44
|
-
options.delete('build')
|
44
|
+
services[name] = extend_options(options, extension_file , service_name, prefix)
|
45
45
|
end
|
46
|
-
|
47
46
|
end
|
48
47
|
if name.nil?
|
49
48
|
services
|
@@ -51,5 +50,35 @@ module Kontena::Cli::Apps
|
|
51
50
|
services[name]
|
52
51
|
end
|
53
52
|
end
|
53
|
+
|
54
|
+
def extend_options(options, file, service_name, prefix)
|
55
|
+
parent_options = parse_services(file, service_name, prefix)
|
56
|
+
options['environment'] = extend_env_vars(parent_options, options)
|
57
|
+
parent_options.merge(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def normalize_env_vars(options)
|
61
|
+
if options['environment'].is_a?(Hash)
|
62
|
+
options['environment'] = options['environment'].map{|k, v| "#{k}=#{v}"}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def extend_env_vars(from, to)
|
67
|
+
env_vars = to['environment'] || []
|
68
|
+
if from['environment']
|
69
|
+
from['environment'].each do |env|
|
70
|
+
env_vars << env unless to['environment'] && to['environment'].find {|key| key.split('=').first == env.split('=').first}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
env_vars
|
74
|
+
end
|
75
|
+
|
76
|
+
def dockerfile_exist?
|
77
|
+
!dockerfile.nil?
|
78
|
+
end
|
79
|
+
|
80
|
+
def dockerfile
|
81
|
+
@dockerfile ||= File.new('Dockerfile') rescue nil
|
82
|
+
end
|
54
83
|
end
|
55
84
|
end
|
@@ -1,30 +1,38 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require_relative 'common'
|
3
|
+
require_relative 'docker_helper'
|
3
4
|
|
4
5
|
module Kontena::Cli::Apps
|
5
6
|
class DeployCommand < Clamp::Command
|
6
7
|
include Kontena::Cli::Common
|
7
8
|
include Common
|
9
|
+
include DockerHelper
|
8
10
|
|
9
11
|
option ['-f', '--file'], 'FILE', 'Specify an alternate Kontena compose file', attribute_name: :filename, default: 'kontena.yml'
|
12
|
+
option ['--no-build'], :flag, 'Don\'t build an image, even if it\'s missing', default: false
|
10
13
|
option ['-p', '--project-name'], 'NAME', 'Specify an alternate project name (default: directory name)'
|
11
14
|
|
12
15
|
parameter "[SERVICE] ...", "Services to start"
|
13
16
|
|
14
|
-
attr_reader :services, :service_prefix
|
17
|
+
attr_reader :services, :service_prefix, :deploy_queue
|
15
18
|
|
16
19
|
def execute
|
17
20
|
require_api_url
|
18
21
|
require_token
|
19
|
-
|
20
|
-
Dir.
|
21
|
-
|
22
|
+
require_config_file(filename)
|
23
|
+
dir = Dir.getwd
|
24
|
+
@deploy_queue = []
|
25
|
+
@service_prefix = project_name || current_dir
|
26
|
+
@services = load_services(filename, service_list, service_prefix)
|
27
|
+
Dir.chdir(dir)
|
28
|
+
process_docker_images(services) if !no_build? && dockerfile_exist?
|
29
|
+
create_or_update_services(services)
|
22
30
|
deploy_services(deploy_queue)
|
23
31
|
end
|
24
32
|
|
25
33
|
private
|
26
34
|
|
27
|
-
def
|
35
|
+
def create_or_update_services(services)
|
28
36
|
services.each do |name, config|
|
29
37
|
create_or_update_service(name, config)
|
30
38
|
end
|
@@ -32,7 +40,7 @@ module Kontena::Cli::Apps
|
|
32
40
|
|
33
41
|
def deploy_services(queue)
|
34
42
|
queue.each do |service|
|
35
|
-
puts "deploying #{service['id']}"
|
43
|
+
puts "deploying #{service['id'].colorize(:cyan)}"
|
36
44
|
data = {}
|
37
45
|
if service['deploy']
|
38
46
|
data[:strategy] = service['deploy']['strategy'] if service['deploy']['strategy']
|
@@ -43,8 +51,7 @@ module Kontena::Cli::Apps
|
|
43
51
|
end
|
44
52
|
|
45
53
|
def create_or_update_service(name, options)
|
46
|
-
|
47
|
-
# skip if service is already created or updated or it's not present
|
54
|
+
# skip if service is already processed or it's not present
|
48
55
|
return nil if in_deploy_queue?(name) || !services.keys.include?(name)
|
49
56
|
|
50
57
|
# create/update linked services recursively before continuing
|
@@ -57,6 +64,7 @@ module Kontena::Cli::Apps
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
67
|
+
merge_external_links(options)
|
60
68
|
merge_env_vars(options)
|
61
69
|
|
62
70
|
if service_exists?(name)
|
@@ -77,7 +85,7 @@ module Kontena::Cli::Apps
|
|
77
85
|
|
78
86
|
def create(name, options)
|
79
87
|
name = prefixed_name(name)
|
80
|
-
puts "creating #{name}"
|
88
|
+
puts "creating #{name.colorize(:cyan)}"
|
81
89
|
data = {name: name}
|
82
90
|
data.merge!(parse_data(options))
|
83
91
|
create_service(token, current_grid, data)
|
@@ -86,7 +94,7 @@ module Kontena::Cli::Apps
|
|
86
94
|
def update(id, options)
|
87
95
|
id = prefixed_name(id)
|
88
96
|
data = parse_data(options)
|
89
|
-
puts "updating #{id}"
|
97
|
+
puts "updating #{id.colorize(:cyan)}"
|
90
98
|
update_service(token, id, data)
|
91
99
|
end
|
92
100
|
|
@@ -107,6 +115,14 @@ module Kontena::Cli::Apps
|
|
107
115
|
options['environment'].uniq! {|s| s.split('=').first}
|
108
116
|
end
|
109
117
|
|
118
|
+
def merge_external_links(options)
|
119
|
+
if options['external_links']
|
120
|
+
options['links'] ||= []
|
121
|
+
options['links'] = options['links'] + options['external_links']
|
122
|
+
options.delete('external_links')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
110
126
|
def read_env_file(path)
|
111
127
|
File.readlines(path).delete_if { |line| line.start_with?('#') || line.empty? }
|
112
128
|
end
|
@@ -129,13 +145,15 @@ module Kontena::Cli::Apps
|
|
129
145
|
data[:affinity] = options['affinity'] if options['affinity']
|
130
146
|
data[:user] = options['user'] if options['user']
|
131
147
|
data[:stateful] = options['stateful'] == true
|
148
|
+
data[:privileged] = options['privileged'] unless options['privileged'].nil?
|
132
149
|
data[:cap_add] = options['cap_add'] if options['cap_add']
|
133
150
|
data[:cap_drop] = options['cap_drop'] if options['cap_drop']
|
151
|
+
data[:net] = options['net'] if options['net']
|
152
|
+
data[:log_driver] = options['log_driver'] if options['log_driver']
|
153
|
+
data[:log_opts] = options['log_opt'] if options['log_opt'] && !options['log_opt'].empty?
|
154
|
+
|
134
155
|
data
|
135
156
|
end
|
136
157
|
|
137
|
-
def deploy_queue
|
138
|
-
@deploy_queue ||= []
|
139
|
-
end
|
140
158
|
end
|
141
159
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Kontena::Cli::Apps
|
2
|
+
module DockerHelper
|
3
|
+
|
4
|
+
def process_docker_images(services, force_build = false)
|
5
|
+
services.each do |name, service|
|
6
|
+
if service['build'] && (!image_exist?(service['image']) || force_build)
|
7
|
+
abort("'#{service['image']}' is not valid Docker image name") unless validate_image_name(service['image'])
|
8
|
+
puts "Building image #{service['image'].colorize(:cyan)}"
|
9
|
+
build_docker_image(service['image'], service['build'])
|
10
|
+
|
11
|
+
puts "Pushing image #{service['image'].colorize(:cyan)} to registry"
|
12
|
+
push_docker_image(service['image'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate_image_name(name)
|
18
|
+
!(/^[\w.\/\-]+:?+[\w+.]+$/ =~ name).nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def build_docker_image(name, path)
|
23
|
+
system("docker build -t #{name} #{path}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def push_docker_image(image)
|
27
|
+
system("docker push #{image}")
|
28
|
+
end
|
29
|
+
|
30
|
+
def image_exist?(image)
|
31
|
+
`docker history #{image} 2>&1` ; $?.success?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'securerandom'
|
2
3
|
|
3
4
|
module Kontena::Cli::Apps
|
4
5
|
class InitCommand < Clamp::Command
|
@@ -7,10 +8,15 @@ module Kontena::Cli::Apps
|
|
7
8
|
option ["-f", "--file"], "FILE", "Specify a docker-compose file", attribute_name: :docker_compose_file, default: 'docker-compose.yml'
|
8
9
|
option ["-i", "--image-name"], "IMAGE_NAME", "Specify a docker image name"
|
9
10
|
option ["-b", "--base-image"], "BASE_IMAGE_NAME", "Specify a docker base image name", default: "kontena/buildstep"
|
11
|
+
option ["-p", "--project-name"], "NAME", "Specify an alternate project name (default: directory name)"
|
12
|
+
|
13
|
+
attr_reader :service_prefix
|
10
14
|
|
11
15
|
def execute
|
12
16
|
require 'highline/import'
|
13
17
|
|
18
|
+
@service_prefix = project_name || File.basename(Dir.getwd)
|
19
|
+
|
14
20
|
if File.exist?('Dockerfile')
|
15
21
|
puts 'Found Dockerfile'
|
16
22
|
else
|
@@ -20,7 +26,21 @@ module Kontena::Cli::Apps
|
|
20
26
|
if File.exist?(docker_compose_file)
|
21
27
|
puts "Found #{docker_compose_file}."
|
22
28
|
else
|
23
|
-
|
29
|
+
if File.exist?('Procfile')
|
30
|
+
procfile = YAML.load(File.read('Procfile'))
|
31
|
+
else
|
32
|
+
procfile = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
app_env = nil
|
36
|
+
addons = []
|
37
|
+
|
38
|
+
if app_json
|
39
|
+
app_env = create_env_file(app_json)
|
40
|
+
addons = app_json['addons'] || []
|
41
|
+
end
|
42
|
+
|
43
|
+
create_docker_compose_yml(procfile, addons, app_env) if create_docker_compose_yml?
|
24
44
|
end
|
25
45
|
|
26
46
|
services = generate_kontena_services(docker_compose_file)
|
@@ -32,18 +52,44 @@ module Kontena::Cli::Apps
|
|
32
52
|
end
|
33
53
|
create_yml(services, 'kontena.yml')
|
34
54
|
|
35
|
-
puts "
|
55
|
+
puts "Your app is ready! Deploy with 'kontena app deploy'.".colorize(:green)
|
36
56
|
end
|
37
57
|
|
38
58
|
|
39
59
|
protected
|
60
|
+
|
61
|
+
def app_json
|
62
|
+
if !@app_json && File.exist?('app.json')
|
63
|
+
@app_json = JSON.parse(File.read('app.json'))
|
64
|
+
end
|
65
|
+
@app_json
|
66
|
+
end
|
67
|
+
|
40
68
|
def create_dockerfile?
|
41
|
-
|
69
|
+
['', 'y', 'yes'].include? ask('Dockerfile not found. Do you want to create it? [Yn]: ').downcase
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_env_file(app_json)
|
73
|
+
|
74
|
+
if app_json['env']
|
75
|
+
app_env = File.new('.env', 'w')
|
76
|
+
app_json['env'].each do |key, env|
|
77
|
+
if env['generator'] == 'secret'
|
78
|
+
value = SecureRandom.hex(64)
|
79
|
+
else
|
80
|
+
value = env['value']
|
81
|
+
end
|
82
|
+
app_env.puts "#{key}=#{value}"
|
83
|
+
end
|
84
|
+
app_env.close
|
85
|
+
return '.env'
|
86
|
+
end
|
87
|
+
nil
|
42
88
|
end
|
43
89
|
|
44
90
|
def current_user
|
45
91
|
token = require_token
|
46
|
-
client(token).get('user')
|
92
|
+
client(token).get('user') rescue ''
|
47
93
|
end
|
48
94
|
|
49
95
|
def create_dockerfile
|
@@ -51,6 +97,7 @@ module Kontena::Cli::Apps
|
|
51
97
|
dockerfile = File.new('Dockerfile', 'w')
|
52
98
|
dockerfile.puts "FROM #{base_image}"
|
53
99
|
dockerfile.puts "MAINTAINER #{current_user['email']}"
|
100
|
+
dockerfile.puts 'CMD ["/start", "web"]'
|
54
101
|
dockerfile.close
|
55
102
|
end
|
56
103
|
|
@@ -65,28 +112,69 @@ module Kontena::Cli::Apps
|
|
65
112
|
end
|
66
113
|
|
67
114
|
def create_docker_compose_yml?
|
68
|
-
|
115
|
+
['', 'y', 'yes'].include? ask("#{docker_compose_file} not found. Do you want to create it? [Yn]: ").downcase
|
69
116
|
end
|
70
117
|
|
71
|
-
def create_docker_compose_yml
|
118
|
+
def create_docker_compose_yml(procfile, addons, env_file)
|
72
119
|
puts "Creating #{docker_compose_file.colorize(:cyan)}"
|
73
|
-
|
120
|
+
if procfile.keys.size > 0
|
121
|
+
# generate services found in Procfile
|
122
|
+
docker_compose = {}
|
123
|
+
procfile.keys.each do |service|
|
124
|
+
docker_compose[service] = {'build' => '.' }
|
125
|
+
docker_compose[service]['environment'] = ['PORT=5000'] if app_json && service == 'web' # Heroku generates PORT env variable so should we do too
|
126
|
+
docker_compose[service]['command'] = "/start #{service}" if service != 'web'
|
127
|
+
docker_compose[service]['env_file'] = env_file if env_file
|
128
|
+
|
129
|
+
# generate addon services
|
130
|
+
addons.each do |addon|
|
131
|
+
addon_service = addon.split(":")[0]
|
132
|
+
addon_service.slice!('heroku-')
|
133
|
+
if valid_addons.has_key?(addon_service)
|
134
|
+
docker_compose[service]['links'] = [] unless docker_compose[service]['links']
|
135
|
+
docker_compose[service]['links'] << "#{addon_service}:#{addon_service}"
|
136
|
+
docker_compose[service]['environment'] = [] unless docker_compose[service]['environment']
|
137
|
+
docker_compose[service]['environment'] += valid_addons[addon_service]['environment']
|
138
|
+
docker_compose[addon_service] = {'image' => valid_addons[addon_service]['image']}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
else
|
143
|
+
# no Procfile found, create dummy web service
|
144
|
+
docker_compose = {'web' => { 'build' => '.'}}
|
145
|
+
docker_compose['web']['env_file'] = env_file if env_file
|
146
|
+
end
|
147
|
+
# create docker-compose.yml file
|
148
|
+
create_yml(docker_compose, docker_compose_file)
|
74
149
|
end
|
75
150
|
|
76
151
|
def generate_kontena_services(docker_compose = nil)
|
77
152
|
services = {}
|
78
153
|
if docker_compose && File.exist?(docker_compose)
|
154
|
+
# extend services from docker-compose.yml
|
79
155
|
compose_services = YAML.load(File.read(docker_compose))
|
80
156
|
compose_services.each do |name, options|
|
81
157
|
services[name] = {'extends' => { 'file' => 'docker-compose.yml', 'service' => name }}
|
82
158
|
if options.has_key?('build')
|
83
|
-
image = image_name || "registry.kontena.local/#{File.basename(Dir.getwd)}
|
159
|
+
image = image_name || "registry.kontena.local/#{File.basename(Dir.getwd)}:latest"
|
84
160
|
services[name]['image'] = image
|
85
|
-
|
161
|
+
end
|
162
|
+
|
163
|
+
# we have to generate Kontena urls to env vars for Heroku addons
|
164
|
+
# redis://openredis:6379 -> redis://project-name-openredis:6379
|
165
|
+
if options['links']
|
166
|
+
options['links'].each do |link|
|
167
|
+
service_link = link.split(':').first
|
168
|
+
if valid_addons.has_key?(service_link)
|
169
|
+
services[name]['environment'] ||= []
|
170
|
+
services[name]['environment'] += valid_addons(service_prefix)[service_link]['environment']
|
171
|
+
end
|
172
|
+
end
|
86
173
|
end
|
87
174
|
end
|
88
175
|
else
|
89
|
-
|
176
|
+
# no docker-compose.yml found, just create dummy service with image name
|
177
|
+
services = {'web' => { 'image' => "registry.kontena.local/#{File.basename(Dir.getwd)}:latest" }}
|
90
178
|
end
|
91
179
|
services
|
92
180
|
end
|
@@ -97,5 +185,37 @@ module Kontena::Cli::Apps
|
|
97
185
|
yml.close
|
98
186
|
end
|
99
187
|
|
188
|
+
def valid_addons(prefix=nil)
|
189
|
+
if prefix
|
190
|
+
prefix = "#{prefix}-"
|
191
|
+
end
|
192
|
+
|
193
|
+
{
|
194
|
+
'openredis' => {
|
195
|
+
'image' => 'redis:latest',
|
196
|
+
'environment' => ["REDIS_URL=redis://#{prefix}openredis:6379"]
|
197
|
+
},
|
198
|
+
'redis' => {
|
199
|
+
'image' => 'redis:latest',
|
200
|
+
'environment' => ["REDIS_URL=redis://#{prefix}redis:6379"]
|
201
|
+
},
|
202
|
+
'rediscloud' => {
|
203
|
+
'image' => 'redis:latest',
|
204
|
+
'environment' => ["REDISCLOUD_URL=#{prefix}redis://rediscloud:6379"]
|
205
|
+
},
|
206
|
+
'postgresql' => {
|
207
|
+
'image' => 'postgres:latest',
|
208
|
+
'environment' => ["DATABASE_URL=postgres://#{prefix}postgres:@postgresql:5432/postgres"]
|
209
|
+
},
|
210
|
+
'mongolab' => {
|
211
|
+
'image' => 'mongo:latest',
|
212
|
+
'environment' => ["MONGOLAB_URI=#{prefix}mongolab:27017"]
|
213
|
+
},
|
214
|
+
'memcachedcloud' => {
|
215
|
+
'image' => 'memcached:latest',
|
216
|
+
'enviroment' => ["MEMCACHEDCLOUD_SERVERS=#{prefix}memcachedcloud:11211"]
|
217
|
+
}
|
218
|
+
}
|
219
|
+
end
|
100
220
|
end
|
101
221
|
end
|