kontena-cli 1.0.2 → 1.0.3.rc1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e12d72f9f29547dfcfa19d475d01f78b2e9398f
4
- data.tar.gz: c705ed180718c7bf37ceb1f6b42d71a422ebea0d
3
+ metadata.gz: 1fea7cc00f263ca36c6b676cb044a5a3648dc0b8
4
+ data.tar.gz: d7aae3f41c4f9dab103e01114bfff4401088292f
5
5
  SHA512:
6
- metadata.gz: 26378859f0abaa499a9e958743c1d26cd08adb0ab8e9d2cf145d254b9e7283d4f99861dbab39204fcdfc2fc405f0a611ec5d40013af62019c8a84ff1450064fb
7
- data.tar.gz: c63b8f577000b8b29234e1c402d590ffba2d985afc2931d52e4dd5c5f89488ae3254efee3a84e379deae209e447d151b8df035f8ee25d658ffaddcd7127a1678
6
+ metadata.gz: 92c78f93962b972872fc150b600cccc704711e97956e63d4f2dc9a74784c1b0ee007b26902f0df27dd26bfebcd5a93ede3ae0a5535f3fad9d156dfcc8898a060
7
+ data.tar.gz: 5a562d665b421e8c78af8c73e8ad7a9c4cad963ef3804f815f170e31f5dcb6b0be9dd648cdea90769fd86932c27e72d0548815d7d2aab887d64c2a455aba0784
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.2
1
+ 1.0.3.rc1
data/kontena-cli.gemspec CHANGED
@@ -31,4 +31,5 @@ Gem::Specification.new do |spec|
31
31
  spec.add_runtime_dependency "retriable", "~> 2.1.0"
32
32
  spec.add_runtime_dependency "opto", "~> 1.5.3"
33
33
  spec.add_runtime_dependency "semantic", "~> 1.5"
34
+ spec.add_runtime_dependency "safe_yaml", "~> 1.0"
34
35
  end
@@ -25,12 +25,12 @@ module Kontena::Cli::Apps
25
25
  end
26
26
 
27
27
  if File.exist?('Procfile')
28
- procfile = ::YAML.load(File.read('Procfile'))
28
+ procfile = ::YAML.safe_load(File.read('Procfile'))
29
29
  else
30
30
  procfile = {}
31
31
  end
32
32
 
33
- app_env = create_env_file(app_json['env']) if app_json['env']
33
+ app_env = create_env_file(app_json['env']) if app_json['env']
34
34
  addons = app_json['addons'] || []
35
35
 
36
36
  if File.exist?(docker_compose_file)
@@ -45,7 +45,7 @@ module Kontena::Cli::Apps
45
45
  end
46
46
 
47
47
  def yml_services(file)
48
- yml = ::YAML.load(file)
48
+ yml = ::YAML.safe_load(file)
49
49
  if yml['version'] == '2'
50
50
  yml['services']
51
51
  else
@@ -29,7 +29,7 @@ module Kontena::Cli::Apps
29
29
  result[:name] = yaml['name']
30
30
  result[:errors] = errors
31
31
  result[:notifications] = notifications
32
- result[:services] = parse_services(service_name) unless errors.count > 0
32
+ result[:services] = errors.count == 0 ? parse_services(service_name) : {}
33
33
  end
34
34
  result
35
35
  end
@@ -52,7 +52,7 @@ module Kontena::Cli::Apps
52
52
  interpolate(content)
53
53
  replace_dollar_dollars(content)
54
54
  begin
55
- @yaml = ::YAML.load(content)
55
+ @yaml = ::YAML.safe_load(content)
56
56
  rescue Psych::SyntaxError => e
57
57
  raise "Error while parsing #{file}".colorize(:red)+ " "+e.message
58
58
  end
@@ -41,7 +41,7 @@ module Kontena::Cli::Master::Config
41
41
  JSON.parse(data)
42
42
  when 'yaml', 'yml'
43
43
  require 'yaml'
44
- YAML.load(data)
44
+ YAML.safe_load(data)
45
45
  else
46
46
  exit_with_error "Unknown input format '#{self.format}'"
47
47
  end
@@ -15,7 +15,7 @@ module Kontena::Cli::Services
15
15
  require_api_url
16
16
 
17
17
  query_params = {}
18
- query_params[:container] = "#{name}-#{instance}" if instance
18
+ query_params[:container] = parse_container_name(name, instance) if instance
19
19
 
