bosh_deployer 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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