knife-google 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/.gitignore +22 -0
  2. data/CONTRIB.md +64 -0
  3. data/Gemfile +11 -0
  4. data/README.md +287 -0
  5. data/Rakefile +53 -0
  6. data/knife-google.gemspec +26 -0
  7. data/lib/chef/knife/google_base.rb +39 -68
  8. data/lib/chef/knife/google_disk_create.rb +60 -0
  9. data/lib/chef/knife/google_disk_delete.rb +60 -0
  10. data/lib/chef/knife/google_disk_list.rb +75 -0
  11. data/lib/chef/knife/google_server_create.rb +273 -184
  12. data/lib/chef/knife/google_server_delete.rb +74 -32
  13. data/lib/chef/knife/google_server_list.rb +45 -64
  14. data/lib/chef/knife/google_setup.rb +31 -0
  15. data/lib/chef/knife/google_zone_list.rb +78 -0
  16. data/lib/google/compute.rb +46 -0
  17. data/lib/google/compute/client.rb +188 -0
  18. data/lib/google/compute/config.rb +23 -0
  19. data/lib/google/compute/creatable_resource_collection.rb +38 -0
  20. data/lib/google/compute/deletable_resource_collection.rb +51 -0
  21. data/lib/google/compute/disk.rb +40 -0
  22. data/lib/google/compute/exception.rb +28 -0
  23. data/lib/google/compute/firewall.rb +65 -0
  24. data/lib/google/compute/global_operation.rb +60 -0
  25. data/lib/google/compute/image.rb +30 -0
  26. data/lib/google/compute/kernel.rb +20 -0
  27. data/lib/google/compute/listable_resource_collection.rb +33 -0
  28. data/lib/google/compute/machine_type.rb +36 -0
  29. data/lib/google/compute/mixins/utils.rb +58 -0
  30. data/lib/google/compute/network.rb +29 -0
  31. data/lib/google/compute/project.rb +76 -0
  32. data/lib/google/compute/resource.rb +81 -0
  33. data/lib/google/compute/resource_collection.rb +78 -0
  34. data/lib/google/compute/server.rb +87 -0
  35. data/lib/google/compute/server/attached_disk.rb +39 -0
  36. data/lib/google/compute/server/network_interface.rb +38 -0
  37. data/lib/google/compute/server/network_interface/access_config.rb +35 -0
  38. data/lib/google/compute/server/serial_port_output.rb +31 -0
  39. data/lib/google/compute/snapshot.rb +30 -0
  40. data/lib/google/compute/version.rb +19 -0
  41. data/lib/google/compute/zone.rb +32 -0
  42. data/lib/google/compute/zone_operation.rb +60 -0
  43. data/lib/knife-google/version.rb +18 -2
  44. data/spec/chef/knife/google_base_spec.rb +46 -0
  45. data/spec/chef/knife/google_disk_create_spec.rb +36 -0
  46. data/spec/chef/knife/google_disk_delete_spec.rb +65 -0
  47. data/spec/chef/knife/google_disk_list_spec.rb +36 -0
  48. data/spec/chef/knife/google_server_create_spec.rb +84 -0
  49. data/spec/chef/knife/google_server_delete_spec.rb +105 -0
  50. data/spec/chef/knife/google_server_list_spec.rb +39 -0
  51. data/spec/chef/knife/google_setup_spec.rb +25 -0
  52. data/spec/chef/knife/google_zone_list_spec.rb +32 -0
  53. data/spec/data/client.json +14 -0
  54. data/spec/data/compute-v1beta14.json +3386 -0
  55. data/spec/data/disk.json +15 -0
  56. data/spec/data/firewall.json +13 -0
  57. data/spec/data/global_operation.json +36 -0
  58. data/spec/data/image.json +12 -0
  59. data/spec/data/kernel.json +15 -0
  60. data/spec/data/machine_type.json +24 -0
  61. data/spec/data/network.json +10 -0
  62. data/spec/data/project.json +21 -0
  63. data/spec/data/serial_port_output.json +5 -0
  64. data/spec/data/server.json +46 -0
  65. data/spec/data/snapshot.json +12 -0
  66. data/spec/data/zone.json +30 -0
  67. data/spec/data/zone_operation.json +36 -0
  68. data/spec/google/compute/disk_spec.rb +105 -0
  69. data/spec/google/compute/firewall_spec.rb +128 -0
  70. data/spec/google/compute/global_operation_spec.rb +62 -0
  71. data/spec/google/compute/image_spec.rb +75 -0
  72. data/spec/google/compute/kernel_spec.rb +49 -0
  73. data/spec/google/compute/machine_type_spec.rb +53 -0
  74. data/spec/google/compute/network_spec.rb +68 -0
  75. data/spec/google/compute/project_spec.rb +71 -0
  76. data/spec/google/compute/server_spec.rb +125 -0
  77. data/spec/google/compute/snapshot_spec.rb +69 -0
  78. data/spec/google/compute/zone_operation_spec.rb +62 -0
  79. data/spec/google/compute/zone_spec.rb +50 -0
  80. data/spec/spec_helper.rb +44 -0
  81. data/spec/support/mocks.rb +62 -0
  82. data/spec/support/resource_examples.rb +70 -0
  83. data/spec/support/spec_google_base.rb +56 -0
  84. metadata +121 -31
  85. data/README.rdoc +0 -96
