Class: Beaker::GoogleCompute
- Inherits:
-
Hypervisor
- Object
- Hypervisor
- Beaker::GoogleCompute
- Defined in:
- lib/beaker/hypervisor/google_compute.rb
Overview
Beaker support for the Google Compute Engine.
Direct Known Subclasses
Constant Summary collapse
- SLEEPWAIT =
5- WINDOWS_IMAGE_PROJECT =
%w[windows-cloud windows-sql-cloud].freeze
Instance Method Summary collapse
-
#cleanup ⇒ Object
Shutdown and destroy virtual machines in the Google Compute Engine, including their associated disks and firewall rules.
-
#connection_preference(host) ⇒ Object
IP is the only way we can be sure to connect TODO: This isn’t being called rubocop:disable Lint/UnusedMethodArgument.
-
#find_google_ssh_private_key ⇒ String
Try to find the private ssh key file.
-
#find_google_ssh_public_key ⇒ String
Try to find the public key file based on the location of the private key or provided data.
-
#initialize(google_hosts, options) ⇒ GoogleCompute
constructor
Create a new instance of the Google Compute Engine hypervisor object.
-
#provision ⇒ Object
Create and configure virtual machines in the Google Compute Engine, including their associated disks and firewall rules.
Constructor Details
#initialize(google_hosts, options) ⇒ GoogleCompute
Create a new instance of the Google Compute Engine hypervisor object
ONLY be of platforms /centos-*/, /debian-*/, /rhel-*/, /suse-*/. Only supports the Google Compute provided templates.
configuration values @option options [String] :gce_project The Google Compute Project name to connect to
service account keyfile
service account key
Compute service account
used to create instances, defaults to n1-highmem-2
before quiting and exiting with failure
80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/beaker/hypervisor/google_compute.rb', line 80 def initialize(google_hosts, ) require 'beaker/hypervisor/google_compute_helper' super = @logger = [:logger] @hosts = google_hosts @external_firewall_name = '' @internal_firewall_name = '' @gce_helper = GoogleComputeHelper.new() end |
Instance Method Details
#cleanup ⇒ Object
Shutdown and destroy virtual machines in the Google Compute Engine, including their associated disks and firewall rules
270 271 272 273 274 275 276 277 278 279 |
# File 'lib/beaker/hypervisor/google_compute.rb', line 270 def cleanup @gce_helper.delete_firewall(@external_firewall_name) @gce_helper.delete_firewall(@internal_firewall_name) @hosts.each do |host| # TODO: Delete any other disks attached during the instance creation @gce_helper.delete_instance(host['vmhostname']) @logger.debug("Deleted Google Compute instance #{host['vmhostname']} for #{host.name}") end end |
#connection_preference(host) ⇒ Object
IP is the only way we can be sure to connect TODO: This isn’t being called rubocop:disable Lint/UnusedMethodArgument
51 52 53 |
# File 'lib/beaker/hypervisor/google_compute.rb', line 51 def connection_preference(host) [:ip] end |
#find_google_ssh_private_key ⇒ String
Try to find the private ssh key file
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/beaker/hypervisor/google_compute.rb', line 20 def find_google_ssh_private_key private_keyfile = ENV.fetch('BEAKER_gce_ssh_public_key', File.join(Dir.home, '.ssh', 'google_compute_engine')) if [:gce_ssh_private_key] && !File.exist?(private_keyfile) private_keyfile = [:gce_ssh_private_key] end raise("Could not find GCE Private SSH key at '#{keyfile}'") unless File.exist?(private_keyfile) [:gce_ssh_private_key] = private_keyfile private_keyfile end |
#find_google_ssh_public_key ⇒ String
Try to find the public key file based on the location of the private key or provided data
38 39 40 41 42 43 44 45 46 |
# File 'lib/beaker/hypervisor/google_compute.rb', line 38 def find_google_ssh_public_key private_keyfile = find_google_ssh_private_key public_keyfile = private_keyfile << '.pub' public_keyfile = [:gce_ssh_public_key] if [:gce_ssh_public_key] && !File.exist?(public_keyfile) raise("Could not find GCE Public SSH key at '#{keyfile}'") unless File.exist?(public_keyfile) [:gce_ssh_public_key] = public_keyfile public_keyfile end |
#provision ⇒ Object
Create and configure virtual machines in the Google Compute Engine, including their associated disks and firewall rules
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/beaker/hypervisor/google_compute.rb', line 94 def provision test_group_identifier = "beaker-#{SecureRandom.hex(4)}" # set firewall to open pe ports network = @gce_helper.get_network @external_firewall_name = "#{test_group_identifier}-external" # Always allow ssh from anywhere as it's needed for Beaker to run @gce_helper.create_firewall( @external_firewall_name, network, allow: [:gce_ports] + ['22/tcp'], source_ranges: ['0.0.0.0/0'], target_tags: [test_group_identifier], ) @logger.debug("Created External Google Compute firewall #{@external_firewall_name}") # Create a firewall that opens everything between all the hosts in this test group @internal_firewall_name = "#{test_group_identifier}-internal" internal_ports = ['1-65535/tcp', '1-65535/udp', '-1/icmp'] @gce_helper.create_firewall( @internal_firewall_name, network, allow: internal_ports, source_tags: [test_group_identifier], target_tags: [test_group_identifier], ) @logger.debug("Created test group Google Compute firewall #{@internal_firewall_name}") @hosts.each do |host| machine_type_name = ENV.fetch('BEAKER_gce_machine_type', host['gce_machine_type']) raise "Must provide a machine type name in 'gce_machine_type'." if machine_type_name.nil? # Get the GCE machine type object for this host machine_type = @gce_helper.get_machine_type(machine_type_name) if machine_type.nil? raise "Unable to find machine type named #{machine_type_name} in region #{@compute.default_zone}" end # Find the image to use to create the new VM. # Either `image` or `family` must be set in the configuration. Accepted formats # for the image and family: # - {project}/{image} # - {project}/{family} # - {image} # - {family} # # If a {project} is not specified, default to the project provided in the # BEAKER_gce_project environment variable if host[:image] image_selector = host[:image] # Do we have a project name? if image_selector.include?('/') image_project, image_name = image_selector.split('/')[0..1] else image_project = @gce_helper.[:gce_project] image_name = image_selector end img = @gce_helper.get_image(image_project, image_name) raise "Unable to find image #{image_name} from project #{image_project}" if img.nil? elsif host[:family] image_selector = host[:family] # Do we have a project name? if image_selector.include?('/') image_project, family_name = image_selector.split('/') else image_project = @gce_helper.[:gce_project] family_name = image_selector end img = @gce_helper.get_latest_image_from_family(image_project, family_name) raise "Unable to find image in family #{family_name} from project #{image_project}" if img.nil? else raise('You must specify either :image or :family') end unique_host_id = "#{test_group_identifier}-#{generate_host_name}" boot_size = host['volume_size'] || img.disk_size_gb # The boot disk is created as part of the instance creation # TODO: Allow creation of other disks # disk = @gce_helper.create_disk(host["diskname"], img, size) # @logger.debug("Created Google Compute disk for #{host.name}: #{host["diskname"]}") # create new host name host['vmhostname'] = unique_host_id # add a new instance of the image operation = @gce_helper.create_instance(host['vmhostname'], img, machine_type, boot_size, host.name) unless operation.error.nil? raise "Unable to create Google Compute Instance #{ host.name }: [#{ operation.error.errors[0].code }] #{ operation.error.errors[0].message }" end @logger.debug("Created Google Compute instance for #{host.name}: #{host['vmhostname']}") instance = @gce_helper.get_instance(host['vmhostname']) @gce_helper.add_instance_tag(host['vmhostname'], test_group_identifier) @logger.debug("Added network tag #{test_group_identifier} to instance") # Make sure we have a non root/Adminsitor user to log in as initial_user = if host['user'] == 'root' || host['user'] == 'Administrator' || host['user'].empty? 'google_compute' else host['user'] end # add metadata to instance, if there is any to set # mdata = format_metadata # TODO: Set a configuration option for this to allow disabeling oslogin mdata = [ { key: 'ssh-keys', value: "#{initial_user}:#{File.read(find_google_ssh_public_key).strip}", }, # For now oslogin needs to be disabled as there's no way to log in as root and it would # take too much work on beaker to add sudo support to everything { key: 'enable-oslogin', value: 'FALSE', }, ] # Check for google's default windows images and turn on ssh if found if WINDOWS_IMAGE_PROJECT.include?(image_project) # Turn on SSH on GCP's default windows images mdata << { key: 'enable-windows-ssh', value: 'TRUE', } mdata << { key: 'sysprep-specialize-script-cmd', value: 'start /wait googet -noconfirm=true update && start /wait googet -noconfirm=true install google-compute-engine-ssh', # rubocop:disable Layout/LineLength } # Some versions of windows don't seem to add the OpenSSH directory to the path which prevents scp from working mdata << { key: 'sysprep-specialize-script-ps1', value: '[Environment]::SetEnvironmentVariable( "PATH", "$ENV:PATH;C:\Program Files\OpenSSH", [EnvironmentVariableTarget]::Machine )', # rubocop:disable Layout/LineLength } end unless mdata.empty? # Add the metadata to the host @gce_helper.(host['vmhostname'], mdata) @logger.debug("Added tags to Google Compute instance #{host.name}: #{host['vmhostname']}") end host['ip'] = instance.network_interfaces[0].access_configs[0].nat_ip if host['disable_root_ssh'] == true @logger.info('Not enabling root ssh as disable_root_ssh is true') else real_user = host['user'] host['user'] = initial_user # Set the ssh private key we need to use host.['ssh']['keys'] = [find_google_ssh_private_key] copy_ssh_to_root(host, ) enable_root_login(host, ) host['user'] = real_user # shut down connection, will reconnect on next exec host.close end @logger.debug("Instance ready: #{host['vmhostname']} for #{host.name}}") end end |