From 539fdb58648e62920bd898080b2660d6053a18cb Mon Sep 17 00:00:00 2001 From: Plamen Petrov Date: Mon, 2 Nov 2020 03:41:27 -0500 Subject: [PATCH 1/4] update swagger, go generate Signed-off-by: Plamen Petrov --- client/models/snapshot_create_params.go | 147 ++++++++++++++++ client/models/vm.go | 114 +++++++++++++ .../operations/create_snapshot_parameters.go | 152 +++++++++++++++++ .../operations/create_snapshot_responses.go | 158 ++++++++++++++++++ client/operations/operations_client.go | 62 +++++++ client/operations/patch_vm_parameters.go | 152 +++++++++++++++++ client/operations/patch_vm_responses.go | 158 ++++++++++++++++++ client/swagger.yaml | 89 ++++++++++ fctesting/firecracker_mock_client.go | 18 ++ 9 files changed, 1050 insertions(+) create mode 100644 client/models/snapshot_create_params.go create mode 100644 client/models/vm.go create mode 100644 client/operations/create_snapshot_parameters.go create mode 100644 client/operations/create_snapshot_responses.go create mode 100644 client/operations/patch_vm_parameters.go create mode 100644 client/operations/patch_vm_responses.go diff --git a/client/models/snapshot_create_params.go b/client/models/snapshot_create_params.go new file mode 100644 index 00000000..b2a18b80 --- /dev/null +++ b/client/models/snapshot_create_params.go @@ -0,0 +1,147 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// SnapshotCreateParams snapshot create params +// swagger:model SnapshotCreateParams +type SnapshotCreateParams struct { + + // Path to the file that will contain the guest memory. + // Required: true + MemFilePath *string `json:"mem_file_path"` + + // Path to the file that will contain the microVM state. + // Required: true + SnapshotPath *string `json:"snapshot_path"` + + // Type of snapshot to create. It is optional and by default, a full snapshot is created. + // Enum: [Full] + SnapshotType string `json:"snapshot_type,omitempty"` + + // The microVM version for which we want to create the snapshot. It is optional and it defaults to the current version. + Version string `json:"version,omitempty"` +} + +// Validate validates this snapshot create params +func (m *SnapshotCreateParams) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMemFilePath(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSnapshotPath(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSnapshotType(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *SnapshotCreateParams) validateMemFilePath(formats strfmt.Registry) error { + + if err := validate.Required("mem_file_path", "body", m.MemFilePath); err != nil { + return err + } + + return nil +} + +func (m *SnapshotCreateParams) validateSnapshotPath(formats strfmt.Registry) error { + + if err := validate.Required("snapshot_path", "body", m.SnapshotPath); err != nil { + return err + } + + return nil +} + +var snapshotCreateParamsTypeSnapshotTypePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["Full"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + snapshotCreateParamsTypeSnapshotTypePropEnum = append(snapshotCreateParamsTypeSnapshotTypePropEnum, v) + } +} + +const ( + + // SnapshotCreateParamsSnapshotTypeFull captures enum value "Full" + SnapshotCreateParamsSnapshotTypeFull string = "Full" +) + +// prop value enum +func (m *SnapshotCreateParams) validateSnapshotTypeEnum(path, location string, value string) error { + if err := validate.Enum(path, location, value, snapshotCreateParamsTypeSnapshotTypePropEnum); err != nil { + return err + } + return nil +} + +func (m *SnapshotCreateParams) validateSnapshotType(formats strfmt.Registry) error { + + if swag.IsZero(m.SnapshotType) { // not required + return nil + } + + // value enum + if err := m.validateSnapshotTypeEnum("snapshot_type", "body", m.SnapshotType); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *SnapshotCreateParams) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *SnapshotCreateParams) UnmarshalBinary(b []byte) error { + var res SnapshotCreateParams + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/client/models/vm.go b/client/models/vm.go new file mode 100644 index 00000000..8ca5e71f --- /dev/null +++ b/client/models/vm.go @@ -0,0 +1,114 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "encoding/json" + + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// VM Defines the microVM running state. It is especially useful in the snapshotting context. +// swagger:model Vm +type VM struct { + + // state + // Required: true + // Enum: [Paused Resumed] + State *string `json:"state"` +} + +// Validate validates this Vm +func (m *VM) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateState(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var vmTypeStatePropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["Paused","Resumed"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + vmTypeStatePropEnum = append(vmTypeStatePropEnum, v) + } +} + +const ( + + // VMStatePaused captures enum value "Paused" + VMStatePaused string = "Paused" + + // VMStateResumed captures enum value "Resumed" + VMStateResumed string = "Resumed" +) + +// prop value enum +func (m *VM) validateStateEnum(path, location string, value string) error { + if err := validate.Enum(path, location, value, vmTypeStatePropEnum); err != nil { + return err + } + return nil +} + +func (m *VM) validateState(formats strfmt.Registry) error { + + if err := validate.Required("state", "body", m.State); err != nil { + return err + } + + // value enum + if err := m.validateStateEnum("state", "body", *m.State); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *VM) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *VM) UnmarshalBinary(b []byte) error { + var res VM + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/client/operations/create_snapshot_parameters.go b/client/operations/create_snapshot_parameters.go new file mode 100644 index 00000000..cb3bab20 --- /dev/null +++ b/client/operations/create_snapshot_parameters.go @@ -0,0 +1,152 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + + strfmt "github.com/go-openapi/strfmt" + + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" +) + +// NewCreateSnapshotParams creates a new CreateSnapshotParams object +// with the default values initialized. +func NewCreateSnapshotParams() *CreateSnapshotParams { + var () + return &CreateSnapshotParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewCreateSnapshotParamsWithTimeout creates a new CreateSnapshotParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewCreateSnapshotParamsWithTimeout(timeout time.Duration) *CreateSnapshotParams { + var () + return &CreateSnapshotParams{ + + timeout: timeout, + } +} + +// NewCreateSnapshotParamsWithContext creates a new CreateSnapshotParams object +// with the default values initialized, and the ability to set a context for a request +func NewCreateSnapshotParamsWithContext(ctx context.Context) *CreateSnapshotParams { + var () + return &CreateSnapshotParams{ + + Context: ctx, + } +} + +// NewCreateSnapshotParamsWithHTTPClient creates a new CreateSnapshotParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewCreateSnapshotParamsWithHTTPClient(client *http.Client) *CreateSnapshotParams { + var () + return &CreateSnapshotParams{ + HTTPClient: client, + } +} + +/*CreateSnapshotParams contains all the parameters to send to the API endpoint +for the create snapshot operation typically these are written to a http.Request +*/ +type CreateSnapshotParams struct { + + /*Body + The configuration used for creating a snaphot. + + */ + Body *models.SnapshotCreateParams + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the create snapshot params +func (o *CreateSnapshotParams) WithTimeout(timeout time.Duration) *CreateSnapshotParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the create snapshot params +func (o *CreateSnapshotParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the create snapshot params +func (o *CreateSnapshotParams) WithContext(ctx context.Context) *CreateSnapshotParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the create snapshot params +func (o *CreateSnapshotParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the create snapshot params +func (o *CreateSnapshotParams) WithHTTPClient(client *http.Client) *CreateSnapshotParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the create snapshot params +func (o *CreateSnapshotParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the create snapshot params +func (o *CreateSnapshotParams) WithBody(body *models.SnapshotCreateParams) *CreateSnapshotParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the create snapshot params +func (o *CreateSnapshotParams) SetBody(body *models.SnapshotCreateParams) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *CreateSnapshotParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/operations/create_snapshot_responses.go b/client/operations/create_snapshot_responses.go new file mode 100644 index 00000000..3f897d38 --- /dev/null +++ b/client/operations/create_snapshot_responses.go @@ -0,0 +1,158 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + + strfmt "github.com/go-openapi/strfmt" + + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" +) + +// CreateSnapshotReader is a Reader for the CreateSnapshot structure. +type CreateSnapshotReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *CreateSnapshotReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 204: + result := NewCreateSnapshotNoContent() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 400: + result := NewCreateSnapshotBadRequest() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + default: + result := NewCreateSnapshotDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewCreateSnapshotNoContent creates a CreateSnapshotNoContent with default headers values +func NewCreateSnapshotNoContent() *CreateSnapshotNoContent { + return &CreateSnapshotNoContent{} +} + +/*CreateSnapshotNoContent handles this case with default header values. + +Snapshot created +*/ +type CreateSnapshotNoContent struct { +} + +func (o *CreateSnapshotNoContent) Error() string { + return fmt.Sprintf("[PUT /snapshot/create][%d] createSnapshotNoContent ", 204) +} + +func (o *CreateSnapshotNoContent) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + return nil +} + +// NewCreateSnapshotBadRequest creates a CreateSnapshotBadRequest with default headers values +func NewCreateSnapshotBadRequest() *CreateSnapshotBadRequest { + return &CreateSnapshotBadRequest{} +} + +/*CreateSnapshotBadRequest handles this case with default header values. + +Snapshot cannot be created due to bad input +*/ +type CreateSnapshotBadRequest struct { + Payload *models.Error +} + +func (o *CreateSnapshotBadRequest) Error() string { + return fmt.Sprintf("[PUT /snapshot/create][%d] createSnapshotBadRequest %+v", 400, o.Payload) +} + +func (o *CreateSnapshotBadRequest) GetPayload() *models.Error { + return o.Payload +} + +func (o *CreateSnapshotBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.Error) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewCreateSnapshotDefault creates a CreateSnapshotDefault with default headers values +func NewCreateSnapshotDefault(code int) *CreateSnapshotDefault { + return &CreateSnapshotDefault{ + _statusCode: code, + } +} + +/*CreateSnapshotDefault handles this case with default header values. + +Internal server error +*/ +type CreateSnapshotDefault struct { + _statusCode int + + Payload *models.Error +} + +// Code gets the status code for the create snapshot default response +func (o *CreateSnapshotDefault) Code() int { + return o._statusCode +} + +func (o *CreateSnapshotDefault) Error() string { + return fmt.Sprintf("[PUT /snapshot/create][%d] createSnapshot default %+v", o._statusCode, o.Payload) +} + +func (o *CreateSnapshotDefault) GetPayload() *models.Error { + return o.Payload +} + +func (o *CreateSnapshotDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.Error) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/client/operations/operations_client.go b/client/operations/operations_client.go index fda65312..25ff041b 100644 --- a/client/operations/operations_client.go +++ b/client/operations/operations_client.go @@ -159,6 +159,36 @@ func (a *Client) PutMmdsConfig(params *PutMmdsConfigParams) (*PutMmdsConfigNoCon } +/* +CreateSnapshot creates a full snapshot post boot only + +Creates a snapshot of the microVM state. The microVM should be in the `Paused` state. +*/ +func (a *Client) CreateSnapshot(params *CreateSnapshotParams) (*CreateSnapshotNoContent, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewCreateSnapshotParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "createSnapshot", + Method: "PUT", + PathPattern: "/snapshot/create", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &CreateSnapshotReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + return result.(*CreateSnapshotNoContent), nil + +} + /* CreateSyncAction creates a synchronous action */ @@ -335,6 +365,36 @@ func (a *Client) PatchMachineConfiguration(params *PatchMachineConfigurationPara } +/* +PatchVM updates the micro VM state + +Sets the desired state (Paused or Resumed) for the microVM. +*/ +func (a *Client) PatchVM(params *PatchVMParams) (*PatchVMNoContent, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewPatchVMParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "patchVm", + Method: "PATCH", + PathPattern: "/vm", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &PatchVMReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + return result.(*PatchVMNoContent), nil + +} + /* PutGuestBootSource creates or updates the boot source pre boot only @@ -553,12 +613,14 @@ type ClientIface interface { PatchMmds(params *PatchMmdsParams) (*PatchMmdsNoContent, error) PutMmds(params *PutMmdsParams) (*PutMmdsNoContent, error) PutMmdsConfig(params *PutMmdsConfigParams) (*PutMmdsConfigNoContent, error) + CreateSnapshot(params *CreateSnapshotParams) (*CreateSnapshotNoContent, error) CreateSyncAction(params *CreateSyncActionParams) (*CreateSyncActionNoContent, error) DescribeInstance(params *DescribeInstanceParams) (*DescribeInstanceOK, error) GetMachineConfiguration(params *GetMachineConfigurationParams) (*GetMachineConfigurationOK, error) PatchGuestDriveByID(params *PatchGuestDriveByIDParams) (*PatchGuestDriveByIDNoContent, error) PatchGuestNetworkInterfaceByID(params *PatchGuestNetworkInterfaceByIDParams) (*PatchGuestNetworkInterfaceByIDNoContent, error) PatchMachineConfiguration(params *PatchMachineConfigurationParams) (*PatchMachineConfigurationNoContent, error) + PatchVM(params *PatchVMParams) (*PatchVMNoContent, error) PutGuestBootSource(params *PutGuestBootSourceParams) (*PutGuestBootSourceNoContent, error) PutGuestDriveByID(params *PutGuestDriveByIDParams) (*PutGuestDriveByIDNoContent, error) PutGuestNetworkInterfaceByID(params *PutGuestNetworkInterfaceByIDParams) (*PutGuestNetworkInterfaceByIDNoContent, error) diff --git a/client/operations/patch_vm_parameters.go b/client/operations/patch_vm_parameters.go new file mode 100644 index 00000000..a2e52a95 --- /dev/null +++ b/client/operations/patch_vm_parameters.go @@ -0,0 +1,152 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + + strfmt "github.com/go-openapi/strfmt" + + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" +) + +// NewPatchVMParams creates a new PatchVMParams object +// with the default values initialized. +func NewPatchVMParams() *PatchVMParams { + var () + return &PatchVMParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewPatchVMParamsWithTimeout creates a new PatchVMParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewPatchVMParamsWithTimeout(timeout time.Duration) *PatchVMParams { + var () + return &PatchVMParams{ + + timeout: timeout, + } +} + +// NewPatchVMParamsWithContext creates a new PatchVMParams object +// with the default values initialized, and the ability to set a context for a request +func NewPatchVMParamsWithContext(ctx context.Context) *PatchVMParams { + var () + return &PatchVMParams{ + + Context: ctx, + } +} + +// NewPatchVMParamsWithHTTPClient creates a new PatchVMParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewPatchVMParamsWithHTTPClient(client *http.Client) *PatchVMParams { + var () + return &PatchVMParams{ + HTTPClient: client, + } +} + +/*PatchVMParams contains all the parameters to send to the API endpoint +for the patch Vm operation typically these are written to a http.Request +*/ +type PatchVMParams struct { + + /*Body + The microVM state + + */ + Body *models.VM + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the patch Vm params +func (o *PatchVMParams) WithTimeout(timeout time.Duration) *PatchVMParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the patch Vm params +func (o *PatchVMParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the patch Vm params +func (o *PatchVMParams) WithContext(ctx context.Context) *PatchVMParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the patch Vm params +func (o *PatchVMParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the patch Vm params +func (o *PatchVMParams) WithHTTPClient(client *http.Client) *PatchVMParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the patch Vm params +func (o *PatchVMParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the patch Vm params +func (o *PatchVMParams) WithBody(body *models.VM) *PatchVMParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the patch Vm params +func (o *PatchVMParams) SetBody(body *models.VM) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *PatchVMParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/operations/patch_vm_responses.go b/client/operations/patch_vm_responses.go new file mode 100644 index 00000000..2e9b2f61 --- /dev/null +++ b/client/operations/patch_vm_responses.go @@ -0,0 +1,158 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + + strfmt "github.com/go-openapi/strfmt" + + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" +) + +// PatchVMReader is a Reader for the PatchVM structure. +type PatchVMReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *PatchVMReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 204: + result := NewPatchVMNoContent() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 400: + result := NewPatchVMBadRequest() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + default: + result := NewPatchVMDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewPatchVMNoContent creates a PatchVMNoContent with default headers values +func NewPatchVMNoContent() *PatchVMNoContent { + return &PatchVMNoContent{} +} + +/*PatchVMNoContent handles this case with default header values. + +Vm state updated +*/ +type PatchVMNoContent struct { +} + +func (o *PatchVMNoContent) Error() string { + return fmt.Sprintf("[PATCH /vm][%d] patchVmNoContent ", 204) +} + +func (o *PatchVMNoContent) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + return nil +} + +// NewPatchVMBadRequest creates a PatchVMBadRequest with default headers values +func NewPatchVMBadRequest() *PatchVMBadRequest { + return &PatchVMBadRequest{} +} + +/*PatchVMBadRequest handles this case with default header values. + +Vm state cannot be updated due to bad input +*/ +type PatchVMBadRequest struct { + Payload *models.Error +} + +func (o *PatchVMBadRequest) Error() string { + return fmt.Sprintf("[PATCH /vm][%d] patchVmBadRequest %+v", 400, o.Payload) +} + +func (o *PatchVMBadRequest) GetPayload() *models.Error { + return o.Payload +} + +func (o *PatchVMBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.Error) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewPatchVMDefault creates a PatchVMDefault with default headers values +func NewPatchVMDefault(code int) *PatchVMDefault { + return &PatchVMDefault{ + _statusCode: code, + } +} + +/*PatchVMDefault handles this case with default header values. + +Internal server error +*/ +type PatchVMDefault struct { + _statusCode int + + Payload *models.Error +} + +// Code gets the status code for the patch Vm default response +func (o *PatchVMDefault) Code() int { + return o._statusCode +} + +func (o *PatchVMDefault) Error() string { + return fmt.Sprintf("[PATCH /vm][%d] patchVm default %+v", o._statusCode, o.Payload) +} + +func (o *PatchVMDefault) GetPayload() *models.Error { + return o.Payload +} + +func (o *PatchVMDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.Error) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/client/swagger.yaml b/client/swagger.yaml index ace7f8a1..6ab2e512 100644 --- a/client/swagger.yaml +++ b/client/swagger.yaml @@ -398,6 +398,56 @@ paths: description: Internal server error schema: $ref: "#/definitions/Error" + /vm: + patch: + summary: Updates the microVM state. + description: + Sets the desired state (Paused or Resumed) for the microVM. + operationId: patchVm + parameters: + - name: body + in: body + description: The microVM state + required: true + schema: + $ref: "#/definitions/Vm" + responses: + 204: + description: Vm state updated + 400: + description: Vm state cannot be updated due to bad input + schema: + $ref: "#/definitions/Error" + default: + description: Internal server error + schema: + $ref: "#/definitions/Error" + + /snapshot/create: + put: + summary: Creates a full snapshot. Post-boot only. + description: + Creates a snapshot of the microVM state. The microVM should be + in the `Paused` state. + operationId: createSnapshot + parameters: + - name: body + in: body + description: The configuration used for creating a snaphot. + required: true + schema: + $ref: "#/definitions/SnapshotCreateParams" + responses: + 204: + description: Snapshot created + 400: + description: Snapshot cannot be created due to bad input + schema: + $ref: "#/definitions/Error" + default: + description: Internal server error + schema: + $ref: "#/definitions/Error" /vsock: put: @@ -668,6 +718,31 @@ definitions: $ref: "#/definitions/TokenBucket" description: Token bucket with operations as tokens + SnapshotCreateParams: + type: object + required: + - mem_file_path + - snapshot_path + properties: + mem_file_path: + type: string + description: Path to the file that will contain the guest memory. + snapshot_path: + type: string + description: Path to the file that will contain the microVM state. + snapshot_type: + type: string + enum: + - Full + description: + Type of snapshot to create. It is optional and by default, a full + snapshot is created. + version: + type: string + description: + The microVM version for which we want to create the snapshot. + It is optional and it defaults to the current version. + TokenBucket: type: object description: @@ -699,6 +774,19 @@ definitions: description: The amount of milliseconds it takes for the bucket to refill. minimum: 0 + Vm: + type: object + description: + Defines the microVM running state. It is especially useful in the snapshotting context. + required: + - state + properties: + state: + type: string + enum: + - Paused + - Resumed + Vsock: type: object description: @@ -725,3 +813,4 @@ definitions: uds_path: type: string description: Path to UNIX domain socket, used to proxy vsock connections. + diff --git a/fctesting/firecracker_mock_client.go b/fctesting/firecracker_mock_client.go index fcef9895..5f48ca1f 100644 --- a/fctesting/firecracker_mock_client.go +++ b/fctesting/firecracker_mock_client.go @@ -24,12 +24,14 @@ type MockClient struct { PatchMmdsFn func(params *ops.PatchMmdsParams) (*ops.PatchMmdsNoContent, error) PutMmdsFn func(params *ops.PutMmdsParams) (*ops.PutMmdsNoContent, error) PutMmdsConfigFn func(params *ops.PutMmdsConfigParams) (*ops.PutMmdsConfigNoContent, error) + CreateSnapshotFn func(params *ops.CreateSnapshotParams) (*ops.CreateSnapshotNoContent, error) CreateSyncActionFn func(params *ops.CreateSyncActionParams) (*ops.CreateSyncActionNoContent, error) DescribeInstanceFn func(params *ops.DescribeInstanceParams) (*ops.DescribeInstanceOK, error) GetMachineConfigurationFn func(params *ops.GetMachineConfigurationParams) (*ops.GetMachineConfigurationOK, error) PatchGuestDriveByIDFn func(params *ops.PatchGuestDriveByIDParams) (*ops.PatchGuestDriveByIDNoContent, error) PatchGuestNetworkInterfaceByIDFn func(params *ops.PatchGuestNetworkInterfaceByIDParams) (*ops.PatchGuestNetworkInterfaceByIDNoContent, error) PatchMachineConfigurationFn func(params *ops.PatchMachineConfigurationParams) (*ops.PatchMachineConfigurationNoContent, error) + PatchVMFn func(params *ops.PatchVMParams) (*ops.PatchVMNoContent, error) PutGuestBootSourceFn func(params *ops.PutGuestBootSourceParams) (*ops.PutGuestBootSourceNoContent, error) PutGuestDriveByIDFn func(params *ops.PutGuestDriveByIDParams) (*ops.PutGuestDriveByIDNoContent, error) PutGuestNetworkInterfaceByIDFn func(params *ops.PutGuestNetworkInterfaceByIDParams) (*ops.PutGuestNetworkInterfaceByIDNoContent, error) @@ -71,6 +73,14 @@ func (c *MockClient) PutMmdsConfig(params *ops.PutMmdsConfigParams) (*ops.PutMmd return nil, nil } +func (c *MockClient) CreateSnapshot(params *ops.CreateSnapshotParams) (*ops.CreateSnapshotNoContent, error) { + if c.CreateSnapshotFn != nil { + return c.CreateSnapshotFn(params) + } + + return nil, nil +} + func (c *MockClient) CreateSyncAction(params *ops.CreateSyncActionParams) (*ops.CreateSyncActionNoContent, error) { if c.CreateSyncActionFn != nil { return c.CreateSyncActionFn(params) @@ -119,6 +129,14 @@ func (c *MockClient) PatchMachineConfiguration(params *ops.PatchMachineConfigura return nil, nil } +func (c *MockClient) PatchVM(params *ops.PatchVMParams) (*ops.PatchVMNoContent, error) { + if c.PatchVMFn != nil { + return c.PatchVMFn(params) + } + + return nil, nil +} + func (c *MockClient) PutGuestBootSource(params *ops.PutGuestBootSourceParams) (*ops.PutGuestBootSourceNoContent, error) { if c.PutGuestBootSourceFn != nil { return c.PutGuestBootSourceFn(params) From 3cfbc8c00f2d890b3bb9aeb38ba70bd1048379b0 Mon Sep 17 00:00:00 2001 From: Plamen Petrov Date: Mon, 2 Nov 2020 12:17:43 +0200 Subject: [PATCH 2/4] added pause, resume, create snapshot Signed-off-by: Plamen Petrov --- firecracker.go | 36 ++++++++++++++++++++++++++++++++++++ machine.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/firecracker.go b/firecracker.go index 8f8c7727..99440409 100644 --- a/firecracker.go +++ b/firecracker.go @@ -229,6 +229,42 @@ func (f *Client) PutGuestVsock(ctx context.Context, vsock *models.Vsock, opts .. return f.client.Operations.PutGuestVsock(params) } +// PatchVMOpt is a functional option to be used for the +// PatchVM API in setting any additional optional fields. +type PatchVMOpt func(*ops.PatchVMParams) + +// PatchVM is a wrapper for the swagger generated client to make +// calling of the API easier. +func (f *Client) PatchVM(ctx context.Context, vm *models.VM, opts ...PatchVMOpt) (*ops.PatchVMNoContent, error) { + timeout, cancel := context.WithTimeout(ctx, time.Duration(f.firecrackerRequestTimeout)*time.Millisecond) + defer cancel() + + params := ops.NewPatchVMParamsWithContext(timeout) + params.SetBody(vm) + for _, opt := range opts { + opt(params) + } + + return f.client.Operations.PatchVM(params) +} + +// CreateSnapshotOpt is a functional option to be used for the +// CreateSnapshot API in setting any additional optional fields. +type CreateSnapshotOpt func(*ops.CreateSnapshotParams) + +// CreateSnapshot is a wrapper for the swagger generated client to make +// calling of the API easier. +func (f *Client) CreateSnapshot(ctx context.Context, snapshotParams *models.SnapshotCreateParams, opts ...CreateSnapshotOpt) (*ops.CreateSnapshotNoContent, error) { + params := ops.NewCreateSnapshotParamsWithContext(ctx) + params.SetBody(snapshotParams) + + for _, opt := range opts { + opt(params) + } + + return f.client.Operations.CreateSnapshot(params) +} + // CreateSyncActionOpt is a functional option to be used for the // CreateSyncAction API in setting any additional optional fields. type CreateSyncActionOpt func(*ops.CreateSyncActionParams) diff --git a/machine.go b/machine.go index cae1caa8..49da32fb 100644 --- a/machine.go +++ b/machine.go @@ -1002,3 +1002,50 @@ func (m *Machine) setupSignals() { close(sigchan) }() } + +// PauseVM Pauses the VM +func (m *Machine) PauseVM(ctx context.Context, opts ...PatchVMOpt) error { + vm := &models.VM{ + State: String(models.VMStatePaused), + } + + if _, err := m.client.PatchVM(ctx, vm, opts...); err != nil { + m.logger.Errorf("failed to pause the VM: %v", err) + return err + } + + m.logger.Debug("VM paused successfully") + return nil +} + +// ResumeVM Resumes the VM +func (m *Machine) ResumeVM(ctx context.Context, opts ...PatchVMOpt) error { + vm := &models.VM{ + State: String(models.VMStateResumed), + } + + if _, err := m.client.PatchVM(ctx, vm, opts...); err != nil { + m.logger.Errorf("failed to resume the VM: %v", err) + return err + } + + m.logger.Debug("VM resumed successfully") + return nil +} + +// CreateSnapshot Creates a snapshot of the VM +func (m *Machine) CreateSnapshot(ctx context.Context, memFilePath, snapshotPath string, opts ...CreateSnapshotOpt) error { + snapshotParams := &models.SnapshotCreateParams{ + MemFilePath: String(memFilePath), + SnapshotPath: String(snapshotPath), + } + + if _, err := m.client.CreateSnapshot(ctx, snapshotParams, opts...); err != nil { + m.logger.Errorf("failed to create a snapshot of the VM: %v", err) + return err + } + + m.logger.Debug("snapshot created successfully") + + return nil +} From 5e1606fc8a478e52e415cf7162c0f3fa35ce296d Mon Sep 17 00:00:00 2001 From: Plamen Petrov Date: Mon, 9 Nov 2020 04:43:55 -0700 Subject: [PATCH 3/4] copy swagger of firecracker v0.23.0 and nits Signed-off-by: Plamen Petrov --- client/models/logger.go | 2 +- client/models/machine_configuration.go | 3 + client/models/snapshot_load_params.go | 97 ++++++++++ client/operations/load_snapshot_parameters.go | 152 +++++++++++++++ client/operations/load_snapshot_responses.go | 158 +++++++++++++++ client/operations/operations_client.go | 31 +++ client/swagger.yaml | 183 +++++++++++------- fctesting/firecracker_mock_client.go | 9 + machine.go | 7 +- 9 files changed, 571 insertions(+), 71 deletions(-) create mode 100644 client/models/snapshot_load_params.go create mode 100644 client/operations/load_snapshot_parameters.go create mode 100644 client/operations/load_snapshot_responses.go diff --git a/client/models/logger.go b/client/models/logger.go index 2ef77ad1..d15cf68b 100644 --- a/client/models/logger.go +++ b/client/models/logger.go @@ -32,7 +32,7 @@ import ( // swagger:model Logger type Logger struct { - // Set the level. + // Set the level. The possible values are case-insensitive. // Enum: [Error Warning Info Debug] Level *string `json:"level,omitempty"` diff --git a/client/models/machine_configuration.go b/client/models/machine_configuration.go index a35c5ad5..8f93cbe6 100644 --- a/client/models/machine_configuration.go +++ b/client/models/machine_configuration.go @@ -41,6 +41,9 @@ type MachineConfiguration struct { // Required: true MemSizeMib *int64 `json:"mem_size_mib"` + // Enable dirty page tracking. If this is enabled, then incremental guest memory snapshots can be created. These belong to diff snapshots, which contain, besides the microVM state, only the memory dirtied since a previous snapshot. Full snapshots each contain a full copy of the guest memory. + TrackDirtyPages bool `json:"track_dirty_pages,omitempty"` + // Number of vCPUs (either 1 or an even number) // Required: true // Maximum: 32 diff --git a/client/models/snapshot_load_params.go b/client/models/snapshot_load_params.go new file mode 100644 index 00000000..e9135ce8 --- /dev/null +++ b/client/models/snapshot_load_params.go @@ -0,0 +1,97 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + strfmt "github.com/go-openapi/strfmt" + + "github.com/go-openapi/errors" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// SnapshotLoadParams snapshot load params +// swagger:model SnapshotLoadParams +type SnapshotLoadParams struct { + + // Enable support for incremental (diff) snapshots by tracking dirty guest pages. + EnableDiffSnapshots bool `json:"enable_diff_snapshots,omitempty"` + + // Path to the file that contains the guest memory to be loaded. + // Required: true + MemFilePath *string `json:"mem_file_path"` + + // Path to the file that contains the microVM state to be loaded. + // Required: true + SnapshotPath *string `json:"snapshot_path"` +} + +// Validate validates this snapshot load params +func (m *SnapshotLoadParams) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateMemFilePath(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSnapshotPath(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *SnapshotLoadParams) validateMemFilePath(formats strfmt.Registry) error { + + if err := validate.Required("mem_file_path", "body", m.MemFilePath); err != nil { + return err + } + + return nil +} + +func (m *SnapshotLoadParams) validateSnapshotPath(formats strfmt.Registry) error { + + if err := validate.Required("snapshot_path", "body", m.SnapshotPath); err != nil { + return err + } + + return nil +} + +// MarshalBinary interface implementation +func (m *SnapshotLoadParams) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *SnapshotLoadParams) UnmarshalBinary(b []byte) error { + var res SnapshotLoadParams + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/client/operations/load_snapshot_parameters.go b/client/operations/load_snapshot_parameters.go new file mode 100644 index 00000000..b9630e74 --- /dev/null +++ b/client/operations/load_snapshot_parameters.go @@ -0,0 +1,152 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "net/http" + "time" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" + cr "github.com/go-openapi/runtime/client" + + strfmt "github.com/go-openapi/strfmt" + + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" +) + +// NewLoadSnapshotParams creates a new LoadSnapshotParams object +// with the default values initialized. +func NewLoadSnapshotParams() *LoadSnapshotParams { + var () + return &LoadSnapshotParams{ + + timeout: cr.DefaultTimeout, + } +} + +// NewLoadSnapshotParamsWithTimeout creates a new LoadSnapshotParams object +// with the default values initialized, and the ability to set a timeout on a request +func NewLoadSnapshotParamsWithTimeout(timeout time.Duration) *LoadSnapshotParams { + var () + return &LoadSnapshotParams{ + + timeout: timeout, + } +} + +// NewLoadSnapshotParamsWithContext creates a new LoadSnapshotParams object +// with the default values initialized, and the ability to set a context for a request +func NewLoadSnapshotParamsWithContext(ctx context.Context) *LoadSnapshotParams { + var () + return &LoadSnapshotParams{ + + Context: ctx, + } +} + +// NewLoadSnapshotParamsWithHTTPClient creates a new LoadSnapshotParams object +// with the default values initialized, and the ability to set a custom HTTPClient for a request +func NewLoadSnapshotParamsWithHTTPClient(client *http.Client) *LoadSnapshotParams { + var () + return &LoadSnapshotParams{ + HTTPClient: client, + } +} + +/*LoadSnapshotParams contains all the parameters to send to the API endpoint +for the load snapshot operation typically these are written to a http.Request +*/ +type LoadSnapshotParams struct { + + /*Body + The configuration used for loading a snaphot. + + */ + Body *models.SnapshotLoadParams + + timeout time.Duration + Context context.Context + HTTPClient *http.Client +} + +// WithTimeout adds the timeout to the load snapshot params +func (o *LoadSnapshotParams) WithTimeout(timeout time.Duration) *LoadSnapshotParams { + o.SetTimeout(timeout) + return o +} + +// SetTimeout adds the timeout to the load snapshot params +func (o *LoadSnapshotParams) SetTimeout(timeout time.Duration) { + o.timeout = timeout +} + +// WithContext adds the context to the load snapshot params +func (o *LoadSnapshotParams) WithContext(ctx context.Context) *LoadSnapshotParams { + o.SetContext(ctx) + return o +} + +// SetContext adds the context to the load snapshot params +func (o *LoadSnapshotParams) SetContext(ctx context.Context) { + o.Context = ctx +} + +// WithHTTPClient adds the HTTPClient to the load snapshot params +func (o *LoadSnapshotParams) WithHTTPClient(client *http.Client) *LoadSnapshotParams { + o.SetHTTPClient(client) + return o +} + +// SetHTTPClient adds the HTTPClient to the load snapshot params +func (o *LoadSnapshotParams) SetHTTPClient(client *http.Client) { + o.HTTPClient = client +} + +// WithBody adds the body to the load snapshot params +func (o *LoadSnapshotParams) WithBody(body *models.SnapshotLoadParams) *LoadSnapshotParams { + o.SetBody(body) + return o +} + +// SetBody adds the body to the load snapshot params +func (o *LoadSnapshotParams) SetBody(body *models.SnapshotLoadParams) { + o.Body = body +} + +// WriteToRequest writes these params to a swagger request +func (o *LoadSnapshotParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { + + if err := r.SetTimeout(o.timeout); err != nil { + return err + } + var res []error + + if o.Body != nil { + if err := r.SetBodyParam(o.Body); err != nil { + return err + } + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} diff --git a/client/operations/load_snapshot_responses.go b/client/operations/load_snapshot_responses.go new file mode 100644 index 00000000..dfec0e27 --- /dev/null +++ b/client/operations/load_snapshot_responses.go @@ -0,0 +1,158 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// Copyright 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 operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "fmt" + "io" + + "github.com/go-openapi/runtime" + + strfmt "github.com/go-openapi/strfmt" + + models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" +) + +// LoadSnapshotReader is a Reader for the LoadSnapshot structure. +type LoadSnapshotReader struct { + formats strfmt.Registry +} + +// ReadResponse reads a server response into the received o. +func (o *LoadSnapshotReader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { + switch response.Code() { + case 204: + result := NewLoadSnapshotNoContent() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return result, nil + case 400: + result := NewLoadSnapshotBadRequest() + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + return nil, result + default: + result := NewLoadSnapshotDefault(response.Code()) + if err := result.readResponse(response, consumer, o.formats); err != nil { + return nil, err + } + if response.Code()/100 == 2 { + return result, nil + } + return nil, result + } +} + +// NewLoadSnapshotNoContent creates a LoadSnapshotNoContent with default headers values +func NewLoadSnapshotNoContent() *LoadSnapshotNoContent { + return &LoadSnapshotNoContent{} +} + +/*LoadSnapshotNoContent handles this case with default header values. + +Snapshot loaded +*/ +type LoadSnapshotNoContent struct { +} + +func (o *LoadSnapshotNoContent) Error() string { + return fmt.Sprintf("[PUT /snapshot/load][%d] loadSnapshotNoContent ", 204) +} + +func (o *LoadSnapshotNoContent) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + return nil +} + +// NewLoadSnapshotBadRequest creates a LoadSnapshotBadRequest with default headers values +func NewLoadSnapshotBadRequest() *LoadSnapshotBadRequest { + return &LoadSnapshotBadRequest{} +} + +/*LoadSnapshotBadRequest handles this case with default header values. + +Snapshot cannot be loaded due to bad input +*/ +type LoadSnapshotBadRequest struct { + Payload *models.Error +} + +func (o *LoadSnapshotBadRequest) Error() string { + return fmt.Sprintf("[PUT /snapshot/load][%d] loadSnapshotBadRequest %+v", 400, o.Payload) +} + +func (o *LoadSnapshotBadRequest) GetPayload() *models.Error { + return o.Payload +} + +func (o *LoadSnapshotBadRequest) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.Error) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} + +// NewLoadSnapshotDefault creates a LoadSnapshotDefault with default headers values +func NewLoadSnapshotDefault(code int) *LoadSnapshotDefault { + return &LoadSnapshotDefault{ + _statusCode: code, + } +} + +/*LoadSnapshotDefault handles this case with default header values. + +Internal server error +*/ +type LoadSnapshotDefault struct { + _statusCode int + + Payload *models.Error +} + +// Code gets the status code for the load snapshot default response +func (o *LoadSnapshotDefault) Code() int { + return o._statusCode +} + +func (o *LoadSnapshotDefault) Error() string { + return fmt.Sprintf("[PUT /snapshot/load][%d] loadSnapshot default %+v", o._statusCode, o.Payload) +} + +func (o *LoadSnapshotDefault) GetPayload() *models.Error { + return o.Payload +} + +func (o *LoadSnapshotDefault) readResponse(response runtime.ClientResponse, consumer runtime.Consumer, formats strfmt.Registry) error { + + o.Payload = new(models.Error) + + // response payload + if err := consumer.Consume(response.Body(), o.Payload); err != nil && err != io.EOF { + return err + } + + return nil +} diff --git a/client/operations/operations_client.go b/client/operations/operations_client.go index 25ff041b..efb46d1a 100644 --- a/client/operations/operations_client.go +++ b/client/operations/operations_client.go @@ -275,6 +275,36 @@ func (a *Client) GetMachineConfiguration(params *GetMachineConfigurationParams) } +/* +LoadSnapshot loads a snapshot pre boot only + +Loads the microVM state from a snapshot. Only accepted on a fresh Firecracker process (before configuring any resource other than the Logger and Metrics). +*/ +func (a *Client) LoadSnapshot(params *LoadSnapshotParams) (*LoadSnapshotNoContent, error) { + // TODO: Validate the params before sending + if params == nil { + params = NewLoadSnapshotParams() + } + + result, err := a.transport.Submit(&runtime.ClientOperation{ + ID: "loadSnapshot", + Method: "PUT", + PathPattern: "/snapshot/load", + ProducesMediaTypes: []string{"application/json"}, + ConsumesMediaTypes: []string{"application/json"}, + Schemes: []string{"http"}, + Params: params, + Reader: &LoadSnapshotReader{formats: a.formats}, + Context: params.Context, + Client: params.HTTPClient, + }) + if err != nil { + return nil, err + } + return result.(*LoadSnapshotNoContent), nil + +} + /* PatchGuestDriveByID updates the properties of a drive post boot only @@ -617,6 +647,7 @@ type ClientIface interface { CreateSyncAction(params *CreateSyncActionParams) (*CreateSyncActionNoContent, error) DescribeInstance(params *DescribeInstanceParams) (*DescribeInstanceOK, error) GetMachineConfiguration(params *GetMachineConfigurationParams) (*GetMachineConfigurationOK, error) + LoadSnapshot(params *LoadSnapshotParams) (*LoadSnapshotNoContent, error) PatchGuestDriveByID(params *PatchGuestDriveByIDParams) (*PatchGuestDriveByIDNoContent, error) PatchGuestNetworkInterfaceByID(params *PatchGuestNetworkInterfaceByIDParams) (*PatchGuestNetworkInterfaceByIDNoContent, error) PatchMachineConfiguration(params *PatchMachineConfigurationParams) (*PatchMachineConfigurationNoContent, error) diff --git a/client/swagger.yaml b/client/swagger.yaml index 6ab2e512..39848a6f 100644 --- a/client/swagger.yaml +++ b/client/swagger.yaml @@ -5,7 +5,7 @@ info: The API is accessible through HTTP calls on specific URLs carrying JSON modeled data. The transport medium is a Unix Domain Socket. - version: 0.22.0 + version: 0.23.0 termsOfService: "" contact: email: "compute-capsule@amazon.com" @@ -398,24 +398,26 @@ paths: description: Internal server error schema: $ref: "#/definitions/Error" - /vm: - patch: - summary: Updates the microVM state. + + /snapshot/create: + put: + summary: Creates a full snapshot. Post-boot only. description: - Sets the desired state (Paused or Resumed) for the microVM. - operationId: patchVm + Creates a snapshot of the microVM state. The microVM should be + in the `Paused` state. + operationId: createSnapshot parameters: - name: body in: body - description: The microVM state + description: The configuration used for creating a snaphot. required: true schema: - $ref: "#/definitions/Vm" + $ref: "#/definitions/SnapshotCreateParams" responses: 204: - description: Vm state updated + description: Snapshot created 400: - description: Vm state cannot be updated due to bad input + description: Snapshot cannot be created due to bad input schema: $ref: "#/definitions/Error" default: @@ -423,25 +425,51 @@ paths: schema: $ref: "#/definitions/Error" - /snapshot/create: + /snapshot/load: put: - summary: Creates a full snapshot. Post-boot only. + summary: Loads a snapshot. Pre-boot only. description: - Creates a snapshot of the microVM state. The microVM should be - in the `Paused` state. - operationId: createSnapshot + Loads the microVM state from a snapshot. + Only accepted on a fresh Firecracker process (before configuring + any resource other than the Logger and Metrics). + operationId: loadSnapshot parameters: - name: body in: body - description: The configuration used for creating a snaphot. + description: The configuration used for loading a snaphot. required: true schema: - $ref: "#/definitions/SnapshotCreateParams" + $ref: "#/definitions/SnapshotLoadParams" responses: 204: - description: Snapshot created + description: Snapshot loaded 400: - description: Snapshot cannot be created due to bad input + description: Snapshot cannot be loaded due to bad input + schema: + $ref: "#/definitions/Error" + default: + description: Internal server error + schema: + $ref: "#/definitions/Error" + + /vm: + patch: + summary: Updates the microVM state. + description: + Sets the desired state (Paused or Resumed) for the microVM. + operationId: patchVm + parameters: + - name: body + in: body + description: The microVM state + required: true + schema: + $ref: "#/definitions/Vm" + responses: + 204: + description: Vm state updated + 400: + description: Vm state cannot be updated due to bad input schema: $ref: "#/definitions/Error" default: @@ -484,15 +512,15 @@ definitions: description: Boot source descriptor. properties: - kernel_image_path: + boot_args: type: string - description: Host level path to the kernel image used to boot the guest + description: Kernel boot arguments initrd_path: type: string description: Host level path to the initrd image used to boot the guest - boot_args: + kernel_image_path: type: string - description: Kernel boot arguments + description: Host level path to the kernel image used to boot the guest CpuTemplate: type: string @@ -507,15 +535,14 @@ definitions: type: object required: - drive_id - - path_on_host - - is_root_device - is_read_only + - is_root_device + - path_on_host properties: drive_id: type: string - path_on_host: - type: string - description: Host level path for the guest drive + is_read_only: + type: boolean is_root_device: type: boolean partuuid: @@ -524,8 +551,9 @@ definitions: Represents the unique id of the boot partition of this device. It is optional and it will be taken into account only if the is_root_device field is true. - is_read_only: - type: boolean + path_on_host: + type: string + description: Host level path for the guest drive rate_limiter: $ref: "#/definitions/RateLimiter" @@ -561,6 +589,9 @@ definitions: - state - vmm_version properties: + app_name: + description: Application name. + type: string id: description: MicroVM / instance ID. type: string @@ -576,9 +607,6 @@ definitions: vmm_version: description: MicroVM hypervisor build version. type: string - app_name: - description: Application name. - type: string Logger: type: object @@ -587,14 +615,14 @@ definitions: required: - log_path properties: - log_path: - type: string - description: Path to the named pipe or file for the human readable log output. level: type: string - description: Set the level. + description: Set the level. The possible values are case-insensitive. enum: [Error, Warning, Info, Debug] default: Warning + log_path: + type: string + description: Path to the named pipe or file for the human readable log output. show_level: type: boolean description: Whether or not to output the level in the logs. @@ -610,23 +638,30 @@ definitions: Describes the number of vCPUs, memory size, Hyperthreading capabilities and the CPU template. required: - - vcpu_count - - mem_size_mib - ht_enabled + - mem_size_mib + - vcpu_count properties: + cpu_template: + $ref: "#/definitions/CpuTemplate" + ht_enabled: + type: boolean + description: Flag for enabling/disabling Hyperthreading + mem_size_mib: + type: integer + description: Memory size of VM + track_dirty_pages: + type: boolean + description: + Enable dirty page tracking. If this is enabled, then incremental guest memory + snapshots can be created. These belong to diff snapshots, which contain, besides + the microVM state, only the memory dirtied since a previous snapshot. Full snapshots + each contain a full copy of the guest memory. vcpu_count: type: integer minimum: 1 maximum: 32 description: Number of vCPUs (either 1 or an even number) - mem_size_mib: - type: integer - description: Memory size of VM - ht_enabled: - type: boolean - description: Flag for enabling/disabling Hyperthreading - cpu_template: - $ref: "#/definitions/CpuTemplate" Metrics: type: object @@ -655,16 +690,9 @@ definitions: description: Defines a network interface. required: - - iface_id - host_dev_name + - iface_id properties: - iface_id: - type: string - guest_mac: - type: string - host_dev_name: - type: string - description: Host level path for the guest network interface allow_mmds_requests: type: boolean description: @@ -673,6 +701,13 @@ definitions: both ARP requests for 169.254.169.254 and TCP segments heading to the same address are intercepted by the device model, and do not reach the associated TAP device. + guest_mac: + type: string + host_dev_name: + type: string + description: Host level path for the guest network interface + iface_id: + type: string rx_rate_limiter: $ref: "#/definitions/RateLimiter" tx_rate_limiter: @@ -742,7 +777,24 @@ definitions: description: The microVM version for which we want to create the snapshot. It is optional and it defaults to the current version. - + + SnapshotLoadParams: + type: object + required: + - mem_file_path + - snapshot_path + properties: + enable_diff_snapshots: + type: boolean + description: + Enable support for incremental (diff) snapshots by tracking dirty guest pages. + mem_file_path: + type: string + description: Path to the file that contains the guest memory to be loaded. + snapshot_path: + type: string + description: Path to the file that contains the microVM state to be loaded. + TokenBucket: type: object description: @@ -755,14 +807,9 @@ definitions: bound in size by the amount of tokens available. Once the token bucket is empty, consumption speed is bound by the refill_rate. required: - - size - refill_time + - size properties: - size: - type: integer - format: int64 - description: The total number of tokens this bucket can hold. - minimum: 0 one_time_burst: type: integer format: int64 @@ -773,6 +820,11 @@ definitions: format: int64 description: The amount of milliseconds it takes for the bucket to refill. minimum: 0 + size: + type: integer + format: int64 + description: The total number of tokens this bucket can hold. + minimum: 0 Vm: type: object @@ -800,12 +852,10 @@ definitions: bound and listening on Unix sockets at `uds_path_`. E.g. "/path/to/host_vsock.sock_52" for port number 52. required: - - vsock_id - guest_cid - uds_path + - vsock_id properties: - vsock_id: - type: string guest_cid: type: integer minimum: 3 @@ -813,4 +863,5 @@ definitions: uds_path: type: string description: Path to UNIX domain socket, used to proxy vsock connections. - + vsock_id: + type: string \ No newline at end of file diff --git a/fctesting/firecracker_mock_client.go b/fctesting/firecracker_mock_client.go index 5f48ca1f..ac9aa3e1 100644 --- a/fctesting/firecracker_mock_client.go +++ b/fctesting/firecracker_mock_client.go @@ -28,6 +28,7 @@ type MockClient struct { CreateSyncActionFn func(params *ops.CreateSyncActionParams) (*ops.CreateSyncActionNoContent, error) DescribeInstanceFn func(params *ops.DescribeInstanceParams) (*ops.DescribeInstanceOK, error) GetMachineConfigurationFn func(params *ops.GetMachineConfigurationParams) (*ops.GetMachineConfigurationOK, error) + LoadSnapshotFn func(params *ops.LoadSnapshotParams) (*ops.LoadSnapshotNoContent, error) PatchGuestDriveByIDFn func(params *ops.PatchGuestDriveByIDParams) (*ops.PatchGuestDriveByIDNoContent, error) PatchGuestNetworkInterfaceByIDFn func(params *ops.PatchGuestNetworkInterfaceByIDParams) (*ops.PatchGuestNetworkInterfaceByIDNoContent, error) PatchMachineConfigurationFn func(params *ops.PatchMachineConfigurationParams) (*ops.PatchMachineConfigurationNoContent, error) @@ -105,6 +106,14 @@ func (c *MockClient) GetMachineConfiguration(params *ops.GetMachineConfiguration return nil, nil } +func (c *MockClient) LoadSnapshot(params *ops.LoadSnapshotParams) (*ops.LoadSnapshotNoContent, error) { + if c.LoadSnapshotFn != nil { + return c.LoadSnapshotFn(params) + } + + return nil, nil +} + func (c *MockClient) PatchGuestDriveByID(params *ops.PatchGuestDriveByIDParams) (*ops.PatchGuestDriveByIDNoContent, error) { if c.PatchGuestDriveByIDFn != nil { return c.PatchGuestDriveByIDFn(params) diff --git a/machine.go b/machine.go index 49da32fb..4607d0a1 100644 --- a/machine.go +++ b/machine.go @@ -1003,7 +1003,7 @@ func (m *Machine) setupSignals() { }() } -// PauseVM Pauses the VM +// PauseVM pauses the VM func (m *Machine) PauseVM(ctx context.Context, opts ...PatchVMOpt) error { vm := &models.VM{ State: String(models.VMStatePaused), @@ -1018,7 +1018,7 @@ func (m *Machine) PauseVM(ctx context.Context, opts ...PatchVMOpt) error { return nil } -// ResumeVM Resumes the VM +// ResumeVM resumes the VM func (m *Machine) ResumeVM(ctx context.Context, opts ...PatchVMOpt) error { vm := &models.VM{ State: String(models.VMStateResumed), @@ -1033,7 +1033,7 @@ func (m *Machine) ResumeVM(ctx context.Context, opts ...PatchVMOpt) error { return nil } -// CreateSnapshot Creates a snapshot of the VM +// CreateSnapshot creates a snapshot of the VM func (m *Machine) CreateSnapshot(ctx context.Context, memFilePath, snapshotPath string, opts ...CreateSnapshotOpt) error { snapshotParams := &models.SnapshotCreateParams{ MemFilePath: String(memFilePath), @@ -1046,6 +1046,5 @@ func (m *Machine) CreateSnapshot(ctx context.Context, memFilePath, snapshotPath } m.logger.Debug("snapshot created successfully") - return nil } From b86c07b7a2f07f9da7f4f0f9f0b379edc9d8183c Mon Sep 17 00:00:00 2001 From: Plamen Petrov Date: Mon, 9 Nov 2020 15:09:11 +0200 Subject: [PATCH 4/4] tests for pause, resume, createSnapshot Signed-off-by: Plamen Petrov --- Makefile | 2 +- machine_test.go | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 51f41622..c0582f6b 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ GID = $(shell id -g) # The below files are needed and can be downloaded from the internet testdata_objects = testdata/vmlinux testdata/root-drive.img testdata/firecracker testdata/jailer -firecracker_version = v0.22.0 +firecracker_version = v0.23.0 # --location is needed to follow redirects on github.com curl = curl --location diff --git a/machine_test.go b/machine_test.go index 5c2126cc..7d55c5c4 100644 --- a/machine_test.go +++ b/machine_test.go @@ -1476,3 +1476,172 @@ func TestSignalForwarding(t *testing.T) { assert.ElementsMatch(t, forwardedSignals, receivedSignals) } + +func TestPauseResume(t *testing.T) { + fctesting.RequiresRoot(t) + + cases := []struct { + name string + state func(m *Machine, ctx context.Context) + }{ + { + name: "PauseVM", + state: func(m *Machine, ctx context.Context) { + err := m.PauseVM(ctx) + require.NoError(t, err) + }, + }, + { + name: "ResumeVM", + state: func(m *Machine, ctx context.Context) { + err := m.ResumeVM(ctx) + require.NoError(t, err) + }, + }, + { + name: "Consecutive PauseVM", + state: func(m *Machine, ctx context.Context) { + err := m.PauseVM(ctx) + require.NoError(t, err) + + err = m.PauseVM(ctx) + require.NoError(t, err) + }, + }, + { + name: "Consecutive ResumeVM", + state: func(m *Machine, ctx context.Context) { + err := m.ResumeVM(ctx) + require.NoError(t, err) + + err = m.ResumeVM(ctx) + require.NoError(t, err) + }, + }, + { + name: "ResumeVM PauseVM", + state: func(m *Machine, ctx context.Context) { + err := m.ResumeVM(ctx) + require.NoError(t, err) + + err = m.PauseVM(ctx) + require.NoError(t, err) + }, + }, + { + name: "PauseVM ResumeVM", + state: func(m *Machine, ctx context.Context) { + err := m.PauseVM(ctx) + require.NoError(t, err) + + err = m.ResumeVM(ctx) + require.NoError(t, err) + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + ctx := context.Background() + + socketPath := filepath.Join(testDataPath, fsSafeTestName.Replace(t.Name())) + defer os.Remove(socketPath) + + // Tee logs for validation: + var logBuffer bytes.Buffer + machineLogger := logrus.New() + machineLogger.Out = io.MultiWriter(os.Stderr, &logBuffer) + + cfg := createValidConfig(t, socketPath) + m, err := NewMachine(ctx, cfg, func(m *Machine) { + // Rewriting m.cmd partially wouldn't work since Cmd has + // some unexported members + args := m.cmd.Args[1:] + m.cmd = exec.Command(getFirecrackerBinaryPath(), args...) + }, WithLogger(logrus.NewEntry(machineLogger))) + require.NoError(t, err) + + err = m.PauseVM(ctx) + require.Error(t, err, "PauseVM must fail before Start is called") + + err = m.ResumeVM(ctx) + require.Error(t, err, "ResumeVM must fail before Start is called") + + err = m.Start(ctx) + require.NoError(t, err) + + c.state(m, ctx) + + err = m.StopVMM() + require.NoError(t, err) + + err = m.PauseVM(ctx) + require.Error(t, err, "PauseVM must fail after StopVMM is called") + + err = m.ResumeVM(ctx) + require.Error(t, err, "ResumeVM must fail after StopVMM is called") + }) + } +} + +func TestCreateSnapshot(t *testing.T) { + fctesting.RequiresRoot(t) + + cases := []struct { + name string + createSnapshot func(m *Machine, ctx context.Context, memPath, snapPath string) + }{ + { + name: "CreateSnapshot", + createSnapshot: func(m *Machine, ctx context.Context, memPath, snapPath string) { + err := m.PauseVM(ctx) + require.NoError(t, err) + + err = m.CreateSnapshot(ctx, memPath, snapPath) + require.NoError(t, err) + }, + }, + { + name: "CreateSnapshot before pause", + createSnapshot: func(m *Machine, ctx context.Context, memPath, snapPath string) { + err := m.CreateSnapshot(ctx, memPath, snapPath) + require.Error(t, err) + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + ctx := context.Background() + + socketPath := filepath.Join(testDataPath, fsSafeTestName.Replace(t.Name())) + snapPath := socketPath + "SnapFile" + memPath := socketPath + "MemFile" + defer os.Remove(socketPath) + defer os.Remove(snapPath) + defer os.Remove(memPath) + + // Tee logs for validation: + var logBuffer bytes.Buffer + machineLogger := logrus.New() + machineLogger.Out = io.MultiWriter(os.Stderr, &logBuffer) + + cfg := createValidConfig(t, socketPath) + m, err := NewMachine(ctx, cfg, func(m *Machine) { + // Rewriting m.cmd partially wouldn't work since Cmd has + // some unexported members + args := m.cmd.Args[1:] + m.cmd = exec.Command(getFirecrackerBinaryPath(), args...) + }, WithLogger(logrus.NewEntry(machineLogger))) + require.NoError(t, err) + + err = m.Start(ctx) + require.NoError(t, err) + + c.createSnapshot(m, ctx, memPath, snapPath) + + err = m.StopVMM() + require.NoError(t, err) + }) + } +}