kontena-cli 0.8.4 → 0.9.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.
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