chef-provisioning-fog 0.10 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3e73de89aa673ce08cddf04a254af4b1808e4a6a
4
- data.tar.gz: 978136a1217ac2b147aa44c9b62497dc7abfec95
3
+ metadata.gz: fe71d09d45a8426eb7af5b9367aac358cf752124
4
+ data.tar.gz: 0c454ebeb8827924742c91f1c566c90f6d6f3560
5
5
  SHA512:
6
- metadata.gz: 57af9e41878abf583365e17f73326a9979c2bab6bf1316d59e1b277a4d4339a54b417730959b701de79f6c3afcc587e40c323b99bfe128dab0f90a6691c4d888
7
- data.tar.gz: 1cb02b4c0fef3f645203882a1b59a31267c5618119214f8de9c019deee0a8e8185687ea65dde469a7438ec4462bafc0605bf3fd0fac67e60f1e316d8ad60adb0
6
+ metadata.gz: 121ff3e73fefe9f6b401727831a46d47b2a7550c07fe0f6ec71915883e7ff7da8626a0989758b674768593149046ecb3a3ba49cb55fffcd112dd2a1d7364b9e8
7
+ data.tar.gz: 34447372a2c4605cc90b4a476aef6454be76892ccfd88b27a85d93edce61d86e810888d115cadba6425f8cd7706579bad125850e8473af1ebda42b542a0f5aa2
@@ -0,0 +1 @@
1
+ require 'chef/provisioning/fog_driver/driver'
@@ -10,7 +10,9 @@ require 'chef/provisioning/convergence_strategy/install_sh'
10
10
  require 'chef/provisioning/convergence_strategy/install_cached'
11
11
  require 'chef/provisioning/convergence_strategy/no_converge'
12
12
  require 'chef/provisioning/transport/ssh'
13
+ require 'chef/provisioning/transport/winrm'
13
14
  require 'chef/provisioning/fog_driver/version'
15
+
14
16
  require 'fog'
15
17
  require 'fog/core'
16
18
  require 'fog/compute'
@@ -258,9 +260,15 @@ module FogDriver
258
260
  end
259
261
 
260
262
  # Not meant to be part of public interface
261
- def transport_for(machine_spec, machine_options, server)
262
- # TODO winrm
263
- create_ssh_transport(machine_spec, machine_options, server)
263
+ def transport_for(machine_spec, machine_options, server, action_handler = nil)
264
+ if machine_spec.location['is_windows']
265
+ action_handler.report_progress "Waiting for admin password on #{machine_spec.name} to be ready (may take up to 15 minutes)..." if action_handler
266
+ transport = create_winrm_transport(machine_spec, machine_options, server)
267
+ action_handler.report_progress 'Admin password available ...' if action_handler
268
+ transport
269
+ else
270
+ create_ssh_transport(machine_spec, machine_options, server)
271
+ end
264
272
  end
265
273
 
266
274
  protected
@@ -400,7 +408,8 @@ module FogDriver
400
408
  end
401
409
 
402
410
  def wait_for_transport(action_handler, machine_spec, machine_options, server)
403
- transport = transport_for(machine_spec, machine_options, server)
411
+
412
+ transport = transport_for(machine_spec, machine_options, server, action_handler)
404
413
  if !transport.available?
405
414
  if action_handler.should_perform_actions
406
415
  action_handler.report_progress "waiting for #{machine_spec.name} (#{server.id} on #{driver_url}) to be connectable (transport up and running) ..."
@@ -560,37 +569,43 @@ module FogDriver
560
569
  end
561
570
  end
562
571
 
563
- def ssh_options_for(machine_spec, machine_options, server)
564
- result = {
565
- # TODO create a user known hosts file
566
- # :user_known_hosts_file => vagrant_ssh_config['UserKnownHostsFile'],
567
- # :paranoid => true,
568
- :auth_methods => [ 'publickey' ],
569
- :keys_only => true,
570
- :host_key_alias => "#{server.id}.#{provider}"
571
- }.merge(machine_options[:ssh_options] || {})
572
+ # Get the private key for a machine - prioritize the server data, fall back to the
573
+ # the machine spec data, and if that doesn't work, raise an exception.
574
+ # @param [Hash] machine_spec Machine spec data
575
+ # @param [Chef::Provisioning::Machine] server a Machine representing the server
576
+ # @return [String] PEM-encoded private key
577
+ def private_key_for(machine_spec, server)
572
578
  if server.respond_to?(:private_key) && server.private_key
573
- result[:key_data] = [ server.private_key ]
579
+ server.private_key
574
580
  elsif server.respond_to?(:key_name) && server.key_name
575
581
  key = get_private_key(server.key_name)
576
582
  if !key
