mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-22 18:50:08 +03:00
F #5112: Increase onegate functionality for VNF
co-authored-by: Christian González <cgonzalez@opennebula.io>
This commit is contained in:
parent
613ea388ba
commit
4c0a5c3ef3
@ -135,6 +135,18 @@ public:
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class VirtualMachinePoolInfoSet : public RequestManagerPoolInfoFilter
|
||||
{
|
||||
public:
|
||||
VirtualMachinePoolInfoSet();
|
||||
|
||||
void request_execute(
|
||||
xmlrpc_c::paramList const& paramList, RequestAttributes& att) override;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class VirtualMachinePoolAccounting : public RequestManagerPoolInfoFilter
|
||||
{
|
||||
public:
|
||||
|
@ -2542,7 +2542,8 @@ src/sunstone/public/locale/languages/tr_datatable.txt"
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
ONEGATE_FILES="src/onegate/onegate-server.rb \
|
||||
src/onegate/config.ru"
|
||||
src/onegate/config.ru \
|
||||
share/onegate/onegate"
|
||||
|
||||
ONEGATE_BIN_FILES="src/onegate/bin/onegate-server"
|
||||
|
||||
|
@ -394,6 +394,35 @@ module OneGate
|
||||
end
|
||||
end
|
||||
|
||||
# Virtual Router module
|
||||
module VirtualRouter
|
||||
|
||||
def self.print(json_hash, _extended = false)
|
||||
OneGate.print_header('VROUTER ' + json_hash['VROUTER']['ID'])
|
||||
OneGate.print_key_value('NAME', json_hash['VROUTER']['NAME'])
|
||||
|
||||
vms_ids = Array(json_hash['VROUTER']['VMS']['ID'])
|
||||
|
||||
vms = vms_ids.join(',')
|
||||
|
||||
OneGate.print_key_value('VMS', vms)
|
||||
puts
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Virtual Network module
|
||||
module VirtualNetwork
|
||||
|
||||
def self.print(json_hash, _extended = false)
|
||||
OneGate.print_header('VNET')
|
||||
OneGate.print_key_value('ID', json_hash['VNET']['ID'])
|
||||
|
||||
puts
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Client
|
||||
def initialize(opts={})
|
||||
@vmid = ENV["VMID"]
|
||||
@ -473,8 +502,8 @@ module OneGate
|
||||
|
||||
def self.parse_json(response)
|
||||
if CloudClient::is_error?(response)
|
||||
puts "ERROR: "
|
||||
puts response.message
|
||||
STDERR.puts 'ERROR: '
|
||||
STDERR.puts response.message
|
||||
exit -1
|
||||
else
|
||||
return JSON.parse(response.body)
|
||||
@ -537,6 +566,10 @@ Available commands
|
||||
$ onegate service show [--json][--extended]
|
||||
|
||||
$ onegate service scale --role ROLE --cardinality CARDINALITY
|
||||
|
||||
$ onegate vrouter show [--json]
|
||||
|
||||
$ onegate vnet show VNETID [--json][--extended]
|
||||
EOT
|
||||
end
|
||||
end
|
||||
@ -576,7 +609,7 @@ OptionParser.new do |opts|
|
||||
end
|
||||
|
||||
opts.on("-h", "--help", "Show this message") do
|
||||
puts OneGate.help_str
|
||||
STDERR.puts OneGate.help_str
|
||||
exit
|
||||
end
|
||||
end.parse!
|
||||
@ -601,7 +634,7 @@ when "vm"
|
||||
end
|
||||
when "update"
|
||||
if !options[:data] && !options[:erase]
|
||||
puts "You have to provide the data as a param (--data, --erase)"
|
||||
STDERR.puts 'You have to provide the data as a param (--data, --erase)'
|
||||
exit -1
|
||||
end
|
||||
|
||||
@ -618,8 +651,8 @@ when "vm"
|
||||
end
|
||||
|
||||
if CloudClient::is_error?(response)
|
||||
puts "ERROR: "
|
||||
puts response.message
|
||||
STDERR.puts 'ERROR: '
|
||||
STDERR.puts response.message
|
||||
exit -1
|
||||
end
|
||||
when "resume",
|
||||
@ -649,18 +682,18 @@ when "vm"
|
||||
response = client.post("/vms/"+ARGV[2]+"/action", action_hash.to_json)
|
||||
|
||||
if CloudClient::is_error?(response)
|
||||
puts "ERROR: "
|
||||
puts response.message
|
||||
STDERR.puts 'ERROR: '
|
||||
STDERR.puts response.message
|
||||
exit -1
|
||||
end
|
||||
else
|
||||
puts "You have to provide a VM ID"
|
||||
STDERR.puts 'You have to provide a VM ID'
|
||||
exit -1
|
||||
end
|
||||
else
|
||||
puts OneGate.help_str
|
||||
puts
|
||||
puts "Action #{ARGV[1]} not supported"
|
||||
STDERR.puts OneGate.help_str
|
||||
STDERR.puts
|
||||
STDERR.puts "Action #{ARGV[1]} not supported"
|
||||
exit -1
|
||||
end
|
||||
when "service"
|
||||
@ -693,18 +726,79 @@ when "service"
|
||||
}.to_json)
|
||||
|
||||
if CloudClient::is_error?(response)
|
||||
puts "ERROR: "
|
||||
puts response.message
|
||||
STDERR.puts 'ERROR: '
|
||||
STDERR.puts response.message
|
||||
exit -1
|
||||
end
|
||||
else
|
||||
puts OneGate.help_str
|
||||
puts
|
||||
puts "Action #{ARGV[1]} not supported"
|
||||
STDERR.puts OneGate.help_str
|
||||
STDERR.puts
|
||||
STDERR.puts "Action #{ARGV[1]} not supported"
|
||||
exit -1
|
||||
end
|
||||
when 'vrouter'
|
||||
case ARGV[1]
|
||||
when 'show'
|
||||
if options[:extended]
|
||||
extra = {}
|
||||
extra['extended'] = true
|
||||
|
||||
extra = URI.encode_www_form(extra)
|
||||
end
|
||||
|
||||
response = client.get('/vrouter', extra)
|
||||
json_hash = OneGate.parse_json(response)
|
||||
|
||||
if options[:json]
|
||||
puts JSON.pretty_generate(json_hash)
|
||||
else
|
||||
if options[:extended]
|
||||
OneGate::VirtualRouter.print(json_hash, true)
|
||||
else
|
||||
OneGate::VirtualRouter.print(json_hash)
|
||||
end
|
||||
end
|
||||
else
|
||||
STDERR.puts OneGate.help_str
|
||||
STDERR.puts
|
||||
STDERR.puts "Action #{ARGV[1]} not supported"
|
||||
exit(-1)
|
||||
end
|
||||
when 'vnet'
|
||||
case ARGV[1]
|
||||
when 'show'
|
||||
if ARGV[2]
|
||||
if options[:extended]
|
||||
extra = {}
|
||||
extra['extended'] = true
|
||||
|
||||
extra = URI.encode_www_form(extra)
|
||||
end
|
||||
|
||||
response = client.get('/vnet/'+ARGV[2], extra)
|
||||
json_hash = OneGate.parse_json(response)
|
||||
|
||||
if options[:json]
|
||||
puts JSON.pretty_generate(json_hash)
|
||||
else
|
||||
if options[:extended]
|
||||
OneGate::VirtualNetwork.print(json_hash, true)
|
||||
else
|
||||
OneGate::VirtualNetwork.print(json_hash)
|
||||
end
|
||||
end
|
||||
else
|
||||
STDERR.puts 'You have to provide a VNET ID'
|
||||
exit -1
|
||||
end
|
||||
else
|
||||
STDERR.puts OneGate.help_str
|
||||
STDERR.puts
|
||||
STDERR.puts "Action #{ARGV[1]} not supported"
|
||||
exit(-1)
|
||||
end
|
||||
else
|
||||
puts OneGate.help_str
|
||||
STDERR.puts OneGate.help_str
|
||||
exit -1
|
||||
end
|
||||
|
||||
|
@ -159,6 +159,20 @@ func (vc *VMsController) InfoExtendedFilter(f *VMFilter) (*vm.Pool, error) {
|
||||
return vmPool, nil
|
||||
}
|
||||
|
||||
// InfoSet connects to OpenNebula and fetches a VM_POOL containing the VMs in vmIds
|
||||
func (vc *VMsController) InfoSet(vmIds string, extended bool) (*vm.Pool, error) {
|
||||
response, err := vc.c.Client.Call("one.vmpool.infoset", vmIds, extended)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
vmPool := &vm.Pool{}
|
||||
err = xml.Unmarshal([]byte(response.Body()), vmPool)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return vmPool, nil
|
||||
}
|
||||
|
||||
// Info connects to OpenNebula and fetches the information of the VM
|
||||
func (vc *VMController) Info(decrypt bool) (*vm.VM, error) {
|
||||
response, err := vc.c.Client.Call("one.vm.info", vc.ID, decrypt)
|
||||
|
@ -34,6 +34,7 @@ public class VirtualMachinePool extends Pool implements Iterable<VirtualMachine>
|
||||
private static final String ELEMENT_NAME = "VM";
|
||||
private static final String INFO_METHOD = "vmpool.info";
|
||||
private static final String INFO_EXTENDED_METHOD = "vmpool.infoextended";
|
||||
private static final String INFO_SET_METHOD = "vmpool.infoset";
|
||||
private static final String MONITORING = "vmpool.monitoring";
|
||||
|
||||
/**
|
||||
@ -133,6 +134,20 @@ public class VirtualMachinePool extends Pool implements Iterable<VirtualMachine>
|
||||
return client.call(INFO_EXTENDED_METHOD, filter, -1, -1, NOT_DONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all of the Virtual Machines in the vm_ids list.
|
||||
*
|
||||
* @param client XML-RPC Client.
|
||||
* @param vm_ids Comma separated list of VM IDs.
|
||||
* @param extended If true the extended body is retrieved.
|
||||
* @return If successful the message contains the string
|
||||
* with the information returned by OpenNebula.
|
||||
*/
|
||||
public static OneResponse info_extended(Client client, int vm_ids, boolean extended)
|
||||
{
|
||||
return client.call(INFO_SET_METHOD, vm_ids, extended);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all the Virtual Machines in the pool.
|
||||
*
|
||||
|
@ -23,14 +23,14 @@ module OpenNebula
|
||||
# Constants and Class attribute accessors
|
||||
#######################################################################
|
||||
|
||||
|
||||
VM_POOL_METHODS = {
|
||||
:info => "vmpool.info",
|
||||
:info_extended => "vmpool.infoextended",
|
||||
:monitoring => "vmpool.monitoring",
|
||||
:accounting => "vmpool.accounting",
|
||||
:showback => "vmpool.showback",
|
||||
:calculate_showback => "vmpool.calculateshowback"
|
||||
:info => 'vmpool.info',
|
||||
:info_extended => 'vmpool.infoextended',
|
||||
:info_set => 'vmpool.infoset',
|
||||
:monitoring => 'vmpool.monitoring',
|
||||
:accounting => 'vmpool.accounting',
|
||||
:showback => 'vmpool.showback',
|
||||
:calculate_showback => 'vmpool.calculateshowback'
|
||||
}
|
||||
|
||||
# Constants for info queries (include/RequestManagerPoolInfoFilter.h)
|
||||
@ -41,7 +41,6 @@ module OpenNebula
|
||||
# Class constructor & Pool Methods
|
||||
#######################################################################
|
||||
|
||||
|
||||
# +client+ a Client object that represents a XML-RPC connection
|
||||
# +user_id+ is to refer to a Pool with VirtualMachines from that user
|
||||
def initialize(client, user_id=0)
|
||||
@ -102,21 +101,21 @@ module OpenNebula
|
||||
end
|
||||
|
||||
# Define info methods shortcuts for different filters
|
||||
# info_all()
|
||||
# info_all()
|
||||
# info_all!()
|
||||
# info_all_extended
|
||||
# info_all_extended
|
||||
# info_all_extended!()
|
||||
# info_mine()
|
||||
# info_mine()
|
||||
# info_mine!()
|
||||
# info_mine_extended
|
||||
# info_mine_extended
|
||||
# info_mine_extended!()
|
||||
# info_group()
|
||||
# info_group()
|
||||
# info_group!()
|
||||
# info_group_extended
|
||||
# info_group_extended
|
||||
# info_group_extended!()
|
||||
# info_primary_group()
|
||||
# info_primary_group()
|
||||
# info_primary_group!()
|
||||
# info_primary_group_extended
|
||||
# info_primary_group_extended
|
||||
# info_primary_group_extended!()
|
||||
%w[mine all group primary_group].each do |ifilter|
|
||||
const_name = "OpenNebula::Pool::INFO_#{ifilter.upcase}"
|
||||
@ -160,6 +159,14 @@ module OpenNebula
|
||||
default_args[:query])
|
||||
end
|
||||
|
||||
# Retrieves the set of VMs especified in vm_ids
|
||||
#
|
||||
# @param [String] comma separated list of vm ids.
|
||||
# @param [Boolean] if true extended body is retrieved.
|
||||
#
|
||||
def info_set(vm_ids, extended)
|
||||
xmlrpc_info(VM_POOL_METHODS[:info_set], vm_ids, extended)
|
||||
end
|
||||
|
||||
# Retrieves the monitoring data for all the VMs in the pool
|
||||
#
|
||||
|
@ -50,6 +50,7 @@ require 'rubygems'
|
||||
require 'sinatra'
|
||||
require 'yaml'
|
||||
require 'json'
|
||||
require 'set'
|
||||
|
||||
require 'CloudAuth'
|
||||
require 'CloudServer'
|
||||
@ -75,6 +76,11 @@ RESTRICTED_ACTIONS = [
|
||||
'reboot'
|
||||
]
|
||||
|
||||
# Attrs of the Virtual Network template that will be retrieved
|
||||
# with onegate vnet | get /vnet/:id requests.
|
||||
VNET_TEMPLATE_ATTRIBUTES = %w[NETWORK_ADDRESS NETWORK_MASK GATEWAY GATEWAY6 DNS
|
||||
GUEST_MTU CONTEXT_FORCE_IPV4 SEARCH_DOMAIN]
|
||||
|
||||
include OpenNebula
|
||||
|
||||
begin
|
||||
@ -162,13 +168,24 @@ helpers do
|
||||
|
||||
def get_requested_vm(requested_vm_id, request_env, client)
|
||||
source_vm = get_source_vm(request_env, client)
|
||||
if source_vm['ID'].to_i != requested_vm_id
|
||||
|
||||
return source_vm if Integer(source_vm['ID']) == requested_vm_id
|
||||
|
||||
if !source_vm['USER_TEMPLATE/SERVICE_ID'].nil?
|
||||
service_id = source_vm['USER_TEMPLATE/SERVICE_ID']
|
||||
check_vm_in_service(requested_vm_id, service_id, client)
|
||||
|
||||
requested_vm = get_vm(requested_vm_id, client)
|
||||
get_vm(requested_vm_id, client)
|
||||
elsif !source_vm['TEMPLATE/VROUTER_ID'].nil?
|
||||
vrouter_id = source_vm['TEMPLATE/VROUTER_ID']
|
||||
vrouter_hash = get_vrouter(vrouter_id, client).to_hash
|
||||
check_vm_in_vrouter(requested_vm_id, vrouter_hash, source_vm)
|
||||
get_vm(requested_vm_id, client)
|
||||
else
|
||||
requested_vm = source_vm
|
||||
error_msg = 'This VM does not belong to any Virtual Router or '\
|
||||
'Service, so it cannot retrieve information '\
|
||||
'from other VMs'
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
end
|
||||
|
||||
@ -241,6 +258,48 @@ helpers do
|
||||
service.body
|
||||
end
|
||||
|
||||
def get_vrouter(vrouter_id, client)
|
||||
begin
|
||||
vrouter_id = Integer(vrouter_id)
|
||||
rescue TypeError
|
||||
error_msg = 'Empty or invalid VROUTER_ID'
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
vrouter = VirtualRouter.new_with_id(vrouter_id, client)
|
||||
rc = vrouter.info
|
||||
|
||||
if OpenNebula.is_error?(rc)
|
||||
error_msg = "Virtual router #{vrouter_id} not found"
|
||||
logger.error {error_msg}
|
||||
halt 404, error_msg
|
||||
end
|
||||
|
||||
vrouter
|
||||
end
|
||||
|
||||
def get_vnet(vnet_id, client)
|
||||
begin
|
||||
vnet_id = Integer(vnet_id)
|
||||
rescue TypeError
|
||||
error_msg = 'Empty or invalid VNET_ID'
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
vnet = VirtualNetwork.new_with_id(vnet_id, client)
|
||||
rc = vnet.info
|
||||
|
||||
if OpenNebula.is_error?(rc)
|
||||
error_msg = "Virtual network #{vnet_id} not found"
|
||||
logger.error {error_msg}
|
||||
halt 404, error_msg
|
||||
end
|
||||
|
||||
vnet
|
||||
end
|
||||
|
||||
def parse_json(json_str, root_element)
|
||||
begin
|
||||
hash = JSON.parse(json_str)
|
||||
@ -294,6 +353,10 @@ helpers do
|
||||
end
|
||||
end
|
||||
|
||||
def get_vnet_template_attributes
|
||||
$conf[:vnet_template_attributes] || VNET_TEMPLATE_ATTRIBUTES
|
||||
end
|
||||
|
||||
# Check if the source VM is part of a service and if the requested
|
||||
# VM is part of the same Service as the source VM.
|
||||
#
|
||||
@ -326,6 +389,91 @@ helpers do
|
||||
return response
|
||||
end
|
||||
|
||||
# Check if the source VM is part of a virtual router and if the
|
||||
# requested VM is part of the same virtual router as the source VM.
|
||||
# If false a halt is triggered
|
||||
#
|
||||
# @param requested_vm_id [Integer]
|
||||
# @param vrouter_hash [Hash]
|
||||
# @param source_vm [OpenNebula::VirtualMachine]
|
||||
#
|
||||
def check_vm_in_vrouter(requested_vm_id, vrouter_hash, source_vm)
|
||||
# Check that the user has not spoofed the VROUTER_ID
|
||||
vrouter_vm_ids = Array(vrouter_hash['VROUTER']['VMS']['ID']).map! do |vm|
|
||||
Integer(vm)
|
||||
end
|
||||
|
||||
if !vrouter_vm_ids.include?(requested_vm_id) ||
|
||||
!vrouter_vm_ids.include?(source_vm.id)
|
||||
|
||||
error_msg = "Virtual Router #{vrouter_hash['VROUTER']['ID']} does "\
|
||||
"not contain VM #{requested_vm_id}."
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
end
|
||||
|
||||
# Check if the requested VNET can be accessed from the curren VROUTER.
|
||||
# If false a halt is triggered.
|
||||
#
|
||||
# @param req_vnet [OpenNebula::VirtualNetwork]
|
||||
# @param vrouter_hash [Hash]
|
||||
# @param client [OpenNebula::Client]
|
||||
#
|
||||
def check_vnet_in_vrouter(req_vnet, vrouter_hash, client)
|
||||
valid_vnets = Set[]
|
||||
|
||||
# Get VR nics
|
||||
nics = vrouter_hash['VROUTER']['TEMPLATE']['NIC']
|
||||
|
||||
if !nics.is_a?(Array)
|
||||
nics = [nics]
|
||||
end
|
||||
|
||||
# Get only one nic if multiple nic in same network
|
||||
nics.uniq! {|n| n['NETWORK_ID'] }
|
||||
|
||||
have_access = false
|
||||
nics.each do |nic|
|
||||
# Get nic VNET
|
||||
nic_vnet = get_vnet(nic['NETWORK_ID'], client)
|
||||
|
||||
# Provide access to nic's VNET
|
||||
valid_vnets.add(Integer(nic['NETWORK_ID']))
|
||||
# Provide access to nic's VNET parent (if exists)
|
||||
if !nic_vnet['PARENT_NETWORK_ID'].nil? &&
|
||||
!nic_vnet['PARENT_NETWORK_ID'].empty?
|
||||
valid_vnets.add(Integer(nic_vnet['PARENT_NETWORK_ID']))
|
||||
end
|
||||
# Provide access to nic's VNET childs
|
||||
xpath = '//LEASE/VNET'
|
||||
childs = nic_vnet.retrieve_xmlelements(xpath)
|
||||
|
||||
childs.each do |c|
|
||||
valid_vnets.add(Integer(c.text))
|
||||
end
|
||||
# Provide access to VNETs with same parent as NIC network
|
||||
if !valid_vnets.include?(req_vnet.id)
|
||||
# Get requested vnet parent
|
||||
if !req_vnet['PARENT_NETWORK_ID'].empty?
|
||||
req_parent = Integer(req_vnet['PARENT_NETWORK_ID'])
|
||||
end
|
||||
|
||||
next unless valid_vnets.include?(req_parent)
|
||||
end
|
||||
|
||||
have_access = true
|
||||
break
|
||||
end
|
||||
|
||||
return if have_access
|
||||
|
||||
error_msg = "Virtual Network #{req_vnet.id} cannot be retrieved"\
|
||||
" from Virtual router #{vrouter_hash['VROUTER']['ID']}."
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
# Escape data from user
|
||||
def scape_attr(attr)
|
||||
ret = ''
|
||||
@ -420,7 +568,7 @@ helpers do
|
||||
end
|
||||
end
|
||||
|
||||
NIC_VALID_KEYS = %w(IP IP6_LINK IP6_SITE IP6_GLOBAL NETWORK MAC NAME PARENT)
|
||||
NIC_VALID_KEYS = %w(IP IP6_LINK IP6_SITE IP6_GLOBAL NETWORK MAC NAME PARENT EXTERNAL)
|
||||
USER_TEMPLATE_INVALID_KEYS = %w(SCHED_MESSAGE)
|
||||
|
||||
def build_vm_hash(vm_hash)
|
||||
@ -514,6 +662,161 @@ def build_service_hash(service_hash, client = nil, extended = false)
|
||||
}
|
||||
end
|
||||
|
||||
def build_vrouter_hash(vrouter_hash, _client = nil, _extended = false)
|
||||
vrouter = {
|
||||
'VROUTER' => {
|
||||
'NAME' => vrouter_hash['VROUTER']['NAME'],
|
||||
'ID' => vrouter_hash['VROUTER']['ID'],
|
||||
'VMS' => vrouter_hash['VROUTER']['VMS'],
|
||||
'TEMPLATE' => vrouter_hash['VROUTER']['TEMPLATE']
|
||||
}
|
||||
}
|
||||
|
||||
# Manage special cases (arrays)
|
||||
if !vrouter['VROUTER']['TEMPLATE']['NIC'].is_a?(Array)
|
||||
if vrouter['VROUTER']['TEMPLATE']['NIC'].nil?
|
||||
vrouter['VROUTER']['TEMPLATE']['NIC'] = []
|
||||
else
|
||||
vrouter['VROUTER']['TEMPLATE']['NIC'] = [
|
||||
vrouter['VROUTER']['TEMPLATE']['NIC']
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
if !vrouter_hash['VROUTER']['VMS']['ID'].is_a?(Array)
|
||||
if vrouter_hash['VROUTER']['VMS']['ID'].nil?
|
||||
vrouter_hash['VROUTER']['VMS']['ID'] = []
|
||||
else
|
||||
vrouter_hash['VROUTER']['VMS']['ID'] = [
|
||||
vrouter_hash['VROUTER']['VMS']['ID']
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
vrouter
|
||||
end
|
||||
|
||||
VNET_ATTRIBUTES = %w[ID NAME USED_LEASES VROUTERS PARENT_NETWORK_ID AR_POOL]
|
||||
|
||||
def process_vnet(vnet_hash)
|
||||
template = {}
|
||||
|
||||
get_vnet_template_attributes.each do |key|
|
||||
value = vnet_hash['VNET']['TEMPLATE'][key]
|
||||
template[key] = value unless value.nil?
|
||||
end
|
||||
|
||||
vnet = {}
|
||||
VNET_ATTRIBUTES.each do |key|
|
||||
vnet[key] = vnet_hash['VNET'][key]
|
||||
end
|
||||
|
||||
vnet['TEMPLATE'] = template
|
||||
|
||||
# Manage special cases (arrays)
|
||||
if !vnet['AR_POOL']['AR'].is_a?(Array)
|
||||
if vnet['AR_POOL']['AR'].nil?
|
||||
vnet['AR_POOL']['AR'] = []
|
||||
else
|
||||
vnet['AR_POOL']['AR'] = [vnet['AR_POOL']['AR']]
|
||||
end
|
||||
end
|
||||
|
||||
vnet['AR_POOL']['AR'].each do |ar|
|
||||
if !ar['LEASES']['LEASE'].is_a?(Array)
|
||||
if ar['LEASES']['LEASE'].nil?
|
||||
ar['LEASES']['LEASE'] = []
|
||||
else
|
||||
ar['LEASES']['LEASE'] = [ar['LEASES']['LEASE']]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if !vnet['VROUTERS']['ID'].is_a?(Array)
|
||||
if vnet['VROUTERS']['ID'].nil?
|
||||
!vnet['VROUTERS']['ID'] = []
|
||||
else
|
||||
vnet['VROUTERS']['ID'] = [vnet['VROUTERS']['ID']]
|
||||
end
|
||||
end
|
||||
|
||||
vnet
|
||||
end
|
||||
|
||||
def build_vnet_hash(vnet, client, extended)
|
||||
# if extended flag is not set
|
||||
if extended.nil? || extended.downcase != 'true'
|
||||
vnet = vnet.to_hash
|
||||
vnet['VNET'] = process_vnet(vnet)
|
||||
|
||||
return vnet
|
||||
end
|
||||
|
||||
vm_pool = VirtualMachinePool.new(client)
|
||||
|
||||
# get VMs that are using the VNET
|
||||
vms = ''
|
||||
vnet.retrieve_xmlelements('//LEASE/VM').each do |vm|
|
||||
vms << ',' unless vms.empty?
|
||||
vms << vm.text
|
||||
end
|
||||
|
||||
vnet = vnet.to_hash
|
||||
vnet['VNET'] = process_vnet(vnet)
|
||||
|
||||
rc = vm_pool.info_set(vms, true)
|
||||
if OpenNebula.is_error?(rc)
|
||||
logger.error {"vmpool.info error: #{rc.message}"}
|
||||
halt 404, rc.message
|
||||
end
|
||||
|
||||
# Get ARs array
|
||||
ars = vnet['VNET']['AR_POOL']['AR']
|
||||
# rubocop:disable Style/ArrayCoercion
|
||||
ars = [ars] unless ars.is_a?(Array)
|
||||
|
||||
ars.each do |ar|
|
||||
leases = ar['LEASES']['LEASE']
|
||||
|
||||
next if leases.nil?
|
||||
|
||||
leases = [leases] unless leases.is_a?(Array)
|
||||
# rubocop:enable Style/ArrayCoercion
|
||||
|
||||
leases.each do |lease|
|
||||
next if lease['VM'].nil?
|
||||
|
||||
# Get the corresponding VM from pool
|
||||
xpath = "/VM_POOL/VM[ID=#{lease['VM']}]"
|
||||
vm = vm_pool.retrieve_xmlelements(xpath)[0]
|
||||
|
||||
# Get corresponding NIC from VM (MAC should be unique)
|
||||
xpath = "./TEMPLATE/NIC[MAC=\"#{lease['MAC']}\"]"
|
||||
nic = vm.retrieve_xmlelements(xpath)[0]
|
||||
|
||||
if nic.nil?
|
||||
xpath = "./TEMPLATE/NIC_ALIAS[MAC=\"#{lease['MAC']}\"]"
|
||||
nic = vm.retrieve_xmlelements(xpath)[0]
|
||||
|
||||
# get parent network
|
||||
xpath = "./TEMPLATE/NIC[NIC_ID=\"#{nic['PARENT_ID']}\"]/NETWORK_ID"
|
||||
parent_id = vm.retrieve_xmlelements(xpath)[0].text
|
||||
|
||||
# Get ALIAS extended info
|
||||
lease['PARENT'] = nic['PARENT']
|
||||
lease['PARENT_NETWORK_ID'] = parent_id
|
||||
lease['EXTERNAL'] = !nic['EXTERNAL'].nil? &&
|
||||
nic['EXTERNAL'].downcase == 'yes'
|
||||
end
|
||||
|
||||
# Get extended info
|
||||
lease['NIC_NAME'] = nic['NAME']
|
||||
end
|
||||
end
|
||||
|
||||
vnet
|
||||
end
|
||||
|
||||
get '/' do
|
||||
client = authenticate(request.env, params)
|
||||
|
||||
@ -565,6 +868,70 @@ get '/service' do
|
||||
[200, response.to_json]
|
||||
end
|
||||
|
||||
get '/vrouter' do
|
||||
check_permissions(:vrouter, :show)
|
||||
client = authenticate(request.env, params)
|
||||
|
||||
source_vm = get_source_vm(request.env, client)
|
||||
vrouter_id = source_vm['TEMPLATE/VROUTER_ID']
|
||||
vrouter_hash = get_vrouter(vrouter_id, client).to_hash
|
||||
|
||||
check_vm_in_vrouter(Integer(source_vm['ID']), vrouter_hash, source_vm)
|
||||
|
||||
response = build_vrouter_hash(vrouter_hash, client, params['extended']) rescue nil
|
||||
if response.nil?
|
||||
error_msg = "Virtual router #{vrouter_id} is empty."
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
[200, response.to_json]
|
||||
end
|
||||
|
||||
get '/vnet/:id' do
|
||||
check_permissions(:vnet, :show_by_id)
|
||||
client = authenticate(request.env, params)
|
||||
|
||||
# Check :id is an integer
|
||||
vnet_id = begin
|
||||
Integer(params[:id])
|
||||
rescue ArgumentError
|
||||
error_msg = "Invalid id format (ID: #{params[:id]}). "\
|
||||
'ID must be an integer.'
|
||||
logger.error { error_msg }
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
source_vm = get_source_vm(request.env, client)
|
||||
vrouter_id = source_vm['TEMPLATE/VROUTER_ID']
|
||||
|
||||
# Check if current VM is a VROUTER
|
||||
if vrouter_id.nil? || vrouter_id.empty?
|
||||
error_msg = 'Virtual networks information can only be' \
|
||||
' retrieved from Virtual Routers.'
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
# Retrieve VROUTER information
|
||||
vrouter_hash = get_vrouter(vrouter_id, client).to_hash
|
||||
check_vm_in_vrouter(Integer(source_vm['ID']), vrouter_hash, source_vm)
|
||||
|
||||
# Retrieve requested VNET
|
||||
req_vnet = get_vnet(Integer(vnet_id), client)
|
||||
check_vnet_in_vrouter(req_vnet, vrouter_hash, client)
|
||||
|
||||
response = build_vnet_hash(req_vnet, client, params['extended']) rescue nil
|
||||
|
||||
if response.nil?
|
||||
error_msg = "Virtual router #{vrouter_hash['VROUTER']['ID']} is empty."
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
|
||||
[200, response.to_json]
|
||||
end
|
||||
|
||||
get '/vms/:id' do
|
||||
check_permissions(:vm, :show_by_id)
|
||||
client = authenticate(request.env, params)
|
||||
@ -617,3 +984,11 @@ put '/vms/:id' do
|
||||
|
||||
[200, ""]
|
||||
end
|
||||
|
||||
%w[get head post put delete options patch].each do |method|
|
||||
send method, '/*' do
|
||||
error_msg = 'OneGate server doesn\'t support this feature'
|
||||
logger.error {error_msg}
|
||||
halt 400, error_msg
|
||||
end
|
||||
end
|
||||
|
@ -490,6 +490,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr datastorepool_info(new DatastorePoolInfo());
|
||||
xmlrpc_c::methodPtr vm_pool_info(new VirtualMachinePoolInfo());
|
||||
xmlrpc_c::methodPtr vm_pool_info_extended(new VirtualMachinePoolInfoExtended());
|
||||
xmlrpc_c::methodPtr vm_pool_info_set(new VirtualMachinePoolInfoSet());
|
||||
xmlrpc_c::methodPtr template_pool_info(new TemplatePoolInfo());
|
||||
xmlrpc_c::methodPtr vnpool_info(new VirtualNetworkPoolInfo());
|
||||
xmlrpc_c::methodPtr vntemplate_pool_info(new VirtualNetworkTemplatePoolInfo());
|
||||
@ -617,6 +618,7 @@ void RequestManager::register_xml_methods()
|
||||
|
||||
RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.infoextended", vm_pool_info_extended);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.infoset", vm_pool_info_set);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.accounting", vm_pool_acct);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.monitoring", vm_pool_monitoring);
|
||||
RequestManagerRegistry.addMethod("one.vmpool.showback", vm_pool_showback);
|
||||
|
@ -368,6 +368,47 @@ void VirtualMachinePoolInfo::request_execute(
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
VirtualMachinePoolInfoSet::VirtualMachinePoolInfoSet()
|
||||
: RequestManagerPoolInfoFilter("one.vmpool.infoset",
|
||||
"Returns a virtual machine instances set",
|
||||
"A:ss")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_vmpool();
|
||||
auth_object = PoolObjectSQL::VM;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void VirtualMachinePoolInfoSet::request_execute(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
std::string ids_str = xmlrpc_c::value_string(paramList.getString(1));
|
||||
extended = xmlrpc_c::value_boolean(paramList.getBoolean(2));
|
||||
|
||||
ostringstream and_filter;
|
||||
ostringstream oss;
|
||||
std::set<unsigned int> ids;
|
||||
|
||||
one_util::split_unique(ids_str, ',', ids);
|
||||
|
||||
if (ids.empty())
|
||||
{
|
||||
std::string empty_pool = "<VM_POOL></VM_POOL>";
|
||||
success_response(empty_pool, att);
|
||||
return;
|
||||
}
|
||||
|
||||
and_filter << "oid in (" << one_util::join(ids, ',') << ")";
|
||||
|
||||
dump(att, -2, -1, -1, and_filter.str(), "");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
VirtualMachinePoolAccounting::VirtualMachinePoolAccounting()
|
||||
: RequestManagerPoolInfoFilter("one.vmpool.accounting",
|
||||
"Returns the virtual machine history records",
|
||||
|
Loading…
x
Reference in New Issue
Block a user