20
20
  show_logs("services/#{parse_service_id(name)}/container_logs", query_params) do |log|
21
21
  show_log(log)
@@ -283,6 +283,17 @@ module Kontena
283
283
  end
284
284
  end
285
285
 
286
+ # Parses container name based on service name and instance number
287
+ # @param [String] service_name
288
+ # @param [Integer] instance_number
289
+ def parse_container_name(service_name, instance_number)
290
+ base = service_name.gsub('/', '-')
291
+ unless service_name.include?('/')
292
+ base = "null-#{base}"
293
+ end
294
+ "#{base}-#{instance_number}"
295
+ end
296
+
286
297
  # @param [Array<String>] port_options
287
298
  # @return [Array<Hash>]
288
299
  def parse_ports(port_options)
@@ -15,12 +15,14 @@ module Kontena::Cli::Stacks
15
15
 
16
16
  def execute
17
17
  require_config_file(filename)
18
- services = Kontena::Cli::Stacks::YAML::Reader.new(filename).execute[:services]
18
+ stack = stack_from_yaml(filename)
19
+ services = stack['services']
20
+
19
21
  unless service_list.empty?
20
- services.select! { |name, _| service_list.include?(name) }
22
+ services.select! { |service| service_list.include?(service['name']) }
21
23
  end
22
24
 
23
- if services.none?{ |name, service| service['build'] }
25
+ if services.none?{ |service| service['build'] }
24
26
  abort 'Not found any service with a build option'.colorize(:red)
25
27
  end
26
28
  build_docker_images(services, no_cache?, no_pull?)
@@ -31,7 +33,7 @@ module Kontena::Cli::Stacks
31
33
  # @param [Boolean] no_cache
32
34
  # @param [Boolean] no_pull
33
35
  def build_docker_images(services, no_cache = false, no_pull = false)
34
- services.each do |name, service|
36
+ services.each do |service|
35
37
  if service['build']
36
38
  dockerfile = service['build']['dockerfile'] || 'Dockerfile'
37
39
  abort("'#{service['image']}' is not valid Docker image name") unless validate_image_name(service['image'])
@@ -48,7 +50,7 @@ module Kontena::Cli::Stacks
48
50
 
49
51
  # @param [Hash] services
50
52
  def push_docker_images(services)
51
- services.each do |name, service|
53
+ services.each do |service|
52
54
  if service['build']
53
55
  puts "Pushing image #{service['image'].colorize(:cyan)}"
54
56
  push_docker_image(service['image'])
@@ -15,7 +15,7 @@ module Kontena::Cli::Stacks::Registry
15
15
  def execute
16
16
  require 'semantic'
17
17
  unless versions?
18
- stack = ::YAML.load(stacks_client.show(stack_name, stack_version))
18
+ stack = ::YAML.safe_load(stacks_client.show(stack_name, stack_version))
19
19
  puts "#{stack['stack']}:"
20
20
  puts " #{"latest_" unless stack_version}version: #{stack['version']}"
21
21
  puts " expose: #{stack['expose'] || '-'}"
@@ -44,7 +44,7 @@ module Kontena::Cli::Stacks
44
44
  return @variables if @variables
45
45
  if yaml && yaml.has_key?('variables')
46
46
  variables_yaml = yaml['variables'].to_yaml
47
- variables_hash = ::YAML.load(replace_dollar_dollars(interpolate(variables_yaml, use_opto: false)))
47
+ variables_hash = ::YAML.safe_load(replace_dollar_dollars(interpolate(variables_yaml, use_opto: false)))
48
48
  @variables = Opto::Group.new(variables_hash, defaults: { from: :env, to: :env })
49
49
  else
50
50
  @variables = Opto::Group.new(defaults: { from: :env, to: :env })
@@ -75,14 +75,14 @@ module Kontena::Cli::Stacks
75
75
  result[:expose] = yaml['expose']
76
76
  result[:errors] = errors unless skip_validation?
77
77
  result[:notifications] = notifications
78
- result[:services] = parse_services(service_name) unless errors.count > 0
78
+ result[:services] = errors.count == 0 ? parse_services(service_name) : {}
79
79
  result[:variables] = variables.to_h(values_only: true).reject { |k,_| variables.option(k).to.has_key?(:vault) } unless skip_variables?
80
80
  end
81
81
  result
82
82
  end
83
83
 
84
84
  def stack_name
