manager

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2024 License: Apache-2.0 Imports: 17 Imported by: 0

README

Manager

Manager service provides a barebones HTTP and gRPC API and Service interface implementation for the development of the manager service.

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
MANAGER_LOG_LEVEL Log level for manager service (debug, info, warn, error) info
MANAGER_HTTP_HOST Manager service HTTP host
MANAGER_HTTP_PORT Manager service HTTP port 9021
MANAGER_HTTP_SERVER_CERT Path to server certificate in pem format
MANAGER_HTTP_SERVER_KEY Path to server key in pem format
MANAGER_GRPC_HOST Manager service gRPC host
MANAGER_GRPC_PORT Manager service gRPC port 7001
MANAGER_GRPC_SERVER_CERT Path to server certificate in pem format
MANAGER_GRPC_SERVER_KEY Path to server key in pem format
COCOS_JAEGER_URL Jaeger server URL http://localhost:14268/api/traces
MANAGER_INSTANCE_ID Manager service instance ID
COCOS_NOTIFICATION_SERVER_URL Server to receive notification events from agent. http:/localhost:9000
MANAGER_HOST_IP Mnagaer host IP address localhost

Setup

git clone https://github.com/ultravioletrs/cocos
cd cocos

NB: all relative paths in this document are relative to cocos repository directory.

QEMU-KVM

QEMU-KVM is a virtualization platform that allows you to run multiple operating systems on the same physical machine. It is a combination of two technologies: QEMU and KVM.

  • QEMU is an emulator that can run a variety of operating systems, including Linux, Windows, and macOS.
  • KVM is a Linux kernel module that allows QEMU to run virtual machines.

To install QEMU-KVM on a Debian based machine, run

sudo apt update
sudo apt install qemu-kvm

Create img directory in cmd/manager. Create tmp directory in cmd/manager.

Prepare Cocos HAL

Cocos HAL for Linux is framework for building custom in-enclave Linux distribution. Use the instructions in Readme. Once the image is built copy the kernel and rootfs image to cmd/manager/img from buildroot/output/images/bzImage and buildroot/output/images/rootfs.cpio.gz respectively.

Test VM creation
cd cmd/manager

sudo find / -name OVMF_CODE.fd
# => /usr/share/OVMF/OVMF_CODE.fd
OVMF_CODE=/usr/share/OVMF/OVMF_CODE.fd

sudo find / -name OVMF_VARS.fd
# => /usr/share/OVMF/OVMF_VARS.fd
OVMF_VARS=/usr/share/OVMF/OVMF_VARS.fd

KERNEL="img/bzImage"
INITRD="img/rootfs.cpio.gz"

qemu-system-x86_64 \
    -enable-kvm \
    -cpu EPYC-v4 \
    -machine q35 \
    -smp 4 \
    -m 2048M,slots=5,maxmem=10240M \
    -no-reboot \
    -drive if=pflash,format=raw,unit=0,file=$OVMF_CODE,readonly=on \
    -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 \
    -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= \
    -kernel $KERNEL \
    -append "earlyprintk=serial console=ttyS0 computation={\"id\":\"c0d15c5e-e37d-4426-b3b7-b432c966fb09\",\"name\":\"Sample_Computation\",\"description\":\"A_sample_computation\",\"datasets\":[{\"provider\":\"Provider1\",\"id\":\"Dataset1\"},{\"provider\":\"Provider2\",\"id\":\"Dataset2\"}],\"algorithms\":[{\"provider\":\"AlgorithmProvider1\",\"id\":\"Algorithm1\"}],\"result_consumers\":[\"Consumer1\"], \"timeout\":\"10m\"}" \
    -initrd $INITRD \
    -nographic \
    -monitor pty \
    -monitor unix:monitor,server,nowait

Once the VM is booted press enter and on the login use username root.

Build and run Agent
# Start the 'agent' executable in the background using '&' at the end.
cocos-agent &

# List running processes and use 'grep' to filter for processes containing 'agent' in their names.
ps aux | grep cocos-agent
# This command helps verify that the 'agent' process is running.
# The output shows the process ID (PID), resource usage, and other information about the 'cocos-agent' process.
# For example: 118 root     cocos-agent

We can also check if Agent is reachable from the host machine:

# Use netcat (nc) to test the connection to localhost on port 9301.
nc -zv localhost 9301
# Output:
# nc: connect to localhost (::1) port 9301 (tcp) failed: Connection refused
# Connection to localhost (127.0.0.1) 9301 port [tcp/*] succeeded!

# Use netcat (nc) to test the connection to localhost on port 7020.
nc -zv localhost 7020
# Output:
# nc: connect to localhost (::1) port 7020 (tcp) failed: Connection refused
# Connection to localhost (127.0.0.1) 7020 port [tcp/*] succeeded!
Conclusion

