kontena-cli 1.1.0.pre1 → 1.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +3 -9
  3. data/README.md +1 -1
  4. data/VERSION +1 -1
  5. data/examples/kontena-plugin-hello/kontena-plugin-hello.gemspec +1 -1
  6. data/kontena-cli.gemspec +3 -2
  7. data/lib/kontena/cli/cloud/master/add_command.rb +2 -2
  8. data/lib/kontena/cli/grids/common.rb +4 -0
  9. data/lib/kontena/cli/grids/create_command.rb +3 -1
  10. data/lib/kontena/cli/grids/update_command.rb +4 -0
  11. data/lib/kontena/cli/master/config/get_command.rb +4 -0
  12. data/lib/kontena/cli/master/remove_command.rb +10 -13
  13. data/lib/kontena/cli/master/ssh_command.rb +43 -0
  14. data/lib/kontena/cli/master_command.rb +3 -0
  15. data/lib/kontena/cli/nodes/ssh_command.rb +28 -13
  16. data/lib/kontena/cli/registry/create_command.rb +1 -1
  17. data/lib/kontena/cli/stack_command.rb +2 -0
  18. data/lib/kontena/cli/stacks/build_command.rb +25 -21
  19. data/lib/kontena/cli/stacks/common.rb +45 -3
  20. data/lib/kontena/cli/stacks/deploy_command.rb +5 -2
  21. data/lib/kontena/cli/stacks/install_command.rb +7 -3
  22. data/lib/kontena/cli/stacks/list_command.rb +4 -4
  23. data/lib/kontena/cli/stacks/registry/push_command.rb +7 -3
  24. data/lib/kontena/cli/stacks/show_command.rb +2 -1
  25. data/lib/kontena/cli/stacks/stacks_helper.rb +55 -5
  26. data/lib/kontena/cli/stacks/upgrade_command.rb +6 -3
  27. data/lib/kontena/cli/stacks/validate_command.rb +47 -0
  28. data/lib/kontena/cli/stacks/yaml/opto/prompt_resolver.rb +1 -6
  29. data/lib/kontena/cli/stacks/yaml/reader.rb +189 -100
  30. data/lib/kontena/debug_instrumentor.rb +1 -1
  31. data/lib/kontena_cli.rb +12 -5
  32. data/omnibus/.gitignore +12 -0
  33. data/omnibus/.kitchen.yml +44 -0
  34. data/omnibus/Berksfile +12 -0
  35. data/omnibus/Gemfile +22 -0
  36. data/omnibus/Gemfile.lock +183 -0
  37. data/omnibus/README.md +120 -0
  38. data/omnibus/config/projects/kontena.rb +33 -0
  39. data/omnibus/config/software/kontena.rb +13 -0
  40. data/omnibus/config/software/liblzma.rb +47 -0
  41. data/omnibus/omnibus.rb +56 -0
  42. data/omnibus/package-scripts/kontena/postinst +22 -0
  43. data/omnibus/package-scripts/kontena/postinstall +12 -0
  44. data/omnibus/package-scripts/kontena/postrm +9 -0
  45. data/omnibus/package-scripts/kontena/preinst +7 -0
  46. data/omnibus/package-scripts/kontena/prerm +15 -0
  47. data/omnibus/resources/kontena/pkg/distribution.xml.erb +22 -0
  48. data/omnibus/resources/kontena/pkg/license.html.erb +202 -0
  49. data/omnibus/resources/kontena/pkg/welcome.html.erb +5 -0
  50. data/omnibus/wrappers/sh/kontena +7 -0
  51. data/spec/fixtures/kontena-with-variables.yml +1 -1
  52. data/spec/fixtures/kontena_build_v3.yml +1 -1
  53. data/spec/fixtures/stack-with-invalid-liquid.yml +22 -0
  54. data/spec/fixtures/stack-with-liquid.yml +21 -0
  55. data/spec/fixtures/stack-with-prompted-variables.yml +10 -5
  56. data/spec/fixtures/stack-with-variables.yml +6 -1
  57. data/spec/kontena/cli/cloud/master/add_command_spec.rb +2 -2
  58. data/spec/kontena/cli/services/containers_command_spec.rb +2 -2
  59. data/spec/kontena/cli/stacks/build_command_spec.rb +37 -26
  60. data/spec/kontena/cli/stacks/install_command_spec.rb +6 -1
  61. data/spec/kontena/cli/stacks/upgrade_command_spec.rb +14 -18
  62. data/spec/kontena/cli/stacks/yaml/reader_spec.rb +76 -21
  63. data/spec/kontena/kontena_cli_spec.rb +28 -0
  64. data/spec/support/requirements_helper.rb +20 -2
  65. metadata +46 -5