85
- yaml = ::YAML.load(raw_content)
85
+ yaml = ::YAML.safe_load(raw_content)
86
86
  yaml['stack'].split('/').last.split(':').first if yaml['stack']
87
87
  end
88
88
 
@@ -101,9 +101,9 @@ module Kontena::Cli::Stacks
101
101
 
102
102
  def load_yaml(interpolate = true)
103
103
  if interpolate
104
- @yaml = ::YAML.load(replace_dollar_dollars(interpolate(raw_content)))
104
+ @yaml = ::YAML.safe_load(replace_dollar_dollars(interpolate(raw_content)))
105
105
  else
106
- @yaml = ::YAML.load(raw_content)
106
+ @yaml = ::YAML.safe_load(raw_content)
107
107
  end
108
108
  rescue Psych::SyntaxError => e
109
109
  raise "Error while parsing #{file}".colorize(:red)+ " "+e.message
@@ -72,7 +72,7 @@ class Helper
72
72
 
73
73
  def yml_services
74
74
  if File.exist?('kontena.yml')
75
- yaml = YAML.load(File.read('kontena.yml'))
75
+ yaml = YAML.safe_load(File.read('kontena.yml'))
76
76
  services = yaml['services']
77
77
  services.keys
78
78
  end
@@ -23,7 +23,7 @@ module Kontena
23
23
  end
24
24
 
25
25
  def load
26
- YAML.load(read)
26
+ YAML.safe_load(read)
27
27
  end
28
28
 
29
29
  def write(content)
@@ -78,7 +78,7 @@ module Kontena
78
78
  else
79
79
  dputs "Retrieving #{stack.stack}:#{stack.version} from registry"
80
80
  content = client.pull(stack.stack, stack.version)
81
- yaml = ::YAML.load(content)
81
+ yaml = ::YAML.safe_load(content)
82
82
  new_stack = CachedStack.new(yaml['stack'], yaml['version'])
83
83
  if new_stack.cached?
84
84
  dputs "Already cached"
data/lib/kontena_cli.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  module Kontena
2
2
  # Run a kontena command like it was launched from the command line.
3
- #
3
+ #
4
4
  # @example
5
5
  # Kontena.run("grid list --help")
6
6
  #
7
- # @param [String] command_line
7
+ # @param [String] command_line
8
8
  # @return [Fixnum] exit_code
9
9
  def self.run(cmdline = "", returning: :status)
10
10
  ENV["DEBUG"] && puts("Running Kontena.run(#{cmdline.inspect}, returning: #{returning}")
@@ -19,7 +19,7 @@ module Kontena
19
19
  ENV["DEBUG"] && puts("Command raised #{$!} with message: #{$!.message}\n #{$!.backtrace.join(" \n")}")
20
20
  returning == :status ? 1 : nil
21
21
  end
22
-
22
+
23
23
 
24
24
  def self.version
25
25
  "kontena-cli/#{Kontena::Cli::VERSION}"
@@ -61,6 +61,8 @@ end
61
61
 
62
62
  require 'ruby_dig'
63
63
  require 'shellwords'
64
+ require "safe_yaml"
65
+ SafeYAML::OPTIONS[:default_mode] = :safe
64
66
  require_relative 'kontena/cli/version'
65
67
  require_relative 'kontena/cli/common'
66
68
  require_relative 'kontena/command'
@@ -0,0 +1,12 @@
1
+ version: '2'
2
+ services:
3
+ wordpress:
4
+ image: wordpress:4.1
5
+ ports:
6
+ - 80:80
7
+ depends_on:
8
+ - mysql
9
+ networks:
10
+ - front
11
+ mysql:
12
+ image: mysql:5.6
@@ -6,7 +6,7 @@ variables:
6
6
  required: true
7
7
  min_length: 10
8
8
  empty_is_nil: true
9
- from:
9
+ from:
10
10
  env: WORDPRESS_DB_PASSWORD # first try from local env
11
11
  random_string: # if prompt returned nil, generate a random string
12
12
  length: 10
@@ -19,10 +19,10 @@ variables:
19
19
  random_string:
20
20
  length: 16
21
21
  charset: hex
22
- to:
22
+ to:
23
23
  env: test_var
24
24
  TEST_ENV_VAR: # the default from/to is to set/read env of the option name
25
- type: :string
25
+ type: string
26
26
 
27
27
  services:
28
28
  wordpress:
