1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-23 22:50:09 +03:00

F : add/remove roles from running service ()

This commit is contained in:
Alejandro Huertas Herrero 2021-05-12 16:36:12 +02:00 committed by GitHub
parent 15a5c1e76d
commit 2bba9e1b8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 418 additions and 26 deletions

@ -428,4 +428,76 @@ CommandParser::CmdParser.new(ARGV) do
0
end
end
###
add_role_desc = <<-EOT.unindent
Add new role to running service
EOT
command :'add-role', add_role_desc, :service_id, [:file, nil] do
service_id = args[0]
client = helper.client(options)
if args[1]
path = args[1]
else
tmp = Tempfile.new(service_id.to_s)
path = tmp.path
if ENV['EDITOR']
editor_path = ENV['EDITOR']
else
editor_path = OpenNebulaHelper::EDITOR_PATH
end
system("#{editor_path} #{path}")
unless $CHILD_STATUS.exitstatus.zero?
STDERR.puts 'Editor not defined'
exit(-1)
end
tmp.close
end
params = {}
params[:role] = File.read(path)
params[:add] = true
json = Service.build_json_action('add_role', params)
response = client.post("#{RESOURCE_PATH}/#{service_id}/role_action",
json)
if CloudClient.is_error?(response)
[response.code.to_i, response.to_s]
else
0
end
end
###
remove_role_desc = <<-EOT.unindent
Remove role from running service
EOT
command :'remove-role', remove_role_desc, :service_id, :role_name do
service_id = args[0]
client = helper.client(options)
params = {}
params[:role] = args[1]
params[:add] = false
json = Service.build_json_action('remove_role', params)
response = client.post("#{RESOURCE_PATH}/#{service_id}/role_action",
json)
if CloudClient.is_error?(response)
[response.code.to_i, response.to_s]
else
0
end
end
end

@ -31,6 +31,8 @@ class EventManager
'WAIT_UNDEPLOY' => :wait_undeploy,
'WAIT_SCALEUP' => :wait_scaleup,
'WAIT_SCALEDOWN' => :wait_scaledown,
'WAIT_ADD' => :wait_add,
'WAIT_REMOVE' => :wait_remove,
'WAIT_COOLDOWN' => :wait_cooldown
}
@ -86,6 +88,10 @@ class EventManager
method('wait_cooldown'))
@am.register_action(ACTIONS['WAIT_SCALEUP'],
method('wait_scaleup_action'))
@am.register_action(ACTIONS['WAIT_ADD'],
method('wait_add_action'))
@am.register_action(ACTIONS['WAIT_REMOVE'],
method('wait_remove_action'))
@am.register_action(ACTIONS['WAIT_SCALEDOWN'],
method('wait_scaledown_action'))
@ -204,6 +210,56 @@ class EventManager
end
end
def wait_add_action(client, service_id, role_name, nodes, report)
if report
Log.info LOG_COMP, "Waiting #{nodes} to report ready"
rc = wait_report_ready(nodes)
else
Log.info LOG_COMP, "Waiting #{nodes} to be (ACTIVE, RUNNING)"
rc = wait(nodes, 'ACTIVE', 'RUNNING')
end
if rc[0]
@lcm.trigger_action(:add_cb,
service_id,
client,
service_id,
role_name,
rc[1])
else
@lcm.trigger_action(:add_failure_cb,
service_id,
client,
service_id,
role_name)
end
end
# Wait for nodes to be in DONE
# @param [service_id] the service id
# @param [role_name] the role name of the role which contains the VMs
# @param [nodes] the list of nodes (VMs) to wait for
def wait_remove_action(client, service_id, role_name, nodes)
Log.info LOG_COMP, "Waiting #{nodes} to be (DONE, LCM_INIT)"
rc = wait(nodes, 'DONE', 'LCM_INIT')
if rc[0]
@lcm.trigger_action(:remove_cb,
service_id,
client,
service_id,
role_name,
rc[1])
else
@lcm.trigger_action(:remove_failure_cb,
service_id,
client,
service_id,
role_name,
rc[1])
end
end
# Wait for nodes to be in DONE
# @param [service_id] the service id
# @param [role_name] the role name of the role which contains the VMs

