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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/kontena +4 -0
  4. data/lib/kontena/cli/app_command.rb +2 -0
  5. data/lib/kontena/cli/apps/build_command.rb +26 -0
  6. data/lib/kontena/cli/apps/common.rb +41 -12
  7. data/lib/kontena/cli/apps/deploy_command.rb +31 -13
  8. data/lib/kontena/cli/apps/docker_helper.rb +34 -0
  9. data/lib/kontena/cli/apps/init_command.rb +130 -10
  10. data/lib/kontena/cli/apps/list_command.rb +4 -2
  11. data/lib/kontena/cli/apps/logs_command.rb +4 -2
  12. data/lib/kontena/cli/apps/remove_command.rb +4 -2
  13. data/lib/kontena/cli/apps/start_command.rb +4 -2
  14. data/lib/kontena/cli/apps/stop_command.rb +4 -2
  15. data/lib/kontena/cli/common.rb +3 -3
  16. data/lib/kontena/cli/container_command.rb +3 -0
  17. data/lib/kontena/cli/containers/inspect_command.rb +16 -0
  18. data/lib/kontena/cli/deploy_command.rb +3 -0
  19. data/lib/kontena/cli/etcd/get_command.rb +21 -0
  20. data/lib/kontena/cli/etcd/list_command.rb +26 -0
  21. data/lib/kontena/cli/etcd/mkdir_command.rb +17 -0
  22. data/lib/kontena/cli/etcd/remove_command.rb +21 -0
  23. data/lib/kontena/cli/etcd/set_command.rb +18 -0
  24. data/lib/kontena/cli/etcd_command.rb +17 -0
  25. data/lib/kontena/cli/grid_command.rb +2 -0
  26. data/lib/kontena/cli/grids/logs_command.rb +71 -0
  27. data/lib/kontena/cli/master/aws/create_command.rb +33 -0
  28. data/lib/kontena/cli/master/aws_command.rb +8 -0
  29. data/lib/kontena/cli/master/azure/create_command.rb +33 -0
  30. data/lib/kontena/cli/master/azure_command.rb +13 -0
  31. data/lib/kontena/cli/master/digital_ocean/create_command.rb +30 -0
  32. data/lib/kontena/cli/master/digital_ocean_command.rb +13 -0
  33. data/lib/kontena/cli/master/vagrant/create_command.rb +19 -0
  34. data/lib/kontena/cli/master/vagrant/restart_command.rb +20 -0
  35. data/lib/kontena/cli/master/vagrant/ssh_command.rb +15 -0
  36. data/lib/kontena/cli/master/vagrant/start_command.rb +20 -0
  37. data/lib/kontena/cli/master/vagrant/stop_command.rb +20 -0
  38. data/lib/kontena/cli/master/vagrant/terminate_command.rb +13 -0
  39. data/lib/kontena/cli/master/vagrant_command.rb +23 -0
  40. data/lib/kontena/cli/master_command.rb +15 -0
  41. data/lib/kontena/cli/node_command.rb +4 -0
  42. data/lib/kontena/cli/nodes/aws/create_command.rb +39 -0
  43. data/lib/kontena/cli/nodes/aws/restart_command.rb +28 -0
  44. data/lib/kontena/cli/nodes/aws/terminate_command.rb +20 -0
  45. data/lib/kontena/cli/nodes/aws_command.rb +15 -0
  46. data/lib/kontena/cli/nodes/azure/create_command.rb +39 -0
  47. data/lib/kontena/cli/nodes/azure/restart_command.rb +31 -0
  48. data/lib/kontena/cli/nodes/azure/terminate_command.rb +20 -0
  49. data/lib/kontena/cli/nodes/azure_command.rb +15 -0
  50. data/lib/kontena/cli/nodes/digital_ocean/create_command.rb +1 -1
  51. data/lib/kontena/cli/nodes/vagrant/create_command.rb +1 -1
  52. data/lib/kontena/cli/service_command.rb +4 -0
  53. data/lib/kontena/cli/services/add_env_command.rb +18 -0
  54. data/lib/kontena/cli/services/create_command.rb +8 -0
  55. data/lib/kontena/cli/services/remove_env_command.rb +17 -0
  56. data/lib/kontena/cli/services/services_helper.rb +20 -1
  57. data/lib/kontena/cli/services/update_command.rb +10 -0
  58. data/lib/kontena/client.rb +22 -1
  59. data/lib/kontena/machine/aws.rb +13 -0
  60. data/lib/kontena/machine/aws/cloudinit.yml +66 -0
  61. data/lib/kontena/machine/aws/cloudinit_master.yml +105 -0
  62. data/lib/kontena/machine/aws/master_provisioner.rb +161 -0
  63. data/lib/kontena/machine/aws/node_destroyer.rb +39 -0
  64. data/lib/kontena/machine/aws/node_provisioner.rb +168 -0
  65. data/lib/kontena/machine/azure.rb +13 -0
  66. data/lib/kontena/machine/azure/cloudinit.yml +59 -0
  67. data/lib/kontena/machine/azure/cloudinit_master.yml +105 -0
  68. data/lib/kontena/machine/azure/logger.rb +27 -0
  69. data/lib/kontena/machine/azure/master_provisioner.rb +126 -0
  70. data/lib/kontena/machine/azure/node_destroyer.rb +53 -0
  71. data/lib/kontena/machine/azure/node_provisioner.rb +128 -0
  72. data/lib/kontena/machine/digital_ocean.rb +1 -0
  73. data/lib/kontena/machine/digital_ocean/cloudinit.yml +1 -0
  74. data/lib/kontena/machine/digital_ocean/cloudinit_master.yml +105 -0
  75. data/lib/kontena/machine/digital_ocean/master_provisioner.rb +94 -0
  76. data/lib/kontena/machine/digital_ocean/node_provisioner.rb +8 -1
  77. data/lib/kontena/machine/vagrant.rb +2 -0
  78. data/lib/kontena/machine/vagrant/Vagrantfile.master.rb.erb +101 -0
  79. data/lib/kontena/machine/vagrant/{Vagrantfile.coreos.rb.erb → Vagrantfile.node.rb.erb} +0 -0
  80. data/lib/kontena/machine/vagrant/cloudinit.yml +2 -1
  81. data/lib/kontena/machine/vagrant/master_destroyer.rb +37 -0
  82. data/lib/kontena/machine/vagrant/master_provisioner.rb +75 -0
  83. data/lib/kontena/machine/vagrant/node_destroyer.rb +4 -0
  84. data/lib/kontena/machine/vagrant/node_provisioner.rb +1 -1
  85. data/lib/kontena/scripts/completer +29 -3
  86. data/spec/kontena/cli/app/common_spec.rb +61 -0
  87. data/spec/kontena/cli/app/deploy_command_spec.rb +25 -6
  88. data/spec/kontena/cli/app/docker_helper_spec.rb +32 -0
  89. data/spec/kontena/cli/common_spec.rb +53 -0
  90. metadata +61 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0628f196135c9957f21c05c15285a0f371189591
