finish dns service on unix

This commit is contained in:
wencaiwulue
2021-07-25 12:36:36 +08:00
parent 9a690b6409
commit dcc3c6d4e9
4 changed files with 144 additions and 116 deletions

View File

@@ -9,21 +9,20 @@ import (
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"kubevpn/remote"
"kubevpn/util"
"os" "os"
"path/filepath" "path/filepath"
) )
func Dns(clientset *kubernetes.Clientset) error { func Dns(ip string) error {
var dnsIP string
var err error var err error
if dnsIP, err = GetDNSIp(clientset); err != nil {
return err
}
if err = os.MkdirAll(filepath.Join("/", "etc", "resolver"), fs.ModePerm); err != nil { if err = os.MkdirAll(filepath.Join("/", "etc", "resolver"), fs.ModePerm); err != nil {
log.Error(err) log.Error(err)
} }
filename := filepath.Join("/", "etc", "resolver", "local") filename := filepath.Join("/", "etc", "resolver", "local")
fileContent := "nameserver " + dnsIP fileContent := "nameserver " + ip
return ioutil.WriteFile(filename, []byte(fileContent), fs.ModePerm) return ioutil.WriteFile(filename, []byte(fileContent), fs.ModePerm)
} }
@@ -39,3 +38,14 @@ func GetDNSIp(clientset *kubernetes.Clientset) (string, error) {
} }
return serviceList.Items[0].Spec.ClusterIP, nil return serviceList.Items[0].Spec.ClusterIP, nil
} }
func GetDNSServiceIpFromPod(clientset *kubernetes.Clientset, restclient *rest.RESTClient, config *rest.Config, podName, namespace string) string {
//if ip, err := GetDNSIp(clientset); err == nil && len(ip) != 0 {
// return ip
//}
if ip, err := util.Shell(clientset, restclient, config, remote.TrafficManager, namespace, "cat /etc/resolv.conf | grep nameserver | awk '{print$2}'"); err == nil && len(ip) != 0 {
return ip
}
log.Fatal("this should not happened")
return ""
}

View File

