1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-22 13:33:52 +03:00

F #1684: Support for LXD/LXC Containers. The LXD/LXC drivers are heavily

inspired by the LXD addon https://github.com/OpenNebula/addon-lxdone.

Co-authored-by: Daniel Clavijo Coca <dclavijo@opennebula.systems>
Co-authored-by: Sergio Vega Gutiérrez <svega@opennebula.systems>
Co-authored-by: José Manuel de la Fé Herrero <jmdelafe92@gmail.com>
This commit is contained in:
Ruben S. Montero 2018-11-28 12:26:59 +01:00
parent 175e9456ce
commit 07399094b3
65 changed files with 78554 additions and 344 deletions

4
.gitignore vendored
View File

@ -21,6 +21,8 @@ src/oca/java/jar
src/oca/java/share/doc
src/oca/java/java-oca*.tar.gz
src/vmm_mad/remotes/lxd/tests/
src/docker_machine/pkg
src/docker_machine/src/docker_machine/bin/docker-machine-driver-opennebula
src/docker_machine/src/docker_machine/vendor/
@ -36,3 +38,5 @@ src/sunstone/public/locale/languages/*.js
share/esx-fw-vnc/*.rpm
share/esx-fw-vnc/.vagrant*
*.vscode

58
SConstruct Normal file → Executable file
View File

@ -21,11 +21,11 @@ sys.path.append("./share/scons")
from lex_bison import *
# This is the absolute path where the project is located
cwd=os.getcwd()
cwd = os.getcwd()
# Environment that will be applied to each scons child
main_env=Environment()
main_env['ENV']['PATH']=os.environ['PATH']
main_env = Environment()
main_env['ENV']['PATH'] = os.environ['PATH']
# snippet borrowed from http://dev.gentoo.org/~vapier/scons-blows.txt
# makes scons aware of build related environment variables
@ -40,7 +40,7 @@ if os.environ.has_key('CXXFLAGS'):
if os.environ.has_key('LDFLAGS'):
main_env['LINKFLAGS'] += SCons.Util.CLVar(os.environ['LDFLAGS'])
else:
os.environ['LDFLAGS']=""
os.environ['LDFLAGS'] = ""
# Add builders for flex and bison
add_lex(main_env)
@ -110,13 +110,13 @@ main_env.Append(LIBS=['z'])
#######################
# SQLITE
sqlite_dir=ARGUMENTS.get('sqlite_dir', 'none')
if sqlite_dir!='none':
sqlite_dir = ARGUMENTS.get('sqlite_dir', 'none')
if sqlite_dir != 'none':
main_env.Append(LIBPATH=[sqlite_dir+"/lib", sqlite_dir+"/lib64"])
main_env.Append(CPPPATH=[sqlite_dir+"/include"])
sqlite=ARGUMENTS.get('sqlite', 'yes')
if sqlite=='yes':
sqlite = ARGUMENTS.get('sqlite', 'yes')
if sqlite == 'yes':
main_env.Append(sqlite='yes')
main_env.Append(CPPFLAGS=["-DSQLITE_DB"])
main_env.Append(LIBS=['sqlite3'])
@ -124,8 +124,8 @@ else:
main_env.Append(sqlite='no')
# MySQL
mysql=ARGUMENTS.get('mysql', 'no')
if mysql=='yes':
mysql = ARGUMENTS.get('mysql', 'no')
if mysql == 'yes':
main_env.Append(mysql='yes')
main_env.Append(CPPFLAGS=["-DMYSQL_DB"])
main_env.Append(LIBS=['mysqlclient'])
@ -133,22 +133,22 @@ else:
main_env.Append(mysql='no')
# Flag to compile with xmlrpc-c versions prior to 1.31 (September 2012)
new_xmlrpc=ARGUMENTS.get('new_xmlrpc', 'no')
if new_xmlrpc=='yes':
new_xmlrpc = ARGUMENTS.get('new_xmlrpc', 'no')
if new_xmlrpc == 'yes':
main_env.Append(new_xmlrpc='yes')
else:
main_env.Append(new_xmlrpc='no')
main_env.Append(CPPFLAGS=["-DOLD_XMLRPC"])
# xmlrpc
xmlrpc_dir=ARGUMENTS.get('xmlrpc', 'none')
if xmlrpc_dir!='none':
xmlrpc_dir = ARGUMENTS.get('xmlrpc', 'none')
if xmlrpc_dir != 'none':
main_env.Append(LIBPATH=[xmlrpc_dir+"/lib", xmlrpc_dir+"/lib64"])
main_env.Append(CPPPATH=[xmlrpc_dir+"/include"])
# systemd
systemd=ARGUMENTS.get('systemd', 'no')
if systemd=='yes':
systemd = ARGUMENTS.get('systemd', 'no')
if systemd == 'yes':
main_env.Append(systemd='yes')
main_env.Append(CPPFLAGS=["-DSYSTEMD"])
main_env.Append(LIBS=['systemd'])
@ -156,8 +156,8 @@ else:
main_env.Append(systemd='no')
# build lex/bison
build_parsers=ARGUMENTS.get('parsers', 'no')
if build_parsers=='yes':
build_parsers = ARGUMENTS.get('parsers', 'no')
if build_parsers == 'yes':
main_env.Append(parsers='yes')
else:
main_env.Append(parsers='no')
@ -173,7 +173,7 @@ main_env.Append(docker_machine=ARGUMENTS.get('docker_machine', 'no'))
if not main_env.GetOption('clean'):
try:
if mysql=='yes':
if mysql == 'yes':
main_env.ParseConfig('mysql_config --cflags --libs')
except Exception, e:
print ""
@ -186,28 +186,27 @@ if not main_env.GetOption('clean'):
print ""
exit(-1)
try:
main_env.ParseConfig(("LDFLAGS='%s' share/scons/get_xmlrpc_config"+
main_env.ParseConfig(("LDFLAGS='%s' share/scons/get_xmlrpc_config" +
" server") % (os.environ['LDFLAGS'],))
main_env.ParseConfig(("LDFLAGS='%s' share/scons/get_xmlrpc_config"+
main_env.ParseConfig(("LDFLAGS='%s' share/scons/get_xmlrpc_config" +
" client") % (os.environ['LDFLAGS'],))
except Exception, e:
print ""
print "Error searching for xmlrpc-c libraries. Please check this"+\
print "Error searching for xmlrpc-c libraries. Please check this" +\
" things:"
print ""
print " * You have installed development libraries for xmlrpc-c. One"+\
print " * You have installed development libraries for xmlrpc-c. One" +\
" way to check"
print " this is calling xmlrpc-c-config that is provided with the"+\
print " this is calling xmlrpc-c-config that is provided with the" +\
" development"
print " package."
print " * Check that the version of xmlrpc-c is at least 1.06. You"+\
print " * Check that the version of xmlrpc-c is at least 1.06. You" +\
" can do this also"
print " calling:"
print " $ xmlrpc-c-config --version"
print " * If all this requirements are already met please send log"+\
print " * If all this requirements are already met please send log" +\
" files located in"
print " .xmlrpc_test to the mailing list."
print ""
@ -269,9 +268,10 @@ build_scripts=[
'share/rubygems/SConstruct',
'src/im_mad/collectd/SConstruct',
'src/client/SConstruct',
'src/docker_machine/SConstruct'
'src/docker_machine/SConstruct',
'src/vmm_mad/remotes/lib/lxd/svncterm_server/SConstruct'
]
for script in build_scripts:
env=main_env.Clone()
env = main_env.Clone()
SConscript(script, exports='env')

View File

@ -253,12 +253,16 @@ VAR_DIRS="$VAR_LOCATION/remotes \
$VAR_LOCATION/remotes/etc \
$VAR_LOCATION/remotes/etc/datastore/ceph \
$VAR_LOCATION/remotes/etc/im/kvm-probes.d \
$VAR_LOCATION/remotes/etc/im/lxd-probes.d \
$VAR_LOCATION/remotes/etc/vmm/kvm \
$VAR_LOCATION/remotes/etc/vmm/lxd \
$VAR_LOCATION/remotes/etc/vmm/vcenter \
$VAR_LOCATION/remotes/etc/vnm \
$VAR_LOCATION/remotes/im \
$VAR_LOCATION/remotes/im/kvm.d \
$VAR_LOCATION/remotes/im/kvm-probes.d \
$VAR_LOCATION/remotes/im/lxd.d \
$VAR_LOCATION/remotes/im/lxd-probes.d \
$VAR_LOCATION/remotes/im/vcenter.d \
$VAR_LOCATION/remotes/im/ec2.d \
$VAR_LOCATION/remotes/im/az.d \
@ -270,6 +274,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \
$VAR_LOCATION/remotes/vmm/ec2 \
$VAR_LOCATION/remotes/vmm/az \
$VAR_LOCATION/remotes/vmm/one \
$VAR_LOCATION/remotes/vmm/lxd \
$VAR_LOCATION/remotes/vnm \
$VAR_LOCATION/remotes/vnm/802.1Q \
$VAR_LOCATION/remotes/vnm/vxlan \
@ -396,6 +401,9 @@ INSTALL_FILES=(
IM_PROBES_KVM_FILES:$VAR_LOCATION/remotes/im/kvm.d
IM_PROBES_KVM_PROBES_FILES:$VAR_LOCATION/remotes/im/kvm-probes.d
IM_PROBES_ETC_KVM_PROBES_FILES:$VAR_LOCATION/remotes/etc/im/kvm-probes.d
IM_PROBES_LXD_FILES:$VAR_LOCATION/remotes/im/lxd.d
IM_PROBES_LXD_PROBES_FILES:$VAR_LOCATION/remotes/im/lxd-probes.d
IM_PROBES_ETC_LXD_PROBES_FILES:$VAR_LOCATION/remotes/etc/im/lxd-probes.d
IM_PROBES_VCENTER_FILES:$VAR_LOCATION/remotes/im/vcenter.d
IM_PROBES_EC2_FILES:$VAR_LOCATION/remotes/im/ec2.d
IM_PROBES_AZ_FILES:$VAR_LOCATION/remotes/im/az.d
@ -411,7 +419,10 @@ INSTALL_FILES=(
VMM_EXEC_LIB_FILES:$VAR_LOCATION/remotes/vmm/lib
VMM_EXEC_LIB_VCENTER_FILES:$LIB_LOCATION/ruby/vcenter_driver
VMM_EXEC_KVM_SCRIPTS:$VAR_LOCATION/remotes/vmm/kvm
VMM_EXEC_LXD_SCRIPTS:$VAR_LOCATION/remotes/vmm/lxd
VMM_EXEC_LXD_LIB:$VAR_LOCATION/remotes/vmm/lxd
VMM_EXEC_ETC_KVM_SCRIPTS:$VAR_LOCATION/remotes/etc/vmm/kvm
VMM_EXEC_ETC_LXD_SCRIPTS:$VAR_LOCATION/remotes/etc/vmm/lxd
VMM_EXEC_VCENTER_SCRIPTS:$VAR_LOCATION/remotes/vmm/vcenter
VMM_EXEC_ETC_VCENTER_SCRIPTS:$VAR_LOCATION/remotes/etc/vmm/vcenter
VMM_EXEC_EC2_SCRIPTS:$VAR_LOCATION/remotes/vmm/ec2
@ -712,6 +723,45 @@ VMM_EXEC_LIB_VCENTER_FILES="src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb
src/vmm_mad/remotes/lib/vcenter_driver/vm_template.rb \
src/vmm_mad/remotes/lib/vcenter_driver/network.rb"
#-------------------------------------------------------------------------------
# VMM SH Driver LXD scripts, to be installed under $REMOTES_LOCATION/vmm/lxd
#-------------------------------------------------------------------------------
VMM_EXEC_LXD_SCRIPTS="src/vmm_mad/remotes/lxd/cancel \
src/vmm_mad/remotes/lxd/deploy \
src/vmm_mad/remotes/lxd/migrate \
src/vmm_mad/remotes/lxd/migrate_local \
src/vmm_mad/remotes/lxd/restore \
src/vmm_mad/remotes/lxd/reboot \
src/vmm_mad/remotes/lxd/reset \
src/vmm_mad/remotes/lxd/save \
src/vmm_mad/remotes/lxd/poll \
src/vmm_mad/remotes/lxd/attach_disk \
src/vmm_mad/remotes/lxd/detach_disk \
src/vmm_mad/remotes/lxd/attach_nic \
src/vmm_mad/remotes/lxd/detach_nic \
src/vmm_mad/remotes/lxd/snapshot_create \
src/vmm_mad/remotes/lxd/snapshot_revert \
src/vmm_mad/remotes/lxd/snapshot_delete \
src/vmm_mad/remotes/lxd/shutdown \
src/vmm_mad/remotes/lxd/reconfigure \
src/vmm_mad/remotes/lxd/prereconfigure \
src/vmm_mad/remotes/lxd/resize_disk"
VMM_EXEC_LXD_LIB="src/vmm_mad/remotes/lib/lxd/opennebula_vm.rb \
src/vmm_mad/remotes/lib/lxd/mapper/mapper.rb \
src/vmm_mad/remotes/lib/lxd/mapper/qcow2.rb \
src/vmm_mad/remotes/lib/lxd/mapper/raw.rb \
src/vmm_mad/remotes/lib/lxd/mapper/rbd.rb \
src/vmm_mad/remotes/lib/lxd/client.rb \
src/vmm_mad/remotes/lib/lxd/command.rb \
src/vmm_mad/remotes/lib/lxd/container.rb"
#-------------------------------------------------------------------------------
# VMM configuration LXD scripts, to be installed under $REMOTES_LOCATION/etc/vmm/lxd
#-------------------------------------------------------------------------------
VMM_EXEC_ETC_LXD_SCRIPTS="src/vmm_mad/remotes/lxd/lxdrc"
#-------------------------------------------------------------------------------
# VMM SH Driver KVM scripts, to be installed under $REMOTES_LOCATION/vmm/kvm
#-------------------------------------------------------------------------------
@ -870,6 +920,21 @@ IM_PROBES_KVM_PROBES_FILES="src/im_mad/remotes/kvm-probes.d/kvm.rb \
IM_PROBES_ETC_KVM_PROBES_FILES="src/im_mad/remotes/kvm-probes.d/pci.conf"
IM_PROBES_LXD_PROBES_FILES="src/im_mad/remotes/lxd-probes.d/lxd.rb \
src/im_mad/remotes/lxd-probes.d/architecture.sh \
src/im_mad/remotes/lxd-probes.d/cpu.sh \
src/im_mad/remotes/lxd-probes.d/poll.sh \
src/im_mad/remotes/lxd-probes.d/name.sh \
src/im_mad/remotes/lxd-probes.d/pci.rb \
src/im_mad/remotes/lxd-probes.d/monitor_ds.sh \
src/im_mad/remotes/lxd-probes.d/version.sh \
src/im_mad/remotes/lxd-probes.d/collectd-client-shepherd.sh"
IM_PROBES_LXD_FILES="src/im_mad/remotes/lxd.d/collectd-client_control.sh \
src/im_mad/remotes/lxd.d/collectd-client.rb"
IM_PROBES_ETC_LXD_PROBES_FILES="src/im_mad/remotes/lxd-probes.d/pci.conf"
IM_PROBES_VCENTER_FILES="src/im_mad/remotes/vcenter.d/poll"
IM_PROBES_EC2_FILES="src/im_mad/remotes/ec2.d/poll"

View File

@ -409,6 +409,32 @@ IM_MAD = [
# ARGUMENTS = "-r 3 -t 15 -w 90 kvm-probes" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# LXD UDP-push Information Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
# -w Timeout in seconds to execute external commands (default unlimited)
#-------------------------------------------------------------------------------
IM_MAD = [
NAME = "lxd",
SUNSTONE_NAME = "LXD",
EXECUTABLE = "one_im_ssh",
ARGUMENTS = "-r 3 -t 15 -w 90 lxd" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# LXD SSH-pull Information Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
# -w Timeout in seconds to execute external commands (default unlimited)
#-------------------------------------------------------------------------------
# IM_MAD = [
# NAME = "lxd",
# SUNSTONE_NAME = "lxd-ssh",
# EXECUTABLE = "one_im_ssh",
# ARGUMENTS = "-r 3 -t 15 -w 90 lxd-probes" ]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# vCenter Information Driver Manager Configuration
# -r number of retries when monitoring a host
@ -548,6 +574,32 @@ VM_MAD = [
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# LXD Virtualization Driver Manager Configuration
# -r number of retries when monitoring a host
# -t number of threads, i.e. number of hosts monitored at the same time
# -l <actions[=command_name]> actions executed locally, command can be
# overridden for each action.
# Valid actions: deploy, shutdown, cancel, save, restore, migrate, poll
# An example: "-l migrate=migrate_local,save"
# -p more than one action per host in parallel, needs support from hypervisor
# -s <shell> to execute remote commands, bash by default
# -w Timeout in seconds to execute external commands (default unlimited)
#
#-------------------------------------------------------------------------------
VM_MAD = [
NAME = "lxd",
SUNSTONE_NAME = "LXD",
EXECUTABLE = "one_vmm_exec",
ARGUMENTS = "-t 15 -r 0 lxd",
# DEFAULT = "vmm_exec/vmm_exec_lxd.conf",
TYPE = "xml",
KEEP_SNAPSHOTS = "no",
IMPORTED_VMS_ACTIONS = "terminate, terminate-hard, reboot, reboot-hard, poweroff, poweroff-hard, suspend, resume, stop, delete, nic-attach, nic-detach"
]
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# vCenter Virtualization Driver Manager Configuration
# -r number of retries when monitoring a host

View File

@ -1,19 +0,0 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
echo ARCH=`uname -m`

View File

@ -0,0 +1 @@
../node-probes.d/architecture.sh

View File

@ -0,0 +1 @@
../common.d/collectd-client-shepherd.sh

View File

@ -1,35 +0,0 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
MODEL=''
if [ -f /proc/cpuinfo ]; then
for NAME in 'model name' 'cpu'; do
MODEL=$(grep -m1 "^${NAME}[[:space:]]*:" /proc/cpuinfo | \
cut -d: -f2 | \
sed -e 's/^ *//')
if [ -n "${MODEL}" ]; then
break
fi
done
fi
if [ -n "${MODEL}" ]; then
echo "MODELNAME=\"${MODEL}\""
fi

