Skip to content
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

delegate-shell lib #1

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions delegateshell/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# About

A golang client which can interact and acquire tasks from the Harness manager (or any task management system which implements the same interface)

delegate-shell library provides two utlities.
1. Register Runner with Runner Manager and sending heartbeats
2. Poll Runner task events

The idea is `delegate-shell` library should be a standalone library. Runner can use this library to handle all lifecycle events and interations with Harness.

# Usage
Example codes in `delegateshell/example` folder. You can run it by `go run main.go`

A way to use this client would be:
1. Registeration & heartbeat
```
// Create a manager http client
managerClient := client.New(...)

keepAlive := heartbeat.New(..., managerClient)

// Register & heartbeat
ctx := context.Background()
resp, _ := keepAlive.Register(ctx)
```
2. Poll tasks
```
requestsChan := make(chan *client.RunnerRequest, 3)

// Start polling for events
eventsServer := poller.New(managerClient, requestsChan)
eventsServer.PollRunnerEvents(ctx, 3, info.ID, time.Second*10)
// next: process requests from 'requestsChan'
```

## TODOs
1. It uses register call for heartbeat. Maybe we should use polling tasks as heartbeat. This reduces network load on Harness gateway significantly
2. thread pool abstraction should be there for handle thread&resource allocation&isolation
3. Create a top level package for logger. Use that everywhere
4. Shutdownhook is not there
5. CPU memory related rejecting tasks is not there
6. Add error library for all places
7. Central Config: implement a global context where it has all the delegate configurations
126 changes: 126 additions & 0 deletions delegateshell/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package client

import (
"context"
"encoding/json"
)

// TODO: Make the structs more generic and remove Harness specific stuff
type (
// Taken from existing manager API
RegisterRequest struct {
AccountID string `json:"accountId,omitempty"`
RunnerName string `json:"delegateName,omitempty"`
LastHeartbeat int64 `json:"lastHeartBeat,omitempty"`
ID string `json:"delegateId,omitempty"`
Type string `json:"delegateType,omitempty"`
NG bool `json:"ng,omitempty"`
Polling bool `json:"pollingModeEnabled,omitempty"` // why Runner needs type ?? maybe should remove
HostName string `json:"hostName,omitempty"`
Connected bool `json:"connected,omitempty"`
KeepAlivePacket bool `json:"keepAlivePacket,omitempty"`
IP string `json:"ip,omitempty"`
Tags []string `json:"tags,omitempty"`
HeartbeatAsObject bool `json:"heartbeatAsObject,omitempty"` // TODO: legacy to remove
}

// Used in the java codebase :'(
RegisterResponse struct {
Resource RegistrationData `json:"resource"`
}

RegistrationData struct {
DelegateID string `json:"delegateId"`
}

TaskEventsResponse struct {
TaskEvents []*TaskEvent `json:"delegateTaskEvents"`
}

RunnerEvent struct {
AccountID string `json:"accountId"`
TaskID string `json:"taskId"`
RunnerType string `json:"runnerType"`
TaskType string `json:"taskType"`
}

RunnerEventsResponse struct {
RunnerEvents []*RunnerEvent `json:"delegateRunnerEvents"`
}

TaskEvent struct {
AccountID string `json:"accountId"`
TaskID string `json:"delegateTaskId"`
Sync bool `json:"sync"`
TaskType string `json:"taskType"`
}

Task struct {
ID string `json:"id"`
Type string `json:"type"`
Data json.RawMessage `json:"data"`
Async bool `json:"async"`
Timeout int `json:"timeout"`
Logging LogInfo `json:"logging"`
DelegateInfo DelegateInfo `json:"delegate"`
Capabilities json.RawMessage `json:"capabilities"`
}

LogInfo struct {
Token string `json:"token"`
Abstractions map[string]string `json:"abstractions"`
}

DelegateInfo struct {
ID string `json:"id"`
InstanceID string `json:"instance_id"`
Token string `json:"token"`
}

TaskResponse struct {
ID string `json:"id"`
Data json.RawMessage `json:"data"`
Type string `json:"type"`
Code string `json:"code"` // OK, FAILED, RETRY_ON_OTHER_DELEGATE
}

DelegateCapacity struct {
MaxBuilds int `json:"maximumNumberOfBuilds"`
}

RunnerAcquiredTasks struct {
Requests []*RunnerRequest `json:"requests"`
}

RunnerRequest struct {
TaskId string `json:"id"`
AccountId string `json:"account_id"`
Task *RunnerTask `json:"task"`
Secrets []*RunnerTask `json:"secrets"`
}

RunnerTask struct {
Type string `json:"type"`
Driver string `json:"driver"`
Data []byte `json:"data"`
Config []byte `json:"config"`
}
)

// Client is an interface which defines methods on interacting with a task managing system.
type Client interface {
// Register registers the runner with the task server
Register(ctx context.Context, r *RegisterRequest) (*RegisterResponse, error)

// Heartbeat pings the task server to let it know that the runner is still alive
Heartbeat(ctx context.Context, r *RegisterRequest) error

// GetTaskEvents gets a list of pending tasks that need to be executed for this runner
GetRunnerEvents(ctx context.Context, delegateID string) (*RunnerEventsResponse, error)

// Acquire tells the task server that the runner is ready to execute a task ID
GetExecutionPayload(ctx context.Context, delegateID, taskID string) (*RunnerAcquiredTasks, error)

// SendStatus sends a response to the task server for a task ID
SendStatus(ctx context.Context, delegateID, taskID string, req *TaskResponse) error
}
Loading