4
- data.tar.gz: 11a863701cb5882231050becdc6580785d32d8cb
3
+ metadata.gz: 5495634079f9438b5489ef1b059675ecd1b1816e
4
+ data.tar.gz: 2f2d23237da702fe1dd1919a83621d004d129d9a
5
5
  SHA512:
6
- metadata.gz: 889e623ca9d6d28f7539b32f71ef88b7e885e7a9f23210fbdddda03a7b0f039c0d4eb736295d8c56724389a1b5fdce410ba8a49e0d4276bac4242ed7083d8ad0
7
- data.tar.gz: fe438888d3eee5e24d4ef5b06e94cd7a81030de268509fa9e98619a510dbf71d45dd2bfb671d4e1a708e1f9cc136c754876ec71675f7d7f81fe4fb2bd9d7c908
6
+ metadata.gz: e44eaeae82ce15d7e09cb238cca449c8d7cfcf9ce666018dc8daa89aceb5a8ddc00a5077d5dbfe81aaae71a7ccb61f4e410054bc2f59dcbe13ed94ff6eacae08
7
+ data.tar.gz: 1a0ac1c623f49eb325c31d41cc108d0fabcce469848cca141b3b280827b6919f3f26a2456f4addac0ad378d74db41ed2ec47a86d67d62f5ad58018af620b95bd
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.4
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 load_services_from_yml
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
- services = parse_yml_file(filename, nil, service_prefix)
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 parse_yml_file(file, name = nil, prefix='')
36
- services = YAML.load(File.read(file) % {prefix: prefix})
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
- extends = options['extends']
41
+ extension_file = options['extends']['file']
42
+ service_name = options['extends']['service']
40
43
  options.delete('extends')
41
- services[name] = parse_yml_file(extends['file'], extends['service']).merge(options)
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
- @services = load_services_from_yml
20
- Dir.chdir(File.dirname(filename))
21
- init_services(services)
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 init_services(services)
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
- create_docker_compose_yml if create_docker_compose_yml?
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 "You are ready to go!".colorize(:green)
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
- %w(y yes).include? ask('Dockerfile not found. Do you want to create it? [Yn]: ').downcase
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
- %w(y yes).include? ask("#{docker_compose_file} not found. Do you want to create it? [Yn]: ").downcase
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
- create_yml({'app' => { 'build' => '.'}}, docker_compose_file)
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)}-#{name}:latest"
159
+ image = image_name || "registry.kontena.local/#{File.basename(Dir.getwd)}:latest"
84
160
  services[name]['image'] = image
85
- options.delete('build')
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
- services = {'app' => { 'image' => "registry.kontena.local/#{File.basename(Dir.getwd)}:latest" }}
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