diff --git a/Makefile b/Makefile index 66189845..72d5a8ef 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ container-local: kubevpn-linux-amd64 .PHONY: container-test container-test: kubevpn-linux-amd64 - docker buildx build --platform linux/amd64 -t docker.io/naison/kubevpn:test-daemon -f $(BUILD_DIR)/test.Dockerfile --push . + docker buildx build --platform linux/amd64,linux/arm64 -t docker.io/naison/kubevpn:test -f $(BUILD_DIR)/test.Dockerfile --push . .PHONY: version version: diff --git a/cmd/kubevpn/cmds/connect.go b/cmd/kubevpn/cmds/connect.go index 111ac54a..64a547e2 100644 --- a/cmd/kubevpn/cmds/connect.go +++ b/cmd/kubevpn/cmds/connect.go @@ -9,6 +9,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" @@ -77,6 +79,8 @@ func CmdConnect(f cmdutil.Factory) *cobra.Command { recv, err := resp.Recv() if err == io.EOF { break + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { + return nil } else if err != nil { return err } @@ -99,6 +103,8 @@ func CmdConnect(f cmdutil.Factory) *cobra.Command { resp, err = stream.Recv() if err == io.EOF { return nil + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { + return nil } else if err != nil { return err } diff --git a/cmd/kubevpn/cmds/disconnect.go b/cmd/kubevpn/cmds/disconnect.go index bf6e1a80..8c69083c 100644 --- a/cmd/kubevpn/cmds/disconnect.go +++ b/cmd/kubevpn/cmds/disconnect.go @@ -7,6 +7,8 @@ import ( "time" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" @@ -44,6 +46,8 @@ func CmdDisconnect(f cmdutil.Factory) *cobra.Command { return nil } else if err == nil { fmt.Fprint(os.Stdout, resp.Message) + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { + return nil } else { return err } diff --git a/cmd/kubevpn/cmds/duplicate.go b/cmd/kubevpn/cmds/duplicate.go index f70428d0..23e83a2c 100644 --- a/cmd/kubevpn/cmds/duplicate.go +++ b/cmd/kubevpn/cmds/duplicate.go @@ -3,13 +3,14 @@ package cmds import ( "context" "fmt" + "os" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" cmdutil "k8s.io/kubectl/pkg/cmd/util" utilcomp "k8s.io/kubectl/pkg/util/completion" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" - "os" "github.com/wencaiwulue/kubevpn/pkg/config" "github.com/wencaiwulue/kubevpn/pkg/handler" diff --git a/cmd/kubevpn/cmds/leave.go b/cmd/kubevpn/cmds/leave.go index d0156cdc..7519a9e9 100644 --- a/cmd/kubevpn/cmds/leave.go +++ b/cmd/kubevpn/cmds/leave.go @@ -5,6 +5,8 @@ import ( "io" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" cmdutil "k8s.io/kubectl/pkg/cmd/util" "github.com/wencaiwulue/kubevpn/pkg/daemon" @@ -30,6 +32,8 @@ func CmdLeave(f cmdutil.Factory) *cobra.Command { recv, err := leave.Recv() if err == io.EOF { return nil + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { + return nil } else if err != nil { return err } diff --git a/cmd/kubevpn/cmds/logs.go b/cmd/kubevpn/cmds/logs.go index 2be1183b..26a4acfd 100644 --- a/cmd/kubevpn/cmds/logs.go +++ b/cmd/kubevpn/cmds/logs.go @@ -1,13 +1,13 @@ package cmds import ( - "context" - "errors" "fmt" "io" "os" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" @@ -39,7 +39,7 @@ func CmdLogs(f cmdutil.Factory) *cobra.Command { break } else if err == nil { fmt.Fprintln(os.Stdout, resp.Message) - } else if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) { + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { return nil } else { return err diff --git a/cmd/kubevpn/cmds/proxy.go b/cmd/kubevpn/cmds/proxy.go index e88d6aba..2e78b740 100644 --- a/cmd/kubevpn/cmds/proxy.go +++ b/cmd/kubevpn/cmds/proxy.go @@ -7,6 +7,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" cmdutil "k8s.io/kubectl/pkg/cmd/util" utilcomp "k8s.io/kubectl/pkg/util/completion" "k8s.io/kubectl/pkg/util/i18n" @@ -111,6 +113,8 @@ func CmdProxy(f cmdutil.Factory) *cobra.Command { break } else if err == nil { fmt.Fprint(os.Stdout, resp.Message) + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { + return nil } else { return err } diff --git a/cmd/kubevpn/cmds/quit.go b/cmd/kubevpn/cmds/quit.go index 72a069e2..6d5f2c19 100644 --- a/cmd/kubevpn/cmds/quit.go +++ b/cmd/kubevpn/cmds/quit.go @@ -7,6 +7,8 @@ import ( "os" "github.com/spf13/cobra" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" @@ -49,6 +51,8 @@ func quit(ctx context.Context, isSudo bool) error { break } else if err == nil { fmt.Fprint(os.Stdout, resp.Message) + } else if code := status.Code(err); code == codes.DeadlineExceeded || code == codes.Canceled { + return nil } else { return err } diff --git a/cmd/kubevpn/cmds/root.go b/cmd/kubevpn/cmds/root.go index 8df4ded8..8e23b2f7 100644 --- a/cmd/kubevpn/cmds/root.go +++ b/cmd/kubevpn/cmds/root.go @@ -62,6 +62,7 @@ func NewKubeVPNCommand() *cobra.Command { CmdUpgrade(factory), CmdReset(factory), CmdVersion(factory), + CmdStatus(factory), // Hidden, Server Commands (DO NOT USE IT !!!) CmdControlPlane(factory), CmdServe(factory), diff --git a/cmd/kubevpn/cmds/serve.go b/cmd/kubevpn/cmds/serve.go index 2611da20..54170292 100644 --- a/cmd/kubevpn/cmds/serve.go +++ b/cmd/kubevpn/cmds/serve.go @@ -5,13 +5,15 @@ import ( "runtime" "time" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "go.uber.org/automaxprocs/maxprocs" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "github.com/wencaiwulue/kubevpn/pkg/config" "github.com/wencaiwulue/kubevpn/pkg/core" "github.com/wencaiwulue/kubevpn/pkg/handler" "github.com/wencaiwulue/kubevpn/pkg/util" - "go.uber.org/automaxprocs/maxprocs" - cmdutil "k8s.io/kubectl/pkg/cmd/util" ) func CmdServe(_ cmdutil.Factory) *cobra.Command { @@ -29,11 +31,16 @@ func CmdServe(_ cmdutil.Factory) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { rand.Seed(time.Now().UnixNano()) _, _ = maxprocs.Set(maxprocs.Logger(nil)) - err := handler.Complete(route) + err := handler.RentIPIfNeeded(route) if err != nil { return err } - defer handler.Final() + defer func() { + err := handler.ReleaseIPIfNeeded() + if err != nil { + log.Error(err) + } + }() servers, err := handler.Parse(*route) if err != nil { return err diff --git a/cmd/kubevpn/cmds/status.go b/cmd/kubevpn/cmds/status.go index ce2fc16d..38921b3e 100644 --- a/cmd/kubevpn/cmds/status.go +++ b/cmd/kubevpn/cmds/status.go @@ -1 +1,37 @@ package cmds + +import ( + "fmt" + + "github.com/spf13/cobra" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "k8s.io/kubectl/pkg/util/i18n" + "k8s.io/kubectl/pkg/util/templates" + + "github.com/wencaiwulue/kubevpn/pkg/daemon" + "github.com/wencaiwulue/kubevpn/pkg/daemon/rpc" +) + +func CmdStatus(f cmdutil.Factory) *cobra.Command { + cmd := &cobra.Command{ + Use: "status", + Short: i18n.T("KubeVPN status"), + Long: templates.LongDesc(i18n.T(`KubeVPN status`)), + Example: templates.Examples(i18n.T(``)), + PreRunE: func(cmd *cobra.Command, args []string) (err error) { + return daemon.StartupDaemon(cmd.Context()) + }, + RunE: func(cmd *cobra.Command, args []string) error { + client, err := daemon.GetClient(false).Status( + cmd.Context(), + &rpc.StatusRequest{}, + ) + if err != nil { + return err + } + fmt.Print(client.GetMessage()) + return nil + }, + } + return cmd +} diff --git a/cmd/kubevpn/cmds/version.go b/cmd/kubevpn/cmds/version.go index 8682e3af..98dfa980 100644 --- a/cmd/kubevpn/cmds/version.go +++ b/cmd/kubevpn/cmds/version.go @@ -35,6 +35,7 @@ func CmdVersion(cmdutil.Factory) *cobra.Command { Run: func(cmd *cobra.Command, args []string) { fmt.Printf("KubeVPN: CLI\n") fmt.Printf(" Version: %s\n", config.Version) + fmt.Printf(" DaemonVersion: %s\n", config.Version) fmt.Printf(" Image: %s\n", config.Image) fmt.Printf(" Branch: %s\n", Branch) fmt.Printf(" Git commit: %s\n", config.GitCommit) diff --git a/pkg/config/const.go b/pkg/config/const.go index fede331b..8b57ba86 100644 --- a/pkg/config/const.go +++ b/pkg/config/const.go @@ -9,8 +9,8 @@ const ( SockPath = "daemon.sock" SudoSockPath = "sudo_daemon.sock" - PidPath = "daemon_pid" - SudoPidPath = "sudo_daemon_pid" + PidPath = "daemon.pid" + SudoPidPath = "sudo_daemon.pid" LogFile = "daemon.log" diff --git a/pkg/daemon/action/connect.go b/pkg/daemon/action/connect.go index a7c1208f..aa2da0ee 100644 --- a/pkg/daemon/action/connect.go +++ b/pkg/daemon/action/connect.go @@ -74,12 +74,12 @@ func InitFactory(kubeconfigBytes string, ns string) cmdutil.Factory { func (svr *Server) Connect(req *rpc.ConnectRequest, resp rpc.Daemon_ConnectServer) error { origin := log.StandardLogger().Out - out := io.MultiWriter(newWarp(resp), origin) - log.SetOutput(out) defer func() { log.SetOutput(origin) log.SetLevel(log.DebugLevel) }() + out := io.MultiWriter(newWarp(resp), origin) + log.SetOutput(out) util.InitLogger(false) if !svr.IsSudo { return svr.redirectToSudoDaemon(req, resp) diff --git a/pkg/daemon/action/logs.go b/pkg/daemon/action/logs.go index 80350721..a701e9be 100644 --- a/pkg/daemon/action/logs.go +++ b/pkg/daemon/action/logs.go @@ -17,6 +17,7 @@ func (svr *Server) Logs(req *rpc.LogRequest, resp rpc.Daemon_LogsServer) error { if err != nil { return err } + defer file.Stop() for { select { case <-resp.Context().Done(): diff --git a/pkg/daemon/action/status.go b/pkg/daemon/action/status.go index 10786e03..226176f6 100644 --- a/pkg/daemon/action/status.go +++ b/pkg/daemon/action/status.go @@ -7,7 +7,11 @@ import ( ) func (svr *Server) Status(ctx context.Context, request *rpc.StatusRequest) (*rpc.StatusResponse, error) { + status := "None" + if svr.connect != nil { + status = "Connected" + } return &rpc.StatusResponse{ - Message: "i am fine", + Message: status, }, nil } diff --git a/pkg/daemon/action/upgrade.go b/pkg/daemon/action/upgrade.go index 5e1133f0..9cf55744 100644 --- a/pkg/daemon/action/upgrade.go +++ b/pkg/daemon/action/upgrade.go @@ -1 +1,34 @@ package action + +import ( + "os" + + goversion "github.com/hashicorp/go-version" + log "github.com/sirupsen/logrus" + + "github.com/wencaiwulue/kubevpn/pkg/config" + "github.com/wencaiwulue/kubevpn/pkg/daemon/rpc" +) + +func (svr *Server) Upgrade(req *rpc.UpgradeRequest, resp rpc.Daemon_UpgradeServer) error { + var err error + var clientVersion, daemonVersion *goversion.Version + clientVersion, err = goversion.NewVersion(req.ClientVersion) + if err != nil { + return err + } + daemonVersion, err = goversion.NewVersion(config.Version) + if err != nil { + return err + } + if clientVersion.GreaterThan(daemonVersion) || (clientVersion.Equal(daemonVersion) && req.ClientCommitId == config.GitCommit) { + log.Info("Already up to date, don't needs to upgrade") + return nil + } + executable, err := os.Executable() + if err != nil { + return err + } + println(executable) + return nil +} diff --git a/pkg/daemon/client.go b/pkg/daemon/client.go index 0b1eb46b..0d312952 100644 --- a/pkg/daemon/client.go +++ b/pkg/daemon/client.go @@ -20,6 +20,7 @@ import ( "github.com/wencaiwulue/kubevpn/pkg/config" "github.com/wencaiwulue/kubevpn/pkg/daemon/rpc" + "github.com/wencaiwulue/kubevpn/pkg/util" ) var daemonClient, sudoDaemonClient rpc.DaemonClient @@ -87,11 +88,27 @@ func GetPidPath(isSudo bool) string { return filepath.Join(config.DaemonPath, name) } -func GetDaemonCommand(isSudo bool) *exec.Cmd { - if isSudo { - return exec.Command("sudo", "--preserve-env", os.Args[0], "daemon", "--sudo") +func GetDaemonCommand(isSudo bool) error { + exe, err := os.Executable() + if err != nil { + return err } - return exec.Command(os.Args[0], "daemon") + fmt.Println(exe) + if isSudo { + return util.RunCmdWithElevated([]string{"daemon", "--sudo"}) + } + cmd := exec.Command(exe, "daemon") + err = cmd.Start() + if err != nil { + return err + } + go func() { + err := cmd.Wait() + if err != nil { + log.Error(err) + } + }() + return nil } func StartupDaemon(ctx context.Context) error { @@ -127,27 +144,27 @@ func runDaemon(ctx context.Context, isSudo bool) error { if err = p.Kill(); err != nil && err != os.ErrProcessDone { log.Error(err) } + p.Wait() } } } - cmd := GetDaemonCommand(isSudo) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err = cmd.Start(); err != nil { - return err - } - err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm) + err = GetDaemonCommand(isSudo) if err != nil { return err } - err = os.Chmod(GetPidPath(false), os.ModePerm) - if err != nil { - return err - } - go func() { - cmd.Wait() - }() + //cmd.Stdin = os.Stdin + //cmd.Stdout = os.Stdout + //cmd.Stderr = os.Stderr + //if err = cmd.Start(); err != nil { + // return err + //} + //err = os.WriteFile(pidPath, []byte(strconv.Itoa(cmd.Process.Pid)), os.ModePerm) + //if err != nil { + // return err + //} + //go func() { + // cmd.Wait() + //}() for ctx.Err() == nil { time.Sleep(time.Millisecond * 50) @@ -156,6 +173,11 @@ func runDaemon(ctx context.Context, isSudo bool) error { } } + err = os.Chmod(GetPidPath(false), os.ModePerm) + if err != nil { + return err + } + client := GetClient(isSudo) if client == nil { return fmt.Errorf("can not get daemon server client") diff --git a/pkg/daemon/rpc/daemon.pb.go b/pkg/daemon/rpc/daemon.pb.go index be1c12d7..cef0964e 100644 --- a/pkg/daemon/rpc/daemon.pb.go +++ b/pkg/daemon/rpc/daemon.pb.go @@ -782,6 +782,108 @@ func (x *LeaveResponse) GetMessage() string { return "" } +type UpgradeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientVersion string `protobuf:"bytes,1,opt,name=ClientVersion,proto3" json:"ClientVersion,omitempty"` + ClientCommitId string `protobuf:"bytes,2,opt,name=ClientCommitId,proto3" json:"ClientCommitId,omitempty"` +} + +func (x *UpgradeRequest) Reset() { + *x = UpgradeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_daemon_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpgradeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpgradeRequest) ProtoMessage() {} + +func (x *UpgradeRequest) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpgradeRequest.ProtoReflect.Descriptor instead. +func (*UpgradeRequest) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{14} +} + +func (x *UpgradeRequest) GetClientVersion() string { + if x != nil { + return x.ClientVersion + } + return "" +} + +func (x *UpgradeRequest) GetClientCommitId() string { + if x != nil { + return x.ClientCommitId + } + return "" +} + +type UpgradeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *UpgradeResponse) Reset() { + *x = UpgradeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_daemon_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpgradeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpgradeResponse) ProtoMessage() {} + +func (x *UpgradeResponse) ProtoReflect() protoreflect.Message { + mi := &file_daemon_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpgradeResponse.ProtoReflect.Descriptor instead. +func (*UpgradeResponse) Descriptor() ([]byte, []int) { + return file_daemon_proto_rawDescGZIP(), []int{15} +} + +func (x *UpgradeResponse) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + var File_daemon_proto protoreflect.FileDescriptor var file_daemon_proto_rawDesc = []byte{ @@ -854,36 +956,48 @@ var file_daemon_proto_rawDesc = []byte{ 0x03, 0x28, 0x09, 0x52, 0x09, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x22, 0x29, 0x0a, 0x0d, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xb5, 0x03, 0x0a, 0x06, 0x44, 0x61, - 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, - 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, - 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x36, - 0x0a, 0x05, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, - 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x12, 0x16, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, - 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, - 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2d, 0x0a, 0x04, 0x4c, 0x6f, 0x67, - 0x73, 0x12, 0x0f, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x33, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x12, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, - 0x04, 0x51, 0x75, 0x69, 0x74, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x69, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, - 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2d, - 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, - 0x05, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, - 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x72, 0x70, 0x63, 0x2e, - 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, - 0x01, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x3b, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x5e, 0x0a, 0x0e, 0x55, 0x70, 0x67, + 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x26, 0x0a, 0x0e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, + 0x74, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x49, 0x64, 0x22, 0x2b, 0x0a, 0x0f, 0x55, 0x70, 0x67, + 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0xef, 0x03, 0x0a, 0x06, 0x44, 0x61, 0x65, 0x6d, 0x6f, + 0x6e, 0x12, 0x38, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x13, 0x2e, 0x72, + 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x36, 0x0a, 0x05, 0x50, + 0x72, 0x6f, 0x78, 0x79, 0x12, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0a, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x12, 0x16, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x44, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2d, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x0f, + 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x33, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x12, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x04, 0x51, 0x75, + 0x69, 0x74, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x69, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x51, 0x75, 0x69, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2d, 0x0a, 0x04, 0x4c, + 0x69, 0x73, 0x74, 0x12, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x05, 0x4c, 0x65, + 0x61, 0x76, 0x65, 0x12, 0x11, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x65, 0x61, + 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x38, + 0x0a, 0x07, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x12, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, + 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x3b, 0x72, 0x70, + 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -898,7 +1012,7 @@ func file_daemon_proto_rawDescGZIP() []byte { return file_daemon_proto_rawDescData } -var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 15) +var file_daemon_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_daemon_proto_goTypes = []interface{}{ (*ConnectRequest)(nil), // 0: rpc.ConnectRequest (*ConnectResponse)(nil), // 1: rpc.ConnectResponse @@ -914,10 +1028,12 @@ var file_daemon_proto_goTypes = []interface{}{ (*ListResponse)(nil), // 11: rpc.ListResponse (*LeaveRequest)(nil), // 12: rpc.LeaveRequest (*LeaveResponse)(nil), // 13: rpc.LeaveResponse - nil, // 14: rpc.ConnectRequest.HeadersEntry + (*UpgradeRequest)(nil), // 14: rpc.UpgradeRequest + (*UpgradeResponse)(nil), // 15: rpc.UpgradeResponse + nil, // 16: rpc.ConnectRequest.HeadersEntry } var file_daemon_proto_depIdxs = []int32{ - 14, // 0: rpc.ConnectRequest.Headers:type_name -> rpc.ConnectRequest.HeadersEntry + 16, // 0: rpc.ConnectRequest.Headers:type_name -> rpc.ConnectRequest.HeadersEntry 0, // 1: rpc.Daemon.Connect:input_type -> rpc.ConnectRequest 0, // 2: rpc.Daemon.Proxy:input_type -> rpc.ConnectRequest 8, // 3: rpc.Daemon.Disconnect:input_type -> rpc.DisconnectRequest @@ -926,16 +1042,18 @@ var file_daemon_proto_depIdxs = []int32{ 2, // 6: rpc.Daemon.Quit:input_type -> rpc.QuitRequest 10, // 7: rpc.Daemon.List:input_type -> rpc.ListRequest 12, // 8: rpc.Daemon.Leave:input_type -> rpc.LeaveRequest - 1, // 9: rpc.Daemon.Connect:output_type -> rpc.ConnectResponse - 1, // 10: rpc.Daemon.Proxy:output_type -> rpc.ConnectResponse - 9, // 11: rpc.Daemon.Disconnect:output_type -> rpc.DisconnectResponse - 7, // 12: rpc.Daemon.Logs:output_type -> rpc.LogResponse - 5, // 13: rpc.Daemon.Status:output_type -> rpc.StatusResponse - 3, // 14: rpc.Daemon.Quit:output_type -> rpc.QuitResponse - 11, // 15: rpc.Daemon.List:output_type -> rpc.ListResponse - 13, // 16: rpc.Daemon.Leave:output_type -> rpc.LeaveResponse - 9, // [9:17] is the sub-list for method output_type - 1, // [1:9] is the sub-list for method input_type + 14, // 9: rpc.Daemon.Upgrade:input_type -> rpc.UpgradeRequest + 1, // 10: rpc.Daemon.Connect:output_type -> rpc.ConnectResponse + 1, // 11: rpc.Daemon.Proxy:output_type -> rpc.ConnectResponse + 9, // 12: rpc.Daemon.Disconnect:output_type -> rpc.DisconnectResponse + 7, // 13: rpc.Daemon.Logs:output_type -> rpc.LogResponse + 5, // 14: rpc.Daemon.Status:output_type -> rpc.StatusResponse + 3, // 15: rpc.Daemon.Quit:output_type -> rpc.QuitResponse + 11, // 16: rpc.Daemon.List:output_type -> rpc.ListResponse + 13, // 17: rpc.Daemon.Leave:output_type -> rpc.LeaveResponse + 15, // 18: rpc.Daemon.Upgrade:output_type -> rpc.UpgradeResponse + 10, // [10:19] is the sub-list for method output_type + 1, // [1:10] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name @@ -1115,6 +1233,30 @@ func file_daemon_proto_init() { return nil } } + file_daemon_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpgradeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_daemon_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpgradeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1122,7 +1264,7 @@ func file_daemon_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_daemon_proto_rawDesc, NumEnums: 0, - NumMessages: 15, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/daemon/rpc/daemon.proto b/pkg/daemon/rpc/daemon.proto index 7fe7b71f..9cf71f92 100644 --- a/pkg/daemon/rpc/daemon.proto +++ b/pkg/daemon/rpc/daemon.proto @@ -13,6 +13,7 @@ service Daemon { rpc Quit (QuitRequest) returns (stream QuitResponse) {} rpc List (ListRequest) returns (ListResponse) {} rpc Leave (LeaveRequest) returns (stream LeaveResponse) {} + rpc Upgrade (UpgradeRequest) returns (stream UpgradeResponse) {} } message ConnectRequest { @@ -87,4 +88,13 @@ message LeaveRequest { message LeaveResponse { string message = 1; +} + +message UpgradeRequest { + string ClientVersion = 1; + string ClientCommitId = 2; +} + +message UpgradeResponse { + string message = 1; } \ No newline at end of file diff --git a/pkg/daemon/rpc/daemon_grpc.pb.go b/pkg/daemon/rpc/daemon_grpc.pb.go index 7d8a9624..4a4d8bc7 100644 --- a/pkg/daemon/rpc/daemon_grpc.pb.go +++ b/pkg/daemon/rpc/daemon_grpc.pb.go @@ -27,6 +27,7 @@ const ( Daemon_Quit_FullMethodName = "/rpc.Daemon/Quit" Daemon_List_FullMethodName = "/rpc.Daemon/List" Daemon_Leave_FullMethodName = "/rpc.Daemon/Leave" + Daemon_Upgrade_FullMethodName = "/rpc.Daemon/Upgrade" ) // DaemonClient is the client API for Daemon service. @@ -41,6 +42,7 @@ type DaemonClient interface { Quit(ctx context.Context, in *QuitRequest, opts ...grpc.CallOption) (Daemon_QuitClient, error) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) Leave(ctx context.Context, in *LeaveRequest, opts ...grpc.CallOption) (Daemon_LeaveClient, error) + Upgrade(ctx context.Context, in *UpgradeRequest, opts ...grpc.CallOption) (Daemon_UpgradeClient, error) } type daemonClient struct { @@ -261,6 +263,38 @@ func (x *daemonLeaveClient) Recv() (*LeaveResponse, error) { return m, nil } +func (c *daemonClient) Upgrade(ctx context.Context, in *UpgradeRequest, opts ...grpc.CallOption) (Daemon_UpgradeClient, error) { + stream, err := c.cc.NewStream(ctx, &Daemon_ServiceDesc.Streams[6], Daemon_Upgrade_FullMethodName, opts...) + if err != nil { + return nil, err + } + x := &daemonUpgradeClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Daemon_UpgradeClient interface { + Recv() (*UpgradeResponse, error) + grpc.ClientStream +} + +type daemonUpgradeClient struct { + grpc.ClientStream +} + +func (x *daemonUpgradeClient) Recv() (*UpgradeResponse, error) { + m := new(UpgradeResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // DaemonServer is the server API for Daemon service. // All implementations must embed UnimplementedDaemonServer // for forward compatibility @@ -273,6 +307,7 @@ type DaemonServer interface { Quit(*QuitRequest, Daemon_QuitServer) error List(context.Context, *ListRequest) (*ListResponse, error) Leave(*LeaveRequest, Daemon_LeaveServer) error + Upgrade(*UpgradeRequest, Daemon_UpgradeServer) error mustEmbedUnimplementedDaemonServer() } @@ -304,6 +339,9 @@ func (UnimplementedDaemonServer) List(context.Context, *ListRequest) (*ListRespo func (UnimplementedDaemonServer) Leave(*LeaveRequest, Daemon_LeaveServer) error { return status.Errorf(codes.Unimplemented, "method Leave not implemented") } +func (UnimplementedDaemonServer) Upgrade(*UpgradeRequest, Daemon_UpgradeServer) error { + return status.Errorf(codes.Unimplemented, "method Upgrade not implemented") +} func (UnimplementedDaemonServer) mustEmbedUnimplementedDaemonServer() {} // UnsafeDaemonServer may be embedded to opt out of forward compatibility for this service. @@ -479,6 +517,27 @@ func (x *daemonLeaveServer) Send(m *LeaveResponse) error { return x.ServerStream.SendMsg(m) } +func _Daemon_Upgrade_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(UpgradeRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(DaemonServer).Upgrade(m, &daemonUpgradeServer{stream}) +} + +type Daemon_UpgradeServer interface { + Send(*UpgradeResponse) error + grpc.ServerStream +} + +type daemonUpgradeServer struct { + grpc.ServerStream +} + +func (x *daemonUpgradeServer) Send(m *UpgradeResponse) error { + return x.ServerStream.SendMsg(m) +} + // Daemon_ServiceDesc is the grpc.ServiceDesc for Daemon service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -526,6 +585,11 @@ var Daemon_ServiceDesc = grpc.ServiceDesc{ Handler: _Daemon_Leave_Handler, ServerStreams: true, }, + { + StreamName: "Upgrade", + Handler: _Daemon_Upgrade_Handler, + ServerStreams: true, + }, }, Metadata: "daemon.proto", } diff --git a/pkg/handler/connect.go b/pkg/handler/connect.go index eb3aec22..ce4ea88e 100644 --- a/pkg/handler/connect.go +++ b/pkg/handler/connect.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "google.golang.org/grpc/metadata" "io" "math" "math/rand" @@ -29,6 +28,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/pflag" "golang.org/x/sync/errgroup" + "google.golang.org/grpc/metadata" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/handler/serve.go b/pkg/handler/serve.go index a875a6a3..56b9a785 100644 --- a/pkg/handler/serve.go +++ b/pkg/handler/serve.go @@ -13,7 +13,7 @@ import ( "github.com/wencaiwulue/kubevpn/pkg/util" ) -func Complete(route *core.Route) error { +func RentIPIfNeeded(route *core.Route) error { if v, ok := os.LookupEnv(config.EnvInboundPodTunIPv4); ok && v == "" { namespace := os.Getenv(config.EnvPodNamespace) if namespace == "" { @@ -60,7 +60,7 @@ func Complete(route *core.Route) error { return nil } -func Final() error { +func ReleaseIPIfNeeded() error { namespace := os.Getenv(config.EnvPodNamespace) url := fmt.Sprintf("https://%s:80%s", util.GetTlsDomain(namespace), config.APIReleaseIP) req, err := http.NewRequest("DELETE", url, nil) diff --git a/pkg/util/elevate_others.go b/pkg/util/elevate_others.go new file mode 100644 index 00000000..1101f5da --- /dev/null +++ b/pkg/util/elevate_others.go @@ -0,0 +1,51 @@ +//go:build !windows +// +build !windows + +package util + +import ( + "flag" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/tools/clientcmd" + "os" + "os/exec" + "runtime" +) + +func RunCmdWithElevated(args []string) error { + // fix if startup with normal user, after elevated home dir will change to root user in linux + // but unix don't have this issue + if runtime.GOOS == "linux" && flag.Lookup("kubeconfig") == nil { + if _, err := os.Stat(clientcmd.RecommendedHomeFile); err == nil { + os.Args = append(os.Args, "--kubeconfig", clientcmd.RecommendedHomeFile) + } + } + exe, err := os.Executable() + if err != nil { + return err + } + cmd := exec.Command("sudo", append([]string{"--preserve-env", exe}, args...)...) + log.Debug(cmd.Args) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + cmd.Env = append(os.Environ(), envStartSudoKubeVPNByKubeVPN+"=1") + //// while send single CTRL+C, command will quit immediately, but output will cut off and print util quit final + //// so, mute single CTRL+C, let inner command handle single only + //go func() { + // signals := make(chan os.Signal) + // signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGSTOP) + // <-signals + //}() + err = cmd.Start() + if err != nil { + return err + } + go func() { + err := cmd.Wait() + if err != nil { + log.Warn(err) + } + }() + return nil +} diff --git a/pkg/util/elevate_windows.go b/pkg/util/elevate_windows.go new file mode 100644 index 00000000..3429de95 --- /dev/null +++ b/pkg/util/elevate_windows.go @@ -0,0 +1,52 @@ +//go:build windows +// +build windows + +package util + +import ( + "os" + "strings" + "syscall" + + "github.com/sirupsen/logrus" + "golang.org/x/sys/windows" +) + +// ref https://stackoverflow.com/questions/31558066/how-to-ask-for-administer-privileges-on-windows-with-go +func RunCmdWithElevated(arg []string) error { + verb := "runas" + exe, err := os.Executable() + if err != nil { + return err + } + cwd, err := os.Getwd() + if err != nil { + return err + } + args := strings.Join(arg, " ") + + verbPtr, err := windows.UTF16PtrFromString(verb) + if err != nil { + return err + } + exePtr, err := syscall.UTF16PtrFromString(exe) + if err != nil { + return err + } + cwdPtr, err := syscall.UTF16PtrFromString(cwd) + if err != nil { + return err + } + argPtr, err := syscall.UTF16PtrFromString(args) + if err != nil { + return err + } + + var showCmd int32 = 1 //SW_NORMAL + + err = windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd) + if err != nil { + logrus.Warn(err) + } + return err +}