1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-20 10:50:08 +03:00

feature #3175: Moved Nic and VM to new modules

This commit is contained in:
Ruben S. Montero 2014-12-22 14:12:16 +01:00
parent 0e49cf00bb
commit fba4deec6e
7 changed files with 455 additions and 14 deletions

View File

@ -16,8 +16,7 @@
module VNMMAD
# The address module provides basic functions to manage IP addresses
module Address
module VNMNetwork
# This methods translates an address range to a set of IPv4 networks
# in CIDR notation

View File

@ -16,8 +16,7 @@
module VNMMAD
# This module includes functions to execute and manage Network commands.
module Command
module VNMNetwork
# Command configuration for common network commands. This CAN be adjust
# to local installations. Any modification requires to sync the hosts with

View File

@ -0,0 +1,154 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
# #
# 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. #
#--------------------------------------------------------------------------- #
module VNMMAD
module VNMNetwork
# This class represents the NICS of a VM, it provides a factory method
# to create VMs of the given hyprtvisor
class Nics < Array
def initialize(hypervisor)
case hypervisor
when "kvm"
@nicClass = NicKVM
when "xen"
@nicClass = NicXen
when "vmware"
@nicClass = NicVMware
end
end
def new_nic
@nicClass.new
end
end
############################################################################
# Hypervisor specific implementation of network interfaces. Each class
# implements the following interface:
# - get_info to populste the VM.vm_info Hash
# - get_tap to set the [:tap] attribute with the associated NIC
############################################################################
# A NIC using KVM. This class implements functions to get the physical
# interface that the NIC is using, based on the MAC address
class NicKVM < Hash
def initialize
super(nil)
end
# Get the VM information with virsh dumpxml
def get_info(vm)
if vm.deploy_id
deploy_id = vm.deploy_id
else
deploy_id = vm['DEPLOY_ID']
end
if deploy_id and vm.vm_info[:dumpxml].nil?
vm.vm_info[:dumpxml] = `#{VNMNetwork::COMMANDS[:virsh]} dumpxml #{deploy_id} 2>/dev/null`
vm.vm_info.each_key do |k|
vm.vm_info[k] = nil if vm.vm_info[k].to_s.strip.empty?
end
end
end
# Look for the tap in
# devices/interface[@type='bridge']/mac[@address='<mac>']/../target"
def get_tap(vm)
dumpxml = vm.vm_info[:dumpxml]
if dumpxml
dumpxml_root = REXML::Document.new(dumpxml).root
xpath = "devices/interface[@type='bridge']/" \
"mac[@address='#{self[:mac]}']/../target"
tap = dumpxml_root.elements[xpath]
self[:tap] = tap.attributes['dev'] if tap
end
self
end
end
# A NIC using Xen. This class implements functions to get the physical interface
# that the NIC is using
class NicXen < Hash
def initialize
super(nil)
end
def get_info(vm)
if vm.deploy_id
deploy_id = vm.deploy_id
else
deploy_id = vm['DEPLOY_ID']
end
if deploy_id and (vm.vm_info[:domid].nil? or vm.vm_info[:networks].nil?)
vm.vm_info[:domid] =`#{VNMNetwork::COMMANDS[:xm]} domid #{deploy_id}`.strip
vm.vm_info[:networks] =`#{VNMNetwork::COMMANDS[:xm]} network-list #{deploy_id}`
vm.vm_info.each_key do |k|
vm.vm_info[k] = nil if vm.vm_info[k].to_s.strip.empty?
end
end
end
def get_tap(vm)
domid = vm.vm_info[:domid]
if domid
networks = vm.vm_info[:networks].split("\n")[1..-1]
networks.each do |net|
n = net.split
iface_id = n[0]
iface_mac = n[2]
if iface_mac == self[:mac]
self[:tap] = "vif#{domid}.#{iface_id}"
break
end
end
end
self
end
end
# A NIC using VMware. This class implements functions to get the physical interface
# that the NIC is using
class NicVMware < Hash
def initialize
super(nil)
end
def get_info(vm)
end
def get_tap(vm)
self
end
end
end
end

View File

