knife-cloud 1.0.0.rc.0

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.
Files changed (68) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +33 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +11 -0
  5. data/CONTRIBUTING.md +5 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +201 -0
  8. data/README.md +420 -0
  9. data/Rakefile +35 -0
  10. data/knife-cloud.gemspec +27 -0
  11. data/lib/chef/knife/cloud/chefbootstrap/bootstrap_distribution.rb +31 -0
  12. data/lib/chef/knife/cloud/chefbootstrap/bootstrap_options.rb +191 -0
  13. data/lib/chef/knife/cloud/chefbootstrap/bootstrap_protocol.rb +69 -0
  14. data/lib/chef/knife/cloud/chefbootstrap/bootstrapper.rb +78 -0
  15. data/lib/chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol.rb +179 -0
  16. data/lib/chef/knife/cloud/chefbootstrap/unix_distribution.rb +31 -0
  17. data/lib/chef/knife/cloud/chefbootstrap/windows_distribution.rb +32 -0
  18. data/lib/chef/knife/cloud/chefbootstrap/winrm_bootstrap_protocol.rb +85 -0
  19. data/lib/chef/knife/cloud/command.rb +101 -0
  20. data/lib/chef/knife/cloud/exceptions.rb +38 -0
  21. data/lib/chef/knife/cloud/fog/options.rb +29 -0
  22. data/lib/chef/knife/cloud/fog/service.rb +200 -0
  23. data/lib/chef/knife/cloud/helpers.rb +39 -0
  24. data/lib/chef/knife/cloud/list_resource_command.rb +97 -0
  25. data/lib/chef/knife/cloud/list_resource_options.rb +21 -0
  26. data/lib/chef/knife/cloud/server/create_command.rb +165 -0
  27. data/lib/chef/knife/cloud/server/create_options.rb +80 -0
  28. data/lib/chef/knife/cloud/server/delete_command.rb +68 -0
  29. data/lib/chef/knife/cloud/server/delete_options.rb +42 -0
  30. data/lib/chef/knife/cloud/server/list_command.rb +84 -0
  31. data/lib/chef/knife/cloud/server/list_options.rb +43 -0
  32. data/lib/chef/knife/cloud/server/options.rb +39 -0
  33. data/lib/chef/knife/cloud/server/show_command.rb +55 -0
  34. data/lib/chef/knife/cloud/server/show_options.rb +36 -0
  35. data/lib/chef/knife/cloud/service.rb +91 -0
  36. data/lib/knife-cloud/version.rb +6 -0
  37. data/lib/test/fixtures/knife.rb +9 -0
  38. data/lib/test/fixtures/validation.pem +27 -0
  39. data/lib/test/knife-utils/helper.rb +39 -0
  40. data/lib/test/knife-utils/knife_test_utils.rb +40 -0
  41. data/lib/test/knife-utils/matchers.rb +29 -0
  42. data/lib/test/knife-utils/test_bed.rb +56 -0
  43. data/lib/test/templates/chef-full-chef-zero.erb +67 -0
  44. data/lib/test/templates/windows-chef-client-msi.erb +231 -0
  45. data/lib/test/templates/windows-shell.erb +77 -0
  46. data/spec/resource_spec_helper.rb +49 -0
  47. data/spec/server_command_common_spec_helper.rb +48 -0
  48. data/spec/spec_helper.rb +25 -0
  49. data/spec/support/shared_examples_for_command.rb +35 -0
  50. data/spec/support/shared_examples_for_servercreatecommand.rb +144 -0
  51. data/spec/support/shared_examples_for_serverdeletecommand.rb +77 -0
  52. data/spec/support/shared_examples_for_service.rb +85 -0
  53. data/spec/unit/bootstrap_protocol_spec.rb +70 -0
  54. data/spec/unit/bootstrapper_spec.rb +171 -0
  55. data/spec/unit/cloud_command_spec.rb +35 -0
  56. data/spec/unit/command_spec.rb +49 -0
  57. data/spec/unit/fog_service_spec.rb +138 -0
  58. data/spec/unit/list_resource_command_spec.rb +136 -0
  59. data/spec/unit/server_create_command_spec.rb +198 -0
  60. data/spec/unit/server_delete_command_spec.rb +25 -0
  61. data/spec/unit/server_list_command_spec.rb +119 -0
  62. data/spec/unit/server_show_command_spec.rb +64 -0
  63. data/spec/unit/service_spec.rb +46 -0
  64. data/spec/unit/ssh_bootstrap_protocol_spec.rb +116 -0
  65. data/spec/unit/unix_distribution_spec.rb +37 -0
  66. data/spec/unit/windows_distribution_spec.rb +37 -0
  67. data/spec/unit/winrm_bootstrap_protocol_spec.rb +106 -0
  68. metadata +248 -0
