bosh_cli 0.16

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 (113) hide show
  1. data/README +4 -0
  2. data/Rakefile +55 -0
  3. data/bin/bosh +17 -0
  4. data/lib/cli.rb +76 -0
  5. data/lib/cli/cache.rb +44 -0
  6. data/lib/cli/changeset_helper.rb +142 -0
  7. data/lib/cli/command_definition.rb +52 -0
  8. data/lib/cli/commands/base.rb +245 -0
  9. data/lib/cli/commands/biff.rb +300 -0
  10. data/lib/cli/commands/blob.rb +125 -0
  11. data/lib/cli/commands/cloudcheck.rb +169 -0
  12. data/lib/cli/commands/deployment.rb +147 -0
  13. data/lib/cli/commands/job.rb +42 -0
  14. data/lib/cli/commands/job_management.rb +117 -0
  15. data/lib/cli/commands/log_management.rb +81 -0
  16. data/lib/cli/commands/maintenance.rb +131 -0
  17. data/lib/cli/commands/misc.rb +240 -0
  18. data/lib/cli/commands/package.rb +112 -0
  19. data/lib/cli/commands/property_management.rb +125 -0
  20. data/lib/cli/commands/release.rb +469 -0
  21. data/lib/cli/commands/ssh.rb +271 -0
  22. data/lib/cli/commands/stemcell.rb +184 -0
  23. data/lib/cli/commands/task.rb +213 -0
  24. data/lib/cli/commands/user.rb +28 -0
  25. data/lib/cli/commands/vms.rb +53 -0
  26. data/lib/cli/config.rb +154 -0
  27. data/lib/cli/core_ext.rb +145 -0
  28. data/lib/cli/dependency_helper.rb +62 -0
  29. data/lib/cli/deployment_helper.rb +263 -0
  30. data/lib/cli/deployment_manifest_compiler.rb +28 -0
  31. data/lib/cli/director.rb +633 -0
  32. data/lib/cli/director_task.rb +64 -0
  33. data/lib/cli/errors.rb +48 -0
  34. data/lib/cli/event_log_renderer.rb +351 -0
  35. data/lib/cli/job_builder.rb +226 -0
  36. data/lib/cli/package_builder.rb +254 -0
  37. data/lib/cli/packaging_helper.rb +248 -0
  38. data/lib/cli/release.rb +176 -0
  39. data/lib/cli/release_builder.rb +215 -0
  40. data/lib/cli/release_compiler.rb +178 -0
  41. data/lib/cli/release_tarball.rb +272 -0
  42. data/lib/cli/runner.rb +771 -0
  43. data/lib/cli/stemcell.rb +83 -0
  44. data/lib/cli/task_log_renderer.rb +40 -0
  45. data/lib/cli/templates/help_message.erb +75 -0
  46. data/lib/cli/validation.rb +42 -0
  47. data/lib/cli/version.rb +7 -0
  48. data/lib/cli/version_calc.rb +48 -0
  49. data/lib/cli/versions_index.rb +126 -0
  50. data/lib/cli/yaml_helper.rb +62 -0
  51. data/spec/assets/biff/bad_gateway_config.yml +28 -0
  52. data/spec/assets/biff/good_simple_config.yml +63 -0
  53. data/spec/assets/biff/good_simple_golden_config.yml +63 -0
  54. data/spec/assets/biff/good_simple_template.erb +69 -0
  55. data/spec/assets/biff/multiple_subnets_config.yml +40 -0
  56. data/spec/assets/biff/network_only_template.erb +34 -0
  57. data/spec/assets/biff/no_cc_config.yml +27 -0
  58. data/spec/assets/biff/no_range_config.yml +27 -0
  59. data/spec/assets/biff/no_subnet_config.yml +16 -0
  60. data/spec/assets/biff/ok_network_config.yml +30 -0
  61. data/spec/assets/biff/properties_template.erb +6 -0
  62. data/spec/assets/deployment.MF +0 -0
  63. data/spec/assets/plugins/bosh/cli/commands/echo.rb +43 -0
  64. data/spec/assets/plugins/bosh/cli/commands/ruby.rb +24 -0
  65. data/spec/assets/release/jobs/cacher.tgz +0 -0
  66. data/spec/assets/release/jobs/cacher/config/file1.conf +0 -0
  67. data/spec/assets/release/jobs/cacher/config/file2.conf +0 -0
  68. data/spec/assets/release/jobs/cacher/job.MF +6 -0
  69. data/spec/assets/release/jobs/cacher/monit +1 -0
  70. data/spec/assets/release/jobs/cleaner.tgz +0 -0
  71. data/spec/assets/release/jobs/cleaner/job.MF +4 -0
  72. data/spec/assets/release/jobs/cleaner/monit +1 -0
  73. data/spec/assets/release/jobs/sweeper.tgz +0 -0
  74. data/spec/assets/release/jobs/sweeper/config/test.conf +1 -0
  75. data/spec/assets/release/jobs/sweeper/job.MF +5 -0
  76. data/spec/assets/release/jobs/sweeper/monit +1 -0
  77. data/spec/assets/release/packages/mutator.tar.gz +0 -0
  78. data/spec/assets/release/packages/stuff.tgz +0 -0
  79. data/spec/assets/release/release.MF +17 -0
  80. data/spec/assets/release_invalid_checksum.tgz +0 -0
  81. data/spec/assets/release_invalid_jobs.tgz +0 -0
  82. data/spec/assets/release_no_name.tgz +0 -0
  83. data/spec/assets/release_no_version.tgz +0 -0
  84. data/spec/assets/stemcell/image +1 -0
  85. data/spec/assets/stemcell/stemcell.MF +6 -0
  86. data/spec/assets/stemcell_invalid_mf.tgz +0 -0
  87. data/spec/assets/stemcell_no_image.tgz +0 -0
  88. data/spec/assets/valid_release.tgz +0 -0
  89. data/spec/assets/valid_stemcell.tgz +0 -0
  90. data/spec/spec_helper.rb +25 -0
  91. data/spec/unit/base_command_spec.rb +66 -0
  92. data/spec/unit/biff_spec.rb +135 -0
  93. data/spec/unit/cache_spec.rb +36 -0
  94. data/spec/unit/cli_commands_spec.rb +481 -0
  95. data/spec/unit/config_spec.rb +139 -0
  96. data/spec/unit/core_ext_spec.rb +77 -0
  97. data/spec/unit/dependency_helper_spec.rb +52 -0
  98. data/spec/unit/deployment_manifest_compiler_spec.rb +63 -0
  99. data/spec/unit/director_spec.rb +511 -0
  100. data/spec/unit/director_task_spec.rb +48 -0
  101. data/spec/unit/event_log_renderer_spec.rb +171 -0
  102. data/spec/unit/hash_changeset_spec.rb +73 -0
  103. data/spec/unit/job_builder_spec.rb +454 -0
  104. data/spec/unit/package_builder_spec.rb +567 -0
  105. data/spec/unit/release_builder_spec.rb +65 -0
  106. data/spec/unit/release_spec.rb +66 -0
  107. data/spec/unit/release_tarball_spec.rb +33 -0
  108. data/spec/unit/runner_spec.rb +140 -0
  109. data/spec/unit/ssh_spec.rb +78 -0
  110. data/spec/unit/stemcell_spec.rb +17 -0
  111. data/spec/unit/version_calc_spec.rb +27 -0
  112. data/spec/unit/versions_index_spec.rb +132 -0
  113. metadata +338 -0