View File

@ -0,0 +1 @@
../node-probes.d/cpu.sh

View File

@ -0,0 +1 @@
../common.d/monitor_ds.sh

View File

@ -1,21 +0,0 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
echo HOSTNAME=`uname -n`

View File

@ -0,0 +1 @@
../node-probes.d/name.sh

View File

@ -1,66 +0,0 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
# This option specifies the main filters for PCI card monitoring. The format
# is the same as used by lspci to filter on PCI card by vendor:device(:class)
# identification. Several filters can be added as a list, or separated
# by commas. The NULL filter will retrieve all PCI cards.
#
# From lspci help:
# -d [<vendor>]:[<device>][:<class>]
# Show only devices with specified vendor, device and class ID.
# The ID's are given in hexadecimal and may be omitted or given
# as "*", both meaning "any value"#
#
# For example:
# :filter:
# - '10de:*' # all NVIDIA VGA cards
# - '10de:11bf' # only GK104GL [GRID K2]
# - '*:10d3' # only 82574L Gigabit Network cards
# - '8086::0c03' # only Intel USB controllers
#
# or
#
# :filter: '*:*' # all devices
#
# or
#
# :filter: '0:0' # no devices
#
:filter: '0:0'
# The PCI cards list restricted by the :filter option above can be even more
# filtered by the list of exact PCI addresses (bus:device.func).
#
# For example:
# :short_address:
# - '07:00.0'
# - '06:00.0'
#
:short_address: []
# The PCI cards list restricted by the :filter option above can be even more
# filtered by matching the device name against the list of regular expression
# case-insensitive patterns.
#
# For example:
# :device_name:
# - 'Virtual Function'
# - 'Gigabit Network'
# - 'USB.*Host Controller'
# - '^MegaRAID'
#
:device_name: []

View File

@ -0,0 +1 @@
../node-probes.d/pci.conf

View File

