kontena-cli 1.1.6 → 1.2.0.dev1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/VERSION +1 -1
- data/bin/kontena +8 -28
- data/kontena-cli.gemspec +2 -2
- data/lib/kontena/cli/app_command.rb +14 -27
- data/lib/kontena/cli/certificate_command.rb +4 -7
- data/lib/kontena/cli/cloud/master_command.rb +5 -12
- data/lib/kontena/cli/cloud_command.rb +4 -7
- data/lib/kontena/cli/container_command.rb +4 -9
- data/lib/kontena/cli/etcd/health_command.rb +1 -0
- data/lib/kontena/cli/etcd_command.rb +6 -13
- data/lib/kontena/cli/external_registry_command.rb +3 -7
- data/lib/kontena/cli/grid_command.rb +14 -29
- data/lib/kontena/cli/grids/cloud_config_command.rb +1 -0
- data/lib/kontena/cli/grids/common.rb +2 -0
- data/lib/kontena/cli/grids/create_command.rb +5 -0
- data/lib/kontena/cli/grids/trusted_subnet_command.rb +6 -8
- data/lib/kontena/cli/grids/user_command.rb +3 -6
- data/lib/kontena/cli/master/config_command.rb +6 -12
- data/lib/kontena/cli/master/token_command.rb +6 -11
- data/lib/kontena/cli/master/users/role_command.rb +2 -4
- data/lib/kontena/cli/master/users_command.rb +4 -8
- data/lib/kontena/cli/master_command.rb +14 -33
- data/lib/kontena/cli/node_command.rb +7 -15
- data/lib/kontena/cli/nodes/health_command.rb +1 -1
- data/lib/kontena/cli/nodes/label_command.rb +3 -9
- data/lib/kontena/cli/nodes/show_command.rb +1 -1
- data/lib/kontena/cli/nodes/ssh_command.rb +13 -4
- data/lib/kontena/cli/plugin_command.rb +5 -9
- data/lib/kontena/cli/registry_command.rb +2 -5
- data/lib/kontena/cli/service_command.rb +22 -45
- data/lib/kontena/cli/services/container_command.rb +2 -3
- data/lib/kontena/cli/services/env_command.rb +3 -6
- data/lib/kontena/cli/services/secret_command.rb +2 -4
- data/lib/kontena/cli/stack_command.rb +11 -24
- data/lib/kontena/cli/stacks/registry_command.rb +5 -12
- data/lib/kontena/cli/stacks/upgrade_command.rb +6 -0
- data/lib/kontena/cli/stacks/yaml/reader.rb +17 -2
- data/lib/kontena/cli/subcommand_loader.rb +82 -0
- data/lib/kontena/cli/vault_command.rb +7 -15
- data/lib/kontena/cli/version.rb +6 -1
- data/lib/kontena/cli/vpn_command.rb +3 -7
- data/lib/kontena/command.rb +28 -1
- data/lib/kontena/machine/cloud_config/cloudinit.yml +1 -1
- data/lib/kontena/main_command.rb +22 -38
- data/lib/kontena/scripts/completer +2 -233
- data/lib/kontena/scripts/completer.rb +230 -0
- data/lib/kontena/scripts/init +5 -8
- data/lib/kontena/scripts/kontena.bash +8 -0
- data/lib/kontena/scripts/kontena.zsh +11 -0
- data/lib/kontena_cli.rb +9 -1
- data/omnibus/wrappers/sh/kontena +1 -1
- data/spec/fixtures/stack-with-liquid-optional.yml +14 -0
- data/spec/fixtures/stack-with-liquid-undefined.yml +12 -0
- data/spec/kontena/cli/app/build_command_spec.rb +1 -2
- data/spec/kontena/cli/app/common_spec.rb +1 -2
- data/spec/kontena/cli/app/config_command_spec.rb +0 -1
- data/spec/kontena/cli/app/deploy_command_spec.rb +2 -3
- data/spec/kontena/cli/app/docker_helper_spec.rb +0 -1
- data/spec/kontena/cli/app/init_command_spec.rb +0 -1
- data/spec/kontena/cli/app/logs_command_spec.rb +0 -1
- data/spec/kontena/cli/app/scale_spec.rb +2 -3
- data/spec/kontena/cli/app/service_generator_spec.rb +1 -2
- data/spec/kontena/cli/app/service_generator_v2_spec.rb +0 -1
- data/spec/kontena/cli/app/yaml/reader_spec.rb +0 -1
- data/spec/kontena/cli/app/yaml/service_extender_spec.rb +0 -1
- data/spec/kontena/cli/app/yaml/validator_spec.rb +0 -1
- data/spec/kontena/cli/app/yaml/validator_v2_spec.rb +0 -1
- data/spec/kontena/cli/cloud/login_command_spec.rb +0 -1
- data/spec/kontena/cli/cloud/logout_command_spec.rb +0 -1
- data/spec/kontena/cli/cloud/master/add_command_spec.rb +0 -1
- data/spec/kontena/cli/common_spec.rb +0 -1
- data/spec/kontena/cli/containers/list_command_spec.rb +0 -1
- data/spec/kontena/cli/containers/logs_command_spec.rb +0 -1
- data/spec/kontena/cli/etcd/health_command_spec.rb +2 -0
- data/spec/kontena/cli/grids/trusted_subnets/add_command_spec.rb +0 -11
- data/spec/kontena/cli/grids/trusted_subnets/list_command_spec.rb +4 -13
- data/spec/kontena/cli/grids/trusted_subnets/remove_command_spec.rb +0 -11
- data/spec/kontena/cli/grids/use_command_spec.rb +0 -1
- data/spec/kontena/cli/helpers/log_helper_spec.rb +0 -1
- data/spec/kontena/cli/main_command_spec.rb +2 -3
- data/spec/kontena/cli/master/current_command_spec.rb +5 -15
- data/spec/kontena/cli/master/init_cloud_command_spec.rb +0 -1
- data/spec/kontena/cli/master/login_command_spec.rb +0 -1
- data/spec/kontena/cli/master/logout_command_spec.rb +0 -1
- data/spec/kontena/cli/master/use_command_spec.rb +0 -1
- data/spec/kontena/cli/master/users/invite_command_spec.rb +1 -5
- data/spec/kontena/cli/master/users/remove_command_spec.rb +2 -14
- data/spec/kontena/cli/master/users/roles/add_command_spec.rb +0 -1
- data/spec/kontena/cli/master/users/roles/remove_command_spec.rb +0 -1
- data/spec/kontena/cli/nodes/list_command_spec.rb +2 -0
- data/spec/kontena/cli/services/containers_command_spec.rb +0 -18
- data/spec/kontena/cli/services/exec_command_spec.rb +6 -4
- data/spec/kontena/cli/services/link_command_spec.rb +5 -19
- data/spec/kontena/cli/services/restart_command_spec.rb +0 -16
- data/spec/kontena/cli/services/secrets/link_command_spec.rb +0 -11
- data/spec/kontena/cli/services/secrets/unlink_command_spec.rb +1 -12
- data/spec/kontena/cli/services/services_helper_spec.rb +0 -1
- data/spec/kontena/cli/services/unlink_command_spec.rb +7 -21
- data/spec/kontena/cli/services/update_command_spec.rb +0 -15
- data/spec/kontena/cli/stacks/build_command_spec.rb +0 -1
- data/spec/kontena/cli/stacks/deploy_command_spec.rb +10 -13
- data/spec/kontena/cli/stacks/install_command_spec.rb +0 -15
- data/spec/kontena/cli/stacks/list_command_spec.rb +4 -10
- data/spec/kontena/cli/stacks/remove_command_spec.rb +1 -16
- data/spec/kontena/cli/stacks/service_generator_spec.rb +0 -1
- data/spec/kontena/cli/stacks/service_generator_v2_spec.rb +0 -1
- data/spec/kontena/cli/stacks/show_command_spec.rb +1 -14
- data/spec/kontena/cli/stacks/upgrade_command_spec.rb +19 -1
- data/spec/kontena/cli/stacks/yaml/reader_spec.rb +163 -130
- data/spec/kontena/cli/stacks/yaml/service_extender_spec.rb +0 -1
- data/spec/kontena/cli/stacks/yaml/validator_v3_spec.rb +0 -1
- data/spec/kontena/cli/vault/export_spec.rb +0 -1
- data/spec/kontena/cli/vault/import_spec.rb +4 -5
- data/spec/kontena/cli/version_command_spec.rb +8 -6
- data/spec/kontena/cli/vpn/create_command_spec.rb +3 -4
- data/spec/kontena/client_spec.rb +0 -1
- data/spec/kontena/config_spec.rb +0 -1
- data/spec/kontena/kontena_cli_spec.rb +1 -1
- data/spec/kontena/main_command_spec.rb +0 -1
- data/spec/kontena/plugin_manager_spec.rb +0 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/client_helpers.rb +1 -1
- data/spec/support/exit_with_error_helper.rb +36 -0
- data/spec/support/fixtures_helpers.rb +5 -2
- metadata +18 -7
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../../spec_helper"
|
2
1
|
require "kontena/cli/grid_options"
|
3
2
|
require "kontena/cli/services/secrets/link_command"
|
4
3
|
|
@@ -7,16 +6,6 @@ describe Kontena::Cli::Services::Secrets::LinkCommand do
|
|
7
6
|
include ClientHelpers
|
8
7
|
|
9
8
|
describe '#execute' do
|
10
|
-
it 'requires api url' do
|
11
|
-
expect(subject).to receive(:require_api_url).once
|
12
|
-
subject.run(['service', 'secret:name:env'])
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'requires token' do
|
16
|
-
expect(subject).to receive(:require_token).and_return(token)
|
17
|
-
subject.run(['service', 'secret:name:env'])
|
18
|
-
end
|
19
|
-
|
20
9
|
it 'requires service as param' do
|
21
10
|
expect {
|
22
11
|
subject.run([])
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../../spec_helper"
|
2
1
|
require "kontena/cli/grid_options"
|
3
2
|
require "kontena/cli/services/secrets/unlink_command"
|
4
3
|
|
@@ -7,16 +6,6 @@ describe Kontena::Cli::Services::Secrets::UnlinkCommand do
|
|
7
6
|
include ClientHelpers
|
8
7
|
|
9
8
|
describe '#execute' do
|
10
|
-
it 'requires api url' do
|
11
|
-
expect(subject).to receive(:require_api_url).once
|
12
|
-
subject.run(['service', 'secret:name:env'])
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'requires token' do
|
16
|
-
expect(subject).to receive(:require_token).and_return(token)
|
17
|
-
subject.run(['service', 'secret:name:env'])
|
18
|
-
end
|
19
|
-
|
20
9
|
it 'requires service as param' do
|
21
10
|
expect {
|
22
11
|
subject.run([])
|
@@ -41,7 +30,7 @@ describe Kontena::Cli::Services::Secrets::UnlinkCommand do
|
|
41
30
|
{'secret' => 'BAR', 'name' => 'BAZ', 'type' => 'env'}
|
42
31
|
]
|
43
32
|
}
|
44
|
-
|
33
|
+
expect(client).to receive(:get).with("services/test-grid/null/mymy").and_return(original)
|
45
34
|
expect(client).to receive(:put).with("services/test-grid/null/mymy", data)
|
46
35
|
subject.run(['mymy', 'FOO:BAR:env'])
|
47
36
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/services/unlink_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Services::UnlinkCommand do
|
@@ -6,34 +5,21 @@ describe Kontena::Cli::Services::UnlinkCommand do
|
|
6
5
|
include ClientHelpers
|
7
6
|
|
8
7
|
describe '#execute' do
|
9
|
-
before(:each) do
|
10
|
-
allow(client).to receive(:get).and_return({
|
11
|
-
'links' => [
|
12
|
-
{'alias' => 'service-b', 'id' => "test-grid/null/service-b", 'name' => 'service-b'}
|
13
|
-
]
|
14
|
-
})
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'requires api url' do
|
18
|
-
expect(subject).to receive(:require_api_url).once
|
19
|
-
subject.run(['service-a', 'service-b'])
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'requires token' do
|
23
|
-
expect(subject).to receive(:require_token).and_return(token)
|
24
|
-
subject.run(['service-a', 'service-b'])
|
25
|
-
end
|
26
|
-
|
27
8
|
it 'aborts if service is not linked' do
|
28
|
-
|
9
|
+
expect(client).to receive(:get).with('services/test-grid/null/service-a').and_return({
|
29
10
|
'links' => []
|
30
11
|
})
|
31
12
|
expect {
|
32
13
|
subject.run(['service-a', 'service-b'])
|
33
|
-
}.to
|
14
|
+
}.to exit_with_error
|
34
15
|
end
|
35
16
|
|
36
17
|
it 'sends link to master' do
|
18
|
+
expect(client).to receive(:get).with('services/test-grid/null/service-a').and_return({
|
19
|
+
'links' => [
|
20
|
+
{'alias' => 'service-b', 'id' => "test-grid/null/service-b", 'name' => 'service-b'}
|
21
|
+
]
|
22
|
+
})
|
37
23
|
expect(client).to receive(:put).with(
|
38
24
|
'services/test-grid/null/service-a', {links: []}
|
39
25
|
)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/grid_options"
|
3
2
|
require "kontena/cli/services/update_command"
|
4
3
|
|
@@ -8,20 +7,6 @@ describe Kontena::Cli::Services::UpdateCommand do
|
|
8
7
|
|
9
8
|
describe '#execute' do
|
10
9
|
|
11
|
-
before(:each) do
|
12
|
-
allow(subject).to receive(:update_service).and_return({})
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'requires api url' do
|
16
|
-
expect(subject).to receive(:require_api_url).once
|
17
|
-
subject.run(['service'])
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'requires token' do
|
21
|
-
expect(subject).to receive(:require_token).once
|
22
|
-
subject.run(['service'])
|
23
|
-
end
|
24
|
-
|
25
10
|
it 'sends update command' do
|
26
11
|
expect(subject).to receive(:update_service).with(duck_type(:access_token), 'service', {privileged: false})
|
27
12
|
subject.run(['service'])
|
@@ -1,29 +1,26 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/stacks/deploy_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Stacks::DeployCommand do
|
5
4
|
|
6
5
|
include ClientHelpers
|
6
|
+
include RequirementsHelper
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
allow(subject).to receive(:wait_for_deploy_to_finish).and_return(spy)
|
11
|
-
end
|
8
|
+
expect_to_require_current_master
|
9
|
+
expect_to_require_current_master_token
|
12
10
|
|
13
|
-
|
14
|
-
expect(described_class.requires_current_master?).to be_truthy
|
15
|
-
subject.run(['test-stack'])
|
16
|
-
end
|
11
|
+
mock_current_master
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
subject.
|
13
|
+
describe '#execute' do
|
14
|
+
before(:each) do
|
15
|
+
allow(subject).to receive(:wait_for_deploy_to_finish).and_return(true)
|
16
|
+
allow(subject).to receive(:wait_for_deployment_to_start).and_return(true)
|
17
|
+
allow(subject).to receive(:wait_for_service_deploy).and_return(true)
|
21
18
|
end
|
22
19
|
|
23
20
|
it 'sends deploy command to master' do
|
24
21
|
expect(client).to receive(:post).with(
|
25
22
|
'stacks/test-grid/test-stack/deploy', {}
|
26
|
-
)
|
23
|
+
).and_return({})
|
27
24
|
subject.run(['test-stack'])
|
28
25
|
end
|
29
26
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/stacks/install_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Stacks::InstallCommand do
|
@@ -26,20 +25,6 @@ describe Kontena::Cli::Stacks::InstallCommand do
|
|
26
25
|
allow(subject).to receive(:yaml_content).and_return("YAML content")
|
27
26
|
end
|
28
27
|
|
29
|
-
it 'requires api url' do
|
30
|
-
allow(File).to receive(:exist?).with('kontena.yml').and_return(true)
|
31
|
-
allow(subject).to receive(:stack_from_yaml).with('kontena.yml', hash_including(name: nil, values: nil)).and_return(stack)
|
32
|
-
expect(described_class.requires_current_master?).to be_truthy
|
33
|
-
subject.run([])
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'requires token' do
|
37
|
-
allow(File).to receive(:exist?).with('kontena.yml').and_return(true)
|
38
|
-
allow(subject).to receive(:stack_from_yaml).with('kontena.yml', hash_including(name: nil, values: nil)).and_return(stack)
|
39
|
-
expect(described_class.requires_current_master_token?).to be_truthy
|
40
|
-
subject.run([])
|
41
|
-
end
|
42
|
-
|
43
28
|
it 'sends stack to master' do
|
44
29
|
allow(File).to receive(:exist?).with('kontena.yml').and_return(true)
|
45
30
|
allow(subject).to receive(:require_config_file).with('kontena.yml').and_return(true)
|
@@ -1,19 +1,13 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/stacks/list_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Stacks::ListCommand do
|
5
|
-
|
6
4
|
include ClientHelpers
|
5
|
+
include RequirementsHelper
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
expect(subject.class.requires_current_master).to be_truthy
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'requires token' do
|
14
|
-
expect(subject.class.requires_current_master_token).to be_truthy
|
15
|
-
end
|
7
|
+
expect_to_require_current_master
|
8
|
+
expect_to_require_current_master_token
|
16
9
|
|
10
|
+
describe '#execute' do
|
17
11
|
it 'fetches stacks from master' do
|
18
12
|
stacks = {
|
19
13
|
'stacks' => []
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/stacks/remove_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Stacks::RemoveCommand do
|
@@ -6,20 +5,6 @@ describe Kontena::Cli::Stacks::RemoveCommand do
|
|
6
5
|
include ClientHelpers
|
7
6
|
|
8
7
|
describe '#execute' do
|
9
|
-
it 'requires api url' do
|
10
|
-
allow(subject).to receive(:forced?).and_return(true)
|
11
|
-
allow(subject).to receive(:wait_stack_removal)
|
12
|
-
expect(described_class.requires_current_master?).to be_truthy
|
13
|
-
subject.run(['test-stack'])
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'requires token' do
|
17
|
-
allow(subject).to receive(:forced?).and_return(true)
|
18
|
-
allow(subject).to receive(:wait_stack_removal)
|
19
|
-
expect(described_class.requires_current_master_token?).to be_truthy
|
20
|
-
subject.run(['test-stack'])
|
21
|
-
end
|
22
|
-
|
23
8
|
it 'sends remove command to master' do
|
24
9
|
allow(subject).to receive(:wait_stack_removal)
|
25
10
|
expect(client).to receive(:delete).with('stacks/test-grid/test-stack')
|
@@ -39,7 +24,7 @@ describe Kontena::Cli::Stacks::RemoveCommand do
|
|
39
24
|
.and_raise(Kontena::Errors::StandardError.new(500, 'internal error'))
|
40
25
|
expect{
|
41
26
|
subject.run(['--force', 'test-stack'])
|
42
|
-
}.to
|
27
|
+
}.to exit_with_error
|
43
28
|
end
|
44
29
|
end
|
45
30
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/stacks/show_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Stacks::ShowCommand do
|
@@ -6,20 +5,8 @@ describe Kontena::Cli::Stacks::ShowCommand do
|
|
6
5
|
include ClientHelpers
|
7
6
|
|
8
7
|
describe '#execute' do
|
9
|
-
it 'requires api url' do
|
10
|
-
allow(subject).to receive(:forced?).and_return(true)
|
11
|
-
expect(described_class.requires_current_master?).to be_truthy
|
12
|
-
subject.run(['test-stack'])
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'requires token' do
|
16
|
-
allow(subject).to receive(:forced?).and_return(true)
|
17
|
-
expect(described_class.requires_current_master_token?).to be_truthy
|
18
|
-
subject.run(['test-stack'])
|
19
|
-
end
|
20
|
-
|
21
8
|
it 'fetches stack info from master' do
|
22
|
-
expect(client).to receive(:get).with('stacks/test-grid/test-stack')
|
9
|
+
expect(client).to receive(:get).with('stacks/test-grid/test-stack').and_return(spy())
|
23
10
|
subject.run(['test-stack'])
|
24
11
|
end
|
25
12
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require_relative "../../../spec_helper"
|
2
1
|
require "kontena/cli/stacks/upgrade_command"
|
3
2
|
|
4
3
|
describe Kontena::Cli::Stacks::UpgradeCommand do
|
@@ -13,6 +12,15 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
13
12
|
let(:stack) do
|
14
13
|
{
|
15
14
|
'name' => 'stack-a',
|
15
|
+
'stack' => 'foo/stack-a',
|
16
|
+
'services' => []
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:stack_with_different_stack_name) do
|
21
|
+
{
|
22
|
+
'name' => 'stack-a',
|
23
|
+
'stack' => 'foo/stack-z',
|
16
24
|
'services' => []
|
17
25
|
}
|
18
26
|
end
|
@@ -24,6 +32,7 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
24
32
|
let(:stack_response) do
|
25
33
|
{
|
26
34
|
'name' => 'stack-a',
|
35
|
+
'stack' => 'foo/stack-a',
|
27
36
|
'services' => [],
|
28
37
|
'variables' => defaults
|
29
38
|
}
|
@@ -39,6 +48,7 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
39
48
|
it 'uses kontena.yml as default stack file' do
|
40
49
|
expect(client).to receive(:get).with('stacks/test-grid/stack-name').and_return(stack_response)
|
41
50
|
expect(subject).to receive(:stack_from_yaml).with('kontena.yml', name: 'stack-name', values: nil, defaults: defaults).and_return(stack)
|
51
|
+
expect(client).to receive(:put).with('stacks/test-grid/stack-name', stack)
|
42
52
|
subject.run(['stack-name'])
|
43
53
|
end
|
44
54
|
|
@@ -64,6 +74,14 @@ describe Kontena::Cli::Stacks::UpgradeCommand do
|
|
64
74
|
subject.run(['stack-b', './path/to/kontena.yml'])
|
65
75
|
end
|
66
76
|
|
77
|
+
it 'requires confirmation when master stack is different than input stack' do
|
78
|
+
expect(client).to receive(:get).with('stacks/test-grid/stack-b').and_return(stack_response)
|
79
|
+
allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
|
80
|
+
allow(subject).to receive(:stack_from_yaml).with('./path/to/kontena.yml', name: 'stack-b', values: nil, defaults: defaults).and_return(stack_with_different_stack_name)
|
81
|
+
expect(subject).to receive(:confirm).and_call_original
|
82
|
+
expect{subject.run(['stack-b', './path/to/kontena.yml'])}.to exit_with_error
|
83
|
+
end
|
84
|
+
|
67
85
|
it 'triggers deploy by default' do
|
68
86
|
expect(client).to receive(:get).with('stacks/test-grid/stack-a').and_return(stack_response)
|
69
87
|
allow(subject).to receive(:require_config_file).with('./path/to/kontena.yml').and_return(true)
|
@@ -1,18 +1,9 @@
|
|
1
|
-
require_relative '../../../../spec_helper'
|
2
1
|
require 'kontena/cli/stacks/yaml/reader'
|
3
2
|
require 'liquid'
|
4
3
|
|
5
4
|
describe Kontena::Cli::Stacks::YAML::Reader do
|
6
5
|
include FixturesHelpers
|
7
6
|
|
8
|
-
def absolute_yaml_path(file = 'kontena_v3.yml')
|
9
|
-
"#{Dir.pwd}/#{file}"
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:subject) do
|
13
|
-
described_class.new('kontena_v3.yml')
|
14
|
-
end
|
15
|
-
|
16
7
|
let(:service_extender) do
|
17
8
|
spy
|
18
9
|
end
|
@@ -49,30 +40,30 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
49
40
|
end
|
50
41
|
|
51
42
|
before(:each) do
|
52
|
-
allow(File).to receive(:read)
|
53
|
-
.with(absolute_yaml_path('docker-compose_v2.yml'))
|
54
|
-
.and_return(fixture('docker-compose_v2.yml'))
|
55
|
-
allow(File).to receive(:read)
|
56
|
-
.with(absolute_yaml_path('kontena_v3.yml'))
|
57
|
-
.and_return(fixture('kontena_v3.yml'))
|
58
43
|
allow_any_instance_of(described_class).to receive(:env)
|
59
44
|
.and_return( { 'STACK' => 'test', 'GRID' => 'test-grid' } )
|
60
45
|
end
|
61
46
|
|
62
47
|
describe '#initialize' do
|
48
|
+
subject do
|
49
|
+
described_class.new(fixture_path('kontena_v3.yml'))
|
50
|
+
end
|
51
|
+
|
63
52
|
it 'reads given file' do
|
64
53
|
expect(File).to receive(:read)
|
65
|
-
.with(
|
54
|
+
.with(fixture_path('kontena_v3.yml'))
|
66
55
|
.and_return(fixture('kontena_v3.yml'))
|
56
|
+
|
67
57
|
subject
|
68
58
|
end
|
69
59
|
end
|
70
60
|
|
71
61
|
context 'when yaml file is malformed' do
|
62
|
+
subject do
|
63
|
+
described_class.new(fixture_path('kontena-malformed-yaml.yml'))
|
64
|
+
end
|
65
|
+
|
72
66
|
it 'exits the execution' do
|
73
|
-
allow(File).to receive(:read)
|
74
|
-
.with(absolute_yaml_path)
|
75
|
-
.and_return(fixture('kontena-malformed-yaml.yml'))
|
76
67
|
expect {
|
77
68
|
subject.execute
|
78
69
|
}.to raise_error(StandardError)
|
@@ -80,17 +71,21 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
80
71
|
end
|
81
72
|
|
82
73
|
context 'when service config is not hash' do
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
.and_return(fixture('kontena-not-hash-service-config.yml'))
|
74
|
+
subject do
|
75
|
+
described_class.new(fixture_path('kontena-not-hash-service-config.yml'))
|
76
|
+
end
|
87
77
|
|
78
|
+
it 'returns error' do
|
88
79
|
outcome = subject.execute
|
89
80
|
expect(outcome[:errors].size).to eq(1)
|
90
81
|
end
|
91
82
|
end
|
92
83
|
|
93
84
|
describe '#execute' do
|
85
|
+
subject do
|
86
|
+
described_class.new(fixture_path('kontena_v3.yml'))
|
87
|
+
end
|
88
|
+
|
94
89
|
context 'when extending services' do
|
95
90
|
it 'extends services from external file' do
|
96
91
|
docker_compose_yml = YAML.load(fixture('docker-compose_v2.yml'))
|
@@ -127,9 +122,8 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
127
122
|
end
|
128
123
|
|
129
124
|
it 'extends services from the same file' do
|
130
|
-
|
131
|
-
|
132
|
-
.and_return(fixture('stack-internal-extend.yml'))
|
125
|
+
subject = described_class.new(fixture_path('stack-internal-extend.yml'))
|
126
|
+
|
133
127
|
kontena_yml = YAML.load(fixture('stack-internal-extend.yml'))
|
134
128
|
|
135
129
|
expect(Kontena::Cli::Stacks::YAML::ServiceExtender).to receive(:new)
|
@@ -142,7 +136,10 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
142
136
|
|
143
137
|
it 'merges validation errors' do
|
144
138
|
allow(File).to receive(:read)
|
145
|
-
.with(
|
139
|
+
.with(fixture_path('kontena_v3.yml'))
|
140
|
+
.and_return(fixture('kontena_v3.yml'))
|
141
|
+
allow(File).to receive(:read)
|
142
|
+
.with(fixture_path('docker-compose_v2.yml'))
|
146
143
|
.and_return(fixture('docker-compose-invalid.yml'))
|
147
144
|
outcome = subject.execute
|
148
145
|
expect(outcome[:errors]).to eq([{
|
@@ -159,7 +156,18 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
159
156
|
end
|
160
157
|
|
161
158
|
context 'variable interpolation' do
|
159
|
+
subject do
|
160
|
+
described_class.new(fixture_path('stack-with-variables.yml'))
|
161
|
+
end
|
162
|
+
|
162
163
|
before(:each) do
|
164
|
+
allow(File).to receive(:read)
|
165
|
+
.with(fixture_path('docker-compose_v2.yml'))
|
166
|
+
.and_return(fixture('docker-compose_v2.yml'))
|
167
|
+
allow(File).to receive(:read)
|
168
|
+
.with(fixture_path('stack-with-variables.yml'))
|
169
|
+
.and_return(fixture('stack-with-variables.yml'))
|
170
|
+
|
163
171
|
allow_any_instance_of(described_class).to receive(:env).and_return(
|
164
172
|
{
|
165
173
|
'STACK' => 'test',
|
@@ -167,32 +175,24 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
167
175
|
'TAG' => '4.1'
|
168
176
|
}
|
169
177
|
)
|
178
|
+
allow(ENV).to receive(:[]).with('TAG').and_return('4.1')
|
170
179
|
allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
|
171
180
|
allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('mariadb:latest')
|
172
181
|
end
|
173
182
|
|
174
183
|
it 'interpolates $VAR variables' do
|
175
|
-
allow(File).to receive(:read)
|
176
|
-
.with(absolute_yaml_path)
|
177
|
-
.and_return(fixture('stack-with-variables.yml'))
|
178
184
|
result = subject.execute
|
179
185
|
services = result[:services]
|
180
186
|
expect(services['wordpress']['image']).to eq('wordpress:4.1')
|
181
187
|
end
|
182
188
|
|
183
189
|
it 'interpolates ${VAR} variables' do
|
184
|
-
allow(File).to receive(:read)
|
185
|
-
.with(absolute_yaml_path)
|
186
|
-
.and_return(fixture('stack-with-variables.yml'))
|
187
190
|
result = subject.execute
|
188
191
|
services = result[:services]
|
189
192
|
expect(services['mysql']['image']).to eq('mariadb:latest')
|
190
193
|
end
|
191
194
|
|
192
195
|
it 'warns about empty variables' do
|
193
|
-
allow(File).to receive(:read)
|
194
|
-
.with(absolute_yaml_path)
|
195
|
-
.and_return(fixture('stack-with-variables.yml'))
|
196
196
|
allow(ENV).to receive(:[])
|
197
197
|
.with('MYSQL_IMAGE')
|
198
198
|
.and_return('')
|
@@ -204,52 +204,48 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
204
204
|
subject.execute
|
205
205
|
}.to output("Value for MYSQL_IMAGE is not set. Substituting with an empty string.\n").to_stdout
|
206
206
|
end
|
207
|
-
end
|
208
207
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
.
|
221
|
-
|
222
|
-
allow(File).to receive(:read)
|
223
|
-
.with(absolute_yaml_path('docker-compose_v2.yml'))
|
224
|
-
.and_return(fixture('docker-compose_v2.yml'))
|
225
|
-
services = subject.execute[:services]
|
226
|
-
expect(services['mysql']['environment'].first).to eq('INTERNAL_VAR=$INTERNAL_VAR')
|
208
|
+
it 'replaces $$VAR variables to $VAR format' do
|
209
|
+
allow_any_instance_of(described_class).to receive(:env).and_return(
|
210
|
+
{
|
211
|
+
'STACK' => 'test',
|
212
|
+
'GRID' => 'test-grid'
|
213
|
+
}
|
214
|
+
)
|
215
|
+
allow(ENV).to receive(:[]).with('TAG').and_return('4.1')
|
216
|
+
allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
|
217
|
+
allow(ENV).to receive(:[]).with('MYSQL_IMAGE').and_return('foo')
|
218
|
+
services = subject.execute[:services]
|
219
|
+
expect(services['mysql']['environment'].first).to eq('INTERNAL_VAR=$INTERNAL_VAR')
|
220
|
+
end
|
227
221
|
end
|
228
222
|
|
229
223
|
context 'environment variables' do
|
230
|
-
|
231
|
-
|
232
|
-
expect(result['wordpress']['environment']).to eq(['WORDPRESS_DB_PASSWORD=test_secret'])
|
224
|
+
subject do
|
225
|
+
described_class.new(fixture_path('stack-with-env-file.yml'))
|
233
226
|
end
|
234
227
|
|
235
|
-
|
236
|
-
|
237
|
-
|
228
|
+
context "with an empty env file" do
|
229
|
+
before(:each) do
|
230
|
+
allow(File).to receive(:readlines).with('.env').and_return([])
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'converts env hash to array' do
|
234
|
+
result = subject.execute[:services]
|
235
|
+
expect(result['wordpress']['environment']).to eq(['WORDPRESS_DB_PASSWORD=test_secret'])
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'does nothing to env array' do
|
239
|
+
result = subject.execute[:services]
|
240
|
+
expect(result['mysql']['environment']).to eq(['MYSQL_ROOT_PASSWORD=test_secret'])
|
241
|
+
end
|
238
242
|
end
|
239
243
|
|
240
244
|
context 'when introduced env_file' do
|
241
245
|
before(:each) do
|
242
|
-
allow(File).to receive(:read)
|
243
|
-
.with(absolute_yaml_path('kontena_v3.yml'))
|
244
|
-
.and_return(fixture('stack-with-env-file.yml'))
|
245
246
|
allow(File).to receive(:readlines).with('.env').and_return(env_file)
|
246
247
|
end
|
247
248
|
|
248
|
-
it 'reads given file' do
|
249
|
-
expect(File).to receive(:readlines).with('.env').and_return(env_file)
|
250
|
-
subject.send(:read_env_file, '.env')
|
251
|
-
end
|
252
|
-
|
253
249
|
it 'discards comment lines' do
|
254
250
|
result = env_file
|
255
251
|
result << "#COMMENTLINE"
|
@@ -294,42 +290,47 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
294
290
|
expect(outcome[:services]).to eq(valid_v3_result['services'])
|
295
291
|
end
|
296
292
|
|
297
|
-
|
298
|
-
|
299
|
-
.
|
300
|
-
|
301
|
-
|
302
|
-
|
293
|
+
context "For an invalid stack file" do
|
294
|
+
subject do
|
295
|
+
described_class.new(fixture_path('stack-invalid.yml'))
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'returns validation errors' do
|
299
|
+
outcome = subject.execute
|
300
|
+
expect(outcome[:errors].size).to eq(1)
|
301
|
+
end
|
303
302
|
end
|
304
303
|
end
|
305
304
|
|
306
305
|
context 'when build option is string' do
|
306
|
+
subject do
|
307
|
+
described_class.new(fixture_path('kontena_build_v3.yml'))
|
308
|
+
end
|
309
|
+
|
307
310
|
it 'expands build option to absolute path' do
|
308
|
-
allow(File).to receive(:read)
|
309
|
-
.with(absolute_yaml_path)
|
310
|
-
.and_return(fixture('kontena_build_v3.yml'))
|
311
311
|
outcome = subject.execute
|
312
|
-
expect(outcome[:services]['webapp']['build']['context']).to eq(
|
312
|
+
expect(outcome[:services]['webapp']['build']['context']).to eq(fixture_path(''))
|
313
313
|
end
|
314
314
|
end
|
315
315
|
|
316
316
|
context 'when build option is Hash' do
|
317
|
+
subject do
|
318
|
+
described_class.new(fixture_path('kontena_build_v3.yml'))
|
319
|
+
end
|
320
|
+
|
317
321
|
it 'expands build context to absolute path' do
|
318
|
-
allow(File).to receive(:read)
|
319
|
-
.with(absolute_yaml_path)
|
320
|
-
.and_return(fixture('kontena_build_v3.yml'))
|
321
322
|
outcome = subject.execute
|
322
|
-
expect(outcome[:services]['webapp']['build']['context']).to eq(
|
323
|
+
expect(outcome[:services]['webapp']['build']['context']).to eq(fixture_path(''))
|
323
324
|
end
|
324
325
|
end
|
325
326
|
|
326
327
|
context 'normalize_build_args' do
|
328
|
+
subject do
|
329
|
+
described_class.new(fixture_path('kontena_build_v3.yml'))
|
330
|
+
end
|
331
|
+
|
327
332
|
context 'when build option is string' do
|
328
333
|
it 'skips normalizing' do
|
329
|
-
allow(File).to receive(:read)
|
330
|
-
.with(absolute_yaml_path)
|
331
|
-
.and_return(fixture('kontena_build_v3.yml'))
|
332
|
-
|
333
334
|
options = {
|
334
335
|
'build' => '.'
|
335
336
|
}
|
@@ -341,10 +342,6 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
341
342
|
|
342
343
|
context 'when build arguments option is Hash' do
|
343
344
|
it 'does not do anything' do
|
344
|
-
allow(File).to receive(:read)
|
345
|
-
.with(absolute_yaml_path)
|
346
|
-
.and_return(fixture('kontena_build_v3.yml'))
|
347
|
-
|
348
345
|
options = {
|
349
346
|
'build' => {
|
350
347
|
'context' => '.',
|
@@ -363,10 +360,6 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
363
360
|
|
364
361
|
context 'when build arguments option is Array' do
|
365
362
|
it 'converts it to array' do
|
366
|
-
allow(File).to receive(:read)
|
367
|
-
.with(absolute_yaml_path)
|
368
|
-
.and_return(fixture('kontena_build_v3.yml'))
|
369
|
-
|
370
363
|
options = {
|
371
364
|
'build' => {
|
372
365
|
'context' => '.',
|
@@ -383,25 +376,39 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
383
376
|
end
|
384
377
|
|
385
378
|
describe '#stack_name' do
|
379
|
+
subject do
|
380
|
+
described_class.new(fixture_path('kontena_v3.yml'))
|
381
|
+
end
|
382
|
+
|
386
383
|
it 'returns name for v3' do
|
387
|
-
allow(File).to receive(:read)
|
388
|
-
.with(absolute_yaml_path)
|
389
|
-
.and_return(fixture('kontena_v3.yml'))
|
390
384
|
name = subject.stack_name
|
391
385
|
expect(name).to eq('stackname')
|
392
386
|
end
|
393
387
|
end
|
394
388
|
|
395
389
|
context 'origins' do
|
390
|
+
before do
|
391
|
+
allow(File).to receive(:read)
|
392
|
+
.with(fixture_path('kontena_v3.yml'))
|
393
|
+
.and_return(fixture('kontena_v3.yml'))
|
394
|
+
end
|
395
|
+
|
396
396
|
it 'can read from a file' do
|
397
|
-
|
398
|
-
.with(
|
399
|
-
.and_return(fixture('
|
397
|
+
allow(File).to receive(:read)
|
398
|
+
.with(fixture_path('docker-compose_v2.yml'))
|
399
|
+
.and_return(fixture('docker-compose-invalid.yml'))
|
400
|
+
|
401
|
+
subject = described_class.new(fixture_path('kontena_v3.yml'))
|
402
|
+
|
400
403
|
expect(subject.from_file?).to be_truthy
|
401
404
|
expect(subject.execute[:registry]).to eq 'file://'
|
402
405
|
end
|
403
406
|
|
404
407
|
it 'can read from the registry' do
|
408
|
+
allow(File).to receive(:read)
|
409
|
+
.with(File.expand_path('docker-compose_v2.yml'))
|
410
|
+
.and_return(fixture('docker-compose-invalid.yml'))
|
411
|
+
|
405
412
|
stack_double = double
|
406
413
|
allow_any_instance_of(Kontena::StacksCache::RegistryClientFactory).to receive(:cloud_auth?).and_return(true)
|
407
414
|
expect(Kontena::StacksCache).to receive(:cache).with('foo/foo', nil).and_return(stack_double)
|
@@ -412,6 +419,10 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
412
419
|
end
|
413
420
|
|
414
421
|
it 'can read from an url' do
|
422
|
+
allow(File).to receive(:read)
|
423
|
+
.with(File.expand_path('docker-compose_v2.yml'))
|
424
|
+
.and_return(fixture('docker-compose-invalid.yml'))
|
425
|
+
|
415
426
|
stub_request(:get, "http://foo.example.com/foo").to_return(:status => 200, :body => fixture('stack-with-liquid.yml'), :headers => {})
|
416
427
|
allow_any_instance_of(described_class).to receive(:load_from_url).and_return(fixture('stack-with-liquid.yml'))
|
417
428
|
instance = described_class.new('http://foo.example.com/foo')
|
@@ -420,21 +431,10 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
420
431
|
end
|
421
432
|
end
|
422
433
|
|
423
|
-
context
|
424
|
-
context
|
425
|
-
|
426
|
-
|
427
|
-
.with(absolute_yaml_path('kontena_v3.yml'))
|
428
|
-
.and_return(fixture('stack-with-liquid.yml'))
|
429
|
-
allow_any_instance_of(described_class).to receive(:env).and_return(
|
430
|
-
{
|
431
|
-
'STACK' => 'test',
|
432
|
-
'GRID' => 'test-grid',
|
433
|
-
'TAG' => '4.1',
|
434
|
-
'MYSQL_IMAGE' => 'mariadb:latest'
|
435
|
-
}
|
436
|
-
)
|
437
|
-
allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
|
434
|
+
context "using Liquid templates" do
|
435
|
+
context "for a valid stack file" do
|
436
|
+
subject do
|
437
|
+
described_class.new(fixture_path('stack-with-liquid.yml'))
|
438
438
|
end
|
439
439
|
|
440
440
|
it 'does not interpolate liquid into variables' do
|
@@ -446,20 +446,9 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
446
446
|
end
|
447
447
|
end
|
448
448
|
|
449
|
-
context
|
450
|
-
|
451
|
-
|
452
|
-
.with(absolute_yaml_path('kontena_v3.yml'))
|
453
|
-
.and_return(fixture('stack-with-invalid-liquid.yml'))
|
454
|
-
allow_any_instance_of(described_class).to receive(:env).and_return(
|
455
|
-
{
|
456
|
-
'STACK' => 'test',
|
457
|
-
'GRID' => 'test-grid',
|
458
|
-
'TAG' => '4.1',
|
459
|
-
'MYSQL_IMAGE' => 'mariadb:latest'
|
460
|
-
}
|
461
|
-
)
|
462
|
-
allow(ENV).to receive(:[]).with('TEST_ENV_VAR').and_return('foo')
|
449
|
+
context "for invalid Liquid syntax" do
|
450
|
+
subject do
|
451
|
+
described_class.new(fixture_path('stack-with-invalid-liquid.yml'))
|
463
452
|
end
|
464
453
|
|
465
454
|
it 'raises' do
|
@@ -467,4 +456,48 @@ describe Kontena::Cli::Stacks::YAML::Reader do
|
|
467
456
|
end
|
468
457
|
end
|
469
458
|
end
|
459
|
+
|
460
|
+
context "for an undefined variable" do
|
461
|
+
subject do
|
462
|
+
described_class.new(fixture_path('stack-with-liquid-undefined.yml'))
|
463
|
+
end
|
464
|
+
|
465
|
+
it "raises an undefined variable error" do
|
466
|
+
expect{subject.execute}.to raise_error(Liquid::UndefinedVariable, /undefined variable asdflol/)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
context "for an optional variable that is not defined" do
|
471
|
+
subject do
|
472
|
+
described_class.new(fixture_path('stack-with-liquid-optional.yml'))
|
473
|
+
end
|
474
|
+
|
475
|
+
before do
|
476
|
+
allow(ENV).to receive(:[]).with('asdf').and_return(nil)
|
477
|
+
end
|
478
|
+
|
479
|
+
it "omits the env" do
|
480
|
+
outcome = subject.execute
|
481
|
+
|
482
|
+
expect(outcome[:variables]).to eq('asdf' => nil), subject.variables.inspect
|
483
|
+
expect(outcome[:services]['test']['environment']).to eq nil
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
context "for an optional variable that is defined" do
|
488
|
+
subject do
|
489
|
+
described_class.new(fixture_path('stack-with-liquid-optional.yml'))
|
490
|
+
end
|
491
|
+
|
492
|
+
before do
|
493
|
+
allow(ENV).to receive(:[]).with('asdf').and_return('test')
|
494
|
+
end
|
495
|
+
|
496
|
+
it "defines the env" do
|
497
|
+
outcome = subject.execute
|
498
|
+
|
499
|
+
expect(outcome[:variables]).to eq 'asdf' => 'test'
|
500
|
+
expect(outcome[:services]['test']['environment']).to eq ['ASDF=test']
|
501
|
+
end
|
502
|
+
end
|
470
503
|
end
|