diff --git a/src/cli/oneflow b/src/cli/oneflow index e4f00d78e4..8e6efbf6c1 100755 --- a/src/cli/oneflow +++ b/src/cli/oneflow @@ -82,6 +82,12 @@ CommandParser::CmdParser.new(ARGV) do :description => 'Force flow necover delete' } + APPEND = { + :name => 'append', + :large => '--append', + :description => 'Append template to the current one' + } + FORMAT = [OpenNebulaHelper::JSON, OpenNebulaHelper::YAML] # create helper object @@ -364,7 +370,11 @@ CommandParser::CmdParser.new(ARGV) do be launched to modify the current content. EOT - command :update, update_desc, :service_id, [:file, nil] do + command :update, + update_desc, + :service_id, + [:file, nil], + :options => APPEND do service_id = args[0] client = helper.client(options) @@ -382,8 +392,10 @@ CommandParser::CmdParser.new(ARGV) do tmp = Tempfile.new(service_id.to_s) path = tmp.path - tmp.write(JSON.pretty_generate(template)) - tmp.flush + unless options[:append] + tmp.write(JSON.pretty_generate(template)) + tmp.flush + end if ENV['EDITOR'] editor_path = ENV['EDITOR'] @@ -402,7 +414,17 @@ CommandParser::CmdParser.new(ARGV) do end end - response = client.put("#{RESOURCE_PATH}/#{service_id}", File.read(path)) + if options[:append] + req = {} + req['append'] = true + req['template'] = File.read(path) + + response = client.put("#{RESOURCE_PATH}/#{service_id}", + req.to_json) + else + response = client.put("#{RESOURCE_PATH}/#{service_id}", + File.read(path)) + end if CloudClient.is_error?(response) [response.code.to_i, response.to_s] diff --git a/src/flow/lib/LifeCycleManager.rb b/src/flow/lib/LifeCycleManager.rb index 06b387bebd..17b9b9d876 100644 --- a/src/flow/lib/LifeCycleManager.rb +++ b/src/flow/lib/LifeCycleManager.rb @@ -464,7 +464,8 @@ class ServiceLCM # @param client [OpenNebula::Client] Client executing action # @param service_id [Integer] Service ID # @param new_tempalte [String] New template - def service_update(client, service_id, new_template) + # @param append [Boolean] True to append template + def service_update(client, service_id, new_template, append) rc = @srv_pool.get(service_id, client) do |service| unless service.can_update? break OpenNebula::Error.new( @@ -472,7 +473,7 @@ class ServiceLCM ) end - rc = service.check_new_template(new_template) + rc = service.check_new_template(new_template, append) unless rc[0] if rc[1] == 'name' @@ -486,7 +487,7 @@ class ServiceLCM end end - service.update(new_template) + service.update(new_template, append) end Log.error LOG_COMP, rc.message if OpenNebula.is_error?(rc) diff --git a/src/flow/lib/models/service.rb b/src/flow/lib/models/service.rb index 6a2c6c7e20..b11795c131 100644 --- a/src/flow/lib/models/service.rb +++ b/src/flow/lib/models/service.rb @@ -522,31 +522,40 @@ module OpenNebula # Check that changes values are correct # - # @param template_json [String] New template + # @param template_json [String] New template + # @param append [Boolean] True to append template to the current # # @return [Boolean, String] True, nil if everything is correct # False, attr if attr was changed - def check_new_template(template_json) + def check_new_template(template_json, append) template = JSON.parse(template_json) - if template['roles'].size != @roles.size - return [false, 'service/roles size'] - end + if append + IMMUTABLE_ATTRS.each do |attr| + next if template[attr].nil? - IMMUTABLE_ATTRS.each do |attr| - next if template[attr] == @body[attr] + return [false, "service/#{attr}"] + end + else + if template['roles'].size != @roles.size + return [false, 'service/roles size'] + end - return [false, "service/#{attr}"] - end + IMMUTABLE_ATTRS.each do |attr| + next if template[attr] == @body[attr] - template['roles'].each do |role| - # Role name can't be changed, if it is changed some problems - # may appear, as name is used to reference roles - return [false, 'name'] unless @roles[role['name']] + return [false, "service/#{attr}"] + end - rc = @roles[role['name']].check_new_template(role) + template['roles'].each do |role| + # Role name can't be changed, if it is changed some problems + # may appear, as name is used to reference roles + return [false, 'name'] unless @roles[role['name']] - return rc unless rc[0] + rc = @roles[role['name']].check_new_template(role) + + return rc unless rc[0] + end end [true, nil] diff --git a/src/flow/oneflow-server.rb b/src/flow/oneflow-server.rb index a36c7a774c..bfd1ada6d9 100644 --- a/src/flow/oneflow-server.rb +++ b/src/flow/oneflow-server.rb @@ -320,18 +320,39 @@ end put '/service/:id' do new_template = request.body.read + append = nil begin # Check that the JSON is valid json_template = JSON.parse(new_template) + # ---------------------------------------------------------------------- + # Manage append + # + # To avoid changing the way the API request is performed, to check if + # manage is present, we check that the JSON contains especific keys: + # + # - template: with template to use to update + # - append: true (or present) to append the template + # ---------------------------------------------------------------------- + if json_template.key?('append') + unless json_template.key?('template') + return internal_error('Missing template to append', + VALIDATION_EC) + end + + append = json_template['append'] + new_template = json_template['template'] + json_template = JSON.parse(new_template) + end + # Check the schema of the new template - ServiceTemplate.validate(json_template) + ServiceTemplate.validate(json_template) unless append rescue Validator::ParseException, JSON::ParserError => e return internal_error(e.message, VALIDATION_EC) end - rc = lcm.service_update(@client, params[:id], new_template) + rc = lcm.service_update(@client, params[:id], new_template, append) if OpenNebula.is_error?(rc) return internal_error(rc.message, one_error_to_http(rc.errno)) diff --git a/src/oca/ruby/opennebula/flow/service_template.rb b/src/oca/ruby/opennebula/flow/service_template.rb index c4dbe8429b..c656104651 100644 --- a/src/oca/ruby/opennebula/flow/service_template.rb +++ b/src/oca/ruby/opennebula/flow/service_template.rb @@ -309,7 +309,9 @@ module OpenNebula if append IMMUTABLE_ATTRS.each do |attr| - return [false, "service_template/#{attr}"] if !template[attr].nil? + next if template[attr].nil? + + return [false, "service_template/#{attr}"] end else IMMUTABLE_ATTRS.each do |attr|