@@ -1,23 +1,16 @@
1
- #
2
- # Author:: Chirag Jog (<chiragj@websym.com>)
3
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
4
- # License:: Apache License, Version 2.0
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
5
2
  #
6
3
  # Licensed under the Apache License, Version 2.0 (the "License");
7
4
  # you may not use this file except in compliance with the License.
8
5
  # You may obtain a copy of the License at
9
- #
6
+ #
10
7
  # http://www.apache.org/licenses/LICENSE-2.0
11
- #
8
+ #
12
9
  # Unless required by applicable law or agreed to in writing, software
13
10
  # distributed under the License is distributed on an "AS IS" BASIS,
14
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
12
  # See the License for the specific language governing permissions and
16
13
  # limitations under the License.
17
- #
18
-
19
- require 'chef/knife'
20
- require 'chef/json_compat'
21
14
 
22
15
  require 'chef/knife/google_base'
23
16
 
@@ -26,34 +19,83 @@ class Chef
26
19
  class GoogleServerDelete < Knife
27
20
 
28
21
  include Knife::GoogleBase
29
- banner "knife google server delete SERVER (options)"
30
22
 
31
- option :project_id,
32
- :short => "-p PROJECTNAME",
33
- :long => "--project_id PROJECTNAME",
34
- :description => "Your Google Compute Project Name",
35
- :proc => Proc.new { |project| Chef::Config[:knife][:google_project] = project }
23
+ deps do
24
+ require 'google/compute'
25
+ end
26
+
27
+ banner "knife google server delete SERVER [SERVER] --google-compute-zone ZONE (options)"
28
+
29
+ attr_reader :instances
30
+
31
+ option :zone,
32
+ :short => "-Z ZONE",
33
+ :long => "--google-compute-zone ZONE",
34
+ :description => "The Zone for this server",
35
+ :required => true
36
36
 
