mirror of
https://github.com/logos-messaging/logos-messaging-simulator.git
synced 2026-01-03 14:33:06 +00:00
295 lines
6.0 KiB
Go
295 lines
6.0 KiB
Go
package simulate
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path"
|
|
|
|
compose "github.com/compose-spec/compose-go/types"
|
|
"github.com/otiai10/copy"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
const (
|
|
BOOSTRAP_SERVICE_NAME = "bootstrap"
|
|
PUBLISHER_SERVICE_NAME = "waku-publisher"
|
|
CONTAINER_ENTRYPOINT = "/opt/run.sh"
|
|
)
|
|
|
|
type Simulation struct {
|
|
Name string
|
|
TargetDir string
|
|
Manifest Manifest
|
|
}
|
|
|
|
func NewSimulation(name string, targetDir string) *Simulation {
|
|
if targetDir == "" {
|
|
targetDir = name
|
|
}
|
|
return &Simulation{
|
|
Name: name,
|
|
TargetDir: targetDir,
|
|
}
|
|
}
|
|
|
|
func (s *Simulation) Load(path string) error {
|
|
bytes, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var m = Manifest{}
|
|
err = yaml.Unmarshal(bytes, &m)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if m.Bootstrap == nil {
|
|
b := true
|
|
m.Bootstrap = &b
|
|
}
|
|
|
|
if m.Monitoring == nil {
|
|
b := true
|
|
m.Monitoring = &b
|
|
}
|
|
|
|
for i, g := range m.Groups {
|
|
if g.Name == "" {
|
|
return fmt.Errorf("Missing name for group %d", i)
|
|
}
|
|
}
|
|
|
|
s.Manifest = m
|
|
return nil
|
|
}
|
|
|
|
func (s *Simulation) Generate() error {
|
|
c := compose.Project{}
|
|
bootstrap := false
|
|
|
|
if *s.Manifest.Bootstrap {
|
|
service, err := s.prepBootstrapNode()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Services = append(c.Services, service)
|
|
bootstrap = true
|
|
}
|
|
|
|
for _, g := range s.Manifest.Groups {
|
|
for j := 0; j < g.Count; j++ {
|
|
service := compose.ServiceConfig{}
|
|
|
|
service.Image = g.Image
|
|
service.Name = fmt.Sprintf("%s-%d", g.Name, j)
|
|
service.Environment = g.Env
|
|
|
|
if bootstrap {
|
|
service.DependsOn = compose.DependsOnConfig{
|
|
BOOSTRAP_SERVICE_NAME: compose.ServiceDependency{
|
|
Condition: compose.ServiceConditionStarted,
|
|
},
|
|
}
|
|
}
|
|
|
|
s.ensureRunScript(g, &service)
|
|
|
|
service.Command = append(service.Command, g.Args...)
|
|
|
|
s.ensureVolumes(g, &service)
|
|
|
|
c.Services = append(c.Services, service)
|
|
}
|
|
}
|
|
|
|
if *s.Manifest.Monitoring {
|
|
services := c.ServiceNames()
|
|
|
|
monitoringServices, err := s.prepMonitoring(s.TargetDir, services)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Services = append(c.Services, monitoringServices...)
|
|
}
|
|
|
|
if s.Manifest.Publisher != nil {
|
|
service, err := s.prepPublisher()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Services = append(c.Services, service)
|
|
}
|
|
|
|
log.Printf("Generating Docker Compose environment into the folder ./%s", s.TargetDir)
|
|
|
|
bytes, err := c.MarshalYAML()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = os.MkdirAll(s.TargetDir, 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ioutil.WriteFile(path.Join(s.TargetDir, "compose.yaml"), bytes, 0644)
|
|
return nil
|
|
|
|
}
|
|
|
|
func (s *Simulation) ensureRunScript(g Group, service *compose.ServiceConfig) error {
|
|
|
|
command := ""
|
|
|
|
switch g.Typ {
|
|
case "nwaku":
|
|
command = "run_nwaku.sh"
|
|
case "gowaku":
|
|
command = "run_gowaku.sh"
|
|
case "wakupublisher":
|
|
command = "run_wakupublisher.sh"
|
|
default:
|
|
return fmt.Errorf("Unknown service type: %s", g.Typ)
|
|
}
|
|
|
|
if service.Command == nil || len(service.Command) == 0 {
|
|
service.Command = compose.ShellCommand{CONTAINER_ENTRYPOINT}
|
|
} else {
|
|
service.Command = append(compose.ShellCommand{CONTAINER_ENTRYPOINT}, service.Command...)
|
|
}
|
|
|
|
if service.Volumes == nil {
|
|
service.Volumes = make([]compose.ServiceVolumeConfig, 0)
|
|
}
|
|
|
|
service.Volumes = append(service.Volumes, compose.ServiceVolumeConfig{
|
|
Type: compose.VolumeTypeBind,
|
|
Source: fmt.Sprintf("../%s", command),
|
|
Target: CONTAINER_ENTRYPOINT,
|
|
ReadOnly: true,
|
|
})
|
|
|
|
service.Entrypoint = compose.ShellCommand{"sh"}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Simulation) ensureVolumes(g Group, service *compose.ServiceConfig) error {
|
|
if len(g.Volumes) > 0 && service.Volumes == nil {
|
|
service.Volumes = make([]compose.ServiceVolumeConfig, 0)
|
|
}
|
|
for _, v := range g.Volumes {
|
|
src := v.Src
|
|
if v.PerNode && !v.ReadOnly {
|
|
src = fmt.Sprintf("%s-%s", v.Src, service.Name)
|
|
|
|
_, err := os.Stat(v.Src) //TODO: Is there a difference between dir and file?
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
|
|
if os.IsNotExist(err) {
|
|
err = os.MkdirAll(path.Join(s.TargetDir, src), 0755)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
err = copy.Copy(v.Src, path.Join(s.TargetDir, src))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
volume := compose.ServiceVolumeConfig{
|
|
Type: compose.VolumeTypeBind,
|
|
Source: src,
|
|
Target: v.Dst,
|
|
ReadOnly: v.ReadOnly,
|
|
}
|
|
service.Volumes = append(service.Volumes, volume)
|
|
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Simulation) prepBootstrapNode() (compose.ServiceConfig, error) {
|
|
service := compose.ServiceConfig{}
|
|
|
|
service.Name = "bootstrap"
|
|
service.Image = "statusteam/nim-waku:v0.19.0"
|
|
service.Entrypoint = compose.ShellCommand{"sh"}
|
|
service.Command = compose.ShellCommand{
|
|
CONTAINER_ENTRYPOINT,
|
|
}
|
|
|
|
service.Volumes = make([]compose.ServiceVolumeConfig, 1)
|
|
service.Volumes[0] = compose.ServiceVolumeConfig{
|
|
Type: compose.VolumeTypeBind,
|
|
Source: "../run_bootstrap.sh",
|
|
Target: CONTAINER_ENTRYPOINT,
|
|
ReadOnly: true,
|
|
}
|
|
|
|
service.Ports = []compose.ServicePortConfig{
|
|
{
|
|
HostIP: "127.0.0.1",
|
|
Target: 60000,
|
|
Published: "60000",
|
|
},
|
|
{
|
|
HostIP: "127.0.0.1",
|
|
Target: 8008,
|
|
Published: "8008",
|
|
},
|
|
{
|
|
HostIP: "127.0.0.1",
|
|
Target: 9000,
|
|
Published: "9000",
|
|
},
|
|
{
|
|
HostIP: "127.0.0.1",
|
|
Target: 8545,
|
|
Published: "8545",
|
|
},
|
|
}
|
|
|
|
return service, nil
|
|
}
|
|
|
|
func (s *Simulation) prepPublisher() (compose.ServiceConfig, error) {
|
|
service := compose.ServiceConfig{}
|
|
|
|
service.Name = PUBLISHER_SERVICE_NAME
|
|
service.Image = s.Manifest.Publisher.Image
|
|
service.Entrypoint = compose.ShellCommand{"sh"}
|
|
service.Command = compose.ShellCommand{
|
|
CONTAINER_ENTRYPOINT,
|
|
}
|
|
|
|
service.Volumes = make([]compose.ServiceVolumeConfig, 1)
|
|
service.Volumes[0] = compose.ServiceVolumeConfig{
|
|
Type: compose.VolumeTypeBind,
|
|
Source: "../run_wakupublisher.sh",
|
|
Target: CONTAINER_ENTRYPOINT,
|
|
ReadOnly: true,
|
|
}
|
|
|
|
service.Environment = make(compose.MappingWithEquals)
|
|
|
|
v := fmt.Sprintf("%d", s.Manifest.Publisher.MsgPerSec)
|
|
service.Environment["MSG_PER_SECOND"] = &v
|
|
|
|
v2 := fmt.Sprintf("%d", s.Manifest.Publisher.MsgSizeKB)
|
|
service.Environment["MSG_SIZE_KBYTES"] = &v2
|
|
|
|
return service, nil
|
|
|
|
}
|