Skip to content

Commit

Permalink
feat: add mapper of windows exec virtual device
Browse files Browse the repository at this point in the history
Signed-off-by: soyowind0 <[email protected]>
  • Loading branch information
soyowind0 committed Sep 30, 2024
1 parent ab4f8b9 commit 5109221
Show file tree
Hide file tree
Showing 22 changed files with 1,310 additions and 0 deletions.
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ require (
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
google.golang.org/grpc v1.47.0
gopkg.in/yaml.v2 v2.4.0
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde
k8s.io/api v0.24.1
k8s.io/apimachinery v0.24.1
k8s.io/klog v1.0.0
Expand Down Expand Up @@ -52,12 +53,15 @@ require (
github.com/gorilla/websocket v1.4.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kubeedge/viaduct v0.0.0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand All @@ -77,6 +81,7 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
gorm.io/driver/sqlite v1.5.6
k8s.io/client-go v0.24.1 // indirect
k8s.io/component-base v0.22.6 // indirect
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,10 @@ github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
Expand Down Expand Up @@ -805,6 +809,8 @@ github.com/mattn/go-shellwords v1.0.11/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
Expand Down Expand Up @@ -1745,6 +1751,10 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE=
gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg=
gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
Expand Down
33 changes: 33 additions & 0 deletions mappers/windows-virtual-exec/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
SHELL := /bin/bash

curr_dir := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
rest_args := $(wordlist 2, $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
$(eval $(rest_args):;@:)

help:
#
# Usage:
# make generate : generate a mapper based on a template.
# make mapper {mapper-name} <action> <parameter>: execute mapper building process.
#
# Actions:
# - mod, m : download code dependencies.
# - lint, l : verify code via go fmt and `golangci-lint`.
# - build, b : compile code.
# - package, p : package docker image.
# - clean, c : clean output binary.
#
# Parameters:
# ARM : true or undefined
# ARM64 : true or undefined
#
# Example:
# - make mapper windows-virtual-exec : execute `build` "windows-virtual-exec" mapper.
@echo

make_rules := $(shell ls $(curr_dir)/hack/make-rules | sed 's/.sh//g')
$(make_rules):
@$(curr_dir)/hack/make-rules/$@.sh $(rest_args)

.DEFAULT_GOAL := help
.PHONY: $(make_rules) build test package
114 changes: 114 additions & 0 deletions mappers/windows-virtual-exec/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Windows Execution Virtual Device

## Overall design

Overall, based on the modularity of Kubeedge, this project utilizes the independent data communication capability provided by DeviceTwin module to expand the usage scenarios of Kubeedge and adapt the problems encountered by the actual landing of Kubeedge in the automotive industry:

1. In order to explore the possibility of Kubeedge cloud-native solution in the automotive industry, Kubeedge is introduced for multi-region- and multi-state edge node management, so that automotive software testing can be automated and the testing environment can go to the cloud.

2. With the increase of automotive testing and simulation needs, some traditional industrial software relies on native Windows platform, even though Kubeedge has provided support for Windows Server with container capability, upgrading the original Windows Enterprise Edition machine to Windows Server is unacceptable to the staff and cost department.

3. Automated testing uses third-party simulation and debugging software based on the Windows platform. In order to analyze and model the test data, it is necessary to upload the test process and result data from the test host computer to the cloud.

For this reason, the following design is made:

![overall-design](./static/1-simple.png)

The overall design is shown in the figure, the software test host, regardless of Windows or Linux, is unified and managed by Kubeedge as a node. Users use K8s API to issue commands to operate it and create corresponding test tasks, and the DeviceTwin module of Kubeedge provides additional data communication capability to realize the triggering and reporting of non-container environment Windows nodes.

## CRDs

Non-containerized Windows environments execute automotive testing tasks that rely on third-party closed-source tools in a bare metal form, where the environment is relatively static and the tasks performed are variable. Therefore, we believe that Windows nodes need a unified executor to execute test tasks (scripts) issued by the cloud, scheduling, running commands and returning data to the cloud.

In this project, automotive software testing has the following characteristics:

1. The execution environment is decentralized and fixed, and the automotive software runs on a collection of hardware called a “pedestal”, which is physically fixed and configured with a PC to access it as a “host computer”. The dais and the host computer are dispersed across the country and around the world, depending on the location of the business unit.
2. Test tasks are dynamically plugged in and out, and their operational status needs to be monitored to prevent the desktop from failing. 3.
3. During the execution of tasks, test logs are constantly generated and need to be aggregated and analyzed in the cloud.

Kubeedge has designed DeviceTwin to support device and data management, and defined CRD resources for Device and DeviceModel. CRD declarative yaml design is simple for users to understand, easy to operate, and can be promoted to testers; Kubeedge CloudCore has implemented DeviceController, a controller for Device resource objects. Kubeedge CloudCore has already implemented DeviceController for Device resource.Considering a test task as a virtual device, according to the design of Kubeedge Device and the requirements of automotive software testing, the Device and DeviceModel are defined as follows:

### Device Model

```yaml
apiVersion: devices.kubeedge.io/v1alpha2
kind: DeviceModel
metadata:
name: win-exec-model
namespace: default
spec:
properties:
- name: exec-file-content
description: custom content to execute
type:
string:
accessMode: ReadOnly
- name: exec-file-name
description: save custom content as filename
type:
string:
accessMode: ReadOnly
- name: exec-command
description: entrypoint of target
type:
string:
accessMode: ReadOnly
- name: status
description: status of current executation
type:
string:
accessMode: ReadWrite
- name: output
description: console output of current executation
type:
string:
accessMode: ReadWrite
```
### Device Instance
```yaml
apiVersion: devices.kubeedge.io/v1alpha2
kind: Device
metadata:
name: exec-instance-001
labels:
description: "test"
model: win-exec-model
spec:
deviceModelRef:
name: win-exec-model
nodeSelector:
nodeSelectorTerms:
- matchExpressions:
- key: ''
operator: In
values:
- win11-node
protocol:
customizedProtocal:
protocolName: winExec
status:
twins:
- propertyName: status
- propertyName: output
- propertyName: exec-file-content
desired:
value: 'echo "hello,world"'
- propertyName: exec-file-name
desired:
value: 'run.bat'
- propertyName: exec-command
desired:
value: 'run.bat'
```
The Device Instance is defined based on the Device Model and instantiates the contents of exec-file-content, exec-file-name and exec-command. The status and output fields are reflected in the actual field after the execution is completed, and the result is reported to the cloud as the test task script. The result of the execution is reported to the cloud.
## Mapper
According to the docs/proposals/device-crd.md document, the lifecycle of an IoT device consists of six parts: registration, configuration, upgrade, monitoring, logout, and destruction. Among them, registration, upgrade, logout, and destruction are not considered in the device-crd.md document. Therefore, device is designed for device configuration and monitoring. Configuration is designed to reconfigure the device multiple times without adding new functionality, setting the expected expectation in the CRD, i.e., a declarative configuration of the behavior that the device should have. Monitoring is designed to constantly update the state of the device so that the cloud can be informed of the state of the device in time for the next step.
Considering the test task as an abstract device, configuring the device means setting the parameters of the test task; monitoring the status of the device means collecting and monitoring the execution logs of the test task.
The execution of test tasks and reporting of results uses only a small portion of the mapper framework, which supports device creation, query and deletion, and does not require the introduction of complete framework logic. The operations are triggered as callback functions, controlled by the cloud, and in addition to the cloud commands, messages are actively pushed to the local MQTT to trigger the next operation. mapper loads the local database into memory at startup, and then triggers the execution of the task and the reporting of the status based on the type of message.
52 changes: 52 additions & 0 deletions mappers/windows-virtual-exec/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"os"
"os/signal"

"k8s.io/klog/v2"

"github.com/kubeedge/mappers-go/mappers/windows-virtual-exec/internal/config"
"github.com/kubeedge/mappers-go/mappers/windows-virtual-exec/internal/core/model"
"github.com/kubeedge/mappers-go/mappers/windows-virtual-exec/internal/core/mqtt"
"github.com/kubeedge/mappers-go/mappers/windows-virtual-exec/internal/core/store"
"github.com/kubeedge/mappers-go/mappers/windows-virtual-exec/internal/missions"
)

func main() {
var err error
var c config.Config

klog.InitFlags(nil)
defer klog.Flush()

if err = c.Parse(); err != nil {
klog.Fatal(err)
os.Exit(1)
}

store.InitDB("internal.db")
store.DB.AutoMigrate(&model.Mission{})

mqtt.Client = &mqtt.MqttClient{
IP: c.Mqtt.ServerAddress,
User: c.Mqtt.Username,
Passwd: c.Mqtt.Password,
Cert: c.Mqtt.Cert,
PrivateKey: c.Mqtt.PrivateKey,
}
if err = mqtt.Client.Connect(); err != nil {
klog.Fatal(err)
os.Exit(1)
}

missions.InitCallback(c.NodeName)
klog.Info("Start to subscribe")
missions.InitMissions(c.NodeName)

// waiting kill signal
var ch = make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
<-ch
klog.Info("Exit")
}
127 changes: 127 additions & 0 deletions mappers/windows-virtual-exec/hack/make-rules/mapper.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

CURR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"
ROOT_DIR="$(cd "${CURR_DIR}/../.." && pwd -P)"
source "${ROOT_DIR}/hack/lib/init.sh"

mkdir -p "${CURR_DIR}/bin"
mkdir -p "${CURR_DIR}/dist"

function mod() {
[[ "${2:-}" != "only" ]]
local mapper="${1}"

# the mapper is sharing the vendor with root
pushd "${ROOT_DIR}" >/dev/null || exist 1
echo "downloading dependencies for mapper ${mapper}..."

if [[ "$(go env GO111MODULE)" == "off" ]]; then
echo "go mod has been disabled by GO111MODULE=off"
else
echo "tidying"
go mod tidy
echo "vending"
go mod vendor
fi

echo "...done"
popd >/dev/null || return
}

function lint() {
[[ "${2:-}" != "only" ]] && mod "$@"
local mapper="${1}"

echo "fmt and linting mapper ${mapper}..."

gofmt -s -w "${CURR_DIR}/"
golangci-lint run "${CURR_DIR}/..."

echo "...done"
}

function build() {
[[ "${2:-}" != "only" ]] && lint "$@"
local mapper="${1}"

local flags=" -w -s "
local ext_flags=" -extldflags '-static' "
local os="${OS:-$(go env GOOS)}"
local arch="${ARCH:-$(go env GOARCH)}"

local platform
if [[ "${ARM:-false}" == "true" ]]; then
echo "crossed packaging for windows/arm"
platform=("windows/arm")
elif [[ "${ARM64:-false}" == "true" ]]; then
echo "crossed packaging for windows/arm64"
platform=("windows/arm64")
else
local os="windows"
local arch="${ARCH:-$(go env GOARCH)}"
platform=("${os}/${arch}")
fi

echo "building ${platform}"

local os_arch
IFS="/" read -r -a os_arch <<<"${platform}"
local os=${os_arch[0]}
local arch=${os_arch[1]}
GOOS=${os} GOARCH=${arch} CGO_ENABLED=0 go build \
-ldflags "${flags} ${ext_flags}" \
-o "${CURR_DIR}/bin/${mapper}_${os}_${arch}" \
"${CURR_DIR}/cmd/main.go"

cp ${CURR_DIR}/bin/${mapper}_${os}_${arch} ${CURR_DIR}/bin/${mapper}
echo "...done"
}

function package() {
echo "docker package not support for windows virtual exec driver"
exit 1
}

function clean() {
local mapper="${1}"

echo "cleanup mapper ${mapper}..."

rm -rf "${CURR_DIR}/bin/*"

echo "...done"
}

function entry() {
local mapper="${1:-}"
shift 1

local stages="${1:-build}"
shift $(($# > 0 ? 1 : 0))

IFS="," read -r -a stages <<<"${stages}"
local commands=$*
if [[ ${#stages[@]} -ne 1 ]]; then
commands="only"
fi

for stage in "${stages[@]}"; do
echo "# make mapper ${mapper} ${stage} ${commands}"
case ${stage} in
m | mod) mod "${mapper}" "${commands}" ;;
l | lint) lint "${mapper}" "${commands}" ;;
b | build) build "${mapper}" "${commands}" ;;
p | pkg | package) package "${mapper}" "${commands}" ;;
t | test) test "${mapper}" "${commands}" ;;
c | clean) clean "${mapper}" "${commands}" ;;
*) echo "unknown action '${stage}', select from mod,lint,build,test,clean" ;;
esac
done
}

echo $@
entry "$@"
Loading

0 comments on commit 5109221

Please sign in to comment.