@@ -0,0 +1,191 @@
1
+ # Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ require 'chef/knife/winrm_base'
19
+ require 'chef/knife/core/bootstrap_context'
20
+ require 'net/ssh/multi'
21
+
22
+ class Chef
23
+ class Knife
24
+ class Cloud
25
+ # Ideally chef/knife/bootstap should expose this as module.
26
+ module BootstrapOptions
27
+
28
+ def self.included(includer)
29
+ includer.class_eval do
30
+
31
+ deps do
32
+ require 'chef/json_compat'
33
+ require 'tempfile'
34
+ require 'highline'
35
+ require 'net/ssh'
36
+ require 'chef/knife/ssh'
37
+ Chef::Knife::Ssh.load_deps
38
+ end
39
+
40
+ include Chef::Knife::WinrmBase
41
+
42
+ option :ssh_user,
43
+ :short => "-x USERNAME",
44
+ :long => "--ssh-user USERNAME",
45
+ :description => "The ssh username",
46
+ :default => "root"
47
+
48
+ option :ssh_password,
49
+ :short => "-P PASSWORD",
50
+ :long => "--ssh-password PASSWORD",
51
+ :description => "The ssh password"
52
+
53
+ option :ssh_port,
54
+ :short => "-p PORT",
55
+ :long => "--ssh-port PORT",
56
+ :description => "The ssh port",
57
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key },
58
+ :default => "22"
59
+
60
+ option :ssh_gateway,
61
+ :long => "--ssh-gateway GATEWAY",
62
+ :description => "The ssh gateway server. Any proxies configured in your ssh config are automatically used by default.",
63
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
64
+
65
+ option :ssh_gateway_identity,
66
+ :long => "--ssh-gateway-identity IDENTITY_FILE",
67
+ :description => "The private key for ssh gateway server",
68
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway_identity] = key }
69
+
70
+ option :forward_agent,
71
+ :long => "--forward-agent",
72
+ :description => "Enable SSH agent forwarding",
73
+ :boolean => true
74
+
75
+ option :identity_file,
76
+ :short => "-i IDENTITY_FILE",
77
+ :long => "--identity-file IDENTITY_FILE",
78
+ :description => "The SSH identity file used for authentication"
79
+
80
+ option :chef_node_name,
81
+ :short => "-N NAME",
82
+ :long => "--node-name NAME",
83
+ :description => "The Chef node name for your new node"
84
+
85
+ option :prerelease,
86
+ :long => "--prerelease",
87
+ :description => "Install the pre-release chef gems"
88
+
89
+ option :bootstrap_version,
90
+ :long => "--bootstrap-version VERSION",
91
+ :description => "The version of Chef to install",
92
+ :proc => lambda { |v| Chef::Config[:knife][:bootstrap_version] = v }
93
+
94
+ option :bootstrap_proxy,
95
+ :long => "--bootstrap-proxy PROXY_URL",
96
+ :description => "The proxy server for the node being bootstrapped",
97
+ :proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
98
+
99
+ option :bootstrap_no_proxy,
100
+ :long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
101
+ :description => "Do not proxy locations for the node being bootstrapped; this option is used internally by Opscode",
102
+ :proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np }
103
+
104
+ option :distro,
105
+ :short => "-d DISTRO",
106
+ :long => "--distro DISTRO",
107
+ :description => "Bootstrap a distro using a template"
108
+
109
+ option :use_sudo,
110
+ :long => "--sudo",
111
+ :description => "Execute the bootstrap via sudo",
112
+ :boolean => true
113
+
114
+ option :use_sudo_password,
115
+ :long => "--use-sudo-password",
116
+ :description => "Execute the bootstrap via sudo with password",
117
+ :boolean => false
118
+
119
+ option :template_file,
120
+ :long => "--template-file TEMPLATE",
121
+ :description => "Full path to location of template to use",
122
+ :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
123
+ :default => false
124
+
125
+ option :run_list,
126
+ :short => "-r RUN_LIST",
127
+ :long => "--run-list RUN_LIST",
128
+ :description => "Comma separated list of roles/recipes to apply",
129
+ :proc => lambda { |o| o.split(/[\s,]+/) },
130
+ :default => []
131
+
132
+ option :first_boot_attributes,
133
+ :short => "-j JSON_ATTRIBS",
134
+ :long => "--json-attributes",
135
+ :description => "A JSON string to be added to the first run of chef-client",
136
+ :proc => lambda { |o| JSON.parse(o) },
137
+ :default => {}
138
+
139
+ option :host_key_verify,
140
+ :long => "--[no-]host-key-verify",
141
+ :description => "Verify host key, enabled by default.",
142
+ :boolean => true,
143
+ :default => true
144
+
145
+ option :hint,
146
+ :long => "--hint HINT_NAME[=HINT_FILE]",
147
+ :description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
148
+ :proc => Proc.new { |h|
149
+ Chef::Config[:knife][:hints] ||= Hash.new
150
+ name, path = h.split("=")
151
+ Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new }
152
+
153
+ option :secret,
154
+ :short => "-s SECRET",
155
+ :long => "--secret ",
156
+ :description => "The secret key to use to encrypt data bag item values"
157
+
158
+ option :secret_file,
159
+ :long => "--secret-file SECRET_FILE",
160
+ :description => "A file containing the secret key to use to encrypt data bag item values"
161
+
162
+ option :bootstrap_url,
163
+ :long => "--bootstrap-url URL",
164
+ :description => "URL to a custom installation script",
165
+ :proc => Proc.new { |u| Chef::Config[:knife][:bootstrap_url] = u }
166
+
167
+ option :bootstrap_install_command,
168
+ :long => "--bootstrap-install-command COMMANDS",
169
+ :description => "Custom command to install chef-client",
170
+ :proc => Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic }
171
+
172
+ option :bootstrap_wget_options,
173
+ :long => "--bootstrap-wget-options OPTIONS",
174
+ :description => "Add options to wget when installing chef-client",
175
+ :proc => Proc.new { |wo| Chef::Config[:knife][:bootstrap_wget_options] = wo }
176
+
177
+ option :bootstrap_curl_options,
178
+ :long => "--bootstrap-curl-options OPTIONS",
179
+ :description => "Add options to curl when install chef-client",
180
+ :proc => Proc.new { |co| Chef::Config[:knife][:bootstrap_curl_options] = co }
181
+
182
+ option :auth_timeout,
183
+ :long => "--auth-timeout MINUTES",
184
+ :description => "The maximum time in minutes to wait to for authentication over the transport to the node to succeed. The default value is 25 minutes.",
185
+ :default => 25
186
+ end
187
+ end
188
+ end # module ends
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,69 @@
1
+ # Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife/core/ui'
21
+ require 'chef/knife/cloud/helpers'
22
+
23
+ class Chef
24
+ class Knife
25
+ class Cloud
26
+ class BootstrapProtocol
27
+ include Chef::Knife::Cloud::Helpers
28
+
29
+ attr_accessor :bootstrap, :ui, :initial_sleep_delay
30
+ attr_reader :config
31
+
32
+ def initialize(config)
33
+ @config = config
34
+ @ui ||= Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
35
+ end
36
+
37
+ def wait_for_server_ready
38
+ raise Chef::Exceptions::Override, "You must override wait_for_server_ready in #{self.to_s}"
39
+ end
40
+
41
+ def send_bootstrap_command
42
+ wait_for_server_ready
43
+ init_bootstrap_options
44
+ @bootstrap.run
45
+ end
46
+
47
+ def init_bootstrap_options
48
+ # set the command bootstrap options.
49
+ bootstrap.name_args = locate_config_value(:bootstrap_ip_address)
50
+ bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name)
51
+ bootstrap.config[:run_list] = locate_config_value(:run_list)
52
+ bootstrap.config[:prerelease] = locate_config_value(:prerelease)
53
+ bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
54
+ bootstrap.config[:distro] = locate_config_value(:distro)
55
+ bootstrap.config[:bootstrap_proxy] = locate_config_value(:bootstrap_proxy)
56
+ bootstrap.config[:environment] = locate_config_value(:environment)
57
+ # see chef/knife/bootstrap.rb #warn_chef_config_secret_key.
58
+ bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
59
+ bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
60
+ bootstrap.config[:first_boot_attributes] = locate_config_value(:first_boot_attributes)
61
+ bootstrap.config[:secret] = locate_config_value(:secret)
62
+ bootstrap.config[:secret_file] = locate_config_value(:secret_file)
63
+ bootstrap.config[:template_file] = locate_config_value(:template_file)
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,78 @@
1
+ # Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife/core/ui'
21
+ require 'chef/knife/cloud/chefbootstrap/ssh_bootstrap_protocol'
22
+ require 'chef/knife/cloud/chefbootstrap/winrm_bootstrap_protocol'
23
+ require 'chef/knife/cloud/chefbootstrap/windows_distribution'
24
+ require 'chef/knife/cloud/chefbootstrap/unix_distribution'
25
+ require 'chef/knife/cloud/exceptions'
26
+
27
+ class Chef
28
+ class Knife
29
+ class Cloud
30
+ class Bootstrapper
31
+
32
+ def initialize(config)
33
+ @config = config
34
+ @ui ||= Chef::Knife::UI.new(STDOUT, STDERR, STDIN, {})
35
+ end
36
+
37
+ def bootstrap
38
+ # uses BootstrapDistribution and BootstrapProtocol to perform bootstrap
39
+ @protocol = create_bootstrap_protocol
40
+ @distribution = create_bootstrap_distribution
41
+ begin
42
+ @protocol.send_bootstrap_command
43
+ rescue Net::SSH::AuthenticationFailed => e
44
+ error_message = "Authentication Failed during bootstrapping. #{e.message}."
45
+ raise CloudExceptions::BootstrapError, error_message
46
+ end
47
+ end
48
+
49
+ def create_bootstrap_protocol
50
+ if @config[:bootstrap_protocol].nil? or @config[:bootstrap_protocol] == 'ssh'
51
+ SshBootstrapProtocol.new(@config)
52
+ elsif @config[:bootstrap_protocol] == 'winrm'
53
+ WinrmBootstrapProtocol.new(@config)
54
+ else
55
+ # raise an exception, invalid bootstrap protocol.
56
+ error_message = "Invalid bootstrap protocol."
57
+ ui.fatal(error_message)
58
+ raise CloudExceptions::BootstrapError, error_message
59
+ end
60
+ end
61
+
62
+ def create_bootstrap_distribution
63
+ if @config[:image_os_type] == 'windows'
64
+ Chef::Knife::Cloud::WindowsDistribution.new(@config)
65
+ elsif @config[:image_os_type] == 'linux'
66
+ Chef::Knife::Cloud::UnixDistribution.new(@config)
67
+ else
68
+ # raise an exception, invalid bootstrap distribution.
69
+ error_message = "Invalid bootstrap distribution. image_os_type should be either windows or linux."
70
+ ui.fatal(error_message)
71
+ raise CloudExceptions::BootstrapError, error_message
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,179 @@
1
+ # Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife/cloud/chefbootstrap/bootstrap_protocol'
21
+ require 'chef/knife/core/windows_bootstrap_context'
22
+ require 'chef/knife/bootstrap'
23
+
24
+
25
+ class Chef
26
+ class Knife
27
+ class Cloud
28
+ class SshBootstrapProtocol < BootstrapProtocol
29
+
30
+ def initialize(config)
31
+ @bootstrap = (config[:image_os_type] == 'linux') ? Chef::Knife::Bootstrap.new : Chef::Knife::BootstrapWindowsSsh.new
32
+ super
33
+ end
34
+
35
+ def init_bootstrap_options
36
+ bootstrap.config[:ssh_user] = @config[:ssh_user]
37
+ bootstrap.config[:ssh_password] = @config[:ssh_password]
38
+ bootstrap.config[:ssh_port] = locate_config_value(:ssh_port)
39
+ bootstrap.config[:identity_file] = @config[:identity_file]
40
+ bootstrap.config[:host_key_verify] = @config[:host_key_verify]
41
+ bootstrap.config[:use_sudo] = true unless @config[:ssh_user] == 'root'
42
+ bootstrap.config[:template_file] = @config[:template_file]
43
+ bootstrap.config[:ssh_gateway] = locate_config_value(:ssh_gateway)
44
+ bootstrap.config[:forward_agent] = locate_config_value(:forward_agent)
45
+ bootstrap.config[:use_sudo_password] = locate_config_value(:use_sudo_password)
46
+ super
47
+ end
48
+
49
+ def wait_for_server_ready
50
+ print "\n#{ui.color("Waiting for sshd to host (#{@config[:bootstrap_ip_address]})", :magenta)}"
51
+
52
+ ssh_gateway = get_ssh_gateway_for(@config[:bootstrap_ip_address])
53
+
54
+ # The ssh_gateway & subnet_id are currently supported only in EC2.
55
+ if ssh_gateway
56
+ print(".") until tunnel_test_ssh(ssh_gateway, @config[:bootstrap_ip_address]) {
57
+ @initial_sleep_delay = !!locate_config_value(:subnet_id) ? 40 : 10
58
+ sleep @initial_sleep_delay
59
+ puts("done")
60
+ }
61
+ else
62
+ print(".") until tcp_test_ssh(@config[:bootstrap_ip_address], locate_config_value(:ssh_port)) {
63
+ @initial_sleep_delay = !!locate_config_value(:subnet_id) ? 40 : 10
64
+ sleep @initial_sleep_delay
65
+ puts("done")
66
+ }
67
+ end
68
+ end
69
+
70
+ def get_ssh_gateway_for(hostname)
71
+ if locate_config_value(:ssh_gateway)
72
+ # The ssh_gateway specified in the knife config (if any) takes
73
+ # precedence over anything in the SSH configuration
74
+ Chef::Log.debug("Using ssh gateway #{locate_config_value(:ssh_gateway)} from knife config")
75
+ locate_config_value(:ssh_gateway)
76
+ else
77
+ # Next, check if the SSH configuration has a ProxyCommand
78
+ # directive for this host. If there is one, parse out the
79
+ # host from the proxy command
80
+ ssh_proxy = Net::SSH::Config.for(hostname)[:proxy]
81
+ if ssh_proxy.respond_to?(:command_line_template)
82
+ # ssh gateway_hostname nc %h %p
83
+ proxy_pattern = /ssh\s+(\S+)\s+nc/
84
+ matchdata = proxy_pattern.match(ssh_proxy.command_line_template)
85
+ if matchdata.nil?
86
+ Chef::Log.debug("Unable to determine ssh gateway for '#{hostname}' from ssh config template: #{ssh_proxy.command_line_template}")
87
+ nil
88
+ else
89
+ # Return hostname extracted from command line template
90
+ Chef::Log.debug("Using ssh gateway #{matchdata[1]} from ssh config")
91
+ matchdata[1]
92
+ end
93
+ else
94
+ # Return nil if we cannot find an ssh_gateway
95
+ Chef::Log.debug("No ssh gateway found, making a direct connection")
96
+ nil
97
+ end
98
+ end
99
+ end
100
+
101
+ def tcp_test_ssh(hostname, ssh_port)
102
+ begin
103
+ tcp_socket = TCPSocket.new(hostname, ssh_port)
104
+ readable = IO.select([tcp_socket], nil, nil, 5)
105
+ if readable
106
+ ssh_banner = tcp_socket.gets
107
+ if ssh_banner.nil? or ssh_banner.empty?
108
+ false
109
+ else
110
+ Chef::Log.debug("ssh accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
111
+ yield
112
+ true
113
+ end
114
+ else
115
+ false
116
+ end
117
+ rescue Errno::EPERM, Errno::ETIMEDOUT
118
+ Chef::Log.debug("ssh timed out: #{hostname}")
119
+ false
120
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
121
+ Chef::Log.debug("ssh failed to connect: #{hostname}")
122
+ sleep 2
123
+ false
124
+ # This happens on some mobile phone networks
125
+ rescue Errno::ECONNRESET
126
+ Chef::Log.debug("ssh reset its connection: #{hostname}")
127
+ sleep 2
128
+ false
129
+ ensure
130
+ tcp_socket && tcp_socket.close
131
+ end
132
+ end
133
+
134
+ def tunnel_test_ssh(ssh_gateway, hostname, &block)
135
+ begin
136
+ status = false
137
+ gateway = configure_ssh_gateway(ssh_gateway)
138
+ gateway.open(hostname, locate_config_value(:ssh_port)) do |local_tunnel_port|
139
+ status = tcp_test_ssh('localhost', local_tunnel_port, &block)
140
+ end
141
+ status
142
+ rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
143
+ sleep 2
144
+ false
145
+ rescue Errno::EPERM, Errno::ETIMEDOUT
146
+ false
147
+ end
148
+ end
149
+
150
+ def configure_ssh_gateway(ssh_gateway)
151
+ gw_host, gw_user = ssh_gateway.split('@').reverse
152
+ gw_host, gw_port = gw_host.split(':')
153
+ gateway_options = { :port => gw_port || 22 }
154
+
155
+ # Load the SSH config for the SSH gateway host.
156
+ # Set the gateway user if it was not part of the
157
+ # SSH gateway string, and use any configured
158
+ # SSH keys.
159
+ ssh_gateway_config = Net::SSH::Config.for(gw_host)
160
+ gw_user ||= ssh_gateway_config[:user]
161
+
162
+ # Always use the gateway keys from the SSH Config
163
+ gateway_keys = ssh_gateway_config[:keys]
164
+
165
+ # Use the keys specificed on the command line if available (overrides SSH Config)
166
+ if locate_config_value(:ssh_gateway_identity)
167
+ gateway_keys = Array(locate_config_value(:ssh_gateway_identity))
168
+ end
169
+
170
+ unless gateway_keys.nil?
171
+ gateway_options[:keys] = gateway_keys
172
+ end
173
+
174
+ Net::SSH::Gateway.new(gw_host, gw_user, gateway_options)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,31 @@
1
+ #
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ require 'chef/knife/cloud/chefbootstrap/bootstrap_distribution'
18
+
19
+ class Chef
20
+ class Knife
21
+ class Cloud
22
+ class UnixDistribution < BootstrapDistribution
23
+
24
+ def initialize(config)
25
+ super
26
+ config[:distro] = config[:distro] || "chef-full"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,32 @@
1
+ #
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ require 'chef/knife/cloud/chefbootstrap/bootstrap_distribution'
19
+ require 'chef/knife/bootstrap_windows_base'
20
+
21
+ class Chef
22
+ class Knife
23
+ class Cloud
24
+ class WindowsDistribution < BootstrapDistribution
25
+ def initialize(config)
26
+ super
27
+ config[:distro] ||= "windows-chef-client-msi"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,85 @@
1
+ # Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
2
+ # Author:: Prabhu Das (<prabhu.das@clogeny.com>)
3
+ #
4
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/knife/cloud/chefbootstrap/bootstrap_protocol'
21
+
22
+ class Chef
23
+ class Knife
24
+ class Cloud
25
+ class WinrmBootstrapProtocol < BootstrapProtocol
26
+
27
+ def initialize(config)
28
+ load_winrm_deps
29
+ @bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
30
+ super
31
+ end
32
+
33
+ def load_winrm_deps
34
+ require 'winrm'
35
+ require 'em-winrm'
36
+ require 'chef/knife/bootstrap_windows_winrm'
37
+ require 'chef/knife/core/windows_bootstrap_context'
38
+ require 'chef/knife/winrm'
39
+ end
40
+
41
+ def init_bootstrap_options
42
+ bootstrap.config[:winrm_user] = @config[:winrm_user] || 'Administrator'
43
+ bootstrap.config[:winrm_password] = @config[:winrm_password]
44
+ bootstrap.config[:winrm_transport] = @config[:winrm_transport]
45
+ bootstrap.config[:winrm_port] = @config[:winrm_port]
46
+ bootstrap.config[:auth_timeout] = @config[:auth_timeout]
47
+ super
48
+ end
49
+
50
+ def wait_for_server_ready
51
+ print "\n#{ui.color("Waiting for winrm to host (#{@config[:bootstrap_ip_address]})", :magenta)}"
52
+ print(".") until tcp_test_winrm(@config[:bootstrap_ip_address], @config[:winrm_port]){
53
+ sleep @initial_sleep_delay ||= 10
54
+ puts("done")
55
+ }
56
+ end
57
+
58
+ def tcp_test_winrm(hostname, port)
59
+ tcp_socket = TCPSocket.new(hostname, port)
60
+ return true
61
+ rescue SocketError
62
+ sleep 2
63
+ false
64
+ rescue Errno::ETIMEDOUT
65
+ false
66
+ rescue Errno::EPERM
67
+ false
68
+ rescue Errno::ECONNREFUSED
69
+ sleep 2
70
+ false
71
+ rescue Errno::EHOSTUNREACH
72
+ sleep 2
73
+ false
74
+ rescue Errno::ENETUNREACH
75
+ sleep 2
76
+ false
77
+ ensure
78
+ tcp_socket && tcp_socket.close
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
85
+