Now you are able to use Manager with Agent. Namely, Manager will create a VM with a separate OVMF variables file on manager /run request.

OVMF

We need Open Virtual Machine Firmware. OVMF is a port of Intel's tianocore firmware - an open source implementation of the Unified Extensible Firmware Interface (UEFI) - used by a qemu virtual machine. We need OVMF in order to run virtual machine with focal-server-cloudimg-amd64. When we install QEMU, we get two files that we need to start a VM: OVMF_VARS.fd and OVMF_CODE.fd. We will make a local copy of OVMF_VARS.fd since a VM will modify this file. On the other hand, OVMF_CODE.fd is only used as a reference, so we only record its path in an environment variable.

sudo find / -name OVMF_CODE.fd
# => /usr/share/OVMF/OVMF_CODE.fd
MANAGER_QEMU_OVMF_CODE_FILE=/usr/share/OVMF/OVMF_CODE.fd

sudo find / -name OVMF_VARS.fd
# => /usr/share/OVMF/OVMF_VARS.fd
MANAGER_QEMU_OVMF_VARS_FILE=/usr/share/OVMF/OVMF_VARS.fd

NB: we set environment variables that we will use in the shell process where we run manager.

Deployment

Standalone

To start the service outside of the container, execute the following shell script:

# download the latest version of the service
go get github.com/ultravioletrs/cocos

cd $GOPATH/src/github.com/ultravioletrs/cocos

# compile the manager
make manager

# copy binary to bin
make install

# set the environment variables and run the service
MANAGER_LOG_LEVEL=debug \
MANAGER_QEMU_USE_SUDO=false \
MANAGER_QEMU_ENABLE_SEV=false \
./build/cocos-manager

To enable AMD SEV support, start manager like this

MANAGER_LOG_LEVEL=debug \
MANAGER_QEMU_USE_SUDO=true \
MANAGER_QEMU_ENABLE_SEV=true \
MANAGER_QEMU_SEV_CBITPOS=51 \
./build/cocos-manager
Docker
go get github.com/ultravioletrs/cocos

cd $GOPATH/src/github.com/ultravioletrs/cocos

# compile the manager
make manager

# create manager docker image
make docker_dev_manager

# start docker composition
make run
Create QEMU virtual machine (VM)

To create an instance of VM and run a computation, run

curl -sSi -X POST \
  http://localhost:9021/run \
  -H "Content-Type: application/json" \
  -d '{
    "computation": {
   "id":"c0d15c5e-e37d-4426-b3b7-b432c966fb09",
   "name":"Sample_Computation",
   "description":"A_sample_computation",
   "datasets":[
      {
         "provider":"Provider1",
         "id":"Dataset1"
      },
      {
         "provider":"Provider2",
         "id":"Dataset2"
      }
   ],
   "algorithms":[
      {
         "provider":"AlgorithmProvider1",
         "id":"Algorithm1"
      }
   ],
   "result_consumers":[
      "Consumer1"
   ],
   "timeout":"10m"
  }
}'

You should be able to create multiple instances by reruning the command.

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.

To verify that the manager launched the VM successfully, run the following command:

ps aux | grep qemu-system-x86_64

You should get something similar to this

darko     324763 95.3  6.0 6398136 981044 ?      Sl   16:17   0:15 /usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 4096M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty

If you run a command as sudo, you should get the output similar to this one

root       37982  0.0  0.0   9444  4572 pts/0    S+   16:18   0:00 sudo /usr/local/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 4096M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 -machine memory-encryption=sev0 -nographic -monitor pty
root       37989  122 13.1 5345816 4252312 pts/0 Sl+  16:19   0:04 /usr/local/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 4096M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -object sev-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 -machine memory-encryption=sev0 -nographic -monitor pty

The two processes are due to the fact that we run the command /usr/bin/qemu-system-x86_64 as sudo, so there is one process for sudo command and the other for /usr/bin/qemu-system-x86_64.

Troubleshooting

If the ps aux | grep qemu-system-x86_64 give you something like this

darko      13913  0.0  0.0      0     0 pts/2    Z+   20:17   0:00 [qemu-system-x86] <defunct>

means that the a QEMU virtual machine that is currently defunct, meaning that it is no longer running. More precisely, the defunct process in the output is also known as a "zombie" process.

You can troubleshoot the VM launch procedure by running directly qemu-system-x86_64 command. When you run manager with MANAGER_LOG_LEVEL=info env var set, it prints out the entire command used to launch a VM. The relevant part of the log might look like this

{"level":"info","message":"/usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 4096M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty","ts":"2023-08-14T18:29:19.2653908Z"}

You can run the command - the value of the "message" key - directly in the terminal:

