bosh-workspace 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +5 -13
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +8 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +2 -2
  6. data/README.md +78 -39
  7. data/Rakefile +4 -0
  8. data/bosh-workspace.gemspec +4 -1
  9. data/lib/bosh/cli/commands/prepare.rb +74 -0
  10. data/lib/bosh/cli/commands/{01_make_manifest.rb → project_deployment.rb} +4 -26
  11. data/lib/bosh/workspace.rb +7 -3
  12. data/lib/bosh/workspace/helpers/dns_helper.rb +72 -0
  13. data/lib/bosh/workspace/helpers/project_deployment_helper.rb +8 -3
  14. data/lib/bosh/workspace/helpers/release_helper.rb +33 -0
  15. data/lib/bosh/workspace/helpers/spiff_helper.rb +1 -1
  16. data/lib/bosh/workspace/helpers/stemcell_helper.rb +45 -0
  17. data/lib/bosh/workspace/manifest_builder.rb +10 -25
  18. data/lib/bosh/workspace/project_deployment.rb +77 -0
  19. data/lib/bosh/workspace/release.rb +41 -33
  20. data/lib/bosh/workspace/stemcell.rb +23 -0
  21. data/lib/bosh/workspace/stub_file.rb +44 -0
  22. data/lib/bosh/workspace/version.rb +1 -1
  23. data/spec/assets/dns/job-properties.yml +22 -0
  24. data/spec/assets/dns/jobs.yml +18 -0
  25. data/spec/assets/dns/networks-manual.yml +19 -0
  26. data/spec/assets/dns/networks-no-manual.yml +18 -0
  27. data/spec/assets/dns/properties.yml +29 -0
  28. data/spec/assets/foo-boshrelease-repo.zip +0 -0
  29. data/spec/commands/prepare_spec.rb +99 -0
  30. data/spec/commands/{command_make_manifest_spec.rb → project_deployment_spec.rb} +4 -23
  31. data/spec/helpers/dns_helper_spec.rb +59 -0
  32. data/spec/helpers/project_deployment_helper_spec.rb +24 -23
  33. data/spec/helpers/release_helper_spec.rb +76 -0
  34. data/spec/helpers/spiff_helper_spec.rb +2 -2
  35. data/spec/helpers/stemcell_helper_spec.rb +89 -0
  36. data/spec/manifest_builder_spec.rb +24 -45
  37. data/spec/project_deployment_spec.rb +157 -0
  38. data/spec/release_spec.rb +39 -18
  39. data/spec/spec_helper.rb +9 -3
  40. data/spec/stemcell_spec.rb +28 -0
  41. data/spec/stub_file_spec.rb +74 -0
  42. metadata +90 -22
  43. data/lib/bosh/workspace/deployment_manifest.rb +0 -67
  44. data/lib/bosh/workspace/release_manager.rb +0 -14
  45. data/spec/deployment_manifest_spec.rb +0 -93
  46. data/spec/release_manager_spec.rb +0 -17
@@ -0,0 +1,33 @@
1
+ module Bosh::Workspace
2
+ module ReleaseHelper
3
+ include ProjectDeploymentHelper
4
+
5
+ def release_uploaded?(name, version)
6
+ remote_release = director.get_release(name) rescue nil
7
+ remote_release && remote_release["versions"].include?(version.to_s)
8
+ end
9
+
10
+ def release_upload(manifest_file)
11
+ release_cmd.upload(manifest_file)
12
+ end
13
+
14
+ def releases_dir
15
+ @releases_dir ||= begin
16
+ FileUtils.mkdir_p(File.join(work_dir, ".releases")).first
17
+ end
18
+ end
19
+
20
+ def project_deployment_releases
21
+ @releases ||= begin
22
+ project_deployment.releases.map { |r| Release.new(r, releases_dir) }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def release_cmd
29
+ @release_cmd ||= Bosh::Cli::Command::Release.new
30
+ end
31
+ end
32
+ end
33
+
@@ -1,4 +1,4 @@
1
- module Bosh::Manifests
1
+ module Bosh::Workspace
2
2
  module SpiffHelper
3
3
  include Bosh::Exec
4
4
 
