knife-google 1.1.0 → 1.2.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.
- checksums.yaml +15 -0
- data/README.md +155 -66
- data/knife-google.gemspec +2 -1
- data/lib/chef/knife/google_base.rb +1 -1
- data/lib/chef/knife/google_disk_create.rb +17 -9
- data/lib/chef/knife/google_disk_delete.rb +2 -2
- data/lib/chef/knife/google_disk_list.rb +8 -8
- data/lib/chef/knife/google_project_list.rb +178 -0
- data/lib/chef/knife/google_region_list.rb +125 -0
- data/lib/chef/knife/google_server_create.rb +174 -46
- data/lib/chef/knife/google_server_delete.rb +9 -13
- data/lib/chef/knife/google_server_list.rb +5 -6
- data/lib/chef/knife/google_zone_list.rb +22 -28
- data/lib/google/compute.rb +2 -1
- data/lib/google/compute/client.rb +12 -7
- data/lib/google/compute/creatable_resource_collection.rb +12 -1
- data/lib/google/compute/disk.rb +0 -2
- data/lib/google/compute/image.rb +1 -2
- data/lib/google/compute/project.rb +2 -2
- data/lib/google/compute/{kernel.rb → region.rb} +12 -1
- data/lib/google/compute/region_operation.rb +62 -0
- data/lib/google/compute/server.rb +3 -2
- data/lib/google/compute/server/attached_disk.rb +3 -3
- data/lib/google/compute/zone.rb +6 -4
- data/lib/google/compute/zone_operation.rb +11 -9
- data/lib/knife-google/version.rb +1 -1
- data/spec/chef/knife/google_base_spec.rb +4 -4
- data/spec/chef/knife/google_disk_create_spec.rb +8 -7
- data/spec/chef/knife/google_disk_delete_spec.rb +15 -16
- data/spec/chef/knife/google_disk_list_spec.rb +6 -6
- data/spec/chef/knife/google_region_list_spec.rb +32 -0
- data/spec/chef/knife/google_server_create_spec.rb +78 -44
- data/spec/chef/knife/google_server_delete_spec.rb +37 -37
- data/spec/chef/knife/google_server_list_spec.rb +8 -7
- data/spec/chef/knife/google_setup_spec.rb +1 -2
- data/spec/chef/knife/google_zone_list_spec.rb +4 -4
- data/spec/data/{compute-v1beta15.json → compute-v1.json} +700 -246
- data/spec/data/disk.json +3 -4
- data/spec/data/firewall.json +2 -2
- data/spec/data/global_operation.json +3 -3
- data/spec/data/image.json +2 -2
- data/spec/data/machine_type.json +1 -1
- data/spec/data/network.json +1 -1
- data/spec/data/project.json +1 -1
- data/spec/data/region.json +23 -0
- data/spec/data/serial_port_output.json +1 -1
- data/spec/data/server.json +7 -7
- data/spec/data/snapshot.json +2 -2
- data/spec/data/zone.json +7 -15
- data/spec/data/zone_operation.json +3 -3
- data/spec/google/compute/disk_spec.rb +32 -32
- data/spec/google/compute/firewall_spec.rb +37 -37
- data/spec/google/compute/global_operation_spec.rb +9 -9
- data/spec/google/compute/image_spec.rb +17 -17
- data/spec/google/compute/machine_type_spec.rb +7 -7
- data/spec/google/compute/network_spec.rb +14 -14
- data/spec/google/compute/project_spec.rb +17 -17
- data/spec/google/compute/region_spec.rb +51 -0
- data/spec/google/compute/server_spec.rb +35 -42
- data/spec/google/compute/snapshot_spec.rb +11 -11
- data/spec/google/compute/zone_operation_spec.rb +9 -9
- data/spec/google/compute/zone_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -0
- data/spec/support/mocks.rb +10 -10
- data/spec/support/resource_examples.rb +7 -7
- data/spec/support/spec_google_base.rb +4 -0
- metadata +14 -26
- data/spec/data/kernel.json +0 -15
- data/spec/google/compute/kernel_spec.rb +0 -49
@@ -0,0 +1,178 @@
|
|
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 GoogleProjectList < Knife
|
21
|
+
|
22
|
+
include Knife::GoogleBase
|
23
|
+
|
24
|
+
banner "knife google project list (options)"
|
25
|
+
|
26
|
+
option :limits,
|
27
|
+
:short => "-L",
|
28
|
+
:long => "--with-limits",
|
29
|
+
:description => "Additionally print the quota limit for each metric",
|
30
|
+
:required => false,
|
31
|
+
:boolean => true,
|
32
|
+
:default => false
|
33
|
+
|
34
|
+
def run
|
35
|
+
$stdout.sync = true
|
36
|
+
|
37
|
+
project_list = [
|
38
|
+
ui.color("name", :bold),
|
39
|
+
ui.color('snapshots', :bold),
|
40
|
+
ui.color('networks', :bold),
|
41
|
+
ui.color('firewalls', :bold),
|
42
|
+
ui.color('images', :bold),
|
43
|
+
ui.color('routes', :bold),
|
44
|
+
ui.color('forwarding-rules', :bold),
|
45
|
+
ui.color('target-pools', :bold),
|
46
|
+
ui.color('health-checks', :bold)].flatten.compact
|
47
|
+
|
48
|
+
output_column_count = project_list.length
|
49
|
+
|
50
|
+
project = client.projects.project
|
51
|
+
|
52
|
+
project_list << project
|
53
|
+
|
54
|
+
snapshots_usage = "0"
|
55
|
+
snapshots_limit = "0"
|
56
|
+
client.projects.get(project).quotas.each do |quota|
|
57
|
+
if quota["metric"] == "SNAPSHOTS"
|
58
|
+
snapshots_usage = "#{quota["usage"].to_i}"
|
59
|
+
snapshots_limit = "#{quota["limit"].to_i}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
if config[:limits] == true
|
63
|
+
snapshots_quota = "#{snapshots_usage}/#{snapshots_limit}"
|
64
|
+
else
|
65
|
+
snapshots_quota = "#{snapshots_usage}"
|
66
|
+
end
|
67
|
+
project_list << snapshots_quota
|
68
|
+
|
69
|
+
networks_usage = "0"
|
70
|
+
networks_limit = "0"
|
71
|
+
client.projects.get(project).quotas.each do |quota|
|
72
|
+
if quota["metric"] == "NETWORKS"
|
73
|
+
networks_usage = "#{quota["usage"].to_i}"
|
74
|
+
networks_limit = "#{quota["limit"].to_i}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
if config[:limits] == true
|
78
|
+
networks_quota = "#{networks_usage}/#{networks_limit}"
|
79
|
+
else
|
80
|
+
networks_quota = "#{networks_usage}"
|
81
|
+
end
|
82
|
+
project_list << networks_quota
|
83
|
+
|
84
|
+
firewalls_usage = "0"
|
85
|
+
firewalls_limit = "0"
|
86
|
+
client.projects.get(project).quotas.each do |quota|
|
87
|
+
if quota["metric"] == "FIREWALLS"
|
88
|
+
firewalls_usage = "#{quota["usage"].to_i}"
|
89
|
+
firewalls_limit = "#{quota["limit"].to_i}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
if config[:limits] == true
|
93
|
+
firewalls_quota = "#{firewalls_usage}/#{firewalls_limit}"
|
94
|
+
else
|
95
|
+
firewalls_quota = "#{firewalls_usage}"
|
96
|
+
end
|
97
|
+
project_list << firewalls_quota
|
98
|
+
|
99
|
+
images_usage = "0"
|
100
|
+
images_limit = "0"
|
101
|
+
client.projects.get(project).quotas.each do |quota|
|
102
|
+
if quota["metric"] == "IMAGES"
|
103
|
+
images_usage = "#{quota["usage"].to_i}"
|
104
|
+
images_limit = "#{quota["limit"].to_i}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
if config[:limits] == true
|
108
|
+
images_quota = "#{images_usage}/#{images_limit}"
|
109
|
+
else
|
110
|
+
images_quota = "#{images_usage}"
|
111
|
+
end
|
112
|
+
project_list << images_quota
|
113
|
+
|
114
|
+
routes_usage = "0"
|
115
|
+
routes_limit = "0"
|
116
|
+
client.projects.get(project).quotas.each do |quota|
|
117
|
+
if quota["metric"] == "ROUTES"
|
118
|
+
routes_usage = "#{quota["usage"].to_i}"
|
119
|
+
routes_limit = "#{quota["limit"].to_i}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
if config[:limits] == true
|
123
|
+
routes_quota = "#{routes_usage}/#{routes_limit}"
|
124
|
+
else
|
125
|
+
routes_quota = "#{routes_usage}"
|
126
|
+
end
|
127
|
+
project_list << routes_quota
|
128
|
+
|
129
|
+
forwarding_usage = "0"
|
130
|
+
forwarding_limit = "0"
|
131
|
+
client.projects.get(project).quotas.each do |quota|
|
132
|
+
if quota["metric"] == "FORWARDING_RULES"
|
133
|
+
forwarding_usage = "#{quota["usage"].to_i}"
|
134
|
+
forwarding_limit = "#{quota["limit"].to_i}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
if config[:limits] == true
|
138
|
+
forwarding_quota = "#{forwarding_usage}/#{forwarding_limit}"
|
139
|
+
else
|
140
|
+
forwarding_quota = "#{forwarding_usage}"
|
141
|
+
end
|
142
|
+
project_list << forwarding_quota
|
143
|
+
|
144
|
+
target_usage = "0"
|
145
|
+
target_limit = "0"
|
146
|
+
client.projects.get(project).quotas.each do |quota|
|
147
|
+
if quota["metric"] == "TARGET_POOLS"
|
148
|
+
target_usage = "#{quota["usage"].to_i}"
|
149
|
+
target_limit = "#{quota["limit"].to_i}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
if config[:limits] == true
|
153
|
+
target_quota = "#{target_usage}/#{target_limit}"
|
154
|
+
else
|
155
|
+
target_quota = "#{target_usage}"
|
156
|
+
end
|
157
|
+
project_list << target_quota
|
158
|
+
|
159
|
+
health_usage = "0"
|
160
|
+
health_limit = "0"
|
161
|
+
client.projects.get(project).quotas.each do |quota|
|
162
|
+
if quota["metric"] == "HEALTH_CHECKS"
|
163
|
+
health_usage = "#{quota["usage"].to_i}"
|
164
|
+
health_limit = "#{quota["limit"].to_i}"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
if config[:limits] == true
|
168
|
+
health_quota = "#{health_usage}/#{health_limit}"
|
169
|
+
else
|
170
|
+
health_quota = "#{health_usage}"
|
171
|
+
end
|
172
|
+
project_list << health_quota
|
173
|
+
|
174
|
+
ui.info(ui.list(project_list, :uneven_columns_across, output_column_count))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,125 @@
|
|
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 GoogleRegionList < Knife
|
21
|
+
|
22
|
+
include Knife::GoogleBase
|
23
|
+
|
24
|
+
banner "knife google region list (options)"
|
25
|
+
|
26
|
+
option :limits,
|
27
|
+
:short => "-L",
|
28
|
+
:long => "--with-limits",
|
29
|
+
:description => "Additionally print the quota limit for each metric",
|
30
|
+
:required => false,
|
31
|
+
:boolean => true,
|
32
|
+
:default => false
|
33
|
+
|
34
|
+
def run
|
35
|
+
$stdout.sync = true
|
36
|
+
|
37
|
+
region_list = [
|
38
|
+
ui.color("name", :bold),
|
39
|
+
ui.color('status', :bold),
|
40
|
+
ui.color('deprecation', :bold),
|
41
|
+
ui.color('cpus', :bold),
|
42
|
+
ui.color('disks-total-gb', :bold),
|
43
|
+
ui.color('in-use-addresses', :bold),
|
44
|
+
ui.color('static-addresses', :bold)].flatten.compact
|
45
|
+
|
46
|
+
output_column_count = region_list.length
|
47
|
+
|
48
|
+
client.regions.list.each do |region|
|
49
|
+
region_list << region.name
|
50
|
+
region_list << begin
|
51
|
+
status = region.status.downcase
|
52
|
+
case status
|
53
|
+
when 'up'
|
54
|
+
ui.color(status, :green)
|
55
|
+
else
|
56
|
+
ui.color(status, :red)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
deprecation_state = "-"
|
60
|
+
if region.deprecated.respond_to?('state')
|
61
|
+
deprecation_state = region.deprecated.state
|
62
|
+
end
|
63
|
+
region_list << deprecation_state
|
64
|
+
cpu_usage = "0"
|
65
|
+
cpu_limit = "0"
|
66
|
+
region.quotas.each do |quota|
|
67
|
+
if quota["metric"] == "CPUS"
|
68
|
+
cpu_usage = "#{quota["usage"].to_i}"
|
69
|
+
cpu_limit = "#{quota["limit"].to_i}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
if config[:limits] == true
|
73
|
+
cpu_quota = "#{cpu_usage}/#{cpu_limit}"
|
74
|
+
else
|
75
|
+
cpu_quota = "#{cpu_usage}"
|
76
|
+
end
|
77
|
+
region_list << cpu_quota
|
78
|
+
disk_usage = "0"
|
79
|
+
disk_limit = "0"
|
80
|
+
region.quotas.each do |quota|
|
81
|
+
if quota["metric"] == "DISKS_TOTAL_GB"
|
82
|
+
disk_usage = "#{quota["usage"].to_i}"
|
83
|
+
disk_limit = "#{quota["limit"].to_i}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if config[:limits] == true
|
87
|
+
disk_quota = "#{disk_usage}/#{disk_limit}"
|
88
|
+
else
|
89
|
+
disk_quota = "#{disk_usage}"
|
90
|
+
end
|
91
|
+
region_list << disk_quota
|
92
|
+
inuse_usage = "0"
|
93
|
+
inuse_limit = "0"
|
94
|
+
region.quotas.each do |quota|
|
95
|
+
if quota["metric"] == "IN_USE_ADDRESSES"
|
96
|
+
inuse_usage = "#{quota["usage"].to_i}"
|
97
|
+
inuse_limit = "#{quota["limit"].to_i}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if config[:limits] == true
|
101
|
+
inuse_quota = "#{inuse_usage}/#{inuse_limit}"
|
102
|
+
else
|
103
|
+
inuse_quota = "#{inuse_usage}"
|
104
|
+
end
|
105
|
+
region_list << inuse_quota
|
106
|
+
static_usage = "0"
|
107
|
+
static_limit = "0"
|
108
|
+
region.quotas.each do |quota|
|
109
|
+
if quota["metric"] == "STATIC_ADDRESSES"
|
110
|
+
static_usage = "#{quota["usage"].to_i}"
|
111
|
+
static_limit = "#{quota["limit"].to_i}"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
if config[:limits] == true
|
115
|
+
static_quota = "#{static_usage}/#{static_limit}"
|
116
|
+
else
|
117
|
+
static_quota = "#{static_usage}"
|
118
|
+
end
|
119
|
+
region_list << static_quota
|
120
|
+
end
|
121
|
+
ui.info(ui.list(region_list, :uneven_columns_across, output_column_count))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -12,6 +12,7 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
#
|
15
|
+
require 'timeout'
|
15
16
|
require 'chef/knife/google_base'
|
16
17
|
|
17
18
|
class Chef
|
@@ -34,47 +35,89 @@ class Chef
|
|
34
35
|
|
35
36
|
option :machine_type,
|
36
37
|
:short => "-m MACHINE_TYPE",
|
37
|
-
:long => "--
|
38
|
+
:long => "--gce-machine-type MACHINE_TYPE",
|
38
39
|
:description => "The machine type of server (n1-highcpu-2, n1-highcpu-2-d, etc)",
|
39
40
|
:required => true
|
40
41
|
|
41
42
|
option :image,
|
42
43
|
:short => "-I IMAGE",
|
43
|
-
:long => "--
|
44
|
+
:long => "--gce-image IMAGE",
|
44
45
|
:description => "The Image for the server",
|
45
46
|
:required => true
|
46
47
|
|
47
48
|
option :image_project_id,
|
48
|
-
:
|
49
|
-
:long => "--google-compute-image-project-id IMAGE_PROJECT_ID",
|
49
|
+
:long => "--gce-image-project-id IMAGE_PROJECT_ID",
|
50
50
|
:description => "The project-id containing the Image (debian-cloud, centos-cloud, etc)",
|
51
51
|
:default => ""
|
52
52
|
|
53
53
|
option :zone,
|
54
54
|
:short => "-Z ZONE",
|
55
|
-
:long => "--
|
55
|
+
:long => "--gce-zone ZONE",
|
56
56
|
:description => "The Zone for this server"
|
57
57
|
|
58
|
+
option :boot_disk_name,
|
59
|
+
:long => "--gce-boot-disk-name DISK",
|
60
|
+
:description => "Name of persistent boot disk; default is to use the server name",
|
61
|
+
:default => ""
|
62
|
+
|
63
|
+
option :boot_disk_size,
|
64
|
+
:long => "--gce-boot-disk-size SIZE",
|
65
|
+
:description => "Size of the persistent boot disk between 10 and 10000 GB, specified in GB; default is '10' GB",
|
66
|
+
:default => "10"
|
67
|
+
|
68
|
+
option :auto_restart,
|
69
|
+
:long => "--[no-]gce-auto-server-restart",
|
70
|
+
:description => "Compute Engine can automatically restart your VM instance if it is terminated for non-user-initiated reasons; enabled by default.",
|
71
|
+
:boolean => true,
|
72
|
+
:default => true
|
73
|
+
|
74
|
+
option :auto_migrate,
|
75
|
+
:long => "--[no-]gce-auto-server-migrate",
|
76
|
+
:description => "Compute Engine can migrate your VM instance to other hardware without downtime prior to periodic infrastructure maintenance, otherwise the server is terminated; enabled by default.",
|
77
|
+
:boolean => true,
|
78
|
+
:default => true
|
79
|
+
|
58
80
|
option :network,
|
59
81
|
:short => "-n NETWORK",
|
60
|
-
:long => "--
|
82
|
+
:long => "--gce-network NETWORK",
|
61
83
|
:description => "The network for this server; default is 'default'",
|
62
84
|
:default => "default"
|
63
85
|
|
64
86
|
option :tags,
|
65
87
|
:short => "-T TAG1,TAG2,TAG3",
|
66
|
-
:long => "--
|
88
|
+
:long => "--gce-tags TAG1,TAG2,TAG3",
|
67
89
|
:description => "Tags for this server",
|
68
90
|
:proc => Proc.new { |tags| tags.split(',') },
|
69
91
|
:default => []
|
70
92
|
|
71
93
|
option :metadata,
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:description => "The metadata for this server",
|
94
|
+
:long => "--gce-metadata Key=Value[,Key=Value...]",
|
95
|
+
:description => "Additional metadata for this server",
|
75
96
|
:proc => Proc.new { |metadata| metadata.split(',') },
|
76
97
|
:default => []
|
77
98
|
|
99
|
+
option :service_account_scopes,
|
100
|
+
:long => "--gce-service-account-scopes SCOPE1,SCOPE2,SCOPE3",
|
101
|
+
:proc => Proc.new { |service_account_scopes| service_account_scopes.split(',') },
|
102
|
+
:description => "Service account scopes for this server",
|
103
|
+
:default => []
|
104
|
+
|
105
|
+
# GCE documentation uses the term 'service account name', the api uses the term 'email'
|
106
|
+
option :service_account_name,
|
107
|
+
:long => "--gce-service-account-name NAME",
|
108
|
+
:description => "Service account name for this server, typically in the form of '123845678986@project.gserviceaccount.com'; default is 'default'",
|
109
|
+
:default => "default"
|
110
|
+
|
111
|
+
option :instance_connect_ip,
|
112
|
+
:long => "--gce-server-connect-ip INTERFACE",
|
113
|
+
:description => "Whether to use PUBLIC or PRIVATE interface/address to connect; default is 'PUBLIC'",
|
114
|
+
:default => 'PUBLIC'
|
115
|
+
|
116
|
+
option :public_ip,
|
117
|
+
:long=> "--gce-public-ip IP_ADDRESS",
|
118
|
+
:description => "EPHEMERAL or static IP address or NONE; default is 'EPHEMERAL'",
|
119
|
+
:default => "EPHEMERAL"
|
120
|
+
|
78
121
|
option :chef_node_name,
|
79
122
|
:short => "-N NAME",
|
80
123
|
:long => "--node-name NAME",
|
@@ -158,23 +201,6 @@ class Chef
|
|
158
201
|
Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new
|
159
202
|
}
|
160
203
|
|
161
|
-
option :instance_connect_ip,
|
162
|
-
:long => "--google-compute-server-connect-ip PUBLIC",
|
163
|
-
:short => "-a PUBLIC",
|
164
|
-
:description => "Whether to use PUBLIC or PRIVATE address to connect; default is 'PUBLIC'",
|
165
|
-
:default => 'PUBLIC'
|
166
|
-
|
167
|
-
option :disks,
|
168
|
-
:long=> "--google-compute-disks DISK1,DISK2",
|
169
|
-
:proc => Proc.new { |metadata| metadata.split(',') },
|
170
|
-
:description => "Disks to be attached",
|
171
|
-
:default => []
|
172
|
-
|
173
|
-
option :public_ip,
|
174
|
-
:long=> "--google-compute-public-ip IP_ADDRESS",
|
175
|
-
:description => "EPHEMERAL or static IP address or NONE; default is 'EPHEMERAL'",
|
176
|
-
:default => "EPHEMERAL"
|
177
|
-
|
178
204
|
def tcp_test_ssh(hostname, ssh_port)
|
179
205
|
tcp_socket = TCPSocket.new(hostname, ssh_port)
|
180
206
|
readable = IO.select([tcp_socket], nil, nil, 5)
|
@@ -200,7 +226,7 @@ class Chef
|
|
200
226
|
|
201
227
|
def wait_for_tunnelled_sshd(hostname)
|
202
228
|
print(".")
|
203
|
-
print(".") until tunnel_test_ssh(
|
229
|
+
print(".") until tunnel_test_ssh(hostname) {
|
204
230
|
sleep @initial_sleep_delay ||= 40
|
205
231
|
puts("done")
|
206
232
|
}
|
@@ -237,7 +263,35 @@ class Chef
|
|
237
263
|
end
|
238
264
|
end
|
239
265
|
|
240
|
-
def
|
266
|
+
def disk_exists(disk, zone)
|
267
|
+
# if client.disks.get errors with a Google::Compute::ResourceNotFound
|
268
|
+
# then the disk does not exist and can be created
|
269
|
+
client.disks.get(:disk => disk, :zone => selflink2name(zone))
|
270
|
+
rescue Google::Compute::ResourceNotFound
|
271
|
+
# disk does not exist
|
272
|
+
# continue provisioning
|
273
|
+
false
|
274
|
+
else
|
275
|
+
true
|
276
|
+
end
|
277
|
+
|
278
|
+
def wait_for_disk(disk, operation, zone)
|
279
|
+
Timeout::timeout(300) do
|
280
|
+
until disk.status == 'DONE'
|
281
|
+
ui.info(".")
|
282
|
+
sleep 1
|
283
|
+
disk = client.zoneOperations.get(:name => disk,
|
284
|
+
:operation => operation,
|
285
|
+
:zone => selflink2name(zone))
|
286
|
+
end
|
287
|
+
disk.target_link
|
288
|
+
end
|
289
|
+
rescue Timeout::Error
|
290
|
+
ui.error("Timeout exceeded with disk status: " + disk.status)
|
291
|
+
exit 1
|
292
|
+
end
|
293
|
+
|
294
|
+
def bootstrap_for_node(instance, ssh_host)
|
241
295
|
bootstrap = Chef::Knife::Bootstrap.new
|
242
296
|
bootstrap.name_args = [ssh_host]
|
243
297
|
bootstrap.config[:run_list] = config[:run_list]
|
@@ -258,6 +312,7 @@ class Chef
|
|
258
312
|
# Modify global configuration state to ensure hint gets set by
|
259
313
|
# knife-bootstrap
|
260
314
|
Chef::Config[:knife][:hints] ||= {}
|
315
|
+
Chef::Config[:knife][:hints]["gce"] ||= {}
|
261
316
|
Chef::Config[:knife][:hints]["google"] ||= {}
|
262
317
|
bootstrap
|
263
318
|
end
|
@@ -265,14 +320,14 @@ class Chef
|
|
265
320
|
def run
|
266
321
|
$stdout.sync = true
|
267
322
|
unless @name_args.size > 0
|
268
|
-
ui.error("Please provide the name of the new server")
|
323
|
+
ui.error("Please provide the name of the new server.")
|
269
324
|
exit 1
|
270
325
|
end
|
271
326
|
|
272
327
|
begin
|
273
|
-
zone = client.zones.get(config[:zone] || Chef::Config[:knife][:
|
328
|
+
zone = client.zones.get(config[:zone] || Chef::Config[:knife][:gce_zone]).self_link
|
274
329
|
rescue Google::Compute::ResourceNotFound
|
275
|
-
ui.error("Zone '#{config[:zone] || Chef::Config[:knife][:
|
330
|
+
ui.error("Zone '#{config[:zone] || Chef::Config[:knife][:gce_zone]}' not found.")
|
276
331
|
exit 1
|
277
332
|
rescue Google::Compute::ParameterValidation
|
278
333
|
ui.error("Must specify zone in knife config file or in command line as an option. Try --help.")
|
@@ -280,18 +335,33 @@ class Chef
|
|
280
335
|
end
|
281
336
|
|
282
337
|
begin
|
283
|
-
machine_type = client.machine_types.get(:name=>config[:machine_type],
|
338
|
+
machine_type = client.machine_types.get(:name => config[:machine_type],
|
339
|
+
:zone => selflink2name(zone)).self_link
|
284
340
|
rescue Google::Compute::ResourceNotFound
|
285
341
|
ui.error("MachineType '#{config[:machine_type]}' not found")
|
286
342
|
exit 1
|
287
343
|
end
|
288
344
|
|
345
|
+
# this parameter is a string during the post and boolean otherwise
|
346
|
+
if config[:auto_restart] then
|
347
|
+
auto_restart = 'true'
|
348
|
+
else
|
349
|
+
auto_restart = 'false'
|
350
|
+
end
|
351
|
+
|
352
|
+
if config[:auto_migrate] then
|
353
|
+
auto_migrate = 'MIGRATE'
|
354
|
+
else
|
355
|
+
auto_migrate = 'TERMINATE'
|
356
|
+
end
|
357
|
+
|
289
358
|
(checked_custom, checked_all) = false
|
290
359
|
begin
|
291
360
|
image_project = config[:image_project_id]
|
292
|
-
|
361
|
+
# use zone url to determine project name
|
362
|
+
zone =~ Regexp.new('/projects/(.*?)/')
|
293
363
|
project = $1
|
294
|
-
if image_project.empty?
|
364
|
+
if image_project.to_s.empty?
|
295
365
|
unless checked_custom
|
296
366
|
checked_custom = true
|
297
367
|
ui.info("Looking for Image '#{config[:image]}' in Project '#{project}'")
|
@@ -323,6 +393,27 @@ class Chef
|
|
323
393
|
end
|
324
394
|
end
|
325
395
|
|
396
|
+
begin
|
397
|
+
boot_disk_size = config[:boot_disk_size].to_i
|
398
|
+
raise if !boot_disk_size.between?(10, 10000)
|
399
|
+
rescue
|
400
|
+
ui.error("Size of the persistent boot disk must be between 10 and 10000 GB.")
|
401
|
+
exit 1
|
402
|
+
end
|
403
|
+
|
404
|
+
if config[:boot_disk_name].to_s.empty? then
|
405
|
+
boot_disk_name = @name_args.first
|
406
|
+
else
|
407
|
+
boot_disk_name = config[:boot_disk_name]
|
408
|
+
end
|
409
|
+
|
410
|
+
ui.info("Waiting for the disk insert operation to complete")
|
411
|
+
boot_disk_insert = client.disks.insert(:sourceImage => image,
|
412
|
+
:zone => selflink2name(zone),
|
413
|
+
:name => boot_disk_name,
|
414
|
+
:sizeGb => boot_disk_size)
|
415
|
+
boot_disk_target_link = wait_for_disk(boot_disk_insert, boot_disk_insert.name, zone)
|
416
|
+
|
326
417
|
begin
|
327
418
|
network = client.networks.get(config[:network]).self_link
|
328
419
|
rescue Google::Compute::ResourceNotFound
|
@@ -330,7 +421,6 @@ class Chef
|
|
330
421
|
exit 1
|
331
422
|
end
|
332
423
|
|
333
|
-
disks = config[:disks].collect{|disk| client.disks.get(:disk=>disk, :zone=>selflink2name(zone)).self_link}
|
334
424
|
metadata = config[:metadata].collect{|pair| Hash[*pair.split('=')] }
|
335
425
|
network_interface = {'network'=>network}
|
336
426
|
|
@@ -346,27 +436,65 @@ class Chef
|
|
346
436
|
ui.error("Invalid public ip value : #{config[:public_ip]}")
|
347
437
|
exit 1
|
348
438
|
end
|
349
|
-
zone_operation = client.instances.create(:name=>@name_args.first, :zone=>selflink2name(zone),
|
350
|
-
:image=> image,
|
351
|
-
:machineType =>machine_type,
|
352
|
-
:disks=>disks,
|
353
|
-
:metadata=>{'items'=> metadata },
|
354
|
-
:networkInterfaces => [network_interface],
|
355
|
-
:tags=> config[:tags]
|
356
|
-
)
|
357
439
|
|
358
440
|
ui.info("Waiting for the create server operation to complete")
|
441
|
+
if !config[:service_account_scopes].any?
|
442
|
+
zone_operation = client.instances.create(:name => @name_args.first,
|
443
|
+
:zone => selflink2name(zone),
|
444
|
+
:machineType => machine_type,
|
445
|
+
:disks => [{
|
446
|
+
'boot' => true,
|
447
|
+
'type' => 'PERSISTENT',
|
448
|
+
'mode' => 'READ_WRITE',
|
449
|
+
'deviceName' => selflink2name(boot_disk_target_link),
|
450
|
+
'source' => boot_disk_target_link
|
451
|
+
}],
|
452
|
+
:networkInterfaces => [network_interface],
|
453
|
+
:scheduling => {
|
454
|
+
'automaticRestart' => auto_restart,
|
455
|
+
'onHostMaintenance' => auto_migrate
|
456
|
+
},
|
457
|
+
:metadata => { 'items' => metadata },
|
458
|
+
:tags => { 'items' => config[:tags] }
|
459
|
+
)
|
460
|
+
else
|
461
|
+
zone_operation = client.instances.create(:name => @name_args.first,
|
462
|
+
:zone=> selflink2name(zone),
|
463
|
+
:machineType => machine_type,
|
464
|
+
:disks => [{
|
465
|
+
'boot' => true,
|
466
|
+
'type' => 'PERSISTENT',
|
467
|
+
'mode' => 'READ_WRITE',
|
468
|
+
'deviceName' => selflink2name(boot_disk_target_link),
|
469
|
+
'source' => boot_disk_target_link
|
470
|
+
}],
|
471
|
+
:networkInterfaces => [network_interface],
|
472
|
+
:serviceAccounts => [{
|
473
|
+
'kind' => 'compute#serviceAccount',
|
474
|
+
'email' => config[:service_account_name],
|
475
|
+
'scopes' => config[:service_account_scopes]
|
476
|
+
}],
|
477
|
+
:scheduling => {
|
478
|
+
'automaticRestart' => auto_restart,
|
479
|
+
'onHostMaintenance' => auto_migrate
|
480
|
+
},
|
481
|
+
:metadata => { 'items'=>metadata },
|
482
|
+
:tags => { 'items' => config[:tags] }
|
483
|
+
)
|
484
|
+
end
|
485
|
+
|
359
486
|
until zone_operation.progress.to_i == 100
|
360
487
|
ui.info(".")
|
361
488
|
sleep 1
|
362
489
|
zone_operation = client.zoneOperations.get(:name=>zone_operation, :operation=>zone_operation.name, :zone=>selflink2name(zone))
|
363
490
|
end
|
491
|
+
|
364
492
|
ui.info("Waiting for the servers to be in running state")
|
365
493
|
|
366
494
|
@instance = client.instances.get(:name=>@name_args.first, :zone=>selflink2name(zone))
|
367
495
|
msg_pair("Instance Name", @instance.name)
|
368
|
-
msg_pair("
|
369
|
-
msg_pair("Image", selflink2name(
|
496
|
+
msg_pair("Machine Type", selflink2name(@instance.machine_type))
|
497
|
+
msg_pair("Image", selflink2name(config[:image]))
|
370
498
|
msg_pair("Zone", selflink2name(@instance.zone))
|
371
499
|
msg_pair("Tags", @instance.tags.has_key?("items") ? @instance.tags["items"].join(",") : "None")
|
372
500
|
until @instance.status == "RUNNING"
|