Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add docs and tests for CRIT #76

Merged
merged 3 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@ jobs:
with:
go-version: ${{ matrix.go-version }}

- name: Run tests
- name: Test go-criu
run: sudo env "PATH=$PATH" make test

- name: Test magicgen script
run: make -C scripts test

- name: Test crit
run: sudo make -C test crit-test

- name: Check code coverage
if: matrix.go-version == '1.18.x' && matrix.criu_branch == 'criu-dev'
run: |
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ test/test.coverage
test/piggie/piggie
test/phaul/phaul
test/phaul/phaul.coverage
test/loop/loop
test/crit/crit-test
test/crit/test-imgs
image
scripts/*.h
scripts/expected.go
Expand Down
18 changes: 14 additions & 4 deletions crit/cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var c crit.CritSvc
var inputFilePath, outputFilePath, inputDirPath string
var pretty, noPayload bool

// The `crit` command
var rootCmd = &cobra.Command{
Use: "crit",
Short: "CRIU Image Tool(CRIT) to manipulate CRIU image files",
Expand All @@ -27,6 +28,7 @@ This is a Go implementation of the original Python app.
Find the complete documentation is at https://criu.org/CRIT`,
}

// The `crit decode` command
var decodeCmd = &cobra.Command{
Use: "decode",
Short: "Convert binary image to JSON",
Expand Down Expand Up @@ -67,9 +69,10 @@ If no output file is provided, the JSON is printed to stdout.`,
},
}

// The `crit encode` command
var encodeCmd = &cobra.Command{
Use: "encode",
Short: "Convert JSON to binary file",
Short: "Convert JSON to binary image file",
Long: "Convert the input JSON to a CRIU image file.",
Run: func(cmd *cobra.Command, args []string) {
c = crit.NewCli(inputFilePath, outputFilePath,
Expand All @@ -79,13 +82,14 @@ var encodeCmd = &cobra.Command{
if err != nil {
log.Fatal(err)
}
// Write Go struct to binary file
// Write Go struct to binary image file
if err := c.Encode(img); err != nil {
log.Fatal(err)
}
},
}

// The `crit show` command
var showCmd = &cobra.Command{
Use: "show INPATH",
Short: "Convert binary image to human-readable JSON",
Expand All @@ -109,6 +113,7 @@ var showCmd = &cobra.Command{
},
}

// The `crit info` command
var infoCmd = &cobra.Command{
Use: "info INPATH",
Short: "Show information about the image file",
Expand All @@ -130,15 +135,19 @@ var infoCmd = &cobra.Command{
},
}

// The `crit x` command
var xCmd = &cobra.Command{
Use: "x DIR {ps|fds|mems|rss}",
Short: "Explore the image directory",
Long: "Explore the image directory with one of (ps, fds, mems, rss) options",
Args: cobra.ExactArgs(2),
// Exactly two arguments are required:
// * Path of the input directory
// * Explore type
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
inputDirPath = args[0]
// We can use an empty interface to hold the
// returned values since we don't really care
// returned object since we don't really care
// about the data itself, as long as we can
// marshal it into JSON and display it.
var xData interface{}
Expand Down Expand Up @@ -171,6 +180,7 @@ var xCmd = &cobra.Command{
},
}

// Add all commands to the root command and configure flags
func init() {
// Disable completion generation
rootCmd.CompletionOptions.DisableDefaultCmd = true
Expand Down
45 changes: 31 additions & 14 deletions crit/crit.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,42 @@ import (
"os"
)

type crit struct {
inputFilePath string
outputFilePath string
// Directory path is required only for `crit explore`
inputDirPath string
pretty bool
noPayload bool
cli bool
}

// CritSvc is the interface that wraps all CRIT operations.
// To create a CRIT service instance, use New().
type CritSvc interface {
// Read binary file into Go struct (`decode.go`)
// Read binary image file into Go struct (decode.go)
Decode() (*CriuImage, error)
// Read only counts of binary file entries into Go struct
// Read only counts of image file entries into Go struct
Info() (*CriuImage, error)
// Read JSON into Go struct
Parse() (*CriuImage, error)
// Write JSON to binary file (`encode.go`)
// Write JSON to binary image file (encode.go)
Encode(*CriuImage) error
// Explore process information (`explore.go`)
// Explore process information (explore.go)
ExplorePs() (*PsTree, error)
ExploreFds() ([]*Fd, error)
ExploreMems() ([]*MemMap, error)
ExploreRss() ([]*RssMap, error)
}

// crit implements the CritSvc interface. It contains:
// * Path of the input file
// * Path of the output file
// * Path of the input directory (for `crit explore`)
// * Boolean to provide indented and multi-line JSON output
// * Boolean to skip payload data
// * Boolean to indicate CLI usage
type crit struct {
inputFilePath string
outputFilePath string
// Directory path is required only for exploring
inputDirPath string
pretty bool
noPayload bool
cli bool
}

// New creates a CRIT service to use in a Go program
func New(
inputFilePath, outputFilePath,
inputDirPath string,
Expand Down Expand Up @@ -67,6 +77,7 @@ func NewCli(
}
}

// Decode loads a binary image file into a CriuImage object
func (c *crit) Decode() (*CriuImage, error) {
// If no input path is provided in the CLI, read
// from stdin (pipe, redirection, or keyboard)
Expand All @@ -86,6 +97,9 @@ func (c *crit) Decode() (*CriuImage, error) {
return decodeImg(imgFile, c.noPayload)
}

// Info loads a binary image file into a CriuImage object
// with a single entry - the number of entries in the file.
// No payload data is present in the returned object.
func (c *crit) Info() (*CriuImage, error) {
// If no input path is provided in the CLI, read
// from stdin (pipe, redirection, or keyboard)
Expand All @@ -105,6 +119,8 @@ func (c *crit) Info() (*CriuImage, error) {
return countImg(imgFile)
}

// Parse is the JSON equivalent of Decode.
// It loads a JSON file into a CriuImage object.
func (c *crit) Parse() (*CriuImage, error) {
var (
jsonData []byte
Expand Down Expand Up @@ -133,6 +149,7 @@ func (c *crit) Parse() (*CriuImage, error) {
return &img, nil
}

// Encode dumps a CriuImage object into a binary image file
func (c *crit) Encode(img *CriuImage) error {
// If no output path is provided in the CLI, print to stdout
if c.outputFilePath == "" {
Expand Down
7 changes: 7 additions & 0 deletions crit/decode-extra.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"google.golang.org/protobuf/proto"
)

// Extra data handler for pipe and FIFO data
func decodePipesData(
f *os.File,
payload proto.Message,
Expand All @@ -35,6 +36,7 @@ func decodePipesData(
return base64.StdEncoding.EncodeToString(extraBuf), nil
}

// Extra data handler for socket queues
func decodeSkQueues(
f *os.File,
payload proto.Message,
Expand Down Expand Up @@ -62,6 +64,7 @@ type tcpStreamExtra struct {
OutQ string `json:"outQ"`
}

// Extra data handler for TCP streams
func decodeTcpStream(
f *os.File,
payload proto.Message,
Expand Down Expand Up @@ -95,6 +98,7 @@ func decodeTcpStream(
return string(extraJson), err
}

// Extra data handler for BPF map data
func decodeBpfmapData(
f *os.File,
payload proto.Message,
Expand All @@ -117,6 +121,7 @@ func decodeBpfmapData(
return base64.StdEncoding.EncodeToString(extraBuf), nil
}

// Extra data handler for IPC semaphores
func decodeIpcSem(
f *os.File,
payload proto.Message,
Expand Down Expand Up @@ -149,6 +154,7 @@ func decodeIpcSem(
return string(extraJson), err
}

// Extra data handler for IPC shared memory
func decodeIpcShm(
f *os.File,
payload proto.Message,
Expand All @@ -174,6 +180,7 @@ func decodeIpcShm(
return base64.StdEncoding.EncodeToString(extraBuf), nil
}

// Extra data handler for IPC messages
func decodeIpcMsg(
f *os.File,
payload proto.Message,
Expand Down
6 changes: 6 additions & 0 deletions crit/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"google.golang.org/protobuf/proto"
)

// decodeImg identifies the type of image file
// and calls the appropriate decode handler
func decodeImg(f *os.File, noPayload bool) (*CriuImage, error) {
img := CriuImage{}
var err error
Expand Down Expand Up @@ -52,6 +54,8 @@ func decodeImg(f *os.File, noPayload bool) (*CriuImage, error) {
return &img, nil
}

// decodeDefault is used for all image files
// that are in the standard protobuf format
func (img *CriuImage) decodeDefault(
f *os.File,
decodeExtra func(*os.File, proto.Message, bool) (string, error),
Expand Down Expand Up @@ -92,6 +96,7 @@ func (img *CriuImage) decodeDefault(
return nil
}

// Special handler for pagemap image
func (img *CriuImage) decodePagemap(f *os.File) error {
sizeBuf := make([]byte, 4)
// First entry is pagemap head
Expand Down Expand Up @@ -121,6 +126,7 @@ func (img *CriuImage) decodePagemap(f *os.File) error {
return nil
}

// Special handler for ghost image
func (img *CriuImage) decodeGhostFile(f *os.File, noPayload bool) error {
sizeBuf := make([]byte, 4)
if _, err := f.Read(sizeBuf); err != nil {
Expand Down
7 changes: 7 additions & 0 deletions crit/encode-extra.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ import (
"google.golang.org/protobuf/proto"
)

// Extra payload handler for pipe and FIFO data
func encodePipesData(extra string) ([]byte, error) {
return base64.StdEncoding.DecodeString(extra)
}

// Extra payload handler for socket queues
func encodeSkQueues(extra string) ([]byte, error) {
return base64.StdEncoding.DecodeString(extra)
}

// Extra payload handler for TCP streams
func encodeTcpStream(extra string) ([]byte, error) {
extraPayload := tcpStreamExtra{}
if err := json.Unmarshal([]byte(extra), &extraPayload); err != nil {
Expand All @@ -36,10 +39,12 @@ func encodeTcpStream(extra string) ([]byte, error) {
return append(inqBytes, outQBytes...), nil
}

// Extra payload handler for BPF map data
func encodeBpfmapData(extra string) ([]byte, error) {
return base64.StdEncoding.DecodeString(extra)
}

// Extra payload handler for IPC semaphores
func encodeIpcSem(extra string) ([]byte, error) {
extraEntries := []uint16{}
if err := json.Unmarshal([]byte(extra), &extraEntries); err != nil {
Expand All @@ -62,6 +67,7 @@ func encodeIpcSem(extra string) ([]byte, error) {
return extraPayload, nil
}

// Extra payload handler for IPC shared memory
func encodeIpcShm(extra string) ([]byte, error) {
extraPayload, err := base64.StdEncoding.DecodeString(extra)
if err != nil {
Expand All @@ -75,6 +81,7 @@ func encodeIpcShm(extra string) ([]byte, error) {
return extraPayload, nil
}

// Extra payload handler for IPC messages
func encodeIpcMsg(extra string) ([]byte, error) {
extraEntries := []string{}
if err := json.Unmarshal([]byte(extra), &extraEntries); err != nil {
Expand Down
5 changes: 5 additions & 0 deletions crit/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"google.golang.org/protobuf/proto"
)

// encodeImg identifies the type of image file
// and calls the appropriate encode handler
func encodeImg(img *CriuImage, f *os.File) error {
magicMap := magic.LoadMagic()
var err error
Expand Down Expand Up @@ -68,6 +70,8 @@ func encodeImg(img *CriuImage, f *os.File) error {
return nil
}

// encodeDefault is used for all image files
// that are in the standard protobuf format
func (img *CriuImage) encodeDefault(
f *os.File,
encodeExtra func(string) ([]byte, error),
Expand Down Expand Up @@ -106,6 +110,7 @@ func (img *CriuImage) encodeDefault(
return nil
}

// Special handler for ghost image
func (img *CriuImage) encodeGhostFile(f *os.File) error {
sizeBuf := make([]byte, 4)
// Write primary entry
Expand Down
Loading