@@ -0,0 +1,45 @@
1
+ module Bosh::Workspace
2
+ module StemcellHelper
3
+ include ProjectDeploymentHelper
4
+
5
+ def stemcell_download(stemcell_name)
6
+ Dir.chdir(stemcells_dir) do
7
+ say "Downloading stemcell '#{stemcell_name}'"
8
+ nl
9
+ stemcell_cmd.download_public(stemcell_name)
10
+ end
11
+ end
12
+
13
+ def stemcell_upload(stemcell_file)
14
+ say "Uploading stemcell '#{File.basename(stemcell_file)}'"
15
+ nl
16
+ stemcell_cmd.upload(stemcell_file)
17
+ end
18
+
19
+ def stemcell_uploaded?(name, version)
20
+ existing = director.list_stemcells.select do |sc|
21
+ sc['name'] == name && sc['version'] == version.to_s
22
+ end
23
+
24
+ !existing.empty?
25
+ end
26
+
27
+ def stemcells_dir
28
+ @stemcells_dir ||= begin
29
+ FileUtils.mkdir_p(File.join(work_dir, ".stemcells")).first
30
+ end
31
+ end
32
+
33
+ def project_deployment_stemcells
34
+ @stemcells ||= begin
35
+ project_deployment.stemcells.map { |s| Stemcell.new(s, stemcells_dir) }
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def stemcell_cmd
42
+ @stemcell_cmd ||= Bosh::Cli::Command::Stemcell.new
43
+ end
44
+ end
45
+ end
@@ -1,19 +1,19 @@
1
- module Bosh::Manifests
1
+ module Bosh::Workspace
2
2
  class ManifestBuilder
3
- include Bosh::Manifests::SpiffHelper
3
+ include Bosh::Workspace::SpiffHelper
4
4
 
5
- def self.build(manifest, work_dir)
6
- manifest_builder = ManifestBuilder.new(manifest, work_dir)
5
+ def self.build(project_deployment, work_dir)
6
+ manifest_builder = ManifestBuilder.new(project_deployment, work_dir)
7
7
  manifest_builder.merge_templates
8
8
  end
9
9
 
10
- def initialize(manifest, work_dir)
11
- @manifest = manifest
10
+ def initialize(project_deployment, work_dir)
11
+ @project_deployment = project_deployment
12
12
  @work_dir = work_dir
13
13
  end
14
14
 
15
15
  def merge_templates
16
- spiff_merge spiff_template_paths, @manifest.merged_file
16
+ spiff_merge spiff_template_paths, @project_deployment.merged_file
17
17
  end
18
18
 
19
19
  private
@@ -24,32 +24,17 @@ module Bosh::Manifests
24
24
  end
25
25
 
26
26
  def template_paths
27
- @manifest.templates.map { |t| template_path(t) }
27
+ @project_deployment.templates.map { |t| template_path(t) }
28
28
  end
29
29
 
30
30
  def stub_file_path
31
31
  path = hidden_file_path(:stubs)
32
- File.open(path, 'w') { |file| file.write(stub_file_content) }
32
+ StubFile.create(path, @project_deployment)
33
33
  path
34
34
  end
35
35
 
36
- def stub_file_content
37
- {
38
- "director_uuid" => @manifest.director_uuid,
39
- "releases" => filterd_releases,
40
- "meta" => @manifest.meta
41
- }.to_yaml
42
- end
43
-
44
- def filterd_releases
45
- allowed_keys = %w[name version]
46
- @manifest.releases.map do |release|
47
- release.select { |key| allowed_keys.include?(key) }
48
- end
49
- end
50
-
51
36
  def hidden_file_path(type)
52
- File.join(hidden_dir_path(type), "#{@manifest.name}.yml")
37
+ File.join(hidden_dir_path(type), "#{@project_deployment.name}.yml")
53
38
  end
54
39
 
55
40
  def hidden_dir_path(name)
