From 1b2ce4a2ad41d06cddde9d4601f86424e142cb2e Mon Sep 17 00:00:00 2001 From: Sagore Sarker Date: Wed, 20 Mar 2024 01:39:28 +0600 Subject: [PATCH] docs: Add comments for improved code readability in main function This commit enhances the readability of the main function by adding comments to explain each line of code. These comments provide clarity and guidance for beginners, helping them understand the purpose and functionality of each step in setting up the environment for managing Firecracker microVM snapshots. Signed-off-by: Sagore Sarker --- examples/cmd/snapshotting/example_demo.go | 68 ++++++++++++++++------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/examples/cmd/snapshotting/example_demo.go b/examples/cmd/snapshotting/example_demo.go index 976bf140..32c4328c 100644 --- a/examples/cmd/snapshotting/example_demo.go +++ b/examples/cmd/snapshotting/example_demo.go @@ -11,6 +11,15 @@ // express or implied. See the License for the specific language governing // permissions and limitations under the License. +// Package main provides a Go program for managing snapshots of Firecracker microVMs. +// The program utilizes the Firecracker Go SDK for creating and loading snapshots, +// and it demonstrates how to establish SSH connections to interact with microVMs. +// Comments are provided to explain each function's purpose and usage. + +// In this program, a "snapshot" refers to a point-in-time copy of the state of a Firecracker microVM. +// Snapshots capture the complete memory and state of the microVM, allowing users to save and restore its exact configuration and execution context. +// They enable quick deployment and management of microVM instances with pre-defined configurations and states, which is useful for testing, development, and deployment scenarios. + package main import ( @@ -31,19 +40,21 @@ import ( models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" ) +// Constants for CNI configuration const ( // Using default cache directory to ensure collision avoidance on IP allocations - cniCacheDir = "/var/lib/cni" - networkName = "fcnet" - ifName = "veth0" + cniCacheDir = "/var/lib/cni" // Default cache directory for IP allocations + networkName = "fcnet" // Name of the network + ifName = "veth0" // Interface name - networkMask string = "/24" - subnet string = "10.168.0.0" + networkMask + networkMask = "/24" // Subnet mask + subnet = "10.168.0.0" + networkMask - maxRetries int = 10 - backoffTimeMs time.Duration = 500 + maxRetries = 10 // Maximum number of retries for SSH connection + backoffTimeMs = 500 * time.Millisecond // Backoff time for retries ) +// writeCNIConfWithHostLocalSubnet writes CNI configuration to a file with a host-local subnet func writeCNIConfWithHostLocalSubnet(path, networkName, subnet string) error { return ioutil.WriteFile(path, []byte(fmt.Sprintf(`{ "cniVersion": "0.3.1", @@ -63,14 +74,17 @@ func writeCNIConfWithHostLocalSubnet(path, networkName, subnet string) error { }`, networkName, subnet)), 0644) } +// configOpt is a functional option for configuring the Firecracker microVM type configOpt func(*sdk.Config) +// withNetworkInterface adds a network interface configuration option to the Firecracker microVM config func withNetworkInterface(networkInterface sdk.NetworkInterface) configOpt { return func(c *sdk.Config) { c.NetworkInterfaces = append(c.NetworkInterfaces, networkInterface) } } +// createNewConfig creates a new Firecracker microVM configuration func createNewConfig(socketPath string, opts ...configOpt) sdk.Config { dir, _ := os.Getwd() fmt.Println(dir) @@ -110,6 +124,7 @@ func createNewConfig(socketPath string, opts ...configOpt) sdk.Config { return cfg } +// connectToVM establishes an SSH connection to the Firecracker microVM func connectToVM(m *sdk.Machine, sshKeyPath string) (*ssh.Client, error) { key, err := ioutil.ReadFile(sshKeyPath) if err != nil { @@ -139,6 +154,7 @@ func connectToVM(m *sdk.Machine, sshKeyPath string) (*ssh.Client, error) { return ssh.Dial("tcp", fmt.Sprintf("%s:22", ip), config) } +// createSnapshotSSH creates a snapshot of a Firecracker microVM and returns the IP of the VM func createSnapshotSSH(ctx context.Context, socketPath, memPath, snapPath string) string { dir, err := os.Getwd() if err != nil { @@ -246,6 +262,7 @@ func createSnapshotSSH(ctx context.Context, socketPath, memPath, snapPath string return vmIP } +// loadSnapshotSSH loads a snapshot of the Firecracker microVM using SSH func loadSnapshotSSH(ctx context.Context, socketPath, memPath, snapPath, ipToRestore string) { var ipFreed bool = false var err error @@ -383,48 +400,57 @@ func loadSnapshotSSH(ctx context.Context, socketPath, memPath, snapPath, ipToRes func main() { // Check for kvm and root access - err := unix.Access("/dev/kvm", unix.W_OK) - if err != nil { + err := unix.Access("/dev/kvm", unix.W_OK) // Check if the program has write access to /dev/kvm + if err != nil { // If there's an error (e.g., access denied), log and exit log.Fatal(err) } + // Check if the program is running with root privileges if x, y := 0, os.Getuid(); x != y { log.Fatal("Root acccess denied") } + // Get the current working directory dir, err := os.Getwd() - if err != nil { + if err != nil { // If there's an error getting the working directory, log and exit log.Fatal(err) } + // Create a directory for CNI configuration files cniConfDir := filepath.Join(dir, "cni.conf") - err = os.Mkdir(cniConfDir, 0777) - if err != nil { + err = os.Mkdir(cniConfDir, 0777) // Create the directory with full permissions + if err != nil { // If there's an error creating the directory, log and exit log.Fatal(err) } - defer os.Remove(cniConfDir) + defer os.Remove(cniConfDir) // Remove the directory when main function exits - // Setup socket and snapshot + memory paths - tempdir, err := ioutil.TempDir("", "FCGoSDKSnapshotExample") - if err != nil { + // Setup temporary directory and paths for socket, snapshot, and memory files + tempdir, err := ioutil.TempDir("", "FCGoSDKSnapshotExample") // Create a temporary directory + if err != nil { // If there's an error creating the temporary directory, log and exit log.Fatal(err) } - defer os.Remove(tempdir) - socketPath := filepath.Join(tempdir, "snapshotssh") + defer os.Remove(tempdir) // Remove the temporary directory when main function exits + socketPath := filepath.Join(tempdir, "snapshotssh") // Create a socket path within the temporary directory + // Create a directory for snapshot and memory files snapshotsshPath := filepath.Join(dir, "snapshotssh") - err = os.Mkdir(snapshotsshPath, 0777) - if err != nil && !errors.Is(err, os.ErrExist) { + err = os.Mkdir(snapshotsshPath, 0777) // Create the directory with full permissions + if err != nil && !errors.Is(err, os.ErrExist) { // If there's an error creating the directory and it's not already exist, log and exit log.Fatal(err) } - defer os.RemoveAll(snapshotsshPath) + defer os.RemoveAll(snapshotsshPath) // Remove the directory and its contents when main function exits + // Set paths for snapshot and memory files snapPath := filepath.Join(snapshotsshPath, "SnapFile") memPath := filepath.Join(snapshotsshPath, "MemFile") + // Create a background context ctx := context.Background() + // Create a snapshot of the Firecracker microVM and get the IP address to restore ipToRestore := createSnapshotSSH(ctx, socketPath, memPath, snapPath) fmt.Println() + + // Load the snapshot of the Firecracker microVM loadSnapshotSSH(ctx, socketPath, memPath, snapPath, ipToRestore) }