From 00278cf57aadc96e3d0e0087a44b37c4b76f6966 Mon Sep 17 00:00:00 2001 From: Aaron Suggs Date: Mon, 9 May 2011 18:28:54 -0400 Subject: [PATCH] [compute|aws] Add get_password_data request. This request only applies to MS Windows instances, so use an MS Win AMI in the instance tests. Relaxes the parser formats flexible to make tests less brittle to other instances. Depends on #302 --- lib/fog/compute/aws.rb | 1 + .../compute/parsers/aws/get_password_data.rb | 26 +++++++ .../compute/requests/aws/get_password_data.rb | 42 +++++++++++ tests/compute/requests/aws/instance_tests.rb | 75 ++++++++++++++----- 4 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 lib/fog/compute/parsers/aws/get_password_data.rb create mode 100644 lib/fog/compute/requests/aws/get_password_data.rb diff --git a/lib/fog/compute/aws.rb b/lib/fog/compute/aws.rb index 113d5aa3d..270de5b12 100644 --- a/lib/fog/compute/aws.rb +++ b/lib/fog/compute/aws.rb @@ -58,6 +58,7 @@ module Fog request :detach_volume request :disassociate_address request :get_console_output + request :get_password_data request :import_key_pair request :modify_image_attributes request :modify_snapshot_attribute diff --git a/lib/fog/compute/parsers/aws/get_password_data.rb b/lib/fog/compute/parsers/aws/get_password_data.rb new file mode 100644 index 000000000..436a2eccd --- /dev/null +++ b/lib/fog/compute/parsers/aws/get_password_data.rb @@ -0,0 +1,26 @@ +module Fog + module Parsers + module AWS + module Compute + + class GetPasswordData < Fog::Parsers::Base + + def reset + @response = {} + end + + def end_element(name) + case name + when 'instanceId', 'requestId', 'passwordData' + @response[name] = @value + when 'timestamp' + @response[name] = Time.parse(@value) + end + end + + end + + end + end + end +end diff --git a/lib/fog/compute/requests/aws/get_password_data.rb b/lib/fog/compute/requests/aws/get_password_data.rb new file mode 100644 index 000000000..30ca950c6 --- /dev/null +++ b/lib/fog/compute/requests/aws/get_password_data.rb @@ -0,0 +1,42 @@ +module Fog + module AWS + class Compute + class Real + + require 'fog/compute/parsers/aws/get_password_data' + + # Retrieves the encrypted administrator password for an instance running Windows. + # + # ==== Parameters + # * instance_id<~String> - A Windows instance ID + # + # ==== Returns + # # * response<~Excon::Response>: + # * body<~Hash>: + # * 'instanceId'<~String> - Id of instance + # * 'passwordData'<~String> - The encrypted, base64-encoded password of the instance. + # * 'requestId'<~String> - Id of request + # * 'timestamp'<~Time> - Timestamp of last update to output + # + # See http://docs.amazonwebservices.com/AWSEC2/2010-08-31/APIReference/index.html?ApiReference-query-GetPasswordData.html + def get_password_data(instance_id) + request( + 'Action' => 'GetPasswordData', + 'InstanceId' => instance_id, + :idempotent => true, + :parser => Fog::Parsers::AWS::Compute::GetPasswordData.new + ) + end + + end + + class Mock + + def get_password_data(instance_id) + Fog::Mock.not_implemented + end + + end + end + end +end diff --git a/tests/compute/requests/aws/instance_tests.rb b/tests/compute/requests/aws/instance_tests.rb index 3c0c2ec08..6417fa98e 100644 --- a/tests/compute/requests/aws/instance_tests.rb +++ b/tests/compute/requests/aws/instance_tests.rb @@ -11,16 +11,16 @@ Shindo.tests('AWS::Compute | instance requests', ['aws']) do 'instanceState' => {'code' => Integer, 'name' => String}, 'instanceType' => String, # 'ipAddress' => String, - 'kernelId' => String, - # 'keyName' => String, + 'kernelId' => Fog::Nullable::String, + 'keyName' => Fog::Nullable::String, 'launchTime' => Time, 'monitoring' => {'state' => Fog::Boolean}, 'placement' => {'availabilityZone' => String}, 'privateDnsName' => NilClass, # 'privateIpAddress' => String, 'productCodes' => [], - 'ramdiskId' => String, - 'reason' => NilClass, + 'ramdiskId' => Fog::Nullable::String, + 'reason' => Fog::Nullable::String, # 'rootDeviceName' => String, 'rootDeviceType' => String, } @@ -38,12 +38,12 @@ Shindo.tests('AWS::Compute | instance requests', ['aws']) do 'groupSet' => [String], 'instancesSet' => [@instance_format.merge( 'architecture' => String, - 'dnsName' => String, - 'ipAddress' => String, - 'privateDnsName' => String, - 'privateIpAddress' => String, - 'stateReason' => {}, - 'tagSet' => {} + 'dnsName' => Fog::Nullable::String, + 'ipAddress' => Fog::Nullable::String, + 'privateDnsName' => Fog::Nullable::String, + 'privateIpAddress' => Fog::Nullable::String, + 'stateReason' => Hash, + 'tagSet' => Hash )], 'ownerId' => String, 'reservationId' => String @@ -58,6 +58,14 @@ Shindo.tests('AWS::Compute | instance requests', ['aws']) do 'timestamp' => Time } + @get_password_data_format = { + 'instanceId' => String, + 'passwordData' => String, + 'requestId' => String, + 'timestamp' => Time + } + + @terminate_instances_format = { 'instancesSet' => [{ 'currentState' => {'code' => Integer, 'name' => String}, @@ -70,19 +78,30 @@ Shindo.tests('AWS::Compute | instance requests', ['aws']) do tests('success') do @instance_id = nil + # Use a MS Windows AMI to test #get_password_data + @windows_ami = 'ami-ee926087' # Microsoft Windows Server 2008 R2 Base 64-bit - tests("#run_instances('#{GENTOO_AMI}', 1, 1)").formats(@run_instances_format) do - data = AWS[:compute].run_instances(GENTOO_AMI, 1, 1).body + # Create a keypair for decrypting the password + key_name = 'fog-test-key' + key = AWS.key_pairs.create(:name => key_name) + + tests("#run_instances").formats(@run_instances_format) do + data = AWS[:compute].run_instances(@windows_ami, 1, 1, 'InstanceType' => 't1.micro', 'KeyName' => key_name).body @instance_id = data['instancesSet'].first['instanceId'] data end - AWS[:compute].servers.get(@instance_id).wait_for { ready? } + server = AWS[:compute].servers.get(@instance_id) + while server.nil? do + # It may take a moment to get the server after launching it + sleep 0.1 + server = AWS[:compute].servers.get(@instance_id) + end + server.wait_for { ready? } - # The format changes depending on state of instance, so this would be brittle - # tests("#describe_instances").formats(@describe_instances_format) do - # AWS[:compute].describe_instances.body - # end + tests("#describe_instances").formats(@describe_instances_format) do + AWS[:compute].describe_instances.body + end # Launch another instance to test filters another_server = AWS[:compute].servers.create @@ -99,6 +118,24 @@ Shindo.tests('AWS::Compute | instance requests', ['aws']) do AWS[:compute].get_console_output(@instance_id).body end + tests("#get_password_data('#{@instance_id}')").formats(@get_password_data_format) do + pending if Fog.mock? + result = nil + Fog.wait_for do + result = AWS[:compute].get_password_data(@instance_id).body + !result['passwordData'].nil? + end + + tests("key can decrypt passwordData").returns(true) do + decoded_password = Base64.decode64(result['passwordData']) + pkey = OpenSSL::PKey::RSA.new(key.private_key) + String === pkey.private_decrypt(decoded_password) + end + result + end + + key.destroy + tests("#reboot_instances('#{@instance_id}')").formats(AWS::Compute::Formats::BASIC) do AWS[:compute].reboot_instances(@instance_id).body end @@ -115,6 +152,10 @@ Shindo.tests('AWS::Compute | instance requests', ['aws']) do AWS[:compute].get_console_output('i-00000000') end + tests("#get_password_data('i-00000000')").raises(Fog::AWS::Compute::NotFound) do + AWS[:compute].get_password_data('i-00000000') + end + tests("#reboot_instances('i-00000000')").raises(Fog::AWS::Compute::NotFound) do AWS[:compute].reboot_instances('i-00000000') end