577
583
  raise "Server has key name '#{server.key_name}', but the corresponding private key was not found locally. Check if the key is in Chef::Config.private_key_paths: #{Chef::Config.private_key_paths.join(', ')}"
578
584
  end
579
- result[:key_data] = [ key ]
585
+ key
580
586
  elsif machine_spec.location['key_name']
581
587
  key = get_private_key(machine_spec.location['key_name'])
582
588
  if !key
583
589
  raise "Server was created with key name '#{machine_spec.location['key_name']}', but the corresponding private key was not found locally. Check if the key is in Chef::Config.private_key_paths: #{Chef::Config.private_key_paths.join(', ')}"
584
590
  end
585
- result[:key_data] = [ key ]
591
+ key
586
592
  elsif machine_options[:bootstrap_options][:key_path]
587
- result[:key_data] = [ IO.read(machine_options[:bootstrap_options][:key_path]) ]
593
+ IO.read(machine_options[:bootstrap_options][:key_path])
588
594
  elsif machine_options[:bootstrap_options][:key_name]
589
- result[:key_data] = [ get_private_key(machine_options[:bootstrap_options][:key_name]) ]
595
+ get_private_key(machine_options[:bootstrap_options][:key_name])
590
596
  else
591
597
  # TODO make a way to suggest other keys to try ...
592
598
  raise "No key found to connect to #{machine_spec.name} (#{machine_spec.location.inspect})!"
593
599
  end
600
+ end
601
+
602
+ def ssh_options_for(machine_spec, machine_options, server)
603
+ result = {
604
+ :auth_methods => [ 'publickey' ],
605
+ :keys_only => true,
606
+ :host_key_alias => "#{server.id}.#{provider}"
607
+ }.merge(machine_options[:ssh_options] || {})
608
+ result[:key_data] = [ private_key_for(machine_spec, server) ]
594
609
  result
595
610
  end
596
611
 
@@ -598,6 +613,10 @@ module FogDriver
598
613
  'root'
599
614
  end
600
615
 
616
+ def create_winrm_transport(machine_spec, machine_options, server)
617
+ fail "This provider doesn't know how to do that."
618
+ end
619
+
601
620
  def create_ssh_transport(machine_spec, machine_options, server)
602
621
  ssh_options = ssh_options_for(machine_spec, machine_options, server)
603
622
  username = machine_spec.location['ssh_username'] || default_ssh_username
@@ -1,6 +1,10 @@
1
1
  require 'chef/log'
2
2
  require 'fog/aws'
3
3
  require 'uri'
4
+ require 'base64'
5
+ require 'openssl'
6
+ require 'pathname'
7
+ require 'chef/provisioning/transport/winrm'
4
8
 
5
9
  # fog:AWS:<account_id>:<region>
6
10
  # fog:AWS:<profile_name>
@@ -23,6 +27,45 @@ module FogDriver
23
27
  'ubuntu'
24
28
  end
25
29
 
30
+ # Create a WinRM transport for an AWS instance
31
+ # @param [Hash] machine_spec Machine-spec hash
32
+ # @param [Hash] machine_options Machine options (from the recipe)
33
+ # @param [Fog::Compute::Server] server A Fog mapping to the AWS instance
34
+ # @return [ChefMetal::Transport::WinRM] A WinRM Transport object to talk to the server
35
+ def create_winrm_transport(machine_spec, machine_options, server)
36
+ remote_host = if machine_spec.location['use_private_ip_for_ssh']
37
+ server.private_ip_address
38
+ elsif !server.public_ip_address
39
+ Chef::Log.warn("Server #{machine_spec.name} has no public ip address. Using private ip '#{server.private_ip_address}'. Set driver option 'use_private_ip_for_ssh' => true if this will always be the case ...")
40
+ server.private_ip_address
41
+ elsif server.public_ip_address
42
+ server.public_ip_address
43
+ else
44
+ fail "Server #{server.id} has no private or public IP address!"
45
+ end
46
+
47
+ port = machine_spec.location['winrm_port'] || 5985
48
+ endpoint = "http://#{remote_host}:#{port}/wsman"
49
+ type = :plaintext
50
+ pem_bytes = private_key_for(machine_spec, server)
51
+ encrypted_admin_password = wait_for_admin_password(machine_spec)
52
+ decoded = Base64.decode64(encrypted_admin_password)
53
+ private_key = OpenSSL::PKey::RSA.new(pem_bytes)
54
+ decrypted_password = private_key.private_decrypt decoded
55
+
56
+ # Use basic HTTP auth - this is required for the WinRM setup we
57
+ # are using
58
+ # TODO: Improve that.
59
+ options = {
60
+ :user => machine_spec.location['winrm.username'] || 'Administrator',
61
+ :pass => decrypted_password,
62
+ :disable_sspi => true,
63
+ :basic_auth_only => true
64
+ }
65
+
66
+ Chef::Provisioning::Transport::WinRM.new(endpoint, type, options, {})
67
+ end
68
+
26
69
  def allocate_image(action_handler, image_spec, image_options, machine_spec)
