Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UV-278 - Modbus Adapter #1

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
The GitHub issue tracker is for bug reports and feature requests. General support can be found at
the following locations:

- Google group - https://groups.google.com/forum/#!forum/mainflux
- Gitter - https://gitter.im/mainflux/mainflux
-->

**FEATURE REQUEST**

1. Is there an open issue addressing this request? If it does, please add a "+1" reaction to the
existing issue, otherwise proceed to step 2.

2. Describe the feature you are requesting, as well as the possible use case(s) for it.

3. Indicate the importance of this feature to you (must-have, should-have, nice-to-have).

**BUG REPORT**

1. What were you trying to achieve?

2. What are the expected results?

3. What are the received results?

4. What are the steps to reproduce the issue?

5. In what environment did you encounter the issue?

6. Additional information you deem important:

**ENHANCEMENT**
1. Describe the enhancement you are requesting. Enhancements include:
- tests
- code refactoring
- documentation
- research
- tooling

2. Indicate the importance of this enhancement to you (must-have, should-have, nice-to-have).
15 changes: 15 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Pull request title should be `MF-XXX - description` or `NOISSUE - description` where XXX is ID of issue that this PR relate to.
Please review the [CONTRIBUTING.md](https://github.com/mainflux/mainflux/blob/master/CONTRIBUTING.md) file for detailed contributing guidelines.

### What does this do?

### Which issue(s) does this PR fix/relate to?
Put here `Resolves #XXX` to auto-close the issue that your PR fixes (if such)

### List any changes that modify/break current functionality

### Have you included tests for your changes?

### Did you document any new/modified functionality?

### Notes
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
strategy:
matrix:
go-version: [1.21.x]
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v3
- name: Build
run: go build -v ./...
- name: Lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --no-config --disable-all --enable gosimple --enable errcheck --enable govet --enable unused --enable goconst --enable godot --enable unused --enable deadcode --timeout 3m
- name: Run tests
run: go test -mod=vendor -v --race -covermode=atomic -coverprofile cover.out ./...
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) Mainflux
# SPDX-License-Identifier: Apache-2.0

# Set your private global .gitignore:
# https://digitalfortress.tech/tricks/creating-a-global-gitignore/

build

113 changes: 113 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Copyright (c) Mainflux
# SPDX-License-Identifier: Apache-2.0

MF_DOCKER_IMAGE_NAME_PREFIX ?= mainflux
BUILD_DIR = build
SERVICES = modbus
DOCKERS = $(addprefix docker_,$(SERVICES))
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
CGO_ENABLED ?= 0
GOARCH ?= amd64
VERSION ?= $(shell git describe --abbrev=0 --tags)
COMMIT ?= $(shell git rev-parse HEAD)
TIME ?= $(shell date +%F_%T)

ifneq ($(MF_BROKER_TYPE),)
MF_BROKER_TYPE := $(MF_BROKER_TYPE)
else
MF_BROKER_TYPE=nats
endif

define compile_service
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
go build -tags $(MF_BROKER_TYPE) -ldflags "-s -w \
-X 'github.com/mainflux/mainflux.BuildTime=$(TIME)' \
-X 'github.com/mainflux/mainflux.Version=$(VERSION)' \
-X 'github.com/mainflux/mainflux.Commit=$(COMMIT)'" \
-o ${BUILD_DIR}/mainflux-$(1) cmd/$(1)/main.go
endef

define make_docker
$(eval svc=$(subst docker_,,$(1)))

docker build \
--no-cache \
--build-arg SVC=$(svc) \
--build-arg GOARCH=$(GOARCH) \
--build-arg GOARM=$(GOARM) \
--build-arg VERSION=$(VERSION) \
--build-arg COMMIT=$(COMMIT) \
--build-arg TIME=$(TIME) \
--tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
-f docker/Dockerfile .
endef

define make_docker_dev
$(eval svc=$(subst docker_dev_,,$(1)))

