lib/kitchen/driver/ec2.rb in kitchen-ec2-0.9.5 vs lib/kitchen/driver/ec2.rb in kitchen-ec2-0.10.0.rc.0

- old
+ new

@@ -44,11 +44,15 @@ default_config :flavor_id, nil default_config :instance_type, nil default_config :ebs_optimized, false default_config :security_group_ids, nil default_config :tags, "created-by" => "test-kitchen" - default_config :user_data, nil + default_config :user_data do |driver| + if driver.windows_os? + driver.default_windows_user_data + end + end default_config :private_ip_address, nil default_config :iam_profile_name, nil default_config :price, nil default_config :retryable_tries, 60 default_config :retryable_sleep, 5 @@ -198,10 +202,18 @@ state[:server_id] = server.id info("EC2 instance <#{state[:server_id]}> created.") wait_until_ready(server, state) + if windows_os? && + instance.transport[:username] =~ /administrator/i && + instance.transport[:password].nil? + # If we're logging into the administrator user and a password isn't + # supplied, try to fetch it from the AWS instance + fetch_windows_admin_password(server, state) + end + info("EC2 instance <#{state[:server_id]}> ready.") instance.transport.connection(state).wait_until_ready create_ec2_json(state) debug("ec2:create '#{state[:hostname]}'") end @@ -320,16 +332,40 @@ hostname = hostname(aws_instance, config[:interface]) # We aggressively store the hostname so if the process fails here # we still have it, even if it will change later state[:hostname] = hostname # Euca instances often report ready before they have an IP - aws_instance.exists? && + ready = aws_instance.exists? && aws_instance.state.name == "running" && hostname != "0.0.0.0" + if ready && windows_os? + output = server.console_output.output + unless output.nil? + output = Base64.decode64(output) + debug "Console output: --- \n#{output}" + end + ready = !!(output =~ /Windows is Ready to use/) + end + ready end end + # rubocop:disable Lint/UnusedBlockArgument + def fetch_windows_admin_password(server, state) + wait_with_destroy(server, state, "to fetch windows admin password") do |aws_instance| + enc = server.client.get_password_data( + :instance_id => state[:server_id] + ).password_data + # Password data is blank until password is available + !enc.nil? && !enc.empty? + end + pass = server.decrypt_windows_password(instance.transport[:ssh_key]) + state[:password] = pass + info("Retrieved Windows password for instance <#{state[:server_id]}>.") + end + # rubocop:enable Lint/UnusedBlockArgument + def wait_with_destroy(server, state, status_msg, &block) wait_log = proc do |attempts| c = attempts * config[:retryable_sleep] t = config[:retryable_tries] * config[:retryable_sleep] info "Waited #{c}/#{t}s for instance <#{state[:server_id]}> #{status_msg}." @@ -389,13 +425,59 @@ potential_hostname end end def create_ec2_json(state) - instance.transport.connection(state).execute( - "sudo mkdir -p /etc/chef/ohai/hints;sudo touch /etc/chef/ohai/hints/ec2.json" - ) + if windows_os? + cmd = "mkdir \\etc\\chef\\ohai\\hints; echo $null >> \\etc\\chef\\ohai\\hints\\ec2.json" + else + cmd = "sudo mkdir -p /etc/chef/ohai/hints;sudo touch /etc/chef/ohai/hints/ec2.json" + end + instance.transport.connection(state).execute(cmd) end + + # rubocop:disable Metrics/MethodLength, Metrics/LineLength + def default_windows_user_data + # Preparing custom static admin user if we defined something other than Administrator + custom_admin_script = "" + if !(instance.transport[:username] =~ /administrator/i) && instance.transport[:password] + custom_admin_script = Kitchen::Util.outdent!(<<-EOH) + "Disabling Complex Passwords" >> $logfile + $seccfg = [IO.Path]::GetTempFileName() + & secedit.exe /export /cfg $seccfg >> $logfile + (Get-Content $seccfg) | Foreach-Object {$_ -replace "PasswordComplexity\\s*=\\s*1", "PasswordComplexity = 0"} | Set-Content $seccfg + & secedit.exe /configure /db $env:windir\\security\\new.sdb /cfg $seccfg /areas SECURITYPOLICY >> $logfile + & cp $seccfg "c:\\" + & del $seccfg + $username="#{instance.transport[:username]}" + $password="#{instance.transport[:password]}" + "Creating static user: $username" >> $logfile + & net.exe user /y /add $username $password >> $logfile + "Adding $username to Administrators" >> $logfile + & net.exe localgroup Administrators /add $username >> $logfile + EOH + end + + # Returning the fully constructed PowerShell script to user_data + Kitchen::Util.outdent!(<<-EOH) + <powershell> + $logfile="C:\\Program Files\\Amazon\\Ec2ConfigService\\Logs\\kitchen-ec2.log" + #PS Remoting and & winrm.cmd basic config + Enable-PSRemoting -Force -SkipNetworkProfileCheck + & winrm.cmd set winrm/config '@{MaxTimeoutms="1800000"}' >> $logfile + & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile + & winrm.cmd set winrm/config/winrs '@{MaxShellsPerUser="50"}' >> $logfile + #Server settings - support username/password login + & winrm.cmd set winrm/config/service/auth '@{Basic="true"}' >> $logfile + & winrm.cmd set winrm/config/service '@{AllowUnencrypted="true"}' >> $logfile + & winrm.cmd set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}' >> $logfile + #Firewall Config + & netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 remoteip=localsubnet new remoteip=any >> $logfile + #{custom_admin_script} + </powershell> + EOH + end + # rubocop:enable Metrics/MethodLength, Metrics/LineLength end end end