lib/beaker/hypervisor/google_compute.rb in beaker-google-0.1.0 vs lib/beaker/hypervisor/google_compute.rb in beaker-google-0.2.0

- old
+ new

@@ -1,102 +1,145 @@ require 'time' module Beaker - #Beaker support for the Google Compute Engine. + + # Beaker support for the Google Compute Engine. class GoogleCompute < Beaker::Hypervisor SLEEPWAIT = 5 - #number of hours before an instance is considered a zombie + + # Hours before an instance is considered a zombie ZOMBIE = 3 - #Create the array of metaData, each member being a hash with a :key and a :value. Sets - #:department, :project and :jenkins_build_url. + # Do some reasonable sleuthing on the SSH public key for GCE + def find_google_ssh_public_key + keyfile = ENV.fetch('BEAKER_gce_ssh_public_key', File.join(ENV['HOME'], '.ssh', 'google_compute_engine.pub')) + + if @options[:gce_ssh_public_key] && !File.exist?(keyfile) + keyfile = @options[:gce_ssh_public_key] + end + + raise("Could not find GCE Public SSH Key at '#{keyfile}'") unless File.exist?(keyfile) + + return keyfile + end + + # Create the array of metaData, each member being a hash with a :key and a + # :value. Sets :department, :project and :jenkins_build_url. def format_metadata [ {:key => :department, :value => @options[:department]}, {:key => :project, :value => @options[:project]}, - {:key => :jenkins_build_url, :value => @options[:jenkins_build_url]} ].delete_if { |member| member[:value].nil? or member[:value].empty?} + {:key => :jenkins_build_url, :value => @options[:jenkins_build_url]}, + {:key => :sshKeys, :value => "google_compute:#{File.read(find_google_ssh_public_key).strip}" } + ].delete_if { |member| member[:value].nil? or member[:value].empty?} end - #Create a new instance of the Google Compute Engine hypervisor object - #@param [<Host>] google_hosts The array of google hosts to provision, may ONLY be of platforms /centos-6-.*/ and - # /debian-7-.*/. We currently only support the Google Compute provided templates. - #@param [Hash{Symbol=>String}] options The options hash containing configuration values - #@option options [String] :gce_project The Google Compute Project name to connect to - #@option options [String] :gce_keyfile The location of the Google Compute service account keyfile - #@option options [String] :gce_password The password for the Google Compute service account key - #@option options [String] :gce_email The email address for the Google Compute service account - #@option options [String] :gce_machine_type A Google Compute machine type used to create instances, defaults to n1-highmem-2 - #@option options [Integer] :timeout The amount of time to attempt execution before quiting and exiting with failure + # Create a new instance of the Google Compute Engine hypervisor object + # + # @param [<Host>] google_hosts The Array of google hosts to provision, may + # ONLY be of platforms /centos-*/, /debian-*/, /rhel-*/, /suse-*/. Only + # supports the Google Compute provided templates. + # + # @param [Hash{Symbol=>String}] options The options hash containing + # configuration values @option options [String] :gce_project The Google + # Compute Project name to connect to + # + # @option options [String] :gce_keyfile The location of the Google Compute + # service account keyfile + # + # @option options [String] :gce_password The password for the Google Compute + # service account key + # + # @option options [String] :gce_email The email address for the Google + # Compute service account + # + # @option options [String] :gce_machine_type A Google Compute machine type + # used to create instances, defaults to n1-highmem-2 + # + # @option options [Integer] :timeout The amount of time to attempt execution + # before quiting and exiting with failure def initialize(google_hosts, options) require 'beaker/hypervisor/google_compute_helper' + @options = options @logger = options[:logger] @hosts = google_hosts @firewall = '' @gce_helper = GoogleComputeHelper.new(options) end - #Create and configure virtual machines in the Google Compute Engine, including their associated disks and firewall rules - #Currently ONLY supports Google Compute provided templates of CENTOS-6 and DEBIAN-7 + # Create and configure virtual machines in the Google Compute Engine, + # including their associated disks and firewall rules def provision - try = 1 attempts = @options[:timeout].to_i / SLEEPWAIT start = Time.now - #get machineType resource, used by all instances + test_group_identifier = "beaker-#{start.to_i}-" + + # get machineType resource, used by all instances machineType = @gce_helper.get_machineType(start, attempts) - #set firewall to open pe ports + # set firewall to open pe ports network = @gce_helper.get_network(start, attempts) - @firewall = generate_host_name + @firewall = test_group_identifier + generate_host_name @gce_helper.create_firewall(@firewall, network, start, attempts) @logger.debug("Created Google Compute firewall #{@firewall}") @hosts.each do |host| - gplatform = Platform.new(host[:image] || host[:platform]) + if host[:image] + gplatform = host[:image] + elsif host[:platform] + gplatform = Platform.new(host[:platform]) + else + raise('You must specify either :image or :platform, or both as necessary') + end + img = @gce_helper.get_latest_image(gplatform, start, attempts) - host['diskname'] = generate_host_name + + unique_host_id = test_group_identifier + generate_host_name + + host['diskname'] = unique_host_id disk = @gce_helper.create_disk(host['diskname'], img, start, attempts) @logger.debug("Created Google Compute disk for #{host.name}: #{host['diskname']}") - #create new host name - host['vmhostname'] = generate_host_name + # create new host name + host['vmhostname'] = unique_host_id #add a new instance of the image instance = @gce_helper.create_instance(host['vmhostname'], img, machineType, disk, start, attempts) @logger.debug("Created Google Compute instance for #{host.name}: #{host['vmhostname']}") - #add metadata to instance, if there is any to set + # add metadata to instance, if there is any to set mdata = format_metadata - if not mdata.empty? + unless mdata.empty? @gce_helper.setMetadata_on_instance(host['vmhostname'], instance['metadata']['fingerprint'], mdata, start, attempts) @logger.debug("Added tags to Google Compute instance #{host.name}: #{host['vmhostname']}") end - #get ip for this host + # get ip for this host host['ip'] = instance['networkInterfaces'][0]['accessConfigs'][0]['natIP'] - #configure ssh + # configure ssh default_user = host['user'] host['user'] = 'google_compute' - disable_se_linux(host, @options) copy_ssh_to_root(host, @options) enable_root_login(host, @options) host['user'] = default_user - #shut down connection, will reconnect on next exec + # shut down connection, will reconnect on next exec host.close @logger.debug("Instance ready: #{host['vmhostname']} for #{host.name}}") end end - #Shutdown and destroy virtual machines in the Google Compute Engine, including their associated disks and firewall rules + # Shutdown and destroy virtual machines in the Google Compute Engine, + # including their associated disks and firewall rules def cleanup() attempts = @options[:timeout].to_i / SLEEPWAIT start = Time.now @gce_helper.delete_firewall(@firewall, start, attempts) @@ -108,57 +151,58 @@ @logger.debug("Deleted Google Compute disk #{host['diskname']} for #{host.name}") end end - #Shutdown and destroy Google Compute instances (including their associated disks and firewall rules) - #that have been alive longer than ZOMBIE hours. + # Shutdown and destroy Google Compute instances (including their associated + # disks and firewall rules) that have been alive longer than ZOMBIE hours. def kill_zombies(max_age = ZOMBIE) now = start = Time.now attempts = @options[:timeout].to_i / SLEEPWAIT - #get rid of old instances + # get rid of old instances instances = @gce_helper.list_instances(start, attempts) if instances instances.each do |instance| created = Time.parse(instance['creationTimestamp']) - alive = (now - created ) /60 /60 + alive = (now - created )/60/60 if alive >= max_age #kill it with fire! @logger.debug("Deleting zombie instance #{instance['name']}") @gce_helper.delete_instance( instance['name'], start, attempts ) end end else @logger.debug("No zombie instances found") end - #get rid of old disks + + # get rid of old disks disks = @gce_helper.list_disks(start, attempts) if disks disks.each do |disk| created = Time.parse(disk['creationTimestamp']) - alive = (now - created ) /60 /60 + alive = (now - created )/60/60 if alive >= max_age - #kill it with fire! + + # kill it with fire! @logger.debug("Deleting zombie disk #{disk['name']}") @gce_helper.delete_disk( disk['name'], start, attempts ) end end else @logger.debug("No zombie disks found") end - #get rid of non-default firewalls + + # get rid of non-default firewalls firewalls = @gce_helper.list_firewalls( start, attempts) - if firewalls and not firewalls.empty? + if firewalls && !firewalls.empty? firewalls.each do |firewall| @logger.debug("Deleting non-default firewall #{firewall['name']}") @gce_helper.delete_firewall( firewall['name'], start, attempts ) end else @logger.debug("No zombie firewalls found") end - end - end end