vendor: Update govmm vendoring

Shortlog:

78d079d Merge pull request #84 from nitkon/master
4692f6b qmp: Conditionally pass threadID and socketID when CPU device add
b9c8f76 Merge pull request #85 from markdryan/fix-travis
1f51b43 Update the versions of Go used to build GoVMM
ad310f9 Fix staticcheck S1023
932fdc7 Fix staticcheck S1023
cb2ce93 Fix staticcheck S1008
f0172cd Fix staticcheck (S1002)
5f2e630 Fix staticcheck (S1025)
4beea51 Fix staticcheck (ST1005) errors

Fixes: #1155

Signed-off-by: Nitesh Konkar niteshkonkar@in.ibm.com
This commit is contained in:
Nitesh Konkar 2019-01-28 23:38:54 +05:30
parent b0986a5f7f
commit b1c666730e
14 changed files with 69 additions and 1440 deletions

8
Gopkg.lock generated
View File

@ -204,10 +204,9 @@
version = "v0.3.3"
[[projects]]
digest = "1:58b18038f51b6f79865fd00e3d883949c9507ede577cd9c4e743ed56cc454122"
digest = "1:351337e3b022de09e72306f1f9711314cc4bd407c15e8d328e218c655fd55731"
name = "github.com/firecracker-microvm/firecracker-go-sdk"
packages = [
".",
"client",
"client/models",
"client/operations",
@ -377,11 +376,11 @@
revision = "3520598351bb3500a49ae9563f5539666ae0a27c"
[[projects]]
digest = "1:15f0da05538e2445b354c620555231448849b7ece222c45578668d0dfd6bec93"
digest = "1:270961b1d5e664d4939ffae00b990e256d92bb5039cae69208211a84c72fe5f5"
name = "github.com/intel/govmm"
packages = ["qemu"]
pruneopts = "NUT"
revision = "737f03de595e216116264cc74a58e5f2a1df789a"
revision = "78d079db6d1f3e32e3ed7578a54baa6257b058a7"
[[projects]]
digest = "1:590bfb6f8d5741fa38bb3022f55588fb7e06389f6b7b6692a965e0e5a4363fb1"
@ -699,7 +698,6 @@
"github.com/containernetworking/plugins/pkg/ns",
"github.com/dlespiau/covertool/pkg/cover",
"github.com/docker/go-units",
"github.com/firecracker-microvm/firecracker-go-sdk",
"github.com/firecracker-microvm/firecracker-go-sdk/client",
"github.com/firecracker-microvm/firecracker-go-sdk/client/models",
"github.com/firecracker-microvm/firecracker-go-sdk/client/operations",

View File

@ -52,7 +52,7 @@
[[constraint]]
name = "github.com/intel/govmm"
revision = "737f03de595e216116264cc74a58e5f2a1df789a"
revision = "78d079db6d1f3e32e3ed7578a54baa6257b058a7"
[[constraint]]
name = "github.com/kata-containers/agent"

View File

@ -1,155 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package firecracker
import (
"context"
"io"
"os"
"os/exec"
)
var defaultFirecrackerVMMCommandBuilder = VMCommandBuilder{}.
WithBin("firecracker").
WithStdin(os.Stdin).
WithStdout(os.Stdout).
WithStderr(os.Stderr)
// VMCommandBuilder is a utility for building an exec.Cmd that represents how to
// start the Firecracker VMM.
type VMCommandBuilder struct {
bin string
args []string
socketPath string
stdin io.Reader
stdout io.Writer
stderr io.Writer
}
// Args returns all args that will be passed to exec.Command
func (b VMCommandBuilder) Args() []string {
return b.args
}
// WithArgs specifies which arguments to pass through to the
// firecracker exec.Command
func (b VMCommandBuilder) WithArgs(args []string) VMCommandBuilder {
b.args = args
return b
}
// AddArgs will append the provided args to the given command
func (b VMCommandBuilder) AddArgs(args ...string) VMCommandBuilder {
b.args = append(b.args, args...)
return b
}
// Bin return the bin that was set
func (b VMCommandBuilder) Bin() string {
return b.bin
}
// WithBin specifies which binary for firecracker to use
func (b VMCommandBuilder) WithBin(bin string) VMCommandBuilder {
b.bin = bin
return b
}
// SocketPath returns the specified socket path
func (b VMCommandBuilder) SocketPath() []string {
if len(b.socketPath) == 0 {
return nil
}
return []string{
"--api-sock",
b.socketPath,
}
}
// WithSocketPath specifies the socket path to be used when
// creating the firecracker exec.Command
func (b VMCommandBuilder) WithSocketPath(path string) VMCommandBuilder {
b.socketPath = path
return b
}
// Stdout will return the stdout that will be used when creating
// the firecracker exec.Command
func (b VMCommandBuilder) Stdout() io.Writer {
return b.stdout
}
// WithStdout specifies which io.Writer to use in place of the
// os.Stdout in the firecracker exec.Command.
func (b VMCommandBuilder) WithStdout(stdout io.Writer) VMCommandBuilder {
b.stdout = stdout
return b
}
// Stderr will return the stderr that will be used when creating
// the firecracker exec.Command
func (b VMCommandBuilder) Stderr() io.Writer {
return b.stderr
}
// WithStderr specifies which io.Writer to use in place of the
// os.Stderr in the firecracker exec.Command.
func (b VMCommandBuilder) WithStderr(stderr io.Writer) VMCommandBuilder {
b.stderr = stderr
return b
}
// Stdin will return the stdin that will be used when creating
// the firecracker exec.Command
func (b VMCommandBuilder) Stdin() io.Reader {
return b.stdin
}
// WithStdin specifies which io.Reader to use in place of the
// os.Stdin in the firecracker exec.Command.
func (b VMCommandBuilder) WithStdin(stdin io.Reader) VMCommandBuilder {
b.stdin = stdin
return b
}
// Build will build a firecracker command using the specific arguments
// specified in the builder.
func (b VMCommandBuilder) Build(ctx context.Context) *exec.Cmd {
args := []string{}
if socketPath := b.SocketPath(); socketPath != nil {
args = append(args, socketPath...)
}
if v := b.Args(); v != nil {
args = append(args, v...)
}
cmd := exec.CommandContext(
ctx,
b.Bin(),
args...,
)
if stdout := b.Stdout(); stdout != nil {
cmd.Stdout = stdout
}
if stderr := b.Stderr(); stderr != nil {
cmd.Stderr = stderr
}
if stdin := b.Stdin(); stdin != nil {
cmd.Stdin = stdin
}
return cmd
}

View File

@ -1,29 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
/*
Package firecracker provides a library to interact with the Firecracker API.
Firecracker is an open-source virtualization technology that is purpose-built
for creating and managing secure, multi-tenant containers and functions-based
services. See https://firecracker-microvm.github.io/ for more details.
This library requires Go 1.11 and can be used with Go modules.
BUG(aws): There are some Firecracker features that are not yet supported by the
SDK. These are tracked as GitHub issues with the firecracker-feature label:
https://github.com/firecracker-microvm/firecracker-go-sdk/issues?q=is%3Aissue+is%3Aopen+label%3Afirecracker-feature
This library is licensed under the Apache 2.0 License.
*/
package firecracker

View File

@ -1,65 +0,0 @@
package firecracker
import (
"strconv"
models "github.com/firecracker-microvm/firecracker-go-sdk/client/models"
)
const rootDriveName = "root-drive"
// DrivesBuilder is a builder that will build an array of drives used to set up
// the firecracker microVM. The DriveID will be an incrementing number starting
// at one
type DrivesBuilder struct {
rootDrive models.Drive
drives []models.Drive
}
// NewDrivesBuilder will return a new DrivesBuilder with a given rootfs.
func NewDrivesBuilder(rootDrivePath string) DrivesBuilder {
return DrivesBuilder{}.WithRootDrive(rootDrivePath)
}
// DriveOpt represents an optional function used to allow for specific
// customization of the models.Drive structure.
type DriveOpt func(*models.Drive)
// WithRootDrive will set the given builder with the a new root path. The root
// drive will be set to read and write by default.
func (b DrivesBuilder) WithRootDrive(rootDrivePath string, opts ...DriveOpt) DrivesBuilder {
b.rootDrive = models.Drive{
DriveID: String(rootDriveName),
PathOnHost: &rootDrivePath,
IsRootDevice: Bool(true),
IsReadOnly: Bool(false),
}
for _, opt := range opts {
opt(&b.rootDrive)
}
return b
}
// AddDrive will add a new drive to the given builder.
func (b DrivesBuilder) AddDrive(path string, readOnly bool, opts ...DriveOpt) DrivesBuilder {
drive := models.Drive{
DriveID: String(strconv.Itoa(len(b.drives))),
PathOnHost: &path,
IsRootDevice: Bool(false),
IsReadOnly: &readOnly,
}
for _, opt := range opts {
opt(&drive)
}
b.drives = append(b.drives, drive)
return b
}
// Build will construct an array of drives with the root drive at the very end.
func (b DrivesBuilder) Build() []models.Drive {
return append(b.drives, b.rootDrive)
}

View File

@ -1,150 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package firecracker
import (
"context"
"net"
"net/http"
"time"
"github.com/go-openapi/strfmt"
"github.com/sirupsen/logrus"
"github.com/firecracker-microvm/firecracker-go-sdk/client"
models "github.com/firecracker-microvm/firecracker-go-sdk/client/models"
ops "github.com/firecracker-microvm/firecracker-go-sdk/client/operations"
httptransport "github.com/go-openapi/runtime/client"
)
const firecrackerRequestTimeout = 500 * time.Millisecond
// FirecrackerClient is a client for interacting with the Firecracker API
type FirecrackerClient struct {
client *client.Firecracker
}
// NewFirecrackerClient creates a FirecrackerClient
func NewFirecrackerClient(socketPath string, logger *logrus.Entry, debug bool) *FirecrackerClient {
httpClient := client.NewHTTPClient(strfmt.NewFormats())
socketTransport := &http.Transport{
DialContext: func(ctx context.Context, network, path string) (net.Conn, error) {
addr, err := net.ResolveUnixAddr("unix", socketPath)
if err != nil {
return nil, err
}
return net.DialUnix("unix", nil, addr)
},
}
transport := httptransport.New(client.DefaultHost, client.DefaultBasePath, client.DefaultSchemes)
transport.Transport = socketTransport
if debug {
transport.SetDebug(debug)
}
if logger != nil {
transport.SetLogger(logger)
}
httpClient.SetTransport(transport)
return &FirecrackerClient{client: httpClient}
}
func (f *FirecrackerClient) PutLogger(ctx context.Context, logger *models.Logger) (*ops.PutLoggerNoContent, error) {
timeout, cancel := context.WithTimeout(ctx, firecrackerRequestTimeout)
defer cancel()
loggerParams := ops.NewPutLoggerParamsWithContext(timeout)
loggerParams.SetBody(logger)
return f.client.Operations.PutLogger(loggerParams)
}
func (f *FirecrackerClient) PutMachineConfiguration(ctx context.Context, cfg *models.MachineConfiguration) (*ops.PutMachineConfigurationNoContent, error) {
timeout, cancel := context.WithTimeout(ctx, firecrackerRequestTimeout)
defer cancel()
mc := ops.NewPutMachineConfigurationParamsWithContext(timeout)
mc.SetBody(cfg)
return f.client.Operations.PutMachineConfiguration(mc)
}
func (f *FirecrackerClient) PutGuestBootSource(ctx context.Context, source *models.BootSource) (*ops.PutGuestBootSourceNoContent, error) {
timeout, cancel := context.WithTimeout(ctx, firecrackerRequestTimeout)
defer cancel()
bootSource := ops.NewPutGuestBootSourceParamsWithContext(timeout)
bootSource.SetBody(source)
return f.client.Operations.PutGuestBootSource(bootSource)
}
func (f *FirecrackerClient) PutGuestNetworkInterfaceByID(ctx context.Context, ifaceID string, ifaceCfg *models.NetworkInterface) (*ops.PutGuestNetworkInterfaceByIDNoContent, error) {
timeout, cancel := context.WithTimeout(ctx, firecrackerRequestTimeout)
defer cancel()
cfg := ops.NewPutGuestNetworkInterfaceByIDParamsWithContext(timeout)
cfg.SetBody(ifaceCfg)
cfg.SetIfaceID(ifaceID)
return f.client.Operations.PutGuestNetworkInterfaceByID(cfg)
}
func (f *FirecrackerClient) PutGuestDriveByID(ctx context.Context, driveID string, drive *models.Drive) (*ops.PutGuestDriveByIDNoContent, error) {
timeout, cancel := context.WithTimeout(ctx, 250*time.Millisecond)
defer cancel()
params := ops.NewPutGuestDriveByIDParamsWithContext(timeout)
params.SetDriveID(driveID)
params.SetBody(drive)
return f.client.Operations.PutGuestDriveByID(params)
}
func (f *FirecrackerClient) PutGuestVsockByID(ctx context.Context, vsockID string, vsock *models.Vsock) (*ops.PutGuestVsockByIDCreated, *ops.PutGuestVsockByIDNoContent, error) {
params := ops.NewPutGuestVsockByIDParams()
params.SetContext(ctx)
params.SetID(vsockID)
params.SetBody(vsock)
return f.client.Operations.PutGuestVsockByID(params)
}
func (f *FirecrackerClient) CreateSyncAction(ctx context.Context, info *models.InstanceActionInfo) (*ops.CreateSyncActionNoContent, error) {
params := ops.NewCreateSyncActionParams()
params.SetContext(ctx)
params.SetInfo(info)
return f.client.Operations.CreateSyncAction(params)
}
func (f *FirecrackerClient) PutMmds(ctx context.Context, metadata interface{}) (*ops.PutMmdsNoContent, error) {
params := ops.NewPutMmdsParams()
params.SetContext(ctx)
params.SetBody(metadata)
return f.client.Operations.PutMmds(params)
}
func (f *FirecrackerClient) GetMachineConfig() (*ops.GetMachineConfigOK, error) {
p := ops.NewGetMachineConfigParams()
p.SetTimeout(firecrackerRequestTimeout)
return f.client.Operations.GetMachineConfig(p)
}

View File

@ -1,237 +0,0 @@
package firecracker
import (
"context"
)
// Handler name constants
const (
StartVMMHandlerName = "fcinit.StartVMM"
BootstrapLoggingHandlerName = "fcinit.BootstrapLogging"
CreateMachineHandlerName = "fcinit.CreateMachine"
CreateBootSourceHandlerName = "fcinit.CreateBootSource"
AttachDrivesHandlerName = "fcinit.AttachDrives"
CreateNetworkInterfacesHandlerName = "fcinit.CreateNetworkInterfaces"
AddVsocksHandlerName = "fcinit.AddVsocks"
SetMetadataHandlerName = "fcinit.SetMetadata"
ValidateCfgHandlerName = "validate.Cfg"
)
// StartVMMHandler is a named handler that will handle starting of the VMM.
// This handler will also set the exit channel on completion.
var StartVMMHandler = Handler{
Name: StartVMMHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.startVMM(ctx)
},
}
// BootstrapLoggingHandler is a named handler that will set up fifo logging of
// firecracker process.
var BootstrapLoggingHandler = Handler{
Name: BootstrapLoggingHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
if err := m.setupLogging(ctx); err != nil {
m.logger.Warnf("setupLogging() returned %s. Continuing anyway.", err)
} else {
m.logger.Debugf("setup logging: success")
}
return nil
},
}
// CreateMachineHandler is a named handler that will "create" the machine and
// upload any necessary configuration to the firecracker process.
var CreateMachineHandler = Handler{
Name: CreateMachineHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.createMachine(ctx)
},
}
// CreateBootSourceHandler is a named handler that will set up the booting
// process of the firecracker process.
var CreateBootSourceHandler = Handler{
Name: CreateBootSourceHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.createBootSource(ctx, m.cfg.KernelImagePath, m.cfg.KernelArgs)
},
}
// AttachDrivesHandler is a named handler that will attach all drives for the
// firecracker process.
var AttachDrivesHandler = Handler{
Name: AttachDrivesHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.attachDrives(ctx, m.cfg.Drives...)
},
}
// CreateNetworkInterfacesHandler is a named handler that sets up network
// interfaces to the firecracker process.
var CreateNetworkInterfacesHandler = Handler{
Name: CreateNetworkInterfacesHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.createNetworkInterfaces(ctx, m.cfg.NetworkInterfaces...)
},
}
// AddVsocksHandler is a named handler that adds vsocks to the firecracker
// process.
var AddVsocksHandler = Handler{
Name: AddVsocksHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.addVsocks(ctx, m.cfg.VsockDevices...)
},
}
// NewSetMetadataHandler is a named handler that puts the metadata into the
// firecracker process.
func NewSetMetadataHandler(metadata interface{}) Handler {
return Handler{
Name: SetMetadataHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
return m.SetMetadata(ctx, m.Metadata)
},
}
}
var defaultValidationHandlerList = HandlerList{}.Append(
Handler{
Name: ValidateCfgHandlerName,
Fn: func(ctx context.Context, m *Machine) error {
// ensure that the configuration is valid for the
// FcInit handlers.
return m.cfg.Validate()
},
},
)
var defaultFcInitHandlerList = HandlerList{}.Append(
StartVMMHandler,
BootstrapLoggingHandler,
CreateMachineHandler,
CreateBootSourceHandler,
AttachDrivesHandler,
CreateNetworkInterfacesHandler,
AddVsocksHandler,
)
var defaultHandlers = Handlers{
Validation: defaultValidationHandlerList,
FcInit: defaultFcInitHandlerList,
}
// Handler represents a named handler that contains a name and a function which
// is used to execute during the initialization process of a machine.
type Handler struct {
Name string
Fn func(context.Context, *Machine) error
}
// Handlers is a container that houses categories of handler lists.
type Handlers struct {
Validation HandlerList
FcInit HandlerList
}
// Run will execute all handlers in the Handlers object by flattening the lists
// into a single list and running.
func (h Handlers) Run(ctx context.Context, m *Machine) error {
l := HandlerList{}.Append(
h.Validation.list...,
).Append(
h.FcInit.list...,
)
return l.Run(ctx, m)
}
// HandlerList represents a list of named handler that can be used to execute a
// flow of instructions for a given machine.
type HandlerList struct {
list []Handler
}
// Append will append a new handler to the handler list.
func (l HandlerList) Append(handlers ...Handler) HandlerList {
l.list = append(l.list, handlers...)
return l
}
// Len return the length of the given handler list
func (l HandlerList) Len() int {
return len(l.list)
}
// Has will iterate through the handler list and check to see if the the named
// handler exists.
func (l HandlerList) Has(name string) bool {
for _, h := range l.list {
if h.Name == name {
return true
}
}
return false
}
// Swap will replace all elements of the given name with the new handler.
func (l HandlerList) Swap(handler Handler) HandlerList {
newList := HandlerList{}
for _, h := range l.list {
if h.Name == handler.Name {
newList.list = append(newList.list, handler)
continue
}
newList.list = append(newList.list, h)
}
return newList
}
// Swappend will either append, if there isn't an element within the handler
// list, otherwise it will replace all elements with the given name.
func (l HandlerList) Swappend(handler Handler) HandlerList {
if l.Has(handler.Name) {
return l.Swap(handler)
}
return l.Append(handler)
}
// Remove will return an updated handler with all instances of the specific
// named handler being removed.
func (l HandlerList) Remove(name string) HandlerList {
newList := HandlerList{}
for _, h := range l.list {
if h.Name != name {
newList.list = append(newList.list, h)
}
}
return newList
}
// Clear clears all named handler in the list.
func (l HandlerList) Clear() HandlerList {
l.list = l.list[0:0]
return l
}
// Run will execute each instruction in the handler list. If an error occurs in
// any of the handlers, then the list will halt execution and return the error.
func (l HandlerList) Run(ctx context.Context, m *Machine) error {
for _, handler := range l.list {
m.logger.Debugf("Running handler %s", handler.Name)
if err := handler.Fn(ctx, m); err != nil {
return err
}
}
return nil
}

