knife-google 1.3.1 → 2.0.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 +5 -13
- data/.gitignore +1 -0
- data/.travis.yml +15 -3
- data/CHANGELOG.md +4 -6
- data/Gemfile +3 -9
- data/README.md +208 -355
- data/RELEASE_NOTES.md +8 -17
- data/Rakefile +8 -49
- data/knife-google.gemspec +20 -17
- data/lib/chef/knife/cloud/google_service.rb +491 -0
- data/lib/chef/knife/cloud/google_service_helpers.rb +62 -0
- data/lib/chef/knife/cloud/google_service_options.rb +58 -0
- data/lib/chef/knife/google_disk_create.rb +40 -44
- data/lib/chef/knife/google_disk_delete.rb +22 -40
- data/lib/chef/knife/google_disk_list.rb +57 -51
- data/lib/chef/knife/google_project_quotas.rb +59 -0
- data/lib/chef/knife/google_region_list.rb +43 -102
- data/lib/chef/knife/google_region_quotas.rb +77 -0
- data/lib/chef/knife/google_server_create.rb +224 -505
- data/lib/chef/knife/google_server_delete.rb +20 -78
- data/lib/chef/knife/google_server_list.rb +42 -53
- data/lib/chef/knife/google_server_show.rb +44 -0
- data/lib/chef/knife/google_zone_list.rb +39 -50
- data/lib/knife-google/version.rb +3 -2
- data/spec/cloud/google_service_helpers_spec.rb +120 -0
- data/spec/cloud/google_service_spec.rb +832 -0
- data/spec/google_disk_create_spec.rb +72 -0
- data/spec/google_disk_delete_spec.rb +64 -0
- data/spec/google_disk_list_spec.rb +93 -0
- data/spec/google_project_quotas_spec.rb +63 -0
- data/spec/google_region_list_spec.rb +65 -0
- data/spec/google_region_quotas_spec.rb +108 -0
- data/spec/google_server_create_spec.rb +177 -0
- data/spec/google_server_delete_spec.rb +39 -0
- data/spec/google_server_list_spec.rb +77 -0
- data/spec/google_server_show_spec.rb +60 -0
- data/spec/google_zone_list_spec.rb +59 -0
- metadata +91 -114
- data/CONTRIB.md +0 -64
- data/lib/chef/knife/google_base.rb +0 -76
- data/lib/chef/knife/google_project_list.rb +0 -178
- data/lib/chef/knife/google_setup.rb +0 -31
- data/lib/google/compute.rb +0 -47
- data/lib/google/compute/client.rb +0 -216
- data/lib/google/compute/config.rb +0 -23
- data/lib/google/compute/creatable_resource_collection.rb +0 -55
- data/lib/google/compute/deletable_resource_collection.rb +0 -51
- data/lib/google/compute/disk.rb +0 -38
- data/lib/google/compute/exception.rb +0 -30
- data/lib/google/compute/firewall.rb +0 -65
- data/lib/google/compute/global_operation.rb +0 -60
- data/lib/google/compute/image.rb +0 -29
- data/lib/google/compute/listable_resource_collection.rb +0 -33
- data/lib/google/compute/machine_type.rb +0 -36
- data/lib/google/compute/mixins/utils.rb +0 -58
- data/lib/google/compute/network.rb +0 -29
- data/lib/google/compute/project.rb +0 -76
- data/lib/google/compute/region.rb +0 -31
- data/lib/google/compute/region_operation.rb +0 -62
- data/lib/google/compute/resource.rb +0 -81
- data/lib/google/compute/resource_collection.rb +0 -78
- data/lib/google/compute/server.rb +0 -88
- data/lib/google/compute/server/attached_disk.rb +0 -39
- data/lib/google/compute/server/network_interface.rb +0 -38
- data/lib/google/compute/server/network_interface/access_config.rb +0 -35
- data/lib/google/compute/server/serial_port_output.rb +0 -31
- data/lib/google/compute/snapshot.rb +0 -30
- data/lib/google/compute/version.rb +0 -19
- data/lib/google/compute/zone.rb +0 -34
- data/lib/google/compute/zone_operation.rb +0 -62
- data/spec/chef/knife/google_base_spec.rb +0 -46
- data/spec/chef/knife/google_disk_create_spec.rb +0 -37
- data/spec/chef/knife/google_disk_delete_spec.rb +0 -64
- data/spec/chef/knife/google_disk_list_spec.rb +0 -36
- data/spec/chef/knife/google_region_list_spec.rb +0 -32
- data/spec/chef/knife/google_server_create_spec.rb +0 -138
- data/spec/chef/knife/google_server_delete_spec.rb +0 -127
- data/spec/chef/knife/google_server_list_spec.rb +0 -39
- data/spec/chef/knife/google_setup_spec.rb +0 -24
- data/spec/chef/knife/google_zone_list_spec.rb +0 -32
- data/spec/data/client.json +0 -14
- data/spec/data/compute-v1.json +0 -6734
- data/spec/data/disk.json +0 -14
- data/spec/data/firewall.json +0 -13
- data/spec/data/global_operation.json +0 -36
- data/spec/data/image.json +0 -12
- data/spec/data/machine_type.json +0 -24
- data/spec/data/network.json +0 -10
- data/spec/data/project.json +0 -21
- data/spec/data/region.json +0 -23
- data/spec/data/serial_port_output.json +0 -5
- data/spec/data/server.json +0 -46
- data/spec/data/snapshot.json +0 -12
- data/spec/data/zone.json +0 -22
- data/spec/data/zone_operation.json +0 -36
- data/spec/google/compute/disk_spec.rb +0 -115
- data/spec/google/compute/firewall_spec.rb +0 -129
- data/spec/google/compute/global_operation_spec.rb +0 -62
- data/spec/google/compute/image_spec.rb +0 -75
- data/spec/google/compute/machine_type_spec.rb +0 -53
- data/spec/google/compute/network_spec.rb +0 -68
- data/spec/google/compute/project_spec.rb +0 -71
- data/spec/google/compute/region_spec.rb +0 -51
- data/spec/google/compute/server_spec.rb +0 -118
- data/spec/google/compute/snapshot_spec.rb +0 -57
- data/spec/google/compute/zone_operation_spec.rb +0 -62
- data/spec/google/compute/zone_spec.rb +0 -51
- data/spec/spec_helper.rb +0 -45
- data/spec/support/mocks.rb +0 -62
- data/spec/support/resource_examples.rb +0 -70
- data/spec/support/spec_google_base.rb +0 -60
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
#
|
|
2
|
+
# Author:: Paul Rossman (<paulrossman@google.com>)
|
|
3
|
+
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
|
4
|
+
# Copyright:: Copyright 2015-2016 Google Inc., Chef Software, Inc.
|
|
5
|
+
# License:: Apache License, Version 2.0
|
|
2
6
|
#
|
|
3
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
8
|
# you may not use this file except in compliance with the License.
|
|
@@ -11,115 +15,52 @@
|
|
|
11
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
16
|
# See the License for the specific language governing permissions and
|
|
13
17
|
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
require 'chef/knife/google_base'
|
|
16
|
-
require 'time'
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
require "chef/knife"
|
|
20
|
+
require "chef/knife/cloud/list_resource_command"
|
|
21
|
+
require "chef/knife/cloud/google_service"
|
|
22
|
+
require "chef/knife/cloud/google_service_helpers"
|
|
23
|
+
require "chef/knife/cloud/google_service_options"
|
|
24
|
+
|
|
25
|
+
class Chef::Knife::Cloud
|
|
26
|
+
class GoogleRegionList < ResourceListCommand
|
|
27
|
+
include GoogleServiceHelpers
|
|
28
|
+
include GoogleServiceOptions
|
|
29
|
+
|
|
30
|
+
banner "knife google zone list"
|
|
21
31
|
|
|
22
|
-
|
|
32
|
+
def validate_params!
|
|
33
|
+
check_for_missing_config_values!
|
|
34
|
+
super
|
|
35
|
+
end
|
|
23
36
|
|
|
24
|
-
|
|
37
|
+
def before_exec_command
|
|
38
|
+
@columns_with_info = [
|
|
39
|
+
{ label: "Region", key: "name" },
|
|
40
|
+
{ label: "Status", key: "status", value_callback: method(:format_status_value) },
|
|
41
|
+
{ label: "Zones", key: "zones", value_callback: method(:format_zones) },
|
|
42
|
+
]
|
|
25
43
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
:long => "--with-limits",
|
|
29
|
-
:description => "Additionally print the quota limit for each metric",
|
|
30
|
-
:required => false,
|
|
31
|
-
:boolean => true,
|
|
32
|
-
:default => false
|
|
44
|
+
@sort_by_field = "name"
|
|
45
|
+
end
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
def query_resource
|
|
48
|
+
service.list_regions
|
|
49
|
+
end
|
|
36
50
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
ui.color('static-addresses', :bold)].flatten.compact
|
|
51
|
+
def format_status_value(status)
|
|
52
|
+
status = status.downcase
|
|
53
|
+
status_color = if status == "up"
|
|
54
|
+
:green
|
|
55
|
+
else
|
|
56
|
+
:red
|
|
57
|
+
end
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
ui.color(status, status_color)
|
|
60
|
+
end
|
|
47
61
|
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
62
|
+
def format_zones(zones)
|
|
63
|
+
zones.map { |zone| zone.split("/").last }.sort.join(", ")
|
|
123
64
|
end
|
|
124
65
|
end
|
|
125
66
|
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Author:: Paul Rossman (<paulrossman@google.com>)
|
|
3
|
+
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
|
4
|
+
# Copyright:: Copyright 2015-2016 Google Inc., Chef Software, Inc.
|
|
5
|
+
# License:: Apache License, Version 2.0
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
|
|
19
|
+
require "chef/knife"
|
|
20
|
+
require "chef/knife/cloud/list_resource_command"
|
|
21
|
+
require "chef/knife/cloud/google_service"
|
|
22
|
+
require "chef/knife/cloud/google_service_helpers"
|
|
23
|
+
require "chef/knife/cloud/google_service_options"
|
|
24
|
+
|
|
25
|
+
class Chef::Knife::Cloud
|
|
26
|
+
class GoogleRegionQuotas < Command
|
|
27
|
+
include GoogleServiceHelpers
|
|
28
|
+
include GoogleServiceOptions
|
|
29
|
+
|
|
30
|
+
banner "knife google region quotas"
|
|
31
|
+
|
|
32
|
+
def validate_params!
|
|
33
|
+
check_for_missing_config_values!
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def execute_command
|
|
38
|
+
service.list_regions.each do |region|
|
|
39
|
+
ui.msg(ui.color("Region: #{region.name}", :bold))
|
|
40
|
+
|
|
41
|
+
quotas = region.quotas
|
|
42
|
+
if quotas.nil? || quotas.empty?
|
|
43
|
+
ui.warn("No quota information available for this region.")
|
|
44
|
+
ui.msg("")
|
|
45
|
+
next
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
output = []
|
|
49
|
+
output << table_header
|
|
50
|
+
quotas.each do |quota|
|
|
51
|
+
output << format_name(quota.metric)
|
|
52
|
+
output << format_number(quota.limit)
|
|
53
|
+
output << format_number(quota.usage)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ui.msg(ui.list(output.flatten, :uneven_columns_across, table_header.size))
|
|
57
|
+
ui.msg("")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def table_header
|
|
62
|
+
[
|
|
63
|
+
ui.color("Quota", :bold),
|
|
64
|
+
ui.color("Limit", :bold),
|
|
65
|
+
ui.color("Usage", :bold),
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def format_name(name)
|
|
70
|
+
name.split("_").map { |x| x.capitalize }.join(" ")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def format_number(number)
|
|
74
|
+
number % 1 == 0 ? number.to_i.to_s : number.to_s
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
#
|
|
2
|
+
# Author:: Paul Rossman (<paulrossman@google.com>)
|
|
3
|
+
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
|
4
|
+
# Copyright:: Copyright 2015-2016 Google Inc., Chef Software, Inc.
|
|
5
|
+
# License:: Apache License, Version 2.0
|
|
2
6
|
#
|
|
3
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
8
|
# you may not use this file except in compliance with the License.
|
|
@@ -11,525 +15,240 @@
|
|
|
11
15
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
16
|
# See the License for the specific language governing permissions and
|
|
13
17
|
# limitations under the License.
|
|
14
|
-
#
|
|
15
|
-
require 'timeout'
|
|
16
|
-
require 'chef/knife/google_base'
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
require "chef/knife"
|
|
20
|
+
require "chef/knife/cloud/server/create_command"
|
|
21
|
+
require "chef/knife/cloud/server/create_options"
|
|
22
|
+
require "chef/knife/cloud/google_service"
|
|
23
|
+
require "chef/knife/cloud/google_service_helpers"
|
|
24
|
+
require "chef/knife/cloud/google_service_options"
|
|
25
|
+
|
|
26
|
+
class Chef::Knife::Cloud
|
|
27
|
+
class GoogleServerCreate < ServerCreateCommand
|
|
28
|
+
include GoogleServiceOptions
|
|
29
|
+
include GoogleServiceHelpers
|
|
30
|
+
include ServerCreateOptions
|
|
31
|
+
|
|
32
|
+
banner "knife google server create NAME -m MACHINE_TYPE -I IMAGE (options)"
|
|
33
|
+
|
|
34
|
+
option :machine_type,
|
|
35
|
+
short: "-m MACHINE_TYPE",
|
|
36
|
+
long: "--gce-machine-type MACHINE_TYPE",
|
|
37
|
+
description: "The machine type of server (n1-highcpu-2, n1-highcpu-2-d, etc)"
|
|
38
|
+
|
|
39
|
+
option :image,
|
|
40
|
+
short: "-I IMAGE",
|
|
41
|
+
long: "--gce-image IMAGE",
|
|
42
|
+
description: "The Image for the server"
|
|
43
|
+
|
|
44
|
+
option :image_project,
|
|
45
|
+
long: "--gce-image-project IMAGE_PROJECT",
|
|
46
|
+
description: "The project-id containing the Image (debian-cloud, centos-cloud, etc)"
|
|
47
|
+
|
|
48
|
+
option :boot_disk_name,
|
|
49
|
+
long: "--gce-boot-disk-name DISK",
|
|
50
|
+
description: "Name of persistent boot disk; default is to use the server name"
|
|
51
|
+
|
|
52
|
+
option :boot_disk_size,
|
|
53
|
+
long: "--gce-boot-disk-size SIZE",
|
|
54
|
+
description: "Size of the persistent boot disk between 10 and 10000 GB, specified in GB; default is '10' GB",
|
|
55
|
+
default: "10"
|
|
56
|
+
|
|
57
|
+
option :boot_disk_ssd,
|
|
58
|
+
long: "--[no-]gce-boot-disk-ssd",
|
|
59
|
+
description: "Use pd-ssd boot disk; default is pd-standard boot disk",
|
|
60
|
+
boolean: true,
|
|
61
|
+
default: false
|
|
62
|
+
|
|
63
|
+
option :boot_disk_autodelete,
|
|
64
|
+
long: "--[no-]gce-boot-disk-autodelete",
|
|
65
|
+
description: "Delete boot disk when server is deleted.",
|
|
66
|
+
boolean: true,
|
|
67
|
+
default: true
|
|
68
|
+
|
|
69
|
+
option :additional_disks,
|
|
70
|
+
long: "--gce-additional-disks DISKS",
|
|
71
|
+
short: "-D DISKS",
|
|
72
|
+
description: "Names of additional disks, comma-separated, to attach to this server (NOTE: this will not create them)",
|
|
73
|
+
proc: Proc.new { |disks| disks.split(",") },
|
|
74
|
+
default: []
|
|
75
|
+
|
|
76
|
+
option :auto_restart,
|
|
77
|
+
long: "--[no-]gce-auto-server-restart",
|
|
78
|
+
description: "GCE can automatically restart your server if it is terminated for non-user-initiated reasons; enabled by default.",
|
|
79
|
+
boolean: true,
|
|
80
|
+
default: true
|
|
81
|
+
|
|
82
|
+
option :auto_migrate,
|
|
83
|
+
long: "--[no-]gce-auto-server-migrate",
|
|
84
|
+
description: "GCE can migrate your server to other hardware without downtime prior to periodic infrastructure maintenance, otherwise the server is terminated; enabled by default.",
|
|
85
|
+
boolean: true,
|
|
86
|
+
default: true
|
|
87
|
+
|
|
88
|
+
option :can_ip_forward,
|
|
89
|
+
long: "--[no-]gce-can-ip-forward",
|
|
90
|
+
description: "Allow server network forwarding",
|
|
91
|
+
boolean: true,
|
|
92
|
+
default: false
|
|
93
|
+
|
|
94
|
+
option :network,
|
|
95
|
+
long: "--gce-network NETWORK",
|
|
96
|
+
description: "The network for this server; default is 'default'",
|
|
97
|
+
default: "default"
|
|
98
|
+
|
|
99
|
+
option :tags,
|
|
100
|
+
short: "-T TAG1,TAG2,TAG3",
|
|
101
|
+
long: "--gce-tags TAG1,TAG2,TAG3",
|
|
102
|
+
description: "Tags for this server",
|
|
103
|
+
proc: Proc.new { |tags| tags.split(",") },
|
|
104
|
+
default: []
|
|
105
|
+
|
|
106
|
+
option :metadata,
|
|
107
|
+
long: "--gce-metadata Key=Value[,Key=Value...]",
|
|
108
|
+
description: "Additional metadata for this server",
|
|
109
|
+
proc: Proc.new { |metadata| metadata.split(",") },
|
|
110
|
+
default: []
|
|
111
|
+
|
|
112
|
+
option :service_account_scopes,
|
|
113
|
+
long: "--gce-service-account-scopes SCOPE1,SCOPE2,SCOPE3",
|
|
114
|
+
proc: Proc.new { |service_account_scopes| service_account_scopes.split(",") },
|
|
115
|
+
description: "Service account scopes for this server",
|
|
116
|
+
default: []
|
|
117
|
+
|
|
118
|
+
option :service_account_name,
|
|
119
|
+
long: "--gce-service-account-name NAME",
|
|
120
|
+
description: "Service account name for this server, typically in the form of '123845678986@project.gserviceaccount.com'; default is 'default'",
|
|
121
|
+
default: "default"
|
|
122
|
+
|
|
123
|
+
option :use_private_ip,
|
|
124
|
+
long: "--gce-use-private-ip",
|
|
125
|
+
description: "if used, Chef will attempt to bootstrap the device using the private IP; default is disabled (use public IP)",
|
|
126
|
+
boolean: true,
|
|
127
|
+
default: false
|
|
128
|
+
|
|
129
|
+
option :public_ip,
|
|
130
|
+
long: "--gce-public-ip IP_ADDRESS",
|
|
131
|
+
description: "EPHEMERAL or static IP address or NONE; default is 'EPHEMERAL'",
|
|
132
|
+
default: "EPHEMERAL"
|
|
133
|
+
|
|
134
|
+
option :gce_email,
|
|
135
|
+
long: "--gce-email EMAIL_ADDRESS",
|
|
136
|
+
description: "email address of the logged-in Google Cloud user; required for bootstrapping windows hosts"
|
|
137
|
+
|
|
138
|
+
deps do
|
|
139
|
+
require "gcewinpass"
|
|
140
|
+
end
|
|
21
141
|
|
|
22
|
-
|
|
142
|
+
def before_exec_command
|
|
143
|
+
super
|
|
144
|
+
|
|
145
|
+
@create_options = {
|
|
146
|
+
name: instance_name,
|
|
147
|
+
image: locate_config_value(:image),
|
|
148
|
+
image_project: locate_config_value(:image_project),
|
|
149
|
+
network: locate_config_value(:network),
|
|
150
|
+
public_ip: locate_config_value(:public_ip),
|
|
151
|
+
auto_migrate: locate_config_value(:auto_migrate),
|
|
152
|
+
auto_restart: locate_config_value(:auto_restart),
|
|
153
|
+
boot_disk_autodelete: locate_config_value(:boot_disk_autodelete),
|
|
154
|
+
boot_disk_name: locate_config_value(:boot_disk_name),
|
|
155
|
+
boot_disk_size: boot_disk_size,
|
|
156
|
+
boot_disk_ssd: locate_config_value(:boot_disk_ssd),
|
|
157
|
+
additional_disks: locate_config_value(:additional_disks),
|
|
158
|
+
can_ip_forward: locate_config_value(:can_ip_forward),
|
|
159
|
+
machine_type: locate_config_value(:machine_type),
|
|
160
|
+
service_account_scopes: locate_config_value(:service_account_scopes),
|
|
161
|
+
service_account_name: locate_config_value(:service_account_name),
|
|
162
|
+
metadata: metadata,
|
|
163
|
+
tags: locate_config_value(:tags),
|
|
164
|
+
}
|
|
165
|
+
end
|
|
23
166
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
167
|
+
def set_default_config
|
|
168
|
+
# dumb hack for knife-cloud, which expects the user to pass in the WinRM password to use when bootstrapping.
|
|
169
|
+
# We won't know the password until the instance is created and we forceably reset it.
|
|
170
|
+
config[:winrm_password] = "will_change_this_later"
|
|
171
|
+
end
|
|
30
172
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
:short => "-m MACHINE_TYPE",
|
|
38
|
-
:long => "--gce-machine-type MACHINE_TYPE",
|
|
39
|
-
:description => "The machine type of server (n1-highcpu-2, n1-highcpu-2-d, etc)",
|
|
40
|
-
:required => true
|
|
41
|
-
|
|
42
|
-
option :image,
|
|
43
|
-
:short => "-I IMAGE",
|
|
44
|
-
:long => "--gce-image IMAGE",
|
|
45
|
-
:description => "The Image for the server",
|
|
46
|
-
:required => true
|
|
47
|
-
|
|
48
|
-
option :image_project_id,
|
|
49
|
-
:long => "--gce-image-project-id IMAGE_PROJECT_ID",
|
|
50
|
-
:description => "The project-id containing the Image (debian-cloud, centos-cloud, etc)",
|
|
51
|
-
:default => ""
|
|
52
|
-
|
|
53
|
-
option :zone,
|
|
54
|
-
:short => "-Z ZONE",
|
|
55
|
-
:long => "--gce-zone ZONE",
|
|
56
|
-
:description => "The Zone for this server"
|
|
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
|
-
|
|
80
|
-
option :network,
|
|
81
|
-
:short => "-n NETWORK",
|
|
82
|
-
:long => "--gce-network NETWORK",
|
|
83
|
-
:description => "The network for this server; default is 'default'",
|
|
84
|
-
:default => "default"
|
|
85
|
-
|
|
86
|
-
option :tags,
|
|
87
|
-
:short => "-T TAG1,TAG2,TAG3",
|
|
88
|
-
:long => "--gce-tags TAG1,TAG2,TAG3",
|
|
89
|
-
:description => "Tags for this server",
|
|
90
|
-
:proc => Proc.new { |tags| tags.split(',') },
|
|
91
|
-
:default => []
|
|
92
|
-
|
|
93
|
-
option :metadata,
|
|
94
|
-
:long => "--gce-metadata Key=Value[,Key=Value...]",
|
|
95
|
-
:description => "Additional metadata for this server",
|
|
96
|
-
:proc => Proc.new { |metadata| metadata.split(',') },
|
|
97
|
-
:default => []
|
|
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
|
-
|
|
121
|
-
option :chef_node_name,
|
|
122
|
-
:short => "-N NAME",
|
|
123
|
-
:long => "--node-name NAME",
|
|
124
|
-
:description => "The Chef node name for your new node"
|
|
125
|
-
|
|
126
|
-
option :ssh_user,
|
|
127
|
-
:short => "-x USERNAME",
|
|
128
|
-
:long => "--ssh-user USERNAME",
|
|
129
|
-
:description => "The ssh username; default is 'root'",
|
|
130
|
-
:default => "root"
|
|
131
|
-
|
|
132
|
-
option :ssh_password,
|
|
133
|
-
:short => "-P PASSWORD",
|
|
134
|
-
:long => "--ssh-password PASSWORD",
|
|
135
|
-
:description => "The ssh password"
|
|
136
|
-
|
|
137
|
-
option :ssh_port,
|
|
138
|
-
:short => "-p PORT",
|
|
139
|
-
:long => "--ssh-port PORT",
|
|
140
|
-
:description => "The ssh port; default is '22'",
|
|
141
|
-
:default => "22"
|
|
142
|
-
|
|
143
|
-
option :ssh_gateway,
|
|
144
|
-
:short => "-w GATEWAY",
|
|
145
|
-
:long => "--ssh-gateway GATEWAY",
|
|
146
|
-
:description => "The ssh gateway server"
|
|
147
|
-
|
|
148
|
-
option :identity_file,
|
|
149
|
-
:short => "-i IDENTITY_FILE",
|
|
150
|
-
:long => "--identity-file IDENTITY_FILE",
|
|
151
|
-
:description => "The SSH identity file used for authentication"
|
|
152
|
-
|
|
153
|
-
option :prerelease,
|
|
154
|
-
:long => "--prerelease",
|
|
155
|
-
:description => "Install the pre-release chef gems"
|
|
156
|
-
|
|
157
|
-
option :bootstrap_version,
|
|
158
|
-
:long => "--bootstrap-version VERSION",
|
|
159
|
-
:description => "The version of Chef to install"
|
|
160
|
-
|
|
161
|
-
option :distro,
|
|
162
|
-
:short => "-d DISTRO",
|
|
163
|
-
:long => "--distro DISTRO",
|
|
164
|
-
:description => "Bootstrap a distro using a template; default is 'chef-full'",
|
|
165
|
-
:default => 'chef-full'
|
|
166
|
-
|
|
167
|
-
option :template_file,
|
|
168
|
-
:long => "--template-file TEMPLATE",
|
|
169
|
-
:description => "Full path to location of template to use",
|
|
170
|
-
:default => false
|
|
171
|
-
|
|
172
|
-
option :run_list,
|
|
173
|
-
:short => "-r RUN_LIST",
|
|
174
|
-
:long => "--run-list RUN_LIST",
|
|
175
|
-
:description => "Comma separated list of roles/recipes to apply",
|
|
176
|
-
:proc => lambda { |o| o.split(/[\s,]+/) }
|
|
177
|
-
|
|
178
|
-
option :json_attributes,
|
|
179
|
-
:short => "-j JSON",
|
|
180
|
-
:long => "--json-attributes JSON",
|
|
181
|
-
:description => "A JSON string to be added to the first run of chef-client",
|
|
182
|
-
:proc => lambda { |o| JSON.parse(o) }
|
|
183
|
-
|
|
184
|
-
option :host_key_verify,
|
|
185
|
-
:long => "--[no-]host-key-verify",
|
|
186
|
-
:description => "Verify host key, enabled by default.",
|
|
187
|
-
:boolean => true,
|
|
188
|
-
:default => true
|
|
189
|
-
|
|
190
|
-
option :compute_user_data,
|
|
191
|
-
:long => "--user-data USER_DATA_FILE",
|
|
192
|
-
:short => "-u USER_DATA_FILE",
|
|
193
|
-
:description => "The Google Compute User Data file to provision the server with"
|
|
194
|
-
|
|
195
|
-
option :hint,
|
|
196
|
-
:long => "--hint HINT_NAME[=HINT_FILE]",
|
|
197
|
-
:description => "Specify Ohai Hint to be set on the bootstrap target. Use multiple --hint options to specify multiple hints.",
|
|
198
|
-
:proc => Proc.new { |h|
|
|
199
|
-
Chef::Config[:knife][:hints] ||= {}
|
|
200
|
-
name, path = h.split("=")
|
|
201
|
-
Chef::Config[:knife][:hints][name] = path ? JSON.parse(::File.read(path)) : Hash.new
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
option :secret,
|
|
205
|
-
:short => "-s SECRET",
|
|
206
|
-
:long => "--secret ",
|
|
207
|
-
:description => "The secret key to use to encrypt data bag item values",
|
|
208
|
-
:proc => lambda { |s| Chef::Config[:knife][:secret] = s }
|
|
209
|
-
|
|
210
|
-
option :secret_file,
|
|
211
|
-
:long => "--secret-file SECRET_FILE",
|
|
212
|
-
:description => "A file containing the secret key to use to encrypt data bag item values",
|
|
213
|
-
:proc => lambda { |sf| Chef::Config[:knife][:secret_file] = sf }
|
|
214
|
-
|
|
215
|
-
def tcp_test_ssh(hostname, ssh_port)
|
|
216
|
-
tcp_socket = TCPSocket.new(hostname, ssh_port)
|
|
217
|
-
readable = IO.select([tcp_socket], nil, nil, 5)
|
|
218
|
-
if readable
|
|
219
|
-
Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}")
|
|
220
|
-
yield
|
|
221
|
-
true
|
|
222
|
-
else
|
|
223
|
-
false
|
|
224
|
-
end
|
|
225
|
-
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
|
226
|
-
sleep 2
|
|
227
|
-
false
|
|
228
|
-
rescue Errno::EPERM, Errno::ETIMEDOUT
|
|
229
|
-
false
|
|
230
|
-
ensure
|
|
231
|
-
tcp_socket && tcp_socket.close
|
|
232
|
-
end
|
|
173
|
+
def validate_params!
|
|
174
|
+
check_for_missing_config_values!(:machine_type, :image, :boot_disk_size, :network)
|
|
175
|
+
raise "You must supply an instance name." if @name_args.first.nil?
|
|
176
|
+
raise "Boot disk size must be between 10 and 10,000" unless valid_disk_size?(boot_disk_size)
|
|
177
|
+
raise "Please provide your Google Cloud console email address via --gce-email. " \
|
|
178
|
+
"It is required when resetting passwords on Windows hosts." if locate_config_value(:bootstrap_protocol) == "winrm" && locate_config_value(:gce_email).nil?
|
|
233
179
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
end
|
|
180
|
+
super
|
|
181
|
+
end
|
|
237
182
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
print(".") until tunnel_test_ssh(hostname) {
|
|
241
|
-
sleep @initial_sleep_delay ||= 40
|
|
242
|
-
puts("done")
|
|
243
|
-
}
|
|
244
|
-
end
|
|
183
|
+
def before_bootstrap
|
|
184
|
+
super
|
|
245
185
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
gw_host, gw_port = gw_host.split(':')
|
|
249
|
-
gateway = Net::SSH::Gateway.new(gw_host, gw_user, :port => gw_port || 22)
|
|
250
|
-
status = false
|
|
251
|
-
gateway.open(hostname, config[:ssh_port]) do |local_tunnel_port|
|
|
252
|
-
status = tcp_test_ssh('localhost', local_tunnel_port, &block)
|
|
253
|
-
end
|
|
254
|
-
status
|
|
255
|
-
rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
|
256
|
-
sleep 2
|
|
257
|
-
false
|
|
258
|
-
rescue Errno::EPERM, Errno::ETIMEDOUT
|
|
259
|
-
false
|
|
260
|
-
end
|
|
186
|
+
config[:chef_node_name] = locate_config_value(:chef_node_name) ? locate_config_value(:chef_node_name) : instance_name
|
|
187
|
+
config[:bootstrap_ip_address] = ip_address_for_bootstrap
|
|
261
188
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
puts("done")
|
|
266
|
-
}
|
|
189
|
+
if locate_config_value(:bootstrap_protocol) == "winrm"
|
|
190
|
+
ui.msg("Resetting the Windows login password so the bootstrap can continue...")
|
|
191
|
+
config[:winrm_password] = reset_windows_password
|
|
267
192
|
end
|
|
193
|
+
end
|
|
268
194
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
195
|
+
# overriding this from Chef::Knife::Cloud::ServerCreateCommand.
|
|
196
|
+
#
|
|
197
|
+
# This gets called in validate_params! in that class before our #before_bootstrap
|
|
198
|
+
# is called, in which it randomly generates a node name, which means we never default
|
|
199
|
+
# to the instance name in our #before_bootstrap method. Instead, we'll just nil this
|
|
200
|
+
# and allow our class here to do The Right Thing.
|
|
201
|
+
def get_node_name(_name, _prefix)
|
|
202
|
+
nil
|
|
203
|
+
end
|
|
276
204
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
client.disks.get(:disk => disk, :zone => selflink2name(zone))
|
|
281
|
-
rescue Google::Compute::ResourceNotFound
|
|
282
|
-
# disk does not exist
|
|
283
|
-
# continue provisioning
|
|
284
|
-
false
|
|
285
|
-
else
|
|
286
|
-
true
|
|
287
|
-
end
|
|
205
|
+
def project
|
|
206
|
+
locate_config_value(:gce_project)
|
|
207
|
+
end
|
|
288
208
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
ui.info(".")
|
|
293
|
-
sleep 1
|
|
294
|
-
disk = client.zoneOperations.get(:name => disk,
|
|
295
|
-
:operation => operation,
|
|
296
|
-
:zone => selflink2name(zone))
|
|
297
|
-
end
|
|
298
|
-
disk.target_link
|
|
299
|
-
end
|
|
300
|
-
rescue Timeout::Error
|
|
301
|
-
ui.error("Timeout exceeded with disk status: " + disk.status)
|
|
302
|
-
exit 1
|
|
303
|
-
end
|
|
209
|
+
def zone
|
|
210
|
+
locate_config_value(:gce_zone)
|
|
211
|
+
end
|
|
304
212
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
bootstrap.config[:run_list] = config[:run_list]
|
|
309
|
-
bootstrap.config[:ssh_user] = config[:ssh_user]
|
|
310
|
-
bootstrap.config[:ssh_port] = config[:ssh_port]
|
|
311
|
-
bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
|
|
312
|
-
bootstrap.config[:identity_file] = config[:identity_file]
|
|
313
|
-
bootstrap.config[:chef_node_name] = config[:chef_node_name] || instance.name
|
|
314
|
-
bootstrap.config[:prerelease] = config[:prerelease]
|
|
315
|
-
bootstrap.config[:bootstrap_version] = config[:bootstrap_version]
|
|
316
|
-
bootstrap.config[:first_boot_attributes] = config[:json_attributes]
|
|
317
|
-
bootstrap.config[:distro] = config[:distro]
|
|
318
|
-
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
|
|
319
|
-
bootstrap.config[:template_file] = config[:template_file]
|
|
320
|
-
bootstrap.config[:environment] = config[:environment]
|
|
321
|
-
bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
|
|
322
|
-
bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
|
|
323
|
-
bootstrap.config[:secret] = locate_config_value(:secret)
|
|
324
|
-
bootstrap.config[:secret_file] = locate_config_value(:secret_file)
|
|
325
|
-
|
|
326
|
-
# may be needed for vpc_mode
|
|
327
|
-
bootstrap.config[:host_key_verify] = config[:host_key_verify]
|
|
328
|
-
# Modify global configuration state to ensure hint gets set by
|
|
329
|
-
# knife-bootstrap
|
|
330
|
-
Chef::Config[:knife][:hints] ||= {}
|
|
331
|
-
Chef::Config[:knife][:hints]["gce"] ||= {}
|
|
332
|
-
Chef::Config[:knife][:hints]["google"] ||= {}
|
|
333
|
-
bootstrap
|
|
334
|
-
end
|
|
213
|
+
def email
|
|
214
|
+
locate_config_value(:gce_email)
|
|
215
|
+
end
|
|
335
216
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
begin
|
|
354
|
-
machine_type = client.machine_types.get(:name => config[:machine_type],
|
|
355
|
-
:zone => selflink2name(zone)).self_link
|
|
356
|
-
rescue Google::Compute::ResourceNotFound
|
|
357
|
-
ui.error("MachineType '#{config[:machine_type]}' not found")
|
|
358
|
-
exit 1
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
# this parameter is a string during the post and boolean otherwise
|
|
362
|
-
if config[:auto_restart] then
|
|
363
|
-
auto_restart = 'true'
|
|
364
|
-
else
|
|
365
|
-
auto_restart = 'false'
|
|
366
|
-
end
|
|
367
|
-
|
|
368
|
-
if config[:auto_migrate] then
|
|
369
|
-
auto_migrate = 'MIGRATE'
|
|
370
|
-
else
|
|
371
|
-
auto_migrate = 'TERMINATE'
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
(checked_custom, checked_all) = false
|
|
375
|
-
begin
|
|
376
|
-
image_project = config[:image_project_id]
|
|
377
|
-
# use zone url to determine project name
|
|
378
|
-
zone =~ Regexp.new('/projects/(.*?)/')
|
|
379
|
-
project = $1
|
|
380
|
-
if image_project.to_s.empty?
|
|
381
|
-
unless checked_custom
|
|
382
|
-
checked_custom = true
|
|
383
|
-
ui.info("Looking for Image '#{config[:image]}' in Project '#{project}'")
|
|
384
|
-
image = client.images.get(:project=>project, :name=>config[:image]).self_link
|
|
385
|
-
else
|
|
386
|
-
case config[:image].downcase
|
|
387
|
-
when /debian/
|
|
388
|
-
project = 'debian-cloud'
|
|
389
|
-
ui.info("Looking for Image '#{config[:image]}' in Project '#{project}'")
|
|
390
|
-
when /centos/
|
|
391
|
-
project = 'centos-cloud'
|
|
392
|
-
ui.info("Looking for Image '#{config[:image]}' in Project '#{project}'")
|
|
393
|
-
end
|
|
394
|
-
checked_all = true
|
|
395
|
-
image = client.images.get(:project=>project, :name=>config[:image]).self_link
|
|
396
|
-
end
|
|
397
|
-
else
|
|
398
|
-
checked_all = true
|
|
399
|
-
project = image_project
|
|
400
|
-
image = client.images.get(:project=>project, :name=>config[:image]).self_link
|
|
401
|
-
end
|
|
402
|
-
ui.info("Found Image '#{config[:image]}' in Project '#{project}'")
|
|
403
|
-
rescue Google::Compute::ResourceNotFound
|
|
404
|
-
unless checked_all then
|
|
405
|
-
retry
|
|
406
|
-
else
|
|
407
|
-
ui.error("Image '#{config[:image]}' not found")
|
|
408
|
-
exit 1
|
|
409
|
-
end
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
begin
|
|
413
|
-
boot_disk_size = config[:boot_disk_size].to_i
|
|
414
|
-
raise if !boot_disk_size.between?(10, 10000)
|
|
415
|
-
rescue
|
|
416
|
-
ui.error("Size of the persistent boot disk must be between 10 and 10000 GB.")
|
|
417
|
-
exit 1
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
if config[:boot_disk_name].to_s.empty? then
|
|
421
|
-
boot_disk_name = @name_args.first
|
|
422
|
-
else
|
|
423
|
-
boot_disk_name = config[:boot_disk_name]
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
ui.info("Waiting for the disk insert operation to complete")
|
|
427
|
-
boot_disk_insert = client.disks.insert(:sourceImage => image,
|
|
428
|
-
:zone => selflink2name(zone),
|
|
429
|
-
:name => boot_disk_name,
|
|
430
|
-
:sizeGb => boot_disk_size)
|
|
431
|
-
boot_disk_target_link = wait_for_disk(boot_disk_insert, boot_disk_insert.name, zone)
|
|
432
|
-
|
|
433
|
-
begin
|
|
434
|
-
network = client.networks.get(config[:network]).self_link
|
|
435
|
-
rescue Google::Compute::ResourceNotFound
|
|
436
|
-
ui.error("Network '#{config[:network]}' not found")
|
|
437
|
-
exit 1
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
metadata = config[:metadata].collect{|pair| Hash[*pair.split('=')] }
|
|
441
|
-
network_interface = {'network'=>network}
|
|
442
|
-
|
|
443
|
-
if config[:public_ip] == 'EPHEMERAL'
|
|
444
|
-
network_interface.merge!('accessConfigs' =>[{"name"=>"External NAT",
|
|
445
|
-
"type"=> "ONE_TO_ONE_NAT"}])
|
|
446
|
-
elsif config[:public_ip] =~ /\d+\.\d+\.\d+\.\d+/
|
|
447
|
-
network_interface.merge!('accessConfigs' =>[{"name"=>"External NAT",
|
|
448
|
-
"type"=>"ONE_TO_ONE_NAT", "natIP"=>config[:public_ip] }])
|
|
449
|
-
elsif config[:public_ip] == 'NONE'
|
|
450
|
-
# do nothing
|
|
451
|
-
else
|
|
452
|
-
ui.error("Invalid public ip value : #{config[:public_ip]}")
|
|
453
|
-
exit 1
|
|
454
|
-
end
|
|
455
|
-
|
|
456
|
-
ui.info("Waiting for the create server operation to complete")
|
|
457
|
-
if !config[:service_account_scopes].any?
|
|
458
|
-
zone_operation = client.instances.create(:name => @name_args.first,
|
|
459
|
-
:zone => selflink2name(zone),
|
|
460
|
-
:machineType => machine_type,
|
|
461
|
-
:disks => [{
|
|
462
|
-
'boot' => true,
|
|
463
|
-
'type' => 'PERSISTENT',
|
|
464
|
-
'mode' => 'READ_WRITE',
|
|
465
|
-
'deviceName' => selflink2name(boot_disk_target_link),
|
|
466
|
-
'source' => boot_disk_target_link
|
|
467
|
-
}],
|
|
468
|
-
:networkInterfaces => [network_interface],
|
|
469
|
-
:scheduling => {
|
|
470
|
-
'automaticRestart' => auto_restart,
|
|
471
|
-
'onHostMaintenance' => auto_migrate
|
|
472
|
-
},
|
|
473
|
-
:metadata => { 'items' => metadata },
|
|
474
|
-
:tags => { 'items' => config[:tags] }
|
|
475
|
-
)
|
|
476
|
-
else
|
|
477
|
-
zone_operation = client.instances.create(:name => @name_args.first,
|
|
478
|
-
:zone=> selflink2name(zone),
|
|
479
|
-
:machineType => machine_type,
|
|
480
|
-
:disks => [{
|
|
481
|
-
'boot' => true,
|
|
482
|
-
'type' => 'PERSISTENT',
|
|
483
|
-
'mode' => 'READ_WRITE',
|
|
484
|
-
'deviceName' => selflink2name(boot_disk_target_link),
|
|
485
|
-
'source' => boot_disk_target_link
|
|
486
|
-
}],
|
|
487
|
-
:networkInterfaces => [network_interface],
|
|
488
|
-
:serviceAccounts => [{
|
|
489
|
-
'kind' => 'compute#serviceAccount',
|
|
490
|
-
'email' => config[:service_account_name],
|
|
491
|
-
'scopes' => config[:service_account_scopes]
|
|
492
|
-
}],
|
|
493
|
-
:scheduling => {
|
|
494
|
-
'automaticRestart' => auto_restart,
|
|
495
|
-
'onHostMaintenance' => auto_migrate
|
|
496
|
-
},
|
|
497
|
-
:metadata => { 'items'=>metadata },
|
|
498
|
-
:tags => { 'items' => config[:tags] }
|
|
499
|
-
)
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
until zone_operation.progress.to_i == 100
|
|
503
|
-
ui.info(".")
|
|
504
|
-
sleep 1
|
|
505
|
-
zone_operation = client.zoneOperations.get(:name=>zone_operation, :operation=>zone_operation.name, :zone=>selflink2name(zone))
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
ui.info("Waiting for the servers to be in running state")
|
|
509
|
-
|
|
510
|
-
@instance = client.instances.get(:name=>@name_args.first, :zone=>selflink2name(zone))
|
|
511
|
-
msg_pair("Instance Name", @instance.name)
|
|
512
|
-
msg_pair("Machine Type", selflink2name(@instance.machine_type))
|
|
513
|
-
msg_pair("Image", selflink2name(config[:image]))
|
|
514
|
-
msg_pair("Zone", selflink2name(@instance.zone))
|
|
515
|
-
msg_pair("Tags", @instance.tags.has_key?("items") ? @instance.tags["items"].join(",") : "None")
|
|
516
|
-
until @instance.status == "RUNNING"
|
|
517
|
-
sleep 3
|
|
518
|
-
msg_pair("Status", @instance.status.downcase)
|
|
519
|
-
@instance = client.instances.get(:name=>@name_args.first, :zone=>selflink2name(zone))
|
|
520
|
-
end
|
|
521
|
-
|
|
522
|
-
msg_pair("Public IP Address", public_ips(@instance)) unless public_ips(@instance).empty?
|
|
523
|
-
msg_pair("Private IP Address", private_ips(@instance))
|
|
524
|
-
ui.info("\n#{ui.color("Waiting for server", :magenta)}")
|
|
525
|
-
|
|
526
|
-
ui.info("\n")
|
|
527
|
-
ui.info(ui.color("Waiting for sshd", :magenta))
|
|
528
|
-
wait_for_sshd(ssh_connect_host)
|
|
529
|
-
bootstrap_for_node(@instance,ssh_connect_host).run
|
|
530
|
-
ui.info("\n")
|
|
531
|
-
ui.info("Complete!!")
|
|
217
|
+
def ip_address_for_bootstrap
|
|
218
|
+
ip = locate_config_value(:use_private_ip) ? private_ip_for(server) : public_ip_for(server)
|
|
219
|
+
|
|
220
|
+
raise "Unable to determine instance IP address for bootstrapping" if ip == "unknown"
|
|
221
|
+
ip
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def instance_name
|
|
225
|
+
@name_args.first
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def metadata
|
|
229
|
+
locate_config_value(:metadata).each_with_object({}) do |item, memo|
|
|
230
|
+
key, value = item.split("=")
|
|
231
|
+
memo[key] = value
|
|
532
232
|
end
|
|
533
233
|
end
|
|
234
|
+
|
|
235
|
+
def boot_disk_size
|
|
236
|
+
locate_config_value(:boot_disk_size).to_i
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def reset_windows_password
|
|
240
|
+
GoogleComputeWindowsPassword.new(
|
|
241
|
+
project: project,
|
|
242
|
+
zone: zone,
|
|
243
|
+
instance_name: instance_name,
|
|
244
|
+
email: email,
|
|
245
|
+
username: locate_config_value(:winrm_user),
|
|
246
|
+
debug: gcewinpass_debug_mode
|
|
247
|
+
).new_password
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def gcewinpass_debug_mode
|
|
251
|
+
Chef::Config[:log_level] == :debug
|
|
252
|
+
end
|
|
534
253
|
end
|
|
535
254
|
end
|