mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-08-07 07:14:50 +00:00
NOISSUE - Add test server (#80)
* add test server Signed-off-by: SammyOina <sammyoina@gmail.com> * clean up and update docs Signed-off-by: SammyOina <sammyoina@gmail.com> * update docs Signed-off-by: SammyOina <sammyoina@gmail.com> * fix lint Signed-off-by: SammyOina <sammyoina@gmail.com> --------- Signed-off-by: SammyOina <sammyoina@gmail.com>
This commit is contained in:
committed by
GitHub
parent
6d0100c096
commit
e2fb7ea88d
-58
@@ -1,58 +0,0 @@
|
|||||||
// Copyright (c) Ultraviolet
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
|
||||||
"github.com/ultravioletrs/cocos/manager"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (cli *CLI) NewRunCmd() *cobra.Command {
|
|
||||||
return &cobra.Command{
|
|
||||||
Use: "run",
|
|
||||||
Short: "Upload a computation manifest json",
|
|
||||||
Example: "run '<computation>'",
|
|
||||||
Args: cobra.ExactArgs(1),
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
computationStr := args[0]
|
|
||||||
|
|
||||||
var cmp agent.Computation
|
|
||||||
if err := json.Unmarshal([]byte(computationStr), &cmp); err != nil {
|
|
||||||
log.Fatalf("Error unmarshling computation json: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := manager.ComputationRunReq{
|
|
||||||
Id: cmp.ID,
|
|
||||||
Description: cmp.Description,
|
|
||||||
Name: cmp.Name,
|
|
||||||
ResultConsumers: cmp.ResultConsumers,
|
|
||||||
AgentConfig: &manager.AgentConfig{
|
|
||||||
Port: cmp.AgentConfig.Port,
|
|
||||||
Host: cmp.AgentConfig.Host,
|
|
||||||
CertFile: cmp.AgentConfig.CertFile,
|
|
||||||
KeyFile: cmp.AgentConfig.KeyFile,
|
|
||||||
LogLevel: cmp.AgentConfig.LogLevel,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, data := range cmp.Datasets {
|
|
||||||
req.Datasets = append(req.Datasets, &manager.Dataset{Id: data.ID, Provider: data.Provider})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, algo := range cmp.Algorithms {
|
|
||||||
req.Algorithms = append(req.Algorithms, &manager.Algorithm{Id: algo.ID, Provider: algo.Provider})
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := cli.managerSDK.Run(cmd.Context(), &req)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error running computation: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Successfully run computation, agent address: %v", response)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-6
@@ -4,17 +4,14 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ultravioletrs/cocos/agent"
|
"github.com/ultravioletrs/cocos/agent"
|
||||||
"github.com/ultravioletrs/cocos/manager"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CLI struct {
|
type CLI struct {
|
||||||
agentSDK agent.Service
|
agentSDK agent.Service
|
||||||
managerSDK manager.Service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(agentSDK agent.Service, managerSDK manager.Service) *CLI {
|
func New(agentSDK agent.Service) *CLI {
|
||||||
return &CLI{
|
return &CLI{
|
||||||
agentSDK: agentSDK,
|
agentSDK: agentSDK,
|
||||||
managerSDK: managerSDK,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-89
@@ -6,26 +6,21 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
mglog "github.com/absmach/magistrala/logger"
|
mglog "github.com/absmach/magistrala/logger"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/ultravioletrs/cocos/cli"
|
"github.com/ultravioletrs/cocos/cli"
|
||||||
"github.com/ultravioletrs/cocos/internal/env"
|
"github.com/ultravioletrs/cocos/internal/env"
|
||||||
managersvc "github.com/ultravioletrs/cocos/manager"
|
|
||||||
"github.com/ultravioletrs/cocos/manager/qemu"
|
|
||||||
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
|
||||||
"github.com/ultravioletrs/cocos/pkg/clients/grpc/agent"
|
"github.com/ultravioletrs/cocos/pkg/clients/grpc/agent"
|
||||||
"github.com/ultravioletrs/cocos/pkg/sdk"
|
"github.com/ultravioletrs/cocos/pkg/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
svcName = "cli"
|
svcName = "cli"
|
||||||
envPrefixAgentGRPC = "AGENT_GRPC_"
|
envPrefixAgentGRPC = "AGENT_GRPC_"
|
||||||
envPrefixManagerGRPC = "MANAGER_GRPC_"
|
completion = "completion"
|
||||||
completion = "completion"
|
|
||||||
envPrefixQemu = "MANAGER_QEMU_"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
@@ -56,22 +51,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer agentGRPCClient.Close()
|
defer agentGRPCClient.Close()
|
||||||
|
|
||||||
qemuCfg := qemu.Config{}
|
|
||||||
if err := env.Parse(&qemuCfg, env.Options{Prefix: envPrefixQemu}); err != nil {
|
|
||||||
logger.Error(fmt.Sprintf("failed to load QEMU configuration: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
exe, args, err := qemu.ExecutableAndArgs(qemuCfg)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(fmt.Sprintf("failed to parse QEMU configuration: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logger.Info(fmt.Sprintf("%s %s", exe, strings.Join(args, " ")))
|
|
||||||
|
|
||||||
agentSDK := sdk.NewAgentSDK(logger, agentClient)
|
agentSDK := sdk.NewAgentSDK(logger, agentClient)
|
||||||
managerSDK := managersvc.New(qemuCfg, logger, make(chan *managersvc.ClientStreamMessage))
|
|
||||||
|
|
||||||
cliSVC := cli.New(agentSDK, managerSDK)
|
cliSVC := cli.New(agentSDK)
|
||||||
|
|
||||||
rootCmd := &cobra.Command{
|
rootCmd := &cobra.Command{
|
||||||
Use: "cocos-cli [command]",
|
Use: "cocos-cli [command]",
|
||||||
@@ -101,80 +83,17 @@ func main() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
agentCmd := &cobra.Command{
|
|
||||||
Use: "agent [command]",
|
|
||||||
Short: "CLI application for agent Service API",
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("CLI application for agent Service API\n\n")
|
|
||||||
fmt.Printf("Usage:\n %s [command]\n\n", cmd.CommandPath())
|
|
||||||
fmt.Printf("Available Commands:\n")
|
|
||||||
|
|
||||||
// Filter out "completion" command
|
|
||||||
availableCommands := make([]*cobra.Command, 0)
|
|
||||||
for _, subCmd := range cmd.Commands() {
|
|
||||||
if subCmd.Name() != completion {
|
|
||||||
availableCommands = append(availableCommands, subCmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subCmd := range availableCommands {
|
|
||||||
fmt.Printf(" %-15s%s\n", subCmd.Name(), subCmd.Short)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("\nFlags:\n")
|
|
||||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
fmt.Printf(" -%s, --%s %s\n", flag.Shorthand, flag.Name, flag.Usage)
|
|
||||||
})
|
|
||||||
fmt.Printf("\nUse \"%s [command] --help\" for more information about a command.\n", cmd.CommandPath())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
managerCmd := &cobra.Command{
|
|
||||||
Use: "manager [command]",
|
|
||||||
Short: "CLI application for manager Service API",
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
fmt.Printf("CLI application for manager Service API\n\n")
|
|
||||||
fmt.Printf("Usage:\n %s [command]\n\n", cmd.CommandPath())
|
|
||||||
fmt.Printf("Available Commands:\n")
|
|
||||||
|
|
||||||
// Filter out "completion" command
|
|
||||||
availableCommands := make([]*cobra.Command, 0)
|
|
||||||
for _, subCmd := range cmd.Commands() {
|
|
||||||
if subCmd.Name() != completion {
|
|
||||||
availableCommands = append(availableCommands, subCmd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subCmd := range availableCommands {
|
|
||||||
fmt.Printf(" %-15s%s\n", subCmd.Name(), subCmd.Short)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("\nFlags:\n")
|
|
||||||
cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
|
||||||
fmt.Printf(" -%s, --%s %s\n", flag.Shorthand, flag.Name, flag.Usage)
|
|
||||||
})
|
|
||||||
fmt.Printf("\nUse \"%s [command] --help\" for more information about a command.\n", cmd.CommandPath())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Root Commands
|
|
||||||
rootCmd.AddCommand(agentCmd)
|
|
||||||
rootCmd.AddCommand(managerCmd)
|
|
||||||
|
|
||||||
// Agent Commands
|
// Agent Commands
|
||||||
agentCmd.AddCommand(cliSVC.NewAlgorithmsCmd())
|
rootCmd.AddCommand(cliSVC.NewAlgorithmsCmd())
|
||||||
agentCmd.AddCommand(cliSVC.NewDatasetsCmd())
|
rootCmd.AddCommand(cliSVC.NewDatasetsCmd())
|
||||||
agentCmd.AddCommand(cliSVC.NewResultsCmd())
|
rootCmd.AddCommand(cliSVC.NewResultsCmd())
|
||||||
attestaionCmd := cliSVC.NewAttestationCmd()
|
attestaionCmd := cliSVC.NewAttestationCmd()
|
||||||
agentCmd.AddCommand(attestaionCmd)
|
rootCmd.AddCommand(attestaionCmd)
|
||||||
|
|
||||||
// Attestation commands
|
// Attestation commands
|
||||||
attestaionCmd.AddCommand(cliSVC.NewGetAttestationCmd())
|
attestaionCmd.AddCommand(cliSVC.NewGetAttestationCmd())
|
||||||
attestaionCmd.AddCommand(cliSVC.NewValidateAttestationValidationCmd())
|
attestaionCmd.AddCommand(cliSVC.NewValidateAttestationValidationCmd())
|
||||||
|
|
||||||
// Manager commands
|
|
||||||
managerCmd.AddCommand(cliSVC.NewRunCmd())
|
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
logger.Error(fmt.Sprintf("Command execution failed: %s", err))
|
logger.Error(fmt.Sprintf("Command execution failed: %s", err))
|
||||||
return
|
return
|
||||||
|
|||||||
+3
-5
@@ -28,11 +28,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
svcName = "manager"
|
svcName = "manager"
|
||||||
envPrefixGRPC = "MANAGER_GRPC_"
|
envPrefixGRPC = "MANAGER_GRPC_"
|
||||||
envPrefixQemu = "MANAGER_QEMU_"
|
envPrefixQemu = "MANAGER_QEMU_"
|
||||||
defSvcGRPCPort = "7001"
|
|
||||||
defSvcHTTPPort = "9021"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
|
|||||||
+3
-11
@@ -135,7 +135,7 @@ NB: we set environment variables that we will use in the shell process where we
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
To start the service outside of the container, execute the following shell script:
|
To start the service, execute the following shell script (note a server needs to be running see [here](../test/manager-server/README.md)):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# download the latest version of the service
|
# download the latest version of the service
|
||||||
@@ -150,6 +150,7 @@ make manager
|
|||||||
make install
|
make install
|
||||||
|
|
||||||
# set the environment variables and run the service
|
# set the environment variables and run the service
|
||||||
|
MANAGER_GRPC_URL=localhost:7001
|
||||||
MANAGER_LOG_LEVEL=debug \
|
MANAGER_LOG_LEVEL=debug \
|
||||||
MANAGER_QEMU_USE_SUDO=false \
|
MANAGER_QEMU_USE_SUDO=false \
|
||||||
MANAGER_QEMU_ENABLE_SEV=false \
|
MANAGER_QEMU_ENABLE_SEV=false \
|
||||||
@@ -159,6 +160,7 @@ MANAGER_QEMU_ENABLE_SEV=false \
|
|||||||
To enable [AMD SEV](https://www.amd.com/en/developer/sev.html) support, start manager like this
|
To enable [AMD SEV](https://www.amd.com/en/developer/sev.html) support, start manager like this
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
MANAGER_GRPC_URL=localhost:7001
|
||||||
MANAGER_LOG_LEVEL=debug \
|
MANAGER_LOG_LEVEL=debug \
|
||||||
MANAGER_QEMU_USE_SUDO=true \
|
MANAGER_QEMU_USE_SUDO=true \
|
||||||
MANAGER_QEMU_ENABLE_SEV=true \
|
MANAGER_QEMU_ENABLE_SEV=true \
|
||||||
@@ -166,16 +168,6 @@ MANAGER_QEMU_SEV_CBITPOS=51 \
|
|||||||
./build/cocos-manager
|
./build/cocos-manager
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create QEMU virtual machine (VM)
|
|
||||||
|
|
||||||
To create an instance of VM and run a computation, run
|
|
||||||
|
|
||||||
```sh
|
|
||||||
go run cmd/cli/main.go manager run '{"id":"123","name":"Sample Computation","description":"A sample computation","status":"Processing","owner":"John Doe","start_time":"2023-11-03T12:03:21.705171284+03:00","end_time":"2023-11-03T13:03:21.705171532+03:00","datasets":[{"provider":"Provider1","id":"Dataset1"},{"provider":"Provider2","id":"Dataset2"}],"algorithms":[{"provider":"AlgorithmProvider1","id":"Algorithm1"}],"result_consumers":["Consumer1","Consumer2"], "agent_config": {"port":"7002"}}'
|
|
||||||
```
|
|
||||||
|
|
||||||
You should be able to create multiple instances by reruning the command.
|
|
||||||
|
|
||||||
### Verifying VM launch
|
### Verifying VM launch
|
||||||
|
|
||||||
NB: To verify that the manager successfully launched the VM, you need to open two terminals on the same machine. In one terminal, you need to launch `go run main.go` (with the environment variables of choice) and in the other, you can run the verification commands.
|
NB: To verify that the manager successfully launched the VM, you need to open two terminals on the same machine. In one terminal, you need to launch `go run main.go` (with the environment variables of choice) and in the other, you can run the verification commands.
|
||||||
|
|||||||
+23
-28
@@ -3,49 +3,44 @@
|
|||||||
package grpc
|
package grpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/ultravioletrs/cocos/manager"
|
"github.com/ultravioletrs/cocos/manager"
|
||||||
"golang.org/x/sync/errgroup"
|
"google.golang.org/grpc/peer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type grpcServer struct {
|
type grpcServer struct {
|
||||||
manager.UnimplementedManagerServiceServer
|
manager.UnimplementedManagerServiceServer
|
||||||
incoming chan *manager.ClientStreamMessage
|
incoming chan *manager.ClientStreamMessage
|
||||||
responses chan *manager.ComputationRunReq
|
svc Service
|
||||||
ctx context.Context
|
}
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
Run(ipAddress string) manager.ComputationRunReq
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServer returns new AuthServiceServer instance.
|
// NewServer returns new AuthServiceServer instance.
|
||||||
func NewServer(ctx context.Context, incoming chan *manager.ClientStreamMessage, responses chan *manager.ComputationRunReq) manager.ManagerServiceServer {
|
func NewServer(incoming chan *manager.ClientStreamMessage, svc Service) manager.ManagerServiceServer {
|
||||||
return &grpcServer{
|
return &grpcServer{
|
||||||
incoming: incoming,
|
incoming: incoming,
|
||||||
responses: responses,
|
svc: svc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *grpcServer) Process(stream manager.ManagerService_ProcessServer) error {
|
func (s *grpcServer) Process(stream manager.ManagerService_ProcessServer) error {
|
||||||
eg, _ := errgroup.WithContext(s.ctx)
|
for {
|
||||||
|
req, err := stream.Recv()
|
||||||
eg.Go(func() error {
|
if err != nil {
|
||||||
for {
|
return err
|
||||||
req, err := stream.Recv()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.incoming <- req
|
|
||||||
}
|
}
|
||||||
})
|
if _, ok := req.Message.(*manager.ClientStreamMessage_Whoami); ok {
|
||||||
|
client, ok := peer.FromContext(stream.Context())
|
||||||
eg.Go(func() error {
|
if ok {
|
||||||
for resp := range s.responses {
|
req := s.svc.Run(client.Addr.String())
|
||||||
if err := stream.Send(resp); err != nil {
|
if err := stream.Send(&req); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return eg.Wait()
|
s.incoming <- req
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-19
@@ -585,7 +585,6 @@ type AgentConfig struct {
|
|||||||
ClientCaFile string `protobuf:"bytes,5,opt,name=client_ca_file,json=clientCaFile,proto3" json:"client_ca_file,omitempty"`
|
ClientCaFile string `protobuf:"bytes,5,opt,name=client_ca_file,json=clientCaFile,proto3" json:"client_ca_file,omitempty"`
|
||||||
ServerCaFile string `protobuf:"bytes,6,opt,name=server_ca_file,json=serverCaFile,proto3" json:"server_ca_file,omitempty"`
|
ServerCaFile string `protobuf:"bytes,6,opt,name=server_ca_file,json=serverCaFile,proto3" json:"server_ca_file,omitempty"`
|
||||||
LogLevel string `protobuf:"bytes,7,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"`
|
LogLevel string `protobuf:"bytes,7,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"`
|
||||||
InstanceId string `protobuf:"bytes,8,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AgentConfig) Reset() {
|
func (x *AgentConfig) Reset() {
|
||||||
@@ -669,13 +668,6 @@ func (x *AgentConfig) GetLogLevel() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AgentConfig) GetInstanceId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.InstanceId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_manager_manager_proto protoreflect.FileDescriptor
|
var File_manager_manager_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_manager_manager_proto_rawDesc = []byte{
|
var file_manager_manager_proto_rawDesc = []byte{
|
||||||
@@ -748,7 +740,7 @@ var file_manager_manager_proto_rawDesc = []byte{
|
|||||||
0x69, 0x74, 0x68, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
0x69, 0x74, 0x68, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
||||||
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
|
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
|
||||||
0x22, 0xf7, 0x01, 0x0a, 0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
0x22, 0xd6, 0x01, 0x0a, 0x0b, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
|
||||||
0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01,
|
0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74,
|
0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x65, 0x72, 0x74,
|
||||||
@@ -761,16 +753,14 @@ var file_manager_manager_proto_rawDesc = []byte{
|
|||||||
0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
0x5f, 0x63, 0x61, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||||
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09,
|
0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x61, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1b, 0x0a, 0x09,
|
||||||
0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73,
|
0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x32, 0x5b, 0x0a, 0x0e, 0x4d, 0x61, 0x6e,
|
||||||
0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
|
0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x07, 0x50,
|
||||||
0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x32, 0x5b, 0x0a, 0x0e, 0x4d, 0x61,
|
0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
|
||||||
0x6e, 0x61, 0x67, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x07,
|
0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65, 0x73,
|
||||||
0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43,
|
||||||
0x72, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x65,
|
0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65, 0x71,
|
||||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e,
|
0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x6d, 0x61, 0x6e, 0x61,
|
||||||
0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x75, 0x6e, 0x52, 0x65,
|
0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x71, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x6d, 0x61, 0x6e,
|
|
||||||
0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -72,5 +72,4 @@ message AgentConfig {
|
|||||||
string client_ca_file = 5;
|
string client_ca_file = 5;
|
||||||
string server_ca_file = 6;
|
string server_ca_file = 6;
|
||||||
string log_level = 7;
|
string log_level = 7;
|
||||||
string instance_id = 8;
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Manager test server
|
||||||
|
Manager service is a grpc client. It connects to a server and sends a whoAmIRequest.
|
||||||
|
The server then responds with a run computation request. Once manager service receives the computation request it will launch an agent service in a virtual machine and pass the computation manifest. Agent will then pass logs and events to manager which are forwarded to the server. `main.go` is a sample of how such a server would be implemented. This is a very simple example for testing purposes.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The service is configured using the environment variables from the following table. Note that any unset variables will be replaced with their default values.
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
| ---------------- | ---------------------------------------- | ------- |
|
||||||
|
| HOST | Manager service gRPC host | |
|
||||||
|
| PORT | Manager service gRPC port | 7001 |
|
||||||
|
| SERVER_CERT | Path to server certificate in pem format | |
|
||||||
|
| SERVER_KEY | Path to server key in pem format | |
|
||||||
|
|
||||||
|
## Running
|
||||||
|
```shell
|
||||||
|
go run main.go
|
||||||
|
```
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// Copyright (c) Ultraviolet
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
mglog "github.com/absmach/magistrala/logger"
|
||||||
|
"github.com/ultravioletrs/cocos/internal/env"
|
||||||
|
"github.com/ultravioletrs/cocos/internal/server"
|
||||||
|
grpcserver "github.com/ultravioletrs/cocos/internal/server/grpc"
|
||||||
|
"github.com/ultravioletrs/cocos/manager"
|
||||||
|
managergrpc "github.com/ultravioletrs/cocos/manager/api/grpc"
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/reflection"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
svcName = "manager_test_server"
|
||||||
|
defaultPort = "7001"
|
||||||
|
)
|
||||||
|
|
||||||
|
type svc struct {
|
||||||
|
logger *slog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *svc) Run(ipAdress string) manager.ComputationRunReq {
|
||||||
|
s.logger.Debug(fmt.Sprintf("received who am on ip address %s", ipAdress))
|
||||||
|
return manager.ComputationRunReq{
|
||||||
|
Id: "1",
|
||||||
|
Name: "sample computation",
|
||||||
|
Description: "sample descrption",
|
||||||
|
Datasets: []*manager.Dataset{{Id: "1", Provider: "provider1"}},
|
||||||
|
Algorithms: []*manager.Algorithm{{Id: "1", Provider: "provider1"}},
|
||||||
|
ResultConsumers: []string{"consumer1"},
|
||||||
|
AgentConfig: &manager.AgentConfig{
|
||||||
|
Port: "7002",
|
||||||
|
LogLevel: "debug",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
g, ctx := errgroup.WithContext(ctx)
|
||||||
|
incomingChan := make(chan *manager.ClientStreamMessage)
|
||||||
|
|
||||||
|
logger, err := mglog.New(os.Stdout, "debug")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for incoming := range incomingChan {
|
||||||
|
switch incoming.Message.(type) {
|
||||||
|
case *manager.ClientStreamMessage_Whoami:
|
||||||
|
fmt.Println("received whoamI")
|
||||||
|
case *manager.ClientStreamMessage_RunRes:
|
||||||
|
fmt.Println("received runRes")
|
||||||
|
case *manager.ClientStreamMessage_AgentEvent:
|
||||||
|
fmt.Println("received agent event")
|
||||||
|
case *manager.ClientStreamMessage_AgentLog:
|
||||||
|
fmt.Println("received agent log")
|
||||||
|
}
|
||||||
|
fmt.Println(incoming.Message)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
registerAgentServiceServer := func(srv *grpc.Server) {
|
||||||
|
reflection.Register(srv)
|
||||||
|
manager.RegisterManagerServiceServer(srv, managergrpc.NewServer(incomingChan, &svc{logger: logger}))
|
||||||
|
}
|
||||||
|
grpcServerConfig := server.Config{Port: defaultPort}
|
||||||
|
if err := env.Parse(&grpcServerConfig, env.Options{}); err != nil {
|
||||||
|
logger.Error(fmt.Sprintf("failed to load %s gRPC client configuration : %s", svcName, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger)
|
||||||
|
|
||||||
|
g.Go(func() error {
|
||||||
|
return gs.Start()
|
||||||
|
})
|
||||||
|
|
||||||
|
g.Go(func() error {
|
||||||
|
return server.StopHandler(ctx, cancel, logger, svcName, gs)
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := g.Wait(); err != nil {
|
||||||
|
logger.Error(fmt.Sprintf("%s service terminated: %s", svcName, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
-14
@@ -16,11 +16,7 @@ pip3 install pandas scikit-learn
|
|||||||
|
|
||||||
### Agent-CLI interaction
|
### Agent-CLI interaction
|
||||||
|
|
||||||
In the VM, open a console and start `agent`:
|
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)
|
||||||
|
|
||||||
```sh
|
|
||||||
AGENT_LOG_LEVEL=info AGENT_GRPC_URL=10.0.2.15:7002 go run cmd/agent/main.go
|
|
||||||
```
|
|
||||||
|
|
||||||
Open console on the host, and run
|
Open console on the host, and run
|
||||||
|
|
||||||
@@ -28,26 +24,23 @@ Open console on the host, and run
|
|||||||
export AGENT_GRPC_URL=localhost:7002
|
export AGENT_GRPC_URL=localhost:7002
|
||||||
export MANAGER_GRPC_URL=localhost:7001
|
export MANAGER_GRPC_URL=localhost:7001
|
||||||
|
|
||||||
# Run CLI to provide manifest
|
|
||||||
go run cmd/cli/main.go run '{"id":"123","name":"Sample Computation","description":"A sample computation","status":"Processing","owner":"John Doe","start_time":"2023-11-03T12:03:21.705171284+03:00","end_time":"2023-11-03T13:03:21.705171532+03:00","datasets":[{"provider":"Provider1","id":"Dataset1"},{"provider":"Provider2","id":"Dataset2"}],"algorithms":[{"provider":"AlgorithmProvider1","id":"Algorithm1"}],"result_consumers":["Consumer1","Consumer2"],"ttl":3600,"metadata":{"key1":"value1","key2":42}, "timeout": "2m"}'
|
|
||||||
|
|
||||||
# Retieve Attestation
|
# Retieve Attestation
|
||||||
go run cmd/cli/main.go agent attestation get '<report_data>'
|
go run cmd/cli/main.go attestation get '<report_data>'
|
||||||
|
|
||||||
# Validate Attestation
|
# Validate Attestation
|
||||||
go run cmd/cli/main.go agent attestation validate '<attesation>' '<report_data>'
|
go run cmd/cli/main.go attestation validate '<attesation>' '<report_data>'
|
||||||
|
|
||||||
# Run the CLI program with algorithm input
|
# Run the CLI program with algorithm input
|
||||||
go run cmd/cli/main.go agent algo test/manual/algo/lin_reg.py Algorithm1 AlgorithmProvider1
|
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
|
# 2023/09/21 10:43:53 Uploading algorithm binary: test/manual/algo/lin_reg.py
|
||||||
|
|
||||||
# Run the CLI program with dataset input
|
# Run the CLI program with dataset input
|
||||||
go run cmd/cli/main.go agent data test/manual/data/iris.csv Dataset1 Provider1
|
go run cmd/cli/main.go data test/manual/data/iris.csv Dataset1 Provider1
|
||||||
go run cmd/cli/main.go agent data test/manual/data/iris.csv Dataset2 Provider2
|
go run cmd/cli/main.go data test/manual/data/iris.csv Dataset2 Provider2
|
||||||
# 2023/09/21 10:45:25 Uploading dataset CSV: test/manual/data/iris.csv
|
# 2023/09/21 10:45:25 Uploading dataset CSV: test/manual/data/iris.csv
|
||||||
|
|
||||||
# Run the CLI program to fetch computation result
|
# Run the CLI program to fetch computation result
|
||||||
go run cmd/cli/main.go agent result Consumer1
|
go run cmd/cli/main.go result Consumer1
|
||||||
# 2023/09/21 10:45:39 Retrieving computation result file
|
# 2023/09/21 10:45:39 Retrieving computation result file
|
||||||
# 2023/09/21 10:45:40 Computation result retrieved and saved successfully!
|
# 2023/09/21 10:45:40 Computation result retrieved and saved successfully!
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// Copyright (c) Ultraviolet
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Simplified script to pass configs to agent without manager and read logs and events for manager.
|
||||||
|
// This tool is meant for testing purposes.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/mdlayher/vsock"
|
||||||
|
)
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
l, err := vsock.Listen(9997, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
l2, err := vsock.Listen(9998, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
ac := Computation{
|
||||||
|
ID: "123",
|
||||||
|
Datasets: Datasets{Dataset{ID: "1", Provider: "pr1"}},
|
||||||
|
Algorithms: Algorithms{Algorithm{ID: "1", Provider: "pr1"}},
|
||||||
|
ResultConsumers: []string{"1"},
|
||||||
|
AgentConfig: AgentConfig{
|
||||||
|
LogLevel: "debug",
|
||||||
|
Port: "7002",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fmt.Println(SendAgentConfig(3, ac))
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b := make([]byte, 1024)
|
||||||
|
n, err := conn.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
fmt.Println(string(b[:n]))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
for {
|
||||||
|
conn, err := l2.Accept()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b := make([]byte, 1024)
|
||||||
|
n, err := conn.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn.Close()
|
||||||
|
fmt.Println(string(b[:n]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendAgentConfig(cid uint32, ac Computation) error {
|
||||||
|
conn, err := vsock.Dial(cid, VsockConfigPort, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
payload, err := json.Marshal(ac)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := conn.Write(payload); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user