nephophobia 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.autotest +29 -0
  2. data/.gitignore +2 -0
  3. data/.rvmrc +1 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +35 -0
  6. data/README.md +23 -0
  7. data/Rakefile +11 -0
  8. data/lib/aws.rb +51 -0
  9. data/lib/hashify.rb +29 -0
  10. data/lib/nephophobia.rb +30 -0
  11. data/lib/nephophobia/client.rb +73 -0
  12. data/lib/nephophobia/compute.rb +150 -0
  13. data/lib/nephophobia/image.rb +78 -0
  14. data/lib/nephophobia/project.rb +113 -0
  15. data/lib/nephophobia/role.rb +5 -0
  16. data/lib/nephophobia/user.rb +86 -0
  17. data/lib/nephophobia/version.rb +3 -0
  18. data/nephophobia.gemspec +30 -0
  19. data/test/fixtures/cassettes/compute_all.yml +28 -0
  20. data/test/fixtures/cassettes/compute_all_with_filter.yml +30 -0
  21. data/test/fixtures/cassettes/compute_all_with_string_into_int_error.yml +28 -0
  22. data/test/fixtures/cassettes/compute_create.yml +28 -0
  23. data/test/fixtures/cassettes/compute_create_with_optional_params.yml +28 -0
  24. data/test/fixtures/cassettes/compute_destroy.yml +28 -0
  25. data/test/fixtures/cassettes/compute_find.yml +28 -0
  26. data/test/fixtures/cassettes/compute_reboot.yml +28 -0
  27. data/test/fixtures/cassettes/compute_start.yml +30 -0
  28. data/test/fixtures/cassettes/compute_stop.yml +30 -0
  29. data/test/fixtures/cassettes/image_all.yml +28 -0
  30. data/test/fixtures/cassettes/image_all_with_filter.yml +28 -0
  31. data/test/fixtures/cassettes/image_all_with_string_into_int_error.yml +28 -0
  32. data/test/fixtures/cassettes/image_find.yml +28 -0
  33. data/test/fixtures/cassettes/project_add_member.yml +28 -0
  34. data/test/fixtures/cassettes/project_all.yml +28 -0
  35. data/test/fixtures/cassettes/project_all_with_string_into_int_error.yml +28 -0
  36. data/test/fixtures/cassettes/project_create.yml +28 -0
  37. data/test/fixtures/cassettes/project_destroy.yml +28 -0
  38. data/test/fixtures/cassettes/project_find.yml +28 -0
  39. data/test/fixtures/cassettes/project_members.yml +28 -0
  40. data/test/fixtures/cassettes/project_remove_member.yml +28 -0
  41. data/test/fixtures/cassettes/user_add_role.yml +28 -0
  42. data/test/fixtures/cassettes/user_create.yml +28 -0
  43. data/test/fixtures/cassettes/user_destroy.yml +28 -0
  44. data/test/fixtures/cassettes/user_find.yml +28 -0
  45. data/test/fixtures/cassettes/user_remove_role.yml +28 -0
  46. data/test/lib/aws_test.rb +22 -0
  47. data/test/lib/hashify_test.rb +15 -0
  48. data/test/lib/nephophobia/compute_test.rb +144 -0
  49. data/test/lib/nephophobia/image_test.rb +76 -0
  50. data/test/lib/nephophobia/project_test.rb +104 -0
  51. data/test/lib/nephophobia/user_test.rb +71 -0
  52. data/test/lib/nephophobia_test.rb +17 -0
  53. data/test/test_helper.rb +47 -0
  54. metadata +221 -0
