require "fog/compute/models/server" module Fog module Compute class Google class Server < Fog::Compute::Server identity :name attribute :kind attribute :id attribute :can_ip_forward, :aliases => "canIpForward" attribute :creation_timestamp, :aliases => "creationTimestamp" attribute :description attribute :disks attribute :machine_type, :aliases => "machineType" attribute :metadata attribute :network_interfaces, :aliases => "networkInterfaces" attribute :scheduling attribute :self_link, :aliases => "selfLink" attribute :service_accounts, :aliases => "serviceAccounts" attribute :state, :aliases => "status" attribute :status_message, :aliases => "statusMessage" attribute :tags attribute :zone, :aliases => :zone_name # These attributes are not available in the representation of an 'instance' returned by the GCE API. # They are useful only for the create process attribute :network, :aliases => "network" attribute :subnetwork, :aliases => "subnetwork" attribute :external_ip, :aliases => "externalIP" attribute :auto_restart attribute :on_host_maintenance attribute :preemptible # Security account scope aliases used by official gcloud utility # List derived from 'gcloud compute instances create --help' GCE_SCOPE_ALIASES = { "compute-ro" => "compute.readonly", "compute-rw" => "compute", "computeaccounts-ro" => "computeaccounts.readonly", "computeaccounts-rw" => "computeaccounts", "logging-write" => "logging.write", "sql" => "sqlservice", "sql-admin" => "sqlservice.admin", "storage-full" => "devstorage.full_control", "storage-ro" => "devstorage.read_only", "storage-rw" => "devstorage.read_write" } def image_name=(_args) Fog::Logger.deprecation("image_name= is no longer used [light_black](#{caller.first})[/]") end def image_name boot_disk = disks.first unless boot_disk.is_a?(Disk) source = boot_disk["source"] match = source.match(%r{/zones/(.*)/disks/(.*)$}) boot_disk = service.disks.get match[2], match[1] end boot_disk.source_image.nil? ? nil : boot_disk.source_image end def kernel=(_args) Fog::Logger.deprecation("kernel= is no longer used [light_black](#{caller.first})[/]") end def kernel Fog::Logger.deprecation("kernel is no longer used [light_black](#{caller.first})[/]") nil end def flavor_id machine_type end def flavor_id=(flavor_id) machine_type = flavor_id end def destroy(async = true) requires :name, :zone data = service.delete_server(name, zone_name) operation = Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) operation.wait_for { ready? } unless async operation end # not used since v1 def image Fog::Logger.deprecation("Server.image is deprecated, get source_image from boot disk") service.get_image(image_name.split("/")[-1]) end def public_ip_address ip = nil if network_interfaces.respond_to? :each network_interfaces.each do |netif| next unless netif["accessConfigs"].respond_to? :each netif["accessConfigs"].each do |access_config| if access_config["name"] == "External NAT" ip = access_config["natIP"] end end end end ip end def private_ip_address ip = nil if network_interfaces.respond_to? :first ip = network_interfaces.first["networkIP"] end ip end def addresses [private_ip_address, public_ip_address] end def attach_disk(disk, options = {}) requires :identity, :zone data = service.attach_disk(identity, zone_name, disk, options) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def detach_disk(device_name) requires :identity, :zone data = service.detach_disk(identity, zone, device_name) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def reboot requires :identity, :zone data = service.reset_server(identity, zone_name) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def start requires :identity, :zone data = service.start_server(identity, zone_name) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def stop requires :identity, :zone data = service.stop_server(identity, zone_name) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def serial_port_output requires :identity, :zone data = service.get_server_serial_port_output(identity, zone_name) data.body["contents"] end def set_disk_auto_delete(auto_delete, device_name = nil) requires :identity, :zone unless device_name if disks.count <= 1 device_name = disks[0]["deviceName"] else raise ArgumentError.new("Device name required if multiple disks are attached") end end data = service.set_server_disk_auto_delete(identity, zone_name, auto_delete, device_name) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def set_scheduling(on_host_maintenance, automatic_restart, preemptible) requires :identity, :zone data = service.set_server_scheduling(identity, zone_name, on_host_maintenance, automatic_restart, preemptible) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def set_metadata(metadata = {}) requires :identity, :zone data = service.set_metadata(identity, zone_name, self.metadata["fingerprint"], metadata) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def set_tags(tags = []) requires :identity, :zone data = service.set_tags(identity, zone_name, self.tags["fingerprint"], tags) Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) end def provisioning? state == PROVISIONING end def ready? state == RUNNING end def zone_name zone.nil? ? nil : zone.split("/")[-1] end def add_ssh_key(username, key) set_metadata(generate_ssh_key_metadata(username, key)) end def map_service_accounts(scope_array) scope_array_expanded = scope_array.map do |e| if GCE_SCOPE_ALIASES[e] GCE_SCOPE_ALIASES[e] else e end end scope_array_finalized = scope_array_expanded.map do |e| if e.start_with?("https://") e else "https://www.googleapis.com/auth/#{e}" end end scope_array_finalized end def reload data = service.get_server(name, zone_name).body merge_attributes(data) end def save requires :name requires :machine_type requires :zone_name requires :disks unless service.zones.detect { |zone| zone.name == zone_name } raise ArgumentError.new "#{zone_name.inspect} is either down or you don't have permission to use it." end generate_ssh_key_metadata(username, public_key) if public_key options = { "machineType" => machine_type, "networkInterfaces" => network_interfaces, "network" => network, "subnetwork" => subnetwork, "externalIp" => external_ip, "disks" => disks, "metadata" => metadata, "serviceAccounts" => service_accounts, "tags" => tags, "auto_restart" => auto_restart, "on_host_maintenance" => on_host_maintenance, "preemptible" => preemptible, "can_ip_forward" => can_ip_forward }.delete_if { |_key, value| value.nil? } if service_accounts options["serviceAccounts"] = [{ "kind" => "compute#serviceAccount", "email" => "default", "scopes" => map_service_accounts(service_accounts) }] end data = service.insert_server(name, zone_name, options) operation = Fog::Compute::Google::Operations.new(:service => service).get(data.body["name"], data.body["zone"]) operation.wait_for { !pending? } reload end private def generate_ssh_key_metadata(username, key) self.metadata = Hash.new("") if metadata.nil? # The key "sshKeys" is deprecated and will be unsupported in the # future - for now defer to using 'ssh-keys' unless the user is # already using the deprecated version # https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#deprecated metadata_key = metadata.key?("sshKeys") ? "sshKeys" : "ssh-keys" # You can have multiple SSH keys, seperated by newlines. # https://developers.google.com/compute/docs/console?hl=en#sshkeys metadata[metadata_key] = "" unless metadata[metadata_key] metadata[metadata_key] += "\n" unless metadata[metadata_key].empty? metadata[metadata_key] += "#{username}:#{key.strip}" metadata end end end end end