Skip to content

Commit

Permalink
Fix occasional error when extracting container file system in contain…
Browse files Browse the repository at this point in the history
…erd #36 (#37)
  • Loading branch information
ramanan-ravi authored Jun 13, 2023
1 parent 60bbb83 commit 84388ea
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 1,005 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
.env
cmd/vessel/vessel
dist/
dev/
40 changes: 20 additions & 20 deletions autodetect.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (

"github.com/containerd/containerd"
"github.com/containerd/containerd/namespaces"
"github.com/deepfence/vessel/constants"
self_containerd "github.com/deepfence/vessel/containerd"
"github.com/deepfence/vessel/crio"
"github.com/deepfence/vessel/docker"
"github.com/deepfence/vessel/utils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/pkg/errors"
Expand All @@ -32,19 +32,19 @@ func init() {

// GetAddressAndDialer returns the address parsed from the given endpoint and a context dialer.
func GetAddressAndDialer(endpoint string) (string, func(ctx context.Context, addr string) (net.Conn, error), error) {
protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, constants.UnixProtocol)
protocol, addr, err := parseEndpointWithFallbackProtocol(endpoint, utils.UnixProtocol)
if err != nil {
return "", nil, err
}
if protocol != constants.UnixProtocol {
if protocol != utils.UnixProtocol {
return "", nil, fmt.Errorf("only support unix socket endpoint")
}

return addr, dial, nil
}

func dial(ctx context.Context, addr string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, constants.UnixProtocol, addr)
return (&net.Dialer{}).DialContext(ctx, utils.UnixProtocol, addr)
}

func parseEndpointWithFallbackProtocol(endpoint string, fallbackProtocol string) (protocol string, addr string, err error) {
Expand Down Expand Up @@ -84,7 +84,7 @@ func checkDockerRuntime(endPoint string) (bool, error) {
if err != nil {
return false, err
}
_, err = net.DialTimeout(constants.UnixProtocol, addr, constants.Timeout)
_, err = net.DialTimeout(utils.UnixProtocol, addr, utils.Timeout)
if err != nil {
return false, errors.New("could not connect to endpoint '" + endPoint + "'")
}
Expand All @@ -93,7 +93,7 @@ func checkDockerRuntime(endPoint string) (bool, error) {
return false, err
}
if !running {
logrus.Debugf(fmt.Sprintf("no running containers found with endpoint %s", endPoint))
logrus.Debugf("no running containers found with endpoint %s", endPoint)
return false, nil
}
return true, nil
Expand All @@ -104,7 +104,7 @@ func checkContainerdRuntime(endPoint string) (bool, error) {
if err != nil {
return false, err
}
ctx, cancel := context.WithTimeout(context.Background(), constants.Timeout)
ctx, cancel := context.WithTimeout(context.Background(), utils.Timeout)
defer cancel()
_, err = grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock(), grpc.WithContextDialer(dialer))
if err != nil {
Expand All @@ -115,7 +115,7 @@ func checkContainerdRuntime(endPoint string) (bool, error) {
return false, err
}
if !running {
logrus.Debugf(fmt.Sprintf("no running containers found with endpoint %s", endPoint))
logrus.Debugf("no running containers found with endpoint %s", endPoint)
return false, nil
}
return true, nil
Expand All @@ -126,7 +126,7 @@ func checkCrioRuntime(endPoint string) (bool, error) {
if err != nil {
return false, err
}
_, err = net.DialTimeout(constants.UnixProtocol, addr, constants.Timeout)
_, err = net.DialTimeout(utils.UnixProtocol, addr, utils.Timeout)
if err != nil {
return false, errors.New("could not connect to endpoint '" + endPoint + "'")
}
Expand All @@ -135,7 +135,7 @@ func checkCrioRuntime(endPoint string) (bool, error) {
return false, err
}
if !running {
logrus.Debugf(fmt.Sprintf("no running containers found with endpoint %s", endPoint))
logrus.Debugf("no running containers found with endpoint %s", endPoint)
return false, nil
}
return true, nil
Expand All @@ -154,22 +154,22 @@ func getContainerRuntime() (string, string, error) {
var connectedRuntimes []containerRuntime
detectedRuntimeChannel := make(chan containerRuntime, 1)

for runtime, endPoints := range constants.SupportedRuntimes {
for runtime, endPoints := range utils.SupportedRuntimes {
for _, endPoint := range endPoints {
wg.Add(1)
go func(runtime, endPoint string) {
logrus.Debugf("trying to connect to endpoint '%s' with timeout '%s'", endPoint, constants.Timeout)
logrus.Debugf("trying to connect to endpoint '%s' with timeout '%s'", endPoint, utils.Timeout)
var connected bool
var err error
switch runtime {
case constants.DOCKER:
case utils.DOCKER:
connected, err = checkDockerRuntime(endPoint)
case constants.CONTAINERD:
case utils.CONTAINERD:
connected, err = checkContainerdRuntime(endPoint)
case constants.CRIO:
case utils.CRIO:
connected, err = checkCrioRuntime(endPoint)
default:
err = errors.New(fmt.Sprintf("unknown container runtime %s", runtime))
err = fmt.Errorf("unknown container runtime %s", runtime)
}
if err != nil {
logrus.Debugf(err.Error())
Expand Down Expand Up @@ -220,7 +220,7 @@ func AutoDetectRuntime() (string, string, error) {
}

func isDockerRunning(host string) (bool, error) {
dockerCli, err := client.NewClientWithOpts(client.WithAPIVersionNegotiation(), client.WithHost(host), client.WithTimeout(constants.Timeout))
dockerCli, err := client.NewClientWithOpts(client.WithAPIVersionNegotiation(), client.WithHost(host), client.WithTimeout(utils.Timeout))
if err != nil {
return false, errors.Wrapf(err, " :error creating docker client")
}
Expand Down Expand Up @@ -281,11 +281,11 @@ func NewRuntime() (Runtime, error) {
return nil, err
}

if runtime == constants.DOCKER {
if runtime == utils.DOCKER {
return docker.New(), nil
} else if runtime == constants.CONTAINERD {
} else if runtime == utils.CONTAINERD {
return self_containerd.New(endpoint), nil
} else if runtime == constants.CRIO {
} else if runtime == utils.CRIO {
return crio.New(endpoint), nil
}

Expand Down
69 changes: 39 additions & 30 deletions containerd/containerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"strings"
"time"

"github.com/deepfence/vessel/constants"
"github.com/deepfence/vessel/utils"
"github.com/sirupsen/logrus"

"github.com/containerd/containerd"
Expand Down Expand Up @@ -149,7 +149,7 @@ func migrateOCIToDockerV1(path, imageID, tarFilePath string) error {

// fileuploader specific
func MigrateOCITarToDockerV1Tar(dir, tarName string) error {
fmt.Println("migrating image ...")
logrus.Info("migrating image ...")
var stderr bytes.Buffer
tarPath := path.Join(dir, tarName)
_, err := exec.Command("tar", "xf", tarPath, "--warning=none", "-C"+dir).Output()
Expand Down Expand Up @@ -182,9 +182,9 @@ func MigrateOCITarToDockerV1Tar(dir, tarName string) error {
}

// ExtractFileSystem Extract the file system from tar of an image by creating a temporary dormant container instance
func (c Containerd) ExtractFileSystem(imageTarPath string, outputTarPath string, imageName string, socketPath string) error {
func (c Containerd) ExtractFileSystem(imageTarPath string, outputTarPath string, imageName string) error {
// create a new client connected to the default socket path for containerd
client, err := containerdApi.New(strings.Replace(socketPath, "unix://", "", 1))
client, err := containerdApi.New(strings.Replace(c.socketPath, "unix://", "", 1))
if err != nil {
return err
}
Expand All @@ -193,30 +193,30 @@ func (c Containerd) ExtractFileSystem(imageTarPath string, outputTarPath string,
ctx := namespaces.WithNamespace(context.Background(), "temp")
reader, err := os.Open(imageTarPath)
if err != nil {
fmt.Println("Error while opening image")
logrus.Error("Error while opening image")
return err
}
imgs, err := client.Import(ctx, reader,
containerdApi.WithSkipDigestRef(func(name string) bool { return name != "" }),
containerdApi.WithDigestRef(archive.DigestTranslator(imageName)))
if err != nil {
fmt.Println("Error while Importing image")
logrus.Error("Error while Importing image")
return err
}
if len(imgs) == 0 {
fmt.Printf("No images imported, imageTarPath: %s, outputTarPath: %s, imageName: %s \n", imageTarPath, outputTarPath, imageName)
logrus.Errorf("No images imported, imageTarPath: %s, outputTarPath: %s, imageName: %s \n", imageTarPath, outputTarPath, imageName)
return errors.New("image not imported from: " + imageTarPath)
}
image, err := client.GetImage(ctx, imgs[0].Name)
if err != nil {
fmt.Println("Error while getting image from client")
logrus.Error("Error while getting image from client")
return err
}
rand.Seed(time.Now().UnixNano())
containerName := "temp" + fmt.Sprint(rand.Intn(9999))
err = image.Unpack(ctx, "")
if err != nil {
fmt.Println("Error while unpacking image")
logrus.Error("Error while unpacking image")
return err
}
container, err := client.NewContainer(
Expand All @@ -227,7 +227,7 @@ func (c Containerd) ExtractFileSystem(imageTarPath string, outputTarPath string,
containerdApi.WithNewSpec(oci.WithImageConfig(image)),
)
if err != nil {
fmt.Println("Error while creating container")
logrus.Error("Error while creating container")
return err
}
info, _ := container.Info(ctx)
Expand All @@ -236,42 +236,46 @@ func (c Containerd) ExtractFileSystem(imageTarPath string, outputTarPath string,
target := strings.Replace(outputTarPath, ".tar", "", 1) + containerName
_, err = exec.Command("mkdir", target).Output()
if err != nil && !strings.Contains(err.Error(), "exit status 1") {
fmt.Println("Error while creating temp target dir", target, err.Error())
logrus.Errorf("Error while creating temp target dir %s: %s", target, err.Error())
return err
}
defer func() {
exec.Command("umount", target).Output()
exec.Command("rm", "-rf", target).Output()
}()
_, err = exec.Command("bash", "-c", fmt.Sprintf("mount -t %s %s %s -o %s\n", mounts[0].Type, mounts[0].Source, target, strings.Join(mounts[0].Options, ","))).Output()
if err != nil {
fmt.Println("Error while mounting image on temp target dir")
logrus.Error("Error while mounting image on temp target dir")
return err
}
_, err = exec.Command("tar", "-czvf", outputTarPath, "-C", target, ".").Output()
if err != nil {
fmt.Println("Error while packing tar")
return err
if !utils.CheckTarFileValid(outputTarPath) {
if err != nil {
logrus.Error("Error while packing tar")
return err
}
}
exec.Command("umount", target).Output()
exec.Command("rm", "-rf", target).Output()
container.Delete(ctx, containerdApi.WithSnapshotCleanup)
client.ImageService().Delete(ctx, imgs[0].Name, images.SynchronousDelete())
return nil
}

// ExtractFileSystemContainer Extract the file system of an existing container to tar
func (c Containerd) ExtractFileSystemContainer(containerId string, namespace string, outputTarPath string, socketPath string) error {
func (c Containerd) ExtractFileSystemContainer(containerId string, namespace string, outputTarPath string) error {
// create a new client connected to the default socket path for containerd
client, err := containerdApi.New(strings.Replace(socketPath, "unix://", "", 1))
client, err := containerdApi.New(strings.Replace(c.socketPath, "unix://", "", 1))
if err != nil {
return err
}
defer client.Close()
// create a new context with namespace
if len(namespace) == 0 {
namespace = constants.CONTAINERD_K8S_NS
namespace = utils.CONTAINERD_K8S_NS
}
ctx := namespaces.WithNamespace(context.Background(), namespace)
container, err := client.LoadContainer(ctx, containerId)
if err != nil {
fmt.Fprintf(os.Stderr, "Error while getting container")
logrus.Error("Error while getting container")
return err
}
info, _ := container.Info(ctx)
Expand All @@ -280,17 +284,21 @@ func (c Containerd) ExtractFileSystemContainer(containerId string, namespace str
target := strings.Replace(outputTarPath, ".tar", "", 1) + containerId
_, err = exec.Command("mkdir", target).Output()
if err != nil && !strings.Contains(err.Error(), "exit status 1") {
fmt.Fprintf(os.Stderr, "Error while creating temp target dir %s %s \n", target, err.Error())
logrus.Errorf("Error while creating temp target dir %s %s \n", target, err.Error())
return err
}
defer func() {
exec.Command("umount", target).Output()
exec.Command("rm", "-rf", target).Output()
}()
var mountStatement = fmt.Sprintf("mount -t %s %s %s -o %s\n", mounts[0].Type, mounts[0].Source, target, strings.Join(mounts[0].Options, ","))
cmd := exec.Command("bash", "-c", mountStatement)
logrus.Infof("mount command: %s", cmd.String())
_, err = cmd.Output()
if err != nil {
mountedHostPath := "/fenced/mnt/host"
fmt.Fprintf(os.Stderr, "error while mounting image on temp target dir %s %s %s \n", mountStatement, " err: ", err.Error())
fmt.Fprintf(os.Stderr, "Reattempting mount from %s \n", mountedHostPath)
logrus.Errorf("error while mounting image on temp target dir %s %s %s \n", mountStatement, " err: ", err.Error())
logrus.Errorf("Reattempting mount from %s \n", mountedHostPath)
var containerdTmpDirs = []string{"/tmp", "/var/lib"}
var workDir, upperDir, lowerDir string
for index, option := range mounts[0].Options {
Expand All @@ -313,16 +321,17 @@ func (c Containerd) ExtractFileSystemContainer(containerId string, namespace str
logrus.Infof("mount command: %s", cmd.String())
_, err := cmd.Output()
if err != nil {
fmt.Fprintf(os.Stderr, "error while mounting image on temp target dir 2nd attempt %s %s %s \n", mountStatement, " err: ", err.Error())
logrus.Errorf("error while mounting image on temp target dir 2nd attempt %s %s %s \n", mountStatement, " err: ", err.Error())
return err
}
fmt.Fprintf(os.Stderr, "mount success \n")
logrus.Error("mount success \n")
}
_, err = exec.Command("tar", "-czvf", outputTarPath, "-C", target, ".").Output()
if err != nil {
fmt.Fprintf(os.Stderr, "Error while packing tar %s %s %s \n", outputTarPath, target, err.Error())
return err
if !utils.CheckTarFileValid(outputTarPath) {
if err != nil {
logrus.Errorf("Error while packing tar %s %s %s \n", outputTarPath, target, err.Error())
return err
}
}
exec.Command("umount", target).Output()
return nil
}
20 changes: 11 additions & 9 deletions crio/crio.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os/exec"
"strings"

"github.com/deepfence/vessel/utils"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -43,15 +44,13 @@ func (c CRIO) Save(imageName, outputParam string) ([]byte, error) {
return cmd.Output()
}

func (c CRIO) ExtractFileSystem(imageTarPath string, outputTarPath string,
imageName string, socketPath string) error {
func (c CRIO) ExtractFileSystem(imageTarPath string, outputTarPath string, imageName string) error {
return errors.New("function not implemented for cri-o")
}

func (c CRIO) ExtractFileSystemContainer(containerId string, namespace string,
outputTarPath string, socketPath string) error {
func (c CRIO) ExtractFileSystemContainer(containerId string, namespace string, outputTarPath string) error {

// inspect doesnot accept runtime endpoint option
// inspect does not accept runtime endpoint option
_, _ = exec.Command(
"crictl",
"config",
Expand Down Expand Up @@ -79,10 +78,13 @@ func (c CRIO) ExtractFileSystemContainer(containerId string, namespace string,

cmd = exec.Command("tar", "-czvf", outputTarPath, "-C", cleanrootpath, ".")
logrus.Infof("tar command: %s", cmd.String())
if _, err := cmd.Output(); err != nil {
logrus.Errorf("error while packing tar containerId: %s file: %s path: %s error: %s",
containerId, outputTarPath, rootpath, err)
return err
_, err = cmd.Output()
if !utils.CheckTarFileValid(outputTarPath) {
if err != nil {
logrus.Errorf("error while packing tar containerId: %s file: %s path: %s error: %s",
containerId, outputTarPath, rootpath, err)
return err
}
}

return nil
Expand Down
Loading

0 comments on commit 84388ea

Please sign in to comment.