@ -39,6 +39,10 @@ class ServiceLCM
'SCALEUP_FAILURE_CB' => :scaleup_failure_cb,
'SCALEDOWN_CB' => :scaledown_cb,
'SCALEDOWN_FAILURE_CB' => :scaledown_failure_cb,
'ADD_CB' => :add_cb,
'ADD_FAILURE_CB' => :add_failure_cb,
'REMOVE_CB' => :remove_cb,
'REMOVE_FAILURE_CB' => :remove_failure_cb,
# WD callbacks
'ERROR_WD_CB' => :error_wd_cb,
@ -79,6 +83,14 @@ class ServiceLCM
method('scaledown_failure_cb'))
@am.register_action(ACTIONS['COOLDOWN_CB'],
method('cooldown_cb'))
@am.register_action(ACTIONS['ADD_CB'],
method('add_cb'))
@am.register_action(ACTIONS['add_FAILURE_CB'],
method('add_failure_cb'))
@am.register_action(ACTIONS['REMOVE_CB'],
method('remove_cb'))
@am.register_action(ACTIONS['REMOVE_FAILURE_CB'],
method('remove_failure_cb'))
@am.register_action(ACTIONS['ERROR_WD_CB'],
method('error_wd_cb'))
@am.register_action(ACTIONS['DONE_WD_CB'],
@ -252,7 +264,7 @@ class ServiceLCM
roles,
'DEPLOYING',
'FAILED_DEPLOYING',
false,
:wait_deploy,
service.report_ready?)
if !OpenNebula.is_error?(rc)
@ -304,7 +316,7 @@ class ServiceLCM
roles,
'UNDEPLOYING',
'FAILED_UNDEPLOYING',
false)
:wait_undeploy)
if !OpenNebula.is_error?(rc)
service.set_state(Service::STATE['UNDEPLOYING'])
@ -371,7 +383,7 @@ class ServiceLCM
{ role_name => role },
'SCALING',
'FAILED_SCALING',
true,
:wait_scaleup,
service.report_ready?)
elsif cardinality_diff < 0
role.scale_way('DOWN')
@ -380,7 +392,7 @@ class ServiceLCM
{ role_name => role },
'SCALING',
'FAILED_SCALING',
true)
:wait_scaledown)
else
break OpenNebula::Error.new(
"Cardinality of #{role_name} is already at #{cardinality}"
@ -515,6 +527,69 @@ class ServiceLCM
rc
end
# Add role from running service
#
# @param client [OpenNebula::Client] Client executing action
# @param service_id [Integer] Service ID
# @param role [Hash] Role information
def add_role_action(client, service_id, role)
rc = @srv_pool.get(service_id, client) do |service|
unless service.running?
break OpenNebula::Error.new(
"Cannot modify roles in state: #{service.state_str}"
)
end
role = service.add_role(role)
break role if OpenNebula.is_error?(role)
service.update
rc = service.deploy_networks(false)
if OpenNebula.is_error?(rc)
service.set_state(Service::STATE['FAILED_DEPLOYING'])
service.update
break rc
end
service.update
add_role(client, service, role)
end
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
rc
end
# Remove role from running service
#
# @param client [OpenNebula::Client] Client executing action
# @param service_id [Integer] Service ID
# @param role [Hash] Role information
def remove_role_action(client, service_id, role)
rc = @srv_pool.get(service_id, client) do |service|
unless service.running?
break OpenNebula::Error.new(
"Cannot modify roles in state: #{service.state_str}"
)
end
unless service.roles[role]
break OpenNebula::Error.new("Role #{role} does not exist")
end
remove_role(client, service, service.roles[role])
end
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
rc
end
private
############################################################################
@ -547,7 +622,7 @@ class ServiceLCM
service.roles_deploy,
'DEPLOYING',
'FAILED_DEPLOYING',
false,
:wait_deploy,
service.report_ready?)
end
@ -608,7 +683,7 @@ class ServiceLCM
service.roles_shutdown,
'UNDEPLOYING',
'FAILED_UNDEPLOYING',
false)
:wait_undeploy)
end
service.update
@ -749,6 +824,72 @@ class ServiceLCM
undeploy_action(client, service_id)
end
def add_cb(client, service_id, role_name, _)
rc = @srv_pool.get(service_id, client) do |service|
service.roles[role_name].set_state(Role::STATE['RUNNING'])
service.set_state(Service::STATE['RUNNING'])
rc = service.update
return rc if OpenNebula.is_error?(rc)
@wd.add_service(service) if service.all_roles_running?
end
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
end
def add_failure_cb(client, service_id, role_name)
rc = @srv_pool.get(service_id, client) do |service|
# stop actions for the service if deploy fails
@event_manager.cancel_action(service_id)
service.set_state(Service::STATE['FAILED_DEPLOYING'])
service.roles[role_name].set_state(Role::STATE['FAILED_DEPLOYING'])
service.update
end
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
end
def remove_cb(client, service_id, role_name, _)
rc = @srv_pool.get(service_id, client) do |service|
service.remove_role(role_name)
service.set_state(Service::STATE['RUNNING'])
rc = service.update
return rc if OpenNebula.is_error?(rc)
@wd.add_service(service) if service.all_roles_running?
end
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
end
def remove_failure_cb(client, service_id, role_name, nodes)
rc = @srv_pool.get(service_id, client) do |service|
# stop actions for the service if deploy fails
@event_manager.cancel_action(service_id)
service.set_state(Service::STATE['FAILED_UNDEPLOYING'])
service.roles[role_name]
.set_state(Role::STATE['FAILED_UNDEPLOYING'])
service.roles[role_name].nodes.delete_if do |node|
!nodes[:failure].include?(node['deploy_id']) &&
nodes[:successful].include?(node['deploy_id'])
end
service.update
end
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
end
############################################################################
# WatchDog Callbacks
############################################################################
@ -773,7 +914,10 @@ class ServiceLCM
undeploy = false
rc = @srv_pool.get(service_id, client) do |service|
role = service.roles[role_name]
role = service.roles[role_name]
next unless role
cardinality = role.cardinality - 1
next unless role.nodes.find {|n| n['deploy_id'] == node }
@ -857,14 +1001,8 @@ class ServiceLCM
# @param [Role::STATE] error_state new state of the role
# if deployed unsuccessfuly
# rubocop:disable Metrics/ParameterLists
def deploy_roles(client, roles, success_state, error_state, scale, report)
def deploy_roles(client, roles, success_state, error_state, action, report)
# rubocop:enable Metrics/ParameterLists
if scale
action = :wait_scaleup
else
action = :wait_deploy
end
roles.each do |name, role|
rc = role.deploy
@ -887,13 +1025,7 @@ class ServiceLCM
end
end
def undeploy_roles(client, roles, success_state, error_state, scale)
if scale
action = :wait_scaledown
else
action = :wait_undeploy
end
def undeploy_roles(client, roles, success_state, error_state, action)
roles.each do |name, role|
rc = role.shutdown(false)
@ -981,5 +1113,54 @@ class ServiceLCM
end
end
def add_role(client, service, role)
@wd.remove_service(service.id)
set_deploy_strategy(service)
rc = deploy_roles(client,
{ role.name => role },
'DEPLOYING',
'FAILED_DEPLOYING',
:wait_add,
service.report_ready?)
if !OpenNebula.is_error?(rc)
service.set_state(Service::STATE['DEPLOYING'])
else
service.set_state(Service::STATE['FAILED_DEPLOYING'])
end
service.update
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
rc
end
def remove_role(client, service, role)
@wd.remove_service(service.id)
set_deploy_strategy(service)
rc = undeploy_roles(client,
{ role.name => role },
'UNDEPLOYING',
'FAILED_UNDEPLOYING',
:wait_remove)
if !OpenNebula.is_error?(rc)
service.set_state(Service::STATE['UNDEPLOYING'])
else
service.set_state(Service::STATE['FAILED_UNDEPLOYING'])
end
service.update
Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc)
rc
end
end
# rubocop:enable Naming/FileName