37
- def run
38
- unless Chef::Config[:knife][:google_project]
39
- ui.error("Project ID is a compulsory parameter")
37
+ option :purge,
38
+ :short => "-P",
39
+ :long => "--purge",
40
+ :boolean => true,
41
+ :default => false,
42
+ :description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the GCE server itself. Assumes node and client have the same name as the server (if not, add the '--node-name' option)."
43
+
44
+ option :chef_node_name,
45
+ :short => "-N NAME",
46
+ :long => "--node-name NAME",
47
+ :description => "The name of the node and client to delete, if it differs from the server name. Only has meaning when used with the '--purge' option."
48
+
49
+ # Taken from knife-ec2 plugin, for rational , check the following link
50
+ # https://github.com/opscode/knife-ec2/blob/master/lib/chef/knife/ec2_server_delete.rb#L48
51
+ def destroy_item(klass, name, type_name)
52
+ begin
53
+ object = klass.load(name)
54
+ object.destroy
55
+ ui.warn("Deleted #{type_name} #{name}")
56
+ rescue Net::HTTPServerException
57
+ ui.warn("Could not find a #{type_name} named #{name} to delete!")
58
+ end
59
+ end
60
+
61
+ def run
62
+ begin
63
+ zone = client.zones.get(config[:zone]).self_link
64
+ rescue Google::Compute::ResourceNotFound
65
+ ui.error("Zone '#{config[:zone]}' not found")
40
66
  exit 1
41
67
  end
42
68
 
43
- $stdout.sync = true
44
- project_id = Chef::Config[:knife][:google_project]
45
- validate_project(project_id)
46
-
47
- @name_args.each do |server|
48
- confirm("Do you really want to delete the server - #{server} ?")
49
- del_instance = exec_shell_cmd("#{@gcompute} deleteinstance #{server} --print_json --project_id=#{project_id} -f")
50
- Chef::Log.debug 'Executing ' + del_instance.command
51
-
52
- if not del_instance.stderr.downcase.scan("error").empty?
53
- ui.error("Failed to delete server. Error: #{error}")
54
- exit 1
69
+ @instances = []
70
+ @name_args.each do |instance_name|
71
+ begin
72
+ instance = client.instances.get(:name=>instance_name, :zone=>selflink2name(zone))
73
+ @instances << instance
74
+ msg_pair("Name", instance.name)
75
+ msg_pair("MachineType", selflink2name(instance.machine_type))
76
+ msg_pair("Image", selflink2name(instance.image))
77
+ msg_pair("Zone", selflink2name(instance.zone))
78
+ msg_pair("Tags", instance.tags.has_key?("items") ? instance.tags["items"].join(',') : "None")
79
+ msg_pair("Public IP Address", public_ips(instance).join(','))
80
+ msg_pair("Private IP Address", private_ips(instance).join(','))
81
+
82
+ puts "\n"
83
+ ui.confirm("Do you really want to delete server '#{selflink2name(zone)}:#{instance.name}'")
84
+
85
+ client.instances.delete(:instance=>instance.name, :zone=>selflink2name(zone))
86
+
87
+ ui.warn("Deleted server '#{selflink2name(zone)}:#{instance.name}'")
88
+
89
+ if config[:purge]
90
+ thing_to_delete = config[:chef_node_name] || instance.name
91
+ destroy_item(Chef::Node, thing_to_delete, "node")
92
+ destroy_item(Chef::ApiClient, thing_to_delete, "client")
93
+ else
94
+ ui.warn("Corresponding node and client for the #{instance.name} server were not deleted and remain registered with the Chef Server")
95
+ end
96
+ rescue
97
+ ui.error("Could not locate server '#{selflink2name(zone)}:#{instance_name}'.")
55
98
  end
56
- ui.warn("Deleted server #{server}")
57
99
  end
58
100
  end
59
101
  end
@@ -1,26 +1,17 @@
1
- # Author:: Chirag Jog (<chiragj@websym.com>)
2
- # Copyright:: Copyright (c) 2012 Opscode, Inc.
3
- # License:: Apache License, Version 2.0
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
4
2
  #
5
3
  # Licensed under the Apache License, Version 2.0 (the "License");
6
4
  # you may not use this file except in compliance with the License.
7
5
  # You may obtain a copy of the License at
8
- #
6
+ #
9
7
  # http://www.apache.org/licenses/LICENSE-2.0
10
- #
8
+ #
11
9
  # Unless required by applicable law or agreed to in writing, software
12
10
  # distributed under the License is distributed on an "AS IS" BASIS,
13
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
12
  # See the License for the specific language governing permissions and
15
13
  # limitations under the License.
