1
0
Fork 0
mirror of https://github.com/postmannen/ctrl.git synced 2024-12-15 17:51:15 +00:00

refactoring for reading input from file...and more

This commit is contained in:
postmannen 2021-02-03 22:08:28 +01:00
parent efb781ccf0
commit dc2352cab7
7 changed files with 131 additions and 60 deletions

View file

@ -2,6 +2,7 @@ package steward
import ( import (
"bufio" "bufio"
"encoding/json"
"fmt" "fmt"
"io" "io"
"log" "log"
@ -13,7 +14,7 @@ import (
// getMessagesFromFile will start a file watcher for the given directory // getMessagesFromFile will start a file watcher for the given directory
// and filename. It will take a channel of []byte as input, and it is // and filename. It will take a channel of []byte as input, and it is
// in this channel the content of a file that has changed is returned. // in this channel the content of a file that has changed is returned.
func getMessagesFromFile(directoryToCheck string, fileName string, fileContentCh chan []byte) { func getMessagesFromFile(directoryToCheck string, fileName string, fileContentCh chan []jsonFromFile) {
fileUpdated := make(chan bool) fileUpdated := make(chan bool)
go fileWatcherStart(directoryToCheck, fileUpdated) go fileWatcherStart(directoryToCheck, fileUpdated)
@ -26,13 +27,36 @@ func getMessagesFromFile(directoryToCheck string, fileName string, fileContentCh
log.Printf("error: reading file: %v", err) log.Printf("error: reading file: %v", err)
} }
fileContentCh <- b // unmarshal the JSON into a struct
fmt.Printf("File content read: %s\n", b) js, err := jsonFromFileData(b)
if err != nil {
log.Printf("%v\n", err)
}
// Send the data back to be consumed
fileContentCh <- js
} }
} }
} }
type jsonFromFile struct {
Subject `json:"subject"`
Message `json:"message"`
}
func jsonFromFileData(b []byte) ([]jsonFromFile, error) {
JS := []jsonFromFile{}
//err := yaml.Unmarshal(b, &JS)
err := json.Unmarshal(b, &JS)
if err != nil {
return nil, fmt.Errorf("error: json unmarshal of file failed: %v", err)
}
return JS, nil
}
// readTruncateMessageFile, will read all the messages in the given // readTruncateMessageFile, will read all the messages in the given
// file, and truncate the file after read. // file, and truncate the file after read.
// A []byte will be returned with the content read. // A []byte will be returned with the content read.
@ -53,20 +77,14 @@ func readTruncateMessageFile(fileName string) ([]byte, error) {
lines = append(lines, scanner.Bytes()...) lines = append(lines, scanner.Bytes()...)
} }
fmt.Printf("*** DEBUG : %s\n", lines)
fmt.Printf("read: %s\n", lines)
// empty the file after all is read // empty the file after all is read
ret, err := f.Seek(0, io.SeekStart) _, err = f.Seek(0, io.SeekStart)
if err != nil { if err != nil {
return nil, fmt.Errorf("f.Seek failed: %v", err) return nil, fmt.Errorf("f.Seek failed: %v", err)
} }
fmt.Printf("** ret=%v\n", ret)
err = f.Truncate(0) err = f.Truncate(0)
if err != nil { if err != nil {
fmt.Printf("******* %#v\n", err)
return nil, fmt.Errorf("f.Truncate failed: %v", err) return nil, fmt.Errorf("f.Truncate failed: %v", err)
} }

2
go.mod
View file

@ -4,8 +4,10 @@ go 1.15
require ( require (
github.com/fsnotify/fsnotify v1.4.9 github.com/fsnotify/fsnotify v1.4.9
github.com/ghodss/yaml v1.0.0
github.com/golang/protobuf v1.4.3 // indirect github.com/golang/protobuf v1.4.3 // indirect
github.com/nats-io/nats-server/v2 v2.1.9 // indirect github.com/nats-io/nats-server/v2 v2.1.9 // indirect
github.com/nats-io/nats.go v1.10.0 github.com/nats-io/nats.go v1.10.0
google.golang.org/protobuf v1.25.0 // indirect google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
) )

5
go.sum
View file

@ -6,6 +6,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -87,5 +89,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

30
orig.json Normal file
View file

@ -0,0 +1,30 @@
[
{
"subject":
{
"node":"ship1",
"messageType":"command",
"method":"shellcommand",
"domain":"shell"
},
"message":
{
"data": ["bash","-c","uname -a"],
"messageType":"eventReturnAck"
}
},
{
"subject":
{
"node":"ship2",
"messageType":"command",
"method":"shellcommand",
"domain":"shell"
},
"message":
{
"data": ["bash","-c","uname -a"],
"messageType":"eventReturnAck"
}
}
]

23
orig.yaml Normal file
View file

@ -0,0 +1,23 @@
---
- subject:
node: ship1
messageType: command
method: shellcommand
domain: shell
message:
data:
- bash
- "-c"
- uname -a
messageType: eventReturnAck
- subject:
node: ship2
messageType: command
method: shellcommand
domain: shell
message:
data:
- bash
- "-c"
- uname -a
messageType: eventReturnAck

View file

@ -12,9 +12,7 @@ import (
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
) )
var mu sync.Mutex type MessageType string
type messageType int
// TODO: Figure it makes sense to have these types at all. // TODO: Figure it makes sense to have these types at all.
// It might make more sense to implement these as two // It might make more sense to implement these as two
@ -25,13 +23,13 @@ const (
// delivered back in the reply ack message. // delivered back in the reply ack message.
// The message should contain the unique ID of the // The message should contain the unique ID of the
// command. // command.
commandReturnOutput messageType = iota CommandReturnOutput MessageType = "commandReturnOutput"
// shellCommand, wait for and return the output // shellCommand, wait for and return the output
// of the command in the ACK message. This means // of the command in the ACK message. This means
// that the command should be executed immediately // that the command should be executed immediately
// and that we should get the confirmation that it // and that we should get the confirmation that it
// was successful or not. // was successful or not.
eventReturnAck messageType = iota EventReturnAck MessageType = "eventReturnAck"
// eventCommand, just wait for the ACK that the // eventCommand, just wait for the ACK that the
// message is received. What action happens on the // message is received. What action happens on the
// receiving side is up to the received to decide. // receiving side is up to the received to decide.
@ -39,13 +37,13 @@ const (
type Message struct { type Message struct {
// The Unique ID of the message // The Unique ID of the message
ID int ID int `json:"id"`
// The actual data in the message // The actual data in the message
// TODO: Change this to a slice instead...or maybe use an // TODO: Change this to a slice instead...or maybe use an
// interface type here to handle several data types ? // interface type here to handle several data types ?
Data []string Data []string `json:"data"`
// The type of the message being sent // The type of the message being sent
MessageType messageType MessageType MessageType `json:"messageType"`
} }
// server is the structure that will hold the state about spawned // server is the structure that will hold the state about spawned
@ -57,6 +55,7 @@ type server struct {
// The last processID created // The last processID created
lastProcessID int lastProcessID int
nodeName string nodeName string
mu sync.Mutex
} }
// newServer will prepare and return a server type // newServer will prepare and return a server type
@ -72,6 +71,9 @@ func NewServer(brokerAddress string, nodeName string) (*server, error) {
processes: make(map[subjectName]process), processes: make(map[subjectName]process),
} }
// Start the error handler
// TODO: For now it will just print the error messages to the
// console.
go func() { go func() {
for { for {
@ -93,29 +95,23 @@ func NewServer(brokerAddress string, nodeName string) (*server, error) {
func (s *server) PublisherStart() { func (s *server) PublisherStart() {
// start the checking of files for input messages // start the checking of files for input messages
fileReadCh := make((chan []byte)) fileReadCh := make((chan []jsonFromFile))
go getMessagesFromFile("./", "inmsg.txt", fileReadCh) go getMessagesFromFile("./", "inmsg.txt", fileReadCh)
// TODO: For now we just print content of the files read. // TODO: For now we just print content of the files read.
// Replace this whit a broker function that will know how // Replace this with a broker function that will know how
// send it on to the correct publisher. // send it on to the correct publisher.
go func() { go func() {
for b := range fileReadCh { for v := range fileReadCh {
// Check if there are new content read from file input // Check if there are new content read from file input
fmt.Printf("received: %s\n", b) fmt.Printf("received: %#v\n", v)
} }
}() }()
// Prepare and start a single process // Prepare and start a single process
{ {
sub := subject{ sub := newSubject("btship1", "command", "shellcommand", "shell")
node: "btship1",
messageType: "command",
method: "shellcommand",
domain: "shell",
messageCh: make(chan Message),
}
proc := s.processPrepareNew(sub) proc := s.processPrepareNew(sub)
// fmt.Printf("*** %#v\n", proc) // fmt.Printf("*** %#v\n", proc)
go s.processSpawn(proc) go s.processSpawn(proc)
@ -123,13 +119,7 @@ func (s *server) PublisherStart() {
// Prepare and start a single process // Prepare and start a single process
{ {
sub := subject{ sub := newSubject("btship2", "command", "shellcommand", "shell")
node: "btship2",
messageType: "command",
method: "shellcommand",
domain: "shell",
messageCh: make(chan Message),
}
proc := s.processPrepareNew(sub) proc := s.processPrepareNew(sub)
// fmt.Printf("*** %#v\n", proc) // fmt.Printf("*** %#v\n", proc)
go s.processSpawn(proc) go s.processSpawn(proc)
@ -140,7 +130,7 @@ func (s *server) PublisherStart() {
for { for {
m := Message{ m := Message{
Data: []string{"bash", "-c", "uname -a"}, Data: []string{"bash", "-c", "uname -a"},
MessageType: eventReturnAck, MessageType: EventReturnAck,
} }
subjName := subjectName("btship1.command.shellcommand.shell") subjName := subjectName("btship1.command.shellcommand.shell")
_, ok := s.processes[subjName] _, ok := s.processes[subjName]
@ -179,26 +169,39 @@ type node string
// subject contains the representation of a subject to be used with one // subject contains the representation of a subject to be used with one
// specific process // specific process
type subject struct { type Subject struct {
// node, the name of the node // node, the name of the node
node string Node string `json:"node"`
// messageType, command/event // messageType, command/event
messageType string MessageType string `json:"messageType"`
// method, what is this message doing, etc. shellcommand, syslog, etc. // method, what is this message doing, etc. shellcommand, syslog, etc.
method string Method string `json:"method"`
// domain is used to differentiate services. Like there can be more // domain is used to differentiate services. Like there can be more
// logging services, but rarely more logging services for the same // logging services, but rarely more logging services for the same
// thing. Domain is here used to differentiate the the services and // thing. Domain is here used to differentiate the the services and
// tell with one word what it is for. // tell with one word what it is for.
domain string Domain string `json:"domain"`
// messageCh is the channel for receiving new content to be sent // messageCh is the channel for receiving new content to be sent
messageCh chan Message messageCh chan Message
} }
// newSubject will return a new variable of the type subject, and insert
// all the values given as arguments. It will also create the channel
// to receive new messages on the specific subject.
func newSubject(node string, messageType string, method string, domain string) Subject {
return Subject{
Node: node,
MessageType: messageType,
Method: method,
Domain: domain,
messageCh: make(chan Message),
}
}
type subjectName string type subjectName string
func (s subject) name() subjectName { func (s Subject) name() subjectName {
return subjectName(fmt.Sprintf("%s.%s.%s.%s", s.node, s.messageType, s.method, s.domain)) return subjectName(fmt.Sprintf("%s.%s.%s.%s", s.Node, s.MessageType, s.Method, s.Domain))
} }
// process are represent the communication to one individual host // process are represent the communication to one individual host
@ -207,7 +210,7 @@ type process struct {
// the subject used for the specific process. One process // the subject used for the specific process. One process
// can contain only one sender on a message bus, hence // can contain only one sender on a message bus, hence
// also one subject // also one subject
subject subject subject Subject
// Put a node here to be able know the node a process is at. // Put a node here to be able know the node a process is at.
// NB: Might not be needed later on. // NB: Might not be needed later on.
node node node node
@ -223,13 +226,13 @@ type process struct {
// prepareNewProcess will set the the provided values and the default // prepareNewProcess will set the the provided values and the default
// values for a process. // values for a process.
func (s *server) processPrepareNew(subject subject) process { func (s *server) processPrepareNew(subject Subject) process {
// create the initial configuration for a sessions communicating with 1 host process. // create the initial configuration for a sessions communicating with 1 host process.
s.lastProcessID++ s.lastProcessID++
proc := process{ proc := process{
messageID: 0, messageID: 0,
subject: subject, subject: subject,
node: node(subject.node), node: node(subject.Node),
processID: s.lastProcessID, processID: s.lastProcessID,
errorCh: make(chan string), errorCh: make(chan string),
//messageCh: make(chan Message), //messageCh: make(chan Message),
@ -242,12 +245,12 @@ func (s *server) processPrepareNew(subject subject) process {
// the next available ID, and also add the process to the processes // the next available ID, and also add the process to the processes
// map. // map.
func (s *server) processSpawn(proc process) { func (s *server) processSpawn(proc process) {
mu.Lock() s.mu.Lock()
// We use the full name of the subject to identify a unique // We use the full name of the subject to identify a unique
// process. We can do that since a process can only handle // process. We can do that since a process can only handle
// one message queue. // one message queue.
s.processes[proc.subject.name()] = proc s.processes[proc.subject.name()] = proc
mu.Unlock() s.mu.Unlock()
// Loop creating one new message every second to simulate getting new // Loop creating one new message every second to simulate getting new
// messages to deliver. // messages to deliver.
@ -258,7 +261,6 @@ func (s *server) processSpawn(proc process) {
// is listened on in the for loop below could be used to receive the // is listened on in the for loop below could be used to receive the
// messages from the message-pickup-process. // messages from the message-pickup-process.
for { for {
// m := getMessageToDeliver()
// Wait and read the next message on the message channel // Wait and read the next message on the message channel
m := <-proc.subject.messageCh m := <-proc.subject.messageCh
m.ID = s.processes[proc.subject.name()].messageID m.ID = s.processes[proc.subject.name()].messageID
@ -277,15 +279,6 @@ func (s *server) processSpawn(proc process) {
} }
} }
// get MessageToDeliver will pick up the next message to be created.
// TODO: read this from local file or rest or....?
func getMessageToDeliver() Message {
return Message{
Data: []string{"bash", "-c", "uname -a"},
MessageType: eventReturnAck,
}
}
func messageDeliver(proc process, message Message, natsConn *nats.Conn) { func messageDeliver(proc process, message Message, natsConn *nats.Conn) {
for { for {
dataPayload, err := gobEncodePayload(message) dataPayload, err := gobEncodePayload(message)

View file

@ -33,7 +33,7 @@ func (s *server) RunSubscriber() {
msg := <-reqMsgCh msg := <-reqMsgCh
fmt.Printf("%v\n", msg) fmt.Printf("%v\n", msg)
switch msg.MessageType { switch msg.MessageType {
case eventReturnAck: case EventReturnAck:
// Since the command to execute is at the first position in the // Since the command to execute is at the first position in the
// slice we need to slice it out. The arguments are at the // slice we need to slice it out. The arguments are at the
// remaining positions. // remaining positions.