lib/vagrant-cloudstack/action/terminate_instance.rb
require 'log4r'
module VagrantPlugins
module Cloudstack
module Action
# This terminates the running instance.
class TerminateInstance
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_cloudstack::action::terminate_instance')
end
def call(env)
# Delete the Firewall rule
remove_firewall_rules(env)
# Disable Static NAT
remove_static_nat(env)
# Delete the Port forwarding rule
remove_portforwarding(env)
# Destroy the server and remove the tracking ID
if env[:machine].id.nil?
env[:ui].info(I18n.t('vagrant_cloudstack.no_instance_found'))
return
else
server = env[:cloudstack_compute].servers.get(env[:machine].id)
env[:ui].info(I18n.t('vagrant_cloudstack.terminating'))
domain = env[:machine].provider_config.domain_id
domain_config = env[:machine].provider_config.get_domain_config(domain)
expunge_on_destroy = domain_config.expunge_on_destroy
options = {}
options['expunge'] = expunge_on_destroy
job = server.destroy(options)
wait_for_job_ready(env, job.id, 'Waiting for instance to be deleted')
end
remove_volumes(env)
# Delete the vmcredentials file
remove_stored_credentials(env)
# Remove keyname from cloudstack
remove_generated_ssh_key(env)
remove_security_groups(env)
env[:machine].id = nil
env[:ui].info(I18n.t('vagrant_cloudstack.terminateinstance_done'))
@app.call(env)
end
def remove_volumes(env)
volumes_file = env[:machine].data_dir.join('volumes')
if volumes_file.file?
env[:ui].info(I18n.t('vagrant_cloudstack.deleting_volumes'))
File.read(volumes_file).each_line do |line|
volume_id = line.strip
begin
resp = env[:cloudstack_compute].detach_volume({:id => volume_id})
job_id = resp['detachvolumeresponse']['jobid']
wait_for_job_ready(env, job_id)
rescue Fog::Compute::Cloudstack::Error => e
if e.message =~ /Unable to execute API command detachvolume.*entity does not exist/
env[:ui].warn(I18n.t('vagrant_cloudstack.detach_volume_failed', message: e.message))
else
raise Errors::FogError, :message => e.message
end
end
resp = env[:cloudstack_compute].delete_volume({:id => volume_id})
env[:ui].warn(I18n.t('vagrant_cloudstack.detach_volume_failed', volume_id: volume_id)) unless resp['deletevolumeresponse']['success'] == 'true'
end
volumes_file.delete
end
end
def remove_security_groups(env)
security_groups_file = env[:machine].data_dir.join('security_groups')
if security_groups_file.file?
File.read(security_groups_file).each_line do |line|
security_group_id = line.strip
begin
security_group = env[:cloudstack_compute].security_groups.get(security_group_id)
security_group.ingress_rules.each do |ir|
env[:cloudstack_compute].revoke_security_group_ingress({:id => ir['ruleid']})
end
env[:ui].info('Deleted ingress rules')
security_group.egress_rules.each do |er|
env[:cloudstack_compute].revoke_security_group_egress({:id => er['ruleid']})
end
env[:ui].info('Deleted egress rules')
rescue Fog::Compute::Cloudstack::Error => e
raise Errors::FogError, :message => e.message
end
begin
env[:cloudstack_compute].delete_security_group({:id => security_group_id})
rescue Fog::Compute::Cloudstack::Error => e
env[:ui].warn("Couldn't delete group right now.")
env[:ui].warn('Waiting 30 seconds to retry')
sleep 30
retry
end
end
security_groups_file.delete
end
end
def remove_generated_ssh_key(env)
sshkeyname_file = env[:machine].data_dir.join('sshkeyname')
if sshkeyname_file.file?
env[:ui].info(I18n.t('vagrant_cloudstack.ssh_key_pair_removing'))
sshkeyname = ''
File.read(sshkeyname_file).each_line do |line|
sshkeyname = line.strip
end
begin
response = env[:cloudstack_compute].delete_ssh_key_pair(name: sshkeyname)
env[:ui].warn(I18n.t('vagrant_cloudstack.ssh_key_pair_no_success_removing', name: sshkeyname)) unless response['deletesshkeypairresponse']['success'] == 'true'
rescue Fog::Compute::Cloudstack::Error => e
env[:ui].warn(I18n.t('vagrant_cloudstack.errors.fog_error', :message => e.message))
end
sshkeyname_file.delete
end
end
def remove_stored_credentials(env)
vmcredentials_file = env[:machine].data_dir.join('vmcredentials')
vmcredentials_file.delete if vmcredentials_file.file?
end
def remove_portforwarding(env)
env[:ui].info(I18n.t('vagrant_cloudstack.deleting_port_forwarding_rule'))
port_forwarding_file = env[:machine].data_dir.join('port_forwarding')
if port_forwarding_file.file?
File.read(port_forwarding_file).each_line do |line|
rule_id = line.strip
begin
resp = env[:cloudstack_compute].delete_port_forwarding_rule({:id => rule_id})
job_id = resp['deleteportforwardingruleresponse']['jobid']
wait_for_job_ready(env, job_id)
rescue Fog::Compute::Cloudstack::Error => e
if e.message =~ /Unable to execute API command deleteportforwardingrule.*entity does not exist/
env[:ui].warn(" -- Failed to delete portforwarding rule: #{e.message}")
else
raise Errors::FogError, :message => e.message
end
end
end
port_forwarding_file.delete
end
# Delete the Communicator Port forwording public port file
# Delete the RDP Port forwording public port file
%w(pf_public_port pf_public_rdp_port).each do |pf_filename|
pf_file = env[:machine].data_dir.join(pf_filename)
pf_file.delete if pf_file.file?
end
end
def remove_static_nat(env)
env[:ui].info(I18n.t('vagrant_cloudstack.disabling_static_nat'))
static_nat_file = env[:machine].data_dir.join('static_nat')
if static_nat_file.file?
File.read(static_nat_file).each_line do |line|
ip_address_id = line.strip
begin
options = {
:command => 'disableStaticNat',
:ipaddressid => ip_address_id
}
resp = env[:cloudstack_compute].request(options)
job_id = resp['disablestaticnatresponse']['jobid']
wait_for_job_ready(env, job_id)
rescue Fog::Compute::Cloudstack::Error => e
raise Errors::FogError, :message => e.message
end
end
static_nat_file.delete
end
end
def remove_firewall_rules(env)
env[:ui].info(I18n.t('vagrant_cloudstack.deleting_firewall_rule'))
firewall_file = env[:machine].data_dir.join('firewall')
if firewall_file.file?
File.read(firewall_file).each_line do |line|
line_items=line.split(",").collect(&:strip)
rule_id = line_items[0]
type_string = line_items[1]
if type_string == 'firewallrule'
command_string = 'deleteFirewallRule'
response_string = 'deletefirewallruleresponse'
else
command_string = 'deleteNetworkACL'
response_string = 'deletenetworkaclresponse'
end
begin
options = {
command: command_string,
id: rule_id
}
resp = env[:cloudstack_compute].request(options)
job_id = resp[response_string]['jobid']
wait_for_job_ready(env, job_id)
rescue Fog::Compute::Cloudstack::Error => e
if e.message =~ /Unable to execute API command deletefirewallrule.*entity does not exist/
env[:ui].warn(" -- Failed to delete #{type_string}: #{e.message}")
else
raise Errors::FogError, :message => e.message
end
end
end
firewall_file.delete
end
end
def wait_for_job_ready(env, job_id, message=nil)
while true
response = env[:cloudstack_compute].query_async_job_result({:jobid => job_id})
if response['queryasyncjobresultresponse']['jobstatus'] != 0
break
else
env[:ui].info(message) if message
sleep 2
end
end
end
end
end
end
end