mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
COCOS-101 - Switch to self-contained algorithms as executables (#119)
* Switch to self-contained algorithms as executables Transitioned from using Python scripts to self-contained binary executables for running algorithms, improving modularity and reducing dependencies. This change removes the reliance on a Python environment, as evident by the removal of Python setup and packages from the build configuration. The service now creates temporary executable files for algorithm runs, handling all permissions and cleanup, enhancing security and maintaining clean execution states. A warning is logged if computation fails, aiding in debugging. Additionally, updated manual tests to reflect these changes in the agent's handling of algorithms. Refactors: - Removed Python runtime const since it's no longer needed. - Updated documentation and test commands to reflect the change from .py to .bin for algorithm files. Build config: - Removed Python and pip packages to reduce the build size and complexity. Signed-off-by: SammyOina <sammyoina@gmail.com> * Update agent service.go file with new constants and file permission Signed-off-by: SammyOina <sammyoina@gmail.com> * Refine singular usage of 'algorithm' across modules Standardized terminology throughout the project to refer to 'algorithm' in the singular form rather than plural. Streamlined various documentations, string constants, function names, and variable names to bring cohesiveness and eliminate ambiguity when handling algorithms across README files, CLI interfaces, and internal API representations. Signed-off-by: SammyOina <sammyoina@gmail.com> * Fix state names and indices in state_string.go Signed-off-by: SammyOina <sammyoina@gmail.com> --------- Signed-off-by: SammyOina <sammyoina@gmail.com>
This commit is contained in:
committed by
GitHub
parent
4b5000d107
commit
8d082567d7
@@ -7,7 +7,7 @@ based on the [Confidential Computing][cc] and [Trusted Execution Environments (T
|
||||
</p>
|
||||
|
||||
With Cocos AI it becomes possible to run AI/ML workloads on combined datasets from multiple organizations
|
||||
while guaranteeing the privacy and security of the data and the algorithms.
|
||||
while guaranteeing the privacy and security of the data and the algorithm.
|
||||
Data is always encrypted, protected by hardware secure enclaves (Trusted Execution Environments),
|
||||
attested via secure remote attestation protocols, and invisible to cloud processors or any other
|
||||
3rd party to which computation is offloaded.
|
||||
|
||||
@@ -26,7 +26,7 @@ type Computation struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Datasets Datasets `json:"datasets,omitempty"`
|
||||
Algorithm Algorithm `json:"algorithms,omitempty"`
|
||||
Algorithm Algorithm `json:"algorithm,omitempty"`
|
||||
ResultConsumers []string `json:"result_consumers,omitempty"`
|
||||
AgentConfig AgentConfig `json:"agent_config,omitempty"`
|
||||
}
|
||||
|
||||
+30
-12
@@ -9,6 +9,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
|
||||
@@ -20,8 +21,12 @@ import (
|
||||
|
||||
var _ Service = (*agentService)(nil)
|
||||
|
||||
// ReportDataSize is the size of the report data expected by the attestation service.
|
||||
const ReportDataSize = 64
|
||||
const (
|
||||
// ReportDataSize is the size of the report data expected by the attestation service.
|
||||
ReportDataSize = 64
|
||||
socketPath = "unix_socket"
|
||||
algoFilePermission = 0o700
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrMalformedEntity indicates malformed entity specification (e.g.
|
||||
@@ -67,11 +72,6 @@ type agentService struct {
|
||||
eventSvc events.Service // Service for publishing events related to computation.
|
||||
}
|
||||
|
||||
const (
|
||||
socketPath = "unix_socket"
|
||||
pyRuntime = "python3"
|
||||
)
|
||||
|
||||
var _ Service = (*agentService)(nil)
|
||||
|
||||
// New instantiates the agent service implementation.
|
||||
@@ -204,6 +204,7 @@ func (as *agentService) runComputation() {
|
||||
result, err := run(as.algorithm, as.datasets[0])
|
||||
if err != nil {
|
||||
as.runError = err
|
||||
as.sm.logger.Warn(fmt.Sprintf("computation failed with error: %s", err.Error()))
|
||||
as.publishEvent("failed", json.RawMessage{})()
|
||||
return
|
||||
}
|
||||
@@ -234,17 +235,34 @@ func run(algoContent, dataContent []byte) ([]byte, error) {
|
||||
|
||||
go socket.AcceptConnection(listener, dataChannel, errorChannel)
|
||||
|
||||
// Construct the Python script content with CSV data as a command-line argument
|
||||
script := string(algoContent)
|
||||
f, err := os.CreateTemp("", "algorithm")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating algorithm file: %v", err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if _, err := f.Write(algoContent); err != nil {
|
||||
return nil, fmt.Errorf("error writing algorithm to file: %v", err)
|
||||
}
|
||||
|
||||
if err := os.Chmod(f.Name(), 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)
|
||||
}
|
||||
|
||||
// Construct the executable with CSV data as a command-line argument
|
||||
data := string(dataContent)
|
||||
cmd := exec.Command(pyRuntime, "-c", script, data, socketPath)
|
||||
cmd := exec.Command(f.Name(), data, socketPath)
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("error starting Python script: %v", err)
|
||||
return nil, fmt.Errorf("error starting algorithm: %v", err)
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("python script execution error: %v", err)
|
||||
return nil, fmt.Errorf("algorithm execution error: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
|
||||
@@ -17,9 +17,9 @@ func _() {
|
||||
_ = x[complete-6]
|
||||
}
|
||||
|
||||
const _state_name = "idlereceivingManifestsreceivingAlgorithmsreceivingDatarunningresultsReadycomplete"
|
||||
const _state_name = "idlereceivingManifestreceivingAlgorithmreceivingDatarunningresultsReadycomplete"
|
||||
|
||||
var _state_index = [...]uint8{0, 4, 22, 41, 54, 61, 73, 81}
|
||||
var _state_index = [...]uint8{0, 4, 21, 39, 52, 59, 71, 79}
|
||||
|
||||
func (i state) String() string {
|
||||
if i < 0 || i >= state(len(_state_index)-1) {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Agent CLI
|
||||
|
||||
This repository contains the command-line interface (CLI) tool for interacting with the Agent and manager service. The CLI allows you to perform various tasks such as running computations, uploading algorithms and datasets, and retrieving results.
|
||||
This repository contains the command-line interface (CLI) tool for interacting with the Agent and manager service. The CLI allows you to perform various tasks such as running computations, uploading algorithm and datasets, and retrieving results.
|
||||
|
||||
## Build
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
)
|
||||
|
||||
func (cli *CLI) NewAlgorithmsCmd() *cobra.Command {
|
||||
func (cli *CLI) NewAlgorithmCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "algo",
|
||||
Short: "Upload an algorithm binary",
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Agent Commands
|
||||
rootCmd.AddCommand(cliSVC.NewAlgorithmsCmd())
|
||||
rootCmd.AddCommand(cliSVC.NewAlgorithmCmd())
|
||||
rootCmd.AddCommand(cliSVC.NewDatasetsCmd())
|
||||
rootCmd.AddCommand(cliSVC.NewResultsCmd())
|
||||
attestaionCmd := cliSVC.NewAttestationCmd()
|
||||
|
||||
@@ -42,7 +42,3 @@ BR2_LINUX_KERNEL_NEEDS_HOST_LIBELF=y
|
||||
# host-qemu for gitlab testing
|
||||
BR2_PACKAGE_HOST_QEMU=y
|
||||
BR2_PACKAGE_HOST_QEMU_SYSTEM_MODE=y
|
||||
|
||||
# Python
|
||||
BR2_PACKAGE_PYTHON3=y
|
||||
BR2_PACKAGE_PYTHON_PIP=y
|
||||
|
||||
@@ -3,6 +3,6 @@ config BR2_PACKAGE_AGENT
|
||||
default y
|
||||
help
|
||||
Confidential Computing Agent is a state machine capable of
|
||||
receiving data and algorithms, running computations, and
|
||||
receiving datasets and algorithm, running computations, and
|
||||
fetching the attestation report from within the
|
||||
Confidential VM.
|
||||
@@ -4,14 +4,15 @@
|
||||
|
||||
Throughout the tests, we assume that our current working directory is the root of the `cocos` repository, both on the host machine and in the VM.
|
||||
|
||||
### Python requirements
|
||||
### Algorithm requirements
|
||||
|
||||
Do this in the VM.
|
||||
|
||||
```sh
|
||||
pip3 install pandas scikit-learn
|
||||
Agent accepts the algorithm as a binary that take in two command line arguments.
|
||||
```shell
|
||||
algorithm-file <dataset as string> <unix socket path>
|
||||
```
|
||||
|
||||
The algorithm program should return the results to a socket and an example can be seen in this [file](./algo/lin_reg.py).
|
||||
|
||||
### Agent-CLI interaction
|
||||
|
||||
Agent is started automatically in the VM when launched but requires configuration and manifest to be passed by manager. Alternatively you can pass configuration using this [simplified script](./agent-config/main.go)
|
||||
@@ -32,8 +33,8 @@ go run cmd/cli/main.go attestation get '<report_data>'
|
||||
go run cmd/cli/main.go attestation validate '<attesation>' --report_data '<report_data>'
|
||||
|
||||
# Run the CLI program with algorithm input
|
||||
go run cmd/cli/main.go algo test/manual/algo/lin_reg.py Algorithm1 AlgorithmProvider1
|
||||
# 2023/09/21 10:43:53 Uploading algorithm binary: test/manual/algo/lin_reg.py
|
||||
go run cmd/cli/main.go algo test/manual/algo/lin_reg.bin Algorithm1 AlgorithmProvider1
|
||||
# 2023/09/21 10:43:53 Uploading algorithm binary: test/manual/algo/lin_reg.bin
|
||||
|
||||
# Run the CLI program with dataset input
|
||||
go run cmd/cli/main.go data test/manual/data/iris.csv Dataset1 Provider1
|
||||
|
||||
@@ -13,64 +13,12 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/mdlayher/vsock"
|
||||
"github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"github.com/ultravioletrs/cocos/agent"
|
||||
"github.com/ultravioletrs/cocos/manager"
|
||||
pkgmanager "github.com/ultravioletrs/cocos/pkg/manager"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const VsockConfigPort uint32 = 9999
|
||||
|
||||
type AgentConfig struct {
|
||||
LogLevel string `json:"log_level"`
|
||||
InstanceID string `json:"instance_id"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
CertFile string `json:"cert_file"`
|
||||
KeyFile string `json:"server_key"`
|
||||
AttestedTls bool `json:"attested_tls"`
|
||||
}
|
||||
|
||||
type Computation struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Datasets Datasets `json:"datasets,omitempty"`
|
||||
Algorithms Algorithms `json:"algorithms,omitempty"`
|
||||
ResultConsumers []string `json:"result_consumers,omitempty"`
|
||||
AgentConfig AgentConfig `json:"agent_config,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Datasets) String() string {
|
||||
dat, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
func (a *Algorithms) String() string {
|
||||
dat, err := json.Marshal(a)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(dat)
|
||||
}
|
||||
|
||||
type Dataset struct {
|
||||
Dataset []byte `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Datasets []Dataset
|
||||
|
||||
type Algorithm struct {
|
||||
Algorithm []byte `json:"-"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type Algorithms []Algorithm
|
||||
|
||||
func main() {
|
||||
attestedTLS := false
|
||||
|
||||
@@ -85,16 +33,16 @@ func main() {
|
||||
log.Fatalf("usage: %s <attested-tls>", os.Args[0])
|
||||
}
|
||||
|
||||
l, err := vsock.Listen(9997, nil)
|
||||
l, err := vsock.Listen(manager.ManagerVsockPort, nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ac := Computation{
|
||||
ac := agent.Computation{
|
||||
ID: "123",
|
||||
Datasets: Datasets{Dataset{ID: "1", Provider: "pr1"}},
|
||||
Algorithms: Algorithms{Algorithm{ID: "1", Provider: "pr1"}},
|
||||
Datasets: agent.Datasets{agent.Dataset{ID: "1", Provider: "pr1"}},
|
||||
Algorithm: agent.Algorithm{ID: "1", Provider: "pr1"},
|
||||
ResultConsumers: []string{"1"},
|
||||
AgentConfig: AgentConfig{
|
||||
AgentConfig: agent.AgentConfig{
|
||||
LogLevel: "debug",
|
||||
Port: "7002",
|
||||
AttestedTls: attestedTLS,
|
||||
@@ -115,7 +63,7 @@ func main() {
|
||||
continue
|
||||
}
|
||||
conn.Close()
|
||||
var mes manager.ClientStreamMessage
|
||||
var mes pkgmanager.ClientStreamMessage
|
||||
if err := proto.Unmarshal(b[:n], &mes); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
@@ -123,8 +71,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func SendAgentConfig(cid uint32, ac Computation) error {
|
||||
conn, err := vsock.Dial(cid, VsockConfigPort, nil)
|
||||
func SendAgentConfig(cid uint32, ac agent.Computation) error {
|
||||
conn, err := vsock.Dial(cid, manager.VsockConfigPort, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Algorithm
|
||||
|
||||
Agent accepts binaries programs. To use the python program you need to bundle or compile it.
|
||||
In this example we'll use [pyinstaller](https://pypi.org/project/pyinstaller/)
|
||||
|
||||
```shell
|
||||
pip install -U pyinstaller
|
||||
pyinstaller lin_reg.py
|
||||
```
|
||||
Reference in New Issue
Block a user