Skip to content

Commit

Permalink
feat: handle dockercompat inspect for devcontainers
Browse files Browse the repository at this point in the history
Signed-off-by: Shubharanshu Mahapatra <[email protected]>
  • Loading branch information
Shubhranshu153 committed Oct 3, 2024
1 parent 5a47eec commit 90ce0b0
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 14 deletions.
100 changes: 100 additions & 0 deletions cmd/finch/devcontainer_patch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// Package main denotes the entry point of finch CLI.
// TODO: Remove all instances of these calls once supported upstream
package main

import (
"bytes"
"encoding/json"
"fmt"

"github.com/sirupsen/logrus"

"github.com/runfinch/finch/pkg/command"
)

// nerdctl outputs multiple id inspect call as multiple arrays of json which is not parsable by json.
//
// Helper function helps to separate out into individual json array and a single json is reconstructed.
func extractOuterArrays(input string) []string {
var arrays []string
var bracketCount, start int

for i, char := range input {
switch char {
case '[':
if bracketCount == 0 {
start = i
}
bracketCount++
case ']':
bracketCount--
if bracketCount == 0 {
arrays = append(arrays, input[start:i+1])
}
}
}

return arrays
}

func prettyPrintJSON(input string) {
jsonArrays := extractOuterArrays(input)
var mergedData []map[string]interface{}

for i, jsonArray := range jsonArrays {
var parsedArray []map[string]interface{}
err := json.Unmarshal([]byte(jsonArray), &parsedArray)
if err != nil {
logrus.Error("Error parsing JSON at index: ", i, err)
continue
}

if len(parsedArray) == 0 {
continue
}

// its always is a single object
firstObject := parsedArray[0]
_, ok := firstObject["Config"].(map[string]interface{})
if ok {
if image, ok := firstObject["Image"].(string); ok {
if config, ok := firstObject["Config"].(map[string]interface{}); ok {
config["Image"] = image
}
}
}

if state, ok := firstObject["State"].(map[string]interface{}); ok {
state["StartedAt"] = "0001-01-01T00:00:00Z"
}

_, ok = firstObject["NetworkSettings"].(map[string]interface{})
if !ok {
firstObject["NetworkSettings"] = map[string]interface{}{
"Ports": map[string]interface{}{},
}
}
mergedData = append(mergedData, firstObject)
}

finalJSON, err := json.MarshalIndent(mergedData, "", " ")
if err != nil {
logrus.Error("Error marshaling final JSON: ", err)
return
}

fmt.Println(string(finalJSON))
}