@ -43,7 +43,8 @@ class ServiceAutoScaler
monitoring = vm_pool.monitoring_xml(-2, 0)
monitoring = XMLElement.new(XMLElement.build_xml(monitoring,
'MONITORING_DATA'))
monitoring = monitoring.to_hash['MONITORING_DATA']['MONITORING']
monitoring = monitoring.to_hash['MONITORING_DATA']
monitoring = monitoring['MONITORING'] if monitoring
monitoring = [monitoring].flatten
vm_pool.info_all_extended

@ -141,7 +141,7 @@ module OpenNebula
# @return true if the service can be undeployed, false otherwise
def can_undeploy?
if (transient_state? && state != Service::STATE['UNDEPLOYING']) ||
state == Service::STATE['DONE'] || failed_state?
state == Service::STATE['DONE'] || failed_state?
false
else
true
@ -166,6 +166,12 @@ module OpenNebula
RECOVER_SCALE_STATES.include? STATE_STR[state]
end
# Return true if the service is running
# @return true if the service is runnning, false otherwise
def running?
state_str == 'RUNNING'
end
# Returns the running_status_vm option
# @return [true, false] true if the running_status_vm option is enabled
def report_ready?
@ -323,6 +329,36 @@ module OpenNebula
nil
end
# Adds a role to the service
#
# @param template [Hash] Role information
#
# @return [OpenNebula::Role] New role
def add_role(template)
template['state'] ||= Role::STATE['PENDING']
role = Role.new(template, self)
if @roles[role.name]
return OpenNebula::Error.new("Role #{role.name} already exists")
end
@roles[role.name] = role
@body['roles'] << template if @body && @body['roles']
role
end
# Removes a role from the service
#
# @param name [String] Role name to delete
def remove_role(name)
@roles.delete(name)
@body['roles'].delete_if do |role|
role['name'] == name
end
end
# Retrieves the information of the Service and all its Nodes.
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
@ -514,8 +550,12 @@ module OpenNebula
[true, nil]
end
def deploy_networks
body = JSON.parse(self['TEMPLATE/BODY'])
def deploy_networks(deploy = true)
if deploy
body = JSON.parse(self['TEMPLATE/BODY'])
else
body = @body
end
return if body['networks_values'].nil?
@ -531,7 +571,7 @@ module OpenNebula
if OpenNebula.is_error?(rc)
return rc
end
end
end if deploy
# Replace $attibute by the corresponding value
resolve_attributes(body)

@ -403,6 +403,38 @@ post '/service/:id/scale' do
status 204
end
post '/service/:id/role_action' do
action = JSON.parse(request.body.read)['action']
opts = action['params']
case action['perform']
when 'add_role'
begin
# Check that the JSON is valid
json_template = JSON.parse(opts['role'])
# Check the schema of the new template
ServiceTemplate.validate_role(json_template)
rescue Validator::ParseException, JSON::ParserError => e
return internal_error(e.message, VALIDATION_EC)
end
rc = lcm.add_role_action(@client, params[:id], json_template)
when 'remove_role'
rc = lcm.remove_role_action(@client, params[:id], opts['role'])
else
rc = OpenNebula::Error.new(
"Action #{action['perform']} not supported"
)
end
if OpenNebula.is_error?(rc)
return internal_error(rc.message, one_error_to_http(rc.errno))
end
status 204
end
##############################################################################
# Service Pool
##############################################################################

@ -451,6 +451,16 @@ module OpenNebula
validate_values(template)
end
def self.validate_role(template)
validator = Validator::Validator.new(
:default_values => true,
:delete_extra_properties => false,
:allow_extra_properties => true
)
validator.validate!(template, ROLE_SCHEMA)
end
def instantiate(merge_template)
rc = nil