Repository: firecracker-microvm/firecracker-containerd
Pull request #272 (2019-10-02 07:32:37)

Added timeout for VMshutdown
Issue #247

Added timeout for VM Shutdown
Added special type of error for case when timeout exceeded 


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.


Zyqsempai: @sipsma PTAL
sipsma: Oh also, the tests are failing just because your commit `Added timeout for VMshutdown` doesn't have a DCO (your other commit does), so please just amend that commit with a signoff when updating.
sipsma: @Zyqsempai Saw in the test runs of your latest commits that the `DeadlineExceeded` error was being returned unexpectedly in the test case, which didn't make any sense since the code you wrote looked good. It took a while, but I think I tracked down why. It's really really tricky (but fortunately easy to fix I think).

The fix should be to not create a new `ctx` derived from the `requestCtx` in `StopVM`. Instead, just use the existing `requestCtx` unmodified. Then, use a`time.Timer` to enforce the timeout, something along the lines of:
```
func (s *service) StopVM(...) {
    ...
    timer := time.NewTimer(timeout)
    ...
    select {
        case <-timer.C:
            ...
        case err = <-shutdownCh:
            ...
    }
}
```

To explain what I think the actual problem is, containerd gives our code [a context object during initialization in the NewService method, which we decided to call `shimCtx`](https://github.com/firecracker-microvm/firecracker-containerd/blob/master/runtime/service.go#L140). This context represents the execution of the shim process as a whole; when it is cancelled that means the process is shutting down (and thus all the services we run need to shut down too).

One place we give the `shimCtx` to is [the server for the firecracker-control API](https://github.com/firecracker-microvm/firecracker-containerd/blob/master/runtime/service.go#L260), which is what serves the `StopVM` API (among others). The TTRPC server implementation uses [that context](https://github.com/containerd/ttrpc/blob/master/server.go#L73) to decide when to shutdown, but it also derives [the `requestCtx` objects for all its methods](https://github.com/containerd/ttrpc/blob/master/server.go#L420) from that context.

As a result, [the `requestCtx` provided to `StopVM`](https://github.com/firecracker-microvm/firecracker-containerd/blob/master/runtime/service.go#L511) is a child context of `shimCtx`. This by itself is reasonable; if the shim is shutting down then ongoing requests should get cancelled too. However, inside [the `Shutdown` method, we cancel the `shimCtx`](https://github.com/firecracker-microvm/firecracker-containerd/blob/master/runtime/service.go#L1029) in order to actually start the full shutdown process, which is also reasonable by itself.

Putting all the above together, canceling `shimCtx` cancels `requestCtx`, which in turn cancels the new `ctx` your code added, so then when we hit the select statement in the new code we always hit the `<-ctx.Done()` case first and return `DeadlineExceeded`. Getting rid of that new extra `ctx` should thus fix the problem (and keep things from getting even more complicated than they already are). Let me know if this makes sense, it's obviously not straightforward at all.
Zyqsempai: @sipsma Yep, it's really tricky, but totally make sense.
Zyqsempai: @sipsma Done, thanks for you comments. PTAL.
kzys: Two (a bit bikeshed-y) questions:

- If a customer do want to shutdown the VM regardless of the time it takes, what would be the right way? Giving large enough timeout?
- Do we want to have server-side timeout for all of operations? It is not clear why StopVM can have the timeout, but others don't.
sipsma: >     * If a customer do want to shutdown the VM regardless of the time it takes, what would be the right way? Giving large enough timeout?

Yes, this change essentially prevents StopVM from ever being blocked forever waiting for the shutdown, which I think is preferable as I can't think of any situation in which being blocked *literally* forever is the desired behavior for stopping the VM.

>     * Do we want to have server-side timeout for all of operations? It is not clear why StopVM can have the timeout, but others don't.

I think adding it to StopVM is particularly valuable because it ensures that users don't get in a situation where they are unable cleanup resources on their machine (once the timeout is hit, we just send SIGKILL).

The cases where other operations besides StopVM get blocked forever are still not good, but the worst case scenario is the user doesn't create a VM or get information about their VM, which is somewhat less harmful than being unable to remove resources from their machine. That being said, I agree that adding timeouts to those other operations could still be valuable and is something to consider in the future (perhaps just not in this PR).
kzys: Thanks. I agree that blocking literally forever won't be what customers want.

How about renaming the field from `VMShutdownTimeoutSeconds` to `TimeoutSeconds` or simply `Timeout`, if we may add the field in other requests?
xibz: I wonder if it may be best to a grpc.ClientConn constructor function. You can set a timeout for the individual methods there. I wonder if that is preferable rather than adding a timeout field, and this would allow us to make use of the context that is being passed in. Thoughts?
sipsma: > Can this not be handled by setting a context deadline when making the request? Rather than an API change?

I think having the client specify the timeout in the `context` of their requests raises a bunch of questions that make the behavior harder to reason about: if the timeout is hit, then will the client be unblocked right away before any response is received (as opposed to receiving a timeout error from the server)? What if the context timeout is applied to other parts of the client connection, could that mean that the user is unable to distinguish between a dial timeout and a timeout shutting down the VM? How would the user determine if SIGKILL was sent in that case?

[Also see this comment](https://github.com/firecracker-microvm/firecracker-containerd/pull/272#issuecomment-538180715); from a purely internal code perspective, using context timeouts here creates more confusion than it's worth IMO.

I think in practice it ends up being simpler to just have it be part of the API.
sipsma: > Thanks. I agree that blocking literally forever won't be what customers want.
> 
> How about renaming the field from `VMShutdownTimeoutSeconds` to `TimeoutSeconds` or simply `Timeout`, if we may add the field in other requests?

Agree, @Zyqsempai I think that's worth making before we merge here.

Patch:
diff --git a/Makefile b/Makefile
index 6d20e90..ac631eb 100644
--- a/Makefile
+++ b/Makefile
@@ -182,7 +182,7 @@ tools/firecracker-builder-stamp: tools/docker/Dockerfile.firecracker-builder
 
 $(FIRECRACKER_BIN) $(JAILER_BIN): $(FIRECRACKER_DIR)/Cargo.toml tools/firecracker-builder-stamp
 	docker run --rm -it --user $(UID) \
-		--volume $(CURDIR)/$(FIRECRACKER_DIR):/src \
+		--volume $(PWD)/$(FIRECRACKER_DIR):/src \
 		--volume $(CARGO_CACHE_VOLUME_NAME):/usr/local/cargo/registry \
 		-e HOME=/tmp \
 		--workdir /src \
@@ -193,7 +193,7 @@ $(FIRECRACKER_BIN) $(JAILER_BIN): $(FIRECRACKER_DIR)/Cargo.toml tools/firecracke
 firecracker-clean:
 	rm -f $(FIRECRACKER_BIN) $(JAILER_BIN)
 	- docker run --rm -it --user $(UID) \
-		--volume $(CURDIR)/$(FIRECRACKER_DIR):/src \
+		--volume $(PWD)/$(FIRECRACKER_DIR):/src \
 		-e HOME=/tmp \
 		--workdir /src \
 		localhost/$(FIRECRACKER_BUILDER_NAME):$(DOCKER_IMAGE_TAG) \
@@ -217,8 +217,8 @@ tools/runc-builder-stamp: tools/docker/Dockerfile.runc-builder
 
 $(RUNC_BIN): $(RUNC_DIR)/VERSION tools/runc-builder-stamp
 	docker run --rm -it --user $(UID) \
-		--volume $(CURDIR)/$(RUNC_DIR):/gopath/src/github.com/opencontainers/runc \
-		--volume $(CURDIR)/deps:/target \
+		--volume $(PWD)/$(RUNC_DIR):/gopath/src/github.com/opencontainers/runc \
+		--volume $(PWD)/deps:/target \
 		-e HOME=/tmp \
 		-e GOPATH=/gopath \
 		--workdir /gopath/src/github.com/opencontainers/runc \
diff --git a/README.md b/README.md
index e6d7500..fffb8fb 100644
--- a/README.md
+++ b/README.md
@@ -60,18 +60,14 @@ For more detailed information on the components and how they work, see
 
 ## Roadmap
 
-To support the widest variety of workloads, firecracker-containerd has to work
-with popular container orchestration frameworks such as Kubernetes and Amazon
-ECS, so we will work to ensure that the software is conformant or compatible
-where necessary.  The project currently allows you to launch a few containers
-colocated in the same microVM, and we are exploring how to raise the number of
-containers.  We recently added support for configuring networking at the microVM
-level with CNI plugins and provide a CNI plugin suitable for chaining called
-"tc-redirect-tap".  Our short term roadmap includes constraining or "jailing"
-the Firecracker VMM process to improve the host security posture.  Our
-longer-term roadmap includes polishing, packaging, and generally making
-firecracker-containerd easier to run as well as exploring CRI conformance and
-compatibility with Kubernetes.
+Initially, this project allows you to launch one container per microVM.  We
+intend it to be a drop-in component that can run a variety of containerized
+applications, so the short term roadmap contains work to support container
+standards such as OCI and CNI. In addition, we intend to support launching
+multiple containers inside of one microVM.  To support the widest variety of
+workloads, the new runtime component has to work with popular container
+orchestration frameworks such as Kubernetes and Amazon ECS, so we will work to
+ensure that the software is conformant or compatible where necessary.
 
 Details of specific roadmap items are tracked in [GitHub
 issues](https://github.com/firecracker-microvm/firecracker-containerd/issues).
diff --git a/firecracker-control/local.go b/firecracker-control/local.go
index 74d233a..24e934b 100644
--- a/firecracker-control/local.go
+++ b/firecracker-control/local.go
@@ -280,12 +280,6 @@ func (s *local) newShim(ns, vmID, containerdAddress string, shimSocket *net.Unix
 		return nil, err
 	}
 
-	// note: The working dir of the shim has an effect on the length of the path
-	// needed to specify various unix sockets that the shim uses to communicate
-	// with the firecracker VMM and guest agent within. The length of that path
-	// has a relatively low limit (usually 108 chars), so modifying the working
-	// dir should be done with caution. See internal/vm/dir.go for the path
-	// definitions.
 	cmd.Dir = shimDir.RootPath()
 
 	shimSocketFile, err := shimSocket.File()
diff --git a/internal/vm/dir.go b/internal/vm/dir.go
index 00fc041..8281790 100644
--- a/internal/vm/dir.go
+++ b/internal/vm/dir.go
@@ -43,12 +43,7 @@ func ShimDir(namespace, vmID string) (Dir, error) {
 		return "", errors.Wrap(err, "invalid vm id")
 	}
 
-	resolvedVarRunDir, err := filepath.EvalSymlinks(varRunDir)
-	if err != nil {
-		return "", errors.Wrapf(err, "failed evaluating any symlinks in path %q", varRunDir)
-	}
-
-	return Dir(filepath.Join(resolvedVarRunDir, namespace, vmID)), nil
+	return Dir(filepath.Join(varRunDir, namespace, vmID)), nil
 }
 
 // Dir represents the root of a firecracker-containerd VM directory, which
@@ -88,24 +83,12 @@ func (d Dir) FirecrackerSockPath() string {
 	return filepath.Join(d.RootPath(), internal.FirecrackerSockName)
 }
 
-// FirecrackerSockRelPath returns the path to FirecrackerSockPath relative to the
-// current working directory
-func (d Dir) FirecrackerSockRelPath() (string, error) {
-	return relPathTo(d.FirecrackerSockPath())
-}
-
 // FirecrackerVSockPath returns the path to the vsock unix socket that the runtime uses
 // to communicate with the VM agent.
 func (d Dir) FirecrackerVSockPath() string {
 	return filepath.Join(d.RootPath(), internal.FirecrackerVSockName)
 }
 
-// FirecrackerVSockRelPath returns the path to FirecrackerVSockPath relative to the
-// current working directory
-func (d Dir) FirecrackerVSockRelPath() (string, error) {
-	return relPathTo(d.FirecrackerVSockPath())
-}
-
 // FirecrackerLogFifoPath returns the path to the FIFO at which the firecracker VMM writes
 // its logs
 func (d Dir) FirecrackerLogFifoPath() string {
@@ -174,17 +157,3 @@ func createSymlink(oldPath, newPath string, errMsgName string) error {
 
 	return nil
 }
-
-func relPathTo(absPath string) (string, error) {
-	cwd, err := os.Getwd()
-	if err != nil {
-		return "", errors.Wrapf(err, "failed to get current working directory")
-	}
-
-	relPath, err := filepath.Rel(cwd, absPath)
-	if err != nil {
-		return "", errors.Wrapf(err, "failed to get relative path from %q to %q", cwd, absPath)
-	}
-
-	return relPath, nil
-}
diff --git a/proto/events.pb.go b/proto/events.pb.go
index 95486da..a191bfd 100644
--- a/proto/events.pb.go
+++ b/proto/events.pb.go
@@ -21,7 +21,7 @@ var _ = math.Inf
 const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 
 type VMStart struct {
-	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
+	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -59,7 +59,7 @@ func (m *VMStart) GetVMID() string {
 }
 
 type VMStop struct {
-	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
+	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -104,11 +104,11 @@ func init() {
 func init() { proto.RegisterFile("events.proto", fileDescriptor_8f22242cb04491f9) }
 
 var fileDescriptor_8f22242cb04491f9 = []byte{
-	// 84 bytes of a gzipped FileDescriptorProto
+	// 81 bytes of a gzipped FileDescriptorProto
 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x2d, 0x4b, 0xcd,
 	0x2b, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x57, 0x92, 0xe5, 0x62, 0x0f, 0xf3, 0x0d, 0x2e,
 	0x49, 0x2c, 0x2a, 0x11, 0x12, 0xe2, 0x62, 0x09, 0xf3, 0xf5, 0x74, 0x91, 0x60, 0x54, 0x60, 0xd4,
-	0xe0, 0x0c, 0x62, 0x29, 0xf3, 0xf5, 0x74, 0x51, 0x92, 0xe1, 0x62, 0x03, 0x49, 0xe7, 0x17, 0x60,
-	0x93, 0x4d, 0x62, 0x03, 0x9b, 0x61, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x8a, 0x85, 0x02,
-	0x53, 0x00, 0x00, 0x00,
+	0xe0, 0x0c, 0x02, 0xb3, 0x95, 0x64, 0xb8, 0xd8, 0x40, 0xd2, 0xf9, 0x05, 0xd8, 0x64, 0x93, 0xd8,
+	0xc0, 0x66, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x83, 0xd8, 0x3c, 0x53, 0x00, 0x00,
+	0x00,
 }
diff --git a/proto/firecracker.pb.go b/proto/firecracker.pb.go
index 2df343d..f363aae 100644
--- a/proto/firecracker.pb.go
+++ b/proto/firecracker.pb.go
@@ -23,23 +23,23 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 // CreateVMRequest specifies creation parameters for a new FC instance
 type CreateVMRequest struct {
 	// VM identifier to assign
-	VMID string `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
+	VMID string `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
 	// Specifies the machine configuration for the VM
-	MachineCfg *FirecrackerMachineConfiguration `protobuf:"bytes,2,opt,name=MachineCfg,json=machineCfg,proto3" json:"MachineCfg,omitempty"`
+	MachineCfg *FirecrackerMachineConfiguration `protobuf:"bytes,2,opt,name=MachineCfg,proto3" json:"MachineCfg,omitempty"`
 	// Specifies the file path where the kernel image is located
-	KernelImagePath string `protobuf:"bytes,3,opt,name=KernelImagePath,json=kernelImagePath,proto3" json:"KernelImagePath,omitempty"`
+	KernelImagePath string `protobuf:"bytes,3,opt,name=KernelImagePath,proto3" json:"KernelImagePath,omitempty"`
 	// Specifies the commandline arguments that should be passed to the kernel
-	KernelArgs string `protobuf:"bytes,4,opt,name=KernelArgs,json=kernelArgs,proto3" json:"KernelArgs,omitempty"`
+	KernelArgs string `protobuf:"bytes,4,opt,name=KernelArgs,proto3" json:"KernelArgs,omitempty"`
 	// Specifies the root block device for the VM
-	RootDrive *FirecrackerDrive `protobuf:"bytes,5,opt,name=RootDrive,json=rootDrive,proto3" json:"RootDrive,omitempty"`
+	RootDrive *FirecrackerDrive `protobuf:"bytes,5,opt,name=RootDrive,proto3" json:"RootDrive,omitempty"`
 	// Specifies the additional block device config for the VM.
-	AdditionalDrives []*FirecrackerDrive `protobuf:"bytes,6,rep,name=AdditionalDrives,json=additionalDrives,proto3" json:"AdditionalDrives,omitempty"`
+	AdditionalDrives []*FirecrackerDrive `protobuf:"bytes,6,rep,name=AdditionalDrives,proto3" json:"AdditionalDrives,omitempty"`
 	// Specifies the networking configuration for a VM
-	NetworkInterfaces []*FirecrackerNetworkInterface `protobuf:"bytes,7,rep,name=NetworkInterfaces,json=networkInterfaces,proto3" json:"NetworkInterfaces,omitempty"`
+	NetworkInterfaces []*FirecrackerNetworkInterface `protobuf:"bytes,7,rep,name=NetworkInterfaces,proto3" json:"NetworkInterfaces,omitempty"`
 	// The number of dummy drives to reserve in advance before running FC instance.
-	ContainerCount int32 `protobuf:"varint,8,opt,name=ContainerCount,json=containerCount,proto3" json:"ContainerCount,omitempty"`
+	ContainerCount int32 `protobuf:"varint,8,opt,name=ContainerCount,proto3" json:"ContainerCount,omitempty"`
 	// Whether the VM should exit after all tasks running in it have been deleted.
-	ExitAfterAllTasksDeleted bool     `protobuf:"varint,9,opt,name=ExitAfterAllTasksDeleted,json=exitAfterAllTasksDeleted,proto3" json:"ExitAfterAllTasksDeleted,omitempty"`
+	ExitAfterAllTasksDeleted bool     `protobuf:"varint,9,opt,name=ExitAfterAllTasksDeleted,proto3" json:"ExitAfterAllTasksDeleted,omitempty"`
 	XXX_NoUnkeyedLiteral     struct{} `json:"-"`
 	XXX_unrecognized         []byte   `json:"-"`
 	XXX_sizecache            int32    `json:"-"`
@@ -133,7 +133,8 @@ func (m *CreateVMRequest) GetExitAfterAllTasksDeleted() bool {
 }
 
 type StopVMRequest struct {
-	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
+	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
+	TimeoutSeconds       uint32   `protobuf:"varint,2,opt,name=TimeoutSeconds,proto3" json:"TimeoutSeconds,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -170,8 +171,15 @@ func (m *StopVMRequest) GetVMID() string {
 	return ""
 }
 
+func (m *StopVMRequest) GetTimeoutSeconds() uint32 {
+	if m != nil {
+		return m.TimeoutSeconds
+	}
+	return 0
+}
+
 type GetVMInfoRequest struct {
-	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
+	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -209,11 +217,11 @@ func (m *GetVMInfoRequest) GetVMID() string {
 }
 
 type GetVMInfoResponse struct {
-	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
-	ContextID            uint32   `protobuf:"varint,2,opt,name=ContextID,json=contextID,proto3" json:"ContextID,omitempty"`
-	SocketPath           string   `protobuf:"bytes,3,opt,name=SocketPath,json=socketPath,proto3" json:"SocketPath,omitempty"`
-	LogFifoPath          string   `protobuf:"bytes,4,opt,name=LogFifoPath,json=logFifoPath,proto3" json:"LogFifoPath,omitempty"`
-	MetricsFifoPath      string   `protobuf:"bytes,5,opt,name=MetricsFifoPath,json=metricsFifoPath,proto3" json:"MetricsFifoPath,omitempty"`
+	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
+	ContextID            uint32   `protobuf:"varint,2,opt,name=ContextID,proto3" json:"ContextID,omitempty"`
+	SocketPath           string   `protobuf:"bytes,3,opt,name=SocketPath,proto3" json:"SocketPath,omitempty"`
+	LogFifoPath          string   `protobuf:"bytes,4,opt,name=LogFifoPath,proto3" json:"LogFifoPath,omitempty"`
+	MetricsFifoPath      string   `protobuf:"bytes,5,opt,name=MetricsFifoPath,proto3" json:"MetricsFifoPath,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -279,8 +287,8 @@ func (m *GetVMInfoResponse) GetMetricsFifoPath() string {
 }
 
 type SetVMMetadataRequest struct {
-	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,json=vMID,proto3" json:"VMID,omitempty"`
-	Metadata             string   `protobuf:"bytes,2,opt,name=Metadata,json=metadata,proto3" json:"Metadata,omitempty"`
+	VMID                 string   `protobuf:"bytes,1,opt,name=VMID,proto3" json:"VMID,omitempty"`
+	Metadata             string   `protobuf:"bytes,2,opt,name=Metadata,proto3" json:"Metadata,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -335,33 +343,33 @@ func init() {
 func init() { proto.RegisterFile("firecracker.proto", fileDescriptor_a73317e9fb8da571) }
 
 var fileDescriptor_a73317e9fb8da571 = []byte{
-	// 448 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x51, 0x8f, 0xd2, 0x40,
-	0x14, 0x85, 0x53, 0x81, 0x5d, 0x7a, 0xc9, 0x2e, 0x30, 0xf1, 0x61, 0xb2, 0xd9, 0x98, 0x06, 0x93,
-	0x0d, 0x4f, 0x6b, 0xa2, 0x6f, 0x26, 0x26, 0x22, 0x15, 0x53, 0xb5, 0xc6, 0x0c, 0x86, 0x07, 0xdf,
-	0xc6, 0x72, 0xdb, 0x9d, 0xb4, 0xcc, 0xe0, 0xcc, 0x65, 0x5d, 0x7f, 0x96, 0x3f, 0xc5, 0x7f, 0x64,
-	0x3a, 0x08, 0x0b, 0x64, 0x97, 0xa7, 0x66, 0xce, 0xfd, 0x4e, 0x7b, 0x9a, 0x7b, 0x06, 0xfa, 0xb9,
-	0xb2, 0x98, 0x59, 0x99, 0x95, 0x68, 0xaf, 0x97, 0xd6, 0x90, 0xb9, 0xe8, 0xd0, 0xef, 0x25, 0xba,
-	0xf5, 0x61, 0xf0, 0xb7, 0x01, 0xdd, 0xb1, 0x45, 0x49, 0x38, 0x4b, 0x05, 0xfe, 0x5c, 0xa1, 0x23,
-	0xc6, 0xa0, 0x39, 0x4b, 0x93, 0x98, 0x07, 0x51, 0x30, 0x0c, 0x45, 0xf3, 0x36, 0x4d, 0x62, 0xf6,
-	0x16, 0x20, 0x95, 0xd9, 0x8d, 0xd2, 0x38, 0xce, 0x0b, 0xfe, 0x24, 0x0a, 0x86, 0x9d, 0x97, 0xd1,
-	0xf5, 0xe4, 0xfe, 0xe5, 0x9b, 0xa9, 0xd1, 0xb9, 0x2a, 0x56, 0x56, 0x92, 0x32, 0x5a, 0xc0, 0x62,
-	0xeb, 0x61, 0x43, 0xe8, 0x7e, 0x42, 0xab, 0xb1, 0x4a, 0x16, 0xb2, 0xc0, 0xaf, 0x92, 0x6e, 0x78,
-	0xc3, 0x7f, 0xa0, 0x5b, 0xee, 0xcb, 0xec, 0x19, 0xc0, 0x9a, 0x1c, 0xd9, 0xc2, 0xf1, 0xa6, 0x87,
-	0xa0, 0xdc, 0x2a, 0xec, 0x05, 0x84, 0xc2, 0x18, 0x8a, 0xad, 0xba, 0x45, 0xde, 0xf2, 0x51, 0xfa,
-	0xbb, 0x51, 0xfc, 0x40, 0x84, 0x76, 0xc3, 0xb0, 0x37, 0xd0, 0x1b, 0xcd, 0xe7, 0xaa, 0x8e, 0x24,
-	0x2b, 0x2f, 0x39, 0x7e, 0x12, 0x35, 0x1e, 0xf6, 0xf5, 0xe4, 0x01, 0xca, 0x3e, 0x42, 0xff, 0x0b,
-	0xd2, 0x2f, 0x63, 0xcb, 0x44, 0x13, 0xda, 0x5c, 0x66, 0xe8, 0xf8, 0xa9, 0xf7, 0x5f, 0xee, 0xfa,
-	0x0f, 0x21, 0xd1, 0xd7, 0x87, 0x36, 0x76, 0x05, 0xe7, 0x63, 0xa3, 0x49, 0x2a, 0x8d, 0x76, 0x6c,
-	0x56, 0x9a, 0x78, 0x3b, 0x0a, 0x86, 0x2d, 0x71, 0x9e, 0xed, 0xa9, 0xec, 0x35, 0xf0, 0xf7, 0x77,
-	0x8a, 0x46, 0x39, 0xa1, 0x1d, 0x55, 0xd5, 0x37, 0xe9, 0x4a, 0x17, 0x63, 0x85, 0x84, 0x73, 0x1e,
-	0x46, 0xc1, 0xb0, 0x2d, 0x38, 0x3e, 0x32, 0x1f, 0x3c, 0x87, 0xb3, 0x29, 0x99, 0xe5, 0xd1, 0x85,
-	0x0e, 0xae, 0xa0, 0xf7, 0x01, 0x69, 0x96, 0x26, 0x3a, 0x37, 0xc7, 0xb8, 0x3f, 0x01, 0xf4, 0x77,
-	0x40, 0xb7, 0x34, 0xda, 0xe1, 0x83, 0x15, 0xb9, 0x84, 0xb0, 0xfe, 0x35, 0xbc, 0xa3, 0x24, 0xf6,
-	0x0d, 0x39, 0x13, 0x61, 0xb6, 0x11, 0xea, 0xa5, 0x4e, 0x4d, 0x56, 0x22, 0xed, 0x6c, 0x1e, 0xdc,
-	0x56, 0x61, 0x11, 0x74, 0x3e, 0x9b, 0x62, 0xa2, 0x72, 0xe3, 0x81, 0xf5, 0xd6, 0x3b, 0xd5, 0xbd,
-	0x54, 0x17, 0x28, 0x45, 0xb2, 0x2a, 0x73, 0x5b, 0xaa, 0xb5, 0x2e, 0xd0, 0x62, 0x5f, 0x1e, 0x4c,
-	0xe0, 0xe9, 0xb4, 0x8e, 0x9c, 0x22, 0xc9, 0xb9, 0x24, 0x79, 0xac, 0xd8, 0x17, 0xd0, 0xde, 0x60,
-	0x3e, 0x74, 0x28, 0xda, 0x8b, 0xff, 0xe7, 0x77, 0xa7, 0xdf, 0x5b, 0xfe, 0x96, 0xfc, 0x38, 0xf1,
-	0x8f, 0x57, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x7a, 0x64, 0xe9, 0x4e, 0x03, 0x00, 0x00,
+	// 446 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x93, 0x4f, 0x6f, 0xd3, 0x4c,
+	0x10, 0xc6, 0xe5, 0x37, 0x4d, 0x1b, 0x4f, 0xd4, 0x3f, 0x59, 0xbd, 0x87, 0x55, 0x55, 0x21, 0xcb,
+	0x87, 0xc8, 0xa7, 0x22, 0xc1, 0x0d, 0x09, 0x89, 0x90, 0x10, 0x64, 0x8a, 0x11, 0xda, 0x54, 0x39,
+	0x70, 0x5b, 0xec, 0xb1, 0xbb, 0x8a, 0xbb, 0x1b, 0x76, 0x27, 0x50, 0x3e, 0x16, 0x1f, 0x85, 0x6f,
+	0x84, 0xbc, 0xa1, 0x8d, 0xe5, 0x96, 0x9c, 0x92, 0xfd, 0xcd, 0xf3, 0xec, 0x3c, 0xf6, 0x8c, 0x61,
+	0x54, 0x2a, 0x8b, 0xb9, 0x95, 0xf9, 0x0a, 0xed, 0xe5, 0xda, 0x1a, 0x32, 0xe7, 0x43, 0xfa, 0xb9,
+	0x46, 0xb7, 0x3d, 0xc4, 0xbf, 0x7b, 0x70, 0x3a, 0xb5, 0x28, 0x09, 0x97, 0x99, 0xc0, 0x6f, 0x1b,
+	0x74, 0xc4, 0x18, 0x1c, 0x2c, 0xb3, 0x74, 0xc6, 0x83, 0x28, 0x48, 0x42, 0xe1, 0xff, 0xb3, 0x37,
+	0x00, 0x99, 0xcc, 0x6f, 0x94, 0xc6, 0x69, 0x59, 0xf1, 0xff, 0xa2, 0x20, 0x19, 0xbe, 0x88, 0x2e,
+	0xe7, 0xbb, 0xcb, 0xef, 0xab, 0x46, 0x97, 0xaa, 0xda, 0x58, 0x49, 0xca, 0x68, 0xd1, 0xf2, 0xb0,
+	0x04, 0x4e, 0xaf, 0xd0, 0x6a, 0xac, 0xd3, 0x5b, 0x59, 0xe1, 0x67, 0x49, 0x37, 0xbc, 0xe7, 0x1b,
+	0x74, 0x31, 0x7b, 0x06, 0xb0, 0x45, 0x13, 0x5b, 0x39, 0x7e, 0xe0, 0x45, 0x2d, 0xc2, 0x9e, 0x43,
+	0x28, 0x8c, 0xa1, 0x99, 0x55, 0xdf, 0x91, 0xf7, 0x7d, 0x94, 0x51, 0x3b, 0x8a, 0x2f, 0x88, 0x9d,
+	0x86, 0xbd, 0x86, 0xb3, 0x49, 0x51, 0xa8, 0x26, 0x92, 0xac, 0x3d, 0x72, 0xfc, 0x30, 0xea, 0x3d,
+	0xed, 0x7b, 0x24, 0x65, 0x1f, 0x60, 0xf4, 0x09, 0xe9, 0x87, 0xb1, 0xab, 0x54, 0x13, 0xda, 0x52,
+	0xe6, 0xe8, 0xf8, 0x91, 0xf7, 0x5f, 0xb4, 0xfd, 0x5d, 0x91, 0x78, 0x6c, 0x63, 0x63, 0x38, 0x99,
+	0x1a, 0x4d, 0x52, 0x69, 0xb4, 0x53, 0xb3, 0xd1, 0xc4, 0x07, 0x51, 0x90, 0xf4, 0x45, 0x87, 0xb2,
+	0x57, 0xc0, 0xdf, 0xdd, 0x29, 0x9a, 0x94, 0x84, 0x76, 0x52, 0xd7, 0xd7, 0xd2, 0xad, 0xdc, 0x0c,
+	0x6b, 0x24, 0x2c, 0x78, 0x18, 0x05, 0xc9, 0x40, 0xfc, 0xb3, 0x1e, 0x5f, 0xc1, 0xf1, 0x82, 0xcc,
+	0x7a, 0xff, 0x40, 0xc7, 0x70, 0x72, 0xad, 0x6e, 0xd1, 0x6c, 0x68, 0x81, 0xb9, 0xd1, 0x85, 0xf3,
+	0x43, 0x3d, 0x16, 0x1d, 0x1a, 0x8f, 0xe1, 0xec, 0x3d, 0xd2, 0x32, 0x4b, 0x75, 0x69, 0xf6, 0xdc,
+	0x17, 0xff, 0x0a, 0x60, 0xd4, 0x12, 0xba, 0xb5, 0xd1, 0x0e, 0x9f, 0xec, 0x7c, 0x01, 0x61, 0xf3,
+	0xb0, 0x78, 0x47, 0xe9, 0xec, 0x6f, 0xd3, 0x1d, 0x68, 0x86, 0xbf, 0x30, 0xf9, 0x0a, 0xa9, 0xb5,
+	0x21, 0x2d, 0xc2, 0x22, 0x18, 0x7e, 0x34, 0xd5, 0x5c, 0x95, 0xc6, 0x0b, 0xb6, 0xdb, 0xd1, 0x46,
+	0xcd, 0xa2, 0x65, 0x48, 0x56, 0xe5, 0xee, 0x41, 0xd5, 0xdf, 0x2e, 0x5a, 0x07, 0xc7, 0x73, 0xf8,
+	0x7f, 0xd1, 0x44, 0xce, 0x90, 0x64, 0x21, 0x49, 0xee, 0x7b, 0x5f, 0xe7, 0x30, 0xb8, 0x97, 0xf9,
+	0xd0, 0xa1, 0x78, 0x38, 0xbf, 0x3d, 0xfa, 0xd2, 0xf7, 0x5f, 0xd3, 0xd7, 0x43, 0xff, 0xf3, 0xf2,
+	0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xad, 0x3b, 0x3d, 0xc6, 0x76, 0x03, 0x00, 0x00,
 }
diff --git a/proto/firecracker.proto b/proto/firecracker.proto
index bc2a5ed..e04caf7 100644
--- a/proto/firecracker.proto
+++ b/proto/firecracker.proto
@@ -36,6 +36,7 @@ message CreateVMRequest {
 
 message StopVMRequest {
     string VMID = 1;
+    uint32 TimeoutSeconds = 2;
 }
 
 message GetVMInfoRequest {
diff --git a/proto/types.pb.go b/proto/types.pb.go
index 14b7cb2..09fdf9d 100644
--- a/proto/types.pb.go
+++ b/proto/types.pb.go
@@ -23,12 +23,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 
 // Message to store bundle/config.json bytes
 type ExtraData struct {
-	JsonSpec             []byte     `protobuf:"bytes,1,opt,name=JsonSpec,json=jsonSpec,proto3" json:"JsonSpec,omitempty"`
-	RuncOptions          *types.Any `protobuf:"bytes,2,opt,name=RuncOptions,json=runcOptions,proto3" json:"RuncOptions,omitempty"`
-	StdinPort            uint32     `protobuf:"varint,3,opt,name=StdinPort,json=stdinPort,proto3" json:"StdinPort,omitempty"`
-	StdoutPort           uint32     `protobuf:"varint,4,opt,name=StdoutPort,json=stdoutPort,proto3" json:"StdoutPort,omitempty"`
-	StderrPort           uint32     `protobuf:"varint,5,opt,name=StderrPort,json=stderrPort,proto3" json:"StderrPort,omitempty"`
-	DriveID              string     `protobuf:"bytes,6,opt,name=DriveID,json=driveID,proto3" json:"DriveID,omitempty"`
+	JsonSpec             []byte     `protobuf:"bytes,1,opt,name=JsonSpec,proto3" json:"JsonSpec,omitempty"`
+	RuncOptions          *types.Any `protobuf:"bytes,2,opt,name=RuncOptions,proto3" json:"RuncOptions,omitempty"`
+	StdinPort            uint32     `protobuf:"varint,3,opt,name=StdinPort,proto3" json:"StdinPort,omitempty"`
+	StdoutPort           uint32     `protobuf:"varint,4,opt,name=StdoutPort,proto3" json:"StdoutPort,omitempty"`
+	StderrPort           uint32     `protobuf:"varint,5,opt,name=StderrPort,proto3" json:"StderrPort,omitempty"`
+	DriveID              string     `protobuf:"bytes,6,opt,name=DriveID,proto3" json:"DriveID,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}   `json:"-"`
 	XXX_unrecognized     []byte     `json:"-"`
 	XXX_sizecache        int32      `json:"-"`
@@ -102,15 +102,15 @@ func (m *ExtraData) GetDriveID() string {
 
 // Message to specify network config for a Firecracker VM
 type FirecrackerNetworkInterface struct {
-	AllowMMDS      bool                    `protobuf:"varint,1,opt,name=AllowMMDS,json=allowMMDS,proto3" json:"AllowMMDS,omitempty"`
-	InRateLimiter  *FirecrackerRateLimiter `protobuf:"bytes,2,opt,name=InRateLimiter,json=inRateLimiter,proto3" json:"InRateLimiter,omitempty"`
-	OutRateLimiter *FirecrackerRateLimiter `protobuf:"bytes,3,opt,name=OutRateLimiter,json=outRateLimiter,proto3" json:"OutRateLimiter,omitempty"`
+	AllowMMDS      bool                    `protobuf:"varint,1,opt,name=AllowMMDS,proto3" json:"AllowMMDS,omitempty"`
+	InRateLimiter  *FirecrackerRateLimiter `protobuf:"bytes,2,opt,name=InRateLimiter,proto3" json:"InRateLimiter,omitempty"`
+	OutRateLimiter *FirecrackerRateLimiter `protobuf:"bytes,3,opt,name=OutRateLimiter,proto3" json:"OutRateLimiter,omitempty"`
 	// CNIConfiguration specifies CNI configuration that will be used to generate
 	// a network interface for a Firecracker VM.
-	CNIConfig *CNIConfiguration `protobuf:"bytes,4,opt,name=CNIConfig,json=cNIConfig,proto3" json:"CNIConfig,omitempty"`
+	CNIConfig *CNIConfiguration `protobuf:"bytes,4,opt,name=CNIConfig,proto3" json:"CNIConfig,omitempty"`
 	// StaticNetworkConfiguration specifies static configuration parameters for a
 	// Firecracker VM's network interface
-	StaticConfig         *StaticNetworkConfiguration `protobuf:"bytes,5,opt,name=StaticConfig,json=staticConfig,proto3" json:"StaticConfig,omitempty"`
+	StaticConfig         *StaticNetworkConfiguration `protobuf:"bytes,5,opt,name=StaticConfig,proto3" json:"StaticConfig,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}                    `json:"-"`
 	XXX_unrecognized     []byte                      `json:"-"`
 	XXX_sizecache        int32                       `json:"-"`
@@ -181,23 +181,23 @@ type CNIConfiguration struct {
 	// NetworkName is the name of a CNI network (as found in CNI
 	// configuration files) that will be used to generate the
 	// network interface.
-	NetworkName string `protobuf:"bytes,1,opt,name=NetworkName,json=networkName,proto3" json:"NetworkName,omitempty"`
+	NetworkName string `protobuf:"bytes,1,opt,name=NetworkName,proto3" json:"NetworkName,omitempty"`
 	// InterfaceName corresponds to the CNI_IFNAME parameter that will be
 	// provided to CNI plugins during invocation.
-	InterfaceName string `protobuf:"bytes,2,opt,name=InterfaceName,json=interfaceName,proto3" json:"InterfaceName,omitempty"`
+	InterfaceName string `protobuf:"bytes,2,opt,name=InterfaceName,proto3" json:"InterfaceName,omitempty"`
 	// BinPath is a list of directories that will be searched when
 	// looking for CNI plugin binaries. Defaults to just "/opt/cni/bin"
-	BinPath []string `protobuf:"bytes,3,rep,name=BinPath,json=binPath,proto3" json:"BinPath,omitempty"`
+	BinPath []string `protobuf:"bytes,3,rep,name=BinPath,proto3" json:"BinPath,omitempty"`
 	// ConfDir is the directory in which CNI configuration will be sought.
 	// If not specified, will default to "/etc/cni/conf.d".
-	ConfDir string `protobuf:"bytes,4,opt,name=ConfDir,json=confDir,proto3" json:"ConfDir,omitempty"`
+	ConfDir string `protobuf:"bytes,4,opt,name=ConfDir,proto3" json:"ConfDir,omitempty"`
 	// CacheDir is the directory in which CNI results will be temporarily
 	// cached by the runtime. If not specified, it will default to
 	// "/var/lib/cni"
-	CacheDir string `protobuf:"bytes,5,opt,name=CacheDir,json=cacheDir,proto3" json:"CacheDir,omitempty"`
+	CacheDir string `protobuf:"bytes,5,opt,name=CacheDir,proto3" json:"CacheDir,omitempty"`
 	// Args corresponds to the CNI_ARGS parameter that will be provided to
 	// CNI plugins on invocation.
-	Args                 []*CNIConfiguration_CNIArg `protobuf:"bytes,6,rep,name=Args,json=args,proto3" json:"Args,omitempty"`
+	Args                 []*CNIConfiguration_CNIArg `protobuf:"bytes,6,rep,name=Args,proto3" json:"Args,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}                   `json:"-"`
 	XXX_unrecognized     []byte                     `json:"-"`
 	XXX_sizecache        int32                      `json:"-"`
@@ -270,8 +270,8 @@ func (m *CNIConfiguration) GetArgs() []*CNIConfiguration_CNIArg {
 }
 
 type CNIConfiguration_CNIArg struct {
-	Key                  string   `protobuf:"bytes,1,opt,name=Key,json=key,proto3" json:"Key,omitempty"`
-	Value                string   `protobuf:"bytes,2,opt,name=Value,json=value,proto3" json:"Value,omitempty"`
+	Key                  string   `protobuf:"bytes,1,opt,name=Key,proto3" json:"Key,omitempty"`
+	Value                string   `protobuf:"bytes,2,opt,name=Value,proto3" json:"Value,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -318,12 +318,12 @@ func (m *CNIConfiguration_CNIArg) GetValue() string {
 // Message to specify static configuration parameters for a
 // Firecracker VM's network interface
 type StaticNetworkConfiguration struct {
-	MacAddress  string `protobuf:"bytes,1,opt,name=MacAddress,json=macAddress,proto3" json:"MacAddress,omitempty"`
-	HostDevName string `protobuf:"bytes,2,opt,name=HostDevName,json=hostDevName,proto3" json:"HostDevName,omitempty"`
+	MacAddress  string `protobuf:"bytes,1,opt,name=MacAddress,proto3" json:"MacAddress,omitempty"`
+	HostDevName string `protobuf:"bytes,2,opt,name=HostDevName,proto3" json:"HostDevName,omitempty"`
 	// IPConfig optionally provides static IP configuration that will be configured
 	// on the VM's internal networking interface. If not specified, no IP
 	// configuration will be applied to the VM's internal nic automatically.
-	IPConfig             *IPConfiguration `protobuf:"bytes,3,opt,name=IPConfig,json=iPConfig,proto3" json:"IPConfig,omitempty"`
+	IPConfig             *IPConfiguration `protobuf:"bytes,3,opt,name=IPConfig,proto3" json:"IPConfig,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}         `json:"-"`
 	XXX_unrecognized     []byte           `json:"-"`
 	XXX_sizecache        int32            `json:"-"`
@@ -380,15 +380,15 @@ type IPConfiguration struct {
 	// PrimaryAddr specifies, in CIDR notation, the primary address
 	// and subnet that a network interface will be assigned inside
 	// the VM.
-	PrimaryAddr string `protobuf:"bytes,1,opt,name=PrimaryAddr,json=primaryAddr,proto3" json:"PrimaryAddr,omitempty"`
+	PrimaryAddr string `protobuf:"bytes,1,opt,name=PrimaryAddr,proto3" json:"PrimaryAddr,omitempty"`
 	// GatewayAddr specifies the default gateway that a network interface
 	// should use inside the VM.
-	GatewayAddr string `protobuf:"bytes,3,opt,name=GatewayAddr,json=gatewayAddr,proto3" json:"GatewayAddr,omitempty"`
+	GatewayAddr string `protobuf:"bytes,3,opt,name=GatewayAddr,proto3" json:"GatewayAddr,omitempty"`
 	// Nameservers is a list of nameservers that the VM will be configured
 	// to use internally. Currently only up to 2 nameservers can be specified
 	// (any more in the list will be ignored) and configuration is provided
 	// to the VM via /proc/net/pnp.
-	Nameservers          []string `protobuf:"bytes,4,rep,name=Nameservers,json=nameservers,proto3" json:"Nameservers,omitempty"`
+	Nameservers          []string `protobuf:"bytes,4,rep,name=Nameservers,proto3" json:"Nameservers,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -441,13 +441,13 @@ func (m *IPConfiguration) GetNameservers() []string {
 
 // Message to set the machine config for a Firecracker VM
 type FirecrackerMachineConfiguration struct {
-	CPUTemplate string `protobuf:"bytes,1,opt,name=CPUTemplate,json=cPUTemplate,proto3" json:"CPUTemplate,omitempty"`
-	HtEnabled   bool   `protobuf:"varint,2,opt,name=HtEnabled,json=htEnabled,proto3" json:"HtEnabled,omitempty"`
+	CPUTemplate string `protobuf:"bytes,1,opt,name=CPUTemplate,proto3" json:"CPUTemplate,omitempty"`
+	HtEnabled   bool   `protobuf:"varint,2,opt,name=HtEnabled,proto3" json:"HtEnabled,omitempty"`
 	// Specifies the memory size of VM
 	// This lets us create a Firecracker VM of up to 4096 TiB, which
 	// for a microVM should be large enough
-	MemSizeMib           uint32   `protobuf:"varint,3,opt,name=MemSizeMib,json=memSizeMib,proto3" json:"MemSizeMib,omitempty"`
-	VcpuCount            uint32   `protobuf:"varint,4,opt,name=VcpuCount,json=vcpuCount,proto3" json:"VcpuCount,omitempty"`
+	MemSizeMib           uint32   `protobuf:"varint,3,opt,name=MemSizeMib,proto3" json:"MemSizeMib,omitempty"`
+	VcpuCount            uint32   `protobuf:"varint,4,opt,name=VcpuCount,proto3" json:"VcpuCount,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -507,11 +507,11 @@ func (m *FirecrackerMachineConfiguration) GetVcpuCount() uint32 {
 
 // Message to specify the block device config for a Firecracker VM
 type FirecrackerDrive struct {
-	IsReadOnly           bool                    `protobuf:"varint,1,opt,name=IsReadOnly,json=isReadOnly,proto3" json:"IsReadOnly,omitempty"`
-	IsRootDevice         bool                    `protobuf:"varint,2,opt,name=IsRootDevice,json=isRootDevice,proto3" json:"IsRootDevice,omitempty"`
-	Partuuid             string                  `protobuf:"bytes,3,opt,name=Partuuid,json=partuuid,proto3" json:"Partuuid,omitempty"`
-	PathOnHost           string                  `protobuf:"bytes,4,opt,name=PathOnHost,json=pathOnHost,proto3" json:"PathOnHost,omitempty"`
-	RateLimiter          *FirecrackerRateLimiter `protobuf:"bytes,5,opt,name=RateLimiter,json=rateLimiter,proto3" json:"RateLimiter,omitempty"`
+	IsReadOnly           bool                    `protobuf:"varint,1,opt,name=IsReadOnly,proto3" json:"IsReadOnly,omitempty"`
+	IsRootDevice         bool                    `protobuf:"varint,2,opt,name=IsRootDevice,proto3" json:"IsRootDevice,omitempty"`
+	Partuuid             string                  `protobuf:"bytes,3,opt,name=Partuuid,proto3" json:"Partuuid,omitempty"`
+	PathOnHost           string                  `protobuf:"bytes,4,opt,name=PathOnHost,proto3" json:"PathOnHost,omitempty"`
+	RateLimiter          *FirecrackerRateLimiter `protobuf:"bytes,5,opt,name=RateLimiter,proto3" json:"RateLimiter,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}                `json:"-"`
 	XXX_unrecognized     []byte                  `json:"-"`
 	XXX_sizecache        int32                   `json:"-"`
@@ -578,8 +578,8 @@ func (m *FirecrackerDrive) GetRateLimiter() *FirecrackerRateLimiter {
 
 // Message to specify an IO rate limiter with bytes/s and ops/s limits
 type FirecrackerRateLimiter struct {
-	Bandwidth            *FirecrackerTokenBucket `protobuf:"bytes,1,opt,name=Bandwidth,json=bandwidth,proto3" json:"Bandwidth,omitempty"`
-	Ops                  *FirecrackerTokenBucket `protobuf:"bytes,2,opt,name=Ops,json=ops,proto3" json:"Ops,omitempty"`
+	Bandwidth            *FirecrackerTokenBucket `protobuf:"bytes,1,opt,name=Bandwidth,proto3" json:"Bandwidth,omitempty"`
+	Ops                  *FirecrackerTokenBucket `protobuf:"bytes,2,opt,name=Ops,proto3" json:"Ops,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}                `json:"-"`
 	XXX_unrecognized     []byte                  `json:"-"`
 	XXX_sizecache        int32                   `json:"-"`
@@ -625,9 +625,9 @@ func (m *FirecrackerRateLimiter) GetOps() *FirecrackerTokenBucket {
 
 // Message to specify a token buicket used to rate limit disk and network IO for a Firecracker VM
 type FirecrackerTokenBucket struct {
-	OneTimeBurst         int64    `protobuf:"varint,1,opt,name=OneTimeBurst,json=oneTimeBurst,proto3" json:"OneTimeBurst,omitempty"`
-	RefillTime           int64    `protobuf:"varint,2,opt,name=RefillTime,json=refillTime,proto3" json:"RefillTime,omitempty"`
-	Capacity             int64    `protobuf:"varint,3,opt,name=Capacity,json=capacity,proto3" json:"Capacity,omitempty"`
+	OneTimeBurst         int64    `protobuf:"varint,1,opt,name=OneTimeBurst,proto3" json:"OneTimeBurst,omitempty"`
+	RefillTime           int64    `protobuf:"varint,2,opt,name=RefillTime,proto3" json:"RefillTime,omitempty"`
+	Capacity             int64    `protobuf:"varint,3,opt,name=Capacity,proto3" json:"Capacity,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -694,58 +694,55 @@ func init() {
 func init() { proto.RegisterFile("types.proto", fileDescriptor_d938547f84707355) }
 
 var fileDescriptor_d938547f84707355 = []byte{
-	// 842 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x95, 0xdd, 0x8e, 0xe3, 0x34,
-	0x14, 0xc7, 0xd5, 0xc9, 0x74, 0xa6, 0x39, 0xe9, 0x2c, 0x83, 0xb5, 0x82, 0x30, 0x8b, 0xa0, 0x8a,
-	0xb8, 0x28, 0xd2, 0xaa, 0x8b, 0x06, 0x81, 0xc4, 0x05, 0x5a, 0xf5, 0x63, 0x61, 0x0b, 0x74, 0x5a,
-	0xb9, 0xc3, 0x5e, 0x70, 0xe7, 0x26, 0x9e, 0xd6, 0x34, 0xb1, 0x23, 0xdb, 0x69, 0xb7, 0xfb, 0x08,
-	0x88, 0x77, 0xe0, 0x09, 0x78, 0x14, 0xae, 0x79, 0x1d, 0x64, 0xc7, 0x49, 0x33, 0xb3, 0xcb, 0x5e,
-	0x55, 0xe7, 0x77, 0xbe, 0xec, 0xff, 0x39, 0x4e, 0x21, 0xd0, 0x87, 0x9c, 0xaa, 0x41, 0x2e, 0x85,
-	0x16, 0x57, 0x9f, 0xac, 0x85, 0x58, 0xa7, 0xf4, 0x99, 0xb5, 0x56, 0xc5, 0xdd, 0x33, 0xc2, 0x0f,
-	0xa5, 0x2b, 0xfa, 0xb7, 0x05, 0xfe, 0x8b, 0xd7, 0x5a, 0x92, 0x09, 0xd1, 0x04, 0x5d, 0x41, 0xe7,
-	0x27, 0x25, 0xf8, 0x32, 0xa7, 0x71, 0xd8, 0xea, 0xb5, 0xfa, 0x5d, 0xdc, 0xf9, 0xdd, 0xd9, 0xe8,
-	0x5b, 0x08, 0x70, 0xc1, 0xe3, 0x79, 0xae, 0x99, 0xe0, 0x2a, 0x3c, 0xe9, 0xb5, 0xfa, 0xc1, 0xf5,
-	0xe3, 0x41, 0x59, 0x7a, 0x50, 0x95, 0x1e, 0x0c, 0xf9, 0x01, 0x07, 0xf2, 0x18, 0x88, 0x3e, 0x05,
-	0x7f, 0xa9, 0x13, 0xc6, 0x17, 0x42, 0xea, 0xd0, 0xeb, 0xb5, 0xfa, 0x17, 0xd8, 0x57, 0x15, 0x40,
-	0x9f, 0x01, 0x2c, 0x75, 0x22, 0x0a, 0x6d, 0xdd, 0xa7, 0xd6, 0x0d, 0xaa, 0x26, 0xce, 0x4f, 0xa5,
-	0xb4, 0xfe, 0x76, 0xed, 0x77, 0x04, 0x85, 0x70, 0x3e, 0x91, 0x6c, 0x47, 0xa7, 0x93, 0xf0, 0xac,
-	0xd7, 0xea, 0xfb, 0xf8, 0x3c, 0x29, 0xcd, 0xe8, 0xef, 0x13, 0x78, 0xf2, 0x03, 0x93, 0x34, 0x96,
-	0x24, 0xde, 0x52, 0x79, 0x43, 0xf5, 0x5e, 0xc8, 0xed, 0x94, 0x6b, 0x2a, 0xef, 0x48, 0x4c, 0xcd,
-	0xb9, 0x86, 0x69, 0x2a, 0xf6, 0xb3, 0xd9, 0x64, 0x69, 0x2f, 0xdb, 0xc1, 0x3e, 0xa9, 0x00, 0xfa,
-	0x1e, 0x2e, 0xa6, 0x1c, 0x13, 0x4d, 0x7f, 0x61, 0x19, 0xd3, 0x54, 0xba, 0xfb, 0x7e, 0x3c, 0x68,
-	0x94, 0x6c, 0xb8, 0xf1, 0x05, 0x6b, 0x46, 0xa3, 0xe7, 0xf0, 0x68, 0x5e, 0xe8, 0x66, 0xbe, 0xf7,
-	0xfe, 0xfc, 0x47, 0xe2, 0x5e, 0x38, 0x7a, 0x06, 0xfe, 0xf8, 0x66, 0x3a, 0x16, 0xfc, 0x8e, 0xad,
-	0xad, 0x2c, 0xc1, 0xf5, 0x87, 0x83, 0x9a, 0x14, 0x92, 0x18, 0x71, 0xb1, 0x1f, 0x57, 0x04, 0x3d,
-	0x87, 0xee, 0x52, 0x13, 0xcd, 0x62, 0x97, 0xd3, 0xb6, 0x39, 0x4f, 0x06, 0x25, 0x74, 0xb7, 0xbf,
-	0x9f, 0xdd, 0x55, 0x8d, 0x84, 0xe8, 0x8f, 0x13, 0xb8, 0x7c, 0xd8, 0x00, 0xf5, 0x20, 0x70, 0xa9,
-	0x37, 0x24, 0xa3, 0x56, 0x26, 0x1f, 0x07, 0xfc, 0x88, 0xd0, 0x17, 0x46, 0x28, 0xa7, 0xa9, 0x8d,
-	0x39, 0xb1, 0x31, 0x17, 0xac, 0x09, 0xcd, 0x98, 0x46, 0x8c, 0x2f, 0x88, 0xde, 0x84, 0x5e, 0xcf,
-	0x33, 0x63, 0x5a, 0x95, 0xa6, 0xf1, 0x98, 0x96, 0x13, 0x26, 0xed, 0x35, 0x7d, 0x7c, 0x1e, 0x97,
-	0xa6, 0x59, 0xc6, 0x31, 0x89, 0x37, 0xd4, 0xb8, 0xda, 0xd6, 0xd5, 0x89, 0x9d, 0x8d, 0x9e, 0xc2,
-	0xe9, 0x50, 0xae, 0x55, 0x78, 0xd6, 0xf3, 0xfa, 0xc1, 0x75, 0xf8, 0x96, 0x32, 0x06, 0x0c, 0xe5,
-	0x1a, 0x9f, 0x12, 0xb9, 0x56, 0x57, 0x5f, 0xc1, 0x59, 0x69, 0xa3, 0x4b, 0xf0, 0x7e, 0xa6, 0x07,
-	0x77, 0x0f, 0x6f, 0x4b, 0x0f, 0xe8, 0x31, 0xb4, 0x5f, 0x91, 0xb4, 0xa8, 0xce, 0xdd, 0xde, 0x19,
-	0x23, 0xfa, 0xb3, 0x05, 0x57, 0xff, 0xaf, 0x9c, 0xd9, 0xca, 0x19, 0x89, 0x87, 0x49, 0x22, 0xa9,
-	0x52, 0xae, 0x1a, 0x64, 0x35, 0x31, 0xb2, 0xbd, 0x14, 0x4a, 0x4f, 0xe8, 0xae, 0x21, 0x49, 0xb0,
-	0x39, 0x22, 0xf4, 0x14, 0x3a, 0xd3, 0x85, 0x1b, 0x55, 0xb9, 0x1a, 0x97, 0x83, 0x0a, 0x54, 0xf3,
-	0xe9, 0x30, 0x07, 0xa2, 0x3d, 0x7c, 0xf0, 0xc0, 0x69, 0x5a, 0x2c, 0x24, 0xcb, 0x88, 0x3c, 0x98,
-	0xa6, 0xd5, 0x64, 0xf2, 0x23, 0x32, 0x11, 0x3f, 0x12, 0x4d, 0xf7, 0xa4, 0x8c, 0xf0, 0xca, 0x88,
-	0xf5, 0x11, 0xd9, 0xe9, 0x92, 0x8c, 0x2a, 0x2a, 0x77, 0x54, 0xaa, 0xf0, 0xd4, 0x4e, 0x26, 0xe0,
-	0x47, 0x14, 0xfd, 0xd5, 0x82, 0xcf, 0x1b, 0x1b, 0x3b, 0x23, 0xf1, 0x86, 0x71, 0xfa, 0xd6, 0x49,
-	0xc6, 0x8b, 0x5f, 0x6f, 0x69, 0x96, 0xa7, 0x44, 0xd7, 0x3b, 0x12, 0x1f, 0x91, 0x79, 0x6a, 0x2f,
-	0xf5, 0x0b, 0x4e, 0x56, 0x29, 0x4d, 0xac, 0x18, 0x1d, 0xec, 0x6f, 0x2a, 0x60, 0xc5, 0xa4, 0xd9,
-	0x92, 0xbd, 0xa1, 0x33, 0xb6, 0x72, 0x5f, 0x08, 0xc8, 0x6a, 0x62, 0xb2, 0x5f, 0xc5, 0x79, 0x31,
-	0x16, 0x05, 0xaf, 0xbe, 0x10, 0xfe, 0xae, 0x02, 0xd1, 0x3f, 0x2d, 0xb8, 0x6c, 0x9c, 0xd0, 0x7e,
-	0x0c, 0x4c, 0xc9, 0xa9, 0xc2, 0x94, 0x24, 0x73, 0x9e, 0x1e, 0xdc, 0xe3, 0x06, 0x56, 0x13, 0x14,
-	0x41, 0x77, 0xaa, 0xb0, 0x10, 0x66, 0x1c, 0x2c, 0xa6, 0xee, 0x4c, 0x5d, 0xd6, 0x60, 0x66, 0xfd,
-	0x16, 0x44, 0xea, 0xa2, 0x60, 0x89, 0xd3, 0xae, 0x93, 0x3b, 0xdb, 0xd4, 0x37, 0xcb, 0x3b, 0xe7,
-	0x66, 0xca, 0x6e, 0x6f, 0x21, 0xaf, 0x09, 0xfa, 0x0e, 0x82, 0xe6, 0xdb, 0x6f, 0xbf, 0xff, 0xed,
-	0x07, 0xf2, 0x68, 0x44, 0x6f, 0xe0, 0xa3, 0x77, 0x87, 0xa1, 0x6f, 0xc0, 0x1f, 0x11, 0x9e, 0xec,
-	0x59, 0xa2, 0x37, 0xf6, 0x4e, 0x0f, 0x4a, 0xde, 0x8a, 0x2d, 0xe5, 0xa3, 0x22, 0xde, 0x52, 0x8d,
-	0xfd, 0x55, 0x15, 0x89, 0xbe, 0x04, 0x6f, 0x9e, 0xab, 0x77, 0x7d, 0xbf, 0x9a, 0x09, 0x9e, 0xc8,
-	0x55, 0xf4, 0xfa, 0x5e, 0xef, 0x86, 0xdb, 0x08, 0x36, 0xe7, 0xf4, 0x96, 0x65, 0x74, 0x54, 0x48,
-	0xa5, 0x6d, 0x7b, 0x0f, 0x77, 0x45, 0x83, 0x19, 0x51, 0x30, 0xbd, 0x63, 0x69, 0x6a, 0x90, 0xed,
-	0xe7, 0x61, 0x90, 0x35, 0x29, 0xdf, 0x73, 0x4e, 0x62, 0xa6, 0x0f, 0x56, 0x50, 0xcf, 0xbc, 0xe7,
-	0xd2, 0x1e, 0x9d, 0xff, 0xd6, 0x2e, 0xff, 0x41, 0xce, 0xec, 0xcf, 0xd7, 0xff, 0x05, 0x00, 0x00,
-	0xff, 0xff, 0xb5, 0x59, 0xac, 0x4c, 0xc0, 0x06, 0x00, 0x00,
+	// 789 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0xdd, 0x8e, 0xe3, 0x34,
+	0x14, 0x56, 0x26, 0xd3, 0x6e, 0xeb, 0xce, 0x42, 0xb1, 0x56, 0x10, 0xba, 0x08, 0xaa, 0x88, 0x8b,
+	0x22, 0xad, 0x32, 0x68, 0x10, 0x48, 0x5c, 0xa0, 0x55, 0x7f, 0x16, 0xb6, 0x40, 0xa7, 0x95, 0x3b,
+	0xec, 0x05, 0x77, 0x9e, 0xe4, 0xb4, 0xb5, 0x9a, 0xda, 0x91, 0xe3, 0x4c, 0xb7, 0xfb, 0x08, 0x88,
+	0x77, 0xe0, 0x09, 0x78, 0x14, 0xae, 0x79, 0x1d, 0x64, 0xc7, 0x49, 0xdd, 0xee, 0xb2, 0x57, 0x33,
+	0xe7, 0xfb, 0xbe, 0x73, 0x8e, 0xfd, 0x9d, 0xe3, 0x14, 0x75, 0xd4, 0x21, 0x83, 0x3c, 0xca, 0xa4,
+	0x50, 0xa2, 0xf7, 0xe9, 0x5a, 0x88, 0x75, 0x0a, 0xd7, 0x26, 0xba, 0x2f, 0x56, 0xd7, 0x94, 0x1f,
+	0x4a, 0x2a, 0xfc, 0xd7, 0x43, 0xed, 0x17, 0xaf, 0x95, 0xa4, 0x13, 0xaa, 0x28, 0xee, 0xa1, 0xd6,
+	0xcf, 0xb9, 0xe0, 0xcb, 0x0c, 0xe2, 0xc0, 0xeb, 0x7b, 0x83, 0x2b, 0x52, 0xc7, 0xf8, 0x3b, 0xd4,
+	0x21, 0x05, 0x8f, 0xe7, 0x99, 0x62, 0x82, 0xe7, 0xc1, 0x45, 0xdf, 0x1b, 0x74, 0x6e, 0x9e, 0x44,
+	0x65, 0xe9, 0xa8, 0x2a, 0x1d, 0x0d, 0xf9, 0x81, 0xb8, 0x42, 0xfc, 0x19, 0x6a, 0x2f, 0x55, 0xc2,
+	0xf8, 0x42, 0x48, 0x15, 0xf8, 0x7d, 0x6f, 0xf0, 0x98, 0x1c, 0x01, 0xfc, 0x39, 0x42, 0x4b, 0x95,
+	0x88, 0x42, 0x19, 0xfa, 0xd2, 0xd0, 0x0e, 0x62, 0x79, 0x90, 0xd2, 0xf0, 0x8d, 0x9a, 0xb7, 0x08,
+	0x0e, 0xd0, 0xa3, 0x89, 0x64, 0x0f, 0x30, 0x9d, 0x04, 0xcd, 0xbe, 0x37, 0x68, 0x93, 0x2a, 0x0c,
+	0xff, 0xbe, 0x40, 0x4f, 0x7f, 0x64, 0x12, 0x62, 0x49, 0xe3, 0x2d, 0xc8, 0x5b, 0x50, 0x7b, 0x21,
+	0xb7, 0x53, 0xae, 0x40, 0xae, 0x68, 0x0c, 0xfa, 0x5c, 0xc3, 0x34, 0x15, 0xfb, 0xd9, 0x6c, 0xb2,
+	0x34, 0x97, 0x6d, 0x91, 0x23, 0x80, 0x7f, 0x40, 0x8f, 0xa7, 0x9c, 0x50, 0x05, 0xbf, 0xb2, 0x1d,
+	0x53, 0x20, 0xed, 0x7d, 0x3f, 0x89, 0x9c, 0x92, 0x0e, 0x4d, 0x4e, 0xd5, 0xf8, 0x39, 0xfa, 0x60,
+	0x5e, 0x28, 0x37, 0xdf, 0x7f, 0x7f, 0xfe, 0x99, 0x1c, 0x5f, 0xa3, 0xf6, 0xf8, 0x76, 0x3a, 0x16,
+	0x7c, 0xc5, 0xd6, 0xc6, 0x96, 0xce, 0xcd, 0x47, 0x51, 0x8d, 0x14, 0x92, 0x6a, 0x73, 0xc9, 0x51,
+	0x83, 0x9f, 0xa3, 0xab, 0xa5, 0xa2, 0x8a, 0xc5, 0x36, 0xa7, 0x61, 0x72, 0x9e, 0x46, 0x25, 0x68,
+	0x6f, 0x7f, 0x9a, 0x7d, 0x92, 0x10, 0xfe, 0x71, 0x81, 0xba, 0xe7, 0x0d, 0x70, 0x1f, 0x75, 0x6c,
+	0xea, 0x2d, 0xdd, 0x81, 0xb1, 0xa9, 0x4d, 0x5c, 0x08, 0x7f, 0xa9, 0x8d, 0xb2, 0x9e, 0x1a, 0xcd,
+	0x85, 0xd1, 0x9c, 0x82, 0x7a, 0x4c, 0x23, 0xc6, 0x17, 0x54, 0x6d, 0x02, 0xbf, 0xef, 0xeb, 0x31,
+	0xd9, 0x50, 0x33, 0xba, 0xe5, 0x84, 0x49, 0x73, 0xcd, 0x36, 0xa9, 0x42, 0xbd, 0x8c, 0x63, 0x1a,
+	0x6f, 0x40, 0x53, 0x0d, 0x43, 0xd5, 0x31, 0x7e, 0x86, 0x2e, 0x87, 0x72, 0x9d, 0x07, 0xcd, 0xbe,
+	0x3f, 0xe8, 0xdc, 0x04, 0x6f, 0x39, 0xa3, 0x81, 0xa1, 0x5c, 0x13, 0xa3, 0xea, 0x7d, 0x8d, 0x9a,
+	0x65, 0x8c, 0xbb, 0xc8, 0xff, 0x05, 0x0e, 0xf6, 0x1e, 0xfa, 0x5f, 0xfc, 0x04, 0x35, 0x5e, 0xd1,
+	0xb4, 0xa8, 0xce, 0x5d, 0x06, 0xe1, 0x9f, 0x1e, 0xea, 0xfd, 0xbf, 0x73, 0x7a, 0x2b, 0x67, 0x34,
+	0x1e, 0x26, 0x89, 0x84, 0x3c, 0xb7, 0xd5, 0x1c, 0x44, 0xdb, 0xf6, 0x52, 0xe4, 0x6a, 0x02, 0x0f,
+	0x8e, 0x25, 0x2e, 0x84, 0x9f, 0xa1, 0xd6, 0x74, 0x61, 0x47, 0x55, 0xae, 0x46, 0x37, 0xaa, 0x80,
+	0x6a, 0x3e, 0xb5, 0x22, 0xdc, 0xa3, 0x0f, 0xcf, 0x48, 0xdd, 0x62, 0x21, 0xd9, 0x8e, 0xca, 0x83,
+	0x6e, 0x5a, 0x4d, 0xc6, 0x81, 0xb4, 0xe2, 0x27, 0xaa, 0x60, 0x4f, 0x4b, 0x85, 0x5f, 0x2a, 0x1c,
+	0xc8, 0x4c, 0x97, 0xee, 0x20, 0x07, 0xf9, 0x00, 0x32, 0x0f, 0x2e, 0xcd, 0x64, 0x5c, 0x28, 0xfc,
+	0xcb, 0x43, 0x5f, 0x38, 0x1b, 0x3b, 0xa3, 0xf1, 0x86, 0x71, 0x78, 0xeb, 0x24, 0xe3, 0xc5, 0x6f,
+	0x77, 0xb0, 0xcb, 0x52, 0xaa, 0xea, 0x1d, 0x71, 0x20, 0xfd, 0xd4, 0x5e, 0xaa, 0x17, 0x9c, 0xde,
+	0xa7, 0x90, 0x18, 0x33, 0x5a, 0xe4, 0x08, 0x18, 0x33, 0x61, 0xb7, 0x64, 0x6f, 0x60, 0xc6, 0xee,
+	0xed, 0x17, 0xc2, 0x41, 0x74, 0xf6, 0xab, 0x38, 0x2b, 0xc6, 0xa2, 0xe0, 0xd5, 0x17, 0xe2, 0x08,
+	0x84, 0xff, 0x78, 0xa8, 0xeb, 0x9c, 0xd0, 0xbc, 0x7e, 0x5d, 0x72, 0x9a, 0x13, 0xa0, 0xc9, 0x9c,
+	0xa7, 0x07, 0xfb, 0xb8, 0x1d, 0x04, 0x87, 0xe8, 0x6a, 0x9a, 0x13, 0x21, 0xf4, 0x38, 0x58, 0x0c,
+	0xf6, 0x4c, 0x27, 0x98, 0x5e, 0xbf, 0x05, 0x95, 0xaa, 0x28, 0x58, 0x62, 0xbd, 0xab, 0x63, 0x5d,
+	0x5f, 0x2f, 0xef, 0x9c, 0xeb, 0x91, 0xda, 0xbd, 0x75, 0x10, 0xfc, 0x3d, 0xea, 0xb8, 0x6f, 0xbf,
+	0xf1, 0xfe, 0xb7, 0xef, 0x6a, 0xc3, 0x37, 0xe8, 0xe3, 0x77, 0xcb, 0xf0, 0xb7, 0xa8, 0x3d, 0xa2,
+	0x3c, 0xd9, 0xb3, 0x44, 0x6d, 0xcc, 0x9d, 0xce, 0x4a, 0xde, 0x89, 0x2d, 0xf0, 0x51, 0x11, 0x6f,
+	0x41, 0x91, 0xa3, 0x12, 0x7f, 0x85, 0xfc, 0x79, 0x96, 0xbf, 0xeb, 0xfb, 0xe5, 0x26, 0x68, 0x4d,
+	0xf8, 0xfa, 0xa4, 0xb7, 0x43, 0x6b, 0xc3, 0xe6, 0x1c, 0xee, 0xd8, 0x0e, 0x46, 0x85, 0xcc, 0x95,
+	0x69, 0xef, 0x93, 0x13, 0x4c, 0x9b, 0x42, 0x60, 0xc5, 0xd2, 0x54, 0x43, 0xa6, 0x9f, 0x4f, 0x1c,
+	0xa4, 0x7c, 0xcf, 0x19, 0x8d, 0x99, 0x3a, 0x18, 0x43, 0x7d, 0x52, 0xc7, 0xa3, 0x47, 0xbf, 0x37,
+	0xca, 0x5f, 0x90, 0xa6, 0xf9, 0xf3, 0xcd, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x79, 0x8c, 0x09,
+	0x9d, 0xc0, 0x06, 0x00, 0x00,
 }
diff --git a/runtime/service.go b/runtime/service.go
index a180183..fab812f 100644
--- a/runtime/service.go
+++ b/runtime/service.go
@@ -67,6 +67,7 @@ const (
 	defaultVsockPort        = 10789
 	minVsockIOPort          = uint32(11000)
 	firecrackerStartTimeout = 5 * time.Second
+	defaultStopVMTimeout    = 5 * time.Second
 
 	// StartEventName is the topic published to when a VM starts
 	StartEventName = "/firecracker-vm/start"
@@ -463,19 +464,9 @@ func (s *service) createVM(requestCtx context.Context, request *proto.CreateVMRe
 		return errors.Wrapf(err, "failed to build VM configuration")
 	}
 
-	relSockPath, err := s.shimDir.FirecrackerSockRelPath()
-	if err != nil {
-		return errors.Wrapf(err, "failed to get relative path to firecracker api socket")
-	}
-
-	relVSockPath, err := s.shimDir.FirecrackerVSockRelPath()
-	if err != nil {
-		return errors.Wrapf(err, "failed to get relative path to firecracker vsock")
-	}
-
 	cmd := firecracker.VMCommandBuilder{}.
 		WithBin(s.config.FirecrackerBinaryPath).
-		WithSocketPath(relSockPath).
+		WithSocketPath(s.shimDir.FirecrackerSockPath()).
 		Build(s.shimCtx) // shimCtx so the VM process is only killed when the shim shuts down
 
 	// use shimCtx so the VM is killed when the shim shuts down
@@ -490,7 +481,7 @@ func (s *service) createVM(requestCtx context.Context, request *proto.CreateVMRe
 	}
 
 	s.logger.Info("calling agent")
-	conn, err := vm.VSockDial(requestCtx, s.logger, relVSockPath, defaultVsockPort)
+	conn, err := vm.VSockDial(requestCtx, s.logger, s.shimDir.FirecrackerVSockPath(), defaultVsockPort)
 	if err != nil {
 		return errors.Wrapf(err, "failed to dial the VM over vsock")
 	}
@@ -509,6 +500,11 @@ func (s *service) createVM(requestCtx context.Context, request *proto.CreateVMRe
 // created yet and the timeout is hit waiting for it to exist, an error will be returned but the shim will
 // continue to shutdown.
 func (s *service) StopVM(requestCtx context.Context, request *proto.StopVMRequest) (_ *empty.Empty, err error) {
+	timeout := defaultStopVMTimeout
+	if request.TimeoutSeconds > 0 {
+		timeout = time.Duration(request.TimeoutSeconds) * time.Second
+	}
+	timer := time.NewTimer(timeout)
 	defer logPanicAndDie(s.logger)
 	// If something goes wrong here, just shut down ungracefully. This eliminates some scenarios that would result
 	// in the user being unable to shut down the VM.
@@ -524,14 +520,22 @@ func (s *service) StopVM(requestCtx context.Context, request *proto.StopVMReques
 		return nil, err
 	}
 
-	// The graceful shutdown logic, including stopping the VM, is centralized in Shutdown. We set "Now" to true
-	// to ensure that the service will actually shutdown even if there are still containers being managed.
-	_, err = s.Shutdown(requestCtx, &taskAPI.ShutdownRequest{Now: true})
-	if err != nil {
-		return nil, err
-	}
+	shutdownCh := make(chan error)
+	go func() {
+		defer close(shutdownCh)
+		_, err := s.Shutdown(requestCtx, &taskAPI.ShutdownRequest{Now: true})
+		shutdownCh <- err
+	}()
 
-	return &empty.Empty{}, nil
+	select {
+	case <-timer.C:
+		return nil, status.Error(codes.DeadlineExceeded, "timed out waiting for VM shutdown")
+	case err = <-shutdownCh:
+		if err != nil {
+			return nil, err
+		}
+		return &empty.Empty{}, nil
+	}
 }
 
 // GetVMInfo returns metadata for the VM being managed by this shim. If the VM has not been created yet, this
@@ -547,7 +551,7 @@ func (s *service) GetVMInfo(requestCtx context.Context, request *proto.GetVMInfo
 
 	return &proto.GetVMInfoResponse{
 		VMID:            s.vmID,
-		SocketPath:      s.shimDir.FirecrackerSockPath(),
+		SocketPath:      s.machineConfig.SocketPath,
 		LogFifoPath:     s.machineConfig.LogFifo,
 		MetricsFifoPath: s.machineConfig.MetricsFifo,
 	}, nil
@@ -575,20 +579,10 @@ func (s *service) SetVMMetadata(requestCtx context.Context, request *proto.SetVM
 }
 
 func (s *service) buildVMConfiguration(req *proto.CreateVMRequest) (*firecracker.Config, error) {
-	relSockPath, err := s.shimDir.FirecrackerSockRelPath()
-	if err != nil {
-		return nil, errors.Wrapf(err, "failed to get relative path to firecracker api socket")
-	}
-
-	relVSockPath, err := s.shimDir.FirecrackerVSockRelPath()
-	if err != nil {
-		return nil, errors.Wrapf(err, "failed to get relative path to firecracker vsock")
-	}
-
 	cfg := firecracker.Config{
-		SocketPath: relSockPath,
+		SocketPath: s.shimDir.FirecrackerSockPath(),
 		VsockDevices: []firecracker.VsockDevice{{
-			Path: relVSockPath,
+			Path: s.shimDir.FirecrackerVSockPath(),
 			ID:   "agent_api",
 		}},
 		LogFifo:     s.shimDir.FirecrackerLogFifoPath(),
@@ -731,11 +725,6 @@ func (s *service) Create(requestCtx context.Context, request *taskAPI.CreateTask
 		return nil, err
 	}
 
-	relVSockPath, err := s.shimDir.FirecrackerVSockRelPath()
-	if err != nil {
-		return nil, errors.Wrapf(err, "failed to get relative path to firecracker vsock")
-	}
-
 	var ioConnectorSet vm.IOProxy
 
 	if vm.IsAgentOnlyIO(request.Stdout, logger) {
@@ -745,14 +734,14 @@ func (s *service) Create(requestCtx context.Context, request *taskAPI.CreateTask
 		if request.Stdin != "" {
 			stdinConnectorPair = &vm.IOConnectorPair{
 				ReadConnector:  vm.FIFOConnector(request.Stdin),
-				WriteConnector: vm.VSockDialConnector(relVSockPath, extraData.StdinPort),
+				WriteConnector: vm.VSockDialConnector(s.shimDir.FirecrackerVSockPath(), extraData.StdinPort),
 			}
 		}
 
 		var stdoutConnectorPair *vm.IOConnectorPair
 		if request.Stdout != "" {
 			stdoutConnectorPair = &vm.IOConnectorPair{
-				ReadConnector:  vm.VSockDialConnector(relVSockPath, extraData.StdoutPort),
+				ReadConnector:  vm.VSockDialConnector(s.shimDir.FirecrackerVSockPath(), extraData.StdoutPort),
 				WriteConnector: vm.FIFOConnector(request.Stdout),
 			}
 		}
@@ -760,7 +749,7 @@ func (s *service) Create(requestCtx context.Context, request *taskAPI.CreateTask
 		var stderrConnectorPair *vm.IOConnectorPair
 		if request.Stderr != "" {
 			stderrConnectorPair = &vm.IOConnectorPair{
-				ReadConnector:  vm.VSockDialConnector(relVSockPath, extraData.StderrPort),
+				ReadConnector:  vm.VSockDialConnector(s.shimDir.FirecrackerVSockPath(), extraData.StderrPort),
 				WriteConnector: vm.FIFOConnector(request.Stderr),
 			}
 		}
@@ -846,11 +835,6 @@ func (s *service) Exec(requestCtx context.Context, req *taskAPI.ExecProcessReque
 		return nil, err
 	}
 
-	relVSockPath, err := s.shimDir.FirecrackerVSockRelPath()
-	if err != nil {
-		return nil, errors.Wrapf(err, "failed to get relative path to firecracker vsock")
-	}
-
 	var ioConnectorSet vm.IOProxy
 
 	if vm.IsAgentOnlyIO(req.Stdout, logger) {
@@ -860,14 +844,14 @@ func (s *service) Exec(requestCtx context.Context, req *taskAPI.ExecProcessReque
 		if req.Stdin != "" {
 			stdinConnectorPair = &vm.IOConnectorPair{
 				ReadConnector:  vm.FIFOConnector(req.Stdin),
-				WriteConnector: vm.VSockDialConnector(relVSockPath, extraData.StdinPort),
+				WriteConnector: vm.VSockDialConnector(s.shimDir.FirecrackerVSockPath(), extraData.StdinPort),
 			}
 		}
 
 		var stdoutConnectorPair *vm.IOConnectorPair
 		if req.Stdout != "" {
 			stdoutConnectorPair = &vm.IOConnectorPair{
-				ReadConnector:  vm.VSockDialConnector(relVSockPath, extraData.StdoutPort),
+				ReadConnector:  vm.VSockDialConnector(s.shimDir.FirecrackerVSockPath(), extraData.StdoutPort),
 				WriteConnector: vm.FIFOConnector(req.Stdout),
 			}
 		}
@@ -875,7 +859,7 @@ func (s *service) Exec(requestCtx context.Context, req *taskAPI.ExecProcessReque
 		var stderrConnectorPair *vm.IOConnectorPair
 		if req.Stderr != "" {
 			stderrConnectorPair = &vm.IOConnectorPair{
-				ReadConnector:  vm.VSockDialConnector(relVSockPath, extraData.StderrPort),
+				ReadConnector:  vm.VSockDialConnector(s.shimDir.FirecrackerVSockPath(), extraData.StderrPort),
 				WriteConnector: vm.FIFOConnector(req.Stderr),
 			}
 		}
diff --git a/tools/image-builder/README.md b/tools/image-builder/README.md
index 273556c..116d0a5 100644
--- a/tools/image-builder/README.md
+++ b/tools/image-builder/README.md
@@ -25,36 +25,32 @@ The image currently expects `vdb` to be the block device containing
 the container root filesystem, and this device is mounted on
 `/container/rootfs`.
 
+If the `vsock_srv` program from the
+[clownix](https://github.com/clownix/cloonix_vsock) github repository
+is present in `ephemeral_files/bin/` when the image is built, it will
+be embedded in the image and run at boot, allowing easy shell access
+to the VM. This can be convenient for debugging, but it is not
+embedded by default for security and licensing reasons.
+
 ### Generation ###
 
 There are two alternatives for providing the build environment. You
 can perform the image build in Docker, in which case the only
 build-time dependency is that you can launch Docker container directly
-(i.e. without `sudo`, etc). To build an image in this configuration,
-run from [the root of the firecracker-containerd package](../../Makefile):
+(i.e. without `sudo`, etc). To build an image in this configuration, use:
 
-`$ make image`
+`$ make rootfs.img-in-docker`
 
 Alternatively, to build outside a container, you'll need:
 
-* To pre-build the `agent` binary, set appropriate permissions and place it
-  under the rootfs builder directory.
-  * For example, run `make agent` from the root of the firecracker-containerd
-    package and copy `agent/agent` to 
-	`tools/image-builder/files_ephemeral/usr/local/bin/agent`.
-* To pre-build the `runc` binary, set appropriate permissions and place it
-  under the rootfs builder directory.
-  * For example, run `make -C _submodules/runc static` from the root of the 
-    firecracker-containerd package and copy `_submodules/runc/runc` to 
-	`tools/image-builder/files_ephemeral/usr/local/bin/runc`
+* To run the build process as root.
 * [`debootstrap`](https://salsa.debian.org/installer-team/debootstrap)
   (Install via the package of the same name on Debian and Ubuntu)
 * `mksquashfs`, available in the
-   [`squashfs-tools`](https://packages.debian.org/stretch/squashfs-tools)
+   `[squashfs-tools](https://packages.debian.org/stretch/squashfs-tools)
    package on Debian and Ubuntu.
-* To run the image build process as root.
 
-Then execute `make rootfs.img` from this directory (`tools/image-builder`)
+Then execute `make rootfs.img`
 
 ### Usage ###
 
diff --git a/tools/image-builder/files_debootstrap/etc/systemd/system/firecracker.target.wants/vsock-cli.service b/tools/image-builder/files_debootstrap/etc/systemd/system/firecracker.target.wants/vsock-cli.service
new file mode 120000
index 0000000..2efa166
--- /dev/null
+++ b/tools/image-builder/files_debootstrap/etc/systemd/system/firecracker.target.wants/vsock-cli.service
@@ -0,0 +1,1 @@
+/etc/systemd/system/vsock-cli.service
\ No newline at end of file
diff --git a/tools/image-builder/files_debootstrap/etc/systemd/system/vsock-cli.service b/tools/image-builder/files_debootstrap/etc/systemd/system/vsock-cli.service
new file mode 100644
index 0000000..57c596b
--- /dev/null
+++ b/tools/image-builder/files_debootstrap/etc/systemd/system/vsock-cli.service
@@ -0,0 +1,28 @@
+# Copyright 2018-2019 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.
+#
+# If the vsock_srv program from
+# https://github.com/clownix/cloonix_vsock is present, let's run it as
+# a service. It's useful for debug and test, but we don't want it
+# installed by default.
+
+[Unit]
+Description=vsock login service
+ConditionFileIsExecutable=/bin/vsock_srv
+StartLimitIntervalSec=2
+
+[Service]
+Type=forking
+ExecStart=/bin/vsock_srv 9999
+GuessMainPID=yes
+Restart=always


Test patch:
diff --git a/internal/vm/dir_test.go b/internal/vm/dir_test.go
index 4672865..7cdef40 100644
--- a/internal/vm/dir_test.go
+++ b/internal/vm/dir_test.go
@@ -40,9 +40,9 @@ func TestShimDir(t *testing.T) {
 		{name: "id with ?", ns: "test", id: "?", outErr: `invalid vm id: identifier "?" must match`},
 		{name: "id with *", ns: "test", id: "*", outErr: `invalid vm id: identifier "*" must match`},
 		{name: "id with ,", ns: "test", id: ",", outErr: `invalid vm id: identifier "," must match`},
-		{name: "valid", ns: "ns", id: "1", outDir: "/run/firecracker-containerd/ns/1"},
-		{name: "valid with dashes", ns: "test-123", id: "123-456", outDir: "/run/firecracker-containerd/test-123/123-456"},
-		{name: "valid with dots", ns: "test.123", id: "123.456", outDir: "/run/firecracker-containerd/test.123/123.456"},
+		{name: "valid", ns: "ns", id: "1", outDir: "/var/run/firecracker-containerd/ns/1"},
+		{name: "valid with dashes", ns: "test-123", id: "123-456", outDir: "/var/run/firecracker-containerd/test-123/123-456"},
+		{name: "valid with dots", ns: "test.123", id: "123.456", outDir: "/var/run/firecracker-containerd/test.123/123.456"},
 	}
 
 	for _, tc := range tests {
diff --git a/runtime/service_integ_test.go b/runtime/service_integ_test.go
index 96036f0..21a7149 100644
--- a/runtime/service_integ_test.go
+++ b/runtime/service_integ_test.go
@@ -45,7 +45,6 @@ import (
 
 	_ "github.com/firecracker-microvm/firecracker-containerd/firecracker-control"
 	"github.com/firecracker-microvm/firecracker-containerd/internal"
-	"github.com/firecracker-microvm/firecracker-containerd/internal/vm"
 	"github.com/firecracker-microvm/firecracker-containerd/proto"
 	fccontrol "github.com/firecracker-microvm/firecracker-containerd/proto/service/fccontrol/ttrpc"
 	"github.com/firecracker-microvm/firecracker-containerd/runtime/firecrackeroci"
@@ -62,7 +61,7 @@ const (
 
 	defaultVMRootfsPath = "/var/lib/firecracker-containerd/runtime/default-rootfs.img"
 	defaultVMNetDevName = "eth0"
-	varRunDir           = "/run/firecracker-containerd"
+	varRunDir           = "/var/run/firecracker-containerd"
 )
 
 // Images are presumed by the isolated tests to have already been pulled
@@ -442,60 +441,13 @@ func TestMultipleVMs_Isolated(t *testing.T) {
 
 			containerWg.Wait()
 
-			_, err = fcClient.StopVM(ctx, &proto.StopVMRequest{VMID: strconv.Itoa(vmID)})
+			_, err = fcClient.StopVM(ctx, &proto.StopVMRequest{VMID: strconv.Itoa(vmID), TimeoutSeconds: 5})
 			require.NoError(t, err, "failed to stop VM %d", vmID)
 		}(vmID)
 	}
 
 	vmWg.Wait()
 }
-
-func TestLongUnixSocketPath_Isolated(t *testing.T) {
-	// Verify that if the absolute path of the Firecracker unix sockets are longer
-	// than the max length enforced by the kernel (UNIX_PATH_MAX, usually 108), we
-	// don't fail (due to the internal implementation using relative paths).
-	// We do this by using the max VMID len (76 chars), which in combination with the
-	// default location we store state results in a path like
-	// "/run/firecracker-containerd/default/<vmID>" (with len 112).
-	internal.RequiresIsolation(t)
-	const maxUnixSockLen = 108
-	vmID := strings.Repeat("x", 76)
-
-	ctx := namespaces.WithNamespace(context.Background(), "default")
-
-	pluginClient, err := ttrpcutil.NewClient(containerdSockPath + ".ttrpc")
-	require.NoError(t, err, "failed to create ttrpc client")
-
-	fcClient := fccontrol.NewFirecrackerClient(pluginClient.Client())
-	_, err = fcClient.CreateVM(ctx, &proto.CreateVMRequest{
-		VMID: vmID,
-		RootDrive: &proto.FirecrackerDrive{
-			PathOnHost:   defaultVMRootfsPath,
-			IsReadOnly:   false,
-			IsRootDevice: true,
-		},
-		NetworkInterfaces: []*proto.FirecrackerNetworkInterface{},
-	})
-	require.NoError(t, err, "failed to create VM")
-
-	// double-check that the sockets are at the expected path and that their absolute
-	// length exceeds 108 bytes
-	shimDir, err := vm.ShimDir("default", vmID)
-	require.NoError(t, err, "failed to get shim dir")
-
-	_, err = os.Stat(shimDir.FirecrackerSockPath())
-	require.NoError(t, err, "failed to stat firecracker socket path")
-	if len(shimDir.FirecrackerSockPath()) <= maxUnixSockLen {
-		assert.Failf(t, "firecracker sock absolute path %q is not greater than max unix socket path length", shimDir.FirecrackerSockPath())
-	}
-
-	_, err = os.Stat(shimDir.FirecrackerVSockPath())
-	require.NoError(t, err, "failed to stat firecracker vsock path")
-	if len(shimDir.FirecrackerVSockPath()) <= maxUnixSockLen {
-		assert.Failf(t, "firecracker vsock absolute path %q is not greater than max unix socket path length", shimDir.FirecrackerVSockPath())
-	}
-}
-
 func TestStubBlockDevices_Isolated(t *testing.T) {
 	internal.RequiresIsolation(t)
 	const vmID = 0
@@ -598,14 +550,15 @@ func TestStubBlockDevices_Isolated(t *testing.T) {
 		}
 
 		const expectedOutput = `
+NAME MAJ:MIN RM      SIZE RO | MAGIC
+vda  254:0    0 53641216B  0 |  104 115 113 115 128  28   0   0
 vdb  254:16   0        0B  0 | 
 vdc  254:32   0      512B  0 |  214 244 216 245 215 177 177 177
 vdd  254:48   0      512B  0 |  214 244 216 245 215 177 177 177
 vde  254:64   0      512B  0 |  214 244 216 245 215 177 177 177
 vdf  254:80   0      512B  0 |  214 244 216 245 215 177 177 177`
 
-		parts := strings.Split(stdout.String(), "vdb")
-		require.Equal(t, strings.TrimSpace(expectedOutput), strings.TrimSpace("vdb"+parts[1]))
+		require.Equal(t, strings.TrimSpace(expectedOutput), strings.TrimSpace(stdout.String()))
 		require.NoError(t, exitStatus.Error(), "failed to retrieve exitStatus")
 		require.Equal(t, uint32(0), exitStatus.ExitCode())
 	case <-ctx.Done():
diff --git a/runtime/service_test.go b/runtime/service_test.go
index 7122e0d..49a7f53 100644
--- a/runtime/service_test.go
+++ b/runtime/service_test.go
@@ -191,17 +191,10 @@ func TestBuildVMConfiguration(t *testing.T) {
 			defer os.RemoveAll(tempDir)
 
 			svc.shimDir = vm.Dir(tempDir)
-
-			relSockPath, err := svc.shimDir.FirecrackerSockRelPath()
-			require.NoError(t, err, "failed to get firecracker sock rel path")
-
-			relVSockPath, err := svc.shimDir.FirecrackerVSockRelPath()
-			require.NoError(t, err, "failed to get firecracker vsock rel path")
-
 			// For values that remain constant between tests, they are written here
-			tc.expectedCfg.SocketPath = relSockPath
+			tc.expectedCfg.SocketPath = svc.shimDir.FirecrackerSockPath()
 			tc.expectedCfg.VsockDevices = []firecracker.VsockDevice{{
-				Path: relVSockPath,
+				Path: svc.shimDir.FirecrackerVSockPath(),
 				ID:   "agent_api",
 			}}
 			tc.expectedCfg.LogFifo = svc.shimDir.FirecrackerLogFifoPath()
@@ -267,10 +260,7 @@ func TestDebugConfig(t *testing.T) {
 		},
 	}
 
-	cwd, err := os.Getwd()
-	require.NoError(t, err, "failed to get working dir")
-
-	path, err := ioutil.TempDir(cwd, "TestDebugConfig")
+	path, err := ioutil.TempDir("./", "TestDebugConfig")
 	assert.NoError(t, err, "failed to create temp directory")
 
 	defer os.RemoveAll(path)
@@ -280,9 +270,7 @@ func TestDebugConfig(t *testing.T) {
 		stubDrivePath := filepath.Join(path, fmt.Sprintf("%d", i))
 		err := os.MkdirAll(stubDrivePath, os.ModePerm)
 		assert.NoError(t, err, "failed to create stub drive path")
-
 		c.service.shimDir = vm.Dir(stubDrivePath)
-
 		req := proto.CreateVMRequest{}
 
 		cfg, err := c.service.buildVMConfiguration(&req)