Move libvirt connect func to libvirt package

Signed-off-by: Darko Draskovic <darko.draskovic@gmail.com>
This commit is contained in:
Darko Draskovic
2023-09-07 13:17:27 +02:00
parent 4354f0574c
commit 83270dc9bc
6 changed files with 119 additions and 92 deletions
+26 -8
View File
@@ -34,19 +34,19 @@ Create `img` directory in `cmd/manager`. Create `tmp` directory in `cmd/manager`
First, we will download *focal-server-cloudimg-amd64*. It is a `qcow2` file with Ubuntu server preinstalled, ready to use with the QEMU virtual machine.
```sh
FOCAL=focal-server-cloudimg-amd64.img
cd cmd/manager
# Use this dir for focal-server-cloudimg-amd64.img and a test copy of firmware vars file.
mkdir img
# Use this dir for temporary firmware vars file and temporary disk image per virtual machine.
mkdir tmp
FOCAL=focal-server-cloudimg-amd64.img
wget -O img/$FOCAL https://cloud-images.ubuntu.com/focal/current/$FOCAL
# focal-server-cloudimg-amd64 comes without the root password
sudo apt-get install libguestfs-tools
PASSWORD=coolpass
sudo virt-customize -a img/$FOCAL --root-password password:$PASSWORD
# Use this dir for temporary firmware vars file and temporary disk image per virtual machine.
mkdir tmp
```
#### Resize disk image, partition and filesystem
We need to resize the disk image:
@@ -59,7 +59,16 @@ To resize `ext4` partition and filesystem on the `qcow2` disk image, start the v
```sh
cd cmd/manager
cp /usr/share/OVMF/OVMF_VARS.fd img/
sudo find / -name OVMF_CODE.fd
# => /usr/share/OVMF/OVMF_CODE.fd
export MANAGER_QEMU_OVMF_CODE_FILE=/usr/share/OVMF/OVMF_CODE.fd
sudo find / -name OVMF_VARS.fd
# => /usr/share/OVMF/OVMF_VARS.fd
export MANAGER_QEMU_OVMF_VARS_FILE=/usr/share/OVMF/OVMF_VARS.fd
# Exported env vars are visible in subshell: start_VM.sh relies on MANAGER_QEMU_OVMF_CODE_FILE and MANAGER_QEMU_OVMF_VARS_FILE
./start_VM.sh
```
@@ -75,6 +84,12 @@ An example (for focal) of this output is:
```
So, the partition that holds the root file system is `/dev/sda1`.
Check the current size of the partition:
```sh
df -h
# Output: /dev/sda1 2.0G 1.5G 520M 74% /
```
Run the `parted` command to increase the `ext4` partition size. We will resize the `/dev/sda` because this is the QEMU hard disk containing the `/dev/sda1` partition and the newly added free space.
```sh
parted /dev/sda
@@ -90,7 +105,6 @@ fix the GPT to use all of the space (an extra 16777216 blocks) or continue with
the current setting?
Fix/Ignore?
```
Type `fix` here to use all of the available space.
An example of the output of the `print free` command should be something like this:
@@ -130,6 +144,11 @@ The last step is to resize the filesystem of the root file system partition. To
```sh
resize2fs /dev/sda1
```
Check the new size of the partition:
```sh
df -h
# Output: /dev/sda1 3.0G 1.5G 1.5G 50% /
```
#### Set up the network interface
@@ -315,7 +334,6 @@ cp build/agent /cocos/agent
# Copy the 'cocos-agent.service' systemd unit file to the '/etc/systemd/system/' directory.
cp systemd/cocos-agent.service /etc/systemd/system/
```
Now we are ready to set up `agent` executable as a systemd daemon service:
```sh
+3 -46
View File
@@ -11,12 +11,9 @@ import (
"context"
"fmt"
"log"
"net"
"os"
"strings"
"time"
"github.com/digitalocean/go-libvirt"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/uuid"
"github.com/ultravioletrs/agent/agent"
@@ -87,13 +84,6 @@ func main() {
}()
tracer := tp.Tracer(svcName)
libvirtConn := initLibvirt(logger)
defer func() {
if err := libvirtConn.Disconnect(); err != nil {
logger.Error(fmt.Sprintf("Error disconnecting from libvirt: %s", err))
}
}()
agentGRPCConfig := agentgrpc.Config{}
if err := env.Parse(&agentGRPCConfig, env.Options{Prefix: envPrefixAgentGRPC}); err != nil {
logger.Fatal(fmt.Sprintf("failed to load %s gRPC client configuration: %s", svcName, err))
@@ -116,7 +106,7 @@ func main() {
}
logger.Info(fmt.Sprintf("%s %s", exe, strings.Join(args, " ")))
svc := newService(libvirtConn, agentClient, logger, tracer, qemuCfg)
svc := newService(agentClient, logger, tracer, qemuCfg)
var httpServerConfig = server.Config{Port: defSvcHTTPPort}
if err := env.Parse(&httpServerConfig, env.Options{Prefix: envPrefixHTTP}); err != nil {
@@ -156,8 +146,8 @@ func main() {
}
}
func newService(libvirtConn *libvirt.Libvirt, agent agent.AgentServiceClient, logger logger.Logger, tracer trace.Tracer, qemuCfg qemu.Config) manager.Service {
svc := manager.New(libvirtConn, agent, qemuCfg)
func newService(agent agent.AgentServiceClient, logger logger.Logger, tracer trace.Tracer, qemuCfg qemu.Config) manager.Service {
svc := manager.New(agent, qemuCfg)
svc = api.LoggingMiddleware(svc, logger)
counter, latency := internal.MakeMetrics(svcName, "api")
@@ -166,36 +156,3 @@ func newService(libvirtConn *libvirt.Libvirt, agent agent.AgentServiceClient, lo
return svc
}
func initLibvirt(logger logger.Logger) *libvirt.Libvirt {
// This dials libvirt on the local machine, but you can substitute the first
// two parameters with "tcp", "<ip address>:<port>" to connect to libvirt on
// a remote machine.
c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
if err != nil {
log.Fatalf("failed to dial libvirt: %v", err)
}
l := libvirt.New(c)
if err := l.Connect(); err != nil {
log.Fatalf("failed to connect: %v", err)
}
v, err := l.Version()
if err != nil {
logger.Error(fmt.Sprintf("failed to retrieve libvirt version: %v", err))
}
fmt.Println("Version:", v)
domains, err := l.Domains()
if err != nil {
logger.Error(fmt.Sprintf("failed to retrieve domains: %v", err))
}
fmt.Println("ID\tName\t\tUUID")
fmt.Printf("--------------------------------------------------------\n")
for _, d := range domains {
fmt.Printf("%d\t%s\t%x\n", d.ID, d.Name, d.UUID)
}
return l
}
+12 -1
View File
@@ -3,8 +3,19 @@
echo "Mapping CTRL-C to CTRL-]"
stty intr ^]
#!/bin/bash
# Check if the destination file exists
if [ ! -f "img/OVMF_VARS.fd" ]; then
# Copy $MANAGER_QEMU_OVMF_VARS_FILE to the destination
cp "$MANAGER_QEMU_OVMF_VARS_FILE" "img/OVMF_VARS.fd"
echo "Copied $MANAGER_QEMU_OVMF_VARS_FILE to img/OVMF_VARS.fd"
else
echo "img/OVMF_VARS.fd already exists. No need to copy."
fi
echo "Launching VM ..."
/usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 2048M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty
/usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 2048M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=$MANAGER_QEMU_OVMF_CODE_FILE,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty
# restore the mapping
stty intr ^c
+44
View File
@@ -0,0 +1,44 @@
package libvirt
import (
"fmt"
"log"
"net"
"time"
libvirt "github.com/digitalocean/go-libvirt"
"github.com/mainflux/mainflux/logger"
)
func Connect(logger logger.Logger) *libvirt.Libvirt {
// This dials libvirt on the local machine, but you can substitute the first
// two parameters with "tcp", "<ip address>:<port>" to connect to libvirt on
// a remote machine.
c, err := net.DialTimeout("unix", "/var/run/libvirt/libvirt-sock", 2*time.Second)
if err != nil {
log.Fatalf("failed to dial libvirt: %v", err)
}
l := libvirt.New(c)
if err := l.Connect(); err != nil {
log.Fatalf("failed to connect: %v", err)
}
v, err := l.Version()
if err != nil {
logger.Error(fmt.Sprintf("failed to retrieve libvirt version: %v", err))
}
fmt.Println("Version:", v)
domains, err := l.Domains()
if err != nil {
logger.Error(fmt.Sprintf("failed to retrieve domains: %v", err))
}
fmt.Println("ID\tName\t\tUUID")
fmt.Printf("--------------------------------------------------------\n")
for _, d := range domains {
fmt.Printf("%d\t%s\t%x\n", d.ID, d.Name, d.UUID)
}
return l
}
+33 -33
View File
@@ -13,13 +13,36 @@ import (
var re = regexp.MustCompile(`'([^']*)'`)
func entityName(msg string) (string, error) {
match := re.FindStringSubmatch(msg)
if len(match) < 1 {
return "", errors.New("entity not found")
func CreateDomain(ctx context.Context, libvirt *libvirt.Libvirt, poolXML, volXML, domXML string) (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}
return match[1], nil
poolStr, err := readXMLFile(poolXML, "pool.xml")
if err != nil {
return "", err
}
poolStr = replaceSubstring(poolStr, "./", wd+"/")
volStr, err := readXMLFile(volXML, "vol.xml")
if err != nil {
return "", err
}
volStr = replaceSubstring(volStr, "./", wd+"/")
domStr, err := readXMLFile(domXML, "dom.xml")
if err != nil {
return "", err
}
domStr = replaceSubstring(domStr, "./", wd+"/")
dom, err := createDomain(libvirt, poolStr, volStr, domStr)
if err != nil {
return "", fmt.Errorf("failed to create domain: %s", err)
}
return dom.Name, nil
}
func createDomain(libvirtConn *libvirt.Libvirt, poolXML string, volXML string, domXML string) (libvirt.Domain, error) {
@@ -101,36 +124,13 @@ vol_exists:
return dom, nil
}
func CreateDomain(ctx context.Context, libvirt *libvirt.Libvirt, poolXML, volXML, domXML string) (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
func entityName(msg string) (string, error) {
match := re.FindStringSubmatch(msg)
if len(match) < 1 {
return "", errors.New("entity not found")
}
poolStr, err := readXMLFile(poolXML, "pool.xml")
if err != nil {
return "", err
}
poolStr = replaceSubstring(poolStr, "./", wd+"/")
volStr, err := readXMLFile(volXML, "vol.xml")
if err != nil {
return "", err
}
volStr = replaceSubstring(volStr, "./", wd+"/")
domStr, err := readXMLFile(domXML, "dom.xml")
if err != nil {
return "", err
}
domStr = replaceSubstring(domStr, "./", wd+"/")
dom, err := createDomain(libvirt, poolStr, volStr, domStr)
if err != nil {
return "", fmt.Errorf("failed to create domain: %s", err)
}
return dom.Name, nil
return match[1], nil
}
func readXMLFile(filename string, defaultFilename string) (string, error) {
+1 -4
View File
@@ -8,7 +8,6 @@ import (
"errors"
"time"
"github.com/digitalocean/go-libvirt"
"github.com/ultravioletrs/agent/agent"
"github.com/ultravioletrs/manager/manager/qemu"
)
@@ -35,7 +34,6 @@ type Service interface {
}
type managerService struct {
libvirt *libvirt.Libvirt
agent agent.AgentServiceClient
qemuCfg qemu.Config
}
@@ -43,9 +41,8 @@ type managerService struct {
var _ Service = (*managerService)(nil)
// New instantiates the manager service implementation.
func New(libvirtConn *libvirt.Libvirt, agent agent.AgentServiceClient, qemuCfg qemu.Config) Service {
func New(agent agent.AgentServiceClient, qemuCfg qemu.Config) Service {
return &managerService{
libvirt: libvirtConn,
agent: agent,
qemuCfg: qemuCfg,
}