@@ -33,7 +33,7 @@ services:
33
33
  stateful: true
34
34
  environment:
35
35
  - WORDPRESS_DB_PASSWORD=${STACK}_secret
36
- secrets:
36
+ secrets:
37
37
  - secret: WP_ADMIN_PASSWORD
38
38
  name: WORDPRESS_PASSWORD
39
39
  type: env
@@ -49,7 +49,7 @@ services:
49
49
  service: mysql
50
50
  image: ${MYSQL_IMAGE}
51
51
  stateful: true
52
- secrets:
52
+ secrets:
53
53
  - secret: WP_MYSQL_ROOT_PW
54
54
  name: MYSQL_PASSWORD
55
55
  type: env
@@ -106,7 +106,7 @@ describe Kontena::Cli::Apps::DeployCommand do
106
106
  allow(subject).to receive(:current_dir).and_return("kontena-test")
107
107
  services['wordpress']['environment'] = ['MYSQL_ADMIN_PASSWORD=password']
108
108
  services['wordpress']['env_file'] = %w(/path/to/env_file .env)
109
- allow(YAML).to receive(:load).and_return(services)
109
+ allow(YAML).to receive(:safe_load).and_return(services)
110
110
 
111
111
  expect(File).to receive(:readlines).with('/path/to/env_file').and_return(env_vars)
112
112
  expect(File).to receive(:readlines).with('.env').and_return(dot_env)
@@ -127,7 +127,7 @@ describe Kontena::Cli::Apps::DeployCommand do
127
127
  allow(subject).to receive(:current_dir).and_return("kontena-test")
128
128
  services['wordpress']['environment'] = ['MYSQL_ADMIN_PASSWORD=password']
129
129
  services['wordpress']['env_file'] = '/path/to/env_file'
130
- allow(YAML).to receive(:load).and_return(services)
130
+ allow(YAML).to receive(:safe_load).and_return(services)
131
131
 
132
132
  expect(File).to receive(:readlines).with('/path/to/env_file').and_return(env_vars)
133
133
 
@@ -145,7 +145,7 @@ describe Kontena::Cli::Apps::DeployCommand do
145
145
  it 'merges external links to links' do
146
146
  allow(subject).to receive(:current_dir).and_return("kontena-test")
147
147
  services['wordpress']['external_links'] = ['loadbalancer:loadbalancer']