27
70
  if image_spec.location
28
71
  image = compute.images.get(image_spec.location['image_id'])
@@ -87,6 +130,12 @@ module FogDriver
87
130
  if !bootstrap_options[:key_name]
88
131
  bootstrap_options[:key_name] = overwrite_default_key_willy_nilly(action_handler, machine_spec)
89
132
  end
133
+
134
+ if machine_options[:is_windows]
135
+ Chef::Log.debug('Attaching WinRM data for user data.')
136
+ # Enable WinRM basic auth, HTTP and open the firewall
137
+ bootstrap_options[:user_data] = user_data
138
+ end
90
139
  bootstrap_options.delete(:tags) # we handle these separately for performance reasons
91
140
  bootstrap_options
92
141
  end
@@ -351,6 +400,27 @@ module FogDriver
351
400
  end
352
401
 
353
402
  private
403
+ def user_data
404
+ # TODO: Make this use HTTPS at some point.
405
+ <<EOD
406
+ <powershell>
407
+ winrm quickconfig -q
408
+ winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}'
409
+ winrm set winrm/config '@{MaxTimeoutms="1800000"}'
410
+ winrm set winrm/config/service '@{AllowUnencrypted="true"}'
411
+ winrm set winrm/config/service/auth '@{Basic="true"}'
412
+
413
+ netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow
414
+ netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow
415
+
416
+ net stop winrm
417
+ sc config winrm start=auto
418
+ net start winrm
419
+ </powershell>
420
+
421
+ EOD
422
+ end
423
+
354
424
  def self.default_ami_for_region(region)
355
425
  Chef::Log.debug("Choosing default AMI for region '#{region}'")
356
426
 
@@ -374,6 +444,33 @@ module FogDriver
374
444
  end
375
445
  end
376
446
 
447
+ # Wait for the Windows Admin password to become available
448
+ # @param [Hash] machine_spec Machine spec data
449
+ # @return [String] encrypted admin password
450
+ def wait_for_admin_password(machine_spec)
451
+ time_elapsed = 0
452
+ sleep_time = 10
453
+ max_wait_time = 900 # 15 minutes
454
+ encrypted_admin_password = nil
455
+ instance_id = machine_spec.location['server_id']
456
+
457
+
458
+ Chef::Log.info "waiting for #{machine_spec.name}'s admin password to be available..."
459
+ while time_elapsed < max_wait_time && encrypted_admin_password.nil?
460
+ response = compute.get_password_data(instance_id)
461
+ encrypted_admin_password = response.body['passwordData']
462
+ if encrypted_admin_password.nil?
463
+ Chef::Log.info "#{time_elapsed}/#{max_wait_time}s elapsed -- sleeping #{sleep_time} seconds for #{machine_spec.name}'s admin password."
464
+ sleep(sleep_time)
465
+ time_elapsed += sleep_time
466
+ end
467
+ end
468
+
469
+ Chef::Log.info "#{machine_spec.name}'s admin password is available!'"
470
+
471
+ encrypted_admin_password
472
+ end
473
+
377
474
  end
378
475
  end
379
476
  end
@@ -1,7 +1,7 @@
1
1
  class Chef
2
2
  module Provisioning
3
3
  module FogDriver
4
- VERSION = '0.10'
4
+ VERSION = '0.11'
5
5
  end
6
6
  end
7
7
  end
@@ -28,7 +28,7 @@ class Chef::Resource::FogKeyPair < Chef::Resource::LWRPBase
28
28
  end
29
29
 
30
30
  # We are not interested in Chef's cloning behavior here.
31
- def load_prior_resource
31
+ def load_prior_resource(*args)
32
32
  Chef::Log.debug("Overloading #{resource_name}.load_prior_resource with NOOP")
33
33
  end
34
34
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-provisioning-fog
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.10'
4
+ version: '0.11'
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Keiser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-01 00:00:00.000000000 Z
11
+ date: 2014-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chef
@@ -107,6 +107,7 @@ files:
107
107
  - Rakefile
108
108
  - lib/chef/provider/fog_key_pair.rb
109
109
  - lib/chef/provisioning/driver_init/fog.rb
110
+ - lib/chef/provisioning/fog_driver.rb
110
111
  - lib/chef/provisioning/fog_driver/driver.rb
111
112
  - lib/chef/provisioning/fog_driver/providers/aws.rb
112
113
  - lib/chef/provisioning/fog_driver/providers/aws/credentials.rb