1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-11 05:17:41 +03:00

F #2645: Add cleanup option and fix some minor bugs (#2954)

This commit is contained in:
Alejandro Huertas Herrero 2019-02-15 16:22:26 +01:00 committed by Tino Vázquez
parent 08538c8156
commit 15533368a8
10 changed files with 281 additions and 184 deletions

View File

@ -85,20 +85,20 @@ class OneProvisionHelper < OpenNebulaHelper::OneHelper
provision.create(config)
end
def configure(provision_id, options)
def configure(provision_id, force)
provision = OneProvision::Provision.new(provision_id)
provision.refresh
provision.configure((options.key? :force))
provision.configure(force)
end
def delete(provision_id)
def delete(provision_id, cleanup)
provision = OneProvision::Provision.new(provision_id)
provision.refresh
provision.delete
provision.delete(cleanup)
end
#######################################################################

View File

@ -155,9 +155,9 @@ CommandParser::CmdParser.new(ARGV) do
:format => Integer
}
DELETE_ALL = {
:name => 'delete_all',
:large => '--delete-all',
CLEANUP = {
:name => 'cleanup',
:large => '--cleanup',
:description => 'Delete all vms and images first, ' \
'then delete the resources.'
}
@ -254,7 +254,7 @@ CommandParser::CmdParser.new(ARGV) do
:options => [MODES, FORCE] do
helper.parse_options(options)
helper.configure(args[0], options)
helper.configure(args[0], (options.key?(:force)))
end
###
@ -266,10 +266,10 @@ CommandParser::CmdParser.new(ARGV) do
command :delete,
provision_delete_desc,
:provisionid,
:options => [MODES, THREADS, DELETE_ALL] do
:options => [MODES, THREADS, CLEANUP] do
helper.parse_options(options)
helper.delete(args[0])
helper.delete(args[0], (options.key? :cleanup))
end
########################################################################

View File

@ -947,16 +947,6 @@ module OpenNebula
end
end
private
def action(name)
return Error.new('ID not defined') if !@pe_id
rc = @client.call(VM_METHODS[:action], name, @pe_id)
rc = nil if !OpenNebula.is_error?(rc)
return rc
end
def wait_state(state, timeout=10)
vm_state = ""
lcm_state = ""
@ -979,6 +969,16 @@ module OpenNebula
"VM is in state #{vm_state}, #{lcm_state}")
end
private
def action(name)
return Error.new('ID not defined') if !@pe_id
rc = @client.call(VM_METHODS[:action], name, @pe_id)
rc = nil if !OpenNebula.is_error?(rc)
return rc
end
def wait_lcm_state(state, timeout=10)
vm_state = ""
lcm_state = ""

View File

@ -30,11 +30,12 @@ module OneProvision
# Creates a new CLUSTER in OpenNebula
#
# @param template [String] Template of the CLUSTER
# @param provision_id [String] ID of the provision
def create(template, provision_id)
# @param template [String] Template of the CLUSTER
# @param provision_id [String] ID of the provision
# @param provision_name [String] Name of the provision
def create(template, provision_id, provision_name)
template['provision']['provision_id'] = provision_id
template['provision']['name'] = template['name']
template['provision']['name'] = provision_name
name = template['name']
template = Utils.template_like_str(template)

View File

@ -32,8 +32,10 @@ module OneProvision
# @param template [String] Template of the DATASTORE
# @param pm_mad [String] Provision Manager Driver
# @param provision_id [String] ID of the provision
def create(cluster_id, template, pm_mad, provision_id)
# @param provision_name [String] Name of the provision
def create(cluster_id, template, pm_mad, provision_id, provision_name)
template['provision']['provision_id'] = provision_id
template['provision']['name'] = provision_name
template = Utils.template_like_str(template)
template += "PM_MAD=\"#{pm_mad}\"\n"

View File

@ -180,30 +180,24 @@ module OneProvision
OneProvisionLogger.debug("Offlining OpenNebula host: #{id}")
@@mutex.synchronize do
rc = @one.offline
if OpenNebula.is_error?(rc)
raise OneProvisionLoopException, rc.message
end
Utils.exception(@one.offline)
end
end
# unprovision host
OneProvisionLogger.debug("Undeploying host: #{id}")
if deploy_id
# unprovision host
OneProvisionLogger.debug("Undeploying host: #{id}")
Driver.pm_driver_action(pm_mad, 'cancel', [deploy_id, name], @one)
params = [deploy_id, name]
Driver.pm_driver_action(pm_mad, 'cancel', params, @one)
end
# delete ONE host
OneProvisionLogger.debug("Deleting OpenNebula host: #{id}")
@@mutex.synchronize do
# Fix ubuntu 14.04 borken pipe
@one.info
rc = @one.delete
if OpenNebula.is_error?(rc)
raise OneProvisionLoopException, rc.message
end
Utils.exception(@one.delete)
end
end