@ -0,0 +1,179 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
# #
# 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. #
#--------------------------------------------------------------------------- #
$: << File.dirname(__FILE__)
$: << File.join(File.dirname(__FILE__), '..')
require 'rexml/document'
require 'base64'
require 'yaml'
require 'one_firewall'
require 'one_sg'
require 'lib/vm'
require 'lib/nic'
require 'lib/address'
require 'lib/security_groups'
require 'lib/security_groups_iptables'
require 'scripts_common'
include OpenNebula
begin
CONF = YAML.load_file(
File.join(File.dirname(__FILE__), "OpenNebulaNetwork.conf")
)
rescue
CONF = {
:start_vlan => 2
}
end
# Set PATH
ENV['PATH'] = "#{ENV['PATH']}:/bin:/sbin:/usr/bin"
################################################################################
# The VNMMAD module provides the basic abstraction to implement custom
# virtual network drivers. The VNMAD module includes:
# - VNMNetwork with base classes and main functionality
# - SGIPTables a module with a SG implementation based in iptables/ipset
################################################################################
module VNMMAD
############################################################################
# Base driver class to implement a Network driver. It relays on two filter
# drivers OpenNebulaFirewall and OpenNebulaSG.
############################################################################
class OpenNebulaNetwork
attr_reader :hypervisor, :vm
# Creates new OpenNebulaNetwork using:
# @param vm_tpl [String] XML String from oned
# @param xpath_filter [String] to get relevant NICs for the driver
# @param deploy_id [String]
# @param hypervisor [String]
def initialize(vm_tpl, xpath_filter, deploy_id = nil, hypervisor = nil)
@locking = false
if !hypervisor
@hypervisor = detect_hypervisor
else
@hypervisor = hypervisor
end
@vm = VM.new(REXML::Document.new(vm_tpl).root, xpath_filter,
deploy_id, @hypervisor)
end
# Creates a new OpenNebulaNetwork using:
# @param vm_64 [String] Base64 encoded XML String from oned
# @param deploy_id [String]
# @param hypervisor [String]
def self.from_base64(vm_64, deploy_id = nil, hypervisor = nil)
vm_xml = Base64::decode64(vm_64)
self.new(vm_xml, deploy_id, hypervisor)
end
# Locking function to serialized driver operations if needed. Similar
# to flock. File is created as /tmp/onevnm-<driver>-lock
def lock
if @locking
driver_name = self.class.name.downcase
@locking_file = File.open("/tmp/onevnm-#{driver_name}-lock","w")
@locking_file.flock(File::LOCK_EX)
end
end
# Unlock driver execution mutex
def unlock
if @locking
@locking_file.close
end
end
# Executes the given block on each NIC
def process(&block)
@vm.each_nic(block)
end
# Return a string for the hypervisor
# @return [String] "kvm", "xen" or nil
def detect_hypervisor
lsmod = `#{VNMNetwork::COMMANDS[:lsmod]}`
xen_file = "/proc/xen/capabilities"
if File.exists?(xen_file)
"xen"
elsif lsmod.match(/kvm/)
"kvm"
else
nil
end
end
# Get hypervisor bridges
# @return [Hash<String>] with the bridge names
def get_interfaces
bridges = Hash.new
brctl_exit =`#{VNMNetwork::COMMANDS[:brctl]} show`
cur_bridge = ""
brctl_exit.split("\n")[1..-1].each do |l|
l = l.split
if l.length > 1
cur_bridge = l[0]
bridges[cur_bridge] = Array.new
bridges[cur_bridge] << l[3] if l[3]
else
bridges[cur_bridge] << l[0]
end
end
bridges
end
# Returns true if the template contains the deprecated firewall attributes:
# - ICMP
# - WHITE_PORTS_TCP
# - WHITE_PORTS_UDP
# - BLACK_PORTS_TCP
# - BLACK_PORTS_UDP
#
# @return Boolean
def self.has_fw_attrs?(vm_xml)
vm_root = REXML::Document.new(vm_xml).root
!vm_root.elements[OpenNebulaFirewall::XPATH_FILTER].nil?
end
# Returns a filter object based on the contents of the template
#
# @return OpenNebulaFirewall or OpenNebulaSG object
def self.filter_driver(vm_64, deploy_id = nil, hypervisor = nil)
vm_xml = Base64::decode64(vm_64)
if self.has_fw_attrs?(vm_xml)
OpenNebulaFirewall.new(vm_xml, deploy_id, hypervisor)
else
OpenNebulaSG.new(vm_xml, deploy_id, hypervisor)
end
end
end
end

View File

@ -17,7 +17,7 @@
module VNMMAD
# This module includes provides the abstractions to implement SecurityGroups
module SGBase
module VNMNetwork
############################################################################
# Rule supports these (final and relevant) attributes:
@ -101,7 +101,7 @@ module SGBase
def net
return [] if @ip.nil? || @size.nil?
Address::to_nets(@ip, @size)
VNMNetwork::to_nets(@ip, @size)
end
# Expand the ICMP type with associated codes if any
@ -190,7 +190,7 @@ module SGBase
@rules = []
@vars = {}
@commands = Commands.new
@commands = VNMNetwork::Commands.new
rules.each do |rule|
@rules << new_rule(rule)

