-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[management/client] Integrate Job API with Job Stream and Client Engine #4428
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
08641b7
171925d
e47e648
dec307f
f1cc9e4
9cb9fc4
7fba07b
7c60ad6
36215b8
426a6f2
3ee24d7
b1077aa
d82d56a
9d5694f
889c3c8
3027029
2eba4af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,8 @@ import ( | |
| log "github.com/sirupsen/logrus" | ||
| "golang.zx2c4.com/wireguard/tun/netstack" | ||
| "golang.zx2c4.com/wireguard/wgctrl/wgtypes" | ||
| "google.golang.org/grpc" | ||
| "google.golang.org/grpc/credentials/insecure" | ||
| "google.golang.org/protobuf/proto" | ||
|
|
||
| nberrors "github.com/netbirdio/netbird/client/errors" | ||
|
|
@@ -53,6 +55,7 @@ import ( | |
| semaphoregroup "github.com/netbirdio/netbird/util/semaphore-group" | ||
|
|
||
| nbssh "github.com/netbirdio/netbird/client/ssh" | ||
| nbstatus "github.com/netbirdio/netbird/client/status" | ||
| "github.com/netbirdio/netbird/client/system" | ||
| nbdns "github.com/netbirdio/netbird/dns" | ||
| "github.com/netbirdio/netbird/route" | ||
|
|
@@ -62,7 +65,9 @@ import ( | |
| relayClient "github.com/netbirdio/netbird/shared/relay/client" | ||
| signal "github.com/netbirdio/netbird/shared/signal/client" | ||
| sProto "github.com/netbirdio/netbird/shared/signal/proto" | ||
| "github.com/netbirdio/netbird/upload-server/types" | ||
| "github.com/netbirdio/netbird/util" | ||
| "google.golang.org/grpc/status" | ||
| ) | ||
|
|
||
| // PeerConnectionTimeoutMax is a timeout of an initial connection attempt to a remote peer. | ||
|
|
@@ -194,6 +199,8 @@ type Engine struct { | |
| latestSyncResponse *mgmProto.SyncResponse | ||
| connSemaphore *semaphoregroup.SemaphoreGroup | ||
| flowManager nftypes.FlowManager | ||
|
|
||
| daemonAddress string | ||
| } | ||
|
|
||
| // Peer is an instance of the Connection Peer | ||
|
|
@@ -217,6 +224,7 @@ func NewEngine( | |
| mobileDep MobileDependency, | ||
| statusRecorder *peer.Status, | ||
| checks []*mgmProto.Checks, | ||
| daemonAddress string, | ||
| ) *Engine { | ||
| engine := &Engine{ | ||
| clientCtx: clientCtx, | ||
|
|
@@ -236,6 +244,7 @@ func NewEngine( | |
| statusRecorder: statusRecorder, | ||
| checks: checks, | ||
| connSemaphore: semaphoregroup.NewSemaphoreGroup(connInitLimit), | ||
| daemonAddress: daemonAddress, | ||
| } | ||
|
|
||
| sm := profilemanager.NewServiceManager("") | ||
|
|
@@ -887,19 +896,45 @@ func (e *Engine) updateConfig(conf *mgmProto.PeerConfig) error { | |
| return nil | ||
| } | ||
|
|
||
| func (e *Engine) getPeerClient() (*grpc.ClientConn, error) { | ||
| conn, err := grpc.NewClient( | ||
| strings.TrimPrefix(e.daemonAddress, "tcp://"), | ||
| grpc.WithTransportCredentials(insecure.NewCredentials()), | ||
| ) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to connect to daemon error: %v\n"+ | ||
| "If the daemon is not running please run: "+ | ||
| "\nnetbird service install \nnetbird service start\n", err) | ||
| } | ||
|
|
||
| return conn, nil | ||
| } | ||
|
|
||
| func (e *Engine) receiveJobEvents() { | ||
| go func() { | ||
| err := e.mgmClient.Job(e.ctx, func(msg *mgmProto.JobRequest) *mgmProto.JobResponse { | ||
| // Simple test handler — replace with real logic | ||
| log.Infof("Received job request: %+v", msg) | ||
| // TODO: trigger local debug bundle or other job | ||
| return &mgmProto.JobResponse{ | ||
| ID: msg.ID, | ||
| WorkloadResults: &mgmProto.JobResponse_Bundle{ | ||
| Bundle: &mgmProto.BundleResult{ | ||
| UploadKey: "upload-key", | ||
| switch params := msg.WorkloadParameters.(type) { | ||
| case *mgmProto.JobRequest_Bundle: | ||
| uploadKey, err := e.handleBundle(params.Bundle) | ||
| if err != nil { | ||
| return &mgmProto.JobResponse{ | ||
| ID: msg.ID, | ||
| Status: mgmProto.JobStatus_failed, | ||
| Reason: []byte(err.Error()), | ||
| } | ||
| } | ||
| return &mgmProto.JobResponse{ | ||
| ID: msg.ID, | ||
| Status: mgmProto.JobStatus_succeeded, | ||
| WorkloadResults: &mgmProto.JobResponse_Bundle{ | ||
| Bundle: &mgmProto.BundleResult{ | ||
| UploadKey: uploadKey, | ||
| }, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you are creating unnecessary code duplication. The only generic part is WorkloadResults. The rest is identical and can be build after the switch
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The generic part are
|
||
| }, | ||
| }, | ||
| } | ||
| default: | ||
| return nil | ||
| } | ||
| }) | ||
| if err != nil { | ||
|
|
@@ -914,6 +949,61 @@ func (e *Engine) receiveJobEvents() { | |
| log.Debugf("connecting to Management Service jobs stream") | ||
| } | ||
|
|
||
| func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (string, error) { | ||
| conn, err := e.getPeerClient() | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| defer func() { | ||
| if err := conn.Close(); err != nil { | ||
| log.Errorf("Failed to close connection: %v", err) | ||
| } | ||
| }() | ||
|
|
||
| statusOutput, err := e.getStatusOutput(params.Anonymize) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| request := &cProto.DebugBundleRequest{ | ||
| Anonymize: params.Anonymize, | ||
| SystemInfo: true, | ||
| Status: statusOutput, | ||
| LogFileCount: uint32(params.LogFileCount), | ||
| UploadURL: types.DefaultBundleURL, | ||
| } | ||
| service := cProto.NewDaemonServiceClient(conn) | ||
| resp, err := service.DebugBundle(e.clientCtx, request) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to bundle debug: " + status.Convert(err).Message()) | ||
| } | ||
|
|
||
| if resp.GetUploadFailureReason() != "" { | ||
| return "", fmt.Errorf("upload failed: " + resp.GetUploadFailureReason()) | ||
| } | ||
| return resp.GetUploadedKey(), nil | ||
| } | ||
|
|
||
| func (e *Engine) getStatusOutput(anon bool) (string, error) { | ||
| // todo: implement with real daemon address | ||
| conn, err := e.getPeerClient() | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| defer func() { | ||
| if err := conn.Close(); err != nil { | ||
| log.Errorf("Failed to close connection: %v", err) | ||
| } | ||
| }() | ||
|
|
||
| statusResp, err := cProto.NewDaemonServiceClient(conn).Status(e.clientCtx, &cProto.StatusRequest{GetFullPeerStatus: true, ShouldRunProbes: true}) | ||
| if err != nil { | ||
| return "", fmt.Errorf("status failed: %v", status.Convert(err).Message()) | ||
| } | ||
| return nbstatus.ParseToFullDetailSummary( | ||
| nbstatus.ConvertToStatusOutputOverview(statusResp, anon, "", nil, nil, nil, "", ""), | ||
| ), nil | ||
| } | ||
|
|
||
| // receiveManagementEvents connects to the Management Service event stream to receive updates from the management service | ||
| // E.g. when a new peer has been registered and we are allowed to connect to it. | ||
| func (e *Engine) receiveManagementEvents() { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is the way to go. The engine is part of the daemon so we are basically connecting to ourself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, i understand , that is why i needed help to understand what is the best why to call bundle ,
is passing grpc client and call it from it or passing address string and call the bundle or without the grpc and call the debugging directly ?
and also considering the other os