chef-provisioning-fog 0.10 → 0.11

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.
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