@@ -0,0 +1,77 @@
1
+ require "membrane"
2
+ module Bosh::Workspace
3
+ class ProjectDeployment
4
+ include Bosh::Cli::Validation
5
+ attr_writer :director_uuid
6
+ attr_reader :file
7
+
8
+ RELEASE_SCHEMA = Membrane::SchemaParser.parse do
9
+ {
10
+ "name" => String,
11
+ "version" => enum(Integer, "latest"),
12
+ "git" => String,
13
+ }
14
+ end
15
+
16
+ STEMCELL_SCHEMA = Membrane::SchemaParser.parse do
17
+ {
18
+ "name" => String,
19
+ "version" => enum(Integer, "latest"),
20
+ }
21
+ end
22
+
23
+ UUID_REGEX = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/
24
+
25
+ PROJECT_DEPLOYMENT_SCHEMA = Membrane::SchemaParser.parse do
26
+ {
27
+ "name" => String,
28
+ "director_uuid" => enum(UUID_REGEX, "current"),
29
+ optional("domain_name") => String,
30
+ "releases" => [RELEASE_SCHEMA],
31
+ "stemcells" => [STEMCELL_SCHEMA],
32
+ "templates" => [String],
33
+ "meta" => Hash
34
+ }
35
+ end
36
+
37
+ def initialize(file)
38
+ @file = file
39
+ err("Deployment file does not exist: #{file}") unless File.exist? @file
40
+ @manifest = Psych.load(File.read(@file))
41
+ end
42
+
43
+ def perform_validation(options = {})
44
+ PROJECT_DEPLOYMENT_SCHEMA.validate @manifest
45
+ rescue Membrane::SchemaValidationError => e
46
+ errors << e.message
47
+ end
48
+
49
+ def director_uuid
50
+ @director_uuid || @manifest["director_uuid"]
51
+ end
52
+
53
+ def merged_file
54
+ @merged_file ||= begin
55
+ path = File.join(file_dirname, "../.deployments", file_basename)
56
+ FileUtils.mkpath File.dirname(path)
57
+ File.expand_path path
58
+ end
59
+ end
60
+
61
+ %w[name templates releases stemcells meta domain_name].each do |var|
62
+ define_method var do
63
+ @manifest[var]
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def file_basename
70
+ File.basename(@file)
71
+ end
72
+
73
+ def file_dirname
74
+ File.dirname(@file)
75
+ end
76
+ end
77
+ end
@@ -1,58 +1,66 @@
1
1
  require "git"
2
- module Bosh::Manifests
2
+ module Bosh::Workspace
3
3
  class Release
4
+ attr_reader :name, :git_uri, :repo_dir
5
+
4
6
  def initialize(release, releases_dir)
5
7
  @name = release["name"]
6
- @version = release["version"]
8
+ @version_ref = release["version"]
7
9
  @git_uri = release["git"]
8
- @work_dir = File.join(releases_dir)
10
+ @repo_dir = File.join(releases_dir, @name)
11
+ init_repo
9
12
  end
10
13
 
11
- def checkout_current_version
12
- repo.pull
13
- repo.checkout(current_version_ref)
14
+ def update_repo
15
+ @repo.pull
16
+ @repo.checkout(ref)
14
17
  end
15
18
 
16
- private
19
+ def manifest_file
20
+ File.join(repo_dir, manifest)
21
+ end
17
22
 
18
- def repo
19
- if File.directory?(repo_dir)
20
- @repo ||= Git.open(repo_dir)
21
- else
22
- FileUtils.mkdir_p(@work_dir)
23
- @repo = Git.clone(@git_uri, @name, path: @work_dir)
24
- end
23
+ def manifest
24
+ final_releases[version]
25
25
  end
26
26
 
27
- def current_version_ref
28
- repo.log().object("releases/#{available_versions[current_version]}")
27
+ def name_version
28
+ "#{name}/#{version}"
29
29
  end
30
30
 
31
- def current_version
32
- if @version == "latest"
33
- available_versions.keys.sort.last
34
- else
35
- version = @version.to_i
36
- unless available_versions[version]
37
- err("Could not find version: #{@version} for release: #{@name}")
38
- end
39
- version
31
+ def version
32
+ return final_releases.keys.sort.last if @version_ref == "latest"
33
+ unless final_releases[@version_ref.to_i]
34
+ err("Could not find version: #{@version_ref} for release: #{@name}")
40
35
  end
36
+ @version_ref.to_i
41
37
  end
42
38
 
39
+ private
40
+
43
41
  # transforms releases/foo-1.yml, releases/bar-2.yml to:
44
42
  # { "1" => foo-1.yml, "2" => bar-2.yml }
