Log the origin VM specification for better troubleshooting (#73)

When importing a VM from VMware or OpenStack, there is no log output of the origin VM spec that is going to be imported. In some situations this information would be helpful for troubleshooting and to understand what is going wrong.

For better processing of the amount of data the specification should be printed as JSON to be able to prettify it externally and to inspect it easily.

Related to: https://github.com/harvester/harvester/issues/8013

Signed-off-by: Volker Theile <vtheile@suse.com>
This commit is contained in:
Volker Theile 2025-04-29 13:24:30 +02:00 committed by GitHub
parent f5a94173e8
commit 6956a12edf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 85 additions and 0 deletions

View File

@ -31,6 +31,7 @@ import (
migration "github.com/harvester/vm-import-controller/pkg/apis/migration.harvesterhci.io/v1beta1"
"github.com/harvester/vm-import-controller/pkg/server"
"github.com/harvester/vm-import-controller/pkg/util"
)
const (
@ -416,6 +417,14 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku
return nil, fmt.Errorf("error finding VM in GenerateVirtualMachine: %v", err)
}
// Log the origin VM specification for better troubleshooting.
// Note, JSON is used to be able to prettify the output for better readability.
logrus.WithFields(util.FieldsToJSON(logrus.Fields{
"name": vm.Name,
"namespace": vm.Namespace,
"spec": vmObj,
}, []string{"spec"})).Info("Origin spec of the VM to be imported")
flavorObj, err := flavors.Get(c.ctx, c.computeClient, vmObj.Flavor["id"].(string)).Extract()
if err != nil {
return nil, fmt.Errorf("error looking up flavor: %v", err)

View File

@ -26,6 +26,7 @@ import (
migration "github.com/harvester/vm-import-controller/pkg/apis/migration.harvesterhci.io/v1beta1"
"github.com/harvester/vm-import-controller/pkg/qemu"
"github.com/harvester/vm-import-controller/pkg/server"
"github.com/harvester/vm-import-controller/pkg/util"
)
type Client struct {
@ -315,6 +316,14 @@ func (c *Client) GenerateVirtualMachine(vm *migration.VirtualMachineImport) (*ku
return nil, err
}
// Log the origin VM specification for better troubleshooting.
// Note, JSON is used to be able to prettify the output for better readability.
logrus.WithFields(util.FieldsToJSON(logrus.Fields{
"name": vm.Name,
"namespace": vm.Namespace,
"spec": o,
}, []string{"spec"})).Info("Origin spec of the VM to be imported")
// Need CPU, Socket, Memory, VirtualNIC information to perform the mapping
networkInfo := identifyNetworkCards(o.Config.Hardware.Device)

26
pkg/util/logrus.go Normal file
View File

@ -0,0 +1,26 @@
package util
import (
"encoding/json"
"github.com/sirupsen/logrus"
)
// FieldsToJSON is a helper function to convert specified fields in a logrus.Fields map to JSON strings.
func FieldsToJSON(fields logrus.Fields, keys []string) logrus.Fields {
for _, k := range keys {
v, ok := fields[k]
if ok {
vBytes, err := json.Marshal(v)
if err != nil {
logrus.WithFields(logrus.Fields{
"key": k,
"value": v,
}).Errorf("Failed to marshall field: %v", err)
} else {
fields[k] = string(vBytes)
}
}
}
return fields
}

41
pkg/util/logrus_test.go Normal file
View File

@ -0,0 +1,41 @@
package util
import (
"testing"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
)
func TestLogJSON_success(t *testing.T) {
type myStruct struct {
ID int `json:"id"`
Name string `json:"name"`
}
assert := require.New(t)
fields := logrus.Fields{
"key1": "value1",
"key2": myStruct{ID: 1, Name: "foo"},
"key3": 4815162342,
}
FieldsToJSON(fields, []string{"key2"})
assert.Equal(fields["key1"], "value1", "expected value not to modified")
assert.JSONEq(fields["key2"].(string), `{"id":1,"name":"foo"}`, "expected value to be marshalled to JSON")
assert.Equal(fields["key3"], 4815162342, "expected value not to modified")
}
func TestLogJSON_fail(t *testing.T) {
type myStruct struct {
Name string
Secret chan int
}
assert := require.New(t)
fields := logrus.Fields{
"key1": myStruct{Name: "John", Secret: make(chan int)}, // this will fail to marshal
"key2": "value2",
}
FieldsToJSON(fields, []string{"key1"})
assert.IsType(fields["key1"], myStruct{}, "expected value not to marshalled to JSON")
}