diff --git a/cmd/hepto/service.go b/cmd/hepto/service.go index fbeeb6f5b3c755f54b16493cb82b6c9554aecff0..1c68875144deb075f9e57d5b17b9d90412de5526 100644 --- a/cmd/hepto/service.go +++ b/cmd/hepto/service.go @@ -1,7 +1,10 @@ package hepto import ( + "encoding/json" "fmt" + "io" + "io/ioutil" "net" "os" "os/exec" @@ -13,6 +16,7 @@ import ( "github.com/spf13/viper" "go.acides.org/hepto/services" "go.acides.org/selfcontain" + "golang.org/x/sys/unix" "k8s.io/component-base/version/verflag" "k8s.io/component-helpers/node/util/sysctl" ) @@ -83,13 +87,64 @@ var Start = &cobra.Command{ go func() { errChan <- selfcontain.RunWithArgs(&config.Container, newArgs) }() - go apiserverForward(errChan) + go func() { + // Wait so that the container is started and its state file exists + time.Sleep(5 * time.Second) + errChan <- apiserverForward() + }() return <-errChan }, } -func apiserverForward(chan error) { - // do nothing for now +// This is the apiserver forward hack, which proxifies the apiserver +// from the host to the container +// Everything is wrong here: so many magic numbers and constants, poor error +// management, this function has to go away at some point +func apiserverForward() error { + // Parsing container config and getting the namespace + statePath := path.Join(config.Container.Data, config.Container.Name, "state.json") + stateBytes, err := ioutil.ReadFile(statePath) + if err != nil { + return fmt.Errorf("could not read container state: %w", err) + } + var state map[string]interface{} + json.Unmarshal(stateBytes, &state) + netnsPath := state["namespace_paths"].(map[string]interface{})["NEWNET"].(string) + netns, err := unix.Open(netnsPath, unix.O_RDONLY|unix.O_CLOEXEC, 0) + if err != nil { + return fmt.Errorf("could not get netns: %w", err) + } + // Getting the current netns + curns, err := unix.Open(fmt.Sprintf("/proc/%d/ns/net", os.Getpid()), unix.O_RDONLY|unix.O_CLOEXEC, 0) + if err != nil { + return fmt.Errorf("could not get current netns: %w", err) + } + // Actually running the proxy + l, err := net.Listen("tcp", "[::1]:6443") + if err != nil { + return fmt.Errorf("could not listen on tcp: %w", err) + } + config.Cluster.Logger.Info("listening on port", "port", l.Addr().String()) + for { + tcp, err := l.Accept() + if err != nil { + config.Cluster.Logger.Error(err, "error on tcp socket") + } + go func() { + defer tcp.Close() + // Open a socket in the apiserver namespace + unix.Setns(netns, unix.CLONE_NEWNET) + proxy, err := net.Dial("tcp", "[::1]:6443") + unix.Setns(curns, unix.CLONE_NEWNET) + if err != nil { + config.Cluster.Logger.Error(err, "cannot dial to container socket") + return + } + defer proxy.Close() + go io.Copy(tcp, proxy) + io.Copy(proxy, tcp) + }() + } } var Run = &cobra.Command{