adding create_disk and create_snapshot method implementation

This commit is contained in:
Samuel Beaulieu 2021-12-03 13:31:04 -06:00
parent 588e29b6e1
commit b631570871
No known key found for this signature in database
GPG key ID: 12030F74136D0F34

View file

@ -70,8 +70,6 @@ module Vmpooler
end end
#Base methods that are implemented: #Base methods that are implemented:
#
#
def vms_in_pool(pool_name) def vms_in_pool(pool_name)
vms = [] vms = []
@ -127,6 +125,10 @@ module Vmpooler
vm_hash = generate_vm_hash(vm_object, pool_name) vm_hash = generate_vm_hash(vm_object, pool_name)
end end
vm_hash vm_hash
rescue ::Google::Apis::ClientError => e
raise e unless e.status_code == 404
#swallow the ClientError error 404 and return nil when the VM was not found
nil
end end
# inputs # inputs
@ -182,17 +184,41 @@ module Vmpooler
nil nil
end end
#TODO
def create_disk(pool_name, vm_name, disk_size) def create_disk(pool_name, vm_name, disk_size)
pool = pool_config(pool_name) pool = pool_config(pool_name)
raise("Pool #{pool_name} does not exist for the provider #{name}") if pool.nil? raise("Pool #{pool_name} does not exist for the provider #{name}") if pool.nil?
@connection_pool.with_metrics do |pool_object| @connection_pool.with_metrics do |pool_object|
connection = ensured_gce_connection(pool_object) connection = ensured_gce_connection(pool_object)
vm_object = find_vm(pool_name, vm_name, connection) begin
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil? vm_object = connection.get_instance(project, zone(pool_name), vm_name)
rescue ::Google::Apis::ClientError => e
raise e unless e.status_code == 404
#if it does not exist
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}")
end
# this number should start at 1 when there is only the boot disk,
# eg the new disk will be named spicy-proton-disk1
number_disk = vm_object.disks.length()
#TODO part 2 disk_name = "#{vm_name}-disk#{number_disk}"
disk = Google::Apis::ComputeV1::Disk.new(
:name => disk_name,
:size_gb => disk_size,
:labels => {"pool" => pool_name, "vm" => vm_name}
)
result = connection.insert_disk(project, zone(pool_name), disk)
wait_for_operation(project, pool_name, result, connection)
new_disk = connection.get_disk(project, zone(pool_name), disk_name)
attached_disk = Google::Apis::ComputeV1::AttachedDisk.new(
:auto_delete => true,
:boot => false,
:source => new_disk.self_link
)
result = connection.attach_disk(project, zone(pool_name), vm_object.name, attached_disk)
wait_for_operation(project, pool_name, result, connection)
true
end end
true true
end end
@ -200,32 +226,45 @@ module Vmpooler
def create_snapshot(pool_name, vm_name, new_snapshot_name) def create_snapshot(pool_name, vm_name, new_snapshot_name)
@connection_pool.with_metrics do |pool_object| @connection_pool.with_metrics do |pool_object|
connection = ensured_gce_connection(pool_object) connection = ensured_gce_connection(pool_object)
vm_object = find_vm(pool_name, vm_name, connection) begin
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil? vm_object = connection.get_instance(project, zone(pool_name), vm_name)
old_snap = find_snapshot(vm_object, new_snapshot_name)
raise("Snapshot #{new_snapshot_name} for VM #{vm_name} in pool #{pool_name} already exists for the provider #{name}") unless old_snap.nil?
snapshot_obj = ::Google::Apis::ComputeV1::Snapshot.new(name: "#{new_snapshot_name}_boot", labels: {"snapshot_name" => new_snapshot_name, "vm" => vm_name})
boot_disk = vm_object.disks[0]
result = connection.create_disk_snapshot(project, zone(pool_name), boot_disk, snapshot_obj)
wait_for_operation(project, pool_name, result, connection)
#TODO snapshot other disks if there are any
end
true
rescue ::Google::Apis::ClientError => e rescue ::Google::Apis::ClientError => e
raise e unless e.status_code == 404 raise e unless e.status_code == 404
nil #if it does not exist
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}")
end
old_snap = find_snapshot(vm_name, new_snapshot_name, connection)
raise("Snapshot #{new_snapshot_name} for VM #{vm_name} in pool #{pool_name} already exists for the provider #{name}") unless old_snap.nil?
filter = "(labels.vm = #{vm_name})"
disk_list = connection.list_disks(project, zone(pool_name), filter: filter)
result_list = []
disk_list.items.each do |disk|
snapshot_obj = ::Google::Apis::ComputeV1::Snapshot.new(
name: "#{new_snapshot_name}-#{disk.name}",
labels: {"snapshot_name" => new_snapshot_name, "vm" => vm_name}
)
result = connection.create_disk_snapshot(project, zone(pool_name), disk.name, snapshot_obj)
# do them all async, keep a list, check later
result_list << result
end
#now check they are done
result_list.each do |result|
wait_for_operation(project, pool_name, result, connection)
end
end
true
end end
#TODO #TODO
def revert_snapshot(pool_name, vm_name, snapshot_name) def revert_snapshot(pool_name, vm_name, snapshot_name)
@connection_pool.with_metrics do |pool_object| @connection_pool.with_metrics do |pool_object|
connection = ensured_gce_connection(pool_object) connection = ensured_gce_connection(pool_object)
vm_object = find_vm(pool_name, vm_name, connection) vm_object = connection.get_instance(project, zone(pool_name), vm_name)
raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil? raise("VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if vm_object.nil?
snapshot_object = find_snapshot(vm_object, snapshot_name) snapshot_object = find_snapshot(vm_object,name, snapshot_name, connection)
raise("Snapshot #{snapshot_name} for VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if snapshot_object.nil? raise("Snapshot #{snapshot_name} for VM #{vm_name} in pool #{pool_name} does not exist for the provider #{name}") if snapshot_object.nil?
#TODO part 2 #TODO part 2
@ -236,23 +275,16 @@ module Vmpooler
def destroy_vm(pool_name, vm_name) def destroy_vm(pool_name, vm_name)
@connection_pool.with_metrics do |pool_object| @connection_pool.with_metrics do |pool_object|
connection = ensured_gce_connection(pool_object) connection = ensured_gce_connection(pool_object)
vm_object = find_vm(pool_name, vm_name, connection) vm_object = connection.get_instance(project, zone(pool_name), vm_name)
# If a VM doesn't exist then it is effectively deleted
return true if vm_object.nil?
start = Time.now result = connection.delete_instance(project, zone(pool_name), vm_name)
wait_for_operation(project, pool_name, result, connection, 10)
result = connection.delete_instance(project, @options[:vm_zone], name)
wait_for_operation(project, pool_name, result, connection)
finish = format('%<time>.2f', time: Time.now - start)
logger.log('s', "[-] [#{pool}] '#{vm_name}' destroyed in #{finish} seconds")
metrics.timing("destroy.#{pool}", finish)
end end
true true
rescue ::Google::Apis::ClientError => e rescue ::Google::Apis::ClientError => e
raise e unless e.status_code == 404 raise e unless e.status_code == 404
nil # If a VM doesn't exist then it is effectively deleted
true
end end
def vm_ready?(_pool_name, vm_name) def vm_ready?(_pool_name, vm_name)
@ -277,13 +309,19 @@ module Vmpooler
# END BASE METHODS # END BASE METHODS
# Compute resource wait for operation to be DONE (synchronous operation) # Compute resource wait for operation to be DONE (synchronous operation)
def wait_for_operation(project, pool_name, result, connection) def wait_for_operation(project, pool_name, result, connection, retries=5)
retries = 5 while result.status != 'DONE'
while result.status != 'DONE' && retries > 0 #logger.log('d',"#{Time.now} (#{retries}) #{result.status}")
retries = retries - 1
result = connection.wait_zone_operation(project, zone(pool_name), result.name) result = connection.wait_zone_operation(project, zone(pool_name), result.name)
end end
result result
rescue Google::Apis::TransmissionError => e
# each retry typically about 1 minute.
if retries > 0
retries = retries - 1
retry
end
raise
end end
# Return a hash of VM data # Return a hash of VM data
@ -324,7 +362,7 @@ module Vmpooler
metrics.increment('connect.open') metrics.increment('connect.open')
compute compute
rescue StandardError => e rescue StandardError => e #is that even a thing?
metrics.increment('connect.fail') metrics.increment('connect.fail')
raise e if try >= max_tries raise e if try >= max_tries
@ -348,8 +386,15 @@ module Vmpooler
end end
end end
def find_snapshot(vm, snapshotname) def find_snapshot(vm, snapshotname, connection)
#TODO filter = "(labels.vm = #{vm}) AND (labels.snapshot_name = #{snapshotname})"
snapshot_list = connection.list_snapshots(project,filter: filter)
return snapshot_list.items #array of snapshot objects
end
#all gce resource names to be RFC1035 compliant
def safe_name(name)
name =~ /[a-z]([-a-z0-9]*[a-z0-9])?/
end end
end end
end end