mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
@@ -15,6 +15,8 @@ define compile_service
|
||||
-o ${BUILD_DIR}/cocos-$(1) cmd/$(1)/main.go
|
||||
endef
|
||||
|
||||
.PHONY: all $(SERVICES)
|
||||
|
||||
all: $(SERVICES)
|
||||
|
||||
$(SERVICES):
|
||||
@@ -45,11 +47,5 @@ copy-agent-rc-sh:
|
||||
chmod +x $(HOST_AGENT_RC_SH_PATH)
|
||||
sudo virt-copy-in -a $(QCOW2_PATH) $(HOST_AGENT_RC_SH_PATH) $(GUEST_AGENT_RC_SH_PATH)
|
||||
|
||||
# docker_mfxkit:
|
||||
# docker build --no-cache --tag=mainflux/mfxkit -f docker/Dockerfile .
|
||||
|
||||
# run:
|
||||
# docker-compose -f docker/docker-compose.yml up
|
||||
|
||||
protoc:
|
||||
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative agent/agent.proto
|
||||
|
||||
@@ -10,7 +10,7 @@ go build -o ./bin/agent -ldflags="-linkmode=external -extldflags=-static -s -w"
|
||||
|
||||
## Copy files to virtual drive
|
||||
|
||||
Log in the VM and create `/cocos` directory. Shut down `QEmu-alpine-standard-x86_64` virtual machine.
|
||||
Log in the VM and create `/cocos` directory. Shut down `QEmu-alpine-standard-x86_64` virtual machine.
|
||||
|
||||
On the host machine install [libguestfs-tools](https://libguestfs.org/). `libguestfs-tools` is "a set of tools for accessing and modifying virtual machine (VM) disk images".
|
||||
|
||||
@@ -40,7 +40,7 @@ GUEST_AGENT_SCRIPT_PATH=/etc/init.d/; \
|
||||
sudo virt-copy-in -a $QCOW2_PATH $HOST_AGENT_SCRIPT_PATH $GUEST_AGENT_SCRIPT_PATH
|
||||
```
|
||||
|
||||
OpenRC init script is used to start `agent` executable as a system service (daemon) on the Alpine Linux boot.
|
||||
OpenRC init script is used to start `agent` executable as a system service (daemon) on the Alpine Linux boot.
|
||||
|
||||
### OpenRC
|
||||
|
||||
@@ -58,21 +58,21 @@ To see if the `agent` service (or deamon) is running, inside Alpine linux run
|
||||
ps aux | grep agent
|
||||
```
|
||||
|
||||
To see if the ports are correctly configured, inside Alpine linux, i.e. *guest machine*, run
|
||||
To see if the ports are correctly configured, inside Alpine linux, i.e. _guest machine_, run
|
||||
|
||||
```sh
|
||||
netstat -tuln | grep 9031
|
||||
netstat -tuln | grep 7002
|
||||
```
|
||||
|
||||
In the *host machine*, you can check if the ports of the guest machine are open and reachable from the host machine with
|
||||
In the _host machine_, you can check if the ports of the guest machine are open and reachable from the host machine with
|
||||
|
||||
```sh
|
||||
nc -zv 192.168.122.251 9031
|
||||
nc -zv 192.168.122.251 7002
|
||||
```
|
||||
|
||||
NB: to find out `192.168.122.251`, i.e. the concrete address of the guest machine, you need to
|
||||
NB: to find out `192.168.122.251`, i.e. the concrete address of the guest machine, you need to
|
||||
|
||||
```sh
|
||||
ip addr show eth0
|
||||
@@ -94,14 +94,10 @@ To check if the `agent` deamon is responding to the requests, run on the host
|
||||
GUEST_ADDR=192.168.122.251:9031
|
||||
```
|
||||
|
||||
```sh
|
||||
curl -i -X POST -H "Content-Type: application/json" ${GUEST_ADDR}/agent -d '{"secret":"secret"}'
|
||||
```
|
||||
|
||||
To run a computation
|
||||
|
||||
```sh
|
||||
curl -sSi -X POST ${GUEST_ADDR}/run -H "Content-Type: application/json" -d @- <<EOF
|
||||
curl -sSi -X POST ${GUEST_ADDR}/run -H "Content-Type: application/json" -d @- <<EOF
|
||||
{
|
||||
"name": "computation_24",
|
||||
"description": "this_computes_the_number_24",
|
||||
|
||||
+17
-37
@@ -1,61 +1,41 @@
|
||||
# Agent
|
||||
|
||||
Agent service provides a barebones HTTP API and Service interface implementation for development of a core Mainflux service.
|
||||
Agent service provides a barebones HTTP and gRPC API and Service interface implementation for the development of the agent 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 |
|
||||
|-----------------------|---------------------------------------------------------|---------|
|
||||
| MF_AGENT_LOG_LEVEL | Log level for agent service (debug, info, warn, error) | error |
|
||||
| MF_AGENT_HTTP_PORT | Agent service HTTP port | 9021 |
|
||||
| MF_AGENT_SERVER_CERT | Path to server certificate in pem format | |
|
||||
| MF_AGENT_SERVER_KEY | Path to server key in pem format | |
|
||||
| MF_JAEGER_URL | Jaeger server URL | |
|
||||
| MF_AGENT_SECRET | Agent service secret | secret |
|
||||
| Variable | Description | Default |
|
||||
| ---------------------- | ------------------------------------------------------ | ------------------------------ |
|
||||
| AGENT_LOG_LEVEL | Log level for agent service (debug, info, warn, error) | info |
|
||||
| AGENT_HTTP_HOST | Agent service HTTP host | "" |
|
||||
| AGENT_HTTP_PORT | Agent service HTTP port | 9031 |
|
||||
| AGENT_HTTP_SERVER_CERT | Path to HTTP server certificate in pem format | "" |
|
||||
| AGENT_HTTP_SERVER_KEY | Path to HTTP server key in pem format | "" |
|
||||
| AGENT_GRPC_HOST | Agent service gRPC host | "" |
|
||||
| AGENT_GRPC_PORT | Agent service gRPC port | 7002 |
|
||||
| AGENT_GRPC_SERVER_CERT | Path to gRPC server certificate in pem format | "" |
|
||||
| AGENT_GRPC_SERVER_KEY | Path to gRPC server key in pem format | "" |
|
||||
| AGENT_JAEGER_URL | Jaeger server URL | http://jaeger:14268/api/traces |
|
||||
|
||||
## Deployment
|
||||
|
||||
The service is distributed as a Docker container. The following snippet provides a compose file template that can be used to deploy the service container locally:
|
||||
|
||||
```yaml
|
||||
version: "3"
|
||||
services:
|
||||
agent:
|
||||
image: ultravioletrs/agent:[version]
|
||||
container_name: [instance name]
|
||||
ports:
|
||||
- [host machine port]:[configured HTTP port]
|
||||
environment:
|
||||
MF_AGENT_LOG_LEVEL: [Kit log level]
|
||||
MF_AGENT_HTTP_PORT: [Service HTTP port]
|
||||
MF_AGENT_SERVER_CERT: [String path to server cert in pem format]
|
||||
MF_AGENT_SERVER_KEY: [String path to server key in pem format]
|
||||
MF_AGENT_SECRET: [Agent service secret]
|
||||
MF_JAEGER_URL: [Jaeger server URL]
|
||||
```
|
||||
|
||||
To start the service outside of the container, execute the following shell script:
|
||||
|
||||
```bash
|
||||
# download the latest version of the service
|
||||
go get github.com/mainflux/mainflux
|
||||
go get github.com/ultravioletrs/agent
|
||||
|
||||
cd $GOPATH/src/github.com/mainflux/mainflux
|
||||
cd $GOPATH/src/github.com/ultravioletrs/agent
|
||||
|
||||
# compile the agent
|
||||
make agent
|
||||
|
||||
# copy binary to bin
|
||||
make install
|
||||
|
||||
# set the environment variables and run the service
|
||||
MF_AGENT_LOG_LEVEL=[Kit log level] MF_AGENT_HTTP_PORT=[Service HTTP port] MF_AGENT_SERVER_CERT: [String path to server cert in pem format] MF_AGENT_SERVER_KEY: [String path to server key in pem format] MF_JAEGER_URL=[Jaeger server URL] MF_AGENT_SECRET: [Agent service secret] $GOBIN/mainflux-kit
|
||||
./build/cocos-agent
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
For more information about service capabilities and its usage, please check out the [API documentation](swagger.yaml).
|
||||
|
||||
[doc]: http://mainflux.readthedocs.io
|
||||
For more information about service capabilities and its usage, please check out the [README documentation](../README.md).
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package grpc contains implementation of kit service gRPC API.
|
||||
package grpc
|
||||
@@ -22,7 +22,7 @@ func runEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
computationStr, err := svc.Run(context.TODO(), computation)
|
||||
computationStr, err := svc.Run(ctx, computation)
|
||||
if err != nil {
|
||||
return runRes{}, err
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// type healthReq struct{}
|
||||
import "errors"
|
||||
|
||||
type runReq struct {
|
||||
Computation []byte `protobuf:"bytes,1,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package grpc
|
||||
|
||||
// type healthRes struct {
|
||||
// Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
// }
|
||||
|
||||
type runRes struct {
|
||||
Computation string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
@@ -10,26 +10,6 @@ import (
|
||||
agent "github.com/ultravioletrs/agent/agent"
|
||||
)
|
||||
|
||||
func pingEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return func(_ context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(pingReq)
|
||||
|
||||
if err := req.validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
greeting, err := svc.Ping(req.Secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := pingRes{
|
||||
Greeting: greeting,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
func runEndpoint(svc agent.Service) endpoint.Endpoint {
|
||||
return func(ctx context.Context, request interface{}) (interface{}, error) {
|
||||
req := request.(runReq)
|
||||
|
||||
@@ -3,21 +3,7 @@
|
||||
|
||||
package http
|
||||
|
||||
import (
|
||||
agent "github.com/ultravioletrs/agent/agent"
|
||||
)
|
||||
|
||||
type pingReq struct {
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
func (req pingReq) validate() error {
|
||||
if req.Secret == "" {
|
||||
return agent.ErrMalformedEntity
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
import agent "github.com/ultravioletrs/agent/agent"
|
||||
|
||||
type runReq struct {
|
||||
computation agent.Computation
|
||||
|
||||
@@ -9,23 +9,7 @@ import (
|
||||
"github.com/mainflux/mainflux"
|
||||
)
|
||||
|
||||
var _ mainflux.Response = (*pingRes)(nil)
|
||||
|
||||
type pingRes struct {
|
||||
Greeting string `json:"greeting"`
|
||||
}
|
||||
|
||||
func (res pingRes) Code() int {
|
||||
return http.StatusOK
|
||||
}
|
||||
|
||||
func (res pingRes) Headers() map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (res pingRes) Empty() bool {
|
||||
return false
|
||||
}
|
||||
var _ mainflux.Response = (*runRes)(nil)
|
||||
|
||||
type runRes struct {
|
||||
Computation string `json:"computation"`
|
||||
|
||||
@@ -15,13 +15,11 @@ import (
|
||||
"github.com/go-zoo/bone"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
agent "github.com/ultravioletrs/agent/agent"
|
||||
"github.com/ultravioletrs/agent/agent"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
|
||||
const (
|
||||
contentType = "application/json"
|
||||
)
|
||||
const contentType = "application/json"
|
||||
|
||||
var (
|
||||
errUnsupportedContentType = errors.New("unsupported content type")
|
||||
@@ -36,12 +34,6 @@ func MakeHandler(svc agent.Service, instanceID string) http.Handler {
|
||||
|
||||
r := bone.New()
|
||||
|
||||
r.Post("/agent", otelhttp.NewHandler(kithttp.NewServer(
|
||||
pingEndpoint(svc),
|
||||
decodePing,
|
||||
encodeResponse,
|
||||
opts...,
|
||||
), "ping"))
|
||||
r.Post("/run", otelhttp.NewHandler(kithttp.NewServer(
|
||||
runEndpoint(svc),
|
||||
decodeRun,
|
||||
@@ -55,19 +47,6 @@ func MakeHandler(svc agent.Service, instanceID string) http.Handler {
|
||||
return r
|
||||
}
|
||||
|
||||
func decodePing(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||
return nil, errUnsupportedContentType
|
||||
}
|
||||
|
||||
req := pingReq{}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func decodeRun(_ context.Context, r *http.Request) (interface{}, error) {
|
||||
if !strings.Contains(r.Header.Get("Content-Type"), contentType) {
|
||||
return nil, errUnsupportedContentType
|
||||
|
||||
@@ -27,19 +27,6 @@ func LoggingMiddleware(svc agent.Service, logger log.Logger) agent.Service {
|
||||
return &loggingMiddleware{logger, svc}
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Ping(secret string) (response string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method ping for secret %s took %s to complete", secret, time.Since(begin))
|
||||
if err != nil {
|
||||
lm.logger.Warn(fmt.Sprintf("%s with error: %s.", message, err))
|
||||
return
|
||||
}
|
||||
lm.logger.Info(fmt.Sprintf("%s without errors.", message))
|
||||
}(time.Now())
|
||||
|
||||
return lm.svc.Ping(secret)
|
||||
}
|
||||
|
||||
func (lm *loggingMiddleware) Run(ctx context.Context, cmp agent.Computation) (response string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
message := fmt.Sprintf("Method Run for computation %s took %s to complete", cmp.ID, time.Since(begin))
|
||||
|
||||
@@ -32,15 +32,6 @@ func MetricsMiddleware(svc agent.Service, counter metrics.Counter, latency metri
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Ping(secret string) (response string, err error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "ping").Add(1)
|
||||
ms.latency.With("method", "ping").Observe(time.Since(begin).Seconds())
|
||||
}(time.Now())
|
||||
|
||||
return ms.svc.Ping(secret)
|
||||
}
|
||||
|
||||
func (ms *metricsMiddleware) Run(ctx context.Context, cmp agent.Computation) (string, error) {
|
||||
defer func(begin time.Time) {
|
||||
ms.counter.With("method", "run").Add(1)
|
||||
|
||||
+2
-14
@@ -24,8 +24,6 @@ type Metadata map[string]interface{}
|
||||
// Service specifies an API that must be fullfiled by the domain service
|
||||
// implementation, and all of its decorators (e.g. logging & metrics).
|
||||
type Service interface {
|
||||
// Ping compares a given string with secret
|
||||
Ping(string) (string, error)
|
||||
Run(ctx context.Context, cmp Computation) (string, error)
|
||||
Algo(ctx context.Context, algorithm []byte) (string, error)
|
||||
Data(ctx context.Context, dataset string) (string, error)
|
||||
@@ -33,23 +31,13 @@ type Service interface {
|
||||
}
|
||||
|
||||
type agentService struct {
|
||||
secret string
|
||||
}
|
||||
|
||||
var _ Service = (*agentService)(nil)
|
||||
|
||||
// New instantiates the agent service implementation.
|
||||
func New(secret string) Service {
|
||||
return &agentService{
|
||||
secret: secret,
|
||||
}
|
||||
}
|
||||
|
||||
func (ks *agentService) Ping(secret string) (string, error) {
|
||||
if ks.secret != secret {
|
||||
return "", ErrUnauthorizedAccess
|
||||
}
|
||||
return "Hello World :)", nil
|
||||
func New() Service {
|
||||
return &agentService{}
|
||||
}
|
||||
|
||||
func (ks *agentService) Run(ctx context.Context, cmp Computation) (string, error) {
|
||||
|
||||
@@ -20,15 +20,6 @@ func New(svc agent.Service, tracer trace.Tracer) agent.Service {
|
||||
return &tracingMiddleware{tracer, svc}
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) Ping(secret string) (string, error) {
|
||||
_, span := tm.tracer.Start(context.Background(), "ping", trace.WithAttributes(
|
||||
attribute.String("secret", secret),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
return tm.svc.Ping(secret)
|
||||
}
|
||||
|
||||
func (tm *tracingMiddleware) Run(ctx context.Context, cmp agent.Computation) (string, error) {
|
||||
ctx, span := tm.tracer.Start(ctx, "run", trace.WithAttributes(
|
||||
attribute.String("id", cmp.ID),
|
||||
|
||||
+3
-4
@@ -35,7 +35,6 @@ const (
|
||||
|
||||
type config struct {
|
||||
LogLevel string `env:"AGENT_LOG_LEVEL" envDefault:"info"`
|
||||
Secret string `env:"AGENT_SECRET" envDefault:"secret"`
|
||||
JaegerURL string `env:"AGENT_JAEGER_URL" envDefault:"http://localhost:14268/api/traces"`
|
||||
InstanceID string `env:"AGENT_INSTANCE_ID" envDefault:""`
|
||||
}
|
||||
@@ -72,7 +71,7 @@ func main() {
|
||||
}()
|
||||
tracer := tp.Tracer(svcName)
|
||||
|
||||
svc := newService(cfg.Secret, logger, tracer)
|
||||
svc := newService(logger, tracer)
|
||||
|
||||
var httpServerConfig = server.Config{Port: defSvcHTTPPort}
|
||||
if err := env.Parse(&httpServerConfig, env.Options{Prefix: envPrefixHTTP}); err != nil {
|
||||
@@ -107,8 +106,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func newService(secret string, logger mflog.Logger, tracer trace.Tracer) agent.Service {
|
||||
svc := agent.New(secret)
|
||||
func newService(logger mflog.Logger, tracer trace.Tracer) agent.Service {
|
||||
svc := agent.New()
|
||||
|
||||
svc = api.LoggingMiddleware(svc, logger)
|
||||
counter, latency := internal.MakeMetrics(svcName, "api")
|
||||
|
||||
@@ -9,8 +9,6 @@ AGENT_JAEGER_URL=http://jaeger:14268/api/traces
|
||||
|
||||
## Agent
|
||||
AGENT_LOG_LEVEL=info
|
||||
AGENT_SECRET=secret
|
||||
AGENT_JAEGER_URL=
|
||||
AGENT_HTTP_HOST=
|
||||
AGENT_HTTP_PORT=9031
|
||||
AGENT_HTTP_SERVER_CERT=
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
FROM golang:1.16-alpine AS builder
|
||||
|
||||
WORKDIR /go/src/github.com/mainflux/mfxkit
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 GOARCH=amd64 \
|
||||
go build -mod=vendor -ldflags "-s -w" -o build/mainflux-mfxkit cmd/mfxkit/main.go \
|
||||
&& mv build/mainflux-mfxkit /exe
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /exe /
|
||||
ENTRYPOINT ["/exe"]
|
||||
Reference in New Issue
Block a user