@@ -0,0 +1,78 @@
1
+ module Nephophobia
2
+ class ImageData
3
+ attr_reader :architecture, :image_id, :image_location, :image_owner_id
4
+ attr_reader :image_type, :kernel_id, :is_public, :state
5
+
6
+ def initialize hash
7
+ @architecture = hash['architecture']
8
+ @id = hash['id']
9
+ @image_id = hash['imageId']
10
+ @image_location = hash['imageLocation']
11
+ @image_owner_id = hash['imageOwnerId']
12
+ @image_type = hash['imageType']
13
+ @is_public = hash['isPublic']
14
+ @kernel_id = hash['kernelId']
15
+ @state = hash['imageState']
16
+ end
17
+ end
18
+
19
+ class Image
20
+ def initialize client
21
+ @client = client
22
+ end
23
+
24
+ ##
25
+ # Returns information about AMIs, AKIs, and ARIs. Images returned include
26
+ # public images, private images that +@client+ owns, and private images
27
+ # owned by other AWS accounts but for which +@client+ has explicit launch
28
+ # permissions.
29
+ #
30
+ # +filter+: An optional Hash, intended for filtering.
31
+ # See the API Reference for further details.
32
+ # {
33
+ # "Filter.1.Name" => "instance-type",
34
+ # "Filter.1.Value.1" => "m1.small",
35
+ # "ExecutableBy.1" => "self",
36
+ # }
37
+
38
+ def all filter = {}
39
+ response = @client.action "DescribeImages", filter
40
+
41
+ Nephophobia.coerce(response.body['DescribeImagesResponse']['imagesSet']['item']).collect do |data|
42
+ ImageData.new data
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Returns information about the specified 'image_id'.
48
+ #
49
+ # +image_id+: A String representing the ID of the image.
50
+
51
+ def find image_id
52
+ filter = {
53
+ "ImageId.1" => image_id
54
+ }
55
+
56
+ response = @client.action "DescribeImages", filter
57
+
58
+ ImageData.new response.body['DescribeImagesResponse']['imagesSet']['item']
59
+ end
60
+
61
+ ##
62
+ # Return information about all public images.
63
+
64
+ def public
65
+ all.select do |image|
66
+ public? image
67
+ end
68
+ end
69
+
70
+ private
71
+ ##
72
+ # images which do not have a valid kernel_id are not runnable.
73
+
74
+ def public? image
75
+ image.is_public == "true" && image.kernel_id != "true"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,113 @@
1
+ module Nephophobia
2
+ class ProjectData
3
+ attr_reader :name, :manager_id, :description
4
+
5
+ def initialize hash
6
+ @name = hash['projectname']
7
+ @manager_id = hash['projectManagerId']
8
+ @description = hash['description']
9
+ end
10
+ end
11
+
12
+ class Project
13
+ def initialize client
14
+ @client = client
15
+ end
16
+
17
+ ##
18
+ # Adds the given 'user_name' to the specified "project_name".
19
+ # Returns a response to the state change.
20
+ #
21
+ # +user_name+: A String representing a nova user_name.
22
+ # +project_name+: A String representing a nova project_name name.
23
+
24
+ def add_member user_name, project_name
25
+ modify_membership user_name, "add", project_name
26
+ end
27
+
28
+ ##
29
+ # Returns information about all projects.
30
+
31
+ def all
32
+ response = @client.action "DescribeProjects", {}
33
+
34
+ Nephophobia.coerce(response.body['DescribeProjectsResponse']['projectSet']['item']).collect do |data|
35
+ ProjectData.new data
36
+ end
37
+ end
38
+
39
+ ##
40
+ # Creates the given 'project_name'.
41
+ # Returns a response to the state change.
42
+ #
43
+ # +user_name+: A String representing a nova user_name.
44
+ # +project_name+: A String representing a nova project name.
45
+
46
+ def create project_name, user_name
47
+ filter = {
48
+ "Name" => project_name,
49
+ "ManagerUser" => user_name
50
+ }
51
+
52
+ response = @client.action "RegisterProject", filter
53
+
54
+ ProjectData.new response.body['RegisterProjectResponse']
55
+ end
56
+
57
+ ##
58
+ # Removes the given 'project_name'.
59
+ # Returns a response to the state change.
60
+ #
61
+ # +project_name+: A String representing a nova project name.
62
+
63
+ def destroy project_name
64
+ response = @client.action "DeregisterProject", "Name" => project_name
65
+
66
+ ResponseData.new response.body['DeregisterProjectResponse']
67
+ end
68
+
69
+ ##
70
+ # Returns information about the given 'project_name'.
71
+ #
72
+ # +project_name+: A String representing a nova project name.
73
+
74
+ def find project_name
75
+ response = @client.action "DescribeProject", "Name" => project_name
76
+
77
+ ProjectData.new response.body['DescribeProjectResponse']
78
+ end
79
+
80
+ ##
81
+ # Returns information about all members of the given 'project_name'.
82
+
83
+ def members project_name
84
+ response = @client.action "DescribeProjectMembers", "Name" => project_name
85
+
86
+ response.body['DescribeProjectMembersResponse']['members']['item']
87
+ end
88
+
89
+ ##
90
+ # Removes the given 'user_name' from the specified "project_name".
91
+ # Returns a response to the state change.
92
+ #
93
+ # +user_name+: A String representing a nova user_name.
94
+ # +project_name+: A String representing a nova project_name name.
95
+
96
+ def remove_member user_name, project_name
97
+ modify_membership user_name, "remove", project_name
98
+ end
99
+
100
+ private
101
+ def modify_membership user_name, operation, project_name
102
+ params = {
103
+ "User" => user_name,
104
+ "Project" => project_name,
105
+ "Operation" => operation
106
+ }
107
+
108
+ response = @client.action "ModifyProjectMember", params
109
+
110
+ ResponseData.new response.body['ModifyProjectMemberResponse']
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,5 @@
1
+ module Nephophobia
2
+ class Role
3
+ DEFAULT = "sysadmin"
4
+ end
5
+ end
@@ -0,0 +1,86 @@
1
+ module Nephophobia
2
+ class UserData
3
+ attr_reader :accesskey, :username, :secretkey
4
+
5
+ def initialize hash
6
+ @accesskey = hash['accesskey']
7
+ @username = hash['username']
8
+ @secretkey = hash['secretkey']
9
+ end
10
+ end
11
+
12
+ class User
13
+ def initialize client
14
+ @client = client
15
+ end
16
+
17
+ ##
18
+ # Adds the given 'user_name' to the specified "project_name's" 'Role::DEFAULT'.
19
+ # Returns a response to the state change.
20
+ #
21
+ # +user_name+: A String representing a nova user_name.
22
+ # +project_name+: A String representing a nova project_name name.
23
+
24
+ def add_role user_name, project_name
25
+ modify_role user_name, "add", project_name
26
+ end
27
+
28
+ ##
29
+ # Creates the given 'user_name'.
30
+ # Returns a response to the state change.
31
+ #
32
+ # +user_name+: A String representing a nova user_name.
33
+
34
+ def create user_name
35
+ response = @client.action "RegisterUser", "Name" => user_name
36
+
37
+ UserData.new response.body['RegisterUserResponse']
38
+ end
39
+
40
+ ##
41
+ # Removes the given 'user_name'.
42
+ # Returns a response to the state change.
43
+ #
44
+ # +user_name+: A String representing a nova user_name.
45
+
46
+ def destroy user_name
47
+ response = @client.action "DeregisterUser", "Name" => user_name
48
+
49
+ ResponseData.new response.body['DeregisterUserResponse']
50
+ end
51
+
52
+ ##
53
+ # Returns information about the given 'user_name'.
54
+ #
55
+ # +user_name+: A String representing the user_name.
56
+
57
+ def find user_name
58
+ response = @client.action "DescribeUser", "Name" => user_name
59
+
60
+ UserData.new response.body['DescribeUserResponse']
61
+ end
62
+
63
+ ##
64
+ # Removes the given 'user_name' from the specified "project_name's" 'Role::DEFAULT'.
65
+ #
66
+ # +user_name+: A String representing a nova user_name.
67
+ # +project_name+: A String representing a nova project_name name.
68
+
69
+ def remove_role user_name, project_name
70
+ modify_role user_name, "remove", project_name
71
+ end
72
+
73
+ private
74
+ def modify_role user_name, operation, project_name
75
+ params = {
76
+ "User" => user_name,
77
+ "Role" => Role::DEFAULT,
78
+ "Operation" => operation
79
+ }
80
+
81
+ response = @client.action "ModifyUserRole", params
82
+
83
+ ResponseData.new response.body['ModifyUserRoleResponse']
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ module Nephophobia
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "nephophobia/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "nephophobia"
7
+ s.version = Nephophobia::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["John Dewey", "Josh Kleinpeter"]
10
+ s.email = ["jdewey@attinteractive.com", "jkleinpeter@attinteractive.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Bindings to EC2/OpenStack}
13
+ s.description = %q{This gem is a simple binding to the EC2 API. It has specific extensions to allow extra functionality provided by OpenStack.}
14
+
15
+ s.rubyforge_project = "nephophobia"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "hugs", "~> 2.5.0"
23
+
24
+ s.add_development_dependency "autotest-standalone"
25
+ s.add_development_dependency "fakeweb", "~> 1.3.0"
26
+ s.add_development_dependency "minitest", "~> 2.0.2"
27
+ s.add_development_dependency "nokogiri", "~> 1.4.4"
28
+ s.add_development_dependency "rake", "~> 0.8.7"
29
+ s.add_development_dependency "vcr", "1.5.0"
30
+ end
@@ -0,0 +1,28 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://10.1.170.32:8773/services/Cloud?AWSAccessKeyId=9c01b833-3047-4f2e-bb2a-5c8dc7c8ae9c%3Aproduction&Action=DescribeInstances&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=1999-12-31T19%3A59%3A59Z&Version=2010-11-15&Signature=WH%2BC76b336Lc35DuC%2Fk7f8UTkiKH0nl6rKYrSlzUqDM%3D
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/xml
10
+ connection:
11
+ - keep-alive
12
+ keep-alive:
13
+ - 30
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ content-type:
20
+ - text/xml
21
+ content-length:
22
+ - "1598"
23
+ date:
24
+ - Mon, 21 Feb 2011 20:09:55 GMT
25
+ connection:
26
+ - keep-alive
27
+ body: <?xml version="1.0" ?><DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/"><requestId>W6P62OURN04XF89JYL86</requestId><reservationSet><item><ownerId>production</ownerId><groupSet><item><groupId>default</groupId></item></groupSet><reservationId>r-6p9fdt2e</reservationId><instancesSet><item><displayDescription/><displayName>Server 199</displayName><keyName>None (production, e3ab3)</keyName><instanceId>i-000000c7</instanceId><instanceState><code>1</code><name>running</name></instanceState><publicDnsName/><imageId>ami-usc3oydl</imageId><productCodesSet/><privateDnsName>10.1.171.8</privateDnsName><dnsName>10.1.171.8</dnsName><launchTime>2011-02-21 17:54:35</launchTime><placement><availabilityZone>nova</availabilityZone></placement><amiLaunchIndex>0</amiLaunchIndex><instanceType>m1.small</instanceType></item></instancesSet></item><item><ownerId>jtran</ownerId><groupSet><item><groupId>default</groupId></item></groupSet><reservationId>r-5oexkoz1</reservationId><instancesSet><item><displayDescription/><displayName>Server 198</displayName><keyName>None (jtran, cm-02)</keyName><instanceId>i-000000c6</instanceId><instanceState><code>1</code><name>running</name></instanceState><publicDnsName/><imageId>ami-usc3oydl</imageId><productCodesSet/><privateDnsName>10.1.173.17</privateDnsName><dnsName>10.1.173.17</dnsName><launchTime>2011-02-20 07:17:03</launchTime><placement><availabilityZone>nova</availabilityZone></placement><amiLaunchIndex>0</amiLaunchIndex><instanceType>m1.small</instanceType></item></instancesSet></item></reservationSet></DescribeInstancesResponse>
28
+ http_version: "1.1"
@@ -0,0 +1,30 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://10.1.170.32:8773/services/Cloud?AWSAccessKeyId=9c01b833-3047-4f2e-bb2a-5c8dc7c8ae9c%3Aproduction&Action=DescribeInstances&Filter.1.Name=instance-type&Filter.1.Value.1=m1.small&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=1999-12-31T19%3A59%3A59Z&Version=2010-11-15&Signature=A%2Foo6aKfI7sbuEdwy8TCgZQq9TPUgu%2BEgrwliuiygZ0%3D
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/xml
10
+ connection:
11
+ - keep-alive
12
+ keep-alive:
13
+ - 30
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 400
17
+ message: Bad Request
18
+ headers:
19
+ content-type:
20
+ - text/xml
21
+ content-length:
22
+ - "223"
23
+ date:
24
+ - Sun, 27 Feb 2011 05:55:55 GMT
25
+ connection:
26
+ - keep-alive
27
+ body: |-
28
+ <?xml version="1.0"?>
29
+ <Response><Errors><Error><Code>UnknownError</Code><Message>An unknown error has occurred. Please try your request again.</Message></Error></Errors><RequestID>XPM759MGOM2Y8IHPY5T5</RequestID></Response>
30
+ http_version: "1.1"
@@ -0,0 +1,28 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://10.1.170.32:8773/services/Cloud?AWSAccessKeyId=9c01b833-3047-4f2e-bb2a-5c8dc7c8ae9c%3Aproduction&Action=DescribeInstances&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=1999-12-31T19%3A59%3A59Z&Version=2010-11-15&Signature=WH%2BC76b336Lc35DuC%2Fk7f8UTkiKH0nl6rKYrSlzUqDM%3D
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/xml
10
+ connection:
11
+ - keep-alive
12
+ keep-alive:
13
+ - 30
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ content-type:
20
+ - text/xml
21
+ content-length:
22
+ - "871"
23
+ date:
24
+ - Fri, 04 Mar 2011 01:56:26 GMT
25
+ connection:
26
+ - keep-alive
27
+ body: <?xml version="1.0" ?><DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/"><requestId>8L9E--E0D-DACB097WCL</requestId><reservationSet><item><ownerId>production</ownerId><groupSet><item><groupId>default</groupId></item></groupSet><reservationId>r-g3b3ggz0</reservationId><instancesSet><item><displayDescription/><displayName>Server 260</displayName><keyName/><instanceId>i-00000104</instanceId><instanceState><code>1</code><name>running</name></instanceState><publicDnsName/><imageId>ami-srgo1p2s</imageId><productCodesSet/><privateDnsName>10.3.172.8</privateDnsName><dnsName>10.3.172.8</dnsName><launchTime>2011-02-25 17:50:23</launchTime><placement><availabilityZone>nova</availabilityZone></placement><amiLaunchIndex>0</amiLaunchIndex><instanceType>m1.small</instanceType></item></instancesSet></item></reservationSet></DescribeInstancesResponse>
28
+ http_version: "1.1"
@@ -0,0 +1,28 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://10.1.170.32:8773/services/Cloud?AWSAccessKeyId=9c01b833-3047-4f2e-bb2a-5c8dc7c8ae9c%3Aproduction&Action=RunInstances&ImageId=ami-usc3oydl&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=1999-12-31T19%3A59%3A59Z&Version=2010-11-15&Signature=Pj%2Bk1BhY5X1256%2Bu8lMPvPdoxkDsm0bJPXqF2PGUzwY%3D
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/xml
10
+ connection:
11
+ - keep-alive
12
+ keep-alive:
13
+ - 30
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ content-type:
20
+ - text/xml
21
+ content-length:
22
+ - "807"
23
+ date:
24
+ - Sun, 27 Feb 2011 05:55:56 GMT
25
+ connection:
26
+ - keep-alive
27
+ body: <?xml version="1.0" ?><RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/"><requestId>ECX3QKATTRPYC9NNJG1M</requestId><ownerId>production</ownerId><groupSet><item><groupId>default</groupId></item></groupSet><reservationId>r-6l687lh5</reservationId><instancesSet><item><displayDescription/><displayName>Server 1145</displayName><keyName>None (production, None)</keyName><instanceId>i-00000479</instanceId><instanceState><code/><name>scheduling</name></instanceState><publicDnsName/><imageId>ami-usc3oydl</imageId><productCodesSet/><privateDnsName/><dnsName/><launchTime>2011-02-27 05:55:56</launchTime><placement><availabilityZone>unknown zone</availabilityZone></placement><amiLaunchIndex>0</amiLaunchIndex><instanceType>m1.small</instanceType></item></instancesSet></RunInstancesResponse>
28
+ http_version: "1.1"
@@ -0,0 +1,28 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :get
5
+ uri: http://10.1.170.32:8773/services/Cloud?AWSAccessKeyId=9c01b833-3047-4f2e-bb2a-5c8dc7c8ae9c%3Aproduction&Action=RunInstances&DisplayDescription=test%20description&DisplayName=testserver1&ImageId=ami-usc3oydl&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=1999-12-31T19%3A59%3A59Z&Version=2010-11-15&Signature=zCOhKyLotYPqEmkGUsSh387A10CDB4ySLuuM2ZIhRbQ%3D
6
+ body:
7
+ headers:
8
+ accept:
9
+ - application/xml
10
+ connection:
11
+ - keep-alive
12
+ keep-alive:
13
+ - 30
14
+ response: !ruby/struct:VCR::Response
15
+ status: !ruby/struct:VCR::ResponseStatus
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ content-type:
20
+ - text/xml
21
+ content-length:
22
+ - "843"
23
+ date:
24
+ - Fri, 04 Mar 2011 17:29:48 GMT
25
+ connection:
26
+ - keep-alive
27
+ body: <?xml version="1.0" ?><RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2010-11-15/"><requestId>8SZ3U7WY7ZSI70GT5X9-</requestId><ownerId>production</ownerId><groupSet><item><groupId>default</groupId></item></groupSet><reservationId>r-hmlklbap</reservationId><instancesSet><item><displayDescription>test description</displayDescription><displayName>testserver1</displayName><keyName>None (production, None)</keyName><instanceId>i-0000048f</instanceId><instanceState><code/><name>scheduling</name></instanceState><publicDnsName/><imageId>ami-usc3oydl</imageId><productCodesSet/><privateDnsName/><dnsName/><launchTime>2011-03-04 17:29:48</launchTime><placement><availabilityZone>unknown zone</availabilityZone></placement><amiLaunchIndex>0</amiLaunchIndex><instanceType>m1.small</instanceType></item></instancesSet></RunInstancesResponse>
28
+ http_version: "1.1"