View File

@ -22,7 +22,7 @@ module SGIPTables
############################################################################
# A Rule implemented with the iptables/ipset Linux kernel facilities
############################################################################
class RuleIPTables < Rule
class RuleIPTables < VNMNetwork::Rule
########################################################################
# Implementation of each rule type
########################################################################
@ -136,7 +136,7 @@ module SGIPTables
# This class represents a SecurityGroup implemented with iptables/ipset
# Kernel facilities.
############################################################################
class SecurityGroupIPTables < SecurityGroup
class SecurityGroupIPTables < VNMNetwork::SecurityGroup
def initialize(vm, nic, sg_id, rules)
super
@ -157,7 +157,7 @@ module SGIPTables
# - :iptables_s
# - :ipset_list
def self.info
commands = Commands.new
commands = VNMNetwork::Commands.new
commands << :iptables "-S"
iptables_s = commands.run!
@ -188,7 +188,7 @@ module SGIPTables
return if info[:iptables_s].split("\n").include? "-N #{GLOBAL_CHAIN}"
commands = Commands.new
commands = VNMNetwork::Commands.new
commands.iptables "-N #{GLOBAL_CHAIN}"
commands.iptables "-A FORWARD -m physdev --physdev-is-bridged -j #{GLOBAL_CHAIN}"
@ -244,7 +244,7 @@ module SGIPTables
# IP spoofing
# iptables -A one-3-0-o ! --source 10.0.0.1 -j DROP
def self.nic_pre(vm, nic)
commands = Commands.new
commands = VNMNetwork::Commands.new
vars = SGIPTables.vars(vm, nic)
@ -285,7 +285,7 @@ module SGIPTables
chain_in = vars[:chain_in]
chain_out = vars[:chain_out]
commands = Commands.new
commands = VNMNetwork::Commands.new
commands << :iptables "-A #{chain_in} -j DROP"
commands << :iptables "-A #{chain_out} -j DROP"
@ -304,7 +304,7 @@ module SGIPTables
iptables_s = info[:iptables_s]
ipset_list = info[:ipset_list]
commands = Commands.new
commands = VNMNetwork::Commands.new
iptables_forwards.lines.reverse_each do |line|
fields = line.split

View File

@ -0,0 +1,110 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
# #
# 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. #
#--------------------------------------------------------------------------- #
module VNMMAD
module VNMNetwork
############################################################################
# This class represents the VM abstraction. It provides basic methods
# to interact with its network interfaces.
############################################################################
class VM
attr_accessor :nics, :vm_info, :deploy_id, :vm_root
# Creates a new VM object, and bootstrap the NICs array
# @param vm_root [REXML] XML document representing the VM
# @param xpath_filer [String] to get the VM NICs
# @param deploy_id [String] refers to the VM in the hypervisor
# @param hypervisor [String]
def initialize(vm_root, xpath_filter, deploy_id, hypervisor)
@vm_root = vm_root
@xpath_filter = xpath_filter
@deploy_id = deploy_id
@hypervisor = hypervisor
@vm_info = Hash.new
@deploy_id = nil if deploy_id == "-"
nics = VNMNetwork::Nics.new(@hypervisor)
@vm_root.elements.each(@xpath_filter) do |nic_element|
nic = nics.new_nic
nic_build_hash(nic_element,nic)
nic.get_info(self)
nic.get_tap(self)
nics << nic
end
@nics = nics
end
# Iterator on each NIC of the VM
def each_nic(block)
if @nics != nil
@nics.each do |the_nic|
block.call(the_nic)
end
end
end
# Access an XML Element of the VM
# @param element [String] element name
# @return [String] valule of the element or nil if not found
def [](element)
if @vm_root
val = @vm_root.elements[element]
return val.text if !val.nil? && val.text
end
nil
end
private:
# Method to build the associated Hash from a NIC
# @param nic_element [REXML] for the NIC
# @param nic [Nic] class representation
def nic_build_hash(nic_element,nic)
nic_element.elements.each('*') do |nic_attribute|
key = nic_attribute.name.downcase.to_sym
if nic_attribute.has_elements?
data = {}
nic_build_hash(nic_attribute,data)
else
data = nic_attribute.text
end
if nic[key]
if nic[key].instance_of?(Array)
nic[key] << data
else
nic[key] = [nic[key], data]
end
else
nic[key] = data
end
end
end
end
end
end