View File

@ -60,35 +60,32 @@ module OneProvision
@name = @clusters[0]['TEMPLATE/PROVISION/NAME']
end
# TODO: rename delete_all -> cleanup
#
# Deletes the PROVISION
#
def delete
# @param cleanup [Boolean] True to delete running VMs and images
def delete(cleanup = false)
Utils.fail('Provision not found.') unless exists
if running_vms? && !cleanup
Utils.fail('Provision with running VMs can\'t be deleted')
end
if images? && !cleanup
Utils.fail('Provision with images can\'t be deleted')
end
delete_vms if cleanup
delete_images if cleanup
OneProvisionLogger.info("Deleting provision #{@id}")
# offline and (optionally) clean all hosts
OneProvisionLogger.debug('Offlining OpenNebula hosts')
@hosts.each do |h|
host = Host.new(h['ID'])
@hosts.each do |host|
Driver.retry_loop 'Failed to offline host' do
rc = h.offline
if OpenNebula.is_error?(rc)
raise OneProvisionLoopException, rc.message
end
rc = h.info
if OpenNebula.is_error?(rc)
raise OneProvisionLoopException, rc.message
end
end
if host.running_vms?
Utils.fail('Provision with running VMs can\'t be deleted')
Utils.exception(host.offline)
end
end
@ -97,25 +94,27 @@ module OneProvision
threads = []
@hosts.each do |host|
host = Host.new(host['ID'])
Driver.retry_loop 'Failed to delete hosts' do
@hosts.each do |host|
host = Host.new(host['ID'])
if Options.threads > 1
while Thread.list.count > Options.threads
threads.map do |thread|
thread.join(5)
if Options.threads > 1
while Thread.list.count > Options.threads
threads.map do |thread|
thread.join(5)
end
end
end
threads << Thread.new do
threads << Thread.new do
host.delete
end
else
host.delete
end
else
host.delete
end
end
threads.map(&:join)
threads.map(&:join)
end
# delete all other deployed objects
OneProvisionLogger.info('Deleting provision objects')
@ -127,13 +126,7 @@ module OneProvision
Driver.retry_loop "Failed to delete #{msg}" do
OneProvisionLogger.debug("Deleting OpenNebula #{msg}")
# Fix ubuntu 14.04 broken pipe
obj.info
rc = obj.delete
if OpenNebula.is_error?(rc)
raise OneProvisionLoopException, rc.message
end
Utils.exception(obj.delete)
end
end
end
@ -170,7 +163,7 @@ module OneProvision
def create(config)
Ansible.check_ansible_version
Driver.retry_loop 'Failed to create provision' do
begin
# read provision file
cfg = Utils.create_config(Utils.read_config(config))
@ -178,12 +171,19 @@ module OneProvision
OneProvisionLogger.info('Creating provision objects')
cluster = create_cluster(cfg)
cid = cluster.id
cluster = nil
cid = nil
Driver.retry_loop 'Failed to create cluster' do
cluster = create_cluster(cfg)
cid = cluster.id
end
Mode.new_cleanup(true)
create_resources(cfg, cid)
Driver.retry_loop 'Failed to create some resources' do
create_resources(cfg, cid)
end
if cfg['hosts'].nil?
puts "ID: #{@id}"
@ -191,35 +191,39 @@ module OneProvision
return 0
end
begin
Driver.retry_loop 'Failed to create hosts' do
create_hosts(cfg, cid)
# ask user to be patient, mandatory for now
STDERR.puts 'WARNING: This operation can ' \
'take tens of minutes. Please be patient.'
OneProvisionLogger.info('Deploying')
deploy_ids = deploy_hosts
if deploy_ids.nil? || deploy_ids.empty?
Utils.fail('Deployment failed, no ID got from driver')
end
OneProvisionLogger.info('Monitoring hosts')
update_hosts(deploy_ids)
Ansible.configure(@hosts)
puts "ID: #{@id}"
0
rescue OneProvisionCleanupException
delete
-1
end
# ask user to be patient, mandatory for now
STDERR.puts 'WARNING: This operation can ' \
'take tens of minutes. Please be patient.'
OneProvisionLogger.info('Deploying')
deploy_ids = nil
Driver.retry_loop 'Failed to deploy hosts' do
deploy_ids = deploy_hosts
end
if deploy_ids.nil? || deploy_ids.empty?
Utils.fail('Deployment failed, no ID got from driver')
end
OneProvisionLogger.info('Monitoring hosts')
update_hosts(deploy_ids)
Ansible.configure(@hosts)
puts "ID: #{@id}"
0
rescue OneProvisionCleanupException
delete
-1
end
end
@ -239,23 +243,19 @@ module OneProvision
#
# @return [OpenNebula::Cluster] The new cluster
def create_cluster(cfg)
cluster = nil
msg = "Creating OpenNebula cluster: #{cfg['cluster']['name']}"
Driver.retry_loop 'Failed to create cluster' do
msg = "Creating OpenNebula cluster: #{cfg['cluster']['name']}"
OneProvisionLogger.debug(msg)
OneProvisionLogger.debug(msg)
# create new cluster
cluster = Cluster.new
cluster.create(cfg['cluster'], @id, @name)
cluster = cluster.one
cid = cluster.id
# create new cluster
cluster = Cluster.new
cluster.create(cfg['cluster'], @id)
cluster = cluster.one
cid = cluster.id
@clusters << cluster
@clusters << cluster
OneProvisionLogger.debug("cluster created with ID: #{cid}")
end
OneProvisionLogger.debug("cluster created with ID: #{cid}")
cluster
end
@ -269,43 +269,32 @@ module OneProvision
next if cfg[r].nil?
cfg[r].each do |x|
begin
if cfg['defaults'] && cfg['defaults']['driver']
driver = cfg['defaults']['provision']['driver']
end
r_name = "#{r}: #{x['name']}"
Driver.retry_loop "Failed to create #{r_name}" do
msg = "Creating OpenNebula #{r_name}"
OneProvisionLogger.debug(msg)
erb = Utils.evaluate_erb(self, x)
if r == 'datastores'
datastore = Datastore.new
datastore.create(cid.to_i, erb, driver, @id)
@datastores << datastore.one
else
vnet = Vnet.new
vnet.create(cid.to_i, erb, driver, @id)
@vnets << vnet.one
end
r = 'vnets' if r == 'networks'
rid = instance_variable_get("@#{r}").last['ID']
rname = r.chomp('s').capitalize
msg = "#{rname} created with ID: #{rid}"
OneProvisionLogger.debug(msg)
end
rescue OneProvisionCleanupException
refresh
delete
-1
if cfg['defaults'] && cfg['defaults']['driver']
driver = cfg['defaults']['provision']['driver']
end
msg = "Creating OpenNebula #{r}: #{x['name']}"
OneProvisionLogger.debug(msg)
erb = Utils.evaluate_erb(self, x)
if r == 'datastores'
datastore = Datastore.new
datastore.create(cid.to_i, erb, driver, @id, @name)
@datastores << datastore.one
else
vnet = Vnet.new
vnet.create(cid.to_i, erb, driver, @id, @name)
@vnets << vnet.one
end
r = 'vnets' if r == 'networks'
rid = instance_variable_get("@#{r}").last['ID']
rname = r.chomp('s').capitalize
msg = "#{rname} created with ID: #{rid}"
OneProvisionLogger.debug(msg)
end
end
end
@ -317,7 +306,7 @@ module OneProvision
def create_hosts(cfg, cid)
cfg['hosts'].each do |h|
erb = Utils.evaluate_erb(self, h)
dfile = Utils .create_deployment_file(erb, @id)
dfile = Utils .create_deployment_file(erb, @id, @name)
playbook = cfg['playbook']
host = Host.new
@ -394,6 +383,111 @@ module OneProvision
end
end
# Checks if the PROVISION has running VMs
#
# @return [Boolean] True if there are running VMs
def running_vms?
@hosts.each do |host|
Utils.exception(host.info)
return true if host['HOST_SHARE/RUNNING_VMS'].to_i > 0
end
false
end
# Checks if the PROVISION has images in its datastores
#
# @return [Boolean] True if there are images
def images?
@datastores.each do |datastore|
Utils.exception(datastore.info)
images = datastore.retrieve_elements('IMAGES/ID')
return true if images
end
false
end
# Deletes VMs from the PROVISION
def delete_vms
Driver.retry_loop 'Failed to delete running_vms' do
hosts = []
@hosts.each do |host|
Utils.exception(host.info)
hosts << host if host['HOST_SHARE/RUNNING_VMS'].to_i > 0
end
hosts.each do |host|
vm_ids = host.retrieve_elements('VMS/ID')
vm_ids.each do |id|
delete_object('vm', id)
end
end
if running_vms?
raise OneProvisionLoopException, 'Still found running VMs'
end
end
end
# Deletes images from the PROVISION
def delete_images
Driver.retry_loop 'Failed to delete images' do
datastores = []
@datastores.each do |datastore|
Utils.exception(datastore.info)
images = datastore.retrieve_elements('IMAGES/ID')
datastores << datastore if images
end
datastores.each do |datastore|
image_ids = datastore.retrieve_elements('IMAGES/ID')
image_ids.each do |id|
delete_object('image', id)
end
end
if images?
raise OneProvisionLoopException, 'Still found images'
end
end
end
# Deletes an object
#
# @param type [String] Type of the object (vm, image)
# @param id [String] ID of the object
def delete_object(type, id)
msg = "Deleting OpenNebula #{type} #{id}"
OneProvision::OneProvisionLogger.debug(msg)
object = nil
client = OpenNebula::Client.new
if type == 'vm'
object = OpenNebula::VirtualMachine.new_with_id(id, client)
else
object = OpenNebula::Image.new_with_id(id, client)
end
Utils.exception(object.info)
Utils.exception(object.delete)
Utils.exception(object.wait_state('DONE')) if type == 'vm'
end
end
end