@@ -4,7 +4,7 @@ services:
4
4
  mysql:
5
5
  stateful: true
6
6
  environment:
7
- - MYSQL_ROOT_PASSWORD=${project}_secret
7
+ - MYSQL_ROOT_PASSWORD=${STACK}_secret
8
8
 
9
9
  webapp:
10
10
  image: webapp
@@ -0,0 +1,22 @@
1
+ stack: user/stackname
2
+ version: 0.1.1
3
+ variables:
4
+ grid_name:
5
+ type: string
6
+ required: true
7
+ min_length: 10
8
+ empty_is_nil: true
9
+ value: "{{ GRID }} ${STACK}"
10
+ copies:
11
+ type: integer
12
+ value: 5
13
+
14
+ services:
15
+ # {% forx copy in (1..copies) %}
16
+ service-{{copy}}:
17
+ image: foo:{{copy}}
18
+ environment:
19
+ - TEST_VAR="{{ grid_name }}"
20
+ # {% endfor %}
21
+
22
+
@@ -0,0 +1,21 @@
1
+ stack: user/stackname
2
+ version: 0.1.1
3
+ variables:
4
+ grid_name:
5
+ type: string
6
+ required: true
7
+ min_length: 10
8
+ empty_is_nil: true
9
+ value: "{{ GRID }} ${STACK}"
10
+ copies:
11
+ type: integer
12
+ value: 5
13
+
14
+ services:
15
+ # {% for copy in (1..copies) %}
16
+ service-{{copy}}:
17
+ image: foo:{{copy}}
18
+ environment:
19
+ - TEST_VAR="{{ grid_name }}"
20
+ # {% endfor %}
21
+
@@ -3,7 +3,7 @@ version: 0.1.1
3
3
  variables:
4
4
  enum_test:
5
5
  type: enum
6
- options:
6
+ options:
7
7
  - Foo
8
8
  - Bar
9
9
  - Baz
@@ -13,7 +13,7 @@ variables:
13
13
  required: true
14
14
  min_length: 10
15
15
  empty_is_nil: true
16
- from:
16
+ from:
17
17
  env: WORDPRESS_DB_PASSWORD # first try from local env
18
18
  prompt: Enter a password for the wordpress instance # then try from prompt
19
19
  random_string: # if prompt returned nil, generate a random string
@@ -31,16 +31,21 @@ variables:
31
31
  env: test_var
32
32
  TEST_ENV_VAR: # the default from/to is to set/read env of the option name
33
33
  type: :string
34
+ TAG:
35
+ type: string
36
+ MYSQL_IMAGE:
37
+ type: string
38
+ empty_is_nil: false
34
39
  services:
35
40
  wordpress:
36
41
  extends:
37
42
  file: docker-compose_v2.yml
38
43
  service: wordpress
39
- image: wordpress:$TAG
44
+ image: "wordpress:$TAG"
40
45
  stateful: true
41
46
  environment:
42
47
  - WORDPRESS_DB_PASSWORD=${STACK}_secret
43
- secrets:
48
+ secrets:
44
49
  - secret: WP_ADMIN_PASSWORD
45
50
  name: WORDPRESS_PASSWORD
46
51
  type: env
@@ -56,7 +61,7 @@ services:
56
61
  service: mysql
57
62
  image: ${MYSQL_IMAGE}
58
63
  stateful: true
59
- secrets:
64
+ secrets:
60
65
  - secret: WP_MYSQL_ROOT_PW
61
66
  name: MYSQL_PASSWORD
62
67
  type: env