@@ -0,0 +1,83 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ class Stemcell
5
+ include Validation
6
+
7
+ attr_reader :stemcell_file, :manifest
8
+
9
+ def initialize(tarball_path, cache)
10
+ @stemcell_file = File.expand_path(tarball_path, Dir.pwd)
11
+ @cache = cache
12
+ end
13
+
14
+ def perform_validation(options = {})
15
+ tmp_dir = Dir.mktmpdir
16
+
17
+ step("File exists and readable",
18
+ "Cannot find stemcell file #{@stemcell_file}", :fatal) do
19
+ File.exists?(@stemcell_file) && File.readable?(@stemcell_file)
20
+ end
21
+
22
+ cache_key = "%s_%s" % [@stemcell_file, File.mtime(@stemcell_file)]
23
+
24
+ manifest_yaml = @cache.read(cache_key)
25
+
26
+ if manifest_yaml
27
+ say("Using cached manifest...")
28
+ else
29
+ say("Manifest not found in cache, verifying tarball...")
30
+
31
+ step("Extract tarball",
32
+ "Cannot extract tarball #{@stemcell_file}", :fatal) do
33
+ `tar -C #{tmp_dir} -xzf #{@stemcell_file} 2>&1`
34
+ $?.exitstatus == 0
35
+ end
36
+
37
+ manifest_file = File.expand_path("stemcell.MF", tmp_dir)
38
+
39
+ step("Manifest exists", "Cannot find stemcell manifest", :fatal) do
40
+ File.exists?(manifest_file)
41
+ end
42
+
43
+ step("Stemcell image file",
44
+ "Stemcell image file is missing", :fatal) do
45
+ File.exists?(File.expand_path("image", tmp_dir))
46
+ end
47
+
48
+ say("Writing manifest to cache...")
49
+ manifest_yaml = File.read(manifest_file)
50
+ @cache.write(cache_key, manifest_yaml)
51
+ end
52
+
53
+ manifest = YAML.load(manifest_yaml)
54
+
55
+ step("Stemcell properties",
56
+ "Manifest should contain valid name, " +
57
+ "version and cloud properties") do
58
+ manifest.is_a?(Hash) && manifest.has_key?("name") &&
59
+ manifest.has_key?("version") &&
60
+ manifest.has_key?("cloud_properties") &&
61
+ manifest["name"].is_a?(String) &&
62
+ (manifest["version"].is_a?(String) ||
63
+ manifest["version"].kind_of?(Numeric)) &&
64
+ (manifest["cloud_properties"].nil? ||
65
+ manifest["cloud_properties"].is_a?(Hash))
66
+ end
67
+
68
+ print_info(manifest)
69
+ @manifest = manifest
70
+ ensure
71
+ FileUtils.rm_rf(tmp_dir)
72
+ end
73
+
74
+ def print_info(manifest)
75
+ say("\nStemcell info")
76
+ say("-------------")
77
+
78
+ say("Name: %s" % [manifest["name"] || "missing".red])
79
+ say("Version: %s" % [manifest["version"] || "missing".red])
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,40 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ class TaskLogRenderer
5
+
6
+ def self.create_for_log_type(log_type)
7
+ if log_type == "event"
8
+ EventLogRenderer.new
9
+ else
10
+ TaskLogRenderer.new
11
+ end
12
+ end
13
+
14
+ attr_accessor :time_adjustment
15
+ attr_accessor :duration
16
+
17
+ def initialize
18
+ @out = Bosh::Cli::Config.output || $stdout
19
+ @out.sync = true
20
+ @lock = Mutex.new
21
+ @output = ""
22
+ @time_adjustment = 0
23
+ end
24
+
25
+ def add_output(output)
26
+ @output = output
27
+ end
28
+
29
+ def refresh
30
+ @out.print(@output)
31
+ @output = ""
32
+ end
33
+
34
+ def finish(state)
35
+ refresh
36
+ @done = true
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,75 @@
1
+ <%= basic_usage %>
2
+ Currently available bosh commands are:
3
+
4
+ Deployment
5
+ <%= command_usage(:deployment) %>
6
+ <%= command_usage(:delete_deployment) %>
7
+ <%= command_usage(:list_deployments) %>
8
+ <%= command_usage(:deploy) %>
9
+ <%= command_usage(:diff) %>
10
+
11
+ Release management
12
+ <%= command_usage(:create_release) %>
13
+ <%= command_usage(:delete_release) %>
14
+ <%= command_usage(:verify_release) %>
15
+ <%= command_usage(:upload_release) %>
16
+ <%= command_usage(:list_releases) %>
17
+ <%= command_usage(:reset_release) %>
18
+
19
+ <%= command_usage(:init_release) %>
20
+ <%= command_usage(:generate_package) %>
21
+ <%= command_usage(:generate_job) %>
22
+
23
+ Stemcells
24
+ <%= command_usage(:upload_stemcell) %>
25
+ <%= command_usage(:verify_stemcell) %>
26
+ <%= command_usage(:list_stemcells) %>
27
+ <%= command_usage(:delete_stemcell) %>
28
+ <%= command_usage(:list_public_stemcells) %>
29
+ <%= command_usage(:download_public_stemcell) %>
30
+
31
+ User management
32
+ <%= command_usage(:create_user) %>
33
+
34
+ Job management
35
+ <%= command_usage(:start_job) %>
36
+ <%= command_usage(:stop_job) %>
37
+ <%= command_usage(:restart_job) %>
38
+ <%= command_usage(:recreate_job) %>
39
+
40
+ Log management
41
+ <%= command_usage(:fetch_logs) %>
42
+
43
+ Task management
44
+ <%= command_usage(:list_running_tasks) %>
45
+ <%= command_usage(:list_recent_tasks) %>
46
+ <%= command_usage(:track_task) %>
47
+ <%= command_usage(:cancel_task) %>
48
+
49
+ Property management
50
+ <%= command_usage(:set_property) %>
51
+ <%= command_usage(:get_property) %>
52
+ <%= command_usage(:unset_property) %>
53
+ <%= command_usage(:list_properties) %>
54
+
55
+ Maintenance
56
+ <%= command_usage(:cleanup) %>
57
+ <%= command_usage(:cloudcheck) %>
58
+
59
+ Misc
60
+ <%= command_usage(:status) %>
61
+ <%= command_usage(:list_vms) %>
62
+ <%= command_usage(:target) %>
63
+ <%= command_usage(:login) %>
64
+ <%= command_usage(:logout) %>
65
+ <%= command_usage(:purge) %>
66
+
67
+ Remote access
68
+ <%= command_usage(:ssh) %>
69
+ <%= command_usage(:scp) %>
70
+ <%= command_usage(:ssh_cleanup) %>
71
+
72
+ Blob
73
+ <%= command_usage(:upload_blob) %>
74
+ <%= command_usage(:sync_blobs) %>
75
+ <%= command_usage(:blobs) %>
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ class ValidationHalted < StandardError; end
5
+
6
+ module Validation
7
+
8
+ def errors
9
+ @errors ||= []
10
+ end
11
+
12
+ def valid?(options = {})
13
+ validate(options) unless @validated
14
+ errors.empty?
15
+ end
16
+
17
+ def validate(options = {})
18
+ perform_validation(options)
19
+ rescue ValidationHalted
20
+ ensure
21
+ @validated = true
22
+ end
23
+
24
+ def reset_validation
25
+ @validated = nil
26
+ @errors = []
27
+ end
28
+
29
+ private
30
+
31
+ def step(name, error_message, kind = :non_fatal, &block)
32
+ passed = yield
33
+
34
+ say("%-60s %s" % [name, passed ? "OK".green : "FAILED".red])
35
+
36
+ unless passed
37
+ errors << error_message
38
+ raise ValidationHalted if kind == :fatal
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh
4
+ module Cli
5
+ VERSION = "0.16"
6
+ end
7
+ end
@@ -0,0 +1,48 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ module VersionCalc
5
+
6
+ # Returns 0 if two versions are the same,
7
+ # 1 if v1 > v2
8
+ # -1 if v1 < v2
9
+ def version_cmp(v1 = "0", v2 = "0")
10
+ vp1 = components(v1)
11
+ vp2 = components(v2)
12
+
13
+ [vp1.size, vp2.size].max.times do |i|
14
+ result = vp1[i].to_i <=> vp2[i].to_i
15
+ return result unless result == 0
16
+ end
17
+
18
+ 0
19
+ end
20
+
21
+ def version_greater(v1, v2)
22
+ version_cmp(v1, v2) > 0
23
+ end
24
+
25
+ def version_less(v1, v2)
26
+ version_cmp(v1, v2) < 0
27
+ end
28
+
29
+ def version_same(v1, v2)
30
+ version_cmp(v1, v2) == 0
31
+ end
32
+
33
+ def major_version(v)
34
+ components(v)[0].to_i
35
+ end
36
+
37
+ def minor_version(v)
38
+ components(v)[1].to_i
39
+ end
40
+
41
+ private
42
+
43
+ def components(v)
44
+ v.to_s.split(".")
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,126 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ class VersionsIndex
5
+ include VersionCalc
6
+
7
+ def initialize(storage_dir, name_prefix = nil)
8
+ @storage_dir = File.expand_path(storage_dir)
9
+ @index_file = File.join(@storage_dir, "index.yml")
10
+ @name_prefix = name_prefix
11
+
12
+ if File.file?(@index_file)
13
+ init_index(load_yaml_file(@index_file, nil))
14
+ else
15
+ init_index({})
16
+ end
17
+ end
18
+
19
+ def find_by_checksum(checksum)
20
+ @data["builds"].each_pair do |fingerprint, build_data|
21
+ return build_data if build_data["sha1"] == checksum
22
+ end
23
+ nil
24
+ end
25
+
26
+ def [](fingerprint)
27
+ @data["builds"][fingerprint]
28
+ end
29
+
30
+ def latest_version(major = nil)
31
+ builds = @data["builds"].values
32
+
33
+ if major
34
+ builds = builds.select do |build|
35
+ major_version(build["version"]) == major
36
+ end
37
+ end
38
+
39
+ return nil if builds.empty?
40
+
41
+ sorted = builds.sort { |build1, build2|
42
+ cmp = version_cmp(build2["version"], build1["version"])
43
+ if cmp == 0
44
+ raise "There is a duplicate version `#{build1["version"]}' " +
45
+ "in index `#{@index_file}'"
46
+ end
47
+ cmp
48
+ }
49
+
50
+ sorted[0]["version"]
51
+ end
52
+
53
+ def version_exists?(version)
54
+ File.exists?(filename(version))
55
+ end
56
+
57
+ def add_version(fingerprint, item, payload = nil)
58
+ version = item["version"]
59
+
60
+ if version.blank?
61
+ raise InvalidIndex,
62
+ "Cannot save index entry without knowing its version"
63
+ end
64
+
65
+ create_directories
66
+
67
+ if payload
68
+ File.open(filename(version), "w") do |f|
69
+ f.write(payload)
70
+ end
71
+ end
72
+
73
+ @data["builds"].each_pair do |fp, build|
74
+ if version_cmp(build["version"], version) == 0 && fp != fingerprint
75
+ raise "Trying to add duplicate version `#{version}' " +
76
+ "into index `#{@index_file}'"
77
+ end
78
+ end
79
+
80
+ @data["builds"][fingerprint] = item
81
+ if payload
82
+ @data["builds"][fingerprint]["sha1"] = Digest::SHA1.hexdigest(payload)
83
+ end
84
+
85
+ File.open(@index_file, "w") do |f|
86
+ f.write(YAML.dump(@data))
87
+ end
88
+
89
+ File.expand_path(filename(version))
90
+ end
91
+
92
+ def filename(version)
93
+ name = @name_prefix.blank? ?
94
+ "#{version}.tgz" : "#{@name_prefix}-#{version}.tgz"
95
+ File.join(@storage_dir, name)
96
+ end
97
+
98
+ private
99
+
100
+ def create_directories
101
+ begin
102
+ FileUtils.mkdir_p(@storage_dir)
103
+ rescue SystemCallError => e
104
+ raise InvalidIndex, "Cannot create index storage directory: #{e}"
105
+ end
106
+
107
+ begin
108
+ FileUtils.touch(@index_file)
109
+ rescue SystemCallError => e
110
+ raise InvalidIndex, "Cannot create index file: #{e}"
111
+ end
112
+ end
113
+
114
+ def init_index(data)
115
+ data ||= {}
116
+
117
+ unless data.kind_of?(Hash)
118
+ raise InvalidIndex, "Invalid versions index data type, " +
119
+ "#{data.class} given, Hash expected"
120
+ end
121
+ @data = data
122
+ @data.delete("latest_version") # Indices used to track latest versions
123
+ @data["builds"] ||= {}
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ module Bosh::Cli
4
+ class YamlHelper
5
+ class << self
6
+ private
7
+ def process_object(o)
8
+ case o
9
+ when @syck_class::Map
10
+ process_map(o)
11
+ when @syck_class::Seq
12
+ process_seq(o)
13
+ when @syck_class::Scalar
14
+ else
15
+ err("Unhandled class #{o.class}, fix yaml duplicate check")
16
+ end
17
+ end
18
+
19
+ def process_seq(s)
20
+ s.value.each do |v|
21
+ process_object(v)
22
+ end
23
+ end
24
+
25
+ def process_map(m)
26
+ return if m.class != @syck_class::Map
27
+ s = Set.new
28
+ m.value.each_key do |k|
29
+ raise "Found dup key #{k.value}" if s.include?(k.value)
30
+ s.add(k.value)
31
+ end
32
+
33
+ m.value.each_value do |v|
34
+ process_object(v)
35
+ end
36
+ end
37
+
38
+ public
39
+ def check_duplicate_keys(path)
40
+ # Some Ruby builds on Ubuntu seem to expose a bug
41
+ # with the opposite order of Syck check, so we first
42
+ # check for Syck and then for YAML::Syck
43
+ if defined?(Syck)
44
+ @syck_class = Syck
45
+ elsif defined?(YAML::Syck)
46
+ @syck_class = YAML::Syck
47
+ else
48
+ raise "Cannot find Syck parser for YAML, " +
49
+ "please check your Ruby installation"
50
+ end
51
+
52
+ File.open(path) do |f|
53
+ begin
54
+ process_map(YAML.parse(f))
55
+ rescue => e
56
+ raise "Bad yaml file #{path}, " + e.message
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end