func inspectContainerOutputHandler(cmd command.Command) error {
var stdoutBuf bytes.Buffer
cmd.SetStdout(&stdoutBuf)

err := cmd.Run()

prettyPrintJSON(stdoutBuf.String())
return err
}
17 changes: 9 additions & 8 deletions cmd/finch/nerdctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type nerdctlCommandCreator struct {

type (
argHandler func(systemDeps NerdctlCommandSystemDeps, fc *config.Finch, args []string, index int) error
commandHandler func(systemDeps NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string, args *[]string) error
commandHandler func(systemDeps NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string, args *[]string, inspectType *string) error
)

func newNerdctlCommandCreator(
Expand Down Expand Up @@ -256,7 +256,7 @@ func handleDockerBuildLoad(_ NerdctlCommandSystemDeps, fc *config.Finch, nerdctl
return nil
}

func handleBuildx(_ NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string, args *[]string) error {
func handleBuildx(_ NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string, args *[]string, _ *string) error {
if fc == nil || !fc.DockerCompat {
return nil
}
Expand All @@ -279,7 +279,7 @@ func handleBuildx(_ NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string,
return nil
}

func handleDockerCompatInspect(_ NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string, args *[]string) error {
func handleDockerCompatInspect(_ NerdctlCommandSystemDeps, fc *config.Finch, cmdName *string, args *[]string, inspectType *string) error {
if fc == nil || !fc.DockerCompat {
return nil
}
Expand All @@ -289,10 +289,10 @@ func handleDockerCompatInspect(_ NerdctlCommandSystemDeps, fc *config.Finch, cmd
}

modeDockerCompat := `--mode=dockercompat`
inspectType := ""
sizeArg := ""
savedArgs := []string{}
skip := false
*inspectType = ""

for idx, arg := range *args {
if skip {
Expand All @@ -301,13 +301,13 @@ func handleDockerCompatInspect(_ NerdctlCommandSystemDeps, fc *config.Finch, cmd
}

if (arg == "--type") && (idx < len(*args)-1) {
inspectType = (*args)[idx+1]
*inspectType = (*args)[idx+1]
skip = true
continue
}

if strings.Contains(arg, "--type") && strings.Contains(arg, "=") {
inspectType = strings.Split(arg, "=")[1]
*inspectType = strings.Split(arg, "=")[1]
continue
}

Expand All @@ -319,7 +319,7 @@ func handleDockerCompatInspect(_ NerdctlCommandSystemDeps, fc *config.Finch, cmd
savedArgs = append(savedArgs, arg)
}

switch inspectType {
switch *inspectType {
case "image":
*cmdName = "image inspect"
*args = append([]string{modeDockerCompat}, savedArgs...)
Expand All @@ -336,8 +336,9 @@ func handleDockerCompatInspect(_ NerdctlCommandSystemDeps, fc *config.Finch, cmd
case "":
*cmdName = "inspect"
*args = append([]string{modeDockerCompat}, savedArgs...)
*inspectType = "container"
default:
return fmt.Errorf("unsupported inspect type: %s", inspectType)
return fmt.Errorf("unsupported inspect type: %s", *inspectType)
}

return nil
Expand Down
7 changes: 7 additions & 0 deletions cmd/finch/nerdctl_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package main

import (
"bytes"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -1306,6 +1307,8 @@ func TestNerdctlCommand_run_inspectCommand(t *testing.T) {
ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false)
ncsd.EXPECT().LookupEnv("COMPOSE_FILE").Return("", false)
c := mocks.NewCommand(ctrl)
var stdoutBuf bytes.Buffer
c.EXPECT().SetStdout(&stdoutBuf)
lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "inspect", "--mode=dockercompat", "da24").Return(c)
c.EXPECT().Run()
},
Expand Down Expand Up @@ -1339,6 +1342,8 @@ func TestNerdctlCommand_run_inspectCommand(t *testing.T) {
ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false)
ncsd.EXPECT().LookupEnv("COMPOSE_FILE").Return("", false)
c := mocks.NewCommand(ctrl)
var stdoutBuf bytes.Buffer
c.EXPECT().SetStdout(&stdoutBuf)
lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "inspect", "--mode=dockercompat", "44de").Return(c)
c.EXPECT().Run()
},
Expand Down Expand Up @@ -1448,6 +1453,8 @@ func TestNerdctlCommand_run_inspectCommand(t *testing.T) {
ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false)
ncsd.EXPECT().LookupEnv("COMPOSE_FILE").Return("", false)
c := mocks.NewCommand(ctrl)
var stdoutBuf bytes.Buffer
c.EXPECT().SetStdout(&stdoutBuf)
lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "inspect", "--mode=dockercompat", "44de").Return(c)
c.EXPECT().Run()
},
Expand Down
9 changes: 7 additions & 2 deletions cmd/finch/nerdctl_native.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {
cmdHandler commandHandler
aMap map[string]argHandler
err error
inspectType string
)

// eat the debug arg, and set the log level to avoid nerdctl parsing this flag
Expand Down Expand Up @@ -48,7 +49,7 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {

// First check if the command has a command handler
if hasCmdHandler {
err := cmdHandler(nc.systemDeps, nc.fc, &cmdName, &args)
err := cmdHandler(nc.systemDeps, nc.fc, &cmdName, &args, &inspectType)
if err != nil {
return err
}
Expand Down Expand Up @@ -81,7 +82,11 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {
)
}

return nc.ncc.Create(cmdArgs...).Run()
cmd := nc.ncc.Create(cmdArgs...)
if inspectType == "container" && nc.fc.DockerCompat {
return inspectContainerOutputHandler(cmd)
}
return cmd.Run()
}

var osAliasMap = map[string]string{}
Expand Down
10 changes: 8 additions & 2 deletions cmd/finch/nerdctl_remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {
cmdHandler commandHandler
aMap map[string]argHandler
firstOptPos int
inspectType string
)

// accumulate distributed map entities
Expand Down Expand Up @@ -80,7 +81,7 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {

// First check if the command has command handler
if hasCmdHandler {
err := cmdHandler(nc.systemDeps, nc.fc, &cmdName, &args)
err := cmdHandler(nc.systemDeps, nc.fc, &cmdName, &args, &inspectType)
if err != nil {
return err
}
Expand Down Expand Up @@ -333,7 +334,12 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {
return nc.ncc.RunWithReplacingStdout([]command.Replacement{{Source: "nerdctl", Target: "finch"}}, runArgs...)
}

return nc.ncc.Create(runArgs...).Run()
cmd := nc.ncc.Create(runArgs...)
if inspectType == "container" && nc.fc.DockerCompat {
return inspectContainerOutputHandler(cmd)
}

return cmd.Run()
}

func (nc *nerdctlCommand) assertVMIsRunning(creator command.NerdctlCmdCreator, logger flog.Logger) error {
Expand Down
4 changes: 2 additions & 2 deletions cmd/finch/nerdctl_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func handleSecretOption(systemDeps NerdctlCommandSystemDeps, _ *config.Finch, ne
}

// cp command handler, takes command arguments and converts hostpath to wsl path in place. It ignores all other arguments.
func cpHandler(systemDeps NerdctlCommandSystemDeps, _ *config.Finch, _ *string, nerdctlCmdArgs *[]string) error {
func cpHandler(systemDeps NerdctlCommandSystemDeps, _ *config.Finch, _ *string, nerdctlCmdArgs *[]string, _ *string) error {
for i, arg := range *nerdctlCmdArgs {
// -L and --follow-symlink don't have to be processed
if strings.HasPrefix(arg, "-") || arg == "cp" {
Expand All @@ -285,7 +285,7 @@ func cpHandler(systemDeps NerdctlCommandSystemDeps, _ *config.Finch, _ *string,
}

// this is the handler for image build command. It translates build context to wsl path.
func imageBuildHandler(systemDeps NerdctlCommandSystemDeps, _ *config.Finch, _ *string, nerdctlCmdArgs *[]string) error {
func imageBuildHandler(systemDeps NerdctlCommandSystemDeps, _ *config.Finch, _ *string, nerdctlCmdArgs *[]string, _ *string) error {
var err error
argLen := len(*nerdctlCmdArgs) - 1
// -h/--help don't have buildcontext, just return
Expand Down

0 comments on commit 90ce0b0

Please sign in to comment.