@@ -23,13 +23,18 @@ variables:
23
23
  env: test_var
24
24
  TEST_ENV_VAR: # the default from/to is to set/read env of the option name
25
25
  type: string
26
+ TAG:
27
+ type: string
28
+ MYSQL_IMAGE:
29
+ type: string
30
+ empty_is_nil: false
26
31
 
27
32
  services:
28
33
  wordpress:
29
34
  extends:
30
35
  file: docker-compose_v2.yml
31
36
  service: wordpress
32
- image: wordpress:$TAG
37
+ image: "wordpress:$TAG"
33
38
  stateful: true
34
39
  environment:
35
40
  - WORDPRESS_DB_PASSWORD=${STACK}_secret
@@ -64,7 +64,7 @@ describe Kontena::Cli::Cloud::Master::AddCommand do
64
64
  let(:success_response) {
65
65
  {
66
66
  'data' => {
67
- 'attributes' => {
67
+ 'attributes' => {
68
68
  'client-id' => '123',
69
69
  'client-secret' => '345',
70
70
  'provider' => 'foo',
@@ -90,7 +90,7 @@ describe Kontena::Cli::Cloud::Master::AddCommand do
90
90
  expect(url).to eq current_master.url
91
91
  expect(provider).to eq 'provider'
92
92
  expect(version).to eq '10.10.10'
93
- expect(redirect_uri).to be_nil
93
+ expect(redirect_uri).to eq (current_master.url + "/cb")
94
94
  end.and_return(success_response)
95
95
 
96
96
  subject.provider = 'provider'
@@ -31,7 +31,7 @@ describe Kontena::Cli::Services::ContainersCommand do
31
31
  })
32
32
  expect {
33
33
  subject.run(['service-a'])
34
- }.to_not raise_error(NoMethodError)
34
+ }.to_not raise_error
35
35
  end
36
36
 
37
37
  it 'to not throw on nil "overlay_cidr" property' do
@@ -42,7 +42,7 @@ describe Kontena::Cli::Services::ContainersCommand do
42
42
  })
43
43
  expect {
44
44
  subject.run(['service-a'])
45
- }.to_not raise_error(NoMethodError)
45
+ }.to_not raise_error
46
46
  end
47
47
  end
48
48
  end
@@ -3,6 +3,10 @@ require "kontena/cli/stacks/build_command"
3
3
 
4
4
  describe Kontena::Cli::Stacks::BuildCommand do
5
5
 
6
+ include RequirementsHelper
7
+
8
+ mock_current_master
9
+
6
10
  let(:subject) do
7
11
  described_class.new(File.basename($0))
8
12
  end
@@ -29,32 +33,39 @@ describe Kontena::Cli::Stacks::BuildCommand do
29
33
  }
30
34
  end