@@ -6,15 +6,16 @@ import (
"fmt" "fmt"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir" cmdutil "k8s.io/kubectl/pkg/cmd/util"
"kubevpn/dns" "kubevpn/dns"
"kubevpn/exe" "kubevpn/exe"
"kubevpn/remote" "kubevpn/remote"
"kubevpn/util"
"net" "net"
"path/filepath"
"runtime" "runtime"
"strings" "strings"
) )
@@ -23,27 +24,29 @@ var (
baseCfg = &baseConfig{} baseCfg = &baseConfig{}
namespace string namespace string
clientset *kubernetes.Clientset clientset *kubernetes.Clientset
config *restclient.Config restclient *rest.RESTClient
config *rest.Config
name string name string
) )
func init() { func init() {
var err error var err error
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( configFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
&clientcmd.ClientConfigLoadingRules{ configFlags.KubeConfig = &clientcmd.RecommendedHomeFile
ExplicitPath: filepath.Join(homedir.HomeDir(), clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName), f := cmdutil.NewFactory(cmdutil.NewMatchVersionFlags(configFlags))
},
nil, if config, err = f.ToRESTConfig(); err != nil {
)
config, err = clientConfig.ClientConfig()
if err != nil {
log.Fatal(err) log.Fatal(err)
} }
clientset, err = kubernetes.NewForConfig(config) if restclient, err = rest.RESTClientFor(config); err != nil {
if err != nil { log.Fatal(err)
}
if clientset, err = kubernetes.NewForConfig(config); err != nil {
log.Fatal(err)
}
if namespace, _, err = f.ToRawKubeConfigLoader().Namespace(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
namespace, _, _ = clientConfig.Namespace()
k8sCIDR, err := getCIDR(clientset, namespace) k8sCIDR, err := getCIDR(clientset, namespace)
if err != nil { if err != nil {
@@ -80,7 +83,7 @@ func main() {
readyChan := make(chan struct{}) readyChan := make(chan struct{})
stop := make(chan struct{}) stop := make(chan struct{})
go func() { go func() {
err := PortForwardPod(config, err := util.PortForwardPod(config,
clientset, clientset,
name, name,
namespace, namespace,
@@ -94,8 +97,8 @@ func main() {
}() }()
<-readyChan <-readyChan
log.Info("port forward ready") log.Info("port forward ready")
dnsServiceIp := dns.GetDNSServiceIpFromPod(clientset, restclient, config, remote.TrafficManager, namespace)
if err := dns.Dns(clientset); err != nil { if err := dns.Dns(dnsServiceIp); err != nil {
log.Fatal(err) log.Fatal(err)
} else { } else {
log.Info("dns service ok") log.Info("dns service ok")

View File

@@ -1,14 +1,15 @@
package main package util
import ( import (
"bytes"
"context" "context"
"fmt" "fmt"
"github.com/moby/term" dockerterm "github.com/moby/term"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"io"
v12 "k8s.io/api/autoscaling/v1" v12 "k8s.io/api/autoscaling/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/genericclioptions"
@@ -22,11 +23,11 @@ import (
clientgowatch "k8s.io/client-go/tools/watch" clientgowatch "k8s.io/client-go/tools/watch"
"k8s.io/client-go/transport/spdy" "k8s.io/client-go/transport/spdy"
"k8s.io/client-go/util/retry" "k8s.io/client-go/util/retry"
"k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/cmd/exec"
term2 "k8s.io/kubectl/pkg/util/term"
"net" "net"
"net/http" "net/http"
"os" "os"
"strings"
"time" "time"
) )
@@ -152,95 +153,58 @@ func ScaleDeploymentReplicasTo(options *kubernetes.Clientset, name, namespace st
} }
} }
type shellOptions interface { func Shell(clientset *kubernetes.Clientset, restclient *rest.RESTClient, config *rest.Config, podName, namespace, cmd string) (string, error) {
GetNamespace() string pod, err := clientset.CoreV1().Pods(namespace).Get(context.Background(), podName, metav1.GetOptions{})
GetDeployment() string
GetLocalDir() string if err != nil {
GetRemoteDir() string return "", err
GetKubeconfig() string }
if pod.Status.Phase == v1.PodSucceeded || pod.Status.Phase == v1.PodFailed {
err = fmt.Errorf("cannot exec into a container in a completed pod; current phase is %s", pod.Status.Phase)
return "", err
}
containerName := pod.Spec.Containers[0].Name
stdin, stdout, stderr := dockerterm.StdStreams()
stdoutBuf := bytes.NewBuffer(nil)
stdout = io.MultiWriter(stdout, stdoutBuf)
StreamOptions := exec.StreamOptions{
Namespace: namespace,
PodName: podName,
ContainerName: containerName,
IOStreams: genericclioptions.IOStreams{In: stdin, Out: stdout, ErrOut: stderr},
}
Executor := &exec.DefaultRemoteExecutor{}
// ensure we can recover the terminal while attached
tt := StreamOptions.SetupTTY()
var sizeQueue remotecommand.TerminalSizeQueue
if tt.Raw {
// this call spawns a goroutine to monitor/update the terminal size
sizeQueue = tt.MonitorSize(tt.GetSize())
// unset p.Err if it was previously set because both stdout and stderr go over p.Out when tty is
// true
StreamOptions.ErrOut = nil
} }
func Shell(client *kubernetes.Clientset, options shellOptions) error { fn := func() error {
deployment, err2 := client.AppsV1().Deployments(options.GetNamespace()). req := restclient.Post().
Get(context.TODO(), options.GetDeployment(), metav1.GetOptions{})
if err2 != nil {
log.Error(err2)
}
labelMap, _ := metav1.LabelSelectorAsMap(deployment.Spec.Selector)
pods, err := client.CoreV1().Pods(options.GetNamespace()).
List(context.TODO(), metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labelMap).String()})
if err != nil {
log.Errorf("get kubedev pod error: %v", err)
}
if len(pods.Items) <= 0 {
log.Warnf("this should not happened, pods items length: %d", len(pods.Items))
}
index := -1
for i, pod := range pods.Items {
if pod.Status.Phase == v1.PodRunning {
index = i
break
}
}
if index < 0 {
return fmt.Errorf("cannot exec into a container in a completed pod; current phase is %s", pods.Items[0].Status.Phase)
}
stdin, stdout, stderr := term.StdStreams()
tty := term2.TTY{
Out: stdout,
In: stdin,
Raw: true,
}
if !tty.IsTerminalIn() {
log.Error("Unable to use a TTY - input is not a terminal or the right kind of file")
}
var terminalSizeQueue remotecommand.TerminalSizeQueue
if tty.Raw {
terminalSizeQueue = tty.MonitorSize(tty.GetSize())
}
f := func() error {
configFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
kubeconfig := options.GetKubeconfig()
configFlags.KubeConfig = &kubeconfig
namespace := options.GetNamespace()
configFlags.Namespace = &namespace
f := util.NewFactory(util.NewMatchVersionFlags(configFlags))
config, _ := f.ToRESTConfig()
restClient, err := rest.RESTClientFor(config)
if err != nil {
return err
}
req := restClient.Post().
Resource("pods"). Resource("pods").
Name(pods.Items[index].Name). Name(pod.Name).
Namespace(options.GetNamespace()). Namespace(pod.Namespace).
SubResource("exec"). SubResource("exec")
VersionedParams( req.VersionedParams(&v1.PodExecOptions{
&v1.PodExecOptions{ Container: containerName,
Container: pods.Items[index].Spec.Containers[0].Name, Command: []string{"sh", "-c", cmd},
Command: []string{"sh", "-c", "(bash||sh)"}, Stdin: StreamOptions.Stdin,
Stdin: true, Stdout: StreamOptions.Out != nil,
Stdout: true, Stderr: StreamOptions.ErrOut != nil,
Stderr: true, TTY: tt.Raw,
TTY: true, }, scheme.ParameterCodec)
}, return Executor.Execute("POST", req.URL(), config, StreamOptions.In, StreamOptions.Out, StreamOptions.ErrOut, tt.Raw, sizeQueue)
scheme.ParameterCodec,
)
executor, err := remotecommand.NewSPDYExecutor(config, "POST", req.URL())
if err != nil {
return err
}
return executor.Stream(remotecommand.StreamOptions{
Stdin: tty.In,
Stdout: tty.Out,
Stderr: stderr,
Tty: true,
TerminalSizeQueue: terminalSizeQueue,
})
} }
if err = tty.Safe(f); err != nil { err = tt.Safe(fn)
return err return strings.TrimRight(stdoutBuf.String(), "\n"), err
}
return nil
} }

51
util/util_test.go Normal file
View File

@@ -0,0 +1,51 @@
package util
import (
"context"
"fmt"
log "github.com/sirupsen/logrus"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubectl/pkg/cmd/util"
"kubevpn/remote"
"testing"
)
var (
namespace string
clientset *kubernetes.Clientset
restclient *rest.RESTClient
config *rest.Config
)
func TestShell(t *testing.T) {
var err error
configFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag()
configFlags.KubeConfig = &clientcmd.RecommendedHomeFile
f := util.NewFactory(util.NewMatchVersionFlags(configFlags))
if config, err = f.ToRESTConfig(); err != nil {
log.Fatal(err)
}
if restclient, err = rest.RESTClientFor(config); err != nil {
log.Fatal(err)
}
if clientset, err = kubernetes.NewForConfig(config); err != nil {
log.Fatal(err)
}
if namespace, _, err = f.ToRawKubeConfigLoader().Namespace(); err != nil {
log.Fatal(err)
}
out, err := Shell(clientset, restclient, config, remote.TrafficManager, namespace, "cat /etc/resolv.conf | grep nameserver | awk '{print$2}'")
serviceList, err := clientset.CoreV1().Services(v1.NamespaceSystem).List(context.Background(), v1.ListOptions{
FieldSelector: fields.OneTermEqualSelector("metadata.name", "kube-dns").String(),
})
fmt.Println(out == serviceList.Items[0].Spec.ClusterIP)
}