bosh-workspace 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,107 @@
1
+ require "bosh/cli/commands/01_make_manifest"
2
+
3
+ describe Bosh::Cli::Command::Manifests do
4
+ let(:command) { Bosh::Cli::Command::Manifests.new }
5
+ let(:project_deployment) do
6
+ instance_double("Bosh::Manifests::DeploymentManifest")
7
+ end
8
+
9
+ let(:deployment_cmd) { instance_double("Bosh::Cli::Command::Deployment") }
10
+
11
+ before do
12
+ setup_home_dir
13
+ command.add_option(:config, home_file(".bosh_config"))
14
+ command.add_option(:non_interactive, true)
15
+ deployment_cmd.stub(:add_option)
16
+ end
17
+
18
+ describe "#deployment" do
19
+ subject { command.set_current(filename) }
20
+
21
+ let(:filename) { "foo" }
22
+
23
+ before do
24
+ Bosh::Cli::Command::Deployment.should_receive(:new)
25
+ .and_return(deployment_cmd)
26
+ end
27
+
28
+ context "with project deployment" do
29
+ let(:deployment) { "deployments/foo.yml" }
30
+ let(:merged_file) { ".manifests/foo.yml" }
31
+
32
+ it "sets filename to merged file" do
33
+ command.should_receive(:find_deployment).with(filename)
34
+ .and_return(deployment)
35
+ command.should_receive(:project_deployment_file?).with(deployment)
36
+ .and_return(true)
37
+ command.should_receive(:project_deployment=).with(deployment)
38
+ command.should_receive(:validate_project_deployment)
39
+ File.should_receive(:exists?).with(merged_file).and_return(false)
40
+ command.should_receive(:create_placeholder_deployment)
41
+ command.should_receive(:project_deployment)
42
+ .and_return(project_deployment)
43
+ project_deployment.should_receive(:merged_file).and_return(merged_file)
44
+ deployment_cmd.should_receive(:set_current).with(merged_file)
45
+ subject
46
+ end
47
+ end
48
+
49
+ context "without filename" do
50
+ let(:filename) { nil }
51
+
52
+ it "returns current deployment" do
53
+ deployment_cmd.should_receive(:set_current).with(filename)
54
+ subject
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#prepare" do
60
+ subject { command.prepare }
61
+ let(:releases) { ["foo", "bar"] }
62
+ let(:release_manager) { instance_double("Bosh::Manifests::ReleaseManager") }
63
+ let(:work_dir) { asset_dir("manifests-repo") }
64
+
65
+ it "resolves deployment requirements" do
66
+ command.should_receive(:require_project_deployment)
67
+ command.should_receive(:auth_required)
68
+ command.should_receive(:project_deployment).and_return(project_deployment)
69
+ project_deployment.should_receive(:releases).and_return(releases)
70
+ command.should_receive(:work_dir).and_return(work_dir)
71
+ Bosh::Manifests::ReleaseManager.should_receive(:new)
72
+ .with(releases, work_dir).and_return(release_manager)
73
+ release_manager.should_receive(:update_release_repos)
74
+ subject
75
+ end
76
+ end
77
+
78
+ describe "deploy" do
79
+ subject { command.deploy }
80
+
81
+ before do
82
+ Bosh::Cli::Command::Deployment.should_receive(:new)
83
+ .and_return(deployment_cmd)
84
+ command.should_receive(:project_deployment?)
85
+ .and_return(is_project_deployment)
86
+ deployment_cmd.should_receive(:perform)
87
+ end
88
+
89
+ context "with project deployment" do
90
+ let(:is_project_deployment) { true }
91
+
92
+ it "requires project deployment" do
93
+ command.should_receive(:require_project_deployment)
94
+ command.should_receive(:build_project_deployment)
95
+ subject
96
+ end
97
+ end
98
+
99
+ context "with normal deployment" do
100
+ let(:is_project_deployment) { false }
101
+
102
+ it "deploys" do
103
+ subject
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,93 @@
1
+ describe Bosh::Manifests::DeploymentManifest do
2
+ subject { Bosh::Manifests::DeploymentManifest.new manifest_file }
3
+ let(:manifest_file) { get_tmp_file_path(manifest.to_yaml) }
4
+ let(:name) { "foo" }
5
+ let(:uuid) { "foo-bar-uuid" }
6
+ let(:templates) { ["path_to_bar", "path_to_baz"] }
7
+ let(:releases) { [
8
+ { "name" => "foo", "version" => "latest", "git" => "example.com/foo.git" }
9
+ ] }
10
+ let(:meta) { { "foo" => "bar" } }
11
+ let(:manifest) { {
12
+ "name" => name,
13
+ "director_uuid" => uuid,
14
+ "templates" => templates,
15
+ "releases" => releases,
16
+ "meta" => meta,
17
+ } }
18
+
19
+ context "invalid manifest" do
20
+ let(:invalid_manifest) { manifest.tap { |m| m.delete(missing) } }
21
+ let(:manifest_file) { get_tmp_file_path(invalid_manifest.to_yaml) }
22
+
23
+ before do
24
+ subject.validate
25
+ expect(subject).to_not be_valid
26
+ end
27
+
28
+ context "not a hash" do
29
+ let(:invalid_manifest) { "foo" }
30
+ it "raises an error" do
31
+ expect(subject.errors).to eq ["Manifest should be a hash"]
32
+ end
33
+ end
34
+
35
+ context "missing name" do
36
+ let(:missing) { "name" }
37
+ it "raises an error" do
38
+ expect(subject.errors).to eq ["Manifest should contain a name"]
39
+ end
40
+ end
41
+
42
+ context "missing director_uuid" do
43
+ let(:missing) { "director_uuid" }
44
+ it "raises an error" do
45
+ expect(subject.errors).to eq ["Manifest should contain a director_uuid"]
46
+ end
47
+ end
48
+
49
+ context "missing templates" do
50
+ let(:missing) { "templates" }
51
+ it "raises an error" do
52
+ expect(subject.errors).to eq ["Manifest should contain templates"]
53
+ end
54
+ end
55
+
56
+ context "missing releases" do
57
+ let(:missing) { "releases" }
58
+ it "raises an error" do
59
+ expect(subject.errors).to eq ["Manifest should contain releases"]
60
+ end
61
+ end
62
+
63
+ context "missing meta" do
64
+ let(:missing) { "meta" }
65
+ it "raises an error" do
66
+ expect(subject.errors).to eq ["Manifest should contain meta hash"]
67
+ end
68
+ end
69
+ end
70
+
71
+ context "valid manifest" do
72
+ it "has properties" do
73
+ subject.validate
74
+ expect(subject).to be_valid
75
+ expect(subject.name).to eq name
76
+ expect(subject.director_uuid).to eq uuid
77
+ expect(subject.templates).to eq templates
78
+ expect(subject.releases).to eq releases
79
+ expect(subject.meta).to eq meta
80
+ end
81
+ end
82
+
83
+ describe "#merged_file" do
84
+ it "creates parent directory" do
85
+ dir = File.dirname(subject.merged_file)
86
+ expect(File.directory?(dir)).to be_true
87
+ end
88
+
89
+ it "retruns merged file" do
90
+ expect(subject.merged_file).to match /\.deployments\//
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,191 @@
1
+ describe Bosh::Manifests::ProjectDeploymentHelper do
2
+ class HelperTester
3
+ include Bosh::Manifests::ProjectDeploymentHelper
4
+
5
+ attr_reader :director, :deployment
6
+
7
+ def initialize(director, deployment, project_deployment = nil)
8
+ @director = director
9
+ @deployment = deployment
10
+ @project_deployment = project_deployment
11
+ end
12
+ end
13
+
14
+ subject { project_deployment_helper }
15
+ let(:project_deployment_helper) { HelperTester.new(director, deployment) }
16
+ let(:deployment) { nil }
17
+ let(:director) { instance_double('Bosh::Cli::Client::Director') }
18
+ let(:work_dir) { asset_dir("manifests-repo") }
19
+ let(:project_deployment) { instance_double("DeploymentManifest") }
20
+
21
+ describe "project_deployment?" do
22
+ subject { project_deployment_helper.project_deployment? }
23
+ let(:deployment) { File.join work_dir, deployment_path }
24
+
25
+ context "deployment" do
26
+ context "without associated project deployment" do
27
+ let(:deployment_path) { "deployments/bar.yml" }
28
+ it { should be_false }
29
+ end
30
+ context "with associated project deployment" do
31
+ let(:deployment_path) { ".manifests/foo.yml" }
32
+ it { should be_true }
33
+ end
34
+ end
35
+
36
+ context "project deployment" do
37
+ let(:deployment_path) { "deployments/foo.yml" }
38
+ it { should be_true }
39
+ end
40
+ end
41
+
42
+ describe "#project_deployment(=)" do
43
+ let(:deployment) { File.join work_dir, deployment_path }
44
+ let(:deployment_path) { "deployments/foo.yml" }
45
+
46
+ before do
47
+ Bosh::Manifests::DeploymentManifest.should_receive(:new)
48
+ .with(deployment).and_return(project_deployment)
49
+ end
50
+
51
+ it "loads deployment manifest" do
52
+ expect(subject.project_deployment).to eq project_deployment
53
+ end
54
+
55
+ it "memoizes deployment manifest" do
56
+ subject.project_deployment = deployment
57
+ expect(subject.project_deployment).to eq project_deployment
58
+ end
59
+ end
60
+
61
+ describe "#project_deployment_file?" do
62
+ subject do
63
+ project_deployment_helper.project_deployment_file? deployment_file
64
+ end
65
+ let(:deployment_file) { get_tmp_file_path(content.to_yaml) }
66
+
67
+ context "project deployment" do
68
+ let(:content) { { "name" => "foo", "templates" => ["bar.yml"] } }
69
+ it { should be_true }
70
+ end
71
+
72
+ context "normal deployment" do
73
+ let(:content) { { "name" => "foo" } }
74
+ it { should be_false }
75
+ end
76
+ end
77
+
78
+ describe "#require_project_deployment" do
79
+ before do
80
+ subject.should_receive(:project_deployment?)
81
+ .and_return(:is_project_deployment)
82
+ end
83
+
84
+ context "project deployment" do
85
+ let(:is_project_deployment) { true }
86
+ it "validates & builds" do
87
+ subject.should_receive(:validate_project_deployment)
88
+ subject.require_project_deployment
89
+ end
90
+ end
91
+
92
+ context "normal deployment" do
93
+ let(:deployment) { "foo" }
94
+ let(:is_project_deployment) { false }
95
+ it "raises and error" do
96
+ expect { subject.require_project_deployment }.to raise_error /foo/
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "#create_placeholder_deployment" do
102
+ subject { project_deployment_helper.create_placeholder_deployment }
103
+ let(:project_deployment_helper) do
104
+ HelperTester.new(director, deployment, project_deployment)
105
+ end
106
+ let(:deployment) { "deployments/bar.yml" }
107
+ let(:file) { instance_double('File') }
108
+ let(:merged_file) { ".deployments/bar.yml" }
109
+ let(:uuid) { "8451a282-4073" }
110
+ let(:content) { "director_uuid #{uuid}" }
111
+
112
+ it "creates placeholder deployment" do
113
+ project_deployment_helper.should_receive(:resolve_director_uuid)
114
+ project_deployment.should_receive(:merged_file).and_return(merged_file)
115
+ project_deployment.should_receive(:file).and_return(deployment)
116
+ project_deployment.should_receive(:director_uuid).and_return(uuid)
117
+ File.should_receive(:open).with(merged_file, "w").and_yield(file)
118
+ file.should_receive(:write).with(/#{uuid}\s# Don't edit/)
119
+ subject
120
+ end
121
+ end
122
+
123
+ describe "#validate_project_deployment" do
124
+ let(:project_deployment_helper) do
125
+ HelperTester.new(director, deployment, project_deployment)
126
+ end
127
+
128
+ it "raises an error" do
129
+ project_deployment.should_receive(:valid?).and_return(false)
130
+ project_deployment.should_receive(:errors).and_return(["foo"])
131
+ project_deployment.should_receive(:file).and_return(["foo.yml"])
132
+ expect { subject.validate_project_deployment }.to raise_error /foo/
133
+ end
134
+ end
135
+
136
+ describe "#build_project_deployment" do
137
+ subject { project_deployment_helper.build_project_deployment }
138
+ let(:project_deployment_helper) do
139
+ HelperTester.new(director, deployment, project_deployment)
140
+ end
141
+
142
+ it "builds project deployment manifest" do
143
+ project_deployment_helper.should_receive(:resolve_director_uuid)
144
+ project_deployment_helper.should_receive(:work_dir).and_return(work_dir)
145
+ Bosh::Manifests::ManifestBuilder.should_receive(:build)
146
+ .with(project_deployment, work_dir)
147
+ subject
148
+ end
149
+ end
150
+
151
+ describe "#resolve_director_uuid" do
152
+ subject { project_deployment_helper.resolve_director_uuid }
153
+ let(:project_deployment_helper) do
154
+ HelperTester.new(director, deployment, project_deployment)
155
+ end
156
+ let(:status) { { "uuid" => current_uuid, "cpi" => cpi } }
157
+ let(:current_uuid) { "current-uuid" }
158
+
159
+ before do
160
+ project_deployment.should_receive(:director_uuid).and_return(uuid)
161
+ director.stub(:get_status).and_return(status)
162
+ end
163
+
164
+ context "using the warden cpi" do
165
+ let(:cpi) { "warden" }
166
+
167
+ context "with director uuid current" do
168
+ let(:uuid) { "current" }
169
+ it "builds manifest" do
170
+ project_deployment.should_receive(:director_uuid=).with(current_uuid)
171
+ subject
172
+ end
173
+ end
174
+
175
+ context "with director uuid" do
176
+ let(:uuid) { "8451a282-4073" }
177
+ it "builds manifest" do
178
+ subject
179
+ end
180
+ end
181
+ end
182
+
183
+ context "and without warden cpi" do
184
+ let(:uuid) { "current" }
185
+ let(:cpi) { "not-warden" }
186
+ it "raises an error" do
187
+ expect { subject }.to raise_error /may not be used in production/
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,55 @@
1
+ describe Bosh::Manifests::SpiffHelper do
2
+ describe ".spiff" do
3
+ class SpiffHelperTester
4
+ include Bosh::Manifests::SpiffHelper
5
+ end
6
+ subject { SpiffHelperTester.new }
7
+ let(:path) { asset_dir("bin") }
8
+ let(:templates) { ["foo.yml", "bar.yml"] }
9
+ let(:target_file) { "spiffed_manifest.yml" }
10
+
11
+ around do |example|
12
+ original_path = ENV["PATH"]
13
+ ENV["PATH"] = path
14
+ example.run
15
+ ENV["PATH"] = original_path
16
+ end
17
+
18
+ before do
19
+ subject.should_receive(:sh).and_yield(result)
20
+ end
21
+
22
+ context "spiff not in path" do
23
+ let(:path) { asset_dir("empty_bin") }
24
+ let(:result) { Bosh::Exec::Result.new("spiff", "", 0, true) }
25
+
26
+ it "raises an error" do
27
+ expect{ subject.spiff_merge templates, target_file }
28
+ .to raise_error /make sure spiff is installed/
29
+ end
30
+ end
31
+
32
+ context "spiff error" do
33
+ let(:path) { asset_dir("empty_bin") }
34
+ let(:result) { Bosh::Exec::Result.new("spiff", "spiff error", 1, false) }
35
+
36
+ it "raises an error" do
37
+ subject.should_receive(:say).with(/Command failed/)
38
+ expect{ subject.spiff_merge templates, target_file }
39
+ .to raise_error /spiff error/
40
+ end
41
+ end
42
+
43
+ describe ".merge" do
44
+ let(:file) { instance_double("File") }
45
+ let(:output) { "---\n{}" }
46
+ let(:result) { Bosh::Exec::Result.new("spiff", output, 0, false) }
47
+
48
+ it "merges manifests" do
49
+ File.should_receive(:open).with(target_file, 'w').and_yield(file)
50
+ file.should_receive(:write).with(output)
51
+ subject.spiff_merge templates, target_file
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,88 @@
1
+ describe Bosh::Manifests::ManifestBuilder do
2
+ let(:manifest) { instance_double("Bosh::Manifests::Manifest") }
3
+ let(:work_dir) { asset_dir("manifests-repo") }
4
+ let(:target_name) { "bar" }
5
+ let(:target_file) {
6
+ File.join(work_dir, ".manifests", "#{target_name}.yml") }
7
+
8
+ describe ".build" do
9
+ subject { Bosh::Manifests::ManifestBuilder.build manifest, work_dir }
10
+ let(:manifest_builder) {
11
+ instance_double("Bosh::Manifests::ManifestBuilder") }
12
+
13
+ it "creates builder and merges templates" do
14
+ Bosh::Manifests::ManifestBuilder.should_receive(:new)
15
+ .with(manifest, work_dir).and_return(manifest_builder)
16
+ manifest_builder.should_receive(:merge_templates)
17
+ subject
18
+ end
19
+ end
20
+
21
+ describe "#merge_templates" do
22
+ subject { Bosh::Manifests::ManifestBuilder.new manifest, work_dir }
23
+ let(:templates) { ["foo.yml"] }
24
+ let(:template_path) { File.join(work_dir, "templates/foo.yml") }
25
+ let(:template_exists) { true }
26
+
27
+ before do
28
+ manifest.should_receive(:templates).and_return(templates)
29
+ File.should_receive(:exists?).with(template_path)
30
+ .and_return(template_exists)
31
+ end
32
+
33
+ context "missing template" do
34
+ let(:template_exists) { false }
35
+ it "raises error" do
36
+ expect{ subject.merge_templates }.to raise_error /does not exist/
37
+ end
38
+ end
39
+
40
+ context "template exists" do
41
+ let(:dir_exists) { true }
42
+ let(:target_dir) { File.join(work_dir, ".manifests" ) }
43
+ let(:uuid) { "foo-bar-uuid" }
44
+ let(:meta_file_path) do
45
+ File.join(work_dir, ".stubs", "#{target_name}.yml")
46
+ end
47
+ let(:meta_file) { instance_double("File") }
48
+ let(:meta) { { "foo" => "bar" } }
49
+ let(:release) { { "name" => "foo", "version" => "latest" } }
50
+ let(:releases) { [release] }
51
+ let(:raw_releases) { [release.merge("git" => "release_repo.git")] }
52
+ let(:meta_file_content) do
53
+ {
54
+ "director_uuid" => uuid,
55
+ "releases" => releases,
56
+ "meta" => meta
57
+ }
58
+ end
59
+
60
+ before do
61
+ manifest.should_receive(:name).and_return(target_name)
62
+ manifest.should_receive(:meta).and_return(meta)
63
+ manifest.should_receive(:director_uuid).and_return(uuid)
64
+ manifest.should_receive(:releases).and_return(raw_releases)
65
+ manifest.should_receive(:merged_file).and_return(target_file)
66
+ File.should_receive(:exists?).and_return(dir_exists)
67
+ File.should_receive(:open).with(meta_file_path, "w")
68
+ .and_yield(meta_file)
69
+ meta_file.should_receive(:write).with(meta_file_content.to_yaml)
70
+ end
71
+
72
+ context "no hidden dirs" do
73
+ let(:dir_exists) { false }
74
+ it "creates hidden dirs" do
75
+ subject.stub(:spiff_merge)
76
+ Dir.should_receive(:mkdir).with(/.stubs/)
77
+ subject.merge_templates
78
+ end
79
+ end
80
+
81
+ it "generates manifest with spiff" do
82
+ subject.should_receive(:spiff_merge)
83
+ .with([template_path, meta_file_path], target_file)
84
+ subject.merge_templates
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,17 @@
1
+ describe Bosh::Manifests::ReleaseManager do
2
+ let(:releases) { [ release_data ] }
3
+ let(:release_data) { { "name" => "foo" } }
4
+ let(:work_dir) { asset_dir("manifests-repo") }
5
+ let(:releases_dir) { File.join(work_dir, ".releases") }
6
+ let(:release) { instance_double("Bosh::Manifests::Release") }
7
+ subject { Bosh::Manifests::ReleaseManager.new(releases, work_dir) }
8
+
9
+ describe "#update_release_repos" do
10
+ it "invokes checkout_current_version" do
11
+ Bosh::Manifests::Release.should_receive(:new)
12
+ .with(release_data, releases_dir).and_return(release)
13
+ release.should_receive(:checkout_current_version)
14
+ subject.update_release_repos
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,74 @@
1
+ describe Bosh::Manifests::Release do
2
+ let(:name) { "foo"}
3
+ let(:version) { 3 }
4
+ let(:repo) { extracted_asset_dir("foo", "foo-boshrelease-repo.zip") }
5
+ let(:release_data) { { "name" => name, "version" => version, "git" => repo } }
6
+ let(:releases_dir) { File.join(asset_dir("manifests-repo"), ".releases") }
7
+ let(:release) { Bosh::Manifests::Release.new release_data, releases_dir }
8
+ subject { Dir[File.join(releases_dir, name, "releases", "foo*.yml")].to_s }
9
+
10
+ describe "#checkout_current_version" do
11
+ context "latest version" do
12
+ let(:version) { "latest" }
13
+
14
+ it "checks out repo" do
15
+ release.checkout_current_version
16
+ expect(subject).to match /foo-11.yml/
17
+ end
18
+ end
19
+
20
+ context "specific version" do
21
+ let(:version) { "2" }
22
+
23
+ it "checks out repo" do
24
+ release.checkout_current_version
25
+ expect(subject).to match /foo-2.yml/
26
+ end
27
+ end
28
+
29
+ context "non existing version " do
30
+ let(:version) { "12" }
31
+
32
+ it "raises an error" do
33
+ expect { release.checkout_current_version }.
34
+ to raise_error /Could not find version/
35
+ end
36
+ end
37
+
38
+ context "already cloned repo" do
39
+ before do
40
+ data = { "name" => name, "version" => 1, "git" => repo }
41
+ cloned_release = Bosh::Manifests::Release.new(data, releases_dir)
42
+ cloned_release.checkout_current_version
43
+ end
44
+
45
+ it "version 3" do
46
+ release.checkout_current_version
47
+ expect(subject).to match /foo-3.yml/
48
+ end
49
+ end
50
+
51
+ context "multiple releases" do
52
+ let(:version) { "3" }
53
+
54
+ before do
55
+ data = { "name" => "bar", "version" => 2, "git" => repo }
56
+ other_release = Bosh::Manifests::Release.new(data, releases_dir)
57
+ other_release.checkout_current_version
58
+ end
59
+
60
+ it "version 3" do
61
+ release.checkout_current_version
62
+ expect(subject).to match /foo-3.yml/
63
+ end
64
+ end
65
+ end
66
+
67
+ after do
68
+ FileUtils.rm_r releases_dir
69
+ end
70
+
71
+ after(:all) do
72
+ FileUtils.rm_r repo
73
+ end
74
+ end