16
-
17
- require 'stringio'
18
- require 'yajl'
19
- require 'highline'
20
- require 'chef/knife'
21
- require 'chef/json_compat'
22
- require 'tempfile'
23
-
14
+ #
24
15
  require 'chef/knife/google_base'
25
16
 
26
17
  class Chef
@@ -29,67 +20,57 @@ class Chef
29
20
 
30
21
  include Knife::GoogleBase
31
22
 
32
- banner "knife google server list (options)"
33
-
34
- option :project_id,
35
- :short => "-p PROJECTNAME",
36
- :long => "--project_id PROJECTNAME",
37
- :description => "Your Google Compute Project Name",
38
- :proc => Proc.new { |project| Chef::Config[:knife][:google_project] = project }
23
+ banner "knife google server list --google-compute-zone ZONE (options)"
39
24
 
40
- def h
41
- @highline ||= HighLine.new
42
- end
25
+ option :zone,
26
+ :short => "-Z ZONE",
27
+ :long => "--google-compute-zone ZONE",
28
+ :description => "The Zone for this server",
29
+ :required => true
43
30
 
44
31
  def run
45
- unless Chef::Config[:knife][:google_project]
46
- ui.error("Project ID is a compulsory parameter")
47
- exit 1
48
- end
49
32
  $stdout.sync = true
50
33
 
51
- project_id = Chef::Config[:knife][:google_project]
52
- validate_project(project_id)
53
- list_instances = exec_shell_cmd("#{@gcompute} listinstances --print_json --project_id=#{project_id}")
54
- Chef::Log.debug 'Executing ' + list_instances.command
55
- list_instances.run_command
56
-
57
- if not list_instances.stderr.downcase.scan("error").empty?
58
- ui.error("Failed to list instances. Error: #{error}")
34
+ begin
35
+ zone = client.zones.get(config[:zone])
36
+ rescue Google::Compute::ResourceNotFound
37
+ ui.error("Zone '#{config[:zone]}' not found")
59
38
  exit 1
60
39
  end
61
- instances_json = to_json(list_instances.stdout)
62
-
63
- server_list = [
64
- h.color('ID', :bold),
65
- h.color('Name', :bold),
66
- h.color('PublicIP', :bold),
67
- h.color('PrivateIP', :bold),
68
- h.color('OperatingSystem', :bold)
69
-
70
- ]
71
-
72
- if not instances_json.has_key?("items")
73
- exit 0
74
- end
75
40
 
76
- instances_json["items"].each do |item|
77
- server_list << item["id"]
78
- server_list << item["name"].split("/").last
79
- private_ip = []
80
- public_ip = []
81
- item["networkInterfaces"].each do |interface|
82
- private_ip << interface["networkIP"]
83
- interface["accessConfigs"].select { |cfg| public_ip << cfg["natIP"] }
41
+ instance_list = [
42
+ ui.color("Name", :bold),
43
+ ui.color('Type', :bold),
44
+ ui.color('Image', :bold),
45
+ ui.color('Public IP', :bold),
46
+ ui.color('Private IP', :bold),
47
+ ui.color('Disks', :bold),
48
+ ui.color("Zone", :bold),
49
+ ui.color('Status', :bold)].flatten.compact
50
+
51
+ output_column_count = instance_list.length
52
+
53
+ client.instances.list(:zone=>zone.name).each do |instance|
54
+ instance_list << instance.name
55
+ instance_list << selflink2name(instance.machine_type.to_s)
56
+ instance_list << selflink2name(instance.image.to_s)
57
+ instance_list << public_ips(instance).join(',')
58
+ instance_list << private_ips(instance).join(',')
59
+ instance_list << disks(instance).join(',')
60
+ instance_list << selflink2name(instance.zone.to_s)
61
+ instance_list << begin
62
+ status = instance.status.downcase
63
+ case status
64
+ when 'stopping', 'stopped', 'terminated'
65
+ ui.color(status, :red)
66
+ when 'requested', 'provisioning', 'staging'
67
+ ui.color(status, :yellow)
68
+ else
69
+ ui.color(status, :green)
70
+ end
84
71
  end
