modules/mu/clouds/google/server.rb in cloud-mu-1.9.0.pre.beta vs modules/mu/clouds/google/server.rb in cloud-mu-2.0.0.pre.alpha
- old
+ new
@@ -87,25 +87,30 @@
# Generate a server-class specific service account, used to grant
# permission to do various API things to a node.
# @param rolename [String]:
# @param project [String]:
# @param scopes [Array<String>]: https://developers.google.com/identity/protocols/googlescopes
- def self.createServiceAccount(rolename, project: MU::Cloud::Google.defaultProject, scopes: ["https://www.googleapis.com/auth/compute.readonly", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/cloud-platform"])
+ # XXX this should be a MU::Cloud::Google::User resource
+ def self.createServiceAccount(rolename, deploy, project: nil, scopes: ["https://www.googleapis.com/auth/compute.readonly", "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/cloud-platform"], credentials: nil)
+ project ||= MU::Cloud::Google.defaultProject(credentials)
+
#https://www.googleapis.com/auth/devstorage.read_only ?
- name = MU::Cloud::Google.nameStr(rolename)
+ name = deploy.getResourceName(rolename, max_length: 30).downcase
saobj = MU::Cloud::Google.iam(:CreateServiceAccountRequest).new(
- account_id: rolename.gsub(/[^a-z]/, ""), # XXX this mangling isn't required in the console, so why is it here?
+ account_id: name.gsub(/[^a-z]/, ""), # XXX this mangling isn't required in the console, so why is it here?
service_account: MU::Cloud::Google.iam(:ServiceAccount).new(
display_name: rolename,
# do NOT specify project_id or name, we know that much
)
)
- resp = MU::Cloud::Google.iam.create_service_account(
+
+ resp = MU::Cloud::Google.iam(credentials: credentials).create_service_account(
"projects/#{project}",
saobj
)
+
MU::Cloud::Google.compute(:ServiceAccount).new(
email: resp.email,
scopes: scopes
)
end
@@ -113,34 +118,36 @@
# Retrieve the cloud descriptor for this machine image, which can be
# a whole or partial URL. Will follow deprecation notices and retrieve
# the latest version, if applicable.
# @param image_id [String]: URL to a Google disk image
# @return [Google::Apis::ComputeBeta::Image]
- def self.fetchImage(image_id)
+ def self.fetchImage(image_id, credentials: nil)
img_proj = img_name = nil
begin
img_proj = image_id.gsub(/.*?\/?projects\/([^\/]+)\/.*/, '\1')
img_name = image_id.gsub(/.*?([^\/]+)$/, '\1')
- img = MU::Cloud::Google.compute.get_image(img_proj, img_name)
+ img = MU::Cloud::Google.compute(credentials: credentials).get_image(img_proj, img_name)
if !img.deprecated.nil? and !img.deprecated.replacement.nil?
image_id = img.deprecated.replacement
end
end while !img.deprecated.nil? and img.deprecated.state == "DEPRECATED" and !img.deprecated.replacement.nil?
- MU::Cloud::Google.compute.get_image(img_proj, img_name)
+ MU::Cloud::Google.compute(credentials: credentials).get_image(img_proj, img_name)
end
# Generator for disk configuration parameters for a Compute instance
# @param config [Hash]: The MU::Cloud::Server config hash for whom we're configuring disks
# @param create [Boolean]: Actually create extra (non-root) disks, or just the one declared as the root disk of the image
# @param disk_as_url [Boolean]: Whether to declare the disk type as a short string or full URL, which can vary depending on the calling resource
# @return [Array]: The Compute :AttachedDisk objects describing disks that've been created
- def self.diskConfig(config, create = true, disk_as_url = true)
+ def self.diskConfig(config, create = true, disk_as_url = true, credentials: nil)
disks = []
- puts config['image_id']
- puts config['basis']
+ if config['image_id'].nil? and config['basis'].nil?
+ pp config.keys
+ raise MuError, "Can't generate disk configuration for server #{config['name']} without an image ID or basis specified"
+ end
- img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'])
+ img = fetchImage(config['image_id'] || config['basis']['launch_config']['image_id'], credentials: credentials)
# XXX slurp settings from /dev/sda or w/e by convention?
disktype = "projects/#{config['project']}/zones/#{config['availability_zone']}/diskTypes/pd-standard"
disktype = "pd-standard" if !disk_as_url
# disk_type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
@@ -187,11 +194,11 @@
# type: projects/project/zones/#{config['availability_zone']}/diskTypes/pd-standard Other values include pd-ssd and local-ssd
name: diskname
)
MU.log "Creating disk #{diskname}", details: newdiskobj
- newdisk = MU::Cloud::Google.compute.insert_disk(
+ newdisk = MU::Cloud::Google.compute(credentials: credentials).insert_disk(
config['project'],
config['availability_zone'],
newdiskobj
)
@@ -237,16 +244,18 @@
# Called automatically by {MU::Deploy#createResources}
def create
service_acct = MU::Cloud::Google::Server.createServiceAccount(
@mu_name.downcase,
- project: @config['project']
+ @deploy,
+ project: @config['project'],
+ credentials: @config['credentials']
)
- MU::Cloud::Google.grantDeploySecretAccess(service_acct.email)
+ MU::Cloud::Google.grantDeploySecretAccess(service_acct.email, credentials: @config['credentials'])
begin
- disks = MU::Cloud::Google::Server.diskConfig(@config)
+ disks = MU::Cloud::Google::Server.diskConfig(@config, credentials: @config['credentials'])
interfaces = MU::Cloud::Google::Server.interfaceConfig(@config, @vpc)
if @config['routes']
@config['routes'].each { |route|
@vpc.cloudobj.createRouteForInstance(route, self)
@@ -289,20 +298,24 @@
instanceobj = MU::Cloud::Google.compute(:Instance).new(desc)
MU.log "Creating instance #{@mu_name}"
begin
- instance = MU::Cloud::Google.compute.insert_instance(
- @config['project'],
- @config['availability_zone'],
- instanceobj
- )
+ instance = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_instance(
+ @config['project'],
+ @config['availability_zone'],
+ instanceobj
+ )
+ if instance and instance.name
+ @cloud_id = instance.name
+ else
+ sleep 10
+ end
rescue ::Google::Apis::ClientError => e
MU.log e.message, MU::ERR
raise e
- end
- @cloud_id = instance.name # XXX or instance.target_link... pick a convention, would you?
+ end while @cloud_id.nil?
if !@config['async_groom']
sleep 5
MU::MommaCat.lock(@cloud_id+"-create")
if !postBoot
@@ -329,11 +342,11 @@
MU::MommaCat.unlockAll
if !@deploy.nocleanup
parent_thread_id = Thread.current.object_id
Thread.new {
MU.dupGlobals(parent_thread_id)
- MU::Cloud::Google::Server.cleanup(noop: false, ignoremaster: false, skipsnapshots: true)
+ MU::Cloud::Google::Server.cleanup(noop: false, ignoremaster: false, flags: { "skipsnapshots" => true } )
}
end
end
raise e
end
@@ -363,11 +376,11 @@
end
# Ask the Google API to stop this node
def stop
MU.log "Stopping #{@cloud_id}"
- MU::Cloud::Google.compute.stop_instance(
+ MU::Cloud::Google.compute(credentials: @config['credentials']).stop_instance(
@config['project'],
@config['availability_zone'],
@cloud_id
)
begin
@@ -376,64 +389,25 @@
end
# Ask the Google API to start this node
def start
MU.log "Starting #{@cloud_id}"
- MU::Cloud::Google.compute.start_instance(
+ MU::Cloud::Google.compute(credentials: @config['credentials']).start_instance(
@config['project'],
@config['availability_zone'],
@cloud_id
)
begin
sleep 5
end while cloud_desc.status != "RUNNING"
end
# Ask the Google API to restart this node
+ # XXX unimplemented
def reboot(hard = false)
return if @cloud_id.nil?
- if hard
- groupname = nil
- if !@config['basis'].nil?
- resp = MU::Cloud::AWS.autoscale(@config['region']).describe_auto_scaling_instances(
- instance_ids: [@cloud_id]
- )
- groupname = resp.auto_scaling_instances.first.auto_scaling_group_name
- MU.log "Pausing Autoscale processes in #{groupname}", MU::NOTICE
- MU::Cloud::AWS.autoscale(@config['region']).suspend_processes(
- auto_scaling_group_name: groupname
- )
- end
- begin
- MU.log "Stopping #{@mu_name} (#{@cloud_id})", MU::NOTICE
- MU::Cloud::AWS.ec2(@config['region']).stop_instances(
- instance_ids: [@cloud_id]
- )
- MU::Cloud::AWS.ec2(@config['region']).wait_until(:instance_stopped, instance_ids: [@cloud_id]) do |waiter|
- waiter.before_attempt do |attempts|
- MU.log "Waiting for #{@mu_name} to stop for hard reboot"
- end
- end
- MU.log "Starting #{@mu_name} (#{@cloud_id})"
- MU::Cloud::AWS.ec2(@config['region']).start_instances(
- instance_ids: [@cloud_id]
- )
- ensure
- if !groupname.nil?
- MU.log "Resuming Autoscale processes in #{groupname}", MU::NOTICE
- MU::Cloud::AWS.autoscale(@config['region']).resume_processes(
- auto_scaling_group_name: groupname
- )
- end
- end
- else
- MU.log "Rebooting #{@mu_name} (#{@cloud_id})"
- MU::Cloud::AWS.ec2(@config['region']).reboot_instances(
- instance_ids: [@cloud_id]
- )
- end
end
# Figure out what's needed to SSH into this server.
# @return [Array<String>]: nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name, alternate_names
def getSSHConfig
@@ -442,11 +416,11 @@
# up in MU::MommaCat's ssh config wangling
ssh_keydir = Etc.getpwuid(Process.uid).dir+"/.ssh"
return nil if @config.nil? or @deploy.nil?
nat_ssh_key = nat_ssh_user = nat_ssh_host = nil
- if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
+ if !@config["vpc"].nil? and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
if !@nat.nil?
if @nat.cloud_desc.nil?
MU.log "NAT was missing cloud descriptor when called in #{@mu_name}'s getSSHConfig", MU::ERR
return nil
@@ -574,259 +548,15 @@
MU::MommaCat.nameKitten(self)
@named = true
end
nat_ssh_key, nat_ssh_user, nat_ssh_host, canonical_ip, ssh_user, ssh_key_name = getSSHConfig
- if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'])
+ if !nat_ssh_host and !MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, region: @config['region'], credentials: @config['credentials'])
# XXX check if canonical_ip is in the private ranges
# raise MuError, "#{node} has no NAT host configured, and I have no other route to it"
end
-# # Set console termination protection. Autoscale nodes won't set this
-# # by default.
-# MU::Cloud::AWS.ec2(@config['region']).modify_instance_attribute(
-# instance_id: @cloud_id,
-# disable_api_termination: {:value => true}
-# )
-
-#MU.log "Let's deal with addressing", MU::WARN, details: cloud_desc
- # If we asked for a public IP address, make sure we get one
-# addrobj = MU::Cloud::Google.compute(:Address).new(
-# name: @mu_name+"-public-ip",
-# description: @deploy.deploy_id
-# )
-# addr_insert = MU::Cloud::Google.compute.insert_global_address(
-# @config['project'],
-## @config['region'],
-# addrobj
-# )
-# pp addr_insert
-# raise "BOOP"
-# has_elastic_ip = false
-# if !instance.public_ip_address.nil?
-# begin
-# resp = MU::Cloud::AWS.ec2((@config['region'])).describe_addresses(public_ips: [instance.public_ip_address])
-# if resp.addresses.size > 0 and resp.addresses.first.instance_id == @cloud_id
-# has_elastic_ip = true
-# end
-# rescue Aws::EC2::Errors::InvalidAddressNotFound => e
-# # XXX this is ok to ignore, it means the public IP isn't Elastic
-# end
-# end
-
-# win_admin_password = nil
-# ec2config_password = nil
-# sshd_password = nil
-# if windows?
-# ssh_keydir = "#{Etc.getpwuid(Process.uid).dir}/.ssh"
-# ssh_key_name = @deploy.ssh_key_name
-#
-# if @config['use_cloud_provider_windows_password']
-# win_admin_password = getWindowsAdminPassword
-# elsif @config['windows_auth_vault'] && !@config['windows_auth_vault'].empty?
-# if @config["windows_auth_vault"].has_key?("password_field")
-# win_admin_password = @groomer.getSecret(
-# vault: @config['windows_auth_vault']['vault'],
-# item: @config['windows_auth_vault']['item'],
-# field: @config["windows_auth_vault"]["password_field"]
-# )
-# else
-# win_admin_password = getWindowsAdminPassword
-# end
-#
-# if @config["windows_auth_vault"].has_key?("ec2config_password_field")
-# ec2config_password = @groomer.getSecret(
-# vault: @config['windows_auth_vault']['vault'],
-# item: @config['windows_auth_vault']['item'],
-# field: @config["windows_auth_vault"]["ec2config_password_field"]
-# )
-# end
-#
-# if @config["windows_auth_vault"].has_key?("sshd_password_field")
-# sshd_password = @groomer.getSecret(
-# vault: @config['windows_auth_vault']['vault'],
-# item: @config['windows_auth_vault']['item'],
-# field: @config["windows_auth_vault"]["sshd_password_field"]
-# )
-# end
-# end
-#
-# win_admin_password = MU.generateWindowsPassword if win_admin_password.nil?
-# ec2config_password = MU.generateWindowsPassword if ec2config_password.nil?
-# sshd_password = MU.generateWindowsPassword if sshd_password.nil?
-#
-# # We're creating the vault here so when we run
-# # MU::Cloud::Server.initialSSHTasks and we need to set the Windows
-# # Admin password we can grab it from said vault.
-# creds = {
-# "username" => @config['windows_admin_username'],
-# "password" => win_admin_password,
-# "ec2config_username" => "ec2config",
-# "ec2config_password" => ec2config_password,
-# "sshd_username" => "sshd_service",
-# "sshd_password" => sshd_password
-# }
-# @groomer.saveSecret(vault: @mu_name, item: "windows_credentials", data: creds, permissions: "name:#{@mu_name}")
-# end
-#
-#
-#
-# # If we've asked for additional subnets (and this @config is not a
-# # member of a Server Pool, which has different semantics), create
-# # extra interfaces to accomodate.
-# if !@config['vpc']['subnets'].nil? and @config['basis'].nil?
-# device_index = 1
-# @vpc.subnets { |subnet|
-# subnet_id = subnet.cloud_id
-# MU.log "Adding network interface on subnet #{subnet_id} for #{node}"
-# iface = MU::Cloud::AWS.ec2(@config['region']).create_network_interface(subnet_id: subnet_id).network_interface
-# MU::MommaCat.createStandardTags(iface.network_interface_id, region: @config['region'])
-# MU::MommaCat.createTag(iface.network_interface_id, "Name", node+"-ETH"+device_index.to_s, region: @config['region'])
-#
-# if @config['optional_tags']
-# MU::MommaCat.listOptionalTags.each { |key, value|
-# MU::MommaCat.createTag(iface.network_interface_id, key, value, region: @config['region'])
-# }
-# end
-#
-# if !@config['tags'].nil?
-# @config['tags'].each { |tag|
-# MU::MommaCat.createTag(iface.network_interface_id, tag['key'], tag['value'], region: @config['region'])
-# }
-# end
-#
-# MU::Cloud::AWS.ec2(@config['region']).attach_network_interface(
-# network_interface_id: iface.network_interface_id,
-# instance_id: @cloud_id,
-# device_index: device_index
-# )
-# device_index = device_index + 1
-# }
-# end
-# elsif !@config['static_ip'].nil?
-# if !@config['static_ip']['ip'].nil?
-# public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true, ip: @config['static_ip']['ip'])
-# elsif !has_elastic_ip
-# public_ip = MU::Cloud::AWS::Server.associateElasticIp(@cloud_id, classic: true)
-# end
-# end
-#
-#
-# if !@config['image_then_destroy']
-# notify
-# end
-#
-# MU.log "EC2 instance #{node} has id #{@cloud_id}", MU::DEBUG
-#
-# @config["private_dns_name"] = instance.private_dns_name
-# @config["public_dns_name"] = instance.public_dns_name
-# @config["private_ip_address"] = instance.private_ip_address
-# @config["public_ip_address"] = instance.public_ip_address
-#
-# ext_mappings = MU.structToHash(instance.block_device_mappings)
-#
-# # Root disk on standard CentOS AMI
-# # tagVolumes(@cloud_id, "/dev/sda", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
-# # Root disk on standard Ubuntu AMI
-# # tagVolumes(@cloud_id, "/dev/sda1", "Name", "ROOT-"+MU.deploy_id+"-"+@config["name"].upcase)
-#
-# # Generic deploy ID tag
-# # tagVolumes(@cloud_id)
-#
-# # Tag volumes with all our standard tags.
-# # Maybe replace tagVolumes with this? There is one more place tagVolumes is called from
-# volumes = MU::Cloud::AWS.ec2(@config['region']).describe_volumes(filters: [name: "attachment.instance-id", values: [@cloud_id]])
-# volumes.each { |vol|
-# vol.volumes.each { |volume|
-# volume.attachments.each { |attachment|
-# MU::MommaCat.listStandardTags.each_pair { |key, value|
-# MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
-#
-# if attachment.device == "/dev/sda" or attachment.device == "/dev/sda1"
-# MU::MommaCat.createTag(attachment.volume_id, "Name", "ROOT-#{MU.deploy_id}-#{@config["name"].upcase}", region: @config['region'])
-# else
-# MU::MommaCat.createTag(attachment.volume_id, "Name", "#{MU.deploy_id}-#{@config["name"].upcase}-#{attachment.device.upcase}", region: @config['region'])
-# end
-# }
-#
-# if @config['optional_tags']
-# MU::MommaCat.listOptionalTags.each { |key, value|
-# MU::MommaCat.createTag(attachment.volume_id, key, value, region: @config['region'])
-# }
-# end
-#
-# if @config['tags']
-# @config['tags'].each { |tag|
-# MU::MommaCat.createTag(attachment.volume_id, tag['key'], tag['value'], region: @config['region'])
-# }
-# end
-# }
-# }
-# }
-#
-# canonical_name = instance.public_dns_name
-# canonical_name = instance.private_dns_name if !canonical_name or nat_ssh_host != nil
-# @config['canonical_name'] = canonical_name
-#
-# if !@config['add_private_ips'].nil?
-# instance.network_interfaces.each { |int|
-# if int.private_ip_address == instance.private_ip_address and int.private_ip_addresses.size < (@config['add_private_ips'] + 1)
-# MU.log "Adding #{@config['add_private_ips']} extra private IP addresses to #{@cloud_id}"
-# MU::Cloud::AWS.ec2(@config['region']).assign_private_ip_addresses(
-# network_interface_id: int.network_interface_id,
-# secondary_private_ip_address_count: @config['add_private_ips'],
-# allow_reassignment: false
-# )
-# end
-# }
-# notify
-# end
-#
-# windows? ? ssh_wait = 60 : ssh_wait = 30
-# windows? ? max_retries = 50 : max_retries = 35
-# begin
-# session = getSSHSession(max_retries, ssh_wait)
-# initialSSHTasks(session)
-# rescue BootstrapTempFail
-# sleep ssh_wait
-# retry
-# ensure
-# session.close if !session.nil?
-# end
-#
-# if @config["existing_deploys"] && !@config["existing_deploys"].empty?
-# @config["existing_deploys"].each { |ext_deploy|
-# if ext_deploy["cloud_id"]
-# found = MU::MommaCat.findStray(
-# @config['cloud'],
-# ext_deploy["cloud_type"],
-# cloud_id: ext_deploy["cloud_id"],
-# region: @config['region'],
-# dummy_ok: false
-# ).first
-#
-# MU.log "Couldn't find existing resource #{ext_deploy["cloud_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
-# @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: found.mu_name, triggering_node: @mu_name)
-# elsif ext_deploy["mu_name"] && ext_deploy["deploy_id"]
-# MU.log "#{ext_deploy["mu_name"]} / #{ext_deploy["deploy_id"]}"
-# found = MU::MommaCat.findStray(
-# @config['cloud'],
-# ext_deploy["cloud_type"],
-# deploy_id: ext_deploy["deploy_id"],
-# mu_name: ext_deploy["mu_name"],
-# region: @config['region'],
-# dummy_ok: false
-# ).first
-#
-# MU.log "Couldn't find existing resource #{ext_deploy["mu_name"]}/#{ext_deploy["deploy_id"]}, #{ext_deploy["cloud_type"]}", MU::ERR if found.nil?
-# @deploy.notify(ext_deploy["cloud_type"], found.config["name"], found.deploydata, mu_name: ext_deploy["mu_name"], triggering_node: @mu_name)
-# else
-# MU.log "Trying to find existing deploy, but either the cloud_id is not valid or no mu_name and deploy_id where provided", MU::ERR
-# end
-# }
-# end
-
# See if this node already exists in our config management. If it does,
# we're done.
if @groomer.haveBootstrapped?
MU.log "Node #{node} has already been bootstrapped, skipping groomer setup.", MU::NOTICE
@groomer.saveDeployData
@@ -854,14 +584,14 @@
# @param tag_key [String]: A tag key to search.
# @param tag_value [String]: The value of the tag specified by tag_key to match when searching by tag.
# @param ip [String]: An IP address associated with the instance
# @param flags [Hash]: Optional flags
# @return [Array<Hash<String,OpenStruct>>]: The cloud provider's complete descriptions of matching instances
- def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, ip: nil, flags: {})
+ def self.find(cloud_id: nil, region: MU.curRegion, tag_key: "Name", tag_value: nil, ip: nil, flags: {}, credentials: nil)
# XXX put that 'ip' value into flags
instance = nil
- flags["project"] ||= MU::Cloud::Google.defaultProject
+ flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
if !region.nil? and MU::Cloud::Google.listRegions.include?(region)
regions = [region]
else
regions = MU::Cloud::Google.listRegions
end
@@ -879,11 +609,11 @@
MU.dupGlobals(parent_thread_id)
MU.log "Hunting for instance with cloud id '#{cloud_id}' in #{region}", MU::DEBUG
MU::Cloud::Google.listAZs(region).each { |az|
resp = nil
begin
- resp = MU::Cloud::Google.compute.get_instance(
+ resp = MU::Cloud::Google.compute(credentials: credentials).get_instance(
flags["project"],
az,
cloud_id
)
rescue ::Google::Apis::ClientError => e
@@ -1063,17 +793,18 @@
family: ("mu-"+@config['platform']+"-"+MU.environment).downcase,
project: @config['project'],
exclude_storage: img_cfg['image_exclude_storage'],
make_public: img_cfg['public'],
tags: @config['tags'],
- zone: @config['availability_zone']
+ zone: @config['availability_zone'],
+ credentials: @config['credentials']
)
@deploy.notify("images", @config['name'], {"image_id" => image_id})
@config['image_created'] = true
if img_cfg['image_then_destroy']
MU.log "Image #{image_id} ready, removing source node #{node}"
- MU::Cloud::Google.compute.delete_instance(
+ MU::Cloud::Google.compute(credentials: @config['credentials']).delete_instance(
@config['project'],
@config['availability_zone'],
@cloud_id
)
destroy
@@ -1091,11 +822,12 @@
# @param storage [Hash]: The storage devices to include in this image.
# @param exclude_storage [Boolean]: Do not include the storage device profile of the running instance when creating this image.
# @param region [String]: The cloud provider region
# @param tags [Array<String>]: Extra/override tags to apply to the image.
# @return [String]: The cloud provider identifier of the new machine image.
- def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, project: MU::Cloud::Google.defaultProject, make_public: false, tags: [], region: nil, family: "mu", zone: MU::Cloud::Google.listAZs.sample)
+ def self.createImage(name: nil, instance_id: nil, storage: {}, exclude_storage: false, project: nil, make_public: false, tags: [], region: nil, family: "mu", zone: MU::Cloud::Google.listAZs.sample, credentials: nil)
+ project ||= MU::Cloud::Google.defaultProject(credentials)
instance = MU::Cloud::Server.find(cloud_id: instance_id, region: region)
if instance.nil?
raise MuError, "Failed to find instance '#{instance_id}' in createImage"
end
@@ -1120,17 +852,17 @@
name: name+"-"+disk.device_name,
description: "Mu image created from #{name} (#{disk.device_name})"
)
diskname = disk.source.gsub(/.*?\//, "")
MU.log "Creating snapshot of #{diskname} in #{zone}", MU::NOTICE, details: snapobj
- snap = MU::Cloud::Google.compute.create_disk_snapshot(
+ snap = MU::Cloud::Google.compute(credentials: credentials).create_disk_snapshot(
project,
zone,
diskname,
snapobj
)
- MU::Cloud::Google.compute.set_snapshot_labels(
+ MU::Cloud::Google.compute(credentials: credentials).set_snapshot_labels(
project,
snap.name,
MU::Cloud::Google.compute(:GlobalSetLabelsRequest).new(
label_fingerprint: snap.label_fingerprint,
labels: labels.merge({
@@ -1154,40 +886,40 @@
description: "Mu image created from #{name}",
labels: labels,
family: family
)
- newimage = MU::Cloud::Google.compute.insert_image(
+ newimage = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_image(
project,
imageobj
)
newimage.name
end
- def cloud_desc
- max_retries = 5
- retries = 0
- if !@cloud_id.nil?
- begin
- return MU::Cloud::Google.compute.get_instance(
- @config['project'],
- @config['availability_zone'],
- @cloud_id
- )
- rescue ::Google::Apis::ClientError => e
- if e.message.match(/^notFound: /)
- return nil
- else
- raise e
- end
- end
- end
- nil
- end
+# def cloud_desc
+# max_retries = 5
+# retries = 0
+# if !@cloud_id.nil?
+# begin
+# return MU::Cloud::Google.compute(credentials: @config['credentials']).get_instance(
+# @config['project'],
+# @config['availability_zone'],
+# @cloud_id
+# )
+# rescue ::Google::Apis::ClientError => e
+# if e.message.match(/^notFound: /)
+# return nil
+# else
+# raise e
+# end
+# end
+# end
+# nil
+# end
def cloud_desc
- MU::Cloud::Google::Server.find(cloud_id: @cloud_id).values.first
+ MU::Cloud::Google::Server.find(cloud_id: @cloud_id, credentials: @config['credentials']).values.first
end
# Return the IP address that we, the Mu server, should be using to access
# this host via the network. Note that this does not factor in SSH
# bastion hosts that may be in the path, see getSSHConfig if that's what
@@ -1212,21 +944,19 @@
}
# Our deploydata gets corrupted often with server pools, this will cause us to use the wrong IP to identify a node
# which will cause us to create certificates, DNS records and other artifacts with incorrect information which will cause our deploy to fail.
# The cloud_id is always correct so lets use 'cloud_desc' to get the correct IPs
- if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc) or public_ips.size == 0
+ if MU::Cloud::Google::VPC.haveRouteToInstance?(cloud_desc, credentials: @config['credentials']) or public_ips.size == 0
@config['canonical_ip'] = private_ips.first
return private_ips.first
else
@config['canonical_ip'] = public_ips.first
return public_ips.first
end
end
- # Retrieves the Cloud provider's randomly generated Windows password
- # Will only work on stock Amazon Windows AMIs or custom AMIs that where created with Administrator Password set to random in EC2Config
# return [String]: A password string.
def getWindowsAdminPassword
end
# Add a volume to this instance
@@ -1249,11 +979,11 @@
# Other values include pd-ssd and local-ssd
name: resname
)
begin
- newdisk = MU::Cloud::Google.compute.insert_disk(
+ newdisk = MU::Cloud::Google.compute(credentials: @config['credentials']).insert_disk(
@config['project'],
@config['availability_zone'],
newdiskobj
)
rescue ::Google::Apis::ClientError => e
@@ -1269,11 +999,11 @@
auto_delete: true,
device_name: devname,
source: newdisk.self_link,
type: "PERSISTENT"
)
- attachment = MU::Cloud::Google.compute.attach_disk(
+ attachment = MU::Cloud::Google.compute(credentials: @config['credentials']).attach_disk(
@config['project'],
@config['availability_zone'],
@cloud_id,
attachobj
)
@@ -1285,22 +1015,31 @@
# @return [Boolean]
def active?
true
end
+ # Does this resource type exist as a global (cloud-wide) artifact, or
+ # is it localized to a region/zone?
+ # @return [Boolean]
+ def self.isGlobal?
+ false
+ end
+
# Remove all instances associated with the currently loaded deployment. Also cleans up associated volumes, droppings in the MU master's /etc/hosts and ~/.ssh, and in whatever Groomer was used.
# @param noop [Boolean]: If true, will only print what would be done
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
# @param region [String]: The cloud provider region
# @return [void]
- def self.cleanup(noop: false, ignoremaster: false, region: $MU_CFG['google']['region'], skipsnapshots: false, onlycloud: false, flags: {})
- flags["project"] ||= MU::Cloud::Google.defaultProject
+ def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
+ flags["project"] ||= MU::Cloud::Google.defaultProject(credentials)
+ skipsnapshots = flags["skipsnapshots"]
+ onlycloud = flags["onlycloud"]
# XXX make damn sure MU.deploy_id is set
MU::Cloud::Google.listAZs(region).each { |az|
disks = []
- resp = MU::Cloud::Google.compute.list_instances(
+ resp = MU::Cloud::Google.compute(credentials: credentials).list_instances(
flags["project"],
az,
filter: "description eq #{MU.deploy_id}"
)
if !resp.items.nil? and resp.items.size > 0
@@ -1310,18 +1049,18 @@
if !instance.disks.nil? and instance.disks.size > 0
instance.disks.each { |disk|
disks << disk if !disk.auto_delete
}
end
- deletia = MU::Cloud::Google.compute.delete_instance(
+ deletia = MU::Cloud::Google.compute(credentials: credentials).delete_instance(
flags["project"],
az,
instance.name
) if !noop
MU.log "Removing service account #{saname}"
begin
- MU::Cloud::Google.iam.delete_project_service_account(
+ MU::Cloud::Google.iam(credentials: credentials).delete_project_service_account(
"projects/#{flags["project"]}/serviceAccounts/#{saname}@#{flags["project"]}.iam.gserviceaccount.com"
) if !noop
rescue ::Google::Apis::ClientError => e
raise e if !e.message.match(/^notFound: /)
end
@@ -1332,11 +1071,11 @@
if disks.size > 0
# XXX make sure we don't miss anything that got created with dumb flags
end
# XXX honor snapshotting
- MU::Cloud::Google.compute.delete(
+ MU::Cloud::Google.compute(credentials: credentials).delete(
"disk",
flags["project"],
az,
noop
) if !noop
@@ -1454,11 +1193,11 @@
end
end
real_image = nil
begin
- real_image = MU::Cloud::Google::Server.fetchImage(server['image_id'].to_s)
+ real_image = MU::Cloud::Google::Server.fetchImage(server['image_id'].to_s, credentials: server['credentials'])
rescue ::Google::Apis::ClientError => e
MU.log e.inspect, MU::WARN
end
if real_image.nil?
@@ -1468,10 +1207,10 @@
server['image_id'] = real_image.self_link
server['image_id'].match(/projects\/([^\/]+)\/.*?\/([^\/]+)$/)
img_project = Regexp.last_match[1]
img_name = Regexp.last_match[2]
begin
- snaps = MU::Cloud::Google.compute.list_snapshots(
+ snaps = MU::Cloud::Google.compute(credentials: server['credentials']).list_snapshots(
img_project,
filter: "name eq #{img_name}-.*"
)
server['storage'] ||= []
used_devs = server['storage'].map { |disk| disk['device'].gsub(/.*?\//, "") }