bosh-workspace 0.8.5 → 0.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -2
- data/.ruby-gemset +1 -1
- data/.travis.yml +2 -0
- data/Guardfile +2 -2
- data/README.md +4 -4
- data/bosh-workspace.gemspec +2 -1
- data/lib/bosh/cli/commands/deployment_patch.rb +96 -0
- data/lib/bosh/cli/commands/prepare.rb +6 -4
- data/lib/bosh/workspace/credentials.rb +30 -0
- data/lib/bosh/workspace/deployment_patch.rb +90 -0
- data/lib/bosh/workspace/helpers/git_credentials_helper.rb +95 -0
- data/lib/bosh/workspace/helpers/spiff_helper.rb +1 -0
- data/lib/bosh/workspace/project_deployment.rb +2 -44
- data/lib/bosh/workspace/release.rb +20 -23
- data/lib/bosh/workspace/schemas/credentials.rb +27 -0
- data/lib/bosh/workspace/schemas/deployment_patch.rb +15 -0
- data/lib/bosh/workspace/schemas/project_deployment.rb +21 -0
- data/lib/bosh/workspace/schemas/releases.rb +16 -0
- data/lib/bosh/workspace/schemas/stemcells.rb +25 -0
- data/lib/bosh/workspace/shell.rb +67 -0
- data/lib/bosh/workspace/tasks/bosh_command_runner.rb +29 -0
- data/lib/bosh/workspace/tasks/deployment.rb +63 -0
- data/lib/bosh/workspace/tasks/workspace.rake +69 -0
- data/lib/bosh/workspace/tasks.rb +15 -0
- data/lib/bosh/workspace/version.rb +1 -1
- data/lib/bosh/workspace.rb +14 -0
- data/spec/assets/foo-boshrelease-repo-new-structure.zip +0 -0
- data/spec/assets/foo-boshrelease-repo-updated.zip +0 -0
- data/spec/assets/foo-boshrelease-repo.zip +0 -0
- data/spec/assets/foo-boshworkspace.zip +0 -0
- data/spec/commands/deployment_patch_spec.rb +152 -0
- data/spec/commands/prepare_spec.rb +5 -3
- data/spec/credentials_spec.rb +46 -0
- data/spec/deployment_patch_spec.rb +171 -0
- data/spec/helpers/git_credentials_helper_spec.rb +160 -0
- data/spec/helpers/spiff_helper_spec.rb +16 -3
- data/spec/project_deployment_spec.rb +52 -163
- data/spec/release_spec.rb +208 -80
- data/spec/schemas/credentials_spec.rb +28 -0
- data/spec/schemas/deployment_patch_spec.rb +30 -0
- data/spec/schemas/project_deployment_spec.rb +45 -0
- data/spec/schemas/releases_spec.rb +31 -0
- data/spec/schemas/stemcells_spec.rb +37 -0
- data/spec/shell_spec.rb +70 -0
- data/spec/spec_helper.rb +11 -5
- data/spec/support/shared_contexts/rake.rb +37 -0
- data/spec/tasks/bosh_command_runner_spec.rb +39 -0
- data/spec/tasks/deployment_spec.rb +80 -0
- data/spec/tasks/workspace_task_spec.rb +99 -0
- metadata +69 -7
@@ -0,0 +1,25 @@
|
|
1
|
+
module Bosh::Workspace
|
2
|
+
module Schemas
|
3
|
+
class Stemcells < Membrane::Schemas::Base
|
4
|
+
def validate(object)
|
5
|
+
Membrane::SchemaParser.parse do
|
6
|
+
[{
|
7
|
+
"name" => String,
|
8
|
+
"version" => StemcellVersion.new
|
9
|
+
}]
|
10
|
+
end.validate object
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class StemcellVersion < Membrane::Schemas::Base
|
15
|
+
def validate(object)
|
16
|
+
return if object.is_a? Integer
|
17
|
+
return if object.is_a? Float
|
18
|
+
return if object == "latest"
|
19
|
+
return if object.to_s =~ /^\d+\.\d+$/
|
20
|
+
raise Membrane::SchemaValidationError.new(
|
21
|
+
"Should match: latest, version.patch or version. Given: #{object}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Workspace
|
3
|
+
class Shell
|
4
|
+
def initialize(stdout = $stdout)
|
5
|
+
@stdout = stdout
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(command, options = {})
|
9
|
+
output_lines = run_command(command, options)
|
10
|
+
output_lines = tail(output_lines, options)
|
11
|
+
|
12
|
+
command_output = output_lines.join("\n")
|
13
|
+
report(command, command_output, options)
|
14
|
+
command_output
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :stdout
|
20
|
+
|
21
|
+
def run_command(command, options)
|
22
|
+
stdout.puts command if options[:output_command]
|
23
|
+
lines = []
|
24
|
+
|
25
|
+
if options[:env]
|
26
|
+
# Wrap in a shell because existing api to Shell#run takes a string
|
27
|
+
# which makes it really hard to pass it to popen with custom environment.
|
28
|
+
popen_args = [options[:env], ENV['SHELL'] || 'bash', '-c', command]
|
29
|
+
else
|
30
|
+
popen_args = command
|
31
|
+
end
|
32
|
+
|
33
|
+
IO.popen(popen_args) do |io|
|
34
|
+
io.each do |line|
|
35
|
+
stdout.puts line.chomp
|
36
|
+
stdout.flush
|
37
|
+
lines << line.chomp
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
lines
|
42
|
+
end
|
43
|
+
|
44
|
+
def tail(lines, options)
|
45
|
+
line_number = options[:last_number]
|
46
|
+
line_number ? lines.last(line_number) : lines
|
47
|
+
end
|
48
|
+
|
49
|
+
def report(cmd, command_output, options)
|
50
|
+
return if command_exited_successfully?
|
51
|
+
|
52
|
+
err_msg = "Failed: '#{cmd}' from #{pwd}, with exit status #{$?.to_i}\n\n #{command_output}"
|
53
|
+
options[:ignore_failures] ? stdout.puts("#{err_msg}, continuing anyway") : raise(err_msg)
|
54
|
+
end
|
55
|
+
|
56
|
+
def command_exited_successfully?
|
57
|
+
$?.success?
|
58
|
+
end
|
59
|
+
|
60
|
+
def pwd
|
61
|
+
Dir.pwd
|
62
|
+
rescue Errno::ENOENT
|
63
|
+
'a deleted directory'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bosh::Workspace::Tasks
|
2
|
+
class BoshCommandRunner
|
3
|
+
attr_reader :target, :username, :password
|
4
|
+
attr_accessor :deployment_file
|
5
|
+
|
6
|
+
def initialize(target, username, password)
|
7
|
+
@target = target
|
8
|
+
@username = username
|
9
|
+
@password = password
|
10
|
+
@shell = Bosh::Workspace::Shell.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(command, options = {})
|
14
|
+
options.merge! default_options
|
15
|
+
args = ['-n', '-t', target]
|
16
|
+
args.concat ['-d', deployment_file] if deployment_file
|
17
|
+
@shell.run "bundle exec bosh #{args.join(' ')} #{command}", options
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def default_options
|
23
|
+
{
|
24
|
+
output_command: true,
|
25
|
+
env: { "BOSH_USER" => username, "BOSH_PASSWORD" => password }
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Bosh::Workspace::Tasks
|
2
|
+
class Deployment
|
3
|
+
def initialize(deployment)
|
4
|
+
schema.validate deployment
|
5
|
+
@raw = OpenStruct.new(deployment)
|
6
|
+
end
|
7
|
+
|
8
|
+
def name
|
9
|
+
file = File.join 'deployments', file_name
|
10
|
+
YAML.load_file(file)["name"]
|
11
|
+
end
|
12
|
+
|
13
|
+
def target
|
14
|
+
return @raw.target unless @raw.target =~ /@/
|
15
|
+
@raw.target.split('@')[1]
|
16
|
+
end
|
17
|
+
|
18
|
+
def username
|
19
|
+
return "admin" unless @raw.target =~ /@/
|
20
|
+
@raw.target.match(/^([^@:]+)/)[1] || "admin"
|
21
|
+
end
|
22
|
+
|
23
|
+
def password
|
24
|
+
return "admin" unless @raw.target =~ /@/
|
25
|
+
match = @raw.target.match(/^[^:@]+:([^@]+)/)
|
26
|
+
match && match[1] || "admin"
|
27
|
+
end
|
28
|
+
|
29
|
+
def merged_file
|
30
|
+
File.join ".deployments", file_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def file_name
|
34
|
+
@raw.name + ".yml"
|
35
|
+
end
|
36
|
+
|
37
|
+
def errands
|
38
|
+
@raw.errands
|
39
|
+
end
|
40
|
+
|
41
|
+
def apply_patch
|
42
|
+
@raw.apply_patch
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_patch
|
46
|
+
@raw.create_patch
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def schema
|
52
|
+
Membrane::SchemaParser.parse do
|
53
|
+
{
|
54
|
+
"name" => /^((?!\.yml).)*$/, # Should not contain .yml
|
55
|
+
"target" => String,
|
56
|
+
optional("apply_patch") => String,
|
57
|
+
optional("create_patch") => String,
|
58
|
+
optional("errands") => [String]
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
namespace :workspace do
|
2
|
+
include Bosh::Workspace::Tasks
|
3
|
+
|
4
|
+
desc "Apply or create patches as defined in deployments.yml"
|
5
|
+
task :patch do
|
6
|
+
with_deployments do |deployment|
|
7
|
+
if apply_patch_path = deployment.apply_patch
|
8
|
+
bosh "apply deployment patch #{apply_patch_path}"
|
9
|
+
end
|
10
|
+
|
11
|
+
if create_patch_path = deployment.create_patch
|
12
|
+
bosh "create deployment patch #{create_patch_path}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Deploy deployments as defined in deployments.yml"
|
18
|
+
task :deploy do
|
19
|
+
with_deployments do
|
20
|
+
bosh "prepare deployment"
|
21
|
+
bosh_deploy
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Verifies deployments by running errands specified in deployments.yml"
|
26
|
+
task :run_errands do
|
27
|
+
with_deployments do |deployment|
|
28
|
+
deployment.errands.each do |errand|
|
29
|
+
bosh "run errand #{errand}"
|
30
|
+
end if deployment.errands
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Cleans up by deleting all deployments specified in deployments.yml"
|
35
|
+
task :clean do
|
36
|
+
unless ENV["DESTROY_DEPLOYMENTS"]
|
37
|
+
raise "Set DESTROY_DEPLOYMENTS to confirm deployment destruction"
|
38
|
+
end
|
39
|
+
|
40
|
+
with_deployments(set_deployment: false) do |deployment|
|
41
|
+
bosh "delete deployment #{deployment.name} --force", ignore_failures: true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_deployments(options = {})
|
46
|
+
deployments.each do |d|
|
47
|
+
@cli = BoshCommandRunner.new(d.target, d.username, d.password)
|
48
|
+
unless options[:set_deployment] == false
|
49
|
+
@cli.deployment_file = d.merged_file
|
50
|
+
end
|
51
|
+
yield d
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def deployments
|
56
|
+
@deployments ||= begin
|
57
|
+
YAML.load_file("deployments.yml").map { |d| Deployment.new(d) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def bosh_deploy
|
62
|
+
out = bosh("deploy", last_number: 1)
|
63
|
+
exit 1 if out =~ /error/
|
64
|
+
end
|
65
|
+
|
66
|
+
def bosh(command, options = {})
|
67
|
+
@cli.run command, options
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "membrane"
|
3
|
+
|
4
|
+
module Bosh
|
5
|
+
module Workspace
|
6
|
+
module Tasks; end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require "bosh/workspace/shell"
|
11
|
+
require "bosh/workspace/tasks/bosh_command_runner.rb"
|
12
|
+
require "bosh/workspace/tasks/deployment.rb"
|
13
|
+
|
14
|
+
rake_paths = File.expand_path('tasks/**/*.rake', File.dirname(__FILE__))
|
15
|
+
Dir.glob(rake_paths).each { |r| import r } if defined? import
|
data/lib/bosh/workspace.rb
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
module Bosh; module Workspace; end; end
|
2
2
|
|
3
|
+
require "membrane"
|
4
|
+
require "shellwords"
|
5
|
+
require "rugged"
|
6
|
+
require "hashdiff"
|
3
7
|
require "cli/core_ext"
|
4
8
|
require "cli/validation"
|
5
9
|
|
6
10
|
require "bosh/workspace/helpers/spiff_helper"
|
7
11
|
require "bosh/workspace/helpers/project_deployment_helper"
|
12
|
+
require "bosh/workspace/helpers/git_credentials_helper"
|
8
13
|
require "bosh/workspace/helpers/release_helper"
|
9
14
|
require "bosh/workspace/helpers/stemcell_helper"
|
10
15
|
require "bosh/workspace/helpers/dns_helper"
|
11
16
|
|
17
|
+
require "bosh/workspace/schemas/project_deployment"
|
18
|
+
require "bosh/workspace/schemas/deployment_patch"
|
19
|
+
require "bosh/workspace/schemas/releases"
|
20
|
+
require "bosh/workspace/schemas/stemcells"
|
21
|
+
require "bosh/workspace/schemas/credentials"
|
22
|
+
|
23
|
+
require "bosh/workspace/shell"
|
12
24
|
require "bosh/workspace/manifest_builder"
|
13
25
|
require "bosh/workspace/release"
|
14
26
|
require "bosh/workspace/stemcell"
|
15
27
|
require "bosh/workspace/project_deployment"
|
16
28
|
require "bosh/workspace/stub_file"
|
29
|
+
require "bosh/workspace/deployment_patch"
|
30
|
+
require "bosh/workspace/credentials"
|
17
31
|
require "bosh/workspace/version"
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require "bosh/cli/commands/deployment_patch"
|
2
|
+
|
3
|
+
module Bosh::Cli::Command
|
4
|
+
include Bosh::Workspace
|
5
|
+
|
6
|
+
describe DeploymentPatch do
|
7
|
+
let(:command) { DeploymentPatch.new }
|
8
|
+
let(:patch) do
|
9
|
+
instance_double 'Bosh::Workspace::DeploymentPatch', templates_ref: ref
|
10
|
+
end
|
11
|
+
let(:current_patch) { instance_double 'Bosh::Workspace::DeploymentPatch' }
|
12
|
+
let(:deployment_file) { 'deployments/foo.yml' }
|
13
|
+
let(:patch_file) { 'patch.yml' }
|
14
|
+
let(:project_dir) { File.realpath Dir.mktmpdir }
|
15
|
+
let(:changes?) { nil }
|
16
|
+
let(:valid?) { true }
|
17
|
+
let(:ref) { "baz" }
|
18
|
+
let(:changes) do
|
19
|
+
{ stemcells: "foo", releases: "bar", templates_ref: ref }
|
20
|
+
end
|
21
|
+
|
22
|
+
before do
|
23
|
+
Dir.chdir project_dir
|
24
|
+
allow(Bosh::Workspace::DeploymentPatch).to receive(:create)
|
25
|
+
.with(deployment_file, /templates/).and_return(current_patch)
|
26
|
+
allow(Bosh::Workspace::DeploymentPatch).to receive(:from_file)
|
27
|
+
.with(patch_file).and_return(patch)
|
28
|
+
allow(current_patch).to receive(:changes?).with(patch)
|
29
|
+
.and_return(changes?)
|
30
|
+
expect(command).to receive(:require_project_deployment)
|
31
|
+
allow(command).to receive_message_chain("project_deployment.file")
|
32
|
+
.and_return(deployment_file)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '.create' do
|
36
|
+
it 'writes to file' do
|
37
|
+
expect(current_patch).to receive(:to_file).with(patch_file)
|
38
|
+
expect(command).to receive(:say).with /wrote patch/i
|
39
|
+
command.create(patch_file)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '.apply' do
|
44
|
+
let(:patch_valid?) { true }
|
45
|
+
|
46
|
+
before do
|
47
|
+
expect(patch).to receive(:valid?).and_return(patch_valid?)
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with non valid patch' do
|
51
|
+
let(:patch_valid?) { false }
|
52
|
+
|
53
|
+
it "raises an error" do
|
54
|
+
expect(patch).to receive(:errors).and_return(['foo', 'bar'])
|
55
|
+
expect(command).to receive(:say).with(/validation errors/i)
|
56
|
+
expect(command).to receive(:say).with(/foo/)
|
57
|
+
expect(command).to receive(:say).with(/bar/)
|
58
|
+
expect { command.apply(patch_file) }.to raise_error(/is not valid/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'with changes' do
|
63
|
+
let(:changes?) { true }
|
64
|
+
let(:index) do
|
65
|
+
instance_double('Rugged::Index',
|
66
|
+
read_tree: true, write_tree: true, add_all: true)
|
67
|
+
end
|
68
|
+
let(:repo) { instance_double 'Rugged::Repository', index: index }
|
69
|
+
|
70
|
+
def expect_patch_changes_table
|
71
|
+
expect(command).to receive(:say) do |s|
|
72
|
+
subject = s.to_s.delete ' '
|
73
|
+
expect(subject).to include "stemcells|foo"
|
74
|
+
expect(subject).to include "releases|bar"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
before do
|
79
|
+
allow(repo).to receive_message_chain('head.target.tree')
|
80
|
+
expect(current_patch).to receive(:changes).with(patch)
|
81
|
+
.and_return(changes)
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'no dry-run' do
|
85
|
+
before do
|
86
|
+
allow(command).to receive(:fetch_repo).with(/templates/)
|
87
|
+
expect(patch).to receive(:apply).with(deployment_file, /templates/)
|
88
|
+
expect(command).to receive(:say).with /successfully applied/i
|
89
|
+
expect_patch_changes_table
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'without no-commit' do
|
93
|
+
before do
|
94
|
+
expect(Rugged::Repository).to receive(:new)
|
95
|
+
.with(project_dir).and_return(repo)
|
96
|
+
end
|
97
|
+
|
98
|
+
def expect_commit(message)
|
99
|
+
expect(Rugged::Commit).to receive(:create) do |repo, options|
|
100
|
+
expect(options[:message]).to match message
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'applies changes, shows changes and commits' do
|
105
|
+
expect_commit "Applied stemcells foo," \
|
106
|
+
" releases bar, templates_ref baz"
|
107
|
+
command.apply(patch_file)
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'without templates_ref' do
|
111
|
+
let(:ref) { nil }
|
112
|
+
let(:changes) do
|
113
|
+
{ stemcells: "foo", releases: "bar" }
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'applies changes, shows changes and commits' do
|
117
|
+
expect_commit("Applied stemcells foo, releases bar")
|
118
|
+
expect(command).to_not receive(:fetch_repo)
|
119
|
+
command.apply(patch_file)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'no-commit' do
|
125
|
+
it 'applies changes and shows changes' do
|
126
|
+
command.add_option(:no_commit, true)
|
127
|
+
command.apply(patch_file)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'dry-run' do
|
133
|
+
it 'only shows changes' do
|
134
|
+
expect(command).to receive(:say).with /deployment patch/i
|
135
|
+
expect_patch_changes_table
|
136
|
+
command.add_option(:dry_run, true)
|
137
|
+
command.apply(patch_file)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'without changes' do
|
143
|
+
let(:changes?) { false }
|
144
|
+
|
145
|
+
it 'says no changes' do
|
146
|
+
expect(command).to receive(:say).with /no changes/i
|
147
|
+
command.apply(patch_file)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -5,7 +5,7 @@ describe Bosh::Cli::Command::Prepare do
|
|
5
5
|
let(:command) { Bosh::Cli::Command::Prepare.new }
|
6
6
|
let(:release) do
|
7
7
|
instance_double("Bosh::Workspace::Release",
|
8
|
-
name: "foo", version: "1", repo_dir: ".releases/foo",
|
8
|
+
name: "foo", version: "1", repo_dir: ".releases/foo", git_url: "/.git",
|
9
9
|
name_version: "foo/1", manifest_file: "releases/foo-1.yml")
|
10
10
|
end
|
11
11
|
let(:stemcell) do
|
@@ -24,7 +24,7 @@ describe Bosh::Cli::Command::Prepare do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe "prepare_release(s/_repos)" do
|
27
|
-
let(:releases) { [
|
27
|
+
let(:releases) { [release] }
|
28
28
|
let(:stemcells) { [] }
|
29
29
|
let(:ref) { nil }
|
30
30
|
|
@@ -33,6 +33,8 @@ describe Bosh::Cli::Command::Prepare do
|
|
33
33
|
expect(release).to receive(:ref).and_return(ref)
|
34
34
|
expect(command).to receive(:release_uploaded?)
|
35
35
|
.with(release.name, release.version).and_return(release_uploaded)
|
36
|
+
expect(command).to receive(:fetch_or_clone_repo)
|
37
|
+
.with(release.repo_dir, release.git_url)
|
36
38
|
end
|
37
39
|
|
38
40
|
context "release uploaded" do
|
@@ -80,7 +82,7 @@ describe Bosh::Cli::Command::Prepare do
|
|
80
82
|
context "stemcell not uploaded" do
|
81
83
|
let(:stemcell_uploaded) { false }
|
82
84
|
|
83
|
-
before do
|
85
|
+
before do
|
84
86
|
allow(stemcell).to receive(:downloaded?)
|
85
87
|
.and_return(stemcell_downloaded)
|
86
88
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Bosh::Workspace
|
2
|
+
describe Credentials do
|
3
|
+
let(:credentials) do
|
4
|
+
[{ "url" => "foo", "private_key" => "foobarkey" }]
|
5
|
+
end
|
6
|
+
|
7
|
+
before do
|
8
|
+
expect(YAML).to receive(:load_file).with(:file).and_return(credentials)
|
9
|
+
end
|
10
|
+
|
11
|
+
subject do
|
12
|
+
Credentials.new(:file)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#find_by_url' do
|
16
|
+
it "returns credentials when found multiple times" do
|
17
|
+
expect(subject.find_by_url("foo")).to eq({ private_key: "foobarkey" })
|
18
|
+
expect(subject.find_by_url("foo")).to eq({ private_key: "foobarkey" })
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns nil when not found" do
|
22
|
+
expect(subject.find_by_url("bar")).to be nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#perform_validation' do
|
27
|
+
context "valid" do
|
28
|
+
it "validates" do
|
29
|
+
allow_any_instance_of(Schemas::Credentials)
|
30
|
+
.to receive(:validate).with(credentials)
|
31
|
+
expect(subject).to be_valid
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "invalid" do
|
36
|
+
it "has errors" do
|
37
|
+
allow_any_instance_of(Schemas::Credentials)
|
38
|
+
.to receive(:validate).with(credentials)
|
39
|
+
.and_raise(Membrane::SchemaValidationError.new("foo"))
|
40
|
+
expect(subject).to_not be_valid
|
41
|
+
expect(subject.errors).to include "foo"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|