Skip to content

Commit

Permalink
lxd/network/acl: If the OVN chassis is in MicroOVN, read the ACL logs…
Browse files Browse the repository at this point in the history
… from syslogs

If the OVN controller is deployed as part of MicroOVN, it means that the `ovn-chassis` snap connection hook
between LXD and MicroOVN has been fired and that a symlink like:

`/run/openvswitch -> /var/snap/lxd/<ID>/microovn/...`

exists. Otherwise, there might still be a symlink but not with that target prefix. That's how we detect the ovn chassis
connection without introducing a new plug / slot between LXD and MicroOVN.

Then, if this case is detected, we check the status of the systemd unit 'snap.microovn.chassis.service' (the one containing the OVN controller in its sd journal)
If it is loaded and active, we read the last 5000 ACL log entries (we can discuss on this limit) in the journal and return them.

Signed-off-by: Gabriel Mougard <[email protected]>
  • Loading branch information
gabrielmougard committed Oct 29, 2024
1 parent da04cc1 commit 843728d
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 20 deletions.
53 changes: 33 additions & 20 deletions lxd/network/acl/driver_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,32 +752,45 @@ func (d *common) Delete() error {
func (d *common) GetLog(clientType request.ClientType) (string, error) {
// ACLs aren't specific to a particular network type but the log only works with OVN.
logPath := shared.HostPath("/var/log/ovn/ovn-controller.log")
logEntries := []string{}
if !shared.PathExists(logPath) {
return "", fmt.Errorf("Only OVN log entries may be retrieved at this time")
}

// Open the log file.
logFile, err := os.Open(logPath)
if err != nil {
return "", fmt.Errorf("Couldn't open OVN log file: %w", err)
}
// Check if this is OVN builtin of if OVN is provided by a MicroOVN deployment.
targetPath, err := os.Readlink("/run/openvswitch")
if err != nil {
return "", fmt.Errorf("Failed to read symlink while checking for OVN logs: %v\n", err)
}

defer func() { _ = logFile.Close() }()
if !openvswitch.MicroovnTargetChassisPath.MatchString(targetPath) {
return "", fmt.Errorf("Only OVN log entries may be retrieved at this time")
}

logEntries := []string{}
scanner := bufio.NewScanner(logFile)
for scanner.Scan() {
logEntry := ovnParseLogEntry(scanner.Text(), fmt.Sprintf("lxd_acl%d-", d.id))
if logEntry == "" {
continue
logEntries, err = ovnParseLogEntriesFromSyslog(d.logger, "snap.microovn.chassis.service", fmt.Sprintf("lxd_acl%d-", d.id))
if err != nil {
return "", fmt.Errorf("Failed to get OVN log entries from syslog: %v\n", err)
}
} else {
// Open the log file.
logFile, err := os.Open(logPath)
if err != nil {
return "", fmt.Errorf("Couldn't open OVN log file: %w", err)
}

logEntries = append(logEntries, logEntry)
}
defer func() { _ = logFile.Close() }()

err = scanner.Err()
if err != nil {
return "", fmt.Errorf("Failed to read OVN log file: %w", err)
scanner := bufio.NewScanner(logFile)
for scanner.Scan() {
logEntry := ovnParseLogEntry(scanner.Text(), "", fmt.Sprintf("lxd_acl%d-", d.id))
if logEntry == "" {
continue
}

logEntries = append(logEntries, logEntry)
}

err = scanner.Err()
if err != nil {
return "", fmt.Errorf("Failed to read OVN log file: %w", err)
}
}

// Aggregates the entries from the rest of the cluster.
Expand Down
3 changes: 3 additions & 0 deletions lxd/network/openvswitch/shared.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package openvswitch

import (
"regexp"
"strconv"
"strings"
)

var MicroovnTargetChassisPath = regexp.MustCompile(`^/var/snap/lxd/[0-9]+/microovn/chassis/switch`)

// unquote passes s through strconv.Unquote if the first character is a ", otherwise returns s unmodified.
// This is useful as openvswitch's tools can sometimes return values double quoted if they start with a number.
func unquote(s string) (string, error) {
Expand Down

0 comments on commit 843728d

Please sign in to comment.