View File

@ -79,9 +79,7 @@ module OneProvision
rc = @one.allocate(template, cluster)
end
if OpenNebula.is_error?(rc)
Utils.fail(rc.message)
end
Utils.exception(rc)
if @type == 'Cluster'
@one.update(template, true)
@ -97,11 +95,7 @@ module OneProvision
# @return [Array] with provision resource if id!=nil
# with all resources if if==nil
def get(id = nil)
rc = @pool.info
if OpenNebula.is_error?(rc)
Utils.fail(rc.message)
end
Utils.exception(@pool.info)
if id
return @pool.select do |resource|

View File

@ -164,7 +164,11 @@ module OneProvision
sections = %w[connection provision configuration]
sections.each do |section|
data = CONFIG_DEFAULTS[section] || {}
defaults = yaml['defaults'][section]
if yaml['defaults']
defaults = yaml['defaults'][section]
end
h_sec = host[section]
# merge defaults with globals
# and device specific params
@ -182,24 +186,21 @@ module OneProvision
next unless yaml[r]
yaml[r] = yaml[r].map do |x|
if defaults && x['provision']
x['provision'] ||= {}
if defaults && defaults.key?('provision')
x['provision'].merge!(defaults['provision'])
else
x['provision'] = {} unless x['provision']
end
x
end
end
cluster_p = yaml['cluster']['provision']
yaml['cluster']['provision'] ||= {}
if defaults && cluster_p
if defaults && defaults.key?('provision')
yaml['cluster']['provision']
.merge!(defaults['provision'])
else
yaml['cluster']['provision'] = {} unless cluster_p
end
rescue StandardError => e
Utils.fail("Failed to read configuration: #{e}")
@ -305,11 +306,12 @@ module OneProvision
# Creates the host deployment file
#
# @param host [Hash] Hash with host information
# @param provision_id [String] ID of the provision
# @param host [Hash] Hash with host information
# @param provision_id [String] ID of the provision
# @param provision_name [String] Name of the provision
#
# @return [Nokogiri::XML] XML with the host information
def create_deployment_file(host, provision_id)
def create_deployment_file(host, provision_id, provision_name)
ssh_key = try_read_file(host['connection']['public_key'])
config = Base64.strict_encode64(host['configuration'].to_yaml)
@ -328,6 +330,7 @@ module OneProvision
end
end
xml.send('PROVISION_ID', provision_id)
xml.send('NAME', provision_name)
end
if host['configuration']
xml.PROVISION_CONFIGURATION_BASE64 config
@ -361,6 +364,13 @@ module OneProvision
exit(code)
end
# Checks if the return_code is error
def exception(return_code)
error = OpenNebula.is_error?(return_code)
raise OneProvisionLoopException, return_code.message if error
end
# Gets error message
#
# @param text [String] Text with error message inside

View File

@ -28,12 +28,14 @@ module OneProvision
# Creates a new VNET in OpenNebula
#
# @param cluster_id [Integer] ID of the CLUSTER where is the VNET
# @param template [String] Template of the VNET
# @param pm_mad [String] Provision Manager Driver
# @param provision_id [String] ID of the provision
def create(cluster_id, template, pm_mad, provision_id)
# @param cluster_id [Integer] ID of the CLUSTER where is the VNET
# @param template [String] Template of the VNET
# @param pm_mad [String] Provision Manager Driver
# @param provision_id [String] ID of the provision
# @param provision_name [String] Name of the provision
def create(cluster_id, template, pm_mad, provision_id, provision_name)
template['provision']['provision_id'] = provision_id
template['provision']['name'] = provision_name
template = Utils.template_like_str(template)
template += "PM_MAD=\"#{pm_mad}\"\n"