View File

@ -1,607 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package firecracker
import (
"context"
"errors"
"fmt"
"io"
"os"
"os/exec"
"os/signal"
"strconv"
"syscall"
"time"
models "github.com/firecracker-microvm/firecracker-go-sdk/client/models"
ops "github.com/firecracker-microvm/firecracker-go-sdk/client/operations"
log "github.com/sirupsen/logrus"
)
const (
userAgent = "firecracker-go-sdk"
)
// Firecracker is an interface that can be used to mock
// out an Firecracker agent for testing purposes.
type Firecracker interface {
PutLogger(ctx context.Context, logger *models.Logger) (*ops.PutLoggerNoContent, error)
PutMachineConfiguration(ctx context.Context, cfg *models.MachineConfiguration) (*ops.PutMachineConfigurationNoContent, error)
PutGuestBootSource(ctx context.Context, source *models.BootSource) (*ops.PutGuestBootSourceNoContent, error)
PutGuestNetworkInterfaceByID(ctx context.Context, ifaceID string, ifaceCfg *models.NetworkInterface) (*ops.PutGuestNetworkInterfaceByIDNoContent, error)
PutGuestDriveByID(ctx context.Context, driveID string, drive *models.Drive) (*ops.PutGuestDriveByIDNoContent, error)
PutGuestVsockByID(ctx context.Context, vsockID string, vsock *models.Vsock) (*ops.PutGuestVsockByIDCreated, *ops.PutGuestVsockByIDNoContent, error)
CreateSyncAction(ctx context.Context, info *models.InstanceActionInfo) (*ops.CreateSyncActionNoContent, error)
PutMmds(ctx context.Context, metadata interface{}) (*ops.PutMmdsNoContent, error)
GetMachineConfig() (*ops.GetMachineConfigOK, error)
}
// Config is a collection of user-configurable VMM settings
type Config struct {
// SocketPath defines the file path where the Firecracker control socket
// should be created.
SocketPath string
// LogFifo defines the file path where the Firecracker log named-pipe should
// be located.
LogFifo string
// LogLevel defines the verbosity of Firecracker logging. Valid values are
// "Error", "Warning", "Info", and "Debug", and are case-sensitive.
LogLevel string
// MetricsFifo defines the file path where the Firecracker metrics
// named-pipe should be located.
MetricsFifo string
// KernelImagePath defines the file path where the kernel image is located.
// The kernel image must be an uncompressed ELF image.
KernelImagePath string
// KernelArgs defines the command-line arguments that should be passed to
// the kernel.
KernelArgs string
// Drives specifies BlockDevices that should be made available to the
// microVM.
Drives []models.Drive
// NetworkInterfaces specifies the tap devices that should be made available
// to the microVM.
NetworkInterfaces []NetworkInterface
// FifoLogWriter is an io.Writer that is used to redirect the contents of the
// fifo log to the writer.
FifoLogWriter io.Writer
// VsockDevices specifies the vsock devices that should be made available to
// the microVM.
VsockDevices []VsockDevice
// Debug enables debug-level logging for the SDK.
Debug bool
// MachineCfg represents the firecracker microVM process configuration
MachineCfg models.MachineConfiguration
// DisableValidation allows for easier mock testing by disabling the
// validation of configuration performed by the SDK.
DisableValidation bool
}
// Validate will ensure that the required fields are set and that
// the fields are valid values.
func (cfg *Config) Validate() error {
if cfg.DisableValidation {
return nil
}
if _, err := os.Stat(cfg.KernelImagePath); err != nil {
return fmt.Errorf("failed to stat kernal image path, %q: %v", cfg.KernelImagePath, err)
}
rootPath := ""
for _, drive := range cfg.Drives {
if BoolValue(drive.IsRootDevice) {
rootPath = StringValue(drive.PathOnHost)
break
}
}
if _, err := os.Stat(rootPath); err != nil {
return fmt.Errorf("failed to stat host path, %q: %v", rootPath, err)
}
// Check the non-existence of some files:
if _, err := os.Stat(cfg.SocketPath); err == nil {
return fmt.Errorf("socket %s already exists", cfg.SocketPath)
}
return nil
}
// Machine is the main object for manipulating Firecracker microVMs
type Machine struct {
cfg Config
client Firecracker
cmd *exec.Cmd
logger *log.Entry
machineConfig models.MachineConfiguration // The actual machine config as reported by Firecracker
// Metadata is the associated metadata that will be sent to the firecracker
// process
Metadata interface{}
errCh chan error
Handlers Handlers
}
// Logger returns a logrus logger appropriate for logging hypervisor messages
func (m *Machine) Logger() *log.Entry {
return m.logger.WithField("subsystem", userAgent)
}
// NetworkInterface represents a Firecracker microVM's network interface.
type NetworkInterface struct {
// MacAddress defines the MAC address that should be assigned to the network
// interface inside the microVM.
MacAddress string
// HostDevName defines the file path of the tap device on the host.
HostDevName string
// AllowMMDS makes the Firecracker MMDS available on this network interface.
AllowMDDS bool
}
// VsockDevice represents a vsock connection between the host and the guest
// microVM.
type VsockDevice struct {
// Path defines the filesystem path of the vsock device on the host.
Path string
// CID defines the 32-bit Context Identifier for the vsock device. See
// the vsock(7) manual page for more information.
CID uint32
}
// SocketPath returns the filesystem path to the socket used for VMM
// communication
func (m Machine) socketPath() string {
return m.cfg.SocketPath
}
// LogFile returns the filesystem path of the VMM log
func (m Machine) LogFile() string {
return m.cfg.LogFifo
}
// LogLevel returns the VMM log level.
func (m Machine) LogLevel() string {
return m.cfg.LogLevel
}
// NewMachine initializes a new Machine instance and performs validation of the
// provided Config.
func NewMachine(ctx context.Context, cfg Config, opts ...Opt) (*Machine, error) {
if err := cfg.Validate(); err != nil {
return nil, err
}
m := &Machine{}
logger := log.New()
if cfg.Debug {
logger.SetLevel(log.DebugLevel)
}
m.logger = log.NewEntry(logger)
m.cmd = defaultFirecrackerVMMCommandBuilder.
WithSocketPath(cfg.SocketPath).
Build(ctx)
m.Handlers = defaultHandlers
for _, opt := range opts {
opt(m)
}
if m.client == nil {
m.client = NewFirecrackerClient(cfg.SocketPath, m.logger, cfg.Debug)
}
m.cfg = cfg
m.logger.Debug("Called NewMachine()")
return m, nil
}
// Start will iterate through the handler list and call each handler. If an
// error occurred during handler execution, that error will be returned. If the
// handlers succeed, then this will start the VMM instance.
func (m *Machine) Start(ctx context.Context) error {
m.logger.Debug("Called Machine.Start()")
if err := m.Handlers.Run(ctx, m); err != nil {
return err
}
return m.StartInstance(ctx)
}
// Wait will wait until the firecracker process has finished
func (m *Machine) Wait(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
case err := <-m.errCh:
return err
}
}
func (m *Machine) addVsocks(ctx context.Context, vsocks ...VsockDevice) error {
for _, dev := range m.cfg.VsockDevices {
if err := m.addVsock(ctx, dev); err != nil {
return err
}
}
return nil
}
func (m *Machine) createNetworkInterfaces(ctx context.Context, ifaces ...NetworkInterface) error {
for id, iface := range ifaces {
if err := m.createNetworkInterface(ctx, iface, id+1); err != nil {
return err
}
m.logger.Debugf("createNetworkInterface returned for %s", iface.HostDevName)
}
return nil
}
func (m *Machine) attachDrives(ctx context.Context, drives ...models.Drive) error {
for _, dev := range drives {
if err := m.attachDrive(ctx, dev); err != nil {
m.logger.Errorf("While attaching drive %s, got error %s", StringValue(dev.PathOnHost), err)
return err
}
m.logger.Debugf("attachDrive returned for %s", StringValue(dev.PathOnHost))
}
return nil
}
// startVMM starts the firecracker vmm process and configures logging.
func (m *Machine) startVMM(ctx context.Context) error {
m.logger.Printf("Called startVMM(), setting up a VMM on %s", m.cfg.SocketPath)
m.errCh = make(chan error)
err := m.cmd.Start()
if err != nil {
m.logger.Errorf("Failed to start VMM: %s", err)
return err
}
m.logger.Debugf("VMM started socket path is %s", m.cfg.SocketPath)
go func() {
if err := m.cmd.Wait(); err != nil {
m.logger.Warnf("firecracker exited: %s", err.Error())
} else {
m.logger.Printf("firecracker exited: status=0")
}
os.Remove(m.cfg.SocketPath)
os.Remove(m.cfg.LogFifo)
os.Remove(m.cfg.MetricsFifo)
m.errCh <- err
}()
// Set up a signal handler and pass INT, QUIT, and TERM through to firecracker
vmchan := make(chan error)
sigchan := make(chan os.Signal)
signal.Notify(sigchan, os.Interrupt,
syscall.SIGQUIT,
syscall.SIGTERM,
syscall.SIGHUP,
syscall.SIGABRT)
m.logger.Debugf("Setting up signal handler")
go func() {
select {
case sig := <-sigchan:
m.logger.Printf("Caught signal %s", sig)
m.cmd.Process.Signal(sig)
case err = <-vmchan:
m.errCh <- err
}
}()
// Wait for firecracker to initialize:
err = m.waitForSocket(3*time.Second, m.errCh)
if err != nil {
msg := fmt.Sprintf("Firecracker did not create API socket %s: %s", m.cfg.SocketPath, err)
err = errors.New(msg)
return err
}
m.logger.Debugf("returning from startVMM()")
return nil
}
//StopVMM stops the current VMM.
func (m *Machine) StopVMM() error {
return m.stopVMM()
}
func (m *Machine) stopVMM() error {
if m.cmd != nil && m.cmd.Process != nil {
log.Debug("stopVMM(): sending sigterm to firecracker")
return m.cmd.Process.Signal(syscall.SIGTERM)
}
log.Debug("stopVMM(): no firecracker process running, not sending a signal")
// don't return an error if the process isn't even running
return nil
}
// createFifos sets up the firecracker logging and metrics FIFOs
func createFifos(logFifo, metricsFifo string) error {
log.Debugf("Creating FIFO %s", logFifo)
if err := syscall.Mkfifo(logFifo, 0700); err != nil {
return fmt.Errorf("Failed to create log fifo: %v", err)
}
log.Debugf("Creating metric FIFO %s", metricsFifo)
if err := syscall.Mkfifo(metricsFifo, 0700); err != nil {
return fmt.Errorf("Failed to create metric fifo: %v", err)
}
return nil
}
func (m *Machine) setupLogging(ctx context.Context) error {
if len(m.cfg.LogFifo) == 0 || len(m.cfg.MetricsFifo) == 0 {
// No logging configured
m.logger.Printf("VMM logging and metrics disabled.")
return nil
}
if err := createFifos(m.cfg.LogFifo, m.cfg.MetricsFifo); err != nil {
m.logger.Errorf("Unable to set up logging: %s", err)
return err
}
m.logger.Debug("Created metrics and logging fifos.")
l := models.Logger{
LogFifo: m.cfg.LogFifo,
Level: m.cfg.LogLevel,
MetricsFifo: m.cfg.MetricsFifo,
ShowLevel: true,
ShowLogOrigin: false,
}
_, err := m.client.PutLogger(ctx, &l)
if err != nil {
return err
}
m.logger.Debugf("Configured VMM logging to %s, metrics to %s",
m.cfg.LogFifo,
m.cfg.MetricsFifo,
)
if m.cfg.FifoLogWriter != nil {
if err := captureFifoToFile(m.logger, m.cfg.LogFifo, m.cfg.FifoLogWriter); err != nil {
return err
}
}
return nil
}
func captureFifoToFile(logger *log.Entry, fifoPath string, fifo io.Writer) error {
// create the fifo pipe which will be used
// to write its contents to a file.
fifoPipe, err := os.OpenFile(fifoPath, os.O_RDONLY, 0600)
if err != nil {
return fmt.Errorf("Failed to open fifo path at %q: %v", fifoPath, err)
}
if err := syscall.Unlink(fifoPath); err != nil {
logger.Warnf("Failed to unlink %s", fifoPath)
}
logger.Debugf("Capturing %q to writer", fifoPath)
// Uses a go routine to do a non-blocking io.Copy. The fifo
// file should be closed when the appication has finished, since
// the forked firecracker application will be closed resulting
// in the pipe to return an io.EOF
go func() {
defer fifoPipe.Close()
if _, err := io.Copy(fifo, fifoPipe); err != nil {
logger.Warnf("io.Copy failed to copy contents of fifo pipe: %v", err)
}
}()
return nil
}
func (m *Machine) createMachine(ctx context.Context) error {
resp, err := m.client.PutMachineConfiguration(ctx, &m.cfg.MachineCfg)
if err != nil {
m.logger.Errorf("PutMachineConfiguration returned %s", resp.Error())
return err
}
m.logger.Debug("PutMachineConfiguration returned")
err = m.refreshMachineConfig()
if err != nil {
log.Errorf("Unable to inspect Firecracker MachineConfig. Continuing anyway. %s", err)
}
m.logger.Debug("createMachine returning")
return err
}
func (m *Machine) createBootSource(ctx context.Context, imagePath, kernelArgs string) error {
bsrc := models.BootSource{
KernelImagePath: &imagePath,
BootArgs: kernelArgs,
}
resp, err := m.client.PutGuestBootSource(ctx, &bsrc)
if err == nil {
m.logger.Printf("PutGuestBootSource: %s", resp.Error())
}
return err
}
func (m *Machine) createNetworkInterface(ctx context.Context, iface NetworkInterface, iid int) error {
ifaceID := strconv.Itoa(iid)
m.logger.Printf("Attaching NIC %s (hwaddr %s) at index %s", iface.HostDevName, iface.MacAddress, ifaceID)
ifaceCfg := models.NetworkInterface{
IfaceID: &ifaceID,
GuestMac: iface.MacAddress,
HostDevName: iface.HostDevName,
AllowMmdsRequests: iface.AllowMDDS,
}
resp, err := m.client.PutGuestNetworkInterfaceByID(ctx, ifaceID, &ifaceCfg)
if err == nil {
m.logger.Printf("PutGuestNetworkInterfaceByID: %s", resp.Error())
}
return err
}
// attachDrive attaches a secondary block device
func (m *Machine) attachDrive(ctx context.Context, dev models.Drive) error {
var err error
hostPath := StringValue(dev.PathOnHost)
_, err = os.Stat(hostPath)
if err != nil {
return err
}
log.Infof("Attaching drive %s, slot %s, root %t.", hostPath, StringValue(dev.DriveID), BoolValue(dev.IsRootDevice))
respNoContent, err := m.client.PutGuestDriveByID(ctx, StringValue(dev.DriveID), &dev)
if err == nil {
m.logger.Printf("Attached drive %s: %s", hostPath, respNoContent.Error())
} else {
m.logger.Errorf("Attach drive failed: %s: %s", hostPath, err)
}
return err
}
// addVsock adds a vsock to the instance
func (m *Machine) addVsock(ctx context.Context, dev VsockDevice) error {
vsockCfg := models.Vsock{
GuestCid: int64(dev.CID),
ID: &dev.Path,
}
resp, _, err := m.client.PutGuestVsockByID(ctx, dev.Path, &vsockCfg)
if err != nil {
return err
}
m.logger.Debugf("Attach vsock %s successful: %s", dev.Path, resp.Error())
return nil
}
// StartInstance starts the Firecracker microVM
func (m *Machine) StartInstance(ctx context.Context) error {
return m.startInstance(ctx)
}
func (m *Machine) startInstance(ctx context.Context) error {
info := models.InstanceActionInfo{
ActionType: models.InstanceActionInfoActionTypeInstanceStart,
}
resp, err := m.client.CreateSyncAction(ctx, &info)
if err == nil {
m.logger.Printf("startInstance successful: %s", resp.Error())
} else {
m.logger.Errorf("Starting instance: %s", err)
}
return err
}
// EnableMetadata will append or replace the metadata handler.
func (m *Machine) EnableMetadata(metadata interface{}) {
m.Handlers.FcInit = m.Handlers.FcInit.Swappend(NewSetMetadataHandler(metadata))
}
// SetMetadata sets the machine's metadata for MDDS
func (m *Machine) SetMetadata(ctx context.Context, metadata interface{}) error {
respnocontent, err := m.client.PutMmds(ctx, metadata)
if err == nil {
var message string
if respnocontent != nil {
message = respnocontent.Error()
}
m.logger.Printf("SetMetadata successful: %s", message)
} else {
m.logger.Errorf("Setting metadata: %s", err)
}
return err
}
// refreshMachineConfig synchronizes our cached representation of the machine configuration
// with that reported by the Firecracker API
func (m *Machine) refreshMachineConfig() error {
resp, err := m.client.GetMachineConfig()
if err != nil {
return err
}
m.logger.Infof("refreshMachineConfig: %s", resp.Error())
m.machineConfig = *resp.Payload
return nil
}
// waitForSocket waits for the given file to exist
func (m *Machine) waitForSocket(timeout time.Duration, exitchan chan error) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
done := make(chan error)
ticker := time.NewTicker(10 * time.Millisecond)
go func() {
for {
select {
case <-ctx.Done():
done <- ctx.Err()
return
case err := <-exitchan:
done <- err
return
case <-ticker.C:
if _, err := os.Stat(m.cfg.SocketPath); err != nil {
continue
}
// Send test HTTP request to make sure socket is available
if _, err := m.client.GetMachineConfig(); err != nil {
continue
}
done <- nil
return
}
}
}()
return <-done
}