31
35
 
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
36
+ before(:each) do
37
+ allow(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
38
+ allow(subject).to receive(:stack_from_yaml).with('kontena.yml', hash_including(:name, :values)).and_return(stack)
39
+ allow(subject).to receive(:system).and_return(true)
40
+ end
41
+
42
+ expect_to_require_current_master
43
+ expect_to_require_current_master_token
44
+
45
+ it 'requires config file' do
46
+ expect(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
47
+ subject.run([])
48
+ end
49
+
50
+ it 'reads stack file' do
51
+ expect(subject).to receive(:stack_from_yaml).with('kontena.yml', hash_including(:name, :values)).and_return(stack)
52
+ subject.run([])
53
+ end
54
+
55
+ it 'builds docker image' do
56
+ expect(subject).to receive(:system).with('docker', 'build', '-t', 'registry.kontena.local/test:latest', '--pull', File.expand_path('.'))
57
+ subject.run([])
58
+ end
59
+
60
+ it 'pushes docker image' do
61
+ expect(subject).to receive(:system).with('docker', 'push', 'registry.kontena.local/test:latest')
62
+ subject.run([])
63
+ end
64
+
65
+ it 'uses sudo when --sudo given' do
66
+ expect(subject).to receive(:system).with('sudo', 'docker', 'build', '-t', 'registry.kontena.local/test:latest', '--pull', File.expand_path('.')).and_return(true)
67
+ expect(subject).to receive(:system).with('sudo', 'docker', 'push', 'registry.kontena.local/test:latest').and_return(true)
68
+ subject.run(['--sudo'])
58
69
  end
59
70
  end
60
71
  end
@@ -4,6 +4,8 @@ require "kontena/cli/stacks/install_command"
4
4
  describe Kontena::Cli::Stacks::InstallCommand do
5
5
 
6
6
  include ClientHelpers
7
+ include RequirementsHelper
8
+ mock_current_master
7
9
 
8
10
  describe '#execute' do
9
11
  let(:stack) do
@@ -17,6 +19,9 @@ describe Kontena::Cli::Stacks::InstallCommand do
17
19
  }
18
20
  end
19
21
 
22
+ expect_to_require_current_master
23
+ expect_to_require_current_master_token
24
+
20
25
  before(:each) do
21
26
  allow(subject).to receive(:yaml_content).and_return("YAML content")
22
27
  end
@@ -59,7 +64,7 @@ describe Kontena::Cli::Stacks::InstallCommand do
59
64
 
60
65
  it 'accepts a stack name as filename' do
61
66
  expect(File).to receive(:exist?).with('user/stack:1.0.0').and_return(false)
62
- expect(subject).to receive(:stack_from_yaml).with('user/stack:1.0.0', from_registry: true, name: nil).and_return(stack)
67
+ expect(subject).to receive(:stack_from_yaml).with('user/stack:1.0.0', from_registry: true, name: nil, values: nil).and_return(stack)
63
68
  expect(client).to receive(:post).with(
64
69
  'grids/test-grid/stacks', stack
65
70
  )
@@ -4,6 +4,9 @@ require "kontena/cli/stacks/upgrade_command"
4
4
  describe Kontena::Cli::Stacks::UpgradeCommand do
5
5
 
6
6
  include ClientHelpers
7
+ include RequirementsHelper
8
+
9
+ mock_current_master
7
10
 
8
11
  describe '#execute' do
9
12
 
@@ -14,35 +17,28 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
14
17
  }
15
18
  end
16
19
 
17
- it 'requires api url' do
18
- allow(subject).to receive(:require_config_file).and_return(true)
19
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-name').and_return(stack)
20
- expect(described_class.requires_current_master?).to be_truthy
21
- subject.run(['stack-name', './path/to/kontena.yml'])
20
+ before(:each) do
21
+ allow(File).to receive(:exist?).with('./path/to/kontena.yml').and_return(true)
22
22
  end
23
23
 
24
- it 'requires token' do
25
- allow(subject).to receive(:require_config_file).and_return(true)
26
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-name').and_return(stack)
27
- expect(described_class.requires_current_master_token?).to be_truthy
28
- subject.run(['stack-name', './path/to/kontena.yml'])
29
- end
24
+ expect_to_require_current_master
25
+ expect_to_require_current_master_token
30
26
 
31
27
  it 'requires stack file' do
