bosh_deployer 0.1.4

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.rdoc ADDED
@@ -0,0 +1,139 @@
1
+ = DESCRIPTION:
2
+
3
+ BOSH Deployer is used to deploy a "micro BOSH". The micro BOSH instance can be used standalone or to deploy additional BOSH instances.
4
+
5
+ Installing the bosh deployer includes an installation of the BOSH cli and a deployer cli plugin called 'micro'.
6
+
7
+ It is recommend that you install into an empty gemset (or similar).
8
+
9
+ = REQUIREMENTS:
10
+
11
+ % apt-get -y install libsqlite3-dev genisoimage
12
+
13
+ % cd bosh/deployer && rake install
14
+
15
+ = CONFIGURATION:
16
+
17
+ For a minimal configuration example, see: deployer/spec/assets/test-bootstrap-config.yml
18
+
19
+ Note that 'disk_path' is 'BOSH_Deployer' rather than 'BOSH_Disks'.
20
+
21
+ A datastore folder other than 'BOSH_Disks' is required if your vCenter hosts other directors.
22
+
23
+ The disk_path folder needs to be created manually.
24
+
25
+ Your configuration must live inside a 'deployments' directory and follow the convention of having a $name subdir containing micro_bosh.yml,
26
+ where $name is your deployment name. For example:
27
+
28
+ % find deployments -name micro_bosh.yml
29
+ deployments/vcs01/micro_bosh.yml
30
+ deployments/dev32/micro_bosh.yml
31
+ deployments/dev33/micro_bosh.yml
32
+
33
+ The 'bosh micro' commands must also be run within the deployments directory.
34
+
35
+ Deployment state is persisted to deployments/bosh-deployments.yml
36
+
37
+ = USAGE:
38
+
39
+ First, be sure to read the CONFIGURATION section and cd into your deployments/ directory.
40
+
41
+ == help
42
+
43
+ The bosh micro plugin help is display after the standard bosh command usage:
44
+
45
+ % bosh help
46
+ ...
47
+ Micro
48
+ micro deployment [<name>] Choose micro deployment to work with
49
+ micro status Display micro BOSH deployment status
50
+ micro deployments Show the list of deployments
51
+ micro deploy <stemcell> Deploy a micro BOSH instance to the currently
52
+ selected deployment
53
+ --update update existing instance
54
+ micro delete Delete micro BOSH instance (including
55
+ persistent disk)
56
+ micro agent <args> Send agent messages
57
+ micro apply <spec> Apply spec
58
+
59
+ == deployment
60
+
61
+ Set the micro bosh deployment to work with:
62
+
63
+ % bosh micro deployment dev33
64
+ Deployment set to '/var/vcap/deployments/dev33/micro_bosh.yml'
65
+
66
+ == deploy
67
+
68
+ Deploy a new micro BOSH instance and create a new persistent disk.
69
+
70
+ % bosh micro deploy ~/cf/stemcells/micro-bosh-stemcell-0.4.2.tgz
71
+
72
+ == deploy --update
73
+
74
+ Update an existing micro BOSH instance. The existing persistent disk will be attached to the new VM.
75
+
76
+ % bosh micro deploy ~/cf/stemcells/micro-bosh-stemcell-0.4.5.tgz --update
77
+
78
+ == delete
79
+
80
+ The delete command will delete the VM, stemcell and persistent disk.
81
+
82
+ Example:
83
+
84
+ % bosh micro delete
85
+
86
+ == status
87
+
88
+ The status command will show the persisted state for a given micro bosh instance.
89
+
90
+ % bosh micro status
91
+ Stemcell CID sc-f2430bf9-666d-4034-9028-abf9040f0edf
92
+ Stemcell name micro-bosh-stemcell-0.4.5
93
+ VM CID vm-9cc859a4-2d51-43ca-8dd5-220425518fd8
94
+ Disk CID 1
95
+ Deployment /var/vcap/deployments/dev33/micro_bosh.yml
96
+ Target micro (http://172.23.194.100:25555) Ver: 0.3.12 (00000000)
97
+
98
+ == deployments
99
+
100
+ Show the list of deployments, this is just a table view of deployments/bosh-deployments.yml.
101
+
102
+ % bosh micro deployments
103
+
104
+ == apply
105
+
106
+ The micro-bosh-stemcell includes an embedded apply_spec.yml. This command can be used to apply a different spec to an existing instance.
107
+ The apply_spec.yml properties are merged with your deployment's network.ip and cloud.properties.vcenters properties.
108
+
109
+ % bosh micro apply apply_spec.yml
110
+
111
+ == agent
112
+
113
+ The cli can send agent messages over HTTP.
114
+
115
+ Example:
116
+
117
+ % bosh micro agent ping
118
+ "pong"
119
+
120
+ = BOSH:
121
+
122
+ Once your micro BOSH instance is deployed, you can target its director:
123
+
124
+ $ bosh micro status
125
+ ...
126
+ Target micro (http://172.23.194.100:25555) Ver: 0.3.12 (00000000)
127
+
128
+ $ bosh target http://172.23.194.100:25555
129
+ Target set to 'micro (http://172.23.194.100:25555) Ver: 0.3.12 (00000000)'
130
+
131
+ $ bosh status
132
+ Updating director data... done
133
+
134
+ Target micro (http://172.23.194.100:25555) Ver: 0.3.12 (00000000)
135
+ UUID b599c640-7351-4717-b23c-532bb35593f0
136
+ User admin
137
+ Deployment not set
138
+
139
+ You can use micro BOSH as-is or to deploy new BOSH instances using micro BOSH: https://github.com/vmware-ac/bosh-release
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ $:.unshift(File.expand_path("../../rake", __FILE__))
4
+
5
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
6
+
7
+ require "rubygems"
8
+ require "bundler"
9
+ Bundler.setup(:default, :test)
10
+
11
+ require "rake/dsl_definition"
12
+ require "rake"
13
+ begin
14
+ require "rspec/core/rake_task"
15
+ rescue LoadError
16
+ end
17
+
18
+ require "bundler_task"
19
+ require "ci_task"
20
+
21
+ gem_helper = Bundler::GemHelper.new(Dir.pwd)
22
+
23
+ desc "Build BOSH Deployer gem into the pkg directory"
24
+ task "build" do
25
+ gem_helper.build_gem
26
+ end
27
+
28
+ desc "Build and install BOSH Deployer gem into system gems"
29
+ task "install" do
30
+ Rake::Task["bundler:install"].invoke
31
+ gem_helper.install_gem
32
+ end
33
+
34
+ BundlerTask.new
35
+
36
+ if defined?(RSpec)
37
+ namespace :spec do
38
+ desc "Run Unit Tests"
39
+ rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
40
+ t.pattern = "spec/unit/**/*_spec.rb"
41
+ t.rspec_opts = %w(--format progress --colour)
42
+ end
43
+
44
+ CiTask.new do |task|
45
+ task.rspec_task = rspec_task
46
+ end
47
+ end
48
+
49
+ desc "Install dependencies and run tests"
50
+ task :spec => %w(bundler:install:test spec:unit)
51
+ end
@@ -0,0 +1,45 @@
1
+ ---
2
+ name:
3
+
4
+ logging:
5
+ level: INFO
6
+
7
+ dir:
8
+
9
+ network:
10
+ type: dynamic
11
+ cloud_properties: {}
12
+
13
+ resources:
14
+ persistent_disk: 4096
15
+ cloud_properties:
16
+ instance_type: m1.small
17
+ availability_zone:
18
+
19
+ cloud:
20
+ plugin: aws
21
+ properties:
22
+ aws:
23
+ access_key_id:
24
+ secret_access_key:
25
+ ec2_endpoint:
26
+ max_retries: 2
27
+ default_key_name: dougm
28
+ default_security_groups: []
29
+ registry:
30
+ endpoint: http://admin:admin@localhost:25777
31
+ user: admin
32
+ password: admin
33
+ stemcell:
34
+ kernel_id:
35
+ disk_size: 4096
36
+ agent:
37
+ ntp: []
38
+ blobstore:
39
+ plugin: local
40
+ properties:
41
+ blobstore_path: /var/vcap/micro_bosh/data/cache
42
+ mbus:
43
+
44
+ apply_spec:
45
+ properties: {}
@@ -0,0 +1,38 @@
1
+ ---
2
+ name:
3
+
4
+ logging:
5
+ level: INFO
6
+
7
+ dir:
8
+
9
+ network:
10
+ ip:
11
+ netmask:
12
+ gateway:
13
+ dns: []
14
+ cloud_properties:
15
+ name:
16
+
17
+ resources:
18
+ persistent_disk: 4096
19
+ cloud_properties:
20
+ ram: 1024
21
+ disk: 4096
22
+ cpu: 1
23
+
24
+ cloud:
25
+ plugin: vsphere
26
+ properties:
27
+ agent:
28
+ ntp: []
29
+ blobstore:
30
+ plugin: local
31
+ properties:
32
+ blobstore_path: /var/vcap/micro_bosh/data/cache
33
+ mbus:
34
+ soap_log:
35
+ vcenters: []
36
+
37
+ apply_spec:
38
+ properties: {}
@@ -0,0 +1,393 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "deployer"
4
+
5
+ module Bosh::Cli::Command
6
+ class Micro < Base
7
+ include Bosh::Cli::DeploymentHelper
8
+
9
+ MICRO_DIRECTOR_PORT = 25555
10
+ DEFAULT_CONFIG_PATH = File.expand_path("~/.bosh_deployer_config")
11
+
12
+ command :micro_deployment do
13
+ usage "micro deployment [<name>]"
14
+ desc "Choose micro deployment to work with"
15
+ route { |args| (args.size > 0) ? [:micro, :set_current] : [:micro, :show_current] }
16
+ end
17
+
18
+ command :micro_status do
19
+ usage "micro status"
20
+ desc "Display micro BOSH deployment status"
21
+ route :micro, :status
22
+ end
23
+
24
+ command :micro_list_deployments do
25
+ usage "micro deployments"
26
+ desc "Show the list of deployments"
27
+ route :micro, :list
28
+ end
29
+
30
+ command :micro_deploy do
31
+ usage "micro deploy <stemcell>"
32
+ desc "Deploy a micro BOSH instance to the currently selected deployment"
33
+ option "--update", "update existing instance"
34
+ route :micro, :perform
35
+ end
36
+
37
+ command :micro_delete do
38
+ usage "micro delete"
39
+ desc "Delete micro BOSH instance (including persistent disk)"
40
+ route :micro, :delete
41
+ end
42
+
43
+ command :micro_agent do
44
+ usage "micro agent <args>"
45
+ desc "Send agent messages"
46
+ route :micro, :agent
47
+ end
48
+
49
+ command :micro_apply do
50
+ usage "micro apply <spec>"
51
+ desc "Apply spec"
52
+ route :micro, :apply
53
+ end
54
+
55
+ def initialize(options = {})
56
+ options[:config] ||= DEFAULT_CONFIG_PATH #hijack Cli::Config
57
+ super(options)
58
+ end
59
+
60
+ def status
61
+ stemcell_cid = deployer_state(:stemcell_cid)
62
+ stemcell_name = deployer_state(:stemcell_name)
63
+ vm_cid = deployer_state(:vm_cid)
64
+ disk_cid = deployer_state(:disk_cid)
65
+ deployment = config.deployment ? config.deployment.green : "not set".red
66
+
67
+ say("Stemcell CID".ljust(15) + stemcell_cid)
68
+ say("Stemcell name".ljust(15) + stemcell_name)
69
+ say("VM CID".ljust(15) + vm_cid)
70
+ say("Disk CID".ljust(15) + disk_cid)
71
+ say("Micro BOSH CID".ljust(15) + Bosh::Deployer::Config.uuid)
72
+ say("Deployment".ljust(15) + deployment)
73
+
74
+ update_target
75
+
76
+ target_name = full_target_name ? full_target_name.green : "not set".red
77
+ say("Target".ljust(15) + target_name)
78
+ end
79
+
80
+ def perform(*options)
81
+ update = options.delete("--update")
82
+ tarball_path = options.shift
83
+
84
+ if tarball_path.nil?
85
+ err "No stemcell provided"
86
+ end
87
+
88
+ rel_path = deployment[/#{Regexp.escape File.join(work_dir, '')}(.*)/, 1]
89
+
90
+ desc = "`#{rel_path.green}' to `#{target_name.green}'"
91
+
92
+ if update
93
+ unless deployer.exists?
94
+ err "No existing instance to update"
95
+ end
96
+
97
+ confirmation = "Updating"
98
+
99
+ method = :update
100
+ else
101
+ if deployer.exists?
102
+ err "Instance exists. Did you mean to --update?"
103
+ end
104
+
105
+ confirmation = "Deploying new"
106
+
107
+ method = :create
108
+ end
109
+
110
+ confirm_deployment("#{confirmation} micro BOSH instance #{desc}")
111
+
112
+ unless File.directory?(tarball_path)
113
+ stemcell = Bosh::Cli::Stemcell.new(tarball_path, cache)
114
+
115
+ say("\nVerifying stemcell...")
116
+ stemcell.validate
117
+ say("\n")
118
+
119
+ unless stemcell.valid?
120
+ err("Stemcell is invalid, please fix, verify and upload again")
121
+ end
122
+ end
123
+
124
+ renderer = DeployerRenderer.new
125
+ renderer.start
126
+ deployer.renderer = renderer
127
+
128
+ start_time = Time.now
129
+
130
+ deployer.send(method, tarball_path)
131
+
132
+ renderer.finish("done")
133
+
134
+ duration = renderer.duration || (Time.now - start_time)
135
+
136
+ update_target
137
+
138
+ say("Deployed #{desc}, took #{format_time(duration).green} to complete")
139
+ end
140
+
141
+ def delete
142
+ unless deployer.exists?
143
+ err "No existing instance to delete"
144
+ end
145
+
146
+ name = deployer.state.name
147
+
148
+ say "\nYou are going to delete micro BOSH deployment `#{name}'.\n\n" \
149
+ "THIS IS A VERY DESTRUCTIVE OPERATION AND IT CANNOT BE UNDONE!\n".red
150
+
151
+ unless confirmed?
152
+ say "Canceled deleting deployment".green
153
+ return
154
+ end
155
+
156
+ renderer = DeployerRenderer.new
157
+ renderer.start
158
+ deployer.renderer = renderer
159
+
160
+ start_time = Time.now
161
+
162
+ deployer.destroy
163
+
164
+ renderer.finish("done")
165
+
166
+ duration = renderer.duration || (Time.now - start_time)
167
+
168
+ say("Deleted deployment '#{name}', took #{format_time(duration).green} to complete")
169
+ end
170
+
171
+ def set_current(name)
172
+ manifest_filename = find_deployment(name)
173
+
174
+ if !File.exists?(manifest_filename)
175
+ err "Missing manifest for #{name} (tried '#{manifest_filename}')"
176
+ end
177
+
178
+ manifest = load_yaml_file(manifest_filename)
179
+
180
+ unless manifest.is_a?(Hash)
181
+ err "Invalid manifest format"
182
+ end
183
+
184
+ if manifest["network"].blank?
185
+ err "network is not defined in deployment manifest"
186
+ end
187
+ ip = deployer.discover_bosh_ip || name
188
+
189
+ if target
190
+ old_director_ip = URI.parse(target).host
191
+ else
192
+ old_director_ip = nil
193
+ end
194
+
195
+ if old_director_ip != ip
196
+ set_target(ip)
197
+ say "#{"WARNING!".red} Your target has been changed to `#{target.red}'!"
198
+ end
199
+
200
+ say "Deployment set to '#{manifest_filename.green}'"
201
+ config.set_deployment(manifest_filename)
202
+ config.save
203
+ end
204
+
205
+ def show_current
206
+ say(deployment ? "Current deployment is '#{deployment.green}'" : "Deployment not set")
207
+ end
208
+
209
+ def list
210
+ file = File.join(work_dir, Bosh::Deployer::InstanceManager::DEPLOYMENTS_FILE)
211
+ if File.exists?(file)
212
+ deployments = load_yaml_file(file)["instances"]
213
+ else
214
+ deployments = []
215
+ end
216
+
217
+ err("No deployments") if deployments.size == 0
218
+
219
+ na = "n/a"
220
+
221
+ deployments_table = table do |t|
222
+ t.headings = [ "Name", "VM name", "Stemcell name" ]
223
+ deployments.each do |r|
224
+ t << [ r[:name], r[:vm_cid] || na, r[:stemcell_cid] || na ]
225
+ end
226
+ end
227
+
228
+ say("\n")
229
+ say(deployments_table)
230
+ say("\n")
231
+ say("Deployments total: %d" % deployments.size)
232
+ end
233
+
234
+ def agent(*args)
235
+ message = args.shift
236
+ args = args.map do |arg|
237
+ if File.exists?(arg)
238
+ load_yaml_file(arg)
239
+ else
240
+ arg
241
+ end
242
+ end
243
+
244
+ say(deployer.agent.send(message.to_sym, *args).pretty_inspect)
245
+ end
246
+
247
+ def apply(spec)
248
+ deployer.apply(load_yaml_file(spec))
249
+ end
250
+
251
+ private
252
+
253
+ def deployer
254
+ check_if_deployments_dir
255
+ deployment_required
256
+
257
+ if @deployer.nil?
258
+ manifest_filename = deployment
259
+
260
+ if !File.exists?(manifest_filename)
261
+ err("Cannot find deployment manifest in `#{manifest_filename}'")
262
+ end
263
+
264
+ manifest = load_yaml_file(manifest_filename)
265
+
266
+ manifest["dir"] ||= work_dir
267
+ manifest["logging"] ||= {}
268
+ if manifest["logging"]["level"] == "DEBUG"
269
+ log_dir = File.dirname(manifest_filename)
270
+ manifest["logging"]["file"] ||= File.join(log_dir, "bosh_micro_deploy.log")
271
+ end
272
+
273
+ @deployer = Bosh::Deployer::InstanceManager.new(manifest)
274
+
275
+ $stderr.reopen("/dev/null") #silence ssl warnings
276
+ end
277
+
278
+ @deployer
279
+ end
280
+
281
+ def check_if_deployments_dir
282
+ #force the issue to maintain central bosh-deployments.yml
283
+ if File.basename(work_dir) != "deployments"
284
+ err "Sorry, your current directory doesn't look like deployments directory"
285
+ end
286
+ end
287
+
288
+ def find_deployment(name)
289
+ check_if_deployments_dir
290
+ File.expand_path(File.join(work_dir, "#{name}", "micro_bosh.yml"))
291
+ end
292
+
293
+ def deployment_name
294
+ File.basename(File.dirname(deployment))
295
+ end
296
+
297
+ def set_target(ip)
298
+ config.target = "http://#{ip}:#{MICRO_DIRECTOR_PORT}"
299
+ config.save
300
+ end
301
+
302
+ def update_target
303
+ if deployer.exists?
304
+ bosh_ip = deployer.discover_bosh_ip
305
+ if URI.parse(target).host != bosh_ip
306
+ set_current(deployment_name)
307
+ end
308
+
309
+ director = Bosh::Cli::Director.new(target)
310
+
311
+ if options[:director_checks]
312
+ begin
313
+ status = director.get_status
314
+ rescue Bosh::Cli::AuthError
315
+ status = {}
316
+ rescue Bosh::Cli::DirectorError
317
+ err("Cannot talk to director at '#{target}', please set correct target")
318
+ end
319
+ else
320
+ status = { "name" => "Unknown Director", "version" => "n/a" }
321
+ end
322
+ else
323
+ status = {}
324
+ end
325
+
326
+ config.target_name = status["name"]
327
+ config.target_version = status["version"]
328
+ config.target_uuid = status["uuid"]
329
+
330
+ config.save
331
+ end
332
+
333
+ def confirm_deployment(msg)
334
+ unless confirmed?(msg)
335
+ cancel_deployment
336
+ end
337
+ end
338
+
339
+ def deployer_state(column)
340
+ if value = deployer.state.send(column)
341
+ value.green
342
+ else
343
+ "n/a".red
344
+ end
345
+ end
346
+
347
+ class DeployerRenderer < Bosh::Cli::EventLogRenderer
348
+ attr_accessor :stage, :total, :index
349
+
350
+ def start
351
+ @thread = Thread.new do
352
+ loop do
353
+ refresh
354
+ sleep(1)
355
+ end
356
+ end
357
+ end
358
+
359
+ def finish(state)
360
+ @thread.kill
361
+ super(state)
362
+ end
363
+
364
+ def enter_stage(stage, total)
365
+ @stage = stage
366
+ @total = total
367
+ @index = 0
368
+ end
369
+
370
+ def parse_event(event)
371
+ event
372
+ end
373
+
374
+ def update(state, task)
375
+ event = {
376
+ "time" => Time.now,
377
+ "stage" => @stage,
378
+ "task" => task,
379
+ "tags" => [],
380
+ "index" => @index+1,
381
+ "total" => @total,
382
+ "state" => state.to_s,
383
+ "progress" => state == :finished ? 100 : 0
384
+ }
385
+
386
+ add_event(event)
387
+
388
+ @index += 1 if state == :finished
389
+ end
390
+ end
391
+
392
+ end
393
+ end