85
-
86
- server_list << public_ip.join(",")
87
- server_list << private_ip.join(",")
88
- server_list << item["image"].split("/").last
89
72
  end
90
-
91
- puts h.list(server_list, :columns_across, 5)
92
-
73
+ puts ui.list(instance_list, :uneven_columns_across, output_column_count)
93
74
  end
94
75
  end
95
76
  end
@@ -0,0 +1,31 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ require 'chef/knife/google_base'
16
+
17
+ class Chef
18
+ class Knife
19
+ class GoogleSetup < Knife
20
+
21
+ include Knife::GoogleBase
22
+
23
+ banner "knife google setup"
24
+
25
+ def run
26
+ Google::Compute::Client.setup
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,78 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ require 'chef/knife/google_base'
16
+ require 'time'
17
+
18
+ class Chef
19
+ class Knife
20
+ class GoogleZoneList < Knife
21
+
22
+ include Knife::GoogleBase
23
+
24
+ banner "knife google zone list (options)"
25
+
26
+ def run
27
+ $stdout.sync = true
28
+
29
+ zone_list = [
30
+ ui.color("Name", :bold),
31
+ ui.color('Status', :bold),
32
+ ui.color('Servers', :bold),
33
+ ui.color('Disks', :bold),
34
+ ui.color('Maintainance Window',:bold)].flatten.compact
35
+
36
+ output_column_count = zone_list.length
37
+
38
+ client.zones.list.each do |zone|
39
+ zone_list << zone.name
40
+ zone_list << begin
41
+ status = zone.status.downcase
42
+ case status
43
+ when 'up'
44
+ ui.color(status, :green)
45
+ else
46
+ ui.color(status, :red)
47
+ end
48
+ end
49
+ instance_quota = "0"
50
+ zone.quotas.each do |quota|
51
+ if quota["metric"] == "INSTANCES"
52
+ instance_quota = "#{quota["usage"].to_i}"
53
+ end
54
+ end
55
+ zone_list << instance_quota
56
+ disk_quota = "0"
57
+ zone.quotas.each do |quota|
58
+ if quota["metric"] == "DISKS"
59
+ disk_quota = "#{quota["usage"].to_i}"
60
+ end
61
+ end
62
+ zone_list << disk_quota
63
+ maintenance_window = zone.maintenance_windows.map do |mw|
64
+ begin_time = Time.parse(mw["beginTime"])
65
+ end_time = Time.parse(mw["endTime"])
66
+ if (Time.now >= begin_time) and (Time.now <= end_time)
67
+ ui.color("#{begin_time} to #{end_time}",:red)
68
+ else
69
+ ui.color("#{begin_time} to #{end_time}",:green)
70
+ end
71
+ end.join(",")
72
+ zone_list << maintenance_window
73
+ end
74
+ ui.info(ui.list(zone_list, :uneven_columns_across, output_column_count))
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Copyright 2013 Google Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless autoload :d by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Google
18
+ module Compute
19
+ end
20
+ end
21
+
22
+ require 'google/compute/version'
23
+ require 'google/compute/config'
24
+ require 'google/compute/resource_collection'
25
+ require 'google/compute/listable_resource_collection'
26
+ require 'google/compute/deletable_resource_collection'
27
+ require 'google/compute/creatable_resource_collection'
28
+ require 'google/compute/resource'
29
+ require 'google/compute/client'
30
+ require 'google/compute/exception'
31
+ require 'google/compute/disk'
32
+ require 'google/compute/firewall'
33
+ require 'google/compute/image'
34
+ require 'google/compute/server'
35
+ require 'google/compute/kernel'
36
+ require 'google/compute/machine_type'
37
+ require 'google/compute/network'
38
+ require 'google/compute/project'
39
+ require 'google/compute/snapshot'
40
+ require 'google/compute/zone'
41
+ require 'google/compute/global_operation'
42
+ require 'google/compute/zone_operation'
43
+ require 'google/compute/server/attached_disk'
44
+ require 'google/compute/server/network_interface'
45
+ require 'google/compute/server/serial_port_output'
46
+ require 'google/compute/server/network_interface/access_config'
@@ -0,0 +1,188 @@
1
+ # Copyright 2013 Google Inc. All Rights Reserved.
2
+ #
3
+ # Copyright 2013 Google Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'google/api_client'
18
+ require 'multi_json'
19
+ require 'google/compute/resource_collection'
20
+
21
+ module Google
22
+ module Compute
23
+ class Client
24
+
25
+ DEFAULT_FILE = '~/.google-compute.json'
26
+
27
+ attr_reader :dispatcher
28
+
29
+ def initialize(authorization, project, credential_file)
30
+ api_client = Google::APIClient.new(:application_name=>'google-compute-ruby-client')
31
+ api_client.authorization = authorization
32
+ api_client.auto_refresh_token = true
33
+ @project = project
34
+ @credential_file = credential_file
35
+ @dispatcher = APIDispatcher.new(:project=>project,:api_client=>api_client)
36
+ end
37
+
38
+ def self.from_json(filename = nil)
39
+ filename ||= File.expand_path(DEFAULT_FILE)
40
+ begin
41
+ credential_data = MultiJson.load(File.read(filename))
42
+ rescue
43
+ $stdout.print "Error reading CREDENTIAL_FILE, please run 'knife google setup'\n"
44
+ exit 1
45
+ end
46
+ authorization = Signet::OAuth2::Client.new(credential_data)
47
+ self.new(authorization, credential_data['project'], filename)
48
+ end
49
+
50
+ def self.setup
51
+ $stdout.print "Enter project ID (not name or number): "
52
+ project = $stdin.gets.chomp
53
+ $stdout.print "Enter client id: "
54
+ client_id = $stdin.gets.chomp
55
+ $stdout.print "Enter client secret: "
56
+ client_secret = $stdin.gets.chomp
57
+ authorization_uri = "https://accounts.google.com/o/oauth2/auth"
58
+ token_credential_uri ="https://accounts.google.com/o/oauth2/token"
59
+ scope = ["https://www.googleapis.com/auth/compute",
60
+ "https://www.googleapis.com/auth/compute.readonly",
61
+ "https://www.googleapis.com/auth/devstorage.full_control",
62
+ "https://www.googleapis.com/auth/devstorage.read_only",
63
+ "https://www.googleapis.com/auth/devstorage.read_write",
64
+ "https://www.googleapis.com/auth/devstorage.write_only",
65
+ "https://www.googleapis.com/auth/userinfo.email"]
66
+ redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
67
+
68
+ api_client = Google::APIClient.new(:application_name=>'google-compute-ruby-client')
69
+
70
+ api_client.authorization.scope = scope
71
+ api_client.authorization.client_id = client_id
72
+ api_client.authorization.client_secret = client_secret
73
+ api_client.authorization.redirect_uri = redirect_uri
74
+ $stdout.puts "Copy and paste the following url in your brower and allow access. Enter the resulting authorization code below.\n\n"
75
+ $stdout.puts api_client.authorization.authorization_uri
76
+ $stdout.print "\n\nAuthorization code: "
77
+ authorization_code = $stdin.gets.chomp
78
+ api_client.authorization.code = authorization_code
79
+ api_client.authorization.fetch_access_token!
80
+ access_token = api_client.authorization.access_token
81
+ refresh_token = api_client.authorization.refresh_token
82
+ id_token = api_client.authorization.id_token
83
+ expires_in = api_client.authorization.expires_in
84
+ issued_at = api_client.authorization.issued_at.to_s
85
+ if !@credential_file
86
+ filepath = File.expand_path(DEFAULT_FILE)
87
+ else
88
+ filepath = File.expand_path(@credential_file)
89
+ end
90
+ File.open(filepath,'w+') do |f|
91
+ f.write(MultiJson.dump({"authorization_uri" => authorization_uri,
92
+ "token_credential_uri"=>"https://accounts.google.com/o/oauth2/token",
93
+ "scope"=>scope,"redirect_uri"=>redirect_uri, "client_id"=>client_id,
94
+ "client_secret"=>client_secret, "access_token"=>access_token,
95
+ "expires_in"=>expires_in,"refresh_token"=> refresh_token, "id_token"=>id_token,
96
+ "issued_at"=>issued_at,"project"=>project }, :pretty=>true))
97
+ end
98
+ end
99
+
100
+ def projects
101
+ ResourceCollection.new(:resource_class => Google::Compute::Project, :dispatcher => @dispatcher)
102
+ end
103
+
104
+ def disks
105
+ CreatableResourceCollection.new(:resource_class => Google::Compute::Disk, :dispatcher=>@dispatcher)
106
+ end
107
+
108
+ def firewalls
109
+ CreatableResourceCollection.new(:resource_class => Google::Compute::Firewall, :dispatcher => @dispatcher)
110
+ end
111
+
112
+ def images
113
+ CreatableResourceCollection.new(:resource_class => Google::Compute::Image, :dispatcher => @dispatcher)
114
+ end
115
+
116
+ def instances
117
+ CreatableResourceCollection.new(:resource_class => Google::Compute::Server, :dispatcher=>@dispatcher)
118
+ end
119
+
120
+ def kernels
121
+ ListableResourceCollection.new(:resource_class => Google::Compute::Kernel,:dispatcher=>@dispatcher)
122
+ end
123
+
124
+ def machine_types
125
+ ListableResourceCollection.new(:resource_class => Google::Compute::MachineType,:dispatcher=>@dispatcher)
126
+ end
127
+
128
+ def networks
129
+ CreatableResourceCollection.new(:resource_class => Google::Compute::Network, :dispatcher=>@dispatcher)
130
+ end
131
+
132
+ def globalOperations
133
+ DeletableResourceCollection.new(:resource_class => Google::Compute::GlobalOperation, :dispatcher=>@dispatcher)
134
+ end
135
+
136
+ def zoneOperations
137
+ DeletableResourceCollection.new(:resource_class => Google::Compute::ZoneOperation, :dispatcher=>@dispatcher)
138
+ end
139
+
140
+ def zones
141
+ ListableResourceCollection.new(:resource_class => Google::Compute::Zone, :dispatcher=>@dispatcher)
142
+ end
143
+
144
+ def snapshots
145
+ CreatableResourceCollection.new(:resource_class => Google::Compute::Snapshot, :dispatcher=>@dispatcher)
146
+ end
147
+
148
+ class APIDispatcher
149
+ attr_reader :project, :api_client
150
+
151
+ def initialize(opts)
152
+ @project= opts[:project]
153
+ @api_client = opts[:api_client]
154
+ end
155
+
156
+ def compute
157
+ @compute ||= @api_client.discovered_api('compute','v1beta14')
158
+ end
159
+
160
+ def dispatch(opts)
161
+ begin
162
+ unless opts[:parameters].has_key?(:project)
163
+ opts[:parameters].merge!( :project => @project )
164
+ end
165
+ result = @api_client.execute(:api_method=>opts[:api_method],
166
+ :parameters=>opts[:parameters],
167
+ :body_object => opts[:body_object]
168
+ )
169
+ unless result.success?
170
+ response = MultiJson.load(result.response.body)
171
+ error_code = response["error"]["code"]
172
+ if error_code == 404
173
+ raise ResourceNotFound, result.response.body
174
+ elsif error_code == 400
175
+ raise BadRequest, result.response.body
176
+ else
177
+ raise BadRequest, result.response.body
178
+ end
179
+ end
180
+ return MultiJson.load(result.response.body) unless result.response.body.nil?
181
+ rescue ArgumentError => e
182
+ raise ParameterValidation, e.message
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end