diff --git a/pkg/hostman/guestman/forwarder/doc.go b/pkg/hostman/guestman/forwarder/doc.go new file mode 100644 index 0000000000..d72f1a34e5 --- /dev/null +++ b/pkg/hostman/guestman/forwarder/doc.go @@ -0,0 +1 @@ +package forwarder // import "yunion.io/x/onecloud/pkg/hostman/guestman/forwarder" diff --git a/pkg/hostman/guestman/guesthandlers/guestforward.go b/pkg/hostman/guestman/guesthandlers/guestforward.go new file mode 100644 index 0000000000..2ab4cba74a --- /dev/null +++ b/pkg/hostman/guestman/guesthandlers/guestforward.go @@ -0,0 +1,64 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package guesthandlers + +import ( + "context" + + "yunion.io/x/jsonutils" + + hostapis "yunion.io/x/onecloud/pkg/apis/host" + "yunion.io/x/onecloud/pkg/hostman/guestman" + "yunion.io/x/onecloud/pkg/httperrors" +) + +func guestOpenForward(ctx context.Context, sid string, body jsonutils.JSONObject) (interface{}, error) { + req := &hostapis.GuestOpenForwardRequest{} + if err := body.Unmarshal(req); err != nil { + return nil, httperrors.NewInputParameterError("unmarshal: %v", err) + } + gm := guestman.GetGuestManager() + resp, err := gm.OpenForward(ctx, sid, req) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + return jsonutils.Marshal(resp), nil +} + +func guestListForward(ctx context.Context, sid string, body jsonutils.JSONObject) (interface{}, error) { + req := &hostapis.GuestListForwardRequest{} + if err := body.Unmarshal(req); err != nil { + return nil, httperrors.NewInputParameterError("unmarshal: %v", err) + } + gm := guestman.GetGuestManager() + resp, err := gm.ListForward(ctx, sid, req) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + return jsonutils.Marshal(resp), nil +} + +func guestCloseForward(ctx context.Context, sid string, body jsonutils.JSONObject) (interface{}, error) { + req := &hostapis.GuestCloseForwardRequest{} + if err := body.Unmarshal(req); err != nil { + return nil, httperrors.NewInputParameterError("unmarshal: %v", err) + } + gm := guestman.GetGuestManager() + resp, err := gm.CloseForward(ctx, sid, req) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + return jsonutils.Marshal(resp), nil +} diff --git a/pkg/hostman/guestman/guesthandlers/guesthandler.go b/pkg/hostman/guestman/guesthandlers/guesthandler.go index 94bba8363d..dea39bbebc 100644 --- a/pkg/hostman/guestman/guesthandlers/guesthandler.go +++ b/pkg/hostman/guestman/guesthandlers/guesthandler.go @@ -77,6 +77,9 @@ func AddGuestTaskHandler(prefix string, app *appsrv.Application) { "cancel-block-jobs": guestCancelBlockJobs, "create-from-libvirt": guestCreateFromLibvirt, "create-form-esxi": guestCreateFromEsxi, + "open-forward": guestOpenForward, + "list-forward": guestListForward, + "close-forward": guestCloseForward, } { app.AddHandler("POST", fmt.Sprintf("%s/%s//%s", prefix, keyWord, action), diff --git a/pkg/hostman/guestman/guestman.go b/pkg/hostman/guestman/guestman.go index 2e686ac8ca..e23f2b10ff 100644 --- a/pkg/hostman/guestman/guestman.go +++ b/pkg/hostman/guestman/guestman.go @@ -33,7 +33,10 @@ import ( "yunion.io/x/pkg/util/seclib" "yunion.io/x/onecloud/pkg/apis/compute" + hostapi "yunion.io/x/onecloud/pkg/apis/host" "yunion.io/x/onecloud/pkg/appsrv" + fwd "yunion.io/x/onecloud/pkg/hostman/guestman/forwarder" + fwdpb "yunion.io/x/onecloud/pkg/hostman/guestman/forwarder/api" "yunion.io/x/onecloud/pkg/hostman/guestman/types" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostutils" @@ -382,6 +385,152 @@ func (m *SGuestManager) Monitor(sid, cmd string, callback func(string)) error { } } +func (m *SGuestManager) sdnClient() (fwdpb.ForwarderClient, error) { + sockPath := options.HostOptions.SdnSocketPath + if strings.HasPrefix(sockPath, "/") { + sockPath = "unix://" + sockPath + } + cli, err := fwd.NewClient(sockPath) + return cli, err +} + +func (m *SGuestManager) OpenForward(ctx context.Context, sid string, req *hostapi.GuestOpenForwardRequest) (*hostapi.GuestOpenForwardResponse, error) { + guest, ok := m.GetServer(sid) + if !ok { + return nil, httperrors.NewNotFoundError("Not found") + } + if !guest.IsRunning() { + return nil, httperrors.NewBadRequestError("Server stopped??") + } + + nic := guest.GetVpcNIC() + if nic == nil { + return nil, httperrors.NewBadRequestError("no vpc nic") + } + + netId, _ := nic.GetString("net_id") + if netId == "" { + return nil, httperrors.NewBadRequestError("no network id") + } + ip, _ := nic.GetString("ip") + if ip == "" { + return nil, httperrors.NewBadRequestError("no vpc ip") + } + pbreq := &fwdpb.OpenRequest{ + NetId: netId, + Proto: req.Proto, + BindAddr: m.host.GetMasterIp(), + RemoteAddr: ip, + RemotePort: uint32(req.Port), + } + cli, err := m.sdnClient() + if err != nil { + log.Errorf("new sdn client error: %v", err) + return nil, httperrors.NewBadGatewayError("lost sdn connection") + } + resp, err := cli.Open(ctx, pbreq) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + output := &hostapi.GuestOpenForwardResponse{ + Proto: resp.Proto, + Addr: resp.RemoteAddr, + Port: int(resp.RemotePort), + + ProxyAddr: resp.BindAddr, + ProxyPort: int(resp.BindPort), + } + return output, nil +} + +func (m *SGuestManager) CloseForward(ctx context.Context, sid string, req *hostapi.GuestCloseForwardRequest) (*hostapi.GuestCloseForwardResponse, error) { + guest, ok := m.GetServer(sid) + if !ok { + return nil, httperrors.NewNotFoundError("Not found") + } + + nic := guest.GetVpcNIC() + if nic == nil { + return nil, httperrors.NewBadRequestError("no vpc nic") + } + + netId, _ := nic.GetString("net_id") + if netId == "" { + return nil, httperrors.NewBadRequestError("no network id") + } + pbreq := &fwdpb.CloseRequest{ + NetId: netId, + Proto: req.Proto, + BindAddr: req.ProxyAddr, + BindPort: uint32(req.ProxyPort), + } + cli, err := m.sdnClient() + if err != nil { + log.Errorf("new sdn client error: %v", err) + return nil, httperrors.NewBadGatewayError("lost sdn connection") + } + resp, err := cli.Close(ctx, pbreq) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + output := &hostapi.GuestCloseForwardResponse{ + Proto: resp.Proto, + ProxyAddr: resp.BindAddr, + ProxyPort: int(resp.BindPort), + } + return output, nil +} + +func (m *SGuestManager) ListForward(ctx context.Context, sid string, req *hostapi.GuestListForwardRequest) (*hostapi.GuestListForwardResponse, error) { + guest, ok := m.GetServer(sid) + if !ok { + return nil, httperrors.NewNotFoundError("Not found") + } + if !guest.IsRunning() { + return nil, httperrors.NewBadRequestError("Server stopped??") + } + + nic := guest.GetVpcNIC() + if nic == nil { + return nil, httperrors.NewBadRequestError("no vpc nic") + } + + netId, _ := nic.GetString("net_id") + if netId == "" { + return nil, httperrors.NewBadRequestError("no network id") + } + pbreq := &fwdpb.ListByRemoteRequest{ + NetId: netId, + Proto: req.Proto, + RemoteAddr: req.Addr, + RemotePort: uint32(req.Port), + } + cli, err := m.sdnClient() + if err != nil { + log.Errorf("new sdn client error: %v", err) + return nil, httperrors.NewBadGatewayError("lost sdn connection") + } + resp, err := cli.ListByRemote(ctx, pbreq) + if err != nil { + return nil, httperrors.NewGeneralError(err) + } + var outputForwards []hostapi.GuestOpenForwardResponse + for i := range resp.Forwards { + outputForwards = append(outputForwards, hostapi.GuestOpenForwardResponse{ + Proto: resp.Forwards[i].Proto, + Addr: resp.Forwards[i].RemoteAddr, + Port: int(resp.Forwards[i].RemotePort), + + ProxyAddr: resp.Forwards[i].BindAddr, + ProxyPort: int(resp.Forwards[i].BindPort), + }) + } + output := &hostapi.GuestListForwardResponse{ + Forwards: outputForwards, + } + return output, nil +} + func (m *SGuestManager) GuestCreate(ctx context.Context, params interface{}) (jsonutils.JSONObject, error) { deployParams, ok := params.(*SGuestDeploy) if !ok { diff --git a/pkg/hostman/guestman/types/doc.go b/pkg/hostman/guestman/types/doc.go new file mode 100644 index 0000000000..2378694cf7 --- /dev/null +++ b/pkg/hostman/guestman/types/doc.go @@ -0,0 +1 @@ +package types // import "yunion.io/x/onecloud/pkg/hostman/guestman/types"