bosh-release 1.5.0.pre.1113
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.
- data/README +3 -0
- data/bin/bosh-release +54 -0
- data/lib/bosh/release.rb +22 -0
- data/lib/bosh/release/compiler.rb +266 -0
- data/lib/bosh/release/version.rb +6 -0
- metadata +133 -0
data/README
ADDED
data/bin/bosh-release
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "trollop"
|
4
|
+
require "bosh/release"
|
5
|
+
|
6
|
+
CPIS = %w[aws openstack vcloud vsphere]
|
7
|
+
COMMANDS = %w[apply compile]
|
8
|
+
|
9
|
+
def usage(msg=nil)
|
10
|
+
$stderr.puts "error: #{msg}" if msg
|
11
|
+
$stderr.puts "usage: bosh-release <options> <command> <arguments>"
|
12
|
+
$stderr.puts " options:"
|
13
|
+
$stderr.puts " --cpi <cloud provider interface> (#{CPIS.join(', ')})"
|
14
|
+
$stderr.puts " --job <job to compile> (defaults to 'micro_<cpi>')"
|
15
|
+
$stderr.puts " commands:"
|
16
|
+
$stderr.puts " apply <apply_spec> <mbus_uri>"
|
17
|
+
$stderr.puts " compile <manifest> <release_tgz> <blobstore_path> <mbus_uri>"
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
|
21
|
+
options = Trollop::options do
|
22
|
+
opt :cpi, "Cloud Provider Interface", :type => String, :required => true
|
23
|
+
opt :job, "Job to compile", :type => String
|
24
|
+
stop_on COMMANDS
|
25
|
+
end
|
26
|
+
|
27
|
+
unless CPIS.include?(options[:cpi])
|
28
|
+
Trollop::die :cpi, "unknown CPI '#{options[:cpi]}'"
|
29
|
+
end
|
30
|
+
|
31
|
+
unless options[:job_given]
|
32
|
+
options[:job] = "micro_#{options[:cpi]}"
|
33
|
+
end
|
34
|
+
|
35
|
+
options["command"] = ARGV.shift
|
36
|
+
|
37
|
+
case options["command"]
|
38
|
+
when "apply"
|
39
|
+
usage "apply requires 2 arguments" unless ARGV.size == 2
|
40
|
+
options["apply_spec"] = ARGV.shift
|
41
|
+
options["agent_uri"] = ARGV.shift
|
42
|
+
when "compile"
|
43
|
+
usage "compile requires 4 arguments" unless ARGV.size == 4
|
44
|
+
options["manifest"] = ARGV.shift
|
45
|
+
options["release"] = ARGV.shift
|
46
|
+
options["blobstore_options"] = {"blobstore_path" => ARGV.shift}
|
47
|
+
options["agent_uri"] = ARGV.shift
|
48
|
+
when nil
|
49
|
+
usage "no command given"
|
50
|
+
else
|
51
|
+
usage "unknown command: #{options["command"]}"
|
52
|
+
end
|
53
|
+
|
54
|
+
Bosh::Release::Runner.start(options)
|
data/lib/bosh/release.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bosh; module Release; end; end
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'yaml'
|
5
|
+
require 'blobstore_client'
|
6
|
+
require 'common/common'
|
7
|
+
require 'common/properties'
|
8
|
+
require 'agent_client'
|
9
|
+
require 'bosh/release/compiler'
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
module Bosh
|
13
|
+
module Release
|
14
|
+
class Runner
|
15
|
+
class << self
|
16
|
+
def start(options)
|
17
|
+
Compiler.new(options).start
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
module Bosh
|
2
|
+
module Release
|
3
|
+
class Compiler
|
4
|
+
include Bosh::Common::PropertyHelper
|
5
|
+
|
6
|
+
OPTIONS = {
|
7
|
+
"blobstore_options" => { "blobstore_path" => "/var/vcap/micro_bosh/data/cache" },
|
8
|
+
"blobstore_provider" => "local",
|
9
|
+
"base_dir" => "/var/vcap",
|
10
|
+
"platform_name" => "ubuntu",
|
11
|
+
"agent_uri" => "https://vcap:vcap@localhost:6969"
|
12
|
+
}
|
13
|
+
|
14
|
+
AGENT_START_RETRIES=16
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
@options = OPTIONS.merge(options)
|
18
|
+
@logger = Logger.new(@options["logfile"] || STDOUT)
|
19
|
+
|
20
|
+
FileUtils.mkdir_p(File.join(@options["base_dir"], "packages"))
|
21
|
+
bsc_provider = @options["blobstore_provider"]
|
22
|
+
bsc_options = @options["blobstore_options"]
|
23
|
+
@logger.info("Creating Blobstore client with #{bsc_provider} provider and options #{bsc_options}")
|
24
|
+
@blobstore_client = Bosh::Blobstore::Client.create(bsc_provider, bsc_options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def start
|
28
|
+
# Start the "compile" or "apply"
|
29
|
+
send(@options["command"].to_sym)
|
30
|
+
end
|
31
|
+
|
32
|
+
def apply_spec
|
33
|
+
File.join(@options["base_dir"], "micro/apply_spec.yml")
|
34
|
+
end
|
35
|
+
|
36
|
+
def connect_to_agent
|
37
|
+
num_tries = 0
|
38
|
+
begin
|
39
|
+
@agent = Bosh::Agent::Client.create(@options["agent_uri"], "user" => "vcap", "password" => "vcap")
|
40
|
+
@agent.ping
|
41
|
+
rescue => e
|
42
|
+
num_tries += 1
|
43
|
+
sleep 0.1
|
44
|
+
# Dont retry forever
|
45
|
+
retry if num_tries < AGENT_START_RETRIES
|
46
|
+
@logger.warn("Error connecting to agent #{e.inspect}")
|
47
|
+
raise
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def compile
|
52
|
+
@logger.info("Compiling #{@options["manifest"]} with tarball #{@options["release"]}")
|
53
|
+
connect_to_agent
|
54
|
+
deployment_mf = Psych.load_file(File.expand_path(@options["manifest"]))
|
55
|
+
@spec = prep_spec(deployment_mf)
|
56
|
+
|
57
|
+
@packages = {}
|
58
|
+
@spec["job"] = { "name" => @options[:job] }
|
59
|
+
|
60
|
+
untar(@options["release"]) do |dir|
|
61
|
+
release_mf = Psych.load_file("release.MF")
|
62
|
+
jobs = []
|
63
|
+
|
64
|
+
jobs_to_compile(@options[:job], deployment_mf).each do |spec_job|
|
65
|
+
job = find_by_name(release_mf["jobs"], spec_job)
|
66
|
+
job_path = File.expand_path("jobs/#{job["name"]}.tgz")
|
67
|
+
jobs << apply_spec_job(job, job_path)
|
68
|
+
|
69
|
+
if job["name"] == @options[:job]
|
70
|
+
@spec["job"]["version"] = job["version"].to_s
|
71
|
+
@spec["job"]["template"] = @options[:job]
|
72
|
+
@spec["job"]["sha1"] = job["sha1"]
|
73
|
+
@spec["job"]["blobstore_id"] = @blobstore_client.create(File.new(job_path))
|
74
|
+
end
|
75
|
+
|
76
|
+
untar(job_path) do
|
77
|
+
job = Psych.load_file("job.MF")
|
78
|
+
|
79
|
+
# add default job spec properties to apply spec
|
80
|
+
add_default_properties(@spec["properties"], job["properties"])
|
81
|
+
|
82
|
+
# Compile job packages
|
83
|
+
compile_packages(dir, release_mf, job["packages"])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
@spec["job"]["templates"] = jobs
|
88
|
+
end
|
89
|
+
cleanup
|
90
|
+
|
91
|
+
# save apply spec
|
92
|
+
FileUtils.mkdir_p(File.dirname(apply_spec))
|
93
|
+
File.open(apply_spec, 'w') { |f| f.write(Psych.dump(@spec)) }
|
94
|
+
|
95
|
+
@spec["packages"]
|
96
|
+
rescue => e
|
97
|
+
@logger.error("Error #{e.message}, #{e.backtrace.join("\n")}")
|
98
|
+
end
|
99
|
+
|
100
|
+
def find_by_name(enum, name)
|
101
|
+
result = enum.find { |j| j["name"] == name }
|
102
|
+
if result
|
103
|
+
result
|
104
|
+
else
|
105
|
+
raise "Could not find name #{name} in #{enum}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check manifest for job collocation
|
110
|
+
def jobs_to_compile(name, manifest)
|
111
|
+
compile_job = manifest["jobs"].find { |j| j["name"] == name } if manifest["jobs"]
|
112
|
+
if compile_job
|
113
|
+
compile_job["template"]
|
114
|
+
else
|
115
|
+
[name]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def apply_spec_job(job, job_path)
|
120
|
+
{
|
121
|
+
"name" => job["name"],
|
122
|
+
"version" => job["version"].to_s,
|
123
|
+
"sha1" => job["sha1"],
|
124
|
+
"blobstore_id" => @blobstore_client.create(File.new(job_path))
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
def cleanup
|
129
|
+
FileUtils.rm_rf("#{@options["base_dir"]}/data/compile")
|
130
|
+
FileUtils.rm_rf("#{@options["base_dir"]}/data/packages")
|
131
|
+
FileUtils.rm_rf("#{@options["base_dir"]}/data/tmp")
|
132
|
+
FileUtils.rm_rf("#{@options["base_dir"]}/packages")
|
133
|
+
end
|
134
|
+
|
135
|
+
def prep_spec(deployment)
|
136
|
+
spec = {}
|
137
|
+
spec["deployment"] = "micro"
|
138
|
+
spec["release"] = deployment["release"]
|
139
|
+
spec["properties"] = deployment["properties"]
|
140
|
+
spec["index"] = 0
|
141
|
+
spec["packages"] = {}
|
142
|
+
spec["configuration_hash"] = {}
|
143
|
+
|
144
|
+
case @options[:cpi]
|
145
|
+
when "vsphere", "vcloud"
|
146
|
+
spec["networks"] = {"local" => {"ip" => "127.0.0.1"}}
|
147
|
+
when "aws"
|
148
|
+
spec["networks"] = {"type" => "dynamic"}
|
149
|
+
when "openstack"
|
150
|
+
spec["networks"] = {"type" => "dynamic"}
|
151
|
+
else
|
152
|
+
puts "WARNING: no CPI specified"
|
153
|
+
end
|
154
|
+
|
155
|
+
spec
|
156
|
+
end
|
157
|
+
|
158
|
+
def compile_packages(dir, manifest, packages)
|
159
|
+
packages.each do |name|
|
160
|
+
package = find_package(manifest, name)
|
161
|
+
compile_packages(dir, manifest, package["dependencies"]) if package["dependencies"]
|
162
|
+
|
163
|
+
@logger.debug "compiling package #{name}"
|
164
|
+
compile_package(dir, package, name)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def find_package(manifest, name)
|
169
|
+
manifest["packages"].detect { |p| p["name"] == name }
|
170
|
+
end
|
171
|
+
|
172
|
+
def compile_package(dir, package, name)
|
173
|
+
# return if package is already compiled
|
174
|
+
return if @spec["packages"].has_key?(name)
|
175
|
+
|
176
|
+
src = "#{dir}/packages/#{name}.tgz"
|
177
|
+
version = package["version"]
|
178
|
+
dependencies = package["dependencies"]
|
179
|
+
|
180
|
+
# push source package into blobstore
|
181
|
+
file = File.new(src)
|
182
|
+
id = @blobstore_client.create(file)
|
183
|
+
|
184
|
+
sha1 = "sha1"
|
185
|
+
dependencies = {}
|
186
|
+
package["dependencies"].each do |name|
|
187
|
+
@logger.debug "dependency: #{name} = #{@spec["packages"][name]}"
|
188
|
+
dependencies[name] = @spec["packages"][name]
|
189
|
+
end
|
190
|
+
|
191
|
+
result = @agent.run_task(:compile_package, id, sha1, name, version, dependencies)
|
192
|
+
@logger.info("result is #{result}")
|
193
|
+
|
194
|
+
# remove source package from blobstore
|
195
|
+
@blobstore_client.delete(id)
|
196
|
+
|
197
|
+
id = result["result"]["blobstore_id"]
|
198
|
+
@logger.debug("stored package #{name} as #{id}")
|
199
|
+
|
200
|
+
@spec["packages"][name] = {
|
201
|
+
"name" => name,
|
202
|
+
"version" => version.to_s,
|
203
|
+
"sha1" => result["result"]["sha1"],
|
204
|
+
"blobstore_id" => id
|
205
|
+
}
|
206
|
+
end
|
207
|
+
|
208
|
+
def untar(file)
|
209
|
+
prev_dir = Dir.getwd
|
210
|
+
dir = Dir.mktmpdir
|
211
|
+
Dir.chdir(dir)
|
212
|
+
@logger.debug("untaring #{file} into #{dir}")
|
213
|
+
out = `tar xzf #{file} 2>&1`
|
214
|
+
raise RuntimeError, "untar of #{file} failed: #{out}" unless $? == 0
|
215
|
+
yield dir
|
216
|
+
ensure
|
217
|
+
Dir.chdir(prev_dir)
|
218
|
+
FileUtils.rm_rf dir
|
219
|
+
end
|
220
|
+
|
221
|
+
def apply
|
222
|
+
connect_to_agent
|
223
|
+
FileUtils.mkdir_p(File.join(@options["base_dir"], 'data/log'))
|
224
|
+
# Stop services
|
225
|
+
@logger.info("Stopping services")
|
226
|
+
begin
|
227
|
+
@agent.run_task(:stop)
|
228
|
+
rescue => e
|
229
|
+
@logger.warn("Ignoring error to stop services #{e.inspect}")
|
230
|
+
end
|
231
|
+
|
232
|
+
@spec = Psych.load_file(@options["apply_spec"])
|
233
|
+
@logger.info("#{@spec.inspect}")
|
234
|
+
update_bosh_spec
|
235
|
+
@agent.run_task(:apply, @spec)
|
236
|
+
|
237
|
+
@logger.info("Starting services")
|
238
|
+
@agent.run_task(:start)
|
239
|
+
end
|
240
|
+
|
241
|
+
def update_bosh_spec
|
242
|
+
uri = URI.parse(@options["agent_uri"])
|
243
|
+
ip = uri.host
|
244
|
+
properties = @spec["properties"]
|
245
|
+
properties["blobstore"]["address"] = ip
|
246
|
+
properties["postgres"]["address"] = ip
|
247
|
+
properties["director"]["address"] = ip
|
248
|
+
properties["redis"]["address"] = ip
|
249
|
+
properties["nats"]["address"] = ip
|
250
|
+
@spec["properties"] = properties
|
251
|
+
end
|
252
|
+
|
253
|
+
def add_default_properties(spec_properties, job_properties)
|
254
|
+
return unless job_properties
|
255
|
+
|
256
|
+
job_properties.each_pair do |name, definition|
|
257
|
+
unless definition["default"].nil?
|
258
|
+
copy_property(spec_properties, spec_properties, name, definition["default"])
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bosh-release
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.5.0.pre.1113
|
5
|
+
prerelease: 6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- VMware
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: agent_client
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0.pre.1113
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.0.pre.1113
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: blobstore_client
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.0.pre.1113
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.0.pre.1113
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bosh_common
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.5.0.pre.1113
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.5.0.pre.1113
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: yajl-ruby
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.1.0
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.1.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: trollop
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '1.16'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '1.16'
|
94
|
+
description: ! 'Bosh package compiler
|
95
|
+
|
96
|
+
cfd471'
|
97
|
+
email: support@cloudfoundry.com
|
98
|
+
executables:
|
99
|
+
- bosh-release
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- lib/bosh/release.rb
|
104
|
+
- lib/bosh/release/compiler.rb
|
105
|
+
- lib/bosh/release/version.rb
|
106
|
+
- README
|
107
|
+
- bin/bosh-release
|
108
|
+
homepage: https://github.com/cloudfoundry/bosh
|
109
|
+
licenses:
|
110
|
+
- Apache 2.0
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 1.9.3
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>'
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 1.3.1
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 1.8.23
|
130
|
+
signing_key:
|
131
|
+
specification_version: 3
|
132
|
+
summary: Bosh package compiler
|
133
|
+
test_files: []
|