/usr/bin/qemu-system-x86_64 -enable-kvm -machine q35 -cpu EPYC -smp 4,maxcpus=64 -m 4096M,slots=5,maxmem=30G -drive if=pflash,format=raw,unit=0,file=/usr/share/OVMF/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=img/OVMF_VARS.fd -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true -drive file=img/focal-server-cloudimg-amd64.img,if=none,id=disk0,format=qcow2 -device scsi-hd,drive=disk0 -netdev user,id=vmnic,hostfwd=tcp::2222-:22,hostfwd=tcp::9301-:9031,hostfwd=tcp::7020-:7002 -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= -nographic -monitor pty

and look for the possible problems. This problems can usually be solved by using the adequate env var assignments. Look in the manager/qemu/config.go file to see the recognized env vars. Don't forget to prepend MANAGER_QEMU_ to the name of the env vars.

Kill qemu-system-x86_64 processes

To kill any leftover qemu-system-x86_64 processes, use

pkill -f qemu-system-x86_64

The pkill command is used to kill processes by name or by pattern. The -f flag to specify that we want to kill processes that match the pattern qemu-system-x86_64. It sends the SIGKILL signal to all processes that are running qemu-system-x86_64.

If this does not work, i.e. if ps aux | grep qemu-system-x86_64 still outputs qemu-system-x86_64 related process(es), you can kill the unwanted process with kill -9 <PID>, which also sends a SIGKILL signal to the process.

Usage

For more information about service capabilities and its usage, please check out the README documentation.

Documentation

Overview

Copyright (c) Ultraviolet SPDX-License-Identifier: Apache-2.0

Index

Constants

View Source
const (
	ManagerService_Run_FullMethodName = "/manager.ManagerService/Run"
)

Variables