docker build \
--no-cache \
--build-arg SVC=$(svc) \
--tag=$(MF_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
-f docker/Dockerfile.dev ./build
endef

all: $(SERVICES)

.PHONY: all $(SERVICES) dockers dockers_dev latest release

clean:
rm -rf ${BUILD_DIR}

cleandocker:
# Stops containers and removes containers, networks, volumes, and images created by up
docker-compose -f docker/docker-compose.yml down --rmi all -v --remove-orphans

ifdef pv
# Remove unused volumes
docker volume ls -f name=$(MF_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
endif

install:
cp ${BUILD_DIR}/* $(GOBIN)

test:
go test -v -race -count 1 -tags test $(shell go list ./... | grep -v 'vendor\|cmd')

$(SERVICES):
$(call compile_service,$(@))

$(DOCKERS):
$(call make_docker,$(@),$(GOARCH))

$(DOCKERS_DEV):
$(call make_docker_dev,$(@))

dockers: $(DOCKERS)
dockers_dev: $(DOCKERS_DEV)

define docker_push
for svc in $(SERVICES); do \
docker push $(MF_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
done
endef

changelog:
git log $(shell git describe --tags --abbrev=0)..HEAD --pretty=format:"- %s"

latest: dockers
$(call docker_push,latest)

release:
$(eval version = $(shell git describe --abbrev=0 --tags))
git checkout $(version)
$(MAKE) dockers
for svc in $(SERVICES); do \
docker tag $(MF_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MF_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
done
$(call docker_push,$(version))

run:
sed -i "s,file: brokers/.*.yml,file: brokers/${MF_BROKER_TYPE}.yml," docker/docker-compose.yml
sed -i "s,MF_BROKER_URL=.*,MF_BROKER_URL=$$\{MF_$(shell echo ${MF_BROKER_TYPE} | tr 'a-z' 'A-Z')_URL\}," docker/.env
docker compose -f docker/docker-compose.yml up
77 changes: 77 additions & 0 deletions cmd/modbus/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0

// Package main contains modbus-adapter main function to start the modbus-adapter service.
package main

import (
"context"
"fmt"
"log"
"os"

"github.com/caarlos0/env/v7"
"github.com/mainflux/edge/modbus"
"github.com/mainflux/edge/modbus/api"
mflog "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
"golang.org/x/sync/errgroup"
)

const svcName = "modbus"

type config struct {
LogLevel string `env:"MF_MODBUS_ADAPTER_LOG_LEVEL" envDefault:"info"`
RPCPort int `env:"MF_MODBUS_ADAPTER_RPC_PORT" envDefault:"8855"`
RPCHost string `env:"MF_MODBUS_ADAPTER_RPC_HOST" envDefault:"localhost"`
}

func main() {
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)

cfg := config{}
if err := env.Parse(&cfg); err != nil {
log.Fatalf("failed to load %s configuration : %s", svcName, err)
}

logger, err := mflog.New(os.Stdout, cfg.LogLevel)
if err != nil {
log.Fatalf("failed to init logger: %s", err)
}

var exitCode int
defer mflog.ExitWithError(&exitCode)

svc := modbus.New()

server, err := api.NewServer(svc, fmt.Sprintf("%s:%d", cfg.RPCHost, cfg.RPCPort))
if err != nil {
logger.Error(err.Error())
return
}

g.Go(func() error {
return server.Start(ctx)
})

logger.Info(fmt.Sprintf("modbus service listening on rpc %s:%d", cfg.RPCHost, cfg.RPCPort))

defer func() {
if err := server.Stop(); err != nil {
logger.Error(err.Error())
}
}()

g.Go(func() error {
if sig := errors.SignalHandler(ctx); sig != nil {
cancel()
logger.Info(fmt.Sprintf("modbus shutdown by signal: %s", sig))
}
return nil
})

if err := g.Wait(); err != nil {
logger.Error(fmt.Sprintf("modbus service terminated: %s", err))
}
}
5 changes: 5 additions & 0 deletions docker/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### Modbus
MF_MODBUS_ADAPTER_LOG_LEVEL=info
MF_MODBUS_ADAPTER_INSTANCE_ID=
MF_MODBUS_ADAPTER_RPC_HOST="http://localhost"
MF_MODBUS_ADAPTER_RPC_PORT=8855
8 changes: 8 additions & 0 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) Mainflux
# SPDX-License-Identifier: Apache-2.0

version: "3.7"

SammyOina marked this conversation as resolved.
Show resolved Hide resolved
networks:
mainflux-edge-base-net:
driver: bridge
31 changes: 31 additions & 0 deletions docker/modbus/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright (c) Mainflux
# SPDX-License-Identifier: Apache-2.0

# This docker-compose file contains modbus service. Since it's optional, this file is
# dependent of docker-compose file from <project_root>/docker. In order to run this services, execute command:
# docker-compose -f docker/docker-compose.yml -f docker/modbus/docker-compose.yml up
# from project root.

version: "3.7"

networks:
docker_mainflux-edge-base-net:
external: true

services:
modbus:
image: mainflux/modbus:${MF_RELEASE_TAG}
container_name: mainflux-modbus
depends_on:
- broker
restart: on-failure
environment:
MF_MODBUS_ADAPTER_LOG_LEVEL: ${MF_MODBUS_ADAPTER_LOG_LEVEL}
MF_MODBUS_ADAPTER_RPC_HOST: ${MF_MODBUS_ADAPTER_RPC_HOST}
MF_HTTP_ADAPTER_RPC_PORT: ${MF_HTTP_ADAPTER_RPC_PORT}
MF_JAEGER_URL: ${MF_JAEGER_URL}
MF_MODBUS_ADAPTER_INSTANCE_ID: ${MF_MODBUS_ADAPTER_INSTANCE_ID}
ports:
- ${MF_HTTP_ADAPTER_RPC_PORT}:${MF_HTTP_ADAPTER_RPC_PORT}
networks:
- docker_mainflux-edge-base-net
Loading