bosh-workspace 0.7.0 → 0.8.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.
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