@ -1,118 +0,0 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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 'shellwords'
require 'yaml'
begin
NAME = File.join(File.dirname(__FILE__), '../../etc/im/kvm-probes.d/pci.conf')
CONF = {
:filter => '0:0',
:short_address => [],
:device_name => [],
}.merge(YAML.load_file(NAME))
rescue
STDERR.puts "Invalid configuration #{NAME}"
exit(-1)
end
def get_pci(filter=nil)
command = "lspci -mmnn"
command << " -d #{filter}" if filter
text = %x(#{command})
text.split("\n").map {|l| Shellwords.split(l) }
end
def get_name_and_id(text)
m = text.match(/^(.*) \[(....)\]$/)
return m[1], m[2]
end
def parse_pci(pci)
card = {}
card[:short_address] = pci[0]
card[:libvirt_address] =
"pci_0000_#{card[:short_address].gsub(/[:.]/, '_')}"
card[:address] = "0000:#{card[:short_address].gsub(/[:.]/, ':')}"
card[:class_name], card[:class] = get_name_and_id(pci[1])
card[:vendor_name], card[:vendor] = get_name_and_id(pci[2])
card[:device_name], card[:device] = get_name_and_id(pci[3])
card[:bus], card[:slot], card[:function] = pci[0].split(/[:.]/)
card[:type] = [card[:vendor], card[:device], card[:class]].join(':')
card
end
def get_devices(filter=nil)
if filter
filter = [filter].flatten.map { |f| f.split(',') }.flatten
else
filter = [nil]
end
filter.map do |f|
get_pci(f).map {|pci| parse_pci(pci) }
end.flatten
end
filter = CONF[:filter]
devices = get_devices(filter)
def pval(name, value)
%Q( #{name} = "#{value}")
end
devices.each do |dev|
next if !CONF[:short_address].empty? && !CONF[:short_address].include?(dev[:short_address])
if !CONF[:device_name].empty?
matched = CONF[:device_name].each { |pattern|
break true if !(dev[:device_name] =~ /#{pattern}/i).nil?
}
next if matched != true
end
puts "PCI = ["
values = [
pval('TYPE', dev[:type]),
pval('VENDOR', dev[:vendor]),
pval('VENDOR_NAME', dev[:vendor_name]),
pval('DEVICE', dev[:device]),
pval('DEVICE_NAME', dev[:device_name]),
pval('CLASS', dev[:class]),
pval('CLASS_NAME', dev[:class_name]),
pval('ADDRESS', dev[:address]),
pval('SHORT_ADDRESS', dev[:short_address]),
pval('DOMAIN', '0000'),
pval('BUS', dev[:bus]),
pval('SLOT', dev[:slot]),
pval('FUNCTION', dev[:function])
]
puts values.join(",\n")
puts "]"
end

View File

@ -0,0 +1 @@
../node-probes.d/pci.rb

View File

@ -0,0 +1 @@
../common.d/version.sh

View File

@ -0,0 +1 @@
../node-probes.d/architecture.sh

View File

@ -0,0 +1 @@
../common.d/collectd-client-shepherd.sh

View File

@ -0,0 +1 @@
../node-probes.d/cpu.sh

View File

@ -0,0 +1,99 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
def print_info(name, value)
value = "0" if value.nil? or value.to_s.strip.empty?
puts "#{name}=#{value}"
end
######
# First, get all the posible info out of virsh
# TODO : use virsh freecell when available
######
ENV['LANG'] = 'C'
ENV['LC_ALL'] = 'C'
nodeinfo_text = `virsh -c qemu:///system nodeinfo`
exit(-1) if $?.exitstatus != 0
nodeinfo_text.split(/\n/).each{|line|
if line =~ /^CPU\(s\)/
$total_cpu = line.split(':')[1].strip.to_i * 100
elsif line =~ /^CPU frequency/
$cpu_speed = line.split(':')[1].strip.split(' ')[0]
elsif line =~ /^Memory size/
$total_memory = line.split(':')[1].strip.split(' ')[0]
end
}
######
# CPU
######
vmstat = `vmstat 1 2`
$free_cpu = $total_cpu * ((vmstat.split("\n").to_a.last.split)[14].to_i)/100
$used_cpu = $total_cpu - $free_cpu
######
# MEMORY
######
memory = `cat /proc/meminfo`
meminfo = Hash.new()
memory.each_line do |line|
key, value = line.split(':')
meminfo[key] = /\d+/.match(value)[0].to_i
end
$total_memory = meminfo['MemTotal']
$used_memory = meminfo['MemTotal'] - meminfo['MemFree'] - meminfo['Buffers'] - meminfo['Cached']
$free_memory = $total_memory - $used_memory
######
# INTERFACE
######
NETINTERFACE = 'eth|bond|em|enp|p[0-9]+p[0-9]+'
net_text=`cat /proc/net/dev`
exit(-1) if $?.exitstatus != 0
$netrx = 0
$nettx = 0
net_text.split(/\n/).each do |line|
next unless line =~ /^ *#{NETINTERFACE}/
arr = line.split(':')[1].split(' ')
$netrx += arr[0].to_i
$nettx += arr[8].to_i
end
print_info("HYPERVISOR","lxd")
print_info("TOTALCPU",$total_cpu)
print_info("CPUSPEED",$cpu_speed)
print_info("TOTALMEMORY",$total_memory)
print_info("USEDMEMORY",$used_memory)
print_info("FREEMEMORY",$free_memory)
print_info("FREECPU",$free_cpu)
print_info("USEDCPU",$used_cpu)
print_info("NETRX",$netrx)
print_info("NETTX",$nettx)

View File

@ -0,0 +1 @@
../common.d/monitor_ds.sh

View File

@ -0,0 +1 @@
../node-probes.d/name.sh

View File

@ -0,0 +1 @@
../node-probes.d/pci.conf

View File

@ -0,0 +1 @@
../node-probes.d/pci.rb

View File

@ -0,0 +1,19 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
../../vmm/lxd/poll -t

View File

@ -0,0 +1 @@
../common.d/version.sh

View File

@ -0,0 +1 @@
../common.d/collectd-client.rb

View File

@ -0,0 +1 @@
../common.d/collectd-client_control.sh

View File

@ -0,0 +1,19 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
echo ARCH=`uname -m`

View File

@ -0,0 +1,35 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
MODEL=''
if [ -f /proc/cpuinfo ]; then
for NAME in 'model name' 'cpu'; do
MODEL=$(grep -m1 "^${NAME}[[:space:]]*:" /proc/cpuinfo | \
cut -d: -f2 | \
sed -e 's/^ *//')
if [ -n "${MODEL}" ]; then
break
fi
done
fi
if [ -n "${MODEL}" ]; then
echo "MODELNAME=\"${MODEL}\""
fi

View File

@ -0,0 +1,21 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
echo HOSTNAME=`uname -n`

View File

@ -0,0 +1,66 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
# This option specifies the main filters for PCI card monitoring. The format
# is the same as used by lspci to filter on PCI card by vendor:device(:class)
# identification. Several filters can be added as a list, or separated
# by commas. The NULL filter will retrieve all PCI cards.
#
# From lspci help:
# -d [<vendor>]:[<device>][:<class>]
# Show only devices with specified vendor, device and class ID.
# The ID's are given in hexadecimal and may be omitted or given
# as "*", both meaning "any value"#
#
# For example:
# :filter:
# - '10de:*' # all NVIDIA VGA cards
# - '10de:11bf' # only GK104GL [GRID K2]
# - '*:10d3' # only 82574L Gigabit Network cards
# - '8086::0c03' # only Intel USB controllers
#
# or
#
# :filter: '*:*' # all devices
#
# or
#
# :filter: '0:0' # no devices
#
:filter: '0:0'
# The PCI cards list restricted by the :filter option above can be even more
# filtered by the list of exact PCI addresses (bus:device.func).
#
# For example:
# :short_address:
# - '07:00.0'
# - '06:00.0'
#
:short_address: []
# The PCI cards list restricted by the :filter option above can be even more
# filtered by matching the device name against the list of regular expression
# case-insensitive patterns.
#
# For example:
# :device_name:
# - 'Virtual Function'
# - 'Gigabit Network'
# - 'USB.*Host Controller'
# - '^MegaRAID'
#
:device_name: []

View File

@ -0,0 +1,121 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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 'shellwords'
require 'yaml'
begin
probes_path = File.dirname(File.realdirpath(__FILE__))
ETC_NAME = probes_path.split(File::SEPARATOR)[-1]
NAME = File.join(File.dirname(__FILE__),"../../etc/im/#{ETC_NAME}/pci.conf")
CONF = {
:filter => '0:0',
:short_address => [],
:device_name => [],
}.merge(YAML.load_file(NAME))
rescue
STDERR.puts "Invalid configuration #{NAME}"
exit(-1)
end
def get_pci(filter=nil)
command = "lspci -mmnn"
command << " -d #{filter}" if filter
text = %x(#{command})
text.split("\n").map {|l| Shellwords.split(l) }
end
def get_name_and_id(text)
m = text.match(/^(.*) \[(....)\]$/)
return m[1], m[2]
end
def parse_pci(pci)
card = {}
card[:short_address] = pci[0]
card[:libvirt_address] =
"pci_0000_#{card[:short_address].gsub(/[:.]/, '_')}"
card[:address] = "0000:#{card[:short_address].gsub(/[:.]/, ':')}"
card[:class_name], card[:class] = get_name_and_id(pci[1])
card[:vendor_name], card[:vendor] = get_name_and_id(pci[2])
card[:device_name], card[:device] = get_name_and_id(pci[3])
card[:bus], card[:slot], card[:function] = pci[0].split(/[:.]/)
card[:type] = [card[:vendor], card[:device], card[:class]].join(':')
card
end
def get_devices(filter=nil)
if filter
filter = [filter].flatten.map { |f| f.split(',') }.flatten
else
filter = [nil]
end
filter.map do |f|
get_pci(f).map {|pci| parse_pci(pci) }
end.flatten
end
filter = CONF[:filter]
devices = get_devices(filter)
def pval(name, value)
%Q( #{name} = "#{value}")
end
devices.each do |dev|
next if !CONF[:short_address].empty? && !CONF[:short_address].include?(dev[:short_address])
if !CONF[:device_name].empty?
matched = CONF[:device_name].each { |pattern|
break true if !(dev[:device_name] =~ /#{pattern}/i).nil?
}
next if matched != true
end
puts "PCI = ["
values = [
pval('TYPE', dev[:type]),
pval('VENDOR', dev[:vendor]),
pval('VENDOR_NAME', dev[:vendor_name]),
pval('DEVICE', dev[:device]),
pval('DEVICE_NAME', dev[:device_name]),
pval('CLASS', dev[:class]),
pval('CLASS_NAME', dev[:class_name]),
pval('ADDRESS', dev[:address]),
pval('SHORT_ADDRESS', dev[:short_address]),
pval('DOMAIN', '0000'),
pval('BUS', dev[:bus]),
pval('SLOT', dev[:slot]),
pval('FUNCTION', dev[:function])
]
puts values.join(",\n")
puts "]"
end

View File

@ -0,0 +1,128 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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 'net/http'
require 'socket'
require 'json'
#
# LXD API Client. This class is used to interact with LXD. Wraps API calls
# through the REST API
#
class LXDClient
# API Configuration Attributes
API = '/1.0'.freeze
HEADER = { 'Host' => 'localhost' }.freeze
SOCK_PATH = '/var/lib/lxd/unix.socket'
# Enable communication with LXD via unix socket
begin
SOCK = Net::BufferedIO.new(UNIXSocket.new(SOCK_PATH))
rescue StandardError
STDERR.puts('Could not open LXD socket')
Process.exit(1)
end
# Performs HTTP::Get
# Params:
# +uri+:: +string+ API path
def get(uri)
get_response(Net::HTTP::Get.new("#{API}/#{uri}", HEADER), data = nil)
end
# Performs HTTP::Delete
# Params:
# +uri+:: +string+ API path
def delete(uri)
get_response(Net::HTTP::Delete.new("#{API}/#{uri}", HEADER), data = nil)
end
# Performs HTTP::Put
# Params:
# +uri+:: +string+ API path
def put(uri, data)
get_response(Net::HTTP::Put.new("#{API}/#{uri}", HEADER), data)
end
# Performs HTTP::Post
# Params:
# +uri+:: +string+ API path
def post(uri, data)
get_response(Net::HTTP::Post.new("#{API}/#{uri}", HEADER), data)
end
# Performs HTTP::Patch
# Params:
# +uri+:: +string+ API path
def patch(uri, data)
get_response(Net::HTTP::Patch.new("#{API}/#{uri}", HEADER), data)
end
# Waits for an operation returned in response to be completed
def wait(response, timeout)
operation_id = response['operation'].split('/').last
timeout = "?timeout=#{timeout}" if timeout
response = get("operations/#{operation_id}/wait#{timeout}")
raise LXDError, response if response['metadata']['status'] == 'Failure'
end
private
# Returns the HTTPResponse body as a hash
# Params:
# +request+:: +Net::HTTP::Request+ made to the http server
# +data+:: +string+ for post/put/patch requests that send data to the server
# (may be nil)
def get_response(request, data)
request.body = JSON.dump(data) unless data.nil?
request.exec(SOCK, '1.1', request.path)
response = nil
loop do
response = Net::HTTPResponse.read_new(SOCK)
break unless response.is_a?(Net::HTTPContinue)
end
response.reading_body(SOCK, request.response_body_permitted?) {}
response = JSON.parse(response.body)
raise LXDError, response if response['type'] == 'error'
response
end
end
# Error used for raising LXDClient exception when response is error return value
class LXDError < StandardError
attr_reader :body
def initialize(msg = 'LXD API error')
@body = msg
super
end
end

View File

@ -0,0 +1,77 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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 'open3'
# This module can be used to execute commands. It wraps popen3 and provides
# locking capabilites using flock
module Command
LOCK_FILE = '/tmp/onelxd-lock'
def self.execute(cmd, block)
rc = -1
stdout = ''
stderr = ''
begin
fd = lock if block
Open3.popen3(cmd) { |i, o, e, t|
rc = t.value.exitstatus
stdout = o.read
stderr = e.read
o.close
e.close
}
rescue
ensure
unlock(fd) if block
end
[rc, stdout, stderr]
end
def self.execute_once(cmd, lock)
execute(cmd, lock) unless running?(cmd.split[0])
end
def self.lxc_execute(lxd_id, cmd)
cmd = "lxc exec #{lxd_id} -- #{cmd}"
execute(cmd, true)
end
# Return true if command is running
def self.running?(command)
!`ps --noheaders -C #{command}`.empty?
end
def self.lock
lfd = File.open(LOCK_FILE,"w")
lfd.flock(File::LOCK_EX)
return lfd
end
def self.unlock(lfd)
lfd.close
end
end

View File

@ -0,0 +1,418 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'client'
require 'opennebula_vm'
require 'command'
require 'mapper'
require 'raw'
require 'qcow2'
require 'rbd'
# This class interacts with the LXD container on REST level
class Container
#---------------------------------------------------------------------------
# Class Constants API and Containers Paths
#---------------------------------------------------------------------------
CONTAINERS = 'containers'.freeze
#---------------------------------------------------------------------------
# Methods to access container attributes
#---------------------------------------------------------------------------
CONTAINER_ATTRIBUTES = %w[name status status_code devices config profile
expanded_config expanded_devices architecture].freeze
CONTAINER_ATTRIBUTES.each do |attr|
define_method(attr.to_sym) do
@lxc[attr]
end
define_method("#{attr}=".to_sym) do |value|
@lxc[attr] = value
end
end
# Return if this is a wild container. Needs the associated OpenNebulaVM
# description
def wild?
@one.wild? if @one
end
#---------------------------------------------------------------------------
# Class constructors & static methods
#---------------------------------------------------------------------------
# Creates the container object in memory.
# Can be later created in LXD using create method
def initialize(lxc, one, client)
@client = client
@lxc = lxc
@one = one
end
class << self
# Returns specific container, by its name
# Params:
# +name+:: container name
def get(name, one_xml, client)
info = client.get("#{CONTAINERS}/#{name}")['metadata']
one = nil
one = OpenNebulaVM.new(one_xml) if one_xml
Container.new(info, one, client)
rescue LXDError => exception
raise exception
end
# Creates container from a OpenNebula VM xml description
def new_from_xml(one_xml, client)
one = OpenNebulaVM.new(one_xml)
Container.new(one.to_lxc, one, client)
end
# Returns an array of container objects
def get_all(client)
containers = []
container_names = client.get(CONTAINERS)['metadata']
container_names.each do |name|
name = name.split('/').last
containers.push(get(name, nil, client))
end
containers
end
# Returns boolean indicating if the container exists(true) or not (false)
def exist?(name, client)
client.get("#{CONTAINERS}/#{name}")
true
rescue LXDError => exception
raise exception if exception.body['error_code'] != 404
false
end
end
#---------------------------------------------------------------------------
# Container Management & Monitor
#---------------------------------------------------------------------------
# Create a container without a base image
def create(wait: true, timeout: '')
@lxc['source'] = { 'type' => 'none' }
wait?(@client.post(CONTAINERS, @lxc), wait, timeout)
@lxc = @client.get("#{CONTAINERS}/#{name}")['metadata']
end
# Delete container
def delete(wait: true, timeout: '')
wait?(@client.delete("#{CONTAINERS}/#{name}"), wait, timeout)
end
# Updates the container in LXD server with the new configuration
def update(wait: true, timeout: '')
wait?(@client.put("#{CONTAINERS}/#{name}", @lxc), wait, timeout)
end
# Returns the container current state
def monitor
@client.get("#{CONTAINERS}/#{name}/state")
end
# Retreive metadata for the container
def get_metadata
@lxc = @client.get("#{CONTAINERS}/#{name}")['metadata']
end
# Runs command inside container
# @param command [String] to execute through lxc exec
def exec(command)
Command.lxd_execute(name, command)
end
#---------------------------------------------------------------------------
# Contianer Status Control
#---------------------------------------------------------------------------
def start(options = {})
change_state(__method__, options)
end
def stop(options = {})
change_state(__method__, options)
end
def restart(options = {})
change_state(__method__, options)
end
def freeze(options = {})
change_state(__method__, options)
end
def unfreeze(options = {})
change_state(__method__, options)
end
#---------------------------------------------------------------------------
# Container Networking
#---------------------------------------------------------------------------
def attach_nic(mac)
return unless @one
nic_xml = @one.get_nic_by_mac(mac)
return unless nic_xml
nic_config = @one.nic(nic_xml)
@lxc['devices'].update(nic_config)
update
end
def detach_nic(mac)
@lxc['devices'].delete_if do |device, config|
device.include?('eth') && config['hwaddr'] == mac
end
update
end
#---------------------------------------------------------------------------
# Container Storage
#---------------------------------------------------------------------------
# Sets up the container mounts for type: disk devices.
def setup_storage(operation)
return unless @one
@one.get_disks.each do |disk|
setup_disk(disk, operation)
end
return unless @one.has_context?
csrc = @lxc['devices']['context']['source'].clone
context = @one.get_context_disk
mapper = FSRawMapper.new
context_path = "#{@one.lxdrc[:containers]}/#{name}/rootfs/context"
create_context_dir = "#{Mapper::COMMANDS[:su_mkdir]} #{context_path}"
Command.execute(create_context_dir, false)
mapper.public_send(operation, @one, context, csrc)
end
# Generate the context devices and maps the context the device
def attach_context
@one.context(@lxc['devices'])
csrc = @lxc['devices']['context']['source'].clone
context = @one.get_context_disk
mapper = FSRawMapper.new
mapper.map(@one, context, csrc)
update
end
# Removes the context section from the LXD configuration and unmap the
# context device
def detach_context
return unless @one.has_context?
csrc = @lxc['devices']['context']['source'].clone
@lxc['devices'].delete('context')['source']
update
context = @one.get_context_disk
mapper = FSRawMapper.new
mapper.unmap(@one, context, csrc)
end
# Attach disk to container (ATTACH = YES) in VM description
def attach_disk(source)
disk_element = hotplug_disk
return unless disk_element
setup_disk(disk_element, 'map')
source2 = source.dup
if source
mapper_location = source2.index('/disk.')
source2.insert(mapper_location, '/mapper')
end
disk_hash = @one.disk(disk_element, source2, nil)
@lxc['devices'].update(disk_hash)
update
end
# Detects disk being hotplugged
def hotplug_disk
return unless @one
disk_a = @one.get_disks.select do |disk|
disk['ATTACH'].casecmp('YES').zero?
end
disk_a.first
end
# Detach disk to container (ATTACH = YES) in VM description
def detach_disk
disk_element = hotplug_disk
return unless disk_element
disk_name = "disk#{disk_element['DISK_ID']}"
csrc = @lxc['devices'][disk_name]['source'].clone
@lxc['devices'].delete(disk_name)['source']
update
mapper = new_disk_mapper(@one, disk_element)
mapper.unmap(@one, disk_element, csrc)
end
# Setup the disk by mapping/unmapping the disk device
def setup_disk(disk, operation)
return unless @one
ds_path = @one.ds_path
ds_id = @one.sysds_id
vm_id = @one.vm_id
disk_id = disk['DISK_ID']
if disk_id == @one.rootfs_id
target = "#{@one.lxdrc[:containers]}/#{name}/rootfs"
else
target = @one.disk_mountpoint(disk_id)
end
mapper = new_disk_mapper(disk)
mapper.public_send(operation, @one, disk, target)
end
# Start the svncterm server if it is down.
def vnc(signal)
command = @one.vnc_command(signal)
return if command.nil?
w = @one.lxdrc[:vnc][:width]
h = @one.lxdrc[:vnc][:height]
t = @one.lxdrc[:vnc][:timeout]
vnc_args = "-w #{w} -h #{h} -t #{t}"
pipe = '/tmp/svncterm_server_pipe'
bin = 'svncterm_server'
server = "#{bin} #{vnc_args}"
Command.execute_once(server, true)
lfd = Command.lock
File.open(pipe, 'a') do |f|
f.write command
end
ensure
Command.unlock(lfd) if lfd
end
private
# Waits or no for response depending on wait value
def wait?(response, wait, timeout)
@client.wait(response, timeout) unless wait == false
end
# Performs an action on the container that changes the execution status.
# Accepts optional args
def change_state(action, options)
options.update(:action => action)
response = @client.put("#{CONTAINERS}/#{name}/state", options)
wait?(response, options[:wait], options[:timeout])
@lxc = @client.get("#{CONTAINERS}/#{name}")['metadata']
status
end
# Returns a mapper for the disk
# @param disk [XMLElement] with the disk data
#
# TODO This maps should be built dynamically or based on a DISK attribute
# so new mappers does not need to modified source code
def new_disk_mapper(disk)
case disk['TYPE']
when 'FILE'
ds_path = @one.ds_path
ds_id = @one.sysds_id
vm_id = @one.vm_id
disk_id = disk['DISK_ID']
ds = "#{ds_path}/#{ds_id}/#{vm_id}/disk.#{disk_id}"
Command.execute("#{Mapper::COMMANDS[:chmod_nfs]} #{ds}", false)
_rc, out, _err = Command.execute("#{Mapper::COMMANDS[:file]} #{ds}", false)
case out
when /.*QEMU QCOW.*/
OpenNebula.log "Using qcow2 mapper for #{ds}"
return Qcow2Mapper.new
when /.*filesystem.*/
OpenNebula.log "Using raw filesystem mapper for #{ds}"
return FSRawMapper.new
when /.*boot sector.*/
OpenNebula.log "Using raw disk mapper for #{ds}"
return DiskRawMapper.new
else
OpenNebula.log('Unknown image format, trying raw filesystem mapper')
return FSRawMapper.new
end
when 'RBD'
RBDMapper.new
end
end
end

View File

@ -0,0 +1,413 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'fileutils'
require 'json'
require 'opennebula_vm'
require 'command'
# Mappers class provides an interface to map devices into the host filesystem
# This class uses an array of partitions as output by lsblk in JSON:
# [
# {
# "name" : "loop1p3",
# "path" : "/dev/mapper/loop1p3",
# "type" : "part",
# "fstype" : "..",
# "label" : null,
# "uuid" : null,
# "fsavail": "...M",
# "fsuse%" : "..%",
# "mountpoint":"/boot"
# },
# {
# ....
# children : [
# ]
# }
# ]
class Mapper
#---------------------------------------------------------------------------
# Class constants
# - COMMANDS list of commands executed by the driver. This list can
# be tunned to specific paths. It contians the list of commands executed
# as root
#---------------------------------------------------------------------------
COMMANDS = {
:lsblk => 'sudo lsblk',
:losetup => 'sudo losetup',
:mount => 'sudo mount',
:umount => 'sudo umount',
:kpartx => 'sudo kpartx',
:nbd => 'sudo qemu-nbd',
:su_mkdir => 'sudo mkdir -p',
:mkdir => 'mkdir -p',
:cat => 'sudo cat',
:file => 'file -L',
:blkid => 'sudo blkid',
:e2fsck => 'sudo e2fsck',
:resize2fs => 'sudo resize2fs',
:xfs_growfs => 'sudo xfs_growfs',
:chmod_nfs => 'chmod o+w'
}
#---------------------------------------------------------------------------
# Interface to be implemented by specific mapper modules
#---------------------------------------------------------------------------
# Maps the disk to host devices
# @param onevm [OpenNebulaVM] with the VM description
# @param disk [XMLElement] with the disk data
# @param directory [String] where the disk has to be mounted
# @return [String] Name of the mapped device, empty in case of error.
#
# Errors should be log using OpenNebula driver functions
def do_map(one_vm, disk, directory)
OpenNebula.log_error("map function not implemented for #{self.class}")
return nil
end
# Unmaps a previously mapped partition
# @param device [String] where the disk is mapped
# @param disk [XMLElement] with the disk data
# @param directory [String] where the disk has to be mounted
#
# @return nil
def do_unmap(device, one_vm, disk, directory)
OpenNebula.log_error("unmap function not implemented for #{self.class}")
return nil
end
#---------------------------------------------------------------------------
# Mapper Interface 'map' & 'unmap' methods
#---------------------------------------------------------------------------
# Maps a disk to a given directory
# @param onevm [OpenNebulaVM] with the VM description
# @param disk [XMLElement] with the disk data
# @param directory [String] Path to the directory where the disk has to be
# mounted. Example: /var/lib/one/datastores/100/3/mapper/disk.2
#
# @return true on success
def map(one_vm, disk, directory)
device = do_map(one_vm, disk, directory)
OpenNebula.log_info "Mapping disk at #{directory} using device #{device}"
return false if !device
partitions = lsblk(device)
return false if !partitions
#-----------------------------------------------------------------------
# Mount disk images with partitions
#-----------------------------------------------------------------------
return mount(partitions, directory) if partitions[0]['type'] == 'part'
#-----------------------------------------------------------------------
# Resize partitions if needed and mount single filesystem disk images
#-----------------------------------------------------------------------
type = partitions[0]['type']
return mount_dev(device, directory) unless %w[loop disk].include?(type)
size = disk['SIZE'].to_i if disk['SIZE']
osize = disk['ORIGINAL_SIZE'].to_i if disk['ORIGINAL_SIZE']
# TODO: Osize is always < size after 1st resize during deployment
return mount_dev(device, directory) unless size > osize
# Resize filesystem
cmd = "#{COMMANDS[:blkid]} -o export #{device}"
_rc, o, _e = Command.execute(cmd, false)
fs_type = ''
o.each_line {|l|
next unless (m = l.match(/TYPE=(.*)/))
fs_type = m[1]
break
}
rc = true
OpenNebula.log_info "Resizing filesystem #{fs_type} on #{device}"
case fs_type
when /xfs/
rc = mount_dev(device, directory)
return false unless rc
Command.execute("#{COMMANDS[:xfs_growfs]} -d #{directory}", false)
when /ext/
Command.execute("#{COMMANDS[:e2fsck]} -f -y #{device}", false)
Command.execute("#{COMMANDS[:resize2fs]} #{device}", false)
rc = mount_dev(device, directory)
else
OpenNebula.log_info "Skipped filesystem #{fs_type} resize"
rc = mount_dev(device, directory)
end
rc
end
# Unmaps a disk from a given directory
# @param disk [XMLElement] with the disk data
# @param directory [String] Path to the directory where the disk has to be
# mounted. Example: /var/lib/one/datastores/100/3/mapper/disk.2
#
# @return true on success
def unmap(one_vm, disk, directory)
OpenNebula.log_info "Unmapping disk at #{directory}"
sys_parts = lsblk('')
partitions = []
device = ''
return false if !sys_parts
sys_parts.each { |d|
if d['mountpoint'] == directory
partitions = [d]
device = d['path']
break
end
d['children'].each { |c|
if c['mountpoint'] == directory
partitions = d['children']
device = d['path']
break
end
} if d['children']
break if !partitions.empty?
}
partitions.delete_if { |p| !p['mountpoint'] }
partitions.sort! { |a,b|
b['mountpoint'].length <=> a['mountpoint'].length
}
umount(partitions)
do_unmap(device, one_vm, disk, directory)
return true
end
private
#---------------------------------------------------------------------------
# Methods to mount/umount partitions
#---------------------------------------------------------------------------
# Umounts partitions
# @param partitions [Array] with partition device names
def umount(partitions)
partitions.each { |p|
next if !p['mountpoint']
umount_dev(p['path'])
}
end
# Mounts partitions
# @param partitions [Array] with partition device names
# @param path [String] to directory to mount the disk partitions
def mount(partitions, path)
# Single partition
# ----------------
return mount_dev(partitions[0]['path'], path) if partitions.size == 1
# Multiple partitions
# -------------------
rc = true
fstab = ''
# Look for fstab and mount rootfs in path. First partition with
# a /etc/fstab file is used as rootfs and it is kept mounted
partitions.each do |p|
rc = mount_dev(p['path'], path)
return false if !rc
cmd = "#{COMMANDS[:cat]} #{path}/etc/fstab"
rc, fstab, e = Command.execute(cmd, false)
if fstab.empty?
umount_dev(p['path'])
next
end
break
end
if fstab.empty?
OpenNebula.log_error("mount: No fstab file found in disk partitions")
return false
end
# Parse fstab contents & mount partitions
fstab.each_line do |l|
next if l.strip.chomp.empty?
next if l =~ /\s*#/
fs, mount_point, type, opts, dump, pass = l.split
if l =~ /^\s*LABEL=/ # disk by LABEL
value = fs.split("=").last.strip.chomp
key = 'label'
elsif l =~ /^\s*UUID=/ #disk by UUID
value = fs.split("=").last.strip.chomp
key = 'uuid'
else #disk by device - NOT SUPPORTED or other FS
next
end
next if mount_point == '/' || mount_point == 'swap'
partitions.each { |p|
next if p[key] != value
rc = mount_dev(p['path'], path + mount_point)
return false if !rc
break
}
end
return rc
end
# --------------------------------------------------------------------------
# Functions to mount/umount devices
# --------------------------------------------------------------------------
# Mount the given device. It creates the directory if need. NOTE: The rootfs
# dir is created as root as it is typically under lxd/storage-pools and it
# is managed by LXD
# @param dev [String] device name
# @param path [String] to mount the device
#
# @return true on success
def mount_dev(dev, path)
OpenNebula.log_info "Mounting #{dev} at #{path}"
if path =~ /.*\/rootfs/
cmd = COMMANDS[:su_mkdir]
else
cmd = COMMANDS[:mkdir]
end
Command.execute("#{cmd} #{path}", false)
rc, out, err = Command.execute("#{COMMANDS[:mount]} #{dev} #{path}",true)
if rc != 0
OpenNebula.log_error("mount_dev: #{err}")
return false
end
true
end
def umount_dev(dev)
OpenNebula.log_info "Umounting disk mapped at #{dev}"
Command.execute("#{COMMANDS[:umount]} #{dev}", true)
end
#---------------------------------------------------------------------------
# Mapper helper functions
#---------------------------------------------------------------------------
# Get the partitions on the system or device
# @param device [String] to get the partitions from. Use and empty string
# for host partitions
# @return [Hash] with partitions
def lsblk(device)
rc, o, e = Command.execute("#{COMMANDS[:lsblk]} -OJ #{device}", false)
if rc != 0 || o.empty?
OpenNebula.log_error("lsblk: #{e}")
return nil
end
partitions = nil
begin
partitions = JSON.parse(o)['blockdevices']
if !device.empty?
partitions = partitions[0]
if partitions['children']
partitions = partitions['children']
else
partitions = [partitions]
end
partitions.delete_if { |p|
p['fstype'].casecmp?('swap') if p['fstype']
}
end
rescue
OpenNebula.log_error("lsblk: error parsing lsblk -OJ #{device}")
return nil
end
# Fix for lsblk paths for version < 2.33
partitions.each { |p|
lsblk_path(p)
p['children'].each { |q| lsblk_path(q) } if p['children']
}
partitions
end
# @return [String] the canonical disk path for the given disk
def disk_source(one_vm, disk)
ds_path = one_vm.ds_path
ds_id = one_vm.sysds_id
vm_id = one_vm.vm_id
disk_id = disk['DISK_ID']
"#{ds_path}/#{ds_id}/#{vm_id}/disk.#{disk_id}"
end
# Adds path to the partition Hash. This is needed for lsblk version < 2.33
def lsblk_path(p)
return unless !p['path'] && p['name']
if File.exists?("/dev/#{p['name']}")
p['path'] = "/dev/#{p['name']}"
elsif File.exists?("/dev/mapper/#{p['name']}")
p['path'] = "/dev/mapper/#{p['name']}"
end
end
end

View File

@ -0,0 +1,86 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'mapper'
class Qcow2Mapper < Mapper
# Max number of block devices. This should be set to the parameter used
# to load the nbd kernel module (default in kernel is 16)
NBDS_MAX = 256
def do_map(one_vm, disk, directory)
device = nbd_device
return nil if device.empty?
dsrc = disk_source(one_vm, disk)
cmd = "#{COMMANDS[:nbd]} -c #{device} #{dsrc}"
rc, out, err = Command.execute(cmd, true)
loop do
sleep 0.5
nbd_parts = lsblk(device)
break if nbd_parts && nbd_parts[0] && nbd_parts[0]['fstype']
end
if rc != 0
OpenNebula.log_error("do_map: #{err}")
return nil
end
device
end
def do_unmap(device, one_vm, disk, directory)
cmd = "#{COMMANDS[:nbd]} -d #{device}"
rc, out, err = Command.execute(cmd, true)
if rc != 0
OpenNebula.log_error("do_unmap: #{err}")
end
end
private
def nbd_device()
sys_parts = lsblk('')
device_id = -1
nbds = []
sys_parts.each { |p|
m = p['name'].match(/nbd(\d+)/)
next if !m
nbds << m[1].to_i
}
NBDS_MAX.times { |i|
return "/dev/nbd#{i}" unless nbds.include?(i)
}
OpenNebula.log_error("nbd_device: Cannot find free nbd device")
''
end
end

View File

@ -0,0 +1,87 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'mapper'
#-------------------------------------------------------------------------------
# These classes implements the mapping of raw filesystems & raw disk images
#-------------------------------------------------------------------------------
class FSRawMapper < Mapper
def do_map(one_vm, disk, directory)
dsrc = disk_source(one_vm, disk)
cmd = "#{COMMANDS[:losetup]} -f --show #{dsrc}"
rc, out, err = Command.execute(cmd, true)
if rc != 0 || out.empty?
OpenNebula.log_error("do_map: #{err}")
return
end
out.chomp
end
def do_unmap(device, one_vm, disk, directory)
cmd = "#{COMMANDS[:losetup]} -d #{device}"
rc, _out, err = Command.execute(cmd, true)
OpenNebula.log_error("do_unmap: #{err}") if rc != 0
end
end
class DiskRawMapper < Mapper
# Maps the whole file using kpartx. The output should be something like:
# $ sudo kpartx -av /var/lib/one/datastores/100/0/disk.0
# add map loop3p1 (253:0): 0 204800 linear 7:3 2048
# add map loop3p2 (253:1): 0 524288 linear 7:3 206848
# add map loop3p3 (253:2): 0 1366016 linear 7:3 731136
# Fisrt line is matched to look for loop device 3, and return "/dev/loop3"
def do_map(one_vm, disk, directory)
dsrc = disk_source(one_vm, disk)
cmd = "#{COMMANDS[:kpartx]} -av #{dsrc}"
rc, out, err = Command.execute(cmd, true)
if rc != 0 || out.empty?
OpenNebula.log_error("do_map: #{err}")
return nil
end
loopdev = out.lines[0].match(/.*add map loop(\d+)p\d+.*/)
return nil if !loopdev
"/dev/loop#{loopdev[1]}"
end
# Unmaps all devices and loops with kpartx using the source file
def do_unmap(device, one_vm, disk, directory)
dsrc = disk_source(one_vm, disk)
cmd = "#{COMMANDS[:kpartx]} -d #{dsrc}"
rc, out, err = Command.execute(cmd, true)
if rc != 0
OpenNebula.log_error("do_unmap: #{err}")
end
end
end

View File

@ -0,0 +1,60 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'mapper'
# Ceph RBD mapper
class RBD < Mapper
def initialize(ceph_user)
@ceph_user = ceph_user
end
def map(image)
`sudo rbd --id #{@ceph_user} map #{image}`.chomp
end
def unmap(block)
shell("sudo rbd --id #{@ceph_user} unmap #{block}")
end
# Returns an array of mountable block's partitions
def detect_parts(block)
parts = `blkid | grep #{block} | grep -w UUID | awk {'print $1'}`.split(":\n")
uuids = []
parts.each {|part| uuids.append `blkid #{part} -o export | grep -w UUID`.chomp("\n")[5..-1] }
formatted = []
0.upto parts.length - 1 do |i|
formatted[i] = { 'name' => parts[i], 'uuid' => uuids[i] }
end
formatted
end
def get_parts(block)
parts = detect_parts(block)
parts.each do |part|
part['name'].slice!('//dev')
end
parts
end
end

View File

@ -0,0 +1,425 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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 'rexml/document'
require 'yaml'
# This class reads and holds configuration attributes for the LXD driver
class LXDConfiguration < Hash
DEFAULT_CONFIGURATION = {
:vnc => {
:command => '/bin/bash',
:width => '800',
:height => '600',
:timeout => '300'
},
:datastore_location => '/var/lib/one/datastores',
:containers => '/var/lib/lxd/storage-pools/default/containers'
}
def initialize
replace(DEFAULT_CONFIGURATION)
begin
merge!(YAML.load_file("#{__dir__}/../../etc/vmm/lxd/lxdrc"))
rescue
end
end
end
# This class parses and wraps the information in the Driver action data
class OpenNebulaVM
attr_reader :xml, :vm_id, :vm_name, :sysds_id, :ds_path, :rootfs_id, :lxdrc
#---------------------------------------------------------------------------
# Class Constructor
#---------------------------------------------------------------------------
def initialize(xml)
@xml = XMLElement.new_s(xml)
@xml = @xml.element('//VM')
@vm_id = @xml['//TEMPLATE/VMID']
@sysds_id = @xml['//HISTORY_RECORDS/HISTORY/DS_ID']
@vm_name = @xml['//DEPLOY_ID']
@vm_name = "one-#{@vm_id}" if @vm_name.empty?
return if wild?
# Load Driver configuration
@lxdrc = LXDConfiguration.new
@ds_path = @lxdrc[:datastore_location]
# Sets the DISK ID of the root filesystem
disk = @xml.element('//TEMPLATE/DISK')
return unless disk
@rootfs_id = disk['DISK_ID']
boot_order = @xml['//TEMPLATE/OS/BOOT']
@rootfs_id = boot_order.split(',')[0][-1] unless boot_order.empty?
end
def has_context?
!@xml['//TEMPLATE/CONTEXT/DISK_ID'].empty?
end
def wild?
@vm_name && !@vm_name.include?('one-')
end
# Returns a Hash representing the LXC configuration for this OpenNebulaVM
def to_lxc
lxc = {}
lxc['name'] = @vm_name
lxc['config'] = {}
lxc['devices'] = {}
profile(lxc)
memory(lxc['config'])
cpu(lxc['config'])
extra_config(lxc['config'])
network(lxc['devices'])
storage(lxc['devices']) unless wild?
lxc
end
#---------------------------------------------------------------------------
# Container Attribute Mapping
#---------------------------------------------------------------------------
# Creates a dictionary for LXD containing $MEMORY RAM allocated
def memory(hash)
hash['limits.memory'] = "#{@xml['//TEMPLATE/MEMORY']}MB"
end
# Creates a dictionary for LXD $CPU percentage and cores
def cpu(hash)
cpu = @xml['//TEMPLATE/CPU']
hash['limits.cpu.allowance'] = "#{(cpu.to_f * 100).to_i}%"
vcpu = @xml['//TEMPLATE/VCPU']
hash['limits.cpu'] = vcpu unless vcpu.empty?
end
#---------------------------------------------------------------------------
# Container Device Mapping: Networking
#---------------------------------------------------------------------------
# Get nic by mac
def get_nic_by_mac(mac)
get_nics.each do |n|
return n if n['MAC'] == mac
end
end
def get_nics
@xml.elements('//TEMPLATE/NIC')
end
# Sets up the network interfaces configuration in devices
def network(hash)
get_nics.each do |n|
hash.update(nic(n))
end
end
# Creates a nic hash from NIC xml root
def nic(info)
eth = {
'name' => "eth#{info['NIC_ID']}",
'host_name' => info['TARGET'],
'parent' => info['BRIDGE'],
'hwaddr' => info['MAC'],
'nictype' => 'bridged',
'type' => 'nic'
}
nic_map = {
'limits.ingress' => 'INBOUND_AVG_BW',
'limits.egress' => 'OUTBOUND_AVG_BW'
}
io_map(nic_map, eth, info) {|v| "#{v.to_i * 8}kbit" }
{ "eth#{info['NIC_ID']}" => eth }
end
#---------------------------------------------------------------------------
# Container Device Mapping: Storage
#---------------------------------------------------------------------------
# Get disk by target
def get_disk_by_target(value)
get_disk_by('TARGET', value)
end
# Get disk by id
def get_disk_by_id(value)
get_disk_by('DISK_ID', value)
end
# Get a disk depending on the filter xml key and the matching value
def get_disks_by(filter, value)
get_disks.each do |n|
return n if n[filter] == value
end
end
def get_context_disk()
@xml.element('//TEMPLATE/CONTEXT')
end
def get_disks
@xml.elements('//TEMPLATE/DISK')
end
# Sets up the storage devices configuration in devices
def storage(hash)
disks = @xml.elements('//TEMPLATE/DISK')
disks.each do |n|
hash.update(disk(n, nil, nil))
end
context(hash)
end
# Generate Context information
def context(hash)
cid = @xml['//TEMPLATE/CONTEXT/DISK_ID']
return if cid.empty?
source = "#{@ds_path}/#{@sysds_id}/#{@vm_id}/mapper/disk.#{cid}"
hash['context'] = {
'type' => 'disk',
'source' => source,
'path' => '/context'
}
end
def disk_mountpoint(disk_id)
"#{@ds_path}/#{@sysds_id}/#{@vm_id}/mapper/disk.#{disk_id}"
end
# Creates a disk hash from DISK xml element
def disk(info, source, path)
disk_id = info['DISK_ID']
disk = {}
#-----------------------------------------------------------------------
# Source & Path attributes
#-----------------------------------------------------------------------
if disk_id == @rootfs_id
disk_name = 'root'
disk = { 'type' => 'disk', 'path' => '/', 'pool' => 'default' }
else
source ||= disk_mountpoint(disk_id)
unless path
path = info['TARGET']
path = "/media/#{disk_id}" unless path[0] == '/'
end
disk_name = "disk#{disk_id}"
disk = { 'type' => 'disk', 'source' => source, 'path' => path }
end
#-----------------------------------------------------------------------
# Readonly attributes
#-----------------------------------------------------------------------
if info['READONLY'].casecmp('yes').zero?
disk['readonly'] = 'true'
else
disk['readonly'] = 'false'
end
#-----------------------------------------------------------------------
# IO limits
#-----------------------------------------------------------------------
tbytes = info['TOTAL_BYTES_SEC']
tiops = info['TOTAL_IOPS_SEC']
if tbytes && !tbytes.empty?
disk['limits.max'] = tbytes
elsif tiops && !tiops.empty?
disk['limits.max'] = "#{tiops}iops"
end
if tbytes.empty? && tiops.empty?
disk_map = {
'limits.read' => 'READ_BYTES_SEC',
'limits.write' => 'WRITE_BYTES_SEC'
}
mapped = io_map(disk_map, disk, info) {|v| v }
if !mapped
disk_map = {
'limits.read' => 'READ_IOPS_SEC',
'limits.write' => 'WRITE_IOPS_SEC'
}
io_map(disk_map, disk, info) {|v| "#{v}iops" }
end
end
{ disk_name => disk }
end
#---------------------------------------------------------------------------
# Container Mapping: Extra Configuration & Profiles
#---------------------------------------------------------------------------
def extra_config(hash)
security = {
'security.privileged' => 'false',
'security.nesting' => 'false'
}
security.each_key do |key|
item = "LXD_SECURITY_#{key.split('.').last.swapcase}"
value = @xml["//USER_TEMPLATE/#{item}"]
security[key] = value unless value.empty?
end
hash.merge!(security)
raw_data = {}
data = @xml['//TEMPLATE/RAW/DATA']
type = @xml['//TEMPLATE/RAW/TYPE']
if !data.empty? && type.casecmp('lxd').zero?
begin
raw_data = JSON.parse("{#{data}}")
rescue StandardError
end
end
hash.merge!(raw_data) unless raw_data.empty?
end
def profile(hash)
profile = @xml['//USER_TEMPLATE/LXD_PROFILE']
profile = 'default' if profile.empty?
hash['profiles'] = [profile]
end
def device_info(devices, key, filter)
devices.each do |device|
return device[key] if device[key].value?(filter)
end
end
# Creates container vnc connection
# Creates or closes a connection to a container rfb port depending on signal
def vnc_command(signal)
data = @xml.element('//TEMPLATE/GRAPHICS')
return unless data && data['PORT'] && data['TYPE'] == 'VNC'
pass = data['PASSWD']
pass = '-' unless pass && !pass.empty?
case signal
when 'start'
command = @lxdrc[:vnc][:command]
"#{data['PORT']} #{pass} lxc exec #{@vm_name} #{command}\n"
when 'stop'
"-#{data['PORT']}\n"
end
end
private
# Maps IO limits from an OpenNebula VM configuration to a LXD configuration
# map: Hash that defines LXD name to OpenNebula name mapping
# lxd_conf: Hash with LXD configuration
# one_conf: XML Element with OpenNebula Configuration
#
# Block: To transform OpenNebula value
def io_map(map, lxd_conf, one_conf)
mapped = false
map.each do |key, value|
one_value = one_conf[value]
next if one_value.empty?
lxd_conf[key] = yield(one_value)
mapped = true
end
mapped
end
end
# This class abstracts the access to XML elements. It provides basic methods
# to get elements by their xpath
class XMLElement
def initialize(xml)
@xml = xml
end
# Create a new XMLElement using a xml document in a string
def self.new_s(xml_s)
xml = nil
xml = REXML::Document.new(xml_s).root unless xml_s.empty?
new(xml)
end
# Gets the text associated to a th element. The element is select by
# its xpath. If not found an empty string is returned
def [](key)
element = @xml.elements[key.to_s]
return '' if (element && !element.has_text?) || !element
element.text
end
# Return an XMLElement for the given xpath
def element(key)
e = @xml.elements[key.to_s]
element = nil
element = XMLElement.new(e) if e
element
end
# Get elements by xpath. This function returns an Array of XMLElements
def elements(key)
collection = []
@xml.elements.each(key) do |pelem|
collection << XMLElement.new(pelem)
end
collection
end
end

View File

@ -0,0 +1,31 @@
# ---------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
# ---------------------------------------------------------------------------- #
import os
env = Environment()
env['LIBS'] = ['-lz']
env.Program('genfont.c')
env = Environment()
env['LIBS'] = ['-lvncserver', '-lnsl', '-lpthread', '-lz', '-ljpeg',
'-lutil', '-lgnutls']
env['CFLAGS'] = ['-D_GNU_SOURCE']
env.Program('svncterm_server.c')

View File

@ -0,0 +1,35 @@
Copyright 2002-2018, OpenNebula Project, OpenNebula Systems
-Changes to genfont utility
* Update psf loader to PSFv2
* Added command line options & usage
* Other minor code changes
-Changes to svncterm
* Added command line options
* inetd like behavior, start vncserver when a conneciton is accepted
Copyright (C) 2016 Universitat Politecnica de Valencia
* Removing the usage of TLS and the need of patched versions of libraries
Copyright (C) 2007 Proxmox Server Solutions GmbH
Copyright: svncterm is under GNU GPL, the GNU General Public License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The complete text of the GNU General
Public License can be found in `/usr/share/common-licenses/GPL'.

View File

@ -0,0 +1,371 @@
/*
Copyright (C) 2007 Proxmox Server Solutions GmbH
Copyright: vzdump is under GNU GPL, the GNU General Public License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
Author: Dietmar Maurer <dietmar@proxmox.com>
Copyright 2002-2018, OpenNebula Project, OpenNebula Systems
- Update psf loader to PSFv2
- Added command line options & usage
- Other minor code changes
contact@opennebula.systems
*/
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
#include <string.h>
/* -------------------------------------------------------------------------- */
/* Font glyph storage array and map pointer */
/* -------------------------------------------------------------------------- */
/* map unicode to font */
static unsigned short vt_fontmap[65536];
/* font glyph storage */
static unsigned char * vt_font_data = NULL;
static int vt_font_size = 0; //Index to current glyph
static int vt_font_maxsize = 0; //Max size of fontmap
/* -------------------------------------------------------------------------- */
/* PC Screen Font v2 data (PSFv2) Header & Constants */
/* -------------------------------------------------------------------------- */
#define PSF2_MAGIC0 0x72
#define PSF2_MAGIC1 0xb5
#define PSF2_MAGIC2 0x4a
#define PSF2_MAGIC3 0x86
/* bits used in flags */
#define PSF2_HAS_UNICODE_TABLE 0x01
/* max version recognized so far */
#define PSF2_MAXVERSION 0
/* UTF8 separators */
#define PSF2_SEPARATOR 0xFF
#define PSF2_STARTSEQ 0xFE
struct psf2_header
{
unsigned char magic[4];
unsigned int version;
unsigned int headersize; /* offset of bitmaps in file */
unsigned int flags;
unsigned int length; /* number of glyphs */
unsigned int charsize; /* number of bytes for each character */
unsigned int height, width; /* max dimensions of glyphs */
/* charsize = height * ((width + 7) / 8) */
};
/* -------------------------------------------------------------------------- */
/* Font map management */
/* -------------------------------------------------------------------------- */
/**
* Copy the glyph to the font map array
* @param data, the glyph bitmap
* @param gzise, size of glyph
*/
static int font_add_glyph (const char *data, unsigned int gsize)
{
if (vt_font_size >= vt_font_maxsize)
{
vt_font_maxsize += 256;
vt_font_data = realloc (vt_font_data, vt_font_maxsize * gsize);
}
memcpy(vt_font_data + vt_font_size * gsize, data, gsize);
return vt_font_size++;
}
/**
* Convert UTF8 to (1, 2 & 3 bytes) Unicode char
* Return 0 success, -1 not ucode, -2 EOU (end of unicode)
*/
static int utf8_2_unicode(gzFile stream, char s, u_int16_t * ucode)
{
char s1, s2;
*ucode = (u_int16_t) s;
if (*ucode == 0xFFFF)
{
return -2;
}
if (*ucode == 0xFFFE)
{
return -1;
}
if (!(*ucode & 0x80))
{
return 0;
}
*ucode = 0;
if ((s & 0xE0) == 0xC0)
{
gzread(stream, &s1, 1);
*ucode = (s & 0x1F) << 6;
*ucode |= (s1 & 0x3F);
}
else if ((s & 0xF0) == 0xE0)
{
gzread(stream, &s1, 1);
gzread(stream, &s2, 1);
*ucode = (s & 0x0F) << 12;
*ucode |= (s1 & 0x3F) << 6;
*ucode |= (s2 & 0x3F);
}
return 0;
}
/**
* Load the PSF font file
*/
static int load_psf_font (const char *filename, int is_default)
{
struct psf2_header psf2hdr;
size_t psf2hdr_len = sizeof(struct psf2_header);
gzFile f = gzopen(filename, "rb");
if (f == NULL)
{
fprintf (stderr, "unable to read file %s\n", filename);
return -1;
}
/* ---------------------------------------------------------------------- */
/* Load PSF2 header and check consistency */
/* ---------------------------------------------------------------------- */
if (gzread(f, &psf2hdr, psf2hdr_len) != psf2hdr_len)
{
fprintf(stderr, "Wrong header in psf2 font file (%s)\n", filename);
gzclose(f);
return -1;
}
if (psf2hdr.magic[0] != PSF2_MAGIC0 || psf2hdr.magic[1] != PSF2_MAGIC1 ||
psf2hdr.magic[2] != PSF2_MAGIC2 || psf2hdr.magic[3] != PSF2_MAGIC3 )
{
fprintf(stderr, "File %s not in PSFv2 format\n", filename);
gzclose(f);
return -1;
}
if (!(psf2hdr.flags & PSF2_HAS_UNICODE_TABLE))
{
fprintf(stderr, "File %s does not include Unicode glyphs\n", filename);
gzclose(f);
return -1;
}
if ( psf2hdr.height != 16 && psf2hdr.width != 8 )
{
fprintf(stderr, "File %s does not include 8x16 font\n", filename);
gzclose(f);
return -1;
}
/* ---------------------------------------------------------------------- */
/* Read the bitmaps */
/* ---------------------------------------------------------------------- */
int gsize = psf2hdr.charsize;
int font_size = gsize * psf2hdr.length;
char *chardata = (char *) malloc (font_size);
if (gzread(f, chardata, font_size)!= font_size)
{
fprintf (stderr, "Cannot read font character data from %s\n", filename);
gzclose (f);
free(chardata);
return -1;
}
/* ---------------------------------------------------------------------- */
/* Read the Unicode description of the glyphs */
/* ---------------------------------------------------------------------- */
for (int glyph = 0 ;glyph < psf2hdr.length ;glyph++)
{
int fi = 0;
char s;
while (gzread(f, &s, 1) == 1)
{
u_int16_t uchar;
int rc = utf8_2_unicode(f, s, &uchar);
if ( rc == -1 )
{
continue;
}
else if ( rc == -2 )
{
break;
}
if (!vt_fontmap[uchar] && uchar != 0)
{
if (!fi)
{
fi = font_add_glyph(chardata + glyph * gsize, gsize);
}
vt_fontmap[uchar] = fi;
}
if (is_default && fi && glyph < 256)
{
vt_fontmap[0xf000 + glyph] = fi;
}
}
}
free(chardata);
gzclose(f);
return 0;
}
/* -------------------------------------------------------------------------- */
/* Print the include file */
/* -------------------------------------------------------------------------- */
void print_glyphs ()
{
printf ("static int vt_font_size = %d;\n\n", vt_font_size);
printf ("static unsigned char vt_font_data[] = {\n");
for (int i = 0; i < vt_font_size; i++)
{
printf("\t/* %d 0x%02x */\n", i, i);
for (int j = 0; j < 16; j++) //glyph size == 16
{
unsigned char d = vt_font_data[i*16+j];
printf ("\t0x%02X, /* ", d);
for (int k = 128; k > 0; k = k>>1)
{
printf ("%c", (d & k) ? '1': '0');
}
printf (" */\n");
}
printf ("\n");
}
printf ("};\n\n");
printf ("static unsigned short vt_fontmap[65536] = {\n");
for (int i = 0; i < 0x0ffff; i++)
{
printf ("\t/* 0x%04X => */ %d,\n", i, vt_fontmap[i]);
}
printf ("};\n\n");
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static void print_usage()
{
fprintf(stderr, "Usage: genfont [-d font_path] [font1 font2...]\n");
fprintf(stderr, "Generate Glyph Bitmaps and associated Unicode mapping\n\n");
fprintf(stderr, "\tfont1... List of fonts, the first one is the default\n\n");
fprintf(stderr, "\t-d path: Font path defaults to /usr/share/consolefonts\n\n");
fprintf(stderr, "Example: genfont default8x16.psf.gz lat1u-16.psf.gz"
" lat2u-16.psf.gz\n");
}
int main (int argc, char** argv)
{
char empty[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char font_dir[PATH_MAX - 256] = "/usr/share/consolefonts";
int opt;
/* ---------------------------------------------------------------------- */
/* Arguments parsing */
/* ---------------------------------------------------------------------- */
while ((opt = getopt(argc, argv, "hd:")) != -1) {
switch (opt) {
case 'h':
print_usage();
exit(0);
case 'd':
strncpy(font_dir, optarg, PATH_MAX - 257);
break;
default: /* '?' */
print_usage();
exit(EXIT_FAILURE);
}
}
/* ---------------------------------------------------------------------- */
/* Load PSF fonts & print glyphs */
/* ---------------------------------------------------------------------- */
font_add_glyph(empty, sizeof(empty));
if ( optind >= argc )
{
print_usage();
exit(EXIT_FAILURE);
}
for (int i=optind ; i < argc; ++i)
{
char font_path[PATH_MAX];
snprintf(font_path, PATH_MAX, "%s/%s", font_dir, argv[i]);
/* font load order is only important if glyphs are redefined */
load_psf_font(font_path, i == optind);
}
print_glyphs ();
exit (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,235 @@
#include <rfb/rfb.h>
#define IBUFSIZE 1024
#define MAX_ESC_PARAMS 16
typedef unsigned short unicode;
typedef struct TextAttributes {
unsigned int fgcol:4;
unsigned int bgcol:4;
unsigned int bold:1;
unsigned int uline:1;
unsigned int blink:1;
unsigned int invers:1;
unsigned int unvisible:1;
} TextAttributes;
typedef struct TextCell {
unicode ch;
TextAttributes attrib;
} TextCell;
typedef struct vncTerm {
int maxx;
int maxy;
int width;
int height;
int total_height;
int scroll_height;
int y_base;
int y_displ;
int altbuf:1;
unsigned int utf8:1; // utf8 mode
long utf_char; // used by utf8 parser
int utf_count; // used by utf8 parser
TextAttributes default_attrib;
TextCell *cells;
TextCell *altcells;
rfbScreenInfoPtr screen;
// cursor
TextAttributes cur_attrib;
TextAttributes cur_attrib_saved;
int tty_state; // 0 - normal, 1 - ESC, 2 - CSI
int cx; // cursor x position
int cy; // cursor y position
int cx_saved; // saved cursor x position
int cy_saved; // saved cursor y position
int esc_buf[MAX_ESC_PARAMS];
int esc_count;
int esc_ques;
int esc_has_par;
char osc_textbuf[4096];
char osc_cmd;
int region_top;
int region_bottom;
unsigned int charset:1; // G0 or G1
unsigned int charset_saved:1; // G0 or G1
unsigned int g0enc:2;
unsigned int g0enc_saved:2;
unsigned int g1enc:2;
unsigned int g1enc_saved:2;
unsigned int cur_enc:2;
unsigned int cur_enc_saved:2;
// input buffer
char ibuf[IBUFSIZE];
int ibuf_count;
unicode *selection;
int selection_len;
unsigned int mark_active:1;
unsigned int report_mouse:1;
} vncTerm;
/* Unicode translations copied from kernel source consolemap.c */
#define LAT1_MAP 0
#define GRAF_MAP 1
#define IBMPC_MAP 2
#define USER_MAP 3
static unsigned short translations[][256] = {
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
},
/* VT100 graphics mapped to Unicode */
{
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
},
/* IBM Codepage 437 mapped to Unicode */
{
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
},
/* User mapping -- default to codes for direct font mapping */
{
0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
image_path = ARGV[1]
target = ARGV[2]
disk_index = ARGV[3]
xml64 = ARGV[4]
vm_id = ARGV[5]
xml = STDIN.read
client = LXDClient.new
container = Container.get(vm_name, xml, client)
container.attach_disk(image_path)

View File

@ -0,0 +1,43 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
mac = ARGV[1]
bridge = ARGV[2]
model = ARGV[3]
net_drv = ARGV[4]
host_nic= ARGV[5]
vm_id = ARGV[6]
host = ARGV[7]
xml = STDIN.read
client = LXDClient.new
container = Container.get(vm_name, xml, client)
container.attach_nic(mac)

19
src/vmm_mad/remotes/lxd/cancel Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$(dirname $0)/shutdown $@ '-f'

91
src/vmm_mad/remotes/lxd/deploy Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
xml_path = ARGV[0]
vm_id = ARGV[2]
xml = STDIN.read
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
client = LXDClient.new
container = Container.new_from_xml(xml, client)
# ------------------------------------------------------------------------------
# Create Container in LXD
# - Already exists: gets container metadata from LXD and set OpenNebula
# configurations to update existing container.
# - Not exists. Creates new container in LXD.
# ------------------------------------------------------------------------------
if Container.exist?(container.name, client)
OpenNebula.log_info('Overriding container')
config = container.config
devices = container.devices
container.get_metadata
err_msg = 'A container with the same ID is already running'
raise LXDError, err_msg if container.status == 'Running'
container.config = config
container.devices = devices
container.update
else
container.create
end
# ------------------------------------------------------------------------------
# Start the container, if not wild, maps storage to host directories
# ------------------------------------------------------------------------------
if container.wild?
container.start
else
container.setup_storage('map')
if container.start != 'Running'
OpenNebula.log_error('Container failed to start')
container.setup_storage('unmap')
container.delete
raise LXDError, container.status
end
end
#-------------------------------------------------------------------------------
# Updates container configuration with the OpenNebulaVM description
# ------------------------------------------------------------------------------
container.config.update('user.xml' => xml)
container.update
container.vnc('start')
puts container.name

View File

@ -0,0 +1,38 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
tgt_path = ARGV[1]
tgt = ARGV[2]
tgt_index = ARGV[3]
xml = STDIN.read
client = LXDClient.new
container = Container.get(vm_name, xml, client)
container.detach_disk

View File

@ -0,0 +1,39 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
mac = ARGV[1]
vm_id = ARGV[2]
host = ARGV[3]
xml = STDIN.read
client = LXDClient.new
container = Container.get(vm_name, xml, client)
container.detach_nic(mac)

View File

@ -0,0 +1,46 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
################################################################################
# VNC Options
################################################################################
#
# Options to customize the VNC access to the container:
# - :command: to be executed in the VNC terminal.
# - :width: of the terminal
# - :height: of the terminal
# - :timeout: seconds to close the terminal if no input has been received
:vnc:
:command: /bin/bash
:width: 800
:height: 600
:timeout: 300
################################################################################
# OpenNebula Configuration Options
################################################################################
#
# Default path for the datastores. This only need to be change if the
# corresponding value in oned.conf has been modified.
:datastore_location: /var/lib/one/datastores
################################################################################
# LXD Options
################################################################################
#
# Path to containers location to mount the root file systems
:containers: /var/lib/lxd/storage-pools/default/containers

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -0,0 +1 @@
../common/not_supported.sh

275
src/vmm_mad/remotes/lxd/poll Executable file
View File

@ -0,0 +1,275 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require 'client'
require_relative '../lib/poll_common'
require 'base64'
################################################################################
#
# LXD Monitor Module
#
################################################################################
module LXD
CLIENT = LXDClient.new
class << self
# Get the information of a single VM. In case of error the VM is reported
# as not found.
# @param one_vm [String] with the VM name
def get_vm_info(one_vm)
vm = Container.get(one_vm, nil, CLIENT)
return { :state => '-' } unless vm
vm_info = get_values([vm]).first.last
vm_info
end
# Gets the information of all VMs
#
# @return [Hash, nil] Hash with the VM information or nil in case of error
def get_all_vm_info
vms = Container.get_all(CLIENT)
return unless vms
vms_info = get_values(vms)
vms_info
end
def get_values(vms)
vms_info = {}
running_containers = []
vms.each do |container|
values = {}
name = container.name
values[:state] = get_state(container)
unless name =~ /^one-\d+/ # Wild VMs
template = to_one(container)
values[:template] = Base64.encode64(template).delete("\n")
values[:vm_name] = name
end
vms_info[name] = values
next unless values[:state] == 'a'
vmd = container.monitor['metadata']
values[:memory] = get_memory(name)
values[:netrx], values[:nettx] = get_net_statistics(vmd['network'])
running_containers.append(name)
vms_info[name][:memory] = values[:memory]
end
unless running_containers.empty?
cpu = get_cpu(running_containers)
vms.each do |container|
vms_info[container.name][:cpu] = cpu[container.name] if cpu[container.name]
end
end
vms_info
end
# Get and translate LXD state to Opennebula monitor state
# @param state [String] libvirt state
# @return [String] OpenNebula state
#
# LXD states for the guest are
# * 'running' state refers to containers which are currently active.
# * 'frozen' after lxc freeze (suspended).
# * 'stopped' container not running or in the process of shutting down.
# * 'failure' container have failed.
def get_state(container)
begin
status = container.status.downcase
rescue StandardError
status = 'unknown'
end
case status
when 'running'
state = 'a'
when 'frozen'
state = 'p'
when 'stopped'
state = 'd'
when 'failure'
state = 'e'
else
state = '-'
end
state
end
def get_memory(vm_name)
stat = File.read('/sys/fs/cgroup/memory/lxc/' + vm_name + '/memory.usage_in_bytes').to_i
stat / 1024
end
def get_net_statistics(vmd)
netrx = 0
nettx = 0
vmd.each do |interface, values|
next if interface == 'lo'
netrx += values['counters']['bytes_received']
nettx += values['counters']['bytes_sent']
end
[netrx, nettx]
end
# Gathers process information from a set of VMs.
# @param vm_names [Array] of vms indexed by name. Value is a hash with :pid
# @return [Hash] with ps information
def get_cpu(vm_names)
multiplier = `nproc`.to_i * 100
start_cpu_jiffies = get_cpu_jiffies
cpu_used = {}
vm_names.each do |vm_name|
cpu_used[vm_name] = get_process_jiffies(vm_name).to_f
end
sleep 1
cpu_jiffies = get_cpu_jiffies - start_cpu_jiffies
vm_names.each do |vm_name|
cpu_used[vm_name] = (get_process_jiffies(vm_name).to_f -
cpu_used[vm_name]) / cpu_jiffies
cpu_used[vm_name] = (cpu_used[vm_name] * multiplier).round(2)
end
cpu_used
end
def get_cpu_jiffies
begin
stat = File.read('/proc/stat')
rescue StandardError
return 0
end
jiffies = 0
# skip cpu string and guest jiffies
stat.lines.first.split(' ')[1..-3].each do |num|
jiffies += num.to_i
end
jiffies
end
def get_process_jiffies(vm_name)
begin
jiffies = 0
stat = File.read('/sys/fs/cgroup/cpu,cpuacct/lxc/' + vm_name + '/cpuacct.stat')
stat.lines.each {|line| jiffies += line.split(' ')[1] }
rescue StandardError
return 0
end
jiffies
end
def parse_memory(memory)
mem_suffix = memory[-2..-1]
memory = memory[0..-3].to_i # remove sufix
case mem_suffix[-2..-1]
when 'GB'
memory *= 1024
when 'TB'
memory *= 1024**2
end
memory
end
def to_one(container)
name = container.name
arch = container.architecture
capacity = container.expanded_config
cpu = ""
vcpu= ""
mem = ""
if capacity
cpu = capacity['limits.cpu.allowance']
vcpu = capacity['limits.cpu']
mem = capacity['limits.memory']
end
cpu = "50%" if !cpu || cpu.empty?
vcpu = "1" if !vcpu || vcpu.empty?
mem = "512M" if !mem || mem.empty?
cpu = cpu.chomp('%').to_f / 100
mem = parse_memory(mem)
template = <<EOT
NAME="#{name}"
CPU=#{cpu}
VCPU=#{vcpu}
MEMORY=#{mem}
HYPERVISOR="lxd"
IMPORT_VM_ID="#{name}"
OS=[ARCH="#{arch}"]
EOT
template
end
end
end
################################################################################
# MAIN PROGRAM
################################################################################
hypervisor = LXD
# file = '../../etc/vmm/kvm/kvmrc'
# load_vars(hypervisor)
vm_id = ARGV[0]
if vm_id == '-t'
print_all_vm_template(hypervisor)
elsif vm_id
print_one_vm_info(hypervisor, vm_id)
else
print_all_vm_info(hypervisor)
end

View File

@ -0,0 +1,39 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
vm_id = ARGV[2]
xml = STDIN.read
# ------------------------------------------------------------------------------
# Setup Context for the container
# ------------------------------------------------------------------------------
client = LXDClient.new
container = Container.get(vm_name, xml, client)
container.detach_context

42
src/vmm_mad/remotes/lxd/reboot Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
client = LXDClient.new
container = Container.get(vm_name, nil, client)
# ------------------------------------------------------------------------------
# Stop the container, start it and reset VNC server
# ------------------------------------------------------------------------------
if ARGV[-1] == '-f'
container.stop(:force => true)
else
container.stop
end
container.start

View File

@ -0,0 +1,43 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
iso_path = ARGV[2]
vm_id = ARGV[3]
xml = STDIN.read
# ------------------------------------------------------------------------------
# Setup Context for the container
# ------------------------------------------------------------------------------
if iso_path != ''
client = LXDClient.new
container = Container.get(vm_name, xml, client)
container.attach_context
container.exec('one-contextd local 2>/dev/null')
end

19
src/vmm_mad/remotes/lxd/reset Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$(dirname $0)/reboot $1 '-f'

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -0,0 +1,57 @@
#!/usr/bin/ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
# #
# 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. #
#--------------------------------------------------------------------------- #
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'container'
require_relative '../../scripts_common'
# ------------------------------------------------------------------------------
# Action Arguments, STDIN includes XML description of the OpenNebula VM
# ------------------------------------------------------------------------------
vm_name = ARGV[0]
vm_id = ARGV[2]
xml = STDIN.read
client = LXDClient.new
container = Container.get(vm_name, xml, client)
# ------------------------------------------------------------------------------
# Stop the container & unmap devices if not a wild container
# ------------------------------------------------------------------------------
if ARGV[-1] == '-f'
container.stop(:force => true)
else
container.stop
end
if !container.wild?
begin
container.setup_storage('unmap')
rescue StandardError => e
container.start
raise e
end
container.delete
end
container.vnc('stop')

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -0,0 +1 @@
../common/not_supported.sh

View File

@ -16,7 +16,7 @@
module VNMMAD
module VNMNetwork
module VNMNetwork
# This Hash will be pppulated by the NicKVM and other hypervisor-nic
# specific classes.
@ -25,6 +25,7 @@ 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)
@nicClass = HYPERVISORS[hypervisor] || NicKVM
end
@ -32,6 +33,7 @@ module VNMNetwork
def new_nic
@nicClass.new
end
end
############################################################################
@ -44,7 +46,8 @@ module VNMNetwork
# 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
VNMNetwork::HYPERVISORS["kvm"] = self
VNMNetwork::HYPERVISORS['kvm'] = self
def initialize
super(nil)
@ -58,7 +61,7 @@ module VNMNetwork
deploy_id = vm['DEPLOY_ID']
end
if deploy_id and vm.vm_info[:dumpxml].nil?
if deploy_id && 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|
@ -85,7 +88,70 @@ module VNMNetwork
self
end
end
# A NIC using LXD. This class implements functions to get the physical
# interface that the NIC is using, based on the MAC address
class NicLXD < Hash
VNMNetwork::HYPERVISORS['lxd'] = self
def initialize
super(nil)
end
# Get the VM information with lxc config show
def get_info(vm)
if vm.deploy_id
deploy_id = vm.deploy_id
else
deploy_id = vm['DEPLOY_ID']
end
if deploy_id && vm.vm_info[:dumpxml].nil?
vm.vm_info[:dumpxml] = YAML.safe_load(`lxc config show #{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 config
def get_tap(vm)
dumpxml = vm.vm_info[:dumpxml]
if dumpxml
devices = dumpxml['devices']
xpath = find_path(devices, self[:mac])
end
if xpath
self[:tap] = devices[xpath]['host_name'] if devices[xpath]['host_name']
end
self
end
def find_path(hash, text)
path = '' unless path.is_a?(String)
hash.each do |k, v|
if v == text
return k
end
if v.is_a?(Hash)
path = k
tmp = find_path(v, text)
end
return path unless tmp.nil?
end
nil
end
end
end
end
end