mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-22 18:50:08 +03:00
F #1684: Discover LXD installation paths, other minor updates
This commit is contained in:
parent
d9fb25db65
commit
48664d4c57
@ -31,14 +31,25 @@ class LXDClient
|
||||
API = '/1.0'.freeze
|
||||
HEADER = { 'Host' => 'localhost' }.freeze
|
||||
|
||||
SOCK_PATH = '/var/lib/lxd/unix.socket'
|
||||
attr_reader :lxd_path
|
||||
|
||||
# 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)
|
||||
def initialize
|
||||
paths = ['/var/lib/lxd', '/var/snap/lxd/common/lxd']
|
||||
|
||||
@socket = nil
|
||||
@lxd_path = nil
|
||||
|
||||
paths.each do |path|
|
||||
begin
|
||||
@socket = socket(path)
|
||||
@lxd_path = path
|
||||
break
|
||||
rescue
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
raise 'Failed to open LXD socket' unless @socket
|
||||
end
|
||||
|
||||
# Performs HTTP::Get
|
||||
@ -89,6 +100,11 @@ class LXDClient
|
||||
|
||||
private
|
||||
|
||||
# Enable communication with LXD via unix socket
|
||||
def socket(lxd_path)
|
||||
Net::BufferedIO.new(UNIXSocket.new("#{lxd_path}/unix.socket"))
|
||||
end
|
||||
|
||||
# Returns the HTTPResponse body as a hash
|
||||
# Params:
|
||||
# +request+:: +Net::HTTP::Request+ made to the http server
|
||||
@ -98,16 +114,16 @@ class LXDClient
|
||||
def get_response(request, data)
|
||||
request.body = JSON.dump(data) unless data.nil?
|
||||
|
||||
request.exec(SOCK, '1.1', request.path)
|
||||
request.exec(@socket, '1.1', request.path)
|
||||
|
||||
response = nil
|
||||
|
||||
loop do
|
||||
response = Net::HTTPResponse.read_new(SOCK)
|
||||
response = Net::HTTPResponse.read_new(@socket)
|
||||
break unless response.is_a?(Net::HTTPContinue)
|
||||
end
|
||||
|
||||
response.reading_body(SOCK, request.response_body_permitted?) {}
|
||||
response.reading_body(@socket, request.response_body_permitted?) {}
|
||||
|
||||
response = JSON.parse(response.body)
|
||||
|
||||
|
@ -68,53 +68,58 @@ class Container
|
||||
|
||||
@lxc = lxc
|
||||
@one = one
|
||||
|
||||
@containers = "#{@client.lxd_path}/storage-pools/default/containers"
|
||||
@rootfs_dir = "#{@containers}/#{name}/rootfs"
|
||||
|
||||
@context_path = "#{@rootfs_dir}/context"
|
||||
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']
|
||||
# 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
|
||||
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))
|
||||
Container.new(info, one, client)
|
||||
rescue LXDError => exception
|
||||
raise exception
|
||||
end
|
||||
|
||||
containers
|
||||
end
|
||||
# Creates container from a OpenNebula VM xml description
|
||||
def new_from_xml(one_xml, client)
|
||||
one = OpenNebulaVM.new(one_xml)
|
||||
|
||||
# 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
|
||||
Container.new(one.to_lxc, one, client)
|
||||
end
|
||||
|
||||
false
|
||||
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
|
||||
|
||||
@ -131,6 +136,10 @@ class Container
|
||||
|
||||
# Delete container
|
||||
def delete(wait: true, timeout: '')
|
||||
unless Dir.empty?(@rootfs_dir) || (Dir["#{@rootfs_dir}/*"] == [@context_path] && Dir.empty?(@context_path))
|
||||
raise 'Container rootfs not empty'
|
||||
end
|
||||
|
||||
wait?(@client.delete("#{CONTAINERS}/#{name}"), wait, timeout)
|
||||
end
|
||||
|
||||
@ -222,8 +231,7 @@ class Container
|
||||
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}"
|
||||
create_context_dir = "#{Mapper::COMMANDS[:su_mkdir]} #{@context_path}"
|
||||
|
||||
rc, _o, e = Command.execute(create_context_dir, false)
|
||||
|
||||
@ -330,7 +338,7 @@ class Container
|
||||
disk_id = disk['DISK_ID']
|
||||
|
||||
if disk_id == @one.rootfs_id
|
||||
target = "#{@one.lxdrc[:containers]}/#{name}/rootfs"
|
||||
target = @rootfs_dir
|
||||
else
|
||||
target = @one.disk_mountpoint(disk_id)
|
||||
end
|
||||
|
@ -190,19 +190,19 @@ class Mapper
|
||||
device = ''
|
||||
real_path = directory
|
||||
|
||||
ds = one_vm.lxdrc[:datastore_location] + "/#{one_vm.sysds_id}"
|
||||
ds = one_vm.sysds_path
|
||||
if File.symlink?(ds)
|
||||
real_ds = File.readlink(ds)
|
||||
real_path = real_ds + directory.split(ds)[-1] if directory.include?(ds)
|
||||
end
|
||||
|
||||
|
||||
sys_parts.each { |d|
|
||||
if d['mountpoint'] == real_path
|
||||
partitions = [d]
|
||||
device = d['path']
|
||||
break
|
||||
end
|
||||
|
||||
|
||||
d['children'].each { |c|
|
||||
if c['mountpoint'] == real_path
|
||||
partitions = d['children']
|
||||
@ -213,13 +213,18 @@ class Mapper
|
||||
|
||||
break if !partitions.empty?
|
||||
}
|
||||
|
||||
|
||||
partitions.delete_if { |p| !p['mountpoint'] }
|
||||
|
||||
partitions.sort! { |a,b|
|
||||
b['mountpoint'].length <=> a['mountpoint'].length
|
||||
}
|
||||
|
||||
if device.empty?
|
||||
OpenNebula.log_error("Failed to detect block device from #{directory}")
|
||||
return
|
||||
end
|
||||
|
||||
return unless umount(partitions)
|
||||
|
||||
return unless do_unmap(device, one_vm, disk, real_path)
|
||||
@ -330,6 +335,18 @@ class Mapper
|
||||
def mount_dev(dev, path)
|
||||
OpenNebula.log_info "Mounting #{dev} at #{path}"
|
||||
|
||||
rc, out, err = Command.execute("#{COMMANDS[:lsblk]} -J", false)
|
||||
|
||||
if rc != 0 || out.empty?
|
||||
OpenNebula.log_error("mount_dev: #{err}")
|
||||
return false
|
||||
end
|
||||
|
||||
if out.match?(path)
|
||||
OpenNebula.log_error("mount_dev: Mount detected in #{path}")
|
||||
return false
|
||||
end
|
||||
|
||||
if path =~ /.*\/rootfs/
|
||||
cmd = COMMANDS[:su_mkdir]
|
||||
else
|
||||
|
@ -33,8 +33,7 @@ class Qcow2Mapper < Mapper
|
||||
dsrc = disk_source(one_vm, disk)
|
||||
cmd = "#{COMMANDS[:nbd]} -c #{device} #{dsrc}"
|
||||
|
||||
ds = one_vm.lxdrc[:datastore_location] + "/#{one_vm.sysds_id}"
|
||||
File.chmod(0664, dsrc) if File.symlink?(ds)
|
||||
File.chmod(0664, dsrc) if File.symlink?(one_vm.sysds_path)
|
||||
|
||||
rc, _out, err = Command.execute(cmd, true)
|
||||
|
||||
|
@ -25,9 +25,7 @@ class LXDConfiguration < Hash
|
||||
:width => '800',
|
||||
:height => '600',
|
||||
:timeout => '300'
|
||||
},
|
||||
:datastore_location => '/var/lib/one/datastores',
|
||||
:containers => '/var/lib/lxd/storage-pools/default/containers'
|
||||
}
|
||||
}
|
||||
|
||||
def initialize
|
||||
@ -44,7 +42,7 @@ 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
|
||||
attr_reader :xml, :vm_id, :vm_name, :sysds_id, :ds_path, :rootfs_id, :lxdrc, :sysds_path
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Class Constructor
|
||||
@ -64,13 +62,14 @@ class OpenNebulaVM
|
||||
# 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
|
||||
|
||||
@ds_path = get_dspath(disk)
|
||||
@sysds_path = "#{@ds_path}/#{@sysds_id}"
|
||||
|
||||
@rootfs_id = disk['DISK_ID']
|
||||
boot_order = @xml['//TEMPLATE/OS/BOOT']
|
||||
@rootfs_id = boot_order.split(',')[0][-1] unless boot_order.empty?
|
||||
@ -373,6 +372,25 @@ class OpenNebulaVM
|
||||
mapped
|
||||
end
|
||||
|
||||
# Returns the datastores BASE_PATH location
|
||||
def get_dspath(disk)
|
||||
source = disk['SOURCE']
|
||||
cut = "/#{disk['DATASTORE_ID']}/"
|
||||
result = source.split(cut)
|
||||
|
||||
if result.length == 2
|
||||
path = result[0]
|
||||
else
|
||||
path = ''
|
||||
0.upto(result.length - 2) do |i|
|
||||
path << "#{result[i]}/#{dsid}/"
|
||||
end
|
||||
|
||||
path = path[0..path.rindex(cut)]
|
||||
end
|
||||
|
||||
path.gsub('//', '/')
|
||||
end
|
||||
end
|
||||
|
||||
# This class abstracts the access to XML elements. It provides basic methods
|
||||
|
@ -27,20 +27,4 @@
|
||||
: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
|
||||
:timeout: 300
|
Loading…
x
Reference in New Issue
Block a user