NOISSUE - Introduce computation runner, log forwarder, ingress, and egress proxy services. (#559)

* feat: Introduce computation runner, log forwarder, ingress, and egress proxy services.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: Update Go environment variable parsing and build system to use new architecture and repository.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: Update package sources to `sammyoina/cocos-ai` at a specific commit, add log-forwarder pre-start hook, and rename proxy binaries.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* chore: Update build system references to a specific commit and enhance logging for service connections and message processing.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* build: Update package source repositories and versions, migrate client logging to slog, and adjust ingress/egress proxy build and install steps.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* debug stuck

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* debug

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* debug

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: add HTTP/2 support to egress proxy and update build system to use specific commit hashes

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: enhance egress proxy CONNECT handling, update package sources, and add gRPC test utility

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: Update build system for various services to a specific commit from a new repository, change agent gRPC port to 7001, and add a gRPC test client.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: Migrate agent-internal gRPC communication to Unix sockets, set ingress proxy to port 7002, and update build hashes.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* refactor: Remove standalone ingress-proxy systemd service and update component versions.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* fix: Prevent computation re-initialization in agent and update component versions across several packages.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: update package versions and enable h2c support in ingress proxy.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: refactor ingress proxy to support HTTP/2 over Unix sockets and update component versions.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: Update build system package sources to `ultravioletrs/cocos` and reduce agent logging verbosity.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* refactor: improve error handling in proxy commands and remove unused gRPC test

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* test: add mock service state return value in handleRunReqChunks test

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* feat: add comprehensive tests for service and proxy components

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* fix linter

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* improve coverage

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* test: add gRPC client and ingress adapter tests, and update egress proxy tests.

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* improve coverage

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

---------

Signed-off-by: Sammy Oina <sammyoina@gmail.com>
This commit is contained in:
Sammy Kerata Oina
2026-02-09 12:38:21 +03:00
committed by GitHub
parent ee52551ca4
commit a3265bc346
57 changed files with 6529 additions and 162 deletions
+141
View File
@@ -0,0 +1,141 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package service
import (
"context"
"fmt"
"log/slog"
"os"
"path/filepath"
"sync"
"github.com/ultravioletrs/cocos/agent/algorithm"
"github.com/ultravioletrs/cocos/agent/algorithm/binary"
"github.com/ultravioletrs/cocos/agent/algorithm/docker"
"github.com/ultravioletrs/cocos/agent/algorithm/python"
"github.com/ultravioletrs/cocos/agent/algorithm/wasm"
"github.com/ultravioletrs/cocos/agent/events"
pb "github.com/ultravioletrs/cocos/agent/runner"
"google.golang.org/protobuf/types/known/emptypb"
)
const (
algoFilePermission = 0o700
)
var _ pb.ComputationRunnerServer = (*RunnerService)(nil)
type RunnerService struct {
pb.UnimplementedComputationRunnerServer
logger *slog.Logger
eventSvc events.Service
currentAlgo algorithm.Algorithm
mu sync.Mutex
}
func New(logger *slog.Logger, eventSvc events.Service) *RunnerService {
return &RunnerService{
logger: logger,
eventSvc: eventSvc,
}
}
func (s *RunnerService) Run(ctx context.Context, req *pb.RunRequest) (*pb.RunResponse, error) {
s.mu.Lock()
if s.currentAlgo != nil {
s.mu.Unlock()
return &pb.RunResponse{
ComputationId: req.ComputationId,
Error: "computation already running",
}, nil
}
s.mu.Unlock()
defer func() {
s.mu.Lock()
s.currentAlgo = nil
s.mu.Unlock()
}()
currentDir, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("error getting current directory: %v", err)
}
// Write Algo File
algoPath := filepath.Join(currentDir, "algo")
f, err := os.Create(algoPath)
if err != nil {
return nil, fmt.Errorf("error creating algorithm file: %v", err)
}
if _, err := f.Write(req.Algorithm); err != nil {
return nil, fmt.Errorf("error writing algorithm to file: %v", err)
}
if err := os.Chmod(algoPath, algoFilePermission); err != nil {
return nil, fmt.Errorf("error changing file permissions: %v", err)
}
if err := f.Close(); err != nil {
return nil, fmt.Errorf("error closing file: %v", err)
}
var algo algorithm.Algorithm
switch req.AlgoType {
case string(algorithm.AlgoTypeBin):
algo = binary.NewAlgorithm(s.logger, s.eventSvc, algoPath, req.Args, req.ComputationId)
case string(algorithm.AlgoTypePython):
var requirementsFile string
if len(req.Requirements) > 0 {
fr, err := os.CreateTemp("", "requirements.txt")
if err != nil {
return nil, fmt.Errorf("error creating requirments file: %v", err)
}
if _, err := fr.Write(req.Requirements); err != nil {
return nil, fmt.Errorf("error writing requirements to file: %v", err)
}
if err := fr.Close(); err != nil {
return nil, fmt.Errorf("error closing file: %v", err)
}
requirementsFile = fr.Name()
}
// Assuming default python runtime if not specified in request (proto doesn't have runtime field yet)
// We can add it or assume.
runtime := python.PyRuntime
algo = python.NewAlgorithm(s.logger, s.eventSvc, runtime, requirementsFile, algoPath, req.Args, req.ComputationId)
case string(algorithm.AlgoTypeWasm):
algo = wasm.NewAlgorithm(s.logger, s.eventSvc, req.Args, algoPath, req.ComputationId)
case string(algorithm.AlgoTypeDocker):
algo = docker.NewAlgorithm(s.logger, s.eventSvc, algoPath, req.ComputationId)
default:
return nil, fmt.Errorf("unsupported algorithm type: %s", req.AlgoType)
}
s.mu.Lock()
s.currentAlgo = algo
s.mu.Unlock()
if err := algo.Run(); err != nil {
s.logger.Error("computation failed", "error", err)
return &pb.RunResponse{
ComputationId: req.ComputationId,
Error: err.Error(),
}, nil
}
return &pb.RunResponse{
ComputationId: req.ComputationId,
}, nil
}
func (s *RunnerService) Stop(ctx context.Context, req *pb.StopRequest) (*emptypb.Empty, error) {
s.mu.Lock()
defer s.mu.Unlock()
if s.currentAlgo != nil {
if err := s.currentAlgo.Stop(); err != nil {
return nil, err
}
}
return &emptypb.Empty{}, nil
}