View File

@ -1,49 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package firecracker
import (
"os/exec"
"github.com/sirupsen/logrus"
)
// Opt represents a functional option to help modify functionality of a Machine.
type Opt func(*Machine)
// WithClient will use the client in place rather than the client constructed
// during bootstrapping of the machine. This option is useful for mocking out
// tests.
func WithClient(client Firecracker) Opt {
return func(machine *Machine) {
machine.client = client
}
}
// WithLogger will allow for the Machine to use the provided logger.
func WithLogger(logger *logrus.Entry) Opt {
return func(machine *Machine) {
machine.logger = logger
}
}
// WithProcessRunner will allow for a specific command to be run instead of the
// default firecracker command.
// For example, this could be used to instead call the jailer instead of
// firecracker directly.
func WithProcessRunner(cmd *exec.Cmd) Opt {
return func(machine *Machine) {
machine.cmd = cmd
}
}

View File

@ -1,46 +0,0 @@
package firecracker
// BoolValue will return a boolean value. If the pointer is nil, then false
// will be returned.
func BoolValue(b *bool) bool {
if b == nil {
return false
}
return *b
}
// Bool will return a pointer value of the given parameter.
func Bool(b bool) *bool {
return &b
}
// StringValue will return a string value. If the pointer is nil, then an empty
// string will be returned.
func StringValue(str *string) string {
if str == nil {
return ""
}
return *str
}
// String will return a pointer value of the given parameter.
func String(str string) *string {
return &str
}
// Int64 will return a pointer value of the given parameter.
func Int64(v int64) *int64 {
return &v
}
// Int64Value will return an int64 value. If the pointer is nil, then zero will
// be returned.
func Int64Value(v *int64) int64 {
if v == nil {
return 0
}
return *v
}