32
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-name').and_return(stack)
33
- expect(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
28
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-name', values: nil, from_registry: false).and_return(stack)
29
+ expect(subject).to receive(:require_config_file).with('./path/to/kontena.yml').at_least(:once).and_return(true)
34
30
  subject.run(['stack-name', './path/to/kontena.yml'])
35
31
  end
36
32
 
37
33
  it 'uses kontena.yml as default stack file' do
38
34
  expect(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
39
- expect(subject).to receive(:stack_from_yaml).with('kontena.yml', name: 'stack-name').and_return(stack)
35
+ expect(subject).to receive(:stack_from_yaml).with('kontena.yml', name: 'stack-name', values: nil, from_registry: nil).and_return(stack)
40
36
  subject.run(['stack-name'])
41
37
  end
42
38
 
43
39
  it 'sends stack to master' do
44
40
  allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
45
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-a').and_return(stack)
41
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-a', values: nil, from_registry: false).and_return(stack)
46
42
  expect(client).to receive(:put).with(
47
43
  'stacks/test-grid/stack-a', anything
48
44
  )
@@ -51,7 +47,7 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
51
47
 
52
48
  it 'allows to override stack name' do
53
49
  allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
54
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-b').and_return(stack)
50
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-b', values: nil, from_registry: false).and_return(stack)
55
51
  stack_b = stack
56
52
  stack_b[:name] = 'stack-b'
57
53
  expect(client).to receive(:put).with(
@@ -64,7 +60,7 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
64
60
  context 'when given' do
65
61
  it 'triggers deploy' do
66
62
  allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
67
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-a').and_return(stack)
63
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-a', values: nil, from_registry: false).and_return(stack)
68
64
  allow(client).to receive(:put).with(
69
65
  'stacks/test-grid/stack-a', anything
70
66
  ).and_return({})
@@ -75,7 +71,7 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
75
71
  context 'when not given' do
76
72
  it 'does not trigger deploy' do
77
73
  allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
78
- allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-a').and_return(stack)
74
+ allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-a', values: nil, from_registry: false).and_return(stack)
79
75
  allow(client).to receive(:put).with(
80
76
  'stacks/test-grid/stack-a', anything
81
77
  ).and_return({})
@@ -1,5 +1,6 @@
1
1
  require_relative '../../../../spec_helper'
2
2
  require 'kontena/cli/stacks/yaml/reader'
3
+ require 'liquid'
3
4
 
4
5
  describe Kontena::Cli::Stacks::YAML::Reader do
5
6
  include FixturesHelpers
@@ -54,6 +55,8 @@ describe Kontena::Cli::Stacks::YAML::Reader do
54
55
  allow(File).to receive(:read)
55
56
  .with(absolute_yaml_path('kontena_v3.yml'))
56
57
  .and_return(fixture('kontena_v3.yml'))
58
+ allow_any_instance_of(described_class).to receive(:env)
59
+ .and_return( { 'STACK' => 'test', 'GRID' => 'test-grid' } )
57
60
  end
58
61
 
59
62
  describe '#initialize' do
@@ -88,11 +91,6 @@ describe Kontena::Cli::Stacks::YAML::Reader do
88
91
  end
89
92
 
90
93
  describe '#execute' do
91
- before(:each) do
92
- allow(ENV).to receive(:[]).with('STACK').and_return('test')
93
- allow(ENV).to receive(:[]).with('GRID').and_return('test-grid')
94
- end
95
-
96
94
  context 'when extending services' do
97
95
  it 'extends services from external file' do
98
96
  docker_compose_yml = YAML.load(fixture('docker-compose_v2.yml'))
@@ -129,7 +127,7 @@ describe Kontena::Cli::Stacks::YAML::Reader do
129
127
  end
130
128
 
131
129
  it 'extends services from the same file' do
132
- allow(File).to receive(:read)
130
+ expect(File).to receive(:read)
133
131
  .with(absolute_yaml_path('kontena_v3.yml'))
134
132
  .and_return(fixture('stack-internal-extend.yml'))
135
133
  kontena_yml = YAML.load(fixture('stack-internal-extend.yml'))
@@ -162,20 +160,23 @@ describe Kontena::Cli::Stacks::YAML::Reader do
162
160
 
163
161
  context 'variable interpolation' do
164
162
  before(:each) do
165
- allow(ENV).to receive(:key?).and_return(true)
166
- allow(ENV).to receive(:[]).with('TAG').and_return('4.1')
167
- allow(ENV).to receive(:[]).with('STACK').and_return('test')
168
- allow(ENV).to receive(:[]).with('GRID').and_return('test-grid')
169
- allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('mariadb:latest')
163
+ allow_any_instance_of(described_class).to receive(:env).and_return(
164
+ {
165
+ 'STACK' => 'test',
166
+ 'GRID' => 'test-grid',
167
+ 'TAG' => '4.1'
168
+ }
169
+ )
170
170
  allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
171
+ allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('mariadb:latest')
171
172
  end
172
173
 
173
174
  it 'interpolates $VAR variables' do
174
175
  allow(File).to receive(:read)
175
176
  .with(absolute_yaml_path)
176
177
  .and_return(fixture('stack-with-variables.yml'))
177
- subject.execute
178
- services = subject.yaml['services']
178
+ result = subject.execute
179
+ services = result[:services]
179
180
  expect(services['wordpress']['image']).to eq('wordpress:4.1')
180
181
  end
181
182
 
@@ -183,8 +184,8 @@ describe Kontena::Cli::Stacks::YAML::Reader do
183
184
  allow(File).to receive(:read)
184
185
  .with(absolute_yaml_path)
185
186
  .and_return(fixture('stack-with-variables.yml'))
186
- subject.execute
187
- services = subject.yaml['services']
187
+ result = subject.execute
188
+ services = result[:services]
188
189
  expect(services['mysql']['image']).to eq('mariadb:latest')
189
190
  end
190
191
 
@@ -194,7 +195,10 @@ describe Kontena::Cli::Stacks::YAML::Reader do
194
195
  .and_return(fixture('stack-with-variables.yml'))
195
196
  allow(ENV).to receive(:[])
196
197
  .with('MYSQL_IMAGE')
197
- .and_return(nil)
198
+ .and_return('')
199
+ allow(ENV).to receive(:[])
200
+ .with('TAG')
201
+ .and_return('4.1')
198
202
 
199
203
  expect {
200
204
  subject.execute
@@ -203,12 +207,15 @@ describe Kontena::Cli::Stacks::YAML::Reader do
203
207
  end
204
208
 
205
209
  it 'replaces $$VAR variables to $VAR format' do
206
- allow(ENV).to receive(:key?).and_return(true)
207
- allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
210
+ allow_any_instance_of(described_class).to receive(:env).and_return(
211
+ {
212
+ 'STACK' => 'test',
213
+ 'GRID' => 'test-grid'
214
+ }
215
+ )
208
216
  allow(ENV).to receive(:[]).with('TAG').and_return('4.1')
209
- allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('mariadb:latest')
210
- allow(ENV).to receive(:[]).with('STACK').and_return('test')
211
- allow(ENV).to receive(:[]).with('GRID').and_return('test-grid')
217
+ allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
218
+ allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('foo')
212
219
  allow(File).to receive(:read)
213
220
  .with(absolute_yaml_path)
214
221
  .and_return(fixture('stack-with-variables.yml'))
@@ -384,4 +391,52 @@ describe Kontena::Cli::Stacks::YAML::Reader do
384
391
  expect(name).to eq('stackname')
385
392
  end
386
393
  end
394
+
395
+ context 'liquid' do
396
+ context 'valid' do
397
+ before(:each) do
398
+ allow(File).to receive(:read)
399
+ .with(absolute_yaml_path('kontena_v3.yml'))
400
+ .and_return(fixture('stack-with-liquid.yml'))
401
+ allow_any_instance_of(described_class).to receive(:env).and_return(
402
+ {
403
+ 'STACK' => 'test',
404
+ 'GRID' => 'test-grid',
405
+ 'TAG' => '4.1',
406
+ 'MYSQL_IMAGE' => 'mariadb:latest'
407
+ }
408
+ )
409
+ allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
410
+ end
411
+
412
+ it 'does not interpolate liquid into variables' do
413
+ expect(subject.variables.value_of('grid_name')).to eq '{{ GRID }} test'
414
+ end
415
+
416
+ it 'interpolates variables into services' do
417
+ expect(subject.execute[:services].size).to eq 5
418
+ end
419
+ end
420
+
421
+ context 'invalid' do
422
+ before(:each) do
423
+ allow(File).to receive(:read)
424
+ .with(absolute_yaml_path('kontena_v3.yml'))
425
+ .and_return(fixture('stack-with-invalid-liquid.yml'))
426
+ allow_any_instance_of(described_class).to receive(:env).and_return(
427
+ {
428
+ 'STACK' => 'test',
429
+ 'GRID' => 'test-grid',
430
+ 'TAG' => '4.1',
431
+ 'MYSQL_IMAGE' => 'mariadb:latest'
432
+ }
433
+ )
434
+ allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
435
+ end
436
+
437
+ it 'raises' do
438
+ expect{subject.execute}.to raise_error(Liquid::SyntaxError)
439
+ end
440
+ end
441
+ end
387
442
  end