Files
kubevpn/pkg/util/volume.go

90 lines
2.7 KiB
Go

package util
import (
"context"
"fmt"
"math/rand"
"os"
"path/filepath"
"strconv"
"github.com/docker/docker/api/types/mount"
"github.com/moby/term"
pkgerr "github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/cli-runtime/pkg/genericiooptions"
"k8s.io/client-go/kubernetes"
"k8s.io/kubectl/pkg/cmd/util"
"github.com/wencaiwulue/kubevpn/v2/pkg/config"
"github.com/wencaiwulue/kubevpn/v2/pkg/cp"
)
// GetVolume key format: [container name]-[volume mount name]
func GetVolume(ctx context.Context, clientset *kubernetes.Clientset, f util.Factory, ns, podName string) (map[string][]mount.Mount, error) {
pod, err := clientset.CoreV1().Pods(ns).Get(ctx, podName, v12.GetOptions{})
if err != nil {
return nil, err
}
result := map[string][]mount.Mount{}
for _, container := range pod.Spec.Containers {
// if container name is vpn or envoy-proxy, not need to download volume
if container.Name == config.ContainerSidecarVPN || container.Name == config.ContainerSidecarEnvoyProxy {
continue
}
var m []mount.Mount
for _, volumeMount := range container.VolumeMounts {
if volumeMount.MountPath == "/tmp" {
continue
}
localPath := filepath.Join(os.TempDir(), strconv.Itoa(rand.Int()))
err = os.MkdirAll(localPath, 0755)
if err != nil {
return nil, err
}
if volumeMount.SubPath != "" {
localPath = filepath.Join(localPath, volumeMount.SubPath)
}
// pod-namespace/pod-name:path
remotePath := fmt.Sprintf("%s/%s:%s", ns, podName, volumeMount.MountPath)
stdIn, stdOut, stdErr := term.StdStreams()
copyOptions := cp.NewCopyOptions(genericiooptions.IOStreams{In: stdIn, Out: stdOut, ErrOut: stdErr})
copyOptions.Container = container.Name
copyOptions.MaxTries = 10
err = copyOptions.Complete(f, &cobra.Command{}, []string{remotePath, localPath})
if err != nil {
return nil, err
}
err = copyOptions.Run()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Failed to download volume %s path %s to %s, err: %v, ignore...\n", volumeMount.Name, remotePath, localPath, err)
continue
}
m = append(m, mount.Mount{
Type: mount.TypeBind,
Source: localPath,
Target: volumeMount.MountPath,
})
log.Infof("%s:%s", localPath, volumeMount.MountPath)
}
result[Join(ns, container.Name)] = m
}
return result, nil
}
func RemoveDir(volume map[string][]mount.Mount) error {
var errs []error
for _, mounts := range volume {
for _, m := range mounts {
err := os.RemoveAll(m.Source)
if err != nil && !pkgerr.Is(err, os.ErrNotExist) {
errs = append(errs, fmt.Errorf("failed to delete dir %s: %v", m.Source, err))
}
}
}
return errors.NewAggregate(errs)
}