View File

@ -1,22 +0,0 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//go:generate find ./client ! -name swagger.yaml -type f -delete
// --skip-validation is used in the command-lines below to remove the network dependency that the swagger generator has
// in attempting to validate that the email address specified in the yaml file is valid.
//go:generate docker run --rm --net=none -v $PWD:/work -w /work quay.io/goswagger/swagger generate model -f ./client/swagger.yaml --model-package=client/models --client-package=client --copyright-file=COPYRIGHT_HEADER --skip-validation
//go:generate docker run --rm --net=none -v $PWD:/work -w /work quay.io/goswagger/swagger generate client -f ./client/swagger.yaml --model-package=client/models --client-package=client --copyright-file=COPYRIGHT_HEADER --skip-validation
package firecracker

View File

@ -51,18 +51,18 @@ func CreateCloudInitISO(ctx context.Context, scratchDir, isoPath string,
err := os.MkdirAll(dataDirPath, 0750)
if err != nil {
return fmt.Errorf("Unable to create config drive directory %s : %v",
return fmt.Errorf("unable to create config drive directory %s : %v",
dataDirPath, err)
}
err = ioutil.WriteFile(metaDataPath, metaData, 0644)
if err != nil {
return fmt.Errorf("Unable to create %s : %v", metaDataPath, err)
return fmt.Errorf("unable to create %s : %v", metaDataPath, err)
}
err = ioutil.WriteFile(userDataPath, userData, 0644)
if err != nil {
return fmt.Errorf("Unable to create %s : %v", userDataPath, err)
return fmt.Errorf("unable to create %s : %v", userDataPath, err)
}
cmd := exec.CommandContext(ctx, "xorriso", "-as", "mkisofs", "-R", "-V", "config-2",
@ -70,7 +70,7 @@ func CreateCloudInitISO(ctx context.Context, scratchDir, isoPath string,
cmd.SysProcAttr = attr
err = cmd.Run()
if err != nil {
return fmt.Errorf("Unable to create cloudinit iso image %v", err)
return fmt.Errorf("unable to create cloudinit iso image %v", err)
}
return nil

View File

@ -260,7 +260,7 @@ func (fsdev FSDevice) QemuParams(config *Config) []string {
var deviceParams []string
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", fsdev.Driver))
deviceParams = append(deviceParams, string(fsdev.Driver))
if s := fsdev.Driver.disableModern(fsdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
@ -346,7 +346,7 @@ func (cdev CharDevice) QemuParams(config *Config) []string {
var deviceParams []string
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", cdev.Driver))
deviceParams = append(deviceParams, string(cdev.Driver))
if s := cdev.Driver.disableModern(cdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
@ -534,7 +534,7 @@ func (netdev NetDevice) QemuNetdevParams(config *Config) []string {
netdevParams = append(netdevParams, netdev.Type.QemuNetdevParam())
netdevParams = append(netdevParams, fmt.Sprintf(",id=%s", netdev.ID))
if netdev.VHost == true {
if netdev.VHost {
netdevParams = append(netdevParams, ",vhost=on")
if len(netdev.VhostFDs) > 0 {
var fdParams []string
@ -627,7 +627,7 @@ func (dev SerialDevice) QemuParams(config *Config) []string {
var deviceParams []string
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", dev.Driver))
deviceParams = append(deviceParams, string(dev.Driver))
if s := dev.Driver.disableModern(dev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
@ -705,16 +705,16 @@ func (blkdev BlockDevice) QemuParams(config *Config) []string {
var deviceParams []string
var qemuParams []string
deviceParams = append(deviceParams, fmt.Sprintf("%s", blkdev.Driver))
deviceParams = append(deviceParams, string(blkdev.Driver))
if s := blkdev.Driver.disableModern(blkdev.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
deviceParams = append(deviceParams, fmt.Sprintf(",drive=%s", blkdev.ID))
if blkdev.SCSI == false {
if !blkdev.SCSI {
deviceParams = append(deviceParams, ",scsi=off")
}
if blkdev.WCE == false {
if !blkdev.WCE {
deviceParams = append(deviceParams, ",config-wce=off")
}
@ -842,11 +842,7 @@ type VFIODevice struct {
// Valid returns true if the VFIODevice structure is valid and complete.
func (vfioDev VFIODevice) Valid() bool {
if vfioDev.BDF == "" {
return false
}
return true
return vfioDev.BDF != ""
}
// QemuParams returns the qemu parameters built out of this vfio device.
@ -889,11 +885,7 @@ type SCSIController struct {
// Valid returns true if the SCSIController structure is valid and complete.
func (scsiCon SCSIController) Valid() bool {
if scsiCon.ID == "" {
return false
}
return true
return scsiCon.ID != ""
}
// QemuParams returns the qemu parameters built out of this SCSIController device.
@ -910,7 +902,7 @@ func (scsiCon SCSIController) QemuParams(config *Config) []string {
devParams = append(devParams, fmt.Sprintf("addr=%s", scsiCon.Addr))
}
if s := driver.disableModern(scsiCon.DisableModern); s != "" {
devParams = append(devParams, fmt.Sprintf("%s", s))
devParams = append(devParams, s)
}
if scsiCon.IOThread != "" {
devParams = append(devParams, fmt.Sprintf("iothread=%s", scsiCon.IOThread))
@ -1057,7 +1049,7 @@ func (vsock VSOCKDevice) QemuParams(config *Config) []string {
var qemuParams []string
driver := VHostVSock
deviceParams = append(deviceParams, fmt.Sprintf("%s", driver))
deviceParams = append(deviceParams, string(driver))
if s := driver.disableModern(vsock.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf(",%s", s))
}
@ -1094,11 +1086,7 @@ type RngDevice struct {
// Valid returns true if the RngDevice structure is valid and complete.
func (v RngDevice) Valid() bool {
if v.ID == "" {
return false
}
return true
return v.ID != ""
}
// QemuParams returns the qemu parameters built out of the RngDevice.
@ -1174,7 +1162,7 @@ func (b BalloonDevice) QemuParams(_ *Config) []string {
deviceParams = append(deviceParams, "deflate-on-oom=off")
}
if s := driver.disableModern(b.DisableModern); s != "" {
deviceParams = append(deviceParams, fmt.Sprintf("%s", s))
deviceParams = append(deviceParams, string(s))
}
qemuParams = append(qemuParams, "-device")
qemuParams = append(qemuParams, strings.Join(deviceParams, ","))
@ -1184,11 +1172,7 @@ func (b BalloonDevice) QemuParams(_ *Config) []string {
// Valid returns true if the balloonDevice structure is valid and complete.
func (b BalloonDevice) Valid() bool {
if b.ID == "" {
return false
}
return true
return b.ID != ""
}
// RTCBaseType is the qemu RTC base time type.
@ -1523,15 +1507,15 @@ func (config *Config) appendCPUModel() {
func (config *Config) appendQMPSockets() {
for _, q := range config.QMPSockets {
if q.Valid() == false {
if !q.Valid() {
continue
}
qmpParams := append([]string{}, fmt.Sprintf("%s:", q.Type))
qmpParams = append(qmpParams, fmt.Sprintf("%s", q.Name))
if q.Server == true {
qmpParams = append(qmpParams, q.Name)
if q.Server {
qmpParams = append(qmpParams, ",server")
if q.NoWait == true {
if q.NoWait {
qmpParams = append(qmpParams, ",nowait")
}
}
@ -1543,7 +1527,7 @@ func (config *Config) appendQMPSockets() {
func (config *Config) appendDevices() {
for _, d := range config.Devices {
if d.Valid() == false {
if !d.Valid() {
continue
}
@ -1611,7 +1595,7 @@ func (config *Config) appendCPUs() error {
}
func (config *Config) appendRTC() {
if config.RTC.Valid() == false {
if !config.RTC.Valid() {
return
}
@ -1663,7 +1647,7 @@ func (config *Config) appendKernel() {
}
func (config *Config) appendMemoryKnobs() {
if config.Knobs.HugePages == true {
if config.Knobs.HugePages {
if config.Memory.Size != "" {
dimmName := "dimm1"
objMemParam := "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=/dev/hugepages,share=on,prealloc=on"
@ -1675,7 +1659,7 @@ func (config *Config) appendMemoryKnobs() {
config.qemuParams = append(config.qemuParams, "-numa")
config.qemuParams = append(config.qemuParams, numaMemParam)
}
} else if config.Knobs.MemPrealloc == true {
} else if config.Knobs.MemPrealloc {
if config.Memory.Size != "" {
dimmName := "dimm1"
objMemParam := "memory-backend-ram,id=" + dimmName + ",size=" + config.Memory.Size + ",prealloc=on"
@ -1687,11 +1671,11 @@ func (config *Config) appendMemoryKnobs() {
config.qemuParams = append(config.qemuParams, "-numa")
config.qemuParams = append(config.qemuParams, numaMemParam)
}
} else if config.Knobs.FileBackedMem == true {
} else if config.Knobs.FileBackedMem {
if config.Memory.Size != "" && config.Memory.Path != "" {
dimmName := "dimm1"
objMemParam := "memory-backend-file,id=" + dimmName + ",size=" + config.Memory.Size + ",mem-path=" + config.Memory.Path
if config.Knobs.FileBackedMemShared == true {
if config.Knobs.FileBackedMemShared {
objMemParam += ",share=on"
}
numaMemParam := "node,memdev=" + dimmName
@ -1706,45 +1690,45 @@ func (config *Config) appendMemoryKnobs() {
}
func (config *Config) appendKnobs() {
if config.Knobs.NoUserConfig == true {
if config.Knobs.NoUserConfig {
config.qemuParams = append(config.qemuParams, "-no-user-config")
}
if config.Knobs.NoDefaults == true {
if config.Knobs.NoDefaults {
config.qemuParams = append(config.qemuParams, "-nodefaults")
}
if config.Knobs.NoGraphic == true {
if config.Knobs.NoGraphic {
config.qemuParams = append(config.qemuParams, "-nographic")
}
if config.Knobs.Daemonize == true {
if config.Knobs.Daemonize {
config.qemuParams = append(config.qemuParams, "-daemonize")
}
config.appendMemoryKnobs()
if config.Knobs.Realtime == true {
if config.Knobs.Realtime {
config.qemuParams = append(config.qemuParams, "-realtime")
// This path is redundant as the default behaviour is locked memory
// Realtime today does not control any other feature even though
// other features may be added in the future
// https://lists.gnu.org/archive/html/qemu-devel/2012-12/msg03330.html
if config.Knobs.Mlock == true {
if config.Knobs.Mlock {
config.qemuParams = append(config.qemuParams, "mlock=on")
} else {
config.qemuParams = append(config.qemuParams, "mlock=off")
}
} else {
// In order to turn mlock off we need the -realtime option as well
if config.Knobs.Mlock == false {
if !config.Knobs.Mlock {
//Enable realtime anyway just to get the right swapping behaviour
config.qemuParams = append(config.qemuParams, "-realtime")
config.qemuParams = append(config.qemuParams, "mlock=off")
}
}
if config.Knobs.Stopped == true {
if config.Knobs.Stopped {
config.qemuParams = append(config.qemuParams, "-S")
}
}

View File

@ -329,14 +329,14 @@ func (q *QMP) errorDesc(errorData interface{}) (string, error) {
// convert error to json
data, err := json.Marshal(errorData)
if err != nil {
return "", fmt.Errorf("Unable to extract error information: %v", err)
return "", fmt.Errorf("unable to extract error information: %v", err)
}
// see: https://github.com/qemu/qemu/blob/stable-2.12/qapi/qmp-dispatch.c#L125
var qmpErr map[string]string
// convert json to qmpError
if err = json.Unmarshal(data, &qmpErr); err != nil {
return "", fmt.Errorf("Unable to convert json to qmpError: %v", err)
return "", fmt.Errorf("unable to convert json to qmpError: %v", err)
}
return qmpErr["desc"], nil
@ -404,7 +404,7 @@ func (q *QMP) writeNextQMPCommand(cmdQueue *list.List) {
encodedCmd, err := json.Marshal(&cmdData)
if err != nil {
cmd.res <- qmpResult{
err: fmt.Errorf("Unable to marhsall command %s: %v",
err: fmt.Errorf("unable to marhsall command %s: %v",
cmd.name, err),
}
cmdQueue.Remove(cmdEl)
@ -419,7 +419,7 @@ func (q *QMP) writeNextQMPCommand(cmdQueue *list.List) {
if err != nil {
cmd.res <- qmpResult{
err: fmt.Errorf("Unable to write command to qmp socket %v", err),
err: fmt.Errorf("unable to write command to qmp socket %v", err),
}
cmdQueue.Remove(cmdEl)
}
@ -525,7 +525,7 @@ func (q *QMP) mainLoop() {
}
/* #nosec */
_ = q.conn.Close()
_ = <-fromVMCh
<-fromVMCh
failOutstandingCommands(cmdQueue)
close(q.disconnectedCh)
}()
@ -689,12 +689,12 @@ func QMPStart(ctx context.Context, socket string, cfg QMPConfig, disconnectedCh
case <-ctx.Done():
q.Shutdown()
<-disconnectedCh
return nil, nil, fmt.Errorf("Canceled by caller")
return nil, nil, fmt.Errorf("canceled by caller")
case <-disconnectedCh:
return nil, nil, fmt.Errorf("Lost connection to VM")
return nil, nil, fmt.Errorf("lost connection to VM")
case q.version = <-connectedCh:
if q.version == nil {
return nil, nil, fmt.Errorf("Failed to find QMP version information")
return nil, nil, fmt.Errorf("failed to find QMP version information")
}
}
@ -860,7 +860,7 @@ func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, drive
}
if !isSCSIDriver {
return fmt.Errorf("Invalid SCSI driver provided %s", driver)
return fmt.Errorf("invalid SCSI driver provided %s", driver)
}
args := map[string]interface{}{
@ -1144,14 +1144,21 @@ func (q *QMP) ExecutePCIVFIOMediatedDeviceAdd(ctx context.Context, devID, sysfsd
// ExecuteCPUDeviceAdd adds a CPU to a QEMU instance using the device_add command.
// driver is the CPU model, cpuID must be a unique ID to identify the CPU, socketID is the socket number within
// node/board the CPU belongs to, coreID is the core number within socket the CPU belongs to, threadID is the
// thread number within core the CPU belongs to.
// thread number within core the CPU belongs to. Note that socketID and threadID are not a requirement for
// architecures like ppc64le.
func (q *QMP) ExecuteCPUDeviceAdd(ctx context.Context, driver, cpuID, socketID, coreID, threadID, romfile string) error {
args := map[string]interface{}{
"driver": driver,
"id": cpuID,
"socket-id": socketID,
"core-id": coreID,
"thread-id": threadID,
"driver": driver,
"id": cpuID,
"core-id": coreID,
}
if socketID != "" {
args["socket-id"] = socketID
}
if threadID != "" {
args["thread-id"] = threadID
}
if isVirtioPCI[DeviceDriver(driver)] {
@ -1171,13 +1178,13 @@ func (q *QMP) ExecuteQueryHotpluggableCPUs(ctx context.Context) ([]HotpluggableC
// convert response to json
data, err := json.Marshal(response)
if err != nil {
return nil, fmt.Errorf("Unable to extract CPU information: %v", err)
return nil, fmt.Errorf("unable to extract CPU information: %v", err)
}
var cpus []HotpluggableCPU
// convert json to []HotpluggableCPU
if err = json.Unmarshal(data, &cpus); err != nil {
return nil, fmt.Errorf("Unable to convert json to hotpluggable CPU: %v", err)
return nil, fmt.Errorf("unable to convert json to hotpluggable CPU: %v", err)
}
return cpus, nil
@ -1211,7 +1218,7 @@ func (q *QMP) ExecQueryMemoryDevices(ctx context.Context) ([]MemoryDevices, erro
// convert response to json
data, err := json.Marshal(response)
if err != nil {
return nil, fmt.Errorf("Unable to extract memory devices information: %v", err)
return nil, fmt.Errorf("unable to extract memory devices information: %v", err)
}
var memoryDevices []MemoryDevices
@ -1235,7 +1242,7 @@ func (q *QMP) ExecQueryCpus(ctx context.Context) ([]CPUInfo, error) {
// convert response to json
data, err := json.Marshal(response)
if err != nil {
return nil, fmt.Errorf("Unable to extract memory devices information: %v", err)
return nil, fmt.Errorf("unable to extract memory devices information: %v", err)
}
var cpuInfo []CPUInfo
@ -1259,7 +1266,7 @@ func (q *QMP) ExecQueryCpusFast(ctx context.Context) ([]CPUInfoFast, error) {
// convert response to json
data, err := json.Marshal(response)
if err != nil {
return nil, fmt.Errorf("Unable to extract memory devices information: %v", err)
return nil, fmt.Errorf("unable to extract memory devices information: %v", err)
}
var cpuInfoFast []CPUInfoFast
@ -1434,12 +1441,12 @@ func (q *QMP) ExecuteQueryMigration(ctx context.Context) (MigrationStatus, error
data, err := json.Marshal(response)
if err != nil {
return MigrationStatus{}, fmt.Errorf("Unable to extract migrate status information: %v", err)
return MigrationStatus{}, fmt.Errorf("unable to extract migrate status information: %v", err)
}
var status MigrationStatus
if err = json.Unmarshal(data, &status); err != nil {
return MigrationStatus{}, fmt.Errorf("Unable to convert migrate status information: %v", err)
return MigrationStatus{}, fmt.Errorf("unable to convert migrate status information: %v", err)
}
return status, nil