148
- allow(YAML).to receive(:load).and_return(services)
148
+ allow(YAML).to receive(:safe_load).and_return(services)
149
149
  data = {
150
150
  'name' => 'kontena-test-wordpress',
151
151
  'image' => 'wordpress:latest',
@@ -159,6 +159,16 @@ module Kontena::Cli::Services
159
159
  end
160
160
  end
161
161
 
162
+ describe '#parse_container_name' do
163
+ it 'parses stack services id properly' do
164
+ expect(subject.parse_container_name('foo/mysql', 1)).to eq('foo-mysql-1')
165
+ end
166
+
167
+ it 'parses stackless services id properly' do
168
+ expect(subject.parse_container_name('mysql', 1)).to eq('null-mysql-1')
169
+ end
170
+ end
171
+
162
172
  describe '#parse_image' do
163
173
  it 'adds :default tag if no tag exist' do
164
174
  expect(subject.parse_image('nginx')).to eq('nginx:latest')
@@ -0,0 +1,60 @@
1
+ require_relative "../../../spec_helper"
2
+ require "kontena/cli/stacks/build_command"
3
+
4
+ describe Kontena::Cli::Stacks::BuildCommand do
5
+
6
+ let(:subject) do
7
+ described_class.new(File.basename($0))
8
+ end
9
+
10
+ describe '#execute' do
11
+ let(:stack) do
12
+ {
13
+ 'name' => 'stack-a',
14
+ 'stack' => 'user/stack-a',
15
+ 'version' => '1.0.0',
16
+ 'services' => [
17
+ service
18
+ ]
19
+ }
20
+ end
21
+
22
+ let(:service) do
23
+ {
24
+ 'name' => 'test',
25
+ 'image' => 'registry.kontena.local/test:latest',
26
+ 'build' => {
27
+ 'context' => File.expand_path('.')
28
+ }
29
+ }
30
+ end
31
+
32
+ describe '#execute' do
33
+ before(:each) do
34
+ allow(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
35
+ allow(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
36
+ allow(subject).to receive(:system).and_return(true)
37
+ end
38
+
39
+ it 'requires config file' do
40
+ expect(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
41
+ subject.run([])
42
+ end
43
+
44
+ it 'reads stack file' do
45
+ expect(subject).to receive(:stack_from_yaml).with('kontena.yml').and_return(stack)
46
+ subject.run([])
47
+ end
48
+
49
+ it 'builds docker image' do
50
+ expect(subject).to receive(:system).with('docker', 'build', '-t', 'registry.kontena.local/test:latest', '--pull', File.expand_path('.'))
51
+ subject.run([])
52
+ end
53
+
54
+ it 'pushes docker image' do
55
+ expect(subject).to receive(:system).with('docker', 'push', 'registry.kontena.local/test:latest')
56
+ subject.run([])
57
+ end
58
+ end
59
+ end
60
+ end
@@ -141,6 +141,23 @@ describe Kontena::Cli::Stacks::YAML::Reader do
141
141
  expect(service_extender).to receive(:extend_from).with(kontena_yml['services']['base'])
142
142
  subject.execute
143
143
  end
144
+
145
+ it 'merges validation errors' do
146
+ allow(File).to receive(:read)
147
+ .with(absolute_yaml_path('docker-compose_v2.yml'))
148
+ .and_return(fixture('docker-compose-invalid.yml'))
149
+ outcome = subject.execute
150
+ expect(outcome[:errors]).to eq([{
151
+ 'docker-compose_v2.yml' =>[
152
+ {
153
+ 'wordpress' => {
154
+ 'networks' => 'key not expected'
155
+ }
156
+ }
157
+ ]
158
+ }])
159
+ end
160
+
144
161
  end
145
162
 
146
163
  context 'variable interpolation' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kontena-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kontena, Inc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-15 00:00:00.000000000 Z
11
+ date: 2016-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '1.5'
167
+ - !ruby/object:Gem::Dependency
168
+ name: safe_yaml
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1.0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.0'
167
181
  description: Kontena command line tool
168
182
  email:
169
183
  - info@kontena.io
@@ -440,6 +454,7 @@ files:
440
454
  - lib/kontena/util.rb
441
455
  - lib/kontena_cli.rb
442
456
  - spec/fixtures/app.json
457
+ - spec/fixtures/docker-compose-invalid.yml
443
458
  - spec/fixtures/docker-compose.yml
444
459
  - spec/fixtures/docker-compose_v2.yml
445
460
  - spec/fixtures/health.yml
@@ -507,6 +522,7 @@ files:
507
522
  - spec/kontena/cli/services/services_helper_spec.rb
508
523
  - spec/kontena/cli/services/unlink_command_spec.rb
509
524
  - spec/kontena/cli/services/update_command_spec.rb
525
+ - spec/kontena/cli/stacks/build_command_spec.rb
510
526
  - spec/kontena/cli/stacks/deploy_command_spec.rb
511
527
  - spec/kontena/cli/stacks/install_command_spec.rb
512
528
  - spec/kontena/cli/stacks/list_command_spec.rb
@@ -544,9 +560,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
544
560
  version: 2.0.0
545
561
  required_rubygems_version: !ruby/object:Gem::Requirement
546
562
  requirements:
547
- - - ">="
563
+ - - ">"
548
564
  - !ruby/object:Gem::Version
549
- version: '0'
565
+ version: 1.3.1
550
566
  requirements: []
551
567
  rubyforge_project:
552
568
  rubygems_version: 2.5.1
@@ -555,6 +571,7 @@ specification_version: 4
555
571
  summary: Kontena command line tool
556
572
  test_files:
557
573
  - spec/fixtures/app.json
574
+ - spec/fixtures/docker-compose-invalid.yml
558
575
  - spec/fixtures/docker-compose.yml
559
576
  - spec/fixtures/docker-compose_v2.yml
560
577
  - spec/fixtures/health.yml
@@ -622,6 +639,7 @@ test_files:
622
639
  - spec/kontena/cli/services/services_helper_spec.rb
623
640
  - spec/kontena/cli/services/unlink_command_spec.rb
624
641
  - spec/kontena/cli/services/update_command_spec.rb
642
+ - spec/kontena/cli/stacks/build_command_spec.rb
625
643
  - spec/kontena/cli/stacks/deploy_command_spec.rb
626
644
  - spec/kontena/cli/stacks/install_command_spec.rb
627
645
  - spec/kontena/cli/stacks/list_command_spec.rb