diff --git a/install.sh b/install.sh index 23dc500a82..cd25ed8d40 100755 --- a/install.sh +++ b/install.sh @@ -1036,7 +1036,6 @@ OZONES_ETC_FILES="src/ozones/Server/etc/ozones-server.conf" OZONES_MODELS_FILES="src/ozones/Server/models/OzonesServer.rb \ src/ozones/Server/models/Auth.rb \ - src/ozones/Server/models/OCAInteraction.rb \ src/sunstone/models/OpenNebulaJSON/JSONUtils.rb" OZONES_TEMPLATE_FILES="src/ozones/Server/templates/index.html \ diff --git a/src/ozones/Client/lib/OZonesClient.rb b/src/ozones/Client/lib/OZonesClient.rb index 9587ea5b1f..bb015b6f63 100644 --- a/src/ozones/Client/lib/OZonesClient.rb +++ b/src/ozones/Client/lib/OZonesClient.rb @@ -95,7 +95,7 @@ EOT end def post_resource_str(kind, tmpl_str) - body_str = OZonesClient::to_body(tmpl_str) + body_str = OZonesClient::to_body(kind, tmpl_str) url = URI.parse("#{@endpoint}/#{kind}") @@ -112,7 +112,7 @@ EOT end def put_resource(kind, id, tmpl_str) - body_str = OZonesClient::to_body(tmpl_str) + body_str = OZonesClient::to_body(kind, tmpl_str) url = URI.parse("#{@endpoint}/#{kind}/#{id}") @@ -248,16 +248,19 @@ EOT # JSON & Template utils ########################################################################## - def self.to_body(tmpl_str) - body_str = "" + def self.to_body(kind, tmpl_str) + body_str = "{\n" + body_str << " \"#{kind}\": {" tmpl_str.strip.each_line{|line| line.strip! key,value = line.split("=") - body_str = body_str + key + "=" + URI.escape(value) + "&" + body_str << "\n \"#{key}\": \"#{value}\"," } + body_str.chop! - body_str = body_str[0..-1] + body_str << "\n }\n" + body_str << "}\n" end def self.parse_json(json_str, root_element) diff --git a/src/ozones/Server/lib/OZones/VDC.rb b/src/ozones/Server/lib/OZones/VDC.rb index bdc23b1ae7..6c452af31f 100644 --- a/src/ozones/Server/lib/OZones/VDC.rb +++ b/src/ozones/Server/lib/OZones/VDC.rb @@ -25,6 +25,7 @@ module OZones property :name, String, :required => true, :unique => true property :group_id, Integer property :vdcadminname, String, :required => true + property :vdcadmin_id, Integer property :acls, String property :hosts, String @@ -45,70 +46,305 @@ module OZones vdc_attributes["VDC"] = attributes return vdc_attributes end + end + + ########################################################################### + # This class represents a VDC able to interact with its supporting + # OpenNebula installation through OCA. Data persistence is provided by a + # Vdc class + ########################################################################### + class OpenNebulaVdc + ####################################################################### + # Constants + ####################################################################### + VDC_ATTRS = [:vdcadminname, :vdcadminpass, :name, :hosts] + + attr_reader :vdc + attr_reader :zone + + #Creates an OpenNebula VDC, using its ID, vdcid and the associated zone + def initialize(vdcid, zone = nil) + + if vdcid != -1 + @vdc = Vdc.get(vdcid) + + if !@vdc + raise "VDC with id #{vdcid} not found." + end + + @zone = OZones::Zones.get(@vdc.zones_id) + else + @zone = zone + end + + @client = OpenNebula::Client.new( + "#{@zone.onename}:#{@zone.onepass}", + @zone.endpoint, + false) + end + + def to_json + @vdc.to_json + end ####################################################################### - # Methods to handle the ACL list + # + ####################################################################### + def create(vdc_data) + #Check and prepare VDC data + VDC_ATTRS.each { |param| + if !vdc_data[param] + return OZones::Error.new("Error: Couldn't create vdc." \ + "Mandatory attribute '#{param}' is missing.") + end + } + + #Create a vdc record + @vdc = Vdc.new + + vdcpass = Digest::SHA1.hexdigest(vdc_data.delete(:vdcadminpass)) + @vdc.attributes = vdc_data + + # Create a group in the zone with the VDC name + group = OpenNebula::Group.new(OpenNebula::Group.build_xml, @client) + rc = group.allocate(@vdc.name) + + return rc if OpenNebula.is_error?(rc) + + @vdc.group_id = group.id + + # Create the VDC admin user in the Zone + user = OpenNebula::User.new(OpenNebula::User.build_xml, @client) + rc = user.allocate(@vdc.vdcadminname, vdcpass) + + return rollback(group, nil, nil, rc) if OpenNebula.is_error?(rc) + + @vdc.vdcadmin_id = user.id + + # Change primary group of the admin user to the VDC group + rc = user.chgrp(group.id) + return rollback(group, user, nil, rc) if OpenNebula.is_error?(rc) + + # Add ACLs + aclp = OpenNebula::AclPool.new(@client) + rules = get_acls + + rc, acls_str = create_acls(rules) + return rollback(group, user,acls_str,rc) if OpenNebula.is_error?(rc) + + @vdc.acls = acls_str + + return true + end + + def destroy + # Delete the resources from the VDC + delete_images + delete_templates + delete_vms + delete_vns + delete_acls + + # Delete users from a group + up = OpenNebula::UserPool.new(@client) + up.info + + up.each{|user| + if user['GID'].to_i == @vdc.group_id + user.delete + end + } + + # Delete the group + OpenNebula::Group.new_with_id(@vdc.group_id, @client).delete + + return @vdc.destroy + end + + #Cleans bootstrap operations in a zone + def clean_bootstrap + delete_acls + + OpenNebula::User.new_with_id(@vdc.vdcadmin_id, @client).delete + OpenNebula::Group.new_with_id(@vdc.group_id, @client).delete + end + + def update(host_list) + # Delete existing host ACLs + delete_host_acls + + if @vdc.acls =~ /((\d+,){#{HOST_ACL_FIRST_ID}}).*/ + newacls = $1.chop + else + newacls = @vdc.acls.clone + end + + # Create new ACLs. TODO Rollback ACL creation + if !host_list.empty? + host_acls = get_host_acls(host_list) + rc, acls_str = create_acls(host_acls) + + return rc if OpenNebula.is_error?(rc) + + #Create the new acl string. + newacls << "," << acls_str + end + + + #Update the VDC Record + begin + @vdc.raise_on_save_failure = true + @vdc.hosts = host_list + @vdc.acls = newacls + + @vdc.save + rescue => e + return OpenNebula::Error.new(e.message) + end + + return @vdc.to_json + end + + private + ####################################################################### + # Functions to generate ACL Strings ####################################################################### # The ID of the first host ACL HOST_ACL_FIRST_ID = 3 # This method returns an Array of ACL strings to create them # in the target zone - def get_vdc_acls_str(user_id, group_id) + def get_acls rule_str = Array.new # Grant permissions to the group - rule_str << "@#{group_id} VM+NET+IMAGE+TEMPLATE/* " \ + rule_str << "@#{@vdc.group_id} VM+NET+IMAGE+TEMPLATE/* " \ "CREATE+INFO_POOL_MINE" # Grant permissions to the vdc admin - rule_str << "##{user_id} USER/* CREATE" - rule_str << "##{user_id} USER/@#{group_id} MANAGE+DELETE+INFO" + rule_str << "##{@vdc.vdcadmin_id} USER/* CREATE" + rule_str << "##{@vdc.vdcadmin_id} USER/@#{@vdc.group_id} " \ + "MANAGE+DELETE+INFO" ############################################################### #When more rules are added the class constant HOST_ACL_FIRST_ID #must be modified ############################################################### - rule_str.concat(self.get_host_acls_str(group_id)) + rule_str.concat(get_host_acls) end - def get_host_acls_str(group_id, host_list = nil) + def get_host_acls(host_list = nil) rule_str = Array.new if host_list == nil - host_list = self.hosts + host_list = @vdc.hosts end # Grant permissions to use the vdc hosts host_list.split(',').each{|hostid| - rule_str << "@#{group_id} HOST/##{hostid} USE" + rule_str << "@#{@vdc.group_id} HOST/##{hostid} USE" } return rule_str end - def get_host_acls - self.acls.split(',')[HOST_ACL_FIRST_ID..-1].collect!{|x| x.to_i} + ####################################################################### + # Functions to delete resources associated to the VDC + ####################################################################### + # Deletes ACLs for the hosts + def delete_host_acls + host_acls = @vdc.acls.split(',')[HOST_ACL_FIRST_ID..-1] + + if host_acls + host_acls.each{|acl| + OpenNebula::Acl.new_with_id(acl.to_i, @client).delete + } + end end - # Returns the host acls as an array of strings. - # The acls of the VDC are updated and the host acl ids removed - def get_host_acls!(new_host_acls = nil) - acl_ids = self.acls.split(',') - vdc_acl = acl_ids.slice!(0,HOST_ACL_FIRST_ID) - - newacl = "" - vdc_acl.each{|id| - newacl << id << ',' + # Delete ACLs + def delete_acls + @vdc.acls.split(",").each{|acl| + OpenNebula::Acl.new_with_id(acl.to_i, @client).delete } - - newacl.chomp - newacl << new_host_acls if new_host_acls + end - self.acls = newacl + # Deletes images + def delete_images + ip = OpenNebula::ImagePool.new(@client) + ip.info - return acl_ids + ip.each{|image| + image.delete if image['GID'].to_i == @vdc.group_id + } + end + + # Deletes templates + def delete_templates + tp = OpenNebula::TemplatePool.new(@client) + tp.info + + tp.each{|template| + template.delete if template['GID'].to_i == @vdc.group_id + } + end + + # Deletes VMs + def delete_vms + vmp = OpenNebula::VirtualMachinePool.new(@client) + vmp.info + + vmp.each{|vm| + vm.delete if vm['GID'].to_i == @vdc.group_id + } + end + + # Deletes VNs + def delete_vns + vnp = OpenNebula::VirtualNetworkPool.new(@client) + vnp.info + + vnp.each{|vn| + vnp.delete if vn['GID'].to_i == @vdc.group_id + } + end + + ####################################################################### + # Misc helper functions for the class + ####################################################################### + + # Deletes resources from failed created VDC + def rollback(group, user, acls, rc) + group.delete + user.delete if user + + if acls + acls.chop + acls.split(",").each{|acl| + OpenNebula::Acl.new_with_id(acl.to_i, @client).delete + } + end + + return rc + end + + # Creates an acl array of acl strings. Returns true or error and + # a comma-separated list with the new acl ids + def create_acls(acls) + acls_str = "" + rc = true + + acls.each{|rule| + acl = OpenNebula::Acl.new(OpenNebula::Acl.build_xml,@client) + rc = acl.allocate(*OpenNebula::Acl.parse_rule(rule)) + + break if OpenNebula.is_error?(rc) + + acls_str << acl.id.to_s << "," + } + + return rc, acls_str.chop end end end diff --git a/src/ozones/Server/lib/OZones/Zones.rb b/src/ozones/Server/lib/OZones/Zones.rb index 6f4a2e167a..6c1567aee6 100644 --- a/src/ozones/Server/lib/OZones/Zones.rb +++ b/src/ozones/Server/lib/OZones/Zones.rb @@ -19,25 +19,38 @@ module OZones class Zones include DataMapper::Resource include OpenNebulaJSON::JSONUtils - extend OpenNebulaJSON::JSONUtils - - property :id, Serial - property :name, String, :required => true, :unique => true - property :onename, String, :required => true - property :onepass, String, :required => true - property :endpoint, String, :required => true - property :sunsendpoint, String + extend OpenNebulaJSON::JSONUtils + + ####################################################################### + # Data Model for the Zone + ####################################################################### + property :id, Serial + property :name, String, :required => true, :unique => true + property :onename, String, :required => true + property :onepass, String, :required => true + property :endpoint, String, :required => true + property :sunsendpoint, String has n, :vdcs + ####################################################################### + # Constants + ####################################################################### + ZONE_ATTRS = [:onename, :onepass, :endpoint, :name] + + ####################################################################### + # JSON Functions + ####################################################################### def self.to_hash zonePoolHash = Hash.new zonePoolHash["ZONE_POOL"] = Hash.new zonePoolHash["ZONE_POOL"]["ZONE"] = Array.new unless self.all.empty? + self.all.each{|zone| zonePoolHash["ZONE_POOL"]["ZONE"] << zone.attributes.merge({:numbervdcs => zone.vdcs.all.size}) } + return zonePoolHash end @@ -45,11 +58,132 @@ module OZones zone_attributes = Hash.new zone_attributes["ZONE"] = attributes zone_attributes["ZONE"][:vdcs] = Array.new + self.vdcs.all.each{|vdc| zone_attributes["ZONE"][:vdcs]< e + return OZones::Error.new(e.message) + end + + return zone + end end + ########################################################################### + # This class represents a Zone able to interact with its supporting + # OpenNebula installation through OCA. Data persistence is provided by a + # Zones class + ########################################################################## + class OpenNebulaZone + def initialize(zoneid) + @zone = Zones.get(zoneid) + + if !@zone + raise "Error: Zone with id #{zoneid} not found" + end + + @client = OpenNebula::Client.new( + "#{@zone.onename}:#{@zone.onepass}", + @zone.endpoint, + false) + end + + def pool_to_json(pool_kind) + pool = case pool_kind + when "host" then + OpenNebulaJSON::HostPoolJSON.new(@client) + when "image" then + OpenNebulaJSON::ImagePoolJSON.new(@client) + when "user" then + OpenNebulaJSON::UserPoolJSON.new(@client) + when "vm" then + OpenNebulaJSON::VirtualMachinePoolJSON.new(@client) + when "vn","vnet" then + OpenNebulaJSON::VirtualNetworkPoolJSON.new(@client) + when "template","vmtemplate" then + OpenNebulaJSON::TemplatePoolJSON.new(@client) + else + error = OZones::Error.new("Error: Pool #{pool_kind} not " \ + "supported for zone view") + return [404, error.to_json] + end + + pool.info + + return [200, pool.to_json] + end + + def self.all_pools_to_json(pool_kind) + pool = case pool_kind + when "host" then + OZones::AggregatedHosts.new + when "image" then + OZones::AggregatedImages.new + when "user" then + OZones::AggregatedUsers.new + when "vm" then + OZones::AggregatedVirtualMachines.new + when "vn","vnet" then + OZones::AggregatedVirtualNetworks.new + when "template","vmtemplate" then + OZones::AggregatedTemplates.new + else + error = OZones::Error.new("Error: Pool #{pool_kind} not" \ + " supported for aggregated zone view") + return [404, error.to_json] + end + + return [200, pool.to_json] + end + + + def self.check_oneadmin(name, pass, endpoint) + # Create a new client to interact with the zone + client = OpenNebula::Client.new("#{name}:#{pass}",endpoint,false) + hostpool = OpenNebula::HostPool.new(client) + + return hostpool.info + end + end end diff --git a/src/ozones/Server/models/OCAInteraction.rb b/src/ozones/Server/models/OCAInteraction.rb deleted file mode 100644 index 1b61136ae2..0000000000 --- a/src/ozones/Server/models/OCAInteraction.rb +++ /dev/null @@ -1,206 +0,0 @@ -# -------------------------------------------------------------------------- # -# Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -#--------------------------------------------------------------------------- # - -require 'OpenNebula' - -class OCAInteraction - - # Creates a VDC (user, group, hosts) - def create_vdc_in_zone(zone, vdc, adminname, adminpass) - # Create a new client to interact with the zone - client = OpenNebula::Client.new(zone.onename + ":" + zone.onepass, - zone.endpoint, - false) - - # Create a group in the zone with the VDC name - group = OpenNebula::Group.new(OpenNebula::Group.build_xml, client) - result = group.allocate(vdc.name) - return result if OpenNebula.is_error?(result) - - # Create the VDC admin user in the Zone - user = OpenNebula::User.new(OpenNebula::User.build_xml, client) - result = user.allocate(adminname, adminpass) - return rollback(client, group, - result, user) if OpenNebula.is_error?(result) - - # Change primary group of the admin user to the VDC group - result = user.chgrp(group.id) - return rollback(client, group, - result, user) if OpenNebula.is_error?(result) - - # Add ACLs - aclp = OpenNebula::AclPool.new client - rules = vdc.get_vdc_acls_str(user.id, group.id) - - acls_str = "" - - rules.each{ |rule_str| - acl = OpenNebula::Acl.new(OpenNebula::Acl.build_xml,client) - rc = acl.allocate(*OpenNebula::Acl.parse_rule(rule_str)) - - if OpenNebula.is_error?(rc) - return rollback(client, group, rc, user, acls_str) - end - - acls_str << acl.id.to_s << "," - } - - return acls_str.chop, group.id - end - - def delete_vdc_in_zone(id) - vdc = OZones::Vdc.get(id) - zone= OZones::Zones.get(vdc.zones_id) - - # Create a new client to interact with the zone - client = OpenNebula::Client.new(zone.onename + ":" + zone.onepass, - zone.endpoint, - false) - - # Delete the resources from the VDC - delete_images(vdc.group_id, client) - delete_templates(vdc.group_id, client) - delete_vms(vdc.group_id, client) - delete_vns(vdc.group_id, client) - - # Delete ACLs - delete_acls(vdc.acls, client) - - # Delete users from a group - up = OpenNebula::UserPool.new(client) - up.info - up.each{|user| - if user['GID'].to_i == vdc.group_id - OpenNebula::User.new_with_id(user['ID'], client).delete - end - } - - # Delete the group - rc = OpenNebula::Group.new_with_id(vdc.group_id, client).delete - - if OpenNebula.is_error?(rc) - return rc - else - return nil - end - end - - def update_vdc_hosts(zone, vdc, host_list) - # Create a new client to interact with the zone - client = OpenNebula::Client.new(zone.onename + ":" + zone.onepass, - zone.endpoint, - false) - # Delete existing host ACLs - vdc.get_host_acls.each{|acl_id| - OpenNebula::Acl.new_with_id(acl_id, client).delete - } - - # Create new ACLs - acls_str = "" - host_acls = vdc.get_host_acls_str(vdc.group_id, host_list) - - host_acls.each{|rule| - acl = OpenNebula::Acl.new(OpenNebula::Acl.build_xml,client) - rc = acl.allocate(*OpenNebula::Acl.parse_rule(rule)) - - - if OpenNebula.is_error?(rc) - return rc - end - - acls_str += acl.id.to_s + "," - } - - return acls_str.chop - end - - # Creates a VDC (user, group, hosts) - def check_oneadmin(oneadminname, oneadminpass, endpoint) - # Create a new client to interact with the zone - client = OpenNebula::Client.new(oneadminname + ":" + oneadminpass, - endpoint, - false) - - hostpool=OpenNebula::HostPool.new(client) - result = hostpool.info - - return result - end - - # Deletes resources from failed created VDC - def rollback(client, group, result, user=nil, acls_str=nil) - user.delete if user - group.delete - - delete_acls(acls_str, client) - - return result - end - - # Deletes images from a group - def delete_images(groupid, client) - ip = OpenNebula::ImagePool.new(client) - ip.info - ip.each{|image| - if image['GID'].to_i == groupid - OpenNebula::Image.new_with_id(image['ID'], client).delete - end - } - end - - # Deletes templates from a group - def delete_templates(groupid, client) - tp = OpenNebula::TemplatePool.new(client) - tp.info - tp.each{|template| - if template['GID'].to_i == groupid - OpenNebula::Image.new_with_id(template['ID'], client).delete - end - } - end - - # Deletes VMs from a group - def delete_vms(groupid, client) - vmp = OpenNebula::VirtualMachinePool.new(client) - vmp.info - vmp.each{|vm| - if vm['GID'].to_i == groupid - OpenNebula::VirtualMachine.new_with_id(vm['ID'], client).delete - end - } - end - - # Deletes VNs from a group - def delete_vns(groupid, client) - vnp = OpenNebula::VirtualNetworkPool.new(client) - vnp.info - vnp.each{|vn| - if vn['GID'].to_i == groupid - OpenNebula::VirtualNetwork.new_with_id(vn['ID'], client).delete - end - } - end - - # Delete ACLs from a group - def delete_acls(acls_str, client) - if acls_str != nil && !acls_str.empty? - acls_str.split(",").each{|acl_id| - OpenNebula::Acl.new_with_id(acl_id.to_i, client).delete - } - end - end -end - diff --git a/src/ozones/Server/models/OzonesServer.rb b/src/ozones/Server/models/OzonesServer.rb index 0c38ff1a5a..ca47d85fdf 100644 --- a/src/ozones/Server/models/OzonesServer.rb +++ b/src/ozones/Server/models/OzonesServer.rb @@ -14,372 +14,250 @@ # limitations under the License. # #--------------------------------------------------------------------------- # -require 'OCAInteraction' require 'JSONUtils' class OzonesServer include OpenNebulaJSON::JSONUtils - def initialize - @ocaInt = OCAInteraction.new - end - ############################################################################ - # Retrieve resources + # Get methods for the Zones and VDC interface ############################################################################ - def get_pool(kind) - pool = case kind - when "vdc" then OZones::Vdc - when "zone" then OZones::Zones - else - error = OZones::Error.new( - "Error: #{kind} resource not supported") - return [404, error.to_json] - end - - return [200, pool.to_json] + # Gets all VDCs + def get_vdcs + return 200, OZones::Vdc.to_json end - # Gets an aggreageted pool for a zone or vdc - # ie All the hosts in all the Zones - def get_aggregated_pool(kind, aggkind) - aggpool = case kind - when "zone" then - case aggkind - when "host" then OZones::AggregatedHosts.new - when "image" then OZones::AggregatedImages.new - when "user" then OZones::AggregatedUsers.new - when "vm" then OZones::AggregatedVirtualMachines.new - when "vn","vnet" then OZones::AggregatedVirtualNetworks.new - when "template","vmtemplate" then OZones::AggregatedTemplates.new - end - else - error = OZones::Error.new( - "Error: #{aggkind} aggregated pool for #{kind} not supported") - return [404, error.to_json] - end + # Gets a VDC + def get_vdc(id) + vdc = OZones::Vdc.get(id) - return [200, aggpool.to_json] - end - - # Gets an aggreageted pool for a zone or vdc in json - # ie All the hosts in all the Zones - def get_full_resource(kind, id, aggkind) - resource = retrieve_resource(kind, id) - - if OZones.is_error?(resource) - return [404, resource.to_json] - end - - # TODO build the vdc retrieval - - if kind == "zone" - client = OpenNebula::Client.new( - resource.onename + ":" + resource.onepass, - resource.endpoint, - false) - - simple_pool = case aggkind - when "host" then OpenNebulaJSON::HostPoolJSON.new(client) - when "image" then OpenNebulaJSON::ImagePoolJSON.new(client) - when "user" then OpenNebulaJSON::UserPoolJSON.new(client) - when "vm" then OpenNebulaJSON::VirtualMachinePoolJSON.new(client) - when "vn","vnet" then OpenNebulaJSON::VirtualNetworkPoolJSON.new(client) - when "template","vmtemplate" then OpenNebulaJSON::TemplatePoolJSON.new(client) - else - error = OZones::Error.new( - "Error: #{aggkind} aggregated pool for #{kind} #{id} not supported") - return [404, error.to_json] - end - - simple_pool.info - - return [200, simple_pool.to_json] - end - end - - # Get a json representation resource with local (DB) info - def get_resource(kind, id) - resource = retrieve_resource(kind, id) - if OZones.is_error?(resource) - return [404, resource.to_json] + if vdc + return [200, vdc.to_json] else - return [200, resource.to_json] + return [404, + OZones::Error.new("Error:VDC with id #{id} not found").to_json] end end + + #Gets all Zones + def get_zones + return 200, OZones::Zones.to_json + end - # Get hold of a object of a particular kind - def retrieve_resource(kind, id) - resource = case kind - when "vdc" then OZones::Vdc.get(id) - when "zone" then OZones::Zones.get(id) - else - return OZones::Error.new( - "Error: #{kind} resource not supported") - end + #Gets a zone + def get_zone(id) + zone = OZones::Zones.get(id) - if resource - return resource + if zone + return [200, zone.to_json] else - return OZones::Error.new( - "Error: Resource #{kind} with id #{id} not found") + return [404, + OZones::Error.new("Error:Zone with id #{id} not found").to_json] end end + # Gets an aggreageted view of a pool for all zones + def get_zones_pool(pool) + OZones::OpenNebulaZone::all_pools_to_json(pool) + end + + # Gets a pool view of a given zone + def get_zone_pool(id, pool) + begin + zone = OZones::OpenNebulaZone.new(id) + return zone.pool_to_json(pool) + rescue => e + return [404, OZones::Error.new(e.message).to_json] + end + end ############################################################################ # Create resources ############################################################################ - # Creates a resource of a kind, and updates the Proxy Rules - def create_resource(kind, data, body, pr) + def create_vdc (body,pr) + #Setup POST data + data = parse_json(body,"vdc") - if body.size > 0 - result = parse_json(body,kind) - data = result if !OpenNebula.is_error?(result) + if OpenNebula.is_error?(data) + return [400, OZones::Error.new("Error: Couldn't update vdc. " \ + "Reason: #{data.message}.").to_json] end - resource = case kind - when "vdc" then - vdc_data = Hash.new - data.each{|key,value| - vdc_data[key.downcase.to_sym]=value if key!="pool" - } + vdc_data = Hash.new - mandatory_params = [:vdcadminname, :vdcadminpass, - :zoneid, :name, :hosts] + data.each{|key,value| + vdc_data[key.downcase.to_sym] = value + } + + #Get the Zone that will host the VDC. And check resouces + zoneid = vdc_data.delete(:zoneid) + force = vdc_data.delete(:force) - mandatory_params.each { |param| - if !vdc_data[param] - return [400, OZones::Error.new( - "Error: Couldn't create resource #{kind}. " + - "Mandatory attribute '#{param}' is missing.").to_json] - end - } + if !zoneid + return [400, OZones::Error.new("Error: Couldn't create vdc. " \ + "Mandatory attribute zoneid missing.").to_json] + end - # Check if the referenced zone exists - zone=OZones::Zones.get(vdc_data[:zoneid]) - if !zone - error = OZones::Error.new("Error: Zone " + - "#{vdc_data[:zoneid]} not found, cannot create Vdc.") - return [404, error.to_json] - end + zone = OZones::Zones.get(zoneid) + if !zone + return [404, OZones::Error.new("Error: Couldn't create vdc. " \ + "Zone #{zoneid} not found.").to_json] + end - if (!defined? vdc_data[:force] or - (defined? vdc_data[:force] and vdc_data[:force]!="yes")) and - !host_uniqueness?(zone, vdc_data[:hosts]) - return [403, OZones::Error.new( - "Error: Couldn't create resource #{kind}. " + - "One or several hosts belong to a different VDC "+ - "and no force option was provided.").to_json] - end + if (!force or force.upcase!="YES") and + !host_uniqueness?(zone, vdc_data[:hosts]) - vdcadminname = vdc_data[:vdcadminname] - vdcadminpass = vdc_data[:vdcadminpass] - vdc_data.delete(:zoneid) - vdc_data.delete(:vdcadminpass) - vdc_data.delete(:force) + return [403, OZones::Error.new("Error: Couldn't create vdc. " \ + "Hosts are not unique, use force to override").to_json] + end - begin - vdc = OZones::Vdc.create(vdc_data) - rescue Exception => e - msg = e.message - msg["accessible in OZones::Vdc"] = "supported." - return [400, OZones::Error.new( - "Error: Couldn't create resource #{kind}." + - " #{msg}").to_json] - end + # Create de VDC + vdc = OZones::OpenNebulaVdc.new(-1,zone) + rc = vdc.create(vdc_data) - zone.vdcs << vdc - zone.save + if OpenNebula.is_error?(rc) + return [400, OZones::Error.new("Error: Couldn't create vdc. " \ + "Reason: #{rc.message}").to_json] + end - if zone.saved? and vdc.saved? - vdcadminpass = Digest::SHA1.hexdigest(vdcadminpass) - rc = @ocaInt.create_vdc_in_zone(zone, - vdc, - vdcadminname, - vdcadminpass) - if OpenNebula.is_error?(rc) - vdc.destroy - return [400, OZones::Error.new( - "Error: Couldn't create #{kind}. Reason: " + - rc.message).to_json] - else - vdc.acls = rc[0] - vdc.group_id = rc[1] - vdc.save + #Update the zone and save the vdc + zone.raise_on_save_failure = true + zone.vdcs << vdc.vdc - pr.update # Rewrite proxy conf file - return [200, vdc.to_json] - end - else - return [400, OZones::Error.new( - "Error: Couldn't create resource #{kind}." + - " Maybe duplicated name?").to_json] - end + begin + zone.save + rescue => e + vdc.clean_bootstrap - when "zone" then - zone_data=Hash.new - data.each{|key,value| - zone_data[key.downcase.to_sym]=value if key!="pool" - } + return [400, OZones::Error.new("Error: Couldn't create " \ + "vdc. Zone could not be saved: #{e.message}").to_json] + end - mandatory_params = [:onename, :onepass, :endpoint, :name] + pr.update # Rewrite proxy conf file + return [200, vdc.to_json] + end - mandatory_params.each { |param| - if !zone_data[param] - return [400, OZones::Error.new( - "Error: Couldn't create resource #{kind}. " + - "Mandatory attribute '#{param}' is missing.").to_json] - end - } + def create_zone(body, pr) + #Setup POST data + data = parse_json(body,"zone") - # Digest and check credentials - zone_data[:onepass] = - Digest::SHA1.hexdigest(zone_data[:onepass]) + if OpenNebula.is_error?(data) + return [400, OZones::Error.new("Error: Couldn't update vdc. " \ + "Reason: #{data.message}.").to_json] + end - rc = @ocaInt.check_oneadmin(zone_data[:onename], - zone_data[:onepass], - zone_data[:endpoint]) + zone = OZones::Zones.create(data) - if OpenNebula.is_error?(rc) - return [400, OZones::Error.new( - "Error: Couldn't create resource #{kind}. Reason: "+ - rc.message).to_json] - end + if OZones.is_error?(zone) + return [400, zone.to_json] + end - # Create the zone - zone = OZones::Zones.create(zone_data) - rc = zone.save - - if rc - pr.update # Rewrite proxy conf file - return [200, zone.to_json] - else - return [400, OZones::Error.new( - "Error: Couldn't create resource #{kind.upcase}." + - " Maybe duplicated name?").to_json] - end - else - error = OZones::Error.new( - "Error: #{kind.upcase} resource not supported") - return [404, error.to_json] - end + pr.update + return [200, zone.to_json] end ############################################################################ # Update resources ############################################################################ - # Updates a resource of a kind, and updates the Proxy Rules if needed - def update_resource(kind, data, body, pr) + def update_vdc(vdc_id, body) + #Setup PUT data + data = parse_json(body,"vdc") - if body.size > 0 - result = parse_json(body,kind) - data = result if !OpenNebula.is_error?(result) + if OpenNebula.is_error?(data) + return [400, OZones::Error.new("Error: Couldn't update vdc. " \ + "Reason: #{data.message}.").to_json] end - resource = case kind - when "vdc" then - vdc_data=Hash.new - vdc_id = nil - data.each{|key,value| - vdc_data[key.downcase.to_sym]=value if key!="id" - vdc_id = value if key=="id" - } + vdc_data = Hash.new - # Check parameters - if !vdc_data[:hosts] || !vdc_id - return [400, OZones::Error.new( - "Error: Couldn't update resource #{kind}. " + - "Need ID and HOSTS to update.").to_json] - end + data.each{|key,value| + vdc_data[key.downcase.to_sym]=value + } - # Check if the referenced Vdc exists - vdc=OZones::Vdc.get(vdc_id) - if !vdc - error = OZones::Error.new("Error: Vdc " + - "#{vdc_id} not found, cannot update Vdc.") - return [404, error.to_json] - end + hosts = vdc_data.delete(:hosts) + force = vdc_data.delete(:force) - # Get the zone where the Vdc belongs - zone=OZones::Zones.get(vdc.zones.id) - if !zone - error = OZones::Error.new("Error: Zone " + - "#{vdc.zones.id} not found, cannot update Vdc.") - return [404, error.to_json] - end - - if (!vdc_data[:force] or vdc_data[:force].upcase!="YES") and - !host_uniqueness?(zone, vdc_data[:hosts], vdc_id.to_i) - return [403, OZones::Error.new( - "Error: Couldn't update resource #{kind}. " + - "One or several hosts belong to a different VDC "+ - "and no force option was provided.").to_json] - end + # Check parameters + if !hosts + return [400, OZones::Error.new("Error: Couldn't update vdc. " \ + "Missing HOSTS.").to_json] + end - rc = @ocaInt.update_vdc_hosts(zone, vdc, vdc_data[:hosts]) + # Check if the referenced Vdc exists + begin + vdc = OZones::OpenNebulaVdc.new(vdc_id) + rescue => e + return [404, OZones::Error.new("Error: Couldn't update vdc. " \ + "#{e.message}").to_json] + end + + if (!force or force.upcase != "YES") and + !host_uniqueness?(vdc.zone, hosts, vdc_id.to_i) - if !OpenNebula.is_error?(rc) - vdc.hosts = vdc_data[:hosts] - vdc.get_host_acls!(rc) - - vdc.save - - if vdc.saved? - return [200, vdc.to_json] - else - return [500, OZones::Error.new( - "Error: Couldn't update resource #{kind}.").to_json] - end - - else - return [500, OZones::Error.new( - "Error: Couldn't update resource #{kind.upcase}." + - " Failed to update ACLs").to_json] - end - else - error = OZones::Error.new( - "Error: #{kind.upcase} resource update not supported") - return [404, error.to_json] - end - end + return [403, OZones::Error.new("Error: Couldn't update vdc. " \ + "Hosts are not unique, use force to override").to_json] + end + + rc = vdc.update(hosts) + + if !OpenNebula.is_error?(rc) + return [200, rc] + else + return [500, OZones::Error.new("Error: Couldn't update vdc. " \ + " Reason: #{rc.message}").to_json] + end + end ############################################################################ # Delete resources ############################################################################ - # Deletes a resource of a kind, and updates the Proxy Rules - def delete_resource(kind, id, pr) - resource = retrieve_resource(kind, id) - if OZones.is_error?(resource) - return [404, resource.to_json] + def delete_vdc(id, pr) + begin + vdc = OZones::OpenNebulaVdc.new(id) + rc = vdc.destroy + rescue => e + return [404, OZones::Error.new("Error: Can not delete vdc. " \ + "Reason: #{e.message}").to_json] end - if kind == "vdc" - rc = @ocaInt.delete_vdc_in_zone(id) - if OpenNebula.is_error?(rc) - return [500, OZones::Error.new( - "Error: Couldn't delete resources from VDC with id #{id}, " + - "aborting VDC deletion. Reason:" + rc.message).to_json] - end - end - - if !resource.destroy - return [500, OZones::Error.new( - "Error: Couldn't delete resource #{kind} with id #{id}").to_json] + if !rc + return [500, OZones::Error.new("Error: Couldn't delete " \ + "vdc #{id}").to_json] else pr.update # Rewrite proxy conf file - return [200, OZones.str_to_json( - "Resource #{kind} with id #{id} successfully deleted")] + return [200, OZones.str_to_json("Vdc #{id} successfully deleted")] + end + end + + def delete_zone(id, pr) + zone = OZones::Zones.get(id) + + if zone + rc = zone.destroy + else + return [404, OZones::Error.new("Error: Can not delete " \ + "zone. Reason: zone #{id} not found").to_json] + end + + if !rc + return [500, OZones::Error.new("Error: Couldn't delete " \ + "zone #{id}").to_json] + else + pr.update # Rewrite proxy conf file + return [200, OZones.str_to_json("Zone #{id} successfully deleted")] end end ############################################################################ - # Helper functions + # Misc Helper Functions ############################################################################ - + private + # Check if hosts are already include in any Vdc of the zone def host_uniqueness?(zone, host_list, vdc_id = -1) + return true if host_list.empty? + all_hosts = "" zone.vdcs.all.each{|vdc| if vdc.hosts != nil and !vdc.hosts.empty? and vdc.id != vdc_id @@ -395,6 +273,4 @@ class OzonesServer return true end - - end diff --git a/src/ozones/Server/ozones-server.rb b/src/ozones/Server/ozones-server.rb index afb31e9f50..80a309a8de 100755 --- a/src/ozones/Server/ozones-server.rb +++ b/src/ozones/Server/ozones-server.rb @@ -226,48 +226,60 @@ get '/config' do end ############################################################################## -# GET Pool information +# GET information ############################################################################## -get '/:pool' do - @OzonesServer.get_pool(params[:pool]) +get '/vdc' do + @OzonesServer.get_vdcs +end + +get '/vdc/:id' do + @OzonesServer.get_vdc(params[:id]) +end + +get '/zone' do + @OzonesServer.get_zones +end + +get %r{/zone/([\d]+)/([\w]+)} do + @OzonesServer.get_zone_pool(params[:captures][0], params[:captures][1]) +end + +get %r{/zone/([\d]+)} do + @OzonesServer.get_zone(params[:captures].first) +end + +get %r{/zone/([\w]+)} do + @OzonesServer.get_zones_pool(params[:captures].first) end ############################################################################## -# GET Resource information +# POSTs information ############################################################################## -get %r{/(zone|vdc)/(\d+)/(\w+)} do |kind, id, aggpool| - @OzonesServer.get_full_resource(kind,id,aggpool) + +post '/vdc' do + @OzonesServer.create_vdc(request.body.read, @pr) end -get %r{/(zone|vdc)/(\d+)} do |kind, id| - @OzonesServer.get_resource(kind,id) -end - -get '/:pool/:aggpool' do - @OzonesServer.get_aggregated_pool(params[:pool], params[:aggpool]) -end - -############################################################################## -# Create a new Resource -############################################################################## -post '/:pool' do - @OzonesServer.create_resource(params[:pool], params, request.body.read, @pr) +post '/zone' do + @OzonesServer.create_zone(request.body.read, @pr) end ############################################################################## # Update Resource ############################################################################## -put '/:resource/:id' do - @OzonesServer.update_resource(params[:resource], params, - request.body.read, @pr) +put '/vdc/:id' do + @OzonesServer.update_vdc(params[:id], request.body.read) end ############################################################################## # Delete Resource ############################################################################## -delete '/:resource/:id' do - @OzonesServer.delete_resource(params[:resource], params[:id], @pr) +delete '/vdc/:id' do + @OzonesServer.delete_vdc(params[:id], @pr) +end + +delete '/zone/:id' do + @OzonesServer.delete_zone(params[:id], @pr) end -