View Source
var (
	// ErrMalformedEntity indicates malformed entity specification (e.g.
	// invalid username or password).
	ErrMalformedEntity = errors.New("malformed entity specification")

	// ErrUnauthorizedAccess indicates missing or invalid credentials provided
	// when accessing a protected resource.
	ErrUnauthorizedAccess = errors.New("missing or invalid credentials provided")

	// ErrNotFound indicates a non-existent entity request.
	ErrNotFound = errors.New("entity not found")

	// ErrFailedToAllocatePort indicates no free port was found on host.
	ErrFailedToAllocatePort = errors.New("failed to allocate free port on host")
)
View Source
var File_manager_manager_proto protoreflect.FileDescriptor
View Source
var ManagerService_ServiceDesc = grpc.ServiceDesc{
	ServiceName: "manager.ManagerService",
	HandlerType: (*ManagerServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "Run",
			Handler:    _ManagerService_Run_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "manager/manager.proto",
}

ManagerService_ServiceDesc is the grpc.ServiceDesc for ManagerService service. It's only intended for direct use with grpc.RegisterService, and not to be introspected or modified (even as a copy)

Functions

func RegisterManagerServiceServer

func RegisterManagerServiceServer(s grpc.ServiceRegistrar, srv ManagerServiceServer)

Types

type Algorithm

type Algorithm struct {
	Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
	Id       string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
	// contains filtered or unexported fields
}

func (*Algorithm) Descriptor deprecated

func (*Algorithm) Descriptor() ([]byte, []int)

Deprecated: Use Algorithm.ProtoReflect.Descriptor instead.

func (*Algorithm) GetId

func (x *Algorithm) GetId() string

func (*Algorithm) GetProvider

func (x *Algorithm) GetProvider() string

func (*Algorithm) ProtoMessage

func (*Algorithm) ProtoMessage()

func (*Algorithm) ProtoReflect

func (x *Algorithm) ProtoReflect() protoreflect.Message

func (*Algorithm) Reset

func (x *Algorithm) Reset()

func (*Algorithm) String

func (x *Algorithm) String() string

type Computation

type Computation struct {
	Id              string       `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
	Name            string       `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
	Description     string       `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
	Datasets        []*Dataset   `protobuf:"bytes,4,rep,name=datasets,proto3" json:"datasets,omitempty"`
	Algorithms      []*Algorithm `protobuf:"bytes,5,rep,name=algorithms,proto3" json:"algorithms,omitempty"`
	ResultConsumers []string     `protobuf:"bytes,6,rep,name=result_consumers,json=resultConsumers,proto3" json:"result_consumers,omitempty"`
	// contains filtered or unexported fields
}

func (*Computation) Descriptor deprecated

func (*Computation) Descriptor() ([]byte, []int)

Deprecated: Use Computation.ProtoReflect.Descriptor instead.

func (*Computation) GetAlgorithms

func (x *Computation) GetAlgorithms() []*Algorithm

func (*Computation) GetDatasets

func (x *Computation) GetDatasets() []*Dataset

func (*Computation) GetDescription

func (x *Computation) GetDescription() string

func (*Computation) GetId

func (x *Computation) GetId() string

func (*Computation) GetName

func (x *Computation) GetName() string

func (*Computation) GetResultConsumers

func (x *Computation) GetResultConsumers() []string

func (*Computation) ProtoMessage

func (*Computation) ProtoMessage()

func (*Computation) ProtoReflect

func (x *Computation) ProtoReflect() protoreflect.Message

func (*Computation) Reset

func (x *Computation) Reset()

func (*Computation) String

func (x *Computation) String() string

type Dataset

type Dataset struct {
	Provider string `protobuf:"bytes,1,opt,name=provider,proto3" json:"provider,omitempty"`
	Id       string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
	// contains filtered or unexported fields
}

func (*Dataset) Descriptor deprecated

func (*Dataset) Descriptor() ([]byte, []int)

Deprecated: Use Dataset.ProtoReflect.Descriptor instead.

func (*Dataset) GetId

func (x *Dataset) GetId() string

func (*Dataset) GetProvider

func (x *Dataset) GetProvider() string

func (*Dataset) ProtoMessage

func (*Dataset) ProtoMessage()

func (*Dataset) ProtoReflect

func (x *Dataset) ProtoReflect() protoreflect.Message

func (*Dataset) Reset

func (x *Dataset) Reset()

func (*Dataset) String

func (x *Dataset) String() string

type ManagerServiceClient

type ManagerServiceClient interface {
	Run(ctx context.Context, in *RunRequest, opts ...grpc.CallOption) (*RunResponse, error)
}

ManagerServiceClient is the client API for ManagerService service.

For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.

type ManagerServiceServer

type ManagerServiceServer interface {
	Run(context.Context, *RunRequest) (*RunResponse, error)
	// contains filtered or unexported methods
}

ManagerServiceServer is the server API for ManagerService service. All implementations must embed UnimplementedManagerServiceServer for forward compatibility

type RunRequest

type RunRequest struct {
	Computation *Computation `protobuf:"bytes,1,opt,name=computation,proto3" json:"computation,omitempty"`
	// contains filtered or unexported fields
}

func (*RunRequest) Descriptor deprecated

func (*RunRequest) Descriptor() ([]byte, []int)

Deprecated: Use RunRequest.ProtoReflect.Descriptor instead.

func (*RunRequest) GetComputation

func (x *RunRequest) GetComputation() *Computation

func (*RunRequest) ProtoMessage

func (*RunRequest) ProtoMessage()

func (*RunRequest) ProtoReflect

func (x *RunRequest) ProtoReflect() protoreflect.Message

func (*RunRequest) Reset

func (x *RunRequest) Reset()

func (*RunRequest) String

func (x *RunRequest) String() string

type RunResponse

type RunResponse struct {
	AgentAddress string `protobuf:"bytes,1,opt,name=agent_address,json=agentAddress,proto3" json:"agent_address,omitempty"`
	// contains filtered or unexported fields
}

func (*RunResponse) Descriptor deprecated

func (*RunResponse) Descriptor() ([]byte, []int)

Deprecated: Use RunResponse.ProtoReflect.Descriptor instead.

func (*RunResponse) GetAgentAddress

func (x *RunResponse) GetAgentAddress() string

func (*RunResponse) ProtoMessage

func (*RunResponse) ProtoMessage()

func (*RunResponse) ProtoReflect

func (x *RunResponse) ProtoReflect() protoreflect.Message

func (*RunResponse) Reset

func (x *RunResponse) Reset()

func (*RunResponse) String

func (x *RunResponse) String() string

type Service

type Service interface {
	Run(ctx context.Context, c *Computation) (string, error)
}

Service specifies an API that must be fulfilled by the domain service implementation, and all of its decorators (e.g. logging & metrics).

func New

func New(qemuCfg qemu.Config, logger mglog.Logger, eventSvc events.Service, hostIP string) Service

New instantiates the manager service implementation.

type UnimplementedManagerServiceServer

type UnimplementedManagerServiceServer struct {
}

UnimplementedManagerServiceServer must be embedded to have forward compatible implementations.

func (UnimplementedManagerServiceServer) Run

type UnsafeManagerServiceServer

type UnsafeManagerServiceServer interface {
	// contains filtered or unexported methods
}

UnsafeManagerServiceServer may be embedded to opt out of forward compatibility for this service. Use of this interface is not recommended, as added methods to ManagerServiceServer will result in compilation errors.

Directories

Path Synopsis
api
Package api contains API-related concerns: endpoint definitions, middlewares and all resource representations.
Package api contains API-related concerns: endpoint definitions, middlewares and all resource representations.
http
Package http contains implementation of kit service HTTP API.
Package http contains implementation of kit service HTTP API.
Package tracing provides tracing instrumentation for cocos auth service.
Package tracing provides tracing instrumentation for cocos auth service.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL