1
0
Fork 0
mirror of https://github.com/postmannen/ctrl.git synced 2024-12-14 12:37:31 +00:00
ctrl/server.go

190 lines
5.7 KiB
Go
Raw Normal View History

// Notes:
2021-02-01 10:13:38 +00:00
package steward
2021-01-25 14:23:00 +00:00
import (
"fmt"
"log"
"os"
2021-01-28 13:58:16 +00:00
"sync"
2021-01-25 14:23:00 +00:00
"time"
"github.com/nats-io/nats.go"
"github.com/prometheus/client_golang/prometheus"
2021-01-25 14:23:00 +00:00
)
2021-02-26 06:55:28 +00:00
type processName string
// Will return a process name made up of subjectName+processKind
2021-02-26 06:55:28 +00:00
func processNameGet(sn subjectName, pk processKind) processName {
pn := fmt.Sprintf("%s_%s", sn, pk)
return processName(pn)
}
// processes holds all the information about running processes
type processes struct {
// The active spawned processes
active map[processName]process
// mutex to lock the map
mu sync.Mutex
// The last processID created
lastProcessID int
}
// newProcesses will prepare and return a *processes
func newProcesses() *processes {
p := processes{
active: make(map[processName]process),
}
return &p
}
// server is the structure that will hold the state about spawned
// processes on a local instance.
2021-01-27 13:02:57 +00:00
type server struct {
// Configuration options used for running the server
configuration *Configuration
// The nats connection to the broker
2021-01-27 13:02:57 +00:00
natsConn *nats.Conn
// processes holds all the information about running processes
processes *processes
// The name of the node
nodeName string
2021-02-24 09:58:02 +00:00
// Mutex for locking when writing to the process map
newMessagesCh chan []subjectAndMessage
2021-02-24 09:58:02 +00:00
// errorKernel is doing all the error handling like what to do if
// an error occurs.
// TODO: Will also send error messages to cental error subscriber.
errorKernel *errorKernel
2021-02-18 11:29:14 +00:00
// metric exporter
metrics *metrics
// Is this the central error logger ?
// collection of the publisher services and the types to control them
publisherServices *publisherServices
centralErrorLogger bool
2021-01-27 13:02:57 +00:00
}
// newServer will prepare and return a server type
func NewServer(c *Configuration) (*server, error) {
conn, err := nats.Connect(c.BrokerAddress, nil)
2021-02-01 10:13:38 +00:00
if err != nil {
log.Printf("error: nats.Connect failed: %v\n", err)
}
s := &server{
configuration: c,
nodeName: c.NodeName,
natsConn: conn,
processes: newProcesses(),
newMessagesCh: make(chan []subjectAndMessage),
metrics: newMetrics(c.PromHostAndPort),
publisherServices: newPublisherServices(c.PublisherServiceSayhello),
centralErrorLogger: c.CentralErrorLogger,
}
// Create the default data folder for where subscribers should
// write it's data if needed.
// Check if data folder exist, and create it if needed.
if _, err := os.Stat(c.SubscribersDataFolder); os.IsNotExist(err) {
if c.SubscribersDataFolder == "" {
return nil, fmt.Errorf("error: subscribersDataFolder value is empty, you need to provide the config or the flag value at startup %v: %v", c.SubscribersDataFolder, err)
}
err := os.Mkdir(c.SubscribersDataFolder, 0700)
if err != nil {
return nil, fmt.Errorf("error: failed to create directory %v: %v", c.SubscribersDataFolder, err)
}
log.Printf("info: Creating subscribers data folder at %v\n", c.SubscribersDataFolder)
}
2021-02-05 06:25:12 +00:00
return s, nil
}
2021-02-24 09:58:02 +00:00
// Start will spawn up all the predefined subscriber processes.
2021-02-10 06:25:44 +00:00
// Spawning of publisher processes is done on the fly by checking
2021-02-24 09:58:02 +00:00
// if there is publisher process for a given message subject, and
// not exist it will spawn one.
func (s *server) Start() {
// Start the error kernel that will do all the error handling
// not done within a process.
s.errorKernel = newErrorKernel()
s.errorKernel.startErrorKernel(s.newMessagesCh)
2021-02-18 11:29:14 +00:00
// Start collecting the metrics
go s.startMetrics()
// Start the checking the input file for new messages from operator.
go s.getMessagesFromFile("./", "inmsg.txt", s.newMessagesCh)
// if enabled, start the sayHello I'm here service at the given interval
if s.publisherServices.sayHelloPublisher.interval != 0 {
go s.publisherServices.sayHelloPublisher.start(s.newMessagesCh, node(s.nodeName))
}
2021-02-24 09:58:02 +00:00
// Start up the predefined subscribers.
// TODO: What to subscribe on should be handled via flags, or config
// files.
s.subscribersStart()
time.Sleep(time.Second * 1)
2021-02-10 06:25:44 +00:00
s.printProcessesMap()
2021-02-24 09:58:02 +00:00
// Start the processing of new messaging from an input channel.
s.processNewMessages("./incommmingBuffer.db", s.newMessagesCh)
select {}
}
2021-02-10 06:25:44 +00:00
func (s *server) printProcessesMap() {
fmt.Println("--------------------------------------------------------------------------------------------")
fmt.Printf("*** Output of processes map :\n")
s.processes.mu.Lock()
for _, v := range s.processes.active {
fmt.Printf("* proc - : id: %v, name: %v, allowed from: %v\n", v.processID, v.subject.name(), v.allowedReceivers)
2021-02-10 06:25:44 +00:00
}
s.processes.mu.Unlock()
s.metrics.metricsCh <- metricType{
metric: prometheus.NewGauge(prometheus.GaugeOpts{
Name: "total_running_processes",
Help: "The current number of total running processes",
}),
value: float64(len(s.processes.active)),
}
2021-02-10 06:25:44 +00:00
fmt.Println("--------------------------------------------------------------------------------------------")
}
2021-02-25 10:08:05 +00:00
// sendErrorMessage will put the error message directly on the channel that is
// read by the nats publishing functions.
func sendErrorLogMessage(newMessagesCh chan<- []subjectAndMessage, FromNode node, theError error) {
// --- Testing
2021-02-25 10:08:05 +00:00
sam := createErrorMsgContent(FromNode, theError)
newMessagesCh <- []subjectAndMessage{sam}
}
2021-02-25 10:08:05 +00:00
// createErrorMsgContent will prepare a subject and message with the content
// of the error
func createErrorMsgContent(FromNode node, theError error) subjectAndMessage {
// TESTING: Creating an error message to send to errorCentral
fmt.Printf(" --- Sending error message to central !!!!!!!!!!!!!!!!!!!!!!!!!!!!\n")
sam := subjectAndMessage{
Subject: Subject{
ToNode: "errorCentral",
CommandOrEvent: EventNACK,
Method: ErrorLog,
},
Message: Message{
ToNode: "errorCentral",
FromNode: FromNode,
Data: []string{theError.Error()},
Method: ErrorLog,
},
}
2021-02-25 10:08:05 +00:00
return sam
}