mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-01 09:42:45 +00:00
Merge pull request #1889 from WeiZhang555/persist-data
persist: manage "hypervisor.json" with new store
This commit is contained in:
commit
6ce5f30d6c
@ -17,6 +17,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/store"
|
"github.com/kata-containers/runtime/virtcontainers/store"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/utils"
|
"github.com/kata-containers/runtime/virtcontainers/utils"
|
||||||
@ -230,7 +231,18 @@ func (a *acrn) setup(id string, hypervisorConfig *HypervisorConfig, vcStore *sto
|
|||||||
a.store = vcStore
|
a.store = vcStore
|
||||||
a.config = *hypervisorConfig
|
a.config = *hypervisorConfig
|
||||||
a.arch = newAcrnArch(a.config)
|
a.arch = newAcrnArch(a.config)
|
||||||
if err = a.store.Load(store.Hypervisor, &a.state); err != nil {
|
|
||||||
|
var create bool
|
||||||
|
|
||||||
|
if a.store != nil { //use old store
|
||||||
|
if err = a.store.Load(store.Hypervisor, &a.info); err != nil {
|
||||||
|
create = true
|
||||||
|
}
|
||||||
|
} else if a.info.PID == 0 { // new store
|
||||||
|
create = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if create {
|
||||||
// acrn currently supports only known UUIDs for security
|
// acrn currently supports only known UUIDs for security
|
||||||
// reasons (FuSa). When launching VM, only these pre-defined
|
// reasons (FuSa). When launching VM, only these pre-defined
|
||||||
// UUID should be used else VM launch will fail. acrn team is
|
// UUID should be used else VM launch will fail. acrn team is
|
||||||
@ -246,15 +258,11 @@ func (a *acrn) setup(id string, hypervisorConfig *HypervisorConfig, vcStore *sto
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.store.Store(store.Hypervisor, a.state); err != nil {
|
if err = a.storeInfo(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = a.store.Load(store.Hypervisor, &a.info); err != nil {
|
|
||||||
a.Logger().WithField("function", "setup").WithError(err).Info("No info could be fetched")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,3 +627,24 @@ func (a *acrn) fromGrpc(ctx context.Context, hypervisorConfig *HypervisorConfig,
|
|||||||
func (a *acrn) toGrpc() ([]byte, error) {
|
func (a *acrn) toGrpc() ([]byte, error) {
|
||||||
return nil, errors.New("acrn is not supported by VM cache")
|
return nil, errors.New("acrn is not supported by VM cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *acrn) storeInfo() error {
|
||||||
|
if a.store != nil {
|
||||||
|
if err := a.store.Store(store.Hypervisor, a.info); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *acrn) save() (s persistapi.HypervisorState) {
|
||||||
|
s.Pid = a.pid()
|
||||||
|
s.Type = string(AcrnHypervisor)
|
||||||
|
s.UUID = a.state.UUID
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *acrn) load(s persistapi.HypervisorState) {
|
||||||
|
a.info.PID = s.Pid
|
||||||
|
a.state.UUID = s.UUID
|
||||||
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kata-containers/agent/protocols/grpc"
|
"github.com/kata-containers/agent/protocols/grpc"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
|
vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
@ -255,4 +256,10 @@ type agent interface {
|
|||||||
|
|
||||||
// cleanup removes all on disk information generated by the agent
|
// cleanup removes all on disk information generated by the agent
|
||||||
cleanup(s *Sandbox)
|
cleanup(s *Sandbox)
|
||||||
|
|
||||||
|
// return data for saving
|
||||||
|
save() persistapi.AgentState
|
||||||
|
|
||||||
|
// load data from disk
|
||||||
|
load(persistapi.AgentState)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BridgedMacvlanEndpoint represents a macvlan endpoint that is bridged to the VM
|
// BridgedMacvlanEndpoint represents a macvlan endpoint that is bridged to the VM
|
||||||
@ -115,3 +116,23 @@ func (endpoint *BridgedMacvlanEndpoint) HotAttach(h hypervisor) error {
|
|||||||
func (endpoint *BridgedMacvlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
|
func (endpoint *BridgedMacvlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
|
||||||
return fmt.Errorf("BridgedMacvlanEndpoint does not support Hot detach")
|
return fmt.Errorf("BridgedMacvlanEndpoint does not support Hot detach")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *BridgedMacvlanEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
netpair := saveNetIfPair(&endpoint.NetPair)
|
||||||
|
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
BridgedMacvlan: &persistapi.BridgedMacvlanEndpoint{
|
||||||
|
NetPair: *netpair,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (endpoint *BridgedMacvlanEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = BridgedMacvlanEndpointType
|
||||||
|
|
||||||
|
if s.BridgedMacvlan != nil {
|
||||||
|
netpair := loadNetIfPair(&s.BridgedMacvlan.NetPair)
|
||||||
|
endpoint.NetPair = *netpair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,8 @@ package virtcontainers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Endpoint represents a physical or virtual network interface.
|
// Endpoint represents a physical or virtual network interface.
|
||||||
@ -24,6 +26,9 @@ type Endpoint interface {
|
|||||||
Detach(netNsCreated bool, netNsPath string) error
|
Detach(netNsCreated bool, netNsPath string) error
|
||||||
HotAttach(h hypervisor) error
|
HotAttach(h hypervisor) error
|
||||||
HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error
|
HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error
|
||||||
|
|
||||||
|
save() persistapi.NetworkEndpoint
|
||||||
|
load(persistapi.NetworkEndpoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointType identifies the type of the network endpoint.
|
// EndpointType identifies the type of the network endpoint.
|
||||||
@ -102,3 +107,79 @@ func (endpointType *EndpointType) String() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func saveTapIf(tapif *TapInterface) *persistapi.TapInterface {
|
||||||
|
if tapif == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &persistapi.TapInterface{
|
||||||
|
ID: tapif.ID,
|
||||||
|
Name: tapif.Name,
|
||||||
|
TAPIface: persistapi.NetworkInterface{
|
||||||
|
Name: tapif.TAPIface.Name,
|
||||||
|
HardAddr: tapif.TAPIface.HardAddr,
|
||||||
|
Addrs: tapif.TAPIface.Addrs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadTapIf(tapif *persistapi.TapInterface) *TapInterface {
|
||||||
|
if tapif == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TapInterface{
|
||||||
|
ID: tapif.ID,
|
||||||
|
Name: tapif.Name,
|
||||||
|
TAPIface: NetworkInterface{
|
||||||
|
Name: tapif.TAPIface.Name,
|
||||||
|
HardAddr: tapif.TAPIface.HardAddr,
|
||||||
|
Addrs: tapif.TAPIface.Addrs,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveNetIfPair(pair *NetworkInterfacePair) *persistapi.NetworkInterfacePair {
|
||||||
|
if pair == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
epVirtIf := pair.VirtIface
|
||||||
|
|
||||||
|
tapif := saveTapIf(&pair.TapInterface)
|
||||||
|
|
||||||
|
virtif := persistapi.NetworkInterface{
|
||||||
|
Name: epVirtIf.Name,
|
||||||
|
HardAddr: epVirtIf.HardAddr,
|
||||||
|
Addrs: epVirtIf.Addrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &persistapi.NetworkInterfacePair{
|
||||||
|
TapInterface: *tapif,
|
||||||
|
VirtIface: virtif,
|
||||||
|
NetInterworkingModel: int(pair.NetInterworkingModel),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNetIfPair(pair *persistapi.NetworkInterfacePair) *NetworkInterfacePair {
|
||||||
|
if pair == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
savedVirtIf := pair.VirtIface
|
||||||
|
|
||||||
|
tapif := loadTapIf(&pair.TapInterface)
|
||||||
|
|
||||||
|
virtif := NetworkInterface{
|
||||||
|
Name: savedVirtIf.Name,
|
||||||
|
HardAddr: savedVirtIf.HardAddr,
|
||||||
|
Addrs: savedVirtIf.Addrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &NetworkInterfacePair{
|
||||||
|
TapInterface: *tapif,
|
||||||
|
VirtIface: virtif,
|
||||||
|
NetInterworkingModel: NetInterworkingModel(pair.NetInterworkingModel),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
package virtcontainers
|
package virtcontainers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -79,3 +83,41 @@ func TestIncorrectEndpointTypeString(t *testing.T) {
|
|||||||
var endpointType EndpointType
|
var endpointType EndpointType
|
||||||
testEndpointTypeString(t, &endpointType, "")
|
testEndpointTypeString(t, &endpointType, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSaveLoadIfPair(t *testing.T) {
|
||||||
|
macAddr := net.HardwareAddr{0x02, 0x00, 0xCA, 0xFE, 0x00, 0x04}
|
||||||
|
|
||||||
|
tmpfile, err := ioutil.TempFile("", "vc-save-load-net-")
|
||||||
|
assert.Nil(t, err)
|
||||||
|
defer os.Remove(tmpfile.Name())
|
||||||
|
|
||||||
|
netPair := &NetworkInterfacePair{
|
||||||
|
TapInterface: TapInterface{
|
||||||
|
ID: "uniqueTestID-4",
|
||||||
|
Name: "br4_kata",
|
||||||
|
TAPIface: NetworkInterface{
|
||||||
|
Name: "tap4_kata",
|
||||||
|
HardAddr: macAddr.String(),
|
||||||
|
},
|
||||||
|
VMFds: []*os.File{tmpfile}, // won't be saved to disk
|
||||||
|
VhostFds: []*os.File{tmpfile}, // won't be saved to disk
|
||||||
|
},
|
||||||
|
VirtIface: NetworkInterface{
|
||||||
|
Name: "eth4",
|
||||||
|
HardAddr: macAddr.String(),
|
||||||
|
},
|
||||||
|
NetInterworkingModel: DefaultNetInterworkingModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save to disk then load it back.
|
||||||
|
savedIfPair := saveNetIfPair(netPair)
|
||||||
|
loadedIfPair := loadNetIfPair(savedIfPair)
|
||||||
|
|
||||||
|
// Since VMFds and VhostFds are't saved, netPair and loadedIfPair are not equal.
|
||||||
|
assert.False(t, reflect.DeepEqual(netPair, loadedIfPair))
|
||||||
|
|
||||||
|
netPair.TapInterface.VMFds = nil
|
||||||
|
netPair.TapInterface.VhostFds = nil
|
||||||
|
// They are equal now.
|
||||||
|
assert.True(t, reflect.DeepEqual(netPair, loadedIfPair))
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
httptransport "github.com/go-openapi/runtime/client"
|
httptransport "github.com/go-openapi/runtime/client"
|
||||||
"github.com/go-openapi/strfmt"
|
"github.com/go-openapi/strfmt"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client"
|
"github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client"
|
||||||
models "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client/models"
|
models "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client/models"
|
||||||
ops "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client/operations"
|
ops "github.com/kata-containers/runtime/virtcontainers/pkg/firecracker/client/operations"
|
||||||
@ -234,8 +235,10 @@ func (fc *firecracker) createSandbox(ctx context.Context, id string, networkNS N
|
|||||||
|
|
||||||
// No need to return an error from there since there might be nothing
|
// No need to return an error from there since there might be nothing
|
||||||
// to fetch if this is the first time the hypervisor is created.
|
// to fetch if this is the first time the hypervisor is created.
|
||||||
if err := fc.store.Load(store.Hypervisor, &fc.info); err != nil {
|
if fc.store != nil {
|
||||||
fc.Logger().WithField("function", "init").WithError(err).Info("No info could be fetched")
|
if err := fc.store.Load(store.Hypervisor, &fc.info); err != nil {
|
||||||
|
fc.Logger().WithField("function", "init").WithError(err).Info("No info could be fetched")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -321,11 +324,13 @@ func (fc *firecracker) fcInit(timeout int) error {
|
|||||||
|
|
||||||
// Fetch sandbox network to be able to access it from the sandbox structure.
|
// Fetch sandbox network to be able to access it from the sandbox structure.
|
||||||
var networkNS NetworkNamespace
|
var networkNS NetworkNamespace
|
||||||
if err := fc.store.Load(store.Network, &networkNS); err == nil {
|
if fc.store != nil {
|
||||||
if networkNS.NetNsPath == "" {
|
if err := fc.store.Load(store.Network, &networkNS); err == nil {
|
||||||
fc.Logger().WithField("NETWORK NAMESPACE NULL", networkNS).Warn()
|
if networkNS.NetNsPath == "" {
|
||||||
|
fc.Logger().WithField("NETWORK NAMESPACE NULL", networkNS).Warn()
|
||||||
|
}
|
||||||
|
fc.netNSPath = networkNS.NetNsPath
|
||||||
}
|
}
|
||||||
fc.netNSPath = networkNS.NetNsPath
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err := os.MkdirAll(fc.jailerRoot, store.DirMode)
|
err := os.MkdirAll(fc.jailerRoot, store.DirMode)
|
||||||
@ -388,7 +393,10 @@ func (fc *firecracker) fcInit(timeout int) error {
|
|||||||
fc.state.set(apiReady)
|
fc.state.set(apiReady)
|
||||||
|
|
||||||
// Store VMM information
|
// Store VMM information
|
||||||
return fc.store.Store(store.Hypervisor, fc.info)
|
if fc.store != nil {
|
||||||
|
return fc.store.Store(store.Hypervisor, fc.info)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fc *firecracker) fcEnd() (err error) {
|
func (fc *firecracker) fcEnd() (err error) {
|
||||||
@ -988,3 +996,13 @@ func (fc *firecracker) fromGrpc(ctx context.Context, hypervisorConfig *Hyperviso
|
|||||||
func (fc *firecracker) toGrpc() ([]byte, error) {
|
func (fc *firecracker) toGrpc() ([]byte, error) {
|
||||||
return nil, errors.New("firecracker is not supported by VM cache")
|
return nil, errors.New("firecracker is not supported by VM cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fc *firecracker) save() (s persistapi.HypervisorState) {
|
||||||
|
s.Pid = fc.pid()
|
||||||
|
s.Type = string(FirecrackerHypervisor)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *firecracker) load(s persistapi.HypervisorState) {
|
||||||
|
fc.info.PID = s.Pid
|
||||||
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/store"
|
"github.com/kata-containers/runtime/virtcontainers/store"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
)
|
)
|
||||||
@ -670,4 +671,7 @@ type hypervisor interface {
|
|||||||
pid() int
|
pid() int
|
||||||
fromGrpc(ctx context.Context, hypervisorConfig *HypervisorConfig, store *store.VCStore, j []byte) error
|
fromGrpc(ctx context.Context, hypervisorConfig *HypervisorConfig, store *store.VCStore, j []byte) error
|
||||||
toGrpc() ([]byte, error)
|
toGrpc() ([]byte, error)
|
||||||
|
|
||||||
|
save() persistapi.HypervisorState
|
||||||
|
load(persistapi.HypervisorState)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPVlanEndpoint represents a ipvlan endpoint that is bridged to the VM
|
// IPVlanEndpoint represents a ipvlan endpoint that is bridged to the VM
|
||||||
@ -118,3 +119,23 @@ func (endpoint *IPVlanEndpoint) HotAttach(h hypervisor) error {
|
|||||||
func (endpoint *IPVlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
|
func (endpoint *IPVlanEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPath string) error {
|
||||||
return fmt.Errorf("IPVlanEndpoint does not support Hot detach")
|
return fmt.Errorf("IPVlanEndpoint does not support Hot detach")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *IPVlanEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
netpair := saveNetIfPair(&endpoint.NetPair)
|
||||||
|
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
IPVlan: &persistapi.IPVlanEndpoint{
|
||||||
|
NetPair: *netpair,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (endpoint *IPVlanEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = IPVlanEndpointType
|
||||||
|
|
||||||
|
if s.IPVlan != nil {
|
||||||
|
netpair := loadNetIfPair(&s.IPVlan.NetPair)
|
||||||
|
endpoint.NetPair = *netpair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
kataclient "github.com/kata-containers/agent/protocols/client"
|
kataclient "github.com/kata-containers/agent/protocols/client"
|
||||||
"github.com/kata-containers/agent/protocols/grpc"
|
"github.com/kata-containers/agent/protocols/grpc"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
|
vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
|
||||||
ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter"
|
ns "github.com/kata-containers/runtime/virtcontainers/pkg/nsenter"
|
||||||
vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
|
vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
|
||||||
@ -286,8 +287,10 @@ func (k *kataAgent) init(ctx context.Context, sandbox *Sandbox, config interface
|
|||||||
k.proxyBuiltIn = isProxyBuiltIn(sandbox.config.ProxyType)
|
k.proxyBuiltIn = isProxyBuiltIn(sandbox.config.ProxyType)
|
||||||
|
|
||||||
// Fetch agent runtime info.
|
// Fetch agent runtime info.
|
||||||
if err := sandbox.store.Load(store.Agent, &k.state); err != nil {
|
if !sandbox.supportNewStore() {
|
||||||
k.Logger().Debug("Could not retrieve anything from storage")
|
if err := sandbox.store.Load(store.Agent, &k.state); err != nil {
|
||||||
|
k.Logger().Debug("Could not retrieve anything from storage")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return disableVMShutdown, nil
|
return disableVMShutdown, nil
|
||||||
@ -686,7 +689,7 @@ func (k *kataAgent) setProxy(sandbox *Sandbox, proxy proxy, pid int, url string)
|
|||||||
k.proxy = proxy
|
k.proxy = proxy
|
||||||
k.state.ProxyPid = pid
|
k.state.ProxyPid = pid
|
||||||
k.state.URL = url
|
k.state.URL = url
|
||||||
if sandbox != nil {
|
if sandbox != nil && !sandbox.supportNewStore() {
|
||||||
if err := sandbox.store.Store(store.Agent, k.state); err != nil {
|
if err := sandbox.store.Store(store.Agent, k.state); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -841,9 +844,11 @@ func (k *kataAgent) stopSandbox(sandbox *Sandbox) error {
|
|||||||
// clean up agent state
|
// clean up agent state
|
||||||
k.state.ProxyPid = -1
|
k.state.ProxyPid = -1
|
||||||
k.state.URL = ""
|
k.state.URL = ""
|
||||||
if err := sandbox.store.Store(store.Agent, k.state); err != nil {
|
if !sandbox.supportNewStore() {
|
||||||
// ignore error
|
if err := sandbox.store.Store(store.Agent, k.state); err != nil {
|
||||||
k.Logger().WithError(err).WithField("sandbox", sandbox.id).Error("failed to clean up agent state")
|
// ignore error
|
||||||
|
k.Logger().WithError(err).WithField("sandbox", sandbox.id).Error("failed to clean up agent state")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -2074,3 +2079,15 @@ func (k *kataAgent) cleanup(s *Sandbox) {
|
|||||||
k.Logger().WithError(err).Errorf("failed to cleanup vm share path %s", path)
|
k.Logger().WithError(err).Errorf("failed to cleanup vm share path %s", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *kataAgent) save() persistapi.AgentState {
|
||||||
|
return persistapi.AgentState{
|
||||||
|
ProxyPid: k.state.ProxyPid,
|
||||||
|
URL: k.state.URL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *kataAgent) load(s persistapi.AgentState) {
|
||||||
|
k.state.ProxyPid = s.ProxyPid
|
||||||
|
k.state.URL = s.URL
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@ package virtcontainers
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MacvtapEndpoint represents a macvtap endpoint
|
// MacvtapEndpoint represents a macvtap endpoint
|
||||||
@ -102,3 +104,20 @@ func (endpoint *MacvtapEndpoint) SetPciAddr(pciAddr string) {
|
|||||||
func (endpoint *MacvtapEndpoint) NetworkPair() *NetworkInterfacePair {
|
func (endpoint *MacvtapEndpoint) NetworkPair() *NetworkInterfacePair {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *MacvtapEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
|
||||||
|
Macvtap: &persistapi.MacvtapEndpoint{
|
||||||
|
PCIAddr: endpoint.PCIAddr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (endpoint *MacvtapEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = MacvtapEndpointType
|
||||||
|
|
||||||
|
if s.Macvtap != nil {
|
||||||
|
endpoint.PCIAddr = s.Macvtap.PCIAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/store"
|
"github.com/kata-containers/runtime/virtcontainers/store"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
)
|
)
|
||||||
@ -114,3 +115,9 @@ func (m *mockHypervisor) fromGrpc(ctx context.Context, hypervisorConfig *Hypervi
|
|||||||
func (m *mockHypervisor) toGrpc() ([]byte, error) {
|
func (m *mockHypervisor) toGrpc() ([]byte, error) {
|
||||||
return nil, errors.New("firecracker is not supported by VM cache")
|
return nil, errors.New("firecracker is not supported by VM cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mockHypervisor) save() (s persistapi.HypervisorState) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockHypervisor) load(s persistapi.HypervisorState) {}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/kata-containers/agent/protocols/grpc"
|
"github.com/kata-containers/agent/protocols/grpc"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
|
vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
@ -233,3 +234,11 @@ func (n *noopAgent) markDead() {
|
|||||||
|
|
||||||
func (n *noopAgent) cleanup(s *Sandbox) {
|
func (n *noopAgent) cleanup(s *Sandbox) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save is the Noop agent state saver. It does nothing.
|
||||||
|
func (n *noopAgent) save() (s persistapi.AgentState) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// load is the Noop agent state loader. It does nothing.
|
||||||
|
func (n *noopAgent) load(s persistapi.AgentState) {}
|
||||||
|
@ -57,7 +57,9 @@ func (s *Sandbox) dumpState(ss *persistapi.SandboxState, cs map[string]persistap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sandbox) dumpHypervisor(ss *persistapi.SandboxState, cs map[string]persistapi.ContainerState) {
|
func (s *Sandbox) dumpHypervisor(ss *persistapi.SandboxState) {
|
||||||
|
ss.HypervisorState = s.hypervisor.save()
|
||||||
|
// BlockIndex will be moved from sandbox state to hypervisor state later
|
||||||
ss.HypervisorState.BlockIndex = s.state.BlockIndex
|
ss.HypervisorState.BlockIndex = s.state.BlockIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +154,23 @@ func (s *Sandbox) dumpMounts(cs map[string]persistapi.ContainerState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) dumpAgent(ss *persistapi.SandboxState) {
|
||||||
|
if s.agent != nil {
|
||||||
|
ss.AgentState = s.agent.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) dumpNetwork(ss *persistapi.SandboxState) {
|
||||||
|
ss.Network = persistapi.NetworkInfo{
|
||||||
|
NetNsPath: s.networkNS.NetNsPath,
|
||||||
|
NetmonPID: s.networkNS.NetmonPID,
|
||||||
|
NetNsCreated: s.networkNS.NetNsCreated,
|
||||||
|
}
|
||||||
|
for _, e := range s.networkNS.Endpoints {
|
||||||
|
ss.Network.Endpoints = append(ss.Network.Endpoints, e.save())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Sandbox) Save() error {
|
func (s *Sandbox) Save() error {
|
||||||
var (
|
var (
|
||||||
ss = persistapi.SandboxState{}
|
ss = persistapi.SandboxState{}
|
||||||
@ -160,10 +179,12 @@ func (s *Sandbox) Save() error {
|
|||||||
|
|
||||||
s.dumpVersion(&ss)
|
s.dumpVersion(&ss)
|
||||||
s.dumpState(&ss, cs)
|
s.dumpState(&ss, cs)
|
||||||
s.dumpHypervisor(&ss, cs)
|
s.dumpHypervisor(&ss)
|
||||||
s.dumpDevices(&ss, cs)
|
s.dumpDevices(&ss, cs)
|
||||||
s.dumpProcess(cs)
|
s.dumpProcess(cs)
|
||||||
s.dumpMounts(cs)
|
s.dumpMounts(cs)
|
||||||
|
s.dumpAgent(&ss)
|
||||||
|
s.dumpNetwork(&ss)
|
||||||
|
|
||||||
if err := s.newStore.ToDisk(ss, cs); err != nil {
|
if err := s.newStore.ToDisk(ss, cs); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -190,6 +211,16 @@ func (c *Container) loadContState(cs persistapi.ContainerState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) loadHypervisor(hs persistapi.HypervisorState) {
|
||||||
|
s.hypervisor.load(hs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) loadAgent(as persistapi.AgentState) {
|
||||||
|
if s.agent != nil {
|
||||||
|
s.agent.load(as)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Sandbox) loadDevices(devStates []persistapi.DeviceState) {
|
func (s *Sandbox) loadDevices(devStates []persistapi.DeviceState) {
|
||||||
s.devManager.LoadDevices(devStates)
|
s.devManager.LoadDevices(devStates)
|
||||||
}
|
}
|
||||||
@ -229,6 +260,39 @@ func (c *Container) loadContProcess(cs persistapi.ContainerState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) loadNetwork(netInfo persistapi.NetworkInfo) {
|
||||||
|
s.networkNS = NetworkNamespace{
|
||||||
|
NetNsPath: netInfo.NetNsPath,
|
||||||
|
NetmonPID: netInfo.NetmonPID,
|
||||||
|
NetNsCreated: netInfo.NetNsCreated,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range netInfo.Endpoints {
|
||||||
|
var ep Endpoint
|
||||||
|
switch EndpointType(e.Type) {
|
||||||
|
case PhysicalEndpointType:
|
||||||
|
ep = &PhysicalEndpoint{}
|
||||||
|
case VethEndpointType:
|
||||||
|
ep = &VethEndpoint{}
|
||||||
|
case VhostUserEndpointType:
|
||||||
|
ep = &VhostUserEndpoint{}
|
||||||
|
case BridgedMacvlanEndpointType:
|
||||||
|
ep = &BridgedMacvlanEndpoint{}
|
||||||
|
case MacvtapEndpointType:
|
||||||
|
ep = &MacvtapEndpoint{}
|
||||||
|
case TapEndpointType:
|
||||||
|
ep = &TapEndpoint{}
|
||||||
|
case IPVlanEndpointType:
|
||||||
|
ep = &IPVlanEndpoint{}
|
||||||
|
default:
|
||||||
|
s.Logger().WithField("endpoint-type", e.Type).Error("unknown endpoint type")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ep.load(e)
|
||||||
|
s.networkNS.Endpoints = append(s.networkNS.Endpoints, ep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Restore will restore sandbox data from persist file on disk
|
// Restore will restore sandbox data from persist file on disk
|
||||||
func (s *Sandbox) Restore() error {
|
func (s *Sandbox) Restore() error {
|
||||||
ss, _, err := s.newStore.FromDisk(s.id)
|
ss, _, err := s.newStore.FromDisk(s.id)
|
||||||
@ -237,7 +301,10 @@ func (s *Sandbox) Restore() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.loadState(ss)
|
s.loadState(ss)
|
||||||
|
s.loadHypervisor(ss.HypervisorState)
|
||||||
s.loadDevices(ss.Devices)
|
s.loadDevices(ss.Devices)
|
||||||
|
s.loadAgent(ss.AgentState)
|
||||||
|
s.loadNetwork(ss.Network)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
43
virtcontainers/persist/api/hypervisor.go
Normal file
43
virtcontainers/persist/api/hypervisor.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2019 Huawei Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
package persistapi
|
||||||
|
|
||||||
|
// Bridge is a bridge where devices can be hot plugged
|
||||||
|
type Bridge struct {
|
||||||
|
// DeviceAddr contains information about devices plugged and its address in the bridge
|
||||||
|
DeviceAddr map[uint32]string
|
||||||
|
|
||||||
|
// Type is the type of the bridge (pci, pcie, etc)
|
||||||
|
Type string
|
||||||
|
|
||||||
|
//ID is used to identify the bridge in the hypervisor
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// Addr is the PCI/e slot of the bridge
|
||||||
|
Addr int
|
||||||
|
}
|
||||||
|
|
||||||
|
// CPUDevice represents a CPU device which was hot-added in a running VM
|
||||||
|
type CPUDevice struct {
|
||||||
|
// ID is used to identify this CPU in the hypervisor options.
|
||||||
|
ID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HypervisorState struct {
|
||||||
|
Pid int
|
||||||
|
// Type of hypervisor, E.g. qemu/firecracker/acrn.
|
||||||
|
Type string
|
||||||
|
BlockIndex int
|
||||||
|
UUID string
|
||||||
|
|
||||||
|
// Belows are qemu specific
|
||||||
|
// Refs: virtcontainers/qemu.go:QemuState
|
||||||
|
Bridges []Bridge
|
||||||
|
// HotpluggedCPUs is the list of CPUs that were hot-added
|
||||||
|
HotpluggedVCPUs []CPUDevice
|
||||||
|
HotpluggedMemory int
|
||||||
|
HotplugVFIOOnRootBus bool
|
||||||
|
}
|
@ -6,27 +6,86 @@
|
|||||||
|
|
||||||
package persistapi
|
package persistapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
// ============= sandbox level resources =============
|
// ============= sandbox level resources =============
|
||||||
|
|
||||||
|
type NetworkInterface struct {
|
||||||
|
Name string
|
||||||
|
HardAddr string
|
||||||
|
Addrs []netlink.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
// TapInterface defines a tap interface
|
||||||
|
type TapInterface struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
TAPIface NetworkInterface
|
||||||
|
// remove VMFds and VhostFds
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkInterfacePair defines a pair between VM and virtual network interfaces.
|
||||||
|
type NetworkInterfacePair struct {
|
||||||
|
TapInterface
|
||||||
|
VirtIface NetworkInterface
|
||||||
|
NetInterworkingModel int
|
||||||
|
}
|
||||||
|
|
||||||
|
type PhysicalEndpoint struct {
|
||||||
|
BDF string
|
||||||
|
Driver string
|
||||||
|
VendorDeviceID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type MacvtapEndpoint struct {
|
||||||
|
// This is for showing information.
|
||||||
|
// Remove this field won't impact anything.
|
||||||
|
PCIAddr string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TapEndpoint struct {
|
||||||
|
TapInterface TapInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
type BridgedMacvlanEndpoint struct {
|
||||||
|
NetPair NetworkInterfacePair
|
||||||
|
}
|
||||||
|
|
||||||
|
type VethEndpoint struct {
|
||||||
|
NetPair NetworkInterfacePair
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPVlanEndpoint struct {
|
||||||
|
NetPair NetworkInterfacePair
|
||||||
|
}
|
||||||
|
|
||||||
|
type VhostUserEndpoint struct {
|
||||||
|
// This is for showing information.
|
||||||
|
// Remove these fields won't impact anything.
|
||||||
|
IfaceName string
|
||||||
|
PCIAddr string
|
||||||
|
}
|
||||||
|
|
||||||
// NetworkEndpoint contains network interface information
|
// NetworkEndpoint contains network interface information
|
||||||
type NetworkEndpoint struct {
|
type NetworkEndpoint struct {
|
||||||
Type string
|
Type string
|
||||||
|
|
||||||
// ID used to pass the netdev option to qemu
|
// One and only one of these below are not nil according to Type.
|
||||||
ID string
|
Physical *PhysicalEndpoint `json:",omitempty"`
|
||||||
|
Veth *VethEndpoint `json:",omitempty"`
|
||||||
// Name of the interface
|
VhostUser *VhostUserEndpoint `json:",omitempty"`
|
||||||
Name string
|
BridgedMacvlan *BridgedMacvlanEndpoint `json:",omitempty"`
|
||||||
|
Macvtap *MacvtapEndpoint `json:",omitempty"`
|
||||||
// Index of interface
|
Tap *TapEndpoint `json:",omitempty"`
|
||||||
Index int
|
IPVlan *IPVlanEndpoint `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkInfo contains network information of sandbox
|
// NetworkInfo contains network information of sandbox
|
||||||
type NetworkInfo struct {
|
type NetworkInfo struct {
|
||||||
NetNsPath string
|
NetNsPath string
|
||||||
NetmonPID int
|
NetmonPID int
|
||||||
NetNsCreated bool
|
NetNsCreated bool
|
||||||
InterworkingModel string
|
Endpoints []NetworkEndpoint
|
||||||
Endpoints []NetworkEndpoint
|
|
||||||
}
|
}
|
||||||
|
@ -8,50 +8,12 @@ package persistapi
|
|||||||
|
|
||||||
// ============= sandbox level resources =============
|
// ============= sandbox level resources =============
|
||||||
|
|
||||||
// SetFunc is function hook used for setting sandbox/container state
|
// AgentState save agent state data
|
||||||
// It can be registered to dynamically set state files when dump
|
type AgentState struct {
|
||||||
type SetFunc (func(*SandboxState, map[string]ContainerState) error)
|
|
||||||
|
|
||||||
// Bridge is a bridge where devices can be hot plugged
|
|
||||||
type Bridge struct {
|
|
||||||
// DeviceAddr contains information about devices plugged and its address in the bridge
|
|
||||||
DeviceAddr map[uint32]string
|
|
||||||
|
|
||||||
// Type is the type of the bridge (pci, pcie, etc)
|
|
||||||
Type string
|
|
||||||
|
|
||||||
//ID is used to identify the bridge in the hypervisor
|
|
||||||
ID string
|
|
||||||
|
|
||||||
// Addr is the PCI/e slot of the bridge
|
|
||||||
Addr int
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPUDevice represents a CPU device which was hot-added in a running VM
|
|
||||||
type CPUDevice struct {
|
|
||||||
// ID is used to identify this CPU in the hypervisor options.
|
|
||||||
ID string
|
|
||||||
}
|
|
||||||
|
|
||||||
// HypervisorState saves state of hypervisor
|
|
||||||
// Refs: virtcontainers/qemu.go:QemuState
|
|
||||||
type HypervisorState struct {
|
|
||||||
Pid int
|
|
||||||
Bridges []Bridge
|
|
||||||
// HotpluggedCPUs is the list of CPUs that were hot-added
|
|
||||||
HotpluggedVCPUs []CPUDevice
|
|
||||||
HotpluggedMemory int
|
|
||||||
UUID string
|
|
||||||
HotplugVFIOOnRootBus bool
|
|
||||||
BlockIndex int
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProxyState save proxy state data
|
|
||||||
type ProxyState struct {
|
|
||||||
// Pid of proxy process
|
// Pid of proxy process
|
||||||
Pid int
|
ProxyPid int
|
||||||
|
|
||||||
// URL to connect to proxy
|
// URL to connect to agent
|
||||||
URL string
|
URL string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +46,8 @@ type SandboxState struct {
|
|||||||
// HypervisorState saves hypervisor specific data
|
// HypervisorState saves hypervisor specific data
|
||||||
HypervisorState HypervisorState
|
HypervisorState HypervisorState
|
||||||
|
|
||||||
// ProxyState saves state data of proxy process
|
// AgentState saves state data of agent
|
||||||
ProxyState ProxyState
|
AgentState AgentState
|
||||||
|
|
||||||
// Network saves network configuration of sandbox
|
// Network saves network configuration of sandbox
|
||||||
Network NetworkInfo
|
Network NetworkInfo
|
||||||
|
@ -83,7 +83,7 @@ func TestSandboxRestore(t *testing.T) {
|
|||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.NotNil(sandbox.newStore)
|
assert.NotNil(sandbox.newStore)
|
||||||
|
|
||||||
// if we don't call ToDisk, we can get nothing from disk
|
// if we don't call Save(), we can get nothing from disk
|
||||||
err = sandbox.Restore()
|
err = sandbox.Restore()
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
assert.True(os.IsNotExist(err))
|
assert.True(os.IsNotExist(err))
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
|
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/safchain/ethtool"
|
"github.com/safchain/ethtool"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -200,3 +201,25 @@ func bindNICToVFIO(endpoint *PhysicalEndpoint) error {
|
|||||||
func bindNICToHost(endpoint *PhysicalEndpoint) error {
|
func bindNICToHost(endpoint *PhysicalEndpoint) error {
|
||||||
return drivers.BindDevicetoHost(endpoint.BDF, endpoint.Driver, endpoint.VendorDeviceID)
|
return drivers.BindDevicetoHost(endpoint.BDF, endpoint.Driver, endpoint.VendorDeviceID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *PhysicalEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
|
||||||
|
Physical: &persistapi.PhysicalEndpoint{
|
||||||
|
BDF: endpoint.BDF,
|
||||||
|
Driver: endpoint.Driver,
|
||||||
|
VendorDeviceID: endpoint.VendorDeviceID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (endpoint *PhysicalEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = PhysicalEndpointType
|
||||||
|
|
||||||
|
if s.Physical != nil {
|
||||||
|
endpoint.BDF = s.Physical.BDF
|
||||||
|
endpoint.Driver = s.Physical.Driver
|
||||||
|
endpoint.VendorDeviceID = s.Physical.VendorDeviceID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,9 +29,11 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/store"
|
"github.com/kata-containers/runtime/virtcontainers/store"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/types"
|
"github.com/kata-containers/runtime/virtcontainers/types"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/utils"
|
"github.com/kata-containers/runtime/virtcontainers/utils"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -252,7 +254,17 @@ func (q *qemu) setup(id string, hypervisorConfig *HypervisorConfig, vcStore *sto
|
|||||||
q.nvdimmCount = 0
|
q.nvdimmCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = q.store.Load(store.Hypervisor, &q.state); err != nil {
|
var create bool
|
||||||
|
if q.store != nil { //use old store
|
||||||
|
if err := q.store.Load(store.Hypervisor, &q.state); err != nil {
|
||||||
|
// hypervisor doesn't exist, create new one
|
||||||
|
create = true
|
||||||
|
}
|
||||||
|
} else if q.state.UUID == "" { // new store
|
||||||
|
create = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if create {
|
||||||
q.Logger().Debug("Creating bridges")
|
q.Logger().Debug("Creating bridges")
|
||||||
q.state.Bridges = q.arch.bridges(q.config.DefaultBridges)
|
q.state.Bridges = q.arch.bridges(q.config.DefaultBridges)
|
||||||
|
|
||||||
@ -267,7 +279,7 @@ func (q *qemu) setup(id string, hypervisorConfig *HypervisorConfig, vcStore *sto
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = q.store.Store(store.Hypervisor, q.state); err != nil {
|
if err = q.storeState(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1222,7 +1234,7 @@ func (q *qemu) hotplugAddDevice(devInfo interface{}, devType deviceType) (interf
|
|||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, q.store.Store(store.Hypervisor, q.state)
|
return data, q.storeState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemu) hotplugRemoveDevice(devInfo interface{}, devType deviceType) (interface{}, error) {
|
func (q *qemu) hotplugRemoveDevice(devInfo interface{}, devType deviceType) (interface{}, error) {
|
||||||
@ -1234,7 +1246,7 @@ func (q *qemu) hotplugRemoveDevice(devInfo interface{}, devType deviceType) (int
|
|||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return data, q.store.Store(store.Hypervisor, q.state)
|
return data, q.storeState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemu) hotplugCPUs(vcpus uint32, op operation) (uint32, error) {
|
func (q *qemu) hotplugCPUs(vcpus uint32, op operation) (uint32, error) {
|
||||||
@ -1314,12 +1326,12 @@ func (q *qemu) hotplugAddCPUs(amount uint32) (uint32, error) {
|
|||||||
hotpluggedVCPUs++
|
hotpluggedVCPUs++
|
||||||
if hotpluggedVCPUs == amount {
|
if hotpluggedVCPUs == amount {
|
||||||
// All vCPUs were hotplugged
|
// All vCPUs were hotplugged
|
||||||
return amount, q.store.Store(store.Hypervisor, q.state)
|
return amount, q.storeState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All vCPUs were NOT hotplugged
|
// All vCPUs were NOT hotplugged
|
||||||
if err := q.store.Store(store.Hypervisor, q.state); err != nil {
|
if err := q.storeState(); err != nil {
|
||||||
q.Logger().Errorf("failed to save hypervisor state after hotplug %d vCPUs: %v", hotpluggedVCPUs, err)
|
q.Logger().Errorf("failed to save hypervisor state after hotplug %d vCPUs: %v", hotpluggedVCPUs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1339,7 +1351,7 @@ func (q *qemu) hotplugRemoveCPUs(amount uint32) (uint32, error) {
|
|||||||
// get the last vCPUs and try to remove it
|
// get the last vCPUs and try to remove it
|
||||||
cpu := q.state.HotpluggedVCPUs[len(q.state.HotpluggedVCPUs)-1]
|
cpu := q.state.HotpluggedVCPUs[len(q.state.HotpluggedVCPUs)-1]
|
||||||
if err := q.qmpMonitorCh.qmp.ExecuteDeviceDel(q.qmpMonitorCh.ctx, cpu.ID); err != nil {
|
if err := q.qmpMonitorCh.qmp.ExecuteDeviceDel(q.qmpMonitorCh.ctx, cpu.ID); err != nil {
|
||||||
_ = q.store.Store(store.Hypervisor, q.state)
|
q.storeState()
|
||||||
return i, fmt.Errorf("failed to hotunplug CPUs, only %d CPUs were hotunplugged: %v", i, err)
|
return i, fmt.Errorf("failed to hotunplug CPUs, only %d CPUs were hotunplugged: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1347,7 +1359,7 @@ func (q *qemu) hotplugRemoveCPUs(amount uint32) (uint32, error) {
|
|||||||
q.state.HotpluggedVCPUs = q.state.HotpluggedVCPUs[:len(q.state.HotpluggedVCPUs)-1]
|
q.state.HotpluggedVCPUs = q.state.HotpluggedVCPUs[:len(q.state.HotpluggedVCPUs)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
return amount, q.store.Store(store.Hypervisor, q.state)
|
return amount, q.storeState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemu) hotplugMemory(memDev *memoryDevice, op operation) (int, error) {
|
func (q *qemu) hotplugMemory(memDev *memoryDevice, op operation) (int, error) {
|
||||||
@ -1453,7 +1465,7 @@ func (q *qemu) hotplugAddMemory(memDev *memoryDevice) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
q.state.HotpluggedMemory += memDev.sizeMB
|
q.state.HotpluggedMemory += memDev.sizeMB
|
||||||
return memDev.sizeMB, q.store.Store(store.Hypervisor, q.state)
|
return memDev.sizeMB, q.storeState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *qemu) pauseSandbox() error {
|
func (q *qemu) pauseSandbox() error {
|
||||||
@ -1907,3 +1919,57 @@ func (q *qemu) toGrpc() ([]byte, error) {
|
|||||||
|
|
||||||
return json.Marshal(&qp)
|
return json.Marshal(&qp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (q *qemu) storeState() error {
|
||||||
|
if q.store != nil {
|
||||||
|
if err := q.store.Store(store.Hypervisor, q.state); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *qemu) save() (s persistapi.HypervisorState) {
|
||||||
|
s.Pid = q.pid()
|
||||||
|
s.Type = string(QemuHypervisor)
|
||||||
|
s.UUID = q.state.UUID
|
||||||
|
s.HotpluggedMemory = q.state.HotpluggedMemory
|
||||||
|
s.HotplugVFIOOnRootBus = q.state.HotplugVFIOOnRootBus
|
||||||
|
|
||||||
|
for _, bridge := range q.state.Bridges {
|
||||||
|
s.Bridges = append(s.Bridges, persistapi.Bridge{
|
||||||
|
DeviceAddr: bridge.Address,
|
||||||
|
Type: string(bridge.Type),
|
||||||
|
ID: bridge.ID,
|
||||||
|
Addr: bridge.Addr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cpu := range q.state.HotpluggedVCPUs {
|
||||||
|
s.HotpluggedVCPUs = append(s.HotpluggedVCPUs, persistapi.CPUDevice{
|
||||||
|
ID: cpu.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *qemu) load(s persistapi.HypervisorState) {
|
||||||
|
q.state.UUID = s.UUID
|
||||||
|
q.state.HotpluggedMemory = s.HotpluggedMemory
|
||||||
|
q.state.HotplugVFIOOnRootBus = s.HotplugVFIOOnRootBus
|
||||||
|
|
||||||
|
for _, bridge := range s.Bridges {
|
||||||
|
q.state.Bridges = append(q.state.Bridges, types.PCIBridge{
|
||||||
|
Address: bridge.DeviceAddr,
|
||||||
|
Type: types.PCIType(bridge.Type),
|
||||||
|
ID: bridge.ID,
|
||||||
|
Addr: bridge.Addr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cpu := range s.HotpluggedVCPUs {
|
||||||
|
q.state.HotpluggedVCPUs = append(q.state.HotpluggedVCPUs, CPUDevice{
|
||||||
|
ID: cpu.ID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -467,20 +467,18 @@ func createSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Fac
|
|||||||
s.Logger().WithField("features", s.config.Experimental).Infof("Enable experimental features")
|
s.Logger().WithField("features", s.config.Experimental).Infof("Enable experimental features")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch sandbox network to be able to access it from the sandbox structure.
|
|
||||||
var networkNS NetworkNamespace
|
|
||||||
if err := s.store.Load(store.Network, &networkNS); err == nil {
|
|
||||||
s.networkNS = networkNS
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.supportNewStore() {
|
if s.supportNewStore() {
|
||||||
s.devManager = deviceManager.NewDeviceManager(sandboxConfig.HypervisorConfig.BlockDeviceDriver, nil)
|
// Restored successfully from newstore before.
|
||||||
|
if s.state.State != "" {
|
||||||
if err := s.Restore(); err == nil && s.state.State != "" {
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Fetch sandbox network to be able to access it from the sandbox structure.
|
||||||
|
var networkNS NetworkNamespace
|
||||||
|
if err := s.store.Load(store.Network, &networkNS); err == nil {
|
||||||
|
s.networkNS = networkNS
|
||||||
|
}
|
||||||
|
|
||||||
devices, err := s.store.LoadDevices()
|
devices, err := s.store.LoadDevices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger().WithError(err).WithField("sandboxid", s.id).Warning("load sandbox devices failed")
|
s.Logger().WithError(err).WithField("sandboxid", s.id).Warning("load sandbox devices failed")
|
||||||
@ -565,17 +563,24 @@ func newSandbox(ctx context.Context, sandboxConfig SandboxConfig, factory Factor
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
s.Logger().WithError(err).WithField("sandboxid", s.id).Error("Create new sandbox failed")
|
s.Logger().WithError(err).WithField("sandboxid", s.id).Error("Create new sandbox failed")
|
||||||
globalSandboxList.removeSandbox(s.id)
|
globalSandboxList.removeSandbox(s.id)
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
s.store.Delete()
|
s.store.Delete()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = s.hypervisor.createSandbox(ctx, s.id, s.networkNS, &sandboxConfig.HypervisorConfig, s.store); err != nil {
|
if s.supportNewStore() {
|
||||||
return nil, err
|
s.devManager = deviceManager.NewDeviceManager(sandboxConfig.HypervisorConfig.BlockDeviceDriver, nil)
|
||||||
|
|
||||||
|
// Ignore the error. Restore can fail for a new sandbox
|
||||||
|
s.Restore()
|
||||||
|
|
||||||
|
// new store doesn't require hypervisor to be stored immediately
|
||||||
|
if err = s.hypervisor.createSandbox(ctx, s.id, s.networkNS, &sandboxConfig.HypervisorConfig, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = s.hypervisor.createSandbox(ctx, s.id, s.networkNS, &sandboxConfig.HypervisorConfig, s.store); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
agentConfig, err := newAgentConfig(sandboxConfig.AgentType, sandboxConfig.AgentConfig)
|
agentConfig, err := newAgentConfig(sandboxConfig.AgentType, sandboxConfig.AgentConfig)
|
||||||
@ -836,7 +841,10 @@ func (s *Sandbox) createNetwork() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the network
|
// Store the network
|
||||||
return s.store.Store(store.Network, s.networkNS)
|
if !s.supportNewStore() {
|
||||||
|
return s.store.Store(store.Network, s.networkNS)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sandbox) postCreatedNetwork() error {
|
func (s *Sandbox) postCreatedNetwork() error {
|
||||||
@ -909,8 +917,14 @@ func (s *Sandbox) AddInterface(inf *vcTypes.Interface) (*vcTypes.Interface, erro
|
|||||||
|
|
||||||
// Update the sandbox storage
|
// Update the sandbox storage
|
||||||
s.networkNS.Endpoints = append(s.networkNS.Endpoints, endpoint)
|
s.networkNS.Endpoints = append(s.networkNS.Endpoints, endpoint)
|
||||||
if err := s.store.Store(store.Network, s.networkNS); err != nil {
|
if s.supportNewStore() {
|
||||||
return nil, err
|
if err := s.Save(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := s.store.Store(store.Network, s.networkNS); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add network for vm
|
// Add network for vm
|
||||||
@ -927,9 +941,17 @@ func (s *Sandbox) RemoveInterface(inf *vcTypes.Interface) (*vcTypes.Interface, e
|
|||||||
return inf, err
|
return inf, err
|
||||||
}
|
}
|
||||||
s.networkNS.Endpoints = append(s.networkNS.Endpoints[:i], s.networkNS.Endpoints[i+1:]...)
|
s.networkNS.Endpoints = append(s.networkNS.Endpoints[:i], s.networkNS.Endpoints[i+1:]...)
|
||||||
if err := s.store.Store(store.Network, s.networkNS); err != nil {
|
|
||||||
return inf, err
|
if s.supportNewStore() {
|
||||||
|
if err := s.Save(); err != nil {
|
||||||
|
return inf, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := s.store.Store(store.Network, s.networkNS); err != nil {
|
||||||
|
return inf, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1001,8 +1023,11 @@ func (s *Sandbox) startVM() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := s.store.Store(store.Network, s.networkNS); err != nil {
|
|
||||||
return err
|
if !s.supportNewStore() {
|
||||||
|
if err := s.store.Store(store.Network, s.networkNS); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
"github.com/vishvananda/netlink"
|
"github.com/vishvananda/netlink"
|
||||||
|
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
|
"github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -187,3 +188,22 @@ func unTapNetwork(name string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *TapEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
tapif := saveTapIf(&endpoint.TapInterface)
|
||||||
|
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
Tap: &persistapi.TapEndpoint{
|
||||||
|
TapInterface: *tapif,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (endpoint *TapEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = TapEndpointType
|
||||||
|
|
||||||
|
if s.Tap != nil {
|
||||||
|
tapif := loadTapIf(&s.Tap.TapInterface)
|
||||||
|
endpoint.TapInterface = *tapif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/containernetworking/plugins/pkg/ns"
|
"github.com/containernetworking/plugins/pkg/ns"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VethEndpoint gathers a network pair and its properties.
|
// VethEndpoint gathers a network pair and its properties.
|
||||||
@ -141,3 +142,23 @@ func (endpoint *VethEndpoint) HotDetach(h hypervisor, netNsCreated bool, netNsPa
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *VethEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
netpair := saveNetIfPair(&endpoint.NetPair)
|
||||||
|
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
Veth: &persistapi.VethEndpoint{
|
||||||
|
NetPair: *netpair,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (endpoint *VethEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = VethEndpointType
|
||||||
|
|
||||||
|
if s.Veth != nil {
|
||||||
|
netpair := loadNetIfPair(&s.Veth.NetPair)
|
||||||
|
endpoint.NetPair = *netpair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
"github.com/kata-containers/runtime/virtcontainers/device/config"
|
||||||
|
persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
|
||||||
"github.com/kata-containers/runtime/virtcontainers/utils"
|
"github.com/kata-containers/runtime/virtcontainers/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,3 +150,22 @@ func vhostUserSocketPath(info interface{}) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (endpoint *VhostUserEndpoint) save() persistapi.NetworkEndpoint {
|
||||||
|
return persistapi.NetworkEndpoint{
|
||||||
|
Type: string(endpoint.Type()),
|
||||||
|
VhostUser: &persistapi.VhostUserEndpoint{
|
||||||
|
IfaceName: endpoint.IfaceName,
|
||||||
|
PCIAddr: endpoint.PCIAddr,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (endpoint *VhostUserEndpoint) load(s persistapi.NetworkEndpoint) {
|
||||||
|
endpoint.EndpointType = VhostUserEndpointType
|
||||||
|
|
||||||
|
if s.VhostUser != nil {
|
||||||
|
endpoint.IfaceName = s.VhostUser.IfaceName
|
||||||
|
endpoint.PCIAddr = s.VhostUser.PCIAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user