45
- def available_versions
46
- @available_versions ||= begin
47
- Hash[Dir[File.join(repo_dir, "releases", "*.yml")].
48
- reject { |f| f[/index.yml/] }.
49
- map { |dir| File.basename(dir) }.
50
- map { |version| [ version[/(\d+)/].to_i, version ] }]
43
+ def final_releases
44
+ @final_releases ||= begin
45
+ Hash[Dir[File.join(repo_dir, "releases", "*.yml")]
46
+ .reject { |f| f[/index.yml/] }
47
+ .map { |dir| File.join("releases", File.basename(dir)) }
48
+ .map { |version| [version[/(\d+)/].to_i, version] }]
51
49
  end
52
50
  end
53
51
 
54
- def repo_dir
55
- File.join(@work_dir, @name)
52
+ def ref
53
+ @repo.log.object(manifest).first
54
+ end
55
+
56
+ def init_repo
57
+ if File.directory?(repo_dir)
58
+ @repo ||= Git.open(repo_dir)
59
+ else
60
+ releases_dir = File.dirname(repo_dir)
61
+ FileUtils.mkdir_p(releases_dir)
62
+ @repo = Git.clone(@git_uri, @name, path: releases_dir)
63
+ end
56
64
  end
57
65
  end
58
66
  end
@@ -0,0 +1,23 @@
1
+ module Bosh::Workspace
2
+ class Stemcell
3
+ attr_reader :name, :version, :file
4
+
5
+ def initialize(stemcell, stemcells_dir)
6
+ @name = stemcell["name"]
7
+ @version = stemcell["version"]
8
+ @file = File.join(stemcells_dir, file_name)
9
+ end
10
+
11
+ def name_version
12
+ "#{name}/#{version}"
13
+ end
14
+
15
+ def file_name
16
+ name.gsub(/^bosh-/, "bosh-stemcell-#{version}-") + ".tgz"
17
+ end
18
+
19
+ def downloaded?
20
+ File.exists? file
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ module Bosh::Workspace
2
+ class StubFile
3
+ attr_reader :name, :director_uuid
4
+
5
+ def self.create(path, project_deployment)
6
+ self.new(project_deployment).tap { |stub| stub.write(path) }
7
+ end
8
+
9
+ def initialize(project_deployment)
10
+ @name = project_deployment.name
11
+ @director_uuid = project_deployment.director_uuid
12
+ @releases = project_deployment.releases
13
+ @stemcells = project_deployment.stemcells
14
+ @meta = project_deployment.meta
15
+ end
16
+
17
+ def write(file)
18
+ IO.write file, content.to_yaml
19
+ end
20
+
21
+ def content
22
+ {
23
+ "name" => name,
24
+ "director_uuid" => director_uuid,
25
+ "releases" => releases,
26
+ "meta" => meta
27
+ }
28
+ end
29
+
30
+ def releases
31
+ @releases.map { |r| r.select { |key| %w[name version].include?(key) } }
32
+ end
33
+
34
+ def meta
35
+ out = case @stemcells.size
36
+ when 1
37
+ { "stemcell" => @stemcells.first }
38
+ else
39
+ { "stemcells" => @stemcells }
40
+ end
41
+ out.merge(@meta)
42
+ end
43
+ end
44
+ end
@@ -1,5 +1,5 @@
1
1
  module Bosh
2
2
  module Manifests
3
- VERSION = "0.7.0"
3
+ VERSION = "0.8.0"
4
4
  end
5
5
  end
@@ -0,0 +1,22 @@
1
+ name: foo
2
+
3
+ networks:
4
+ - name: default
5
+ type: manual
6
+
7
+ jobs:
8
+ - name: first_job_az1
9
+ networks:
10
+ - name: default
11
+ static_ips:
12
+ - 10.0.0.50
13
+
14
+ - name: second_job_az1
15
+ networks:
16
+ - name: default
17
+ static_ips:
18
+ - 10.0.0.51
19
+ properties:
20
+ job1:
21
+ foo: bar
22
+ address: 10.0.0.50
@@ -0,0 +1,18 @@
1
+ networks:
2
+ - name: default
3
+ type: manual
4
+
5
+ jobs:
6
+ - name: job1
7
+ networks:
8
+ - name: default
9
+ static_ips:
10
+ - 10.0.0.50
11
+ - name: job2
12
+ networks:
13
+ - name: default
14
+ static_ips:
15
+ - 10.0.0.51
